2 * FreeLoader PowerPC Part
3 * Copyright (C) 2005 Art Yerkes
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "ppcmmu/mmu.h"
26 extern void BootMain( PSTR CmdLine
);
27 extern ULONG CacheSizeLimit
;
29 void *PageDirectoryStart
, *PageDirectoryEnd
;
30 static int chosen_package
, stdin_handle
, stdout_handle
, part_handle
= -1;
33 BOOLEAN AcpiPresent
= FALSE
;
34 CHAR FrLdrBootPath
[MAX_PATH
] = "", BootPart
[MAX_PATH
] = "", CmdLine
[MAX_PATH
] = "bootprep";
36 volatile char *video_mem
= 0;
38 void PpcOfwPutChar( int ch
) {
40 if( ch
== 0x0a ) { buf
[0] = 0x0d; buf
[1] = 0x0a; }
41 else { buf
[0] = ch
; buf
[1] = 0; }
43 ofw_write(stdout_handle
, buf
, strlen(buf
));
46 int PpcFindDevice( int depth
, int parent
, char *devname
, int *nth
) {
53 next
= ofw_child( parent
);
55 //printf( "next = %x\n", next );
57 gotname
= ofw_getprop(parent
, "name", buf
, 256);
59 //printf( "gotname = %d\n", gotname );
61 match
= !strncmp(buf
, devname
, strlen(devname
));
63 if( !nth
&& match
) return parent
;
65 for( i
= 0; i
< depth
; i
++ ) PpcOfwPutChar( ' ' );
69 printf( "%c Name: %s\n", match
? '*' : ' ', buf
);
71 printf( "- No name attribute for %x\n", parent
);
75 while( !match
&& next
) {
76 i
= PpcFindDevice( depth
+1, next
, devname
, nth
);
78 next
= ofw_peer( next
);
84 BOOLEAN
PpcConsKbHit() {
90 ofw_read( stdin_handle
, &buf
, 1 );
94 void PpcVideoClearScreen( UCHAR Attr
) {
97 VOID
PpcVideoGetDisplaySize( PULONG Width
, PULONG Height
, PULONG Depth
) {
103 ULONG
PpcVideoGetBufferSize() {
104 ULONG Width
, Height
, Depth
;
105 MachVideoGetDisplaySize( &Width
, &Height
, &Depth
);
106 return Width
* Height
* Depth
/ 8;
109 VIDEODISPLAYMODE
PpcVideoSetDisplayMode( char *DisplayMode
, BOOLEAN Init
) {
110 //printf( "DisplayMode: %s %s\n", DisplayMode, Init ? "true" : "false" );
111 if( Init
&& !video_mem
) {
112 video_mem
= MmAllocateMemory( PpcVideoGetBufferSize() );
114 return VideoTextMode
;
117 VOID
PpcVideoSetTextCursorPosition( ULONG X
, ULONG Y
) {
118 printf("SetTextCursorPosition(%d,%d)\n", X
,Y
);
121 VOID
PpcVideoHideShowTextCursor( BOOLEAN Show
) {
122 printf("HideShowTextCursor(%s)\n", Show
? "true" : "false");
125 VOID
PpcVideoPutChar( int Ch
, UCHAR Attr
, unsigned X
, unsigned Y
) {
126 printf( "\033[%d;%dH%c", Y
, X
, Ch
);
129 VOID
PpcVideoCopyOffScreenBufferToVRAM( PVOID Buffer
) {
132 PCHAR ChBuf
= Buffer
;
135 MachVideoGetDisplaySize( &w
, &h
, &d
);
137 for( i
= 0; i
< h
; i
++ ) {
138 for( j
= 0; j
< w
; j
++ ) {
139 offset
= (j
* 2) + (i
* w
* 2);
140 if( ChBuf
[offset
] != video_mem
[offset
] ) {
141 video_mem
[offset
] = ChBuf
[offset
];
142 MachVideoPutChar(ChBuf
[offset
],0,j
+1,i
+1);
148 BOOLEAN
PpcVideoIsPaletteFixed() {
152 VOID
PpcVideoSetPaletteColor( UCHAR Color
,
153 UCHAR Red
, UCHAR Green
, UCHAR Blue
) {
154 printf( "SetPaletteColor(%x,%x,%x,%x)\n", Color
, Red
, Green
, Blue
);
157 VOID
PpcVideoGetPaletteColor( UCHAR Color
,
158 UCHAR
*Red
, UCHAR
*Green
, UCHAR
*Blue
) {
159 printf( "GetPaletteColor(%x)\n", Color
);
162 VOID
PpcVideoSync() {
166 int mmu_initialized
= 0;
168 VOID
PpcInitializeMmu()
173 MmuDbgInit(0, 0x800003f8);
174 MmuSetMemorySize(mem_range_end
);
180 ULONG
PpcPrepGetMemoryMap( PBIOS_MEMORY_MAP BiosMemoryMap
,
181 ULONG MaxMemoryMapSize
);
184 * Get memory the proper openfirmware way
186 ULONG
PpcGetMemoryMap( PBIOS_MEMORY_MAP BiosMemoryMap
,
187 ULONG MaxMemoryMapSize
) {
188 int i
, memhandle
, total
= 0, slots
= 0, last
= 0x40000, allocstart
= 0x1000000;
191 printf("PpcGetMemoryMap(%d)\n", MaxMemoryMapSize
);
193 memhandle
= ofw_finddevice("/memory");
195 ofw_getprop(memhandle
, "reg", (char *)regdata
, sizeof(regdata
));
197 /* Try to claim some memory in usable blocks. Try to get some 8mb bits */
198 for( i
= 0; i
< sizeof(claimed
) / sizeof(claimed
[0]); ) {
200 claimed
[i
] = ofw_claim(allocstart
, 8 * 1024 * 1024, 0x1000);
202 allocstart
+= 8 * 1024 * 1024;
205 if (last
< claimed
[i
]) {
206 BiosMemoryMap
[slots
].Type
= BiosMemoryAcpiReclaim
;
207 BiosMemoryMap
[slots
].BaseAddress
= last
;
208 BiosMemoryMap
[slots
].Length
= claimed
[i
] - last
;
212 BiosMemoryMap
[slots
].Type
= BiosMemoryUsable
;
213 BiosMemoryMap
[slots
].BaseAddress
= claimed
[i
];
214 BiosMemoryMap
[slots
].Length
= 8 * 1024 * 1024;
216 total
+= BiosMemoryMap
[slots
].Length
;
218 BiosMemoryMap
[slots
].BaseAddress
+
219 BiosMemoryMap
[slots
].Length
;
225 /* Get the rest until the end of the memory object as we see it */
226 if (last
< regdata
[1]) {
227 BiosMemoryMap
[slots
].Type
= BiosMemoryAcpiReclaim
;
228 BiosMemoryMap
[slots
].BaseAddress
= last
;
229 BiosMemoryMap
[slots
].Length
= regdata
[1] - last
;
233 for (i
= 0; i
< slots
; i
++) {
234 printf("MemoryMap[%d] = (%x:%x)\n",
236 (int)BiosMemoryMap
[i
].BaseAddress
,
237 (int)BiosMemoryMap
[i
].Length
);
241 mem_range_end
= regdata
[1];
243 printf( "Returning memory map (%d entries, %dk free, %dk total ram)\n",
244 slots
, total
/ 1024, regdata
[1] / 1024 );
249 BOOLEAN
PpcDiskReadLogicalSectors( ULONG DriveNumber
, ULONGLONG SectorNumber
,
250 ULONG SectorCount
, PVOID Buffer
) {
253 if( part_handle
== -1 ) {
254 part_handle
= ofw_open( BootPart
);
256 if( part_handle
== -1 ) {
257 printf("Could not open any disk devices we know about\n");
262 if( part_handle
== -1 ) {
263 printf("Got partition handle %x\n", part_handle
);
267 if( ofw_seek( part_handle
,
268 (ULONG
)(SectorNumber
>> 25),
269 (ULONG
)((SectorNumber
* 512) & 0xffffffff) ) ) {
270 printf("Seek to %x failed\n", (ULONG
)(SectorNumber
* 512));
274 rlen
= ofw_read( part_handle
, Buffer
, (ULONG
)(SectorCount
* 512) );
278 BOOLEAN
PpcDiskGetDriveGeometry( ULONG DriveNumber
, PGEOMETRY DriveGeometry
) {
279 printf("GetGeometry(%d)\n", DriveNumber
);
280 DriveGeometry
->BytesPerSector
= 512;
281 DriveGeometry
->Heads
= 16;
282 DriveGeometry
->Sectors
= 63;
286 ULONG
PpcDiskGetCacheableBlockCount( ULONG DriveNumber
) {
287 printf("GetCacheableBlockCount\n");
294 static TIMEINFO TimeInfo
;
295 //printf("PpcGetTime\n");
299 VOID
NarrowToWide(WCHAR
*wide_name
, char *name
)
302 WCHAR
*wide_name_ptr
;
303 for (wide_name_ptr
= wide_name
, copy_name
= name
;
304 (*wide_name_ptr
= *copy_name
);
305 wide_name_ptr
++, copy_name
++);
308 /* Recursively copy the device tree into our representation
309 * It'll be passed to HAL.
311 * When NT was first done on PPC, it was on PReP hardware, which is very
312 * like PC hardware (really, just a PPC on a PC motherboard). HAL can guess
313 * the addresses of needed resources in this scheme as it can on x86.
315 * Most PPC hardware doesn't assign fixed addresses to hardware, which is
316 * the problem that open firmware partially solves. It allows hardware makers
317 * much more leeway in building PPC systems. Unfortunately, because
318 * openfirmware as originally specified neither captures nor standardizes
319 * all possible information, and also because of bugs, most OSs use a hybrid
320 * configuration scheme that relies both on verification of devices and
321 * recording information from openfirmware to be treated as hints.
323 VOID OfwCopyDeviceTree
324 (PCONFIGURATION_COMPONENT_DATA ParentKey
,
328 ULONG
*DiskController
,
331 int proplen
= 0, node
= innode
;
332 char *prev_name
, cur_name
[64], data
[256], *slash
, devtype
[64];
333 wchar_t wide_name
[64];
334 PCONFIGURATION_COMPONENT_DATA NewKey
;
336 NarrowToWide(wide_name
, name
);
338 /* Create a key for this device */
339 FldrCreateComponentKey
342 MultiFunctionAdapter
,
352 for (prev_name
= ""; ofw_nextprop(node
, prev_name
, cur_name
) == 1; )
354 proplen
= ofw_getproplen(node
, cur_name
);
355 if (proplen
> 256 || proplen
< 0)
357 printf("Warning: not getting prop %s (too long: %d)\n",
361 ofw_getprop(node
, cur_name
, data
, sizeof(data
));
363 /* Get device type so we can examine it */
364 if (!strcmp(cur_name
, "device_type"))
365 strcpy(devtype
, (char *)data
);
367 NarrowToWide(wide_name
, cur_name
);
368 //RegSetValue(NewKey, wide_name, REG_BINARY, data, proplen);
370 strcpy(data
, cur_name
);
375 /* Special device handling */
376 if (!strcmp(devtype
, "ata"))
378 OfwHandleDiskController(NewKey
, node
, *DiskController
);
382 else if (!strcmp(devtype
, "disk"))
384 OfwHandleDiskObject(NewKey
, node
, *DiskController
, *DiskNumber
);
390 for (node
= ofw_child(node
); node
; node
= ofw_peer(node
))
392 ofw_package_to_path(node
, data
, sizeof(data
));
393 slash
= strrchr(data
, '/');
394 if (slash
) slash
++; else continue;
396 (NewKey
, slash
, node
, BusNumber
, DiskController
, DiskNumber
);
400 PCONFIGURATION_COMPONENT_DATA
PpcHwDetect() {
401 PCONFIGURATION_COMPONENT_DATA RootKey
;
402 ULONG BusNumber
= 0, DiskController
= 0, DiskNumber
= 0;
403 int node
= ofw_finddevice("/");
405 FldrCreateSystemKey(&RootKey
);
407 OfwCopyDeviceTree(RootKey
,"/",node
,&BusNumber
,&DiskController
,&DiskNumber
);
417 void PpcDefaultMachVtbl()
419 MachVtbl
.ConsPutChar
= PpcOfwPutChar
;
420 MachVtbl
.ConsKbHit
= PpcConsKbHit
;
421 MachVtbl
.ConsGetCh
= PpcConsGetCh
;
422 MachVtbl
.VideoClearScreen
= PpcVideoClearScreen
;
423 MachVtbl
.VideoSetDisplayMode
= PpcVideoSetDisplayMode
;
424 MachVtbl
.VideoGetDisplaySize
= PpcVideoGetDisplaySize
;
425 MachVtbl
.VideoGetBufferSize
= PpcVideoGetBufferSize
;
426 MachVtbl
.VideoSetTextCursorPosition
= PpcVideoSetTextCursorPosition
;
427 MachVtbl
.VideoHideShowTextCursor
= PpcVideoHideShowTextCursor
;
428 MachVtbl
.VideoPutChar
= PpcVideoPutChar
;
429 MachVtbl
.VideoCopyOffScreenBufferToVRAM
=
430 PpcVideoCopyOffScreenBufferToVRAM
;
431 MachVtbl
.VideoIsPaletteFixed
= PpcVideoIsPaletteFixed
;
432 MachVtbl
.VideoSetPaletteColor
= PpcVideoSetPaletteColor
;
433 MachVtbl
.VideoGetPaletteColor
= PpcVideoGetPaletteColor
;
434 MachVtbl
.VideoSync
= PpcVideoSync
;
436 MachVtbl
.GetMemoryMap
= PpcGetMemoryMap
;
438 MachVtbl
.DiskReadLogicalSectors
= PpcDiskReadLogicalSectors
;
439 MachVtbl
.DiskGetDriveGeometry
= PpcDiskGetDriveGeometry
;
440 MachVtbl
.DiskGetCacheableBlockCount
= PpcDiskGetCacheableBlockCount
;
442 MachVtbl
.GetTime
= PpcGetTime
;
444 MachVtbl
.HwDetect
= PpcHwDetect
;
445 MachVtbl
.HwIdle
= PpcHwIdle
;
450 chosen_package
= ofw_finddevice( "/chosen" );
452 ofw_getprop(chosen_package
, "bootargs",
453 CmdLine
, sizeof(CmdLine
));
454 ofw_getprop( chosen_package
, "stdin",
455 (char *)&stdin_handle
, sizeof(stdin_handle
) );
456 ofw_getprop( chosen_package
, "stdout",
457 (char *)&stdout_handle
, sizeof(stdout_handle
) );
458 ofw_getprop( chosen_package
, "mmu",
459 (char *)&mmu_handle
, sizeof(mmu_handle
) );
461 // Allow forcing prep for broken OFW
462 if(!strncmp(CmdLine
, "bootprep", 8))
464 printf("Going to PREP init...\n");
470 printf( "FreeLDR version [%s]\n", FrLdrVersionString
);
475 void PpcInit( of_proxy the_ofproxy
) {
476 // Hack to be a bit easier on ram
477 CacheSizeLimit
= 64 * 1024;
478 ofproxy
= the_ofproxy
;
479 PpcDefaultMachVtbl();
480 if(ofproxy
) PpcOfwInit();
484 void MachInit(const char *CmdLine
) {
489 FrLdrBootPath
[0] = 0;
491 printf( "Determining boot device: [%s]\n", CmdLine
);
494 for( i
= 0; i
< strlen(CmdLine
); i
++ ) {
495 if( strncmp(CmdLine
+ i
, "boot=", 5) == 0) {
496 strcpy(BootPart
, CmdLine
+ i
+ 5);
497 sep
= strchr(BootPart
, ',');
500 while(CmdLine
[i
] && CmdLine
[i
]!=',') i
++;
504 if( strlen(BootPart
) == 0 ) {
506 len
= ofw_getprop(chosen_package
, "bootpath",
507 FrLdrBootPath
, sizeof(FrLdrBootPath
));
510 if( len
< 0 ) len
= 0;
511 FrLdrBootPath
[len
] = 0;
512 printf( "Boot Path: %s\n", FrLdrBootPath
);
514 sep
= strrchr(FrLdrBootPath
, ',');
516 strcpy(BootPart
, FrLdrBootPath
);
518 BootPart
[sep
- FrLdrBootPath
] = 0;
522 printf( "FreeLDR starting (boot partition: %s)\n", BootPart
);
528 UCHAR NTAPI
READ_PORT_UCHAR(PUCHAR Address
) {
529 return GetPhysByte(((ULONG
)Address
)+0x80000000);
532 void WRITE_PORT_UCHAR(PUCHAR Address
, UCHAR Value
) {
533 SetPhysByte(((ULONG
)Address
)+0x80000000, Value
);
536 VOID __cdecl
BootLinuxKernel(
538 IN PVOID KernelCurrentLoadAddress
,
539 IN PVOID KernelTargetLoadAddress
,
540 IN UCHAR DriveNumber
,
541 IN ULONG PartitionNumber
)
546 VOID __cdecl
ChainLoadBiosBootSectorCode(
547 IN UCHAR BootDrive OPTIONAL
,
548 IN ULONG BootPartition OPTIONAL
)
553 void DbgBreakPoint() {
554 __asm__("twi 31,0,0");