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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "ppcmmu/mmu.h"
26 extern void BootMain( LPSTR CmdLine
);
27 extern PCHAR
GetFreeLoaderVersionString();
28 extern ULONG CacheSizeLimit
;
30 void *PageDirectoryStart
, *PageDirectoryEnd
;
31 static int chosen_package
, stdin_handle
, stdout_handle
, part_handle
= -1;
34 BOOLEAN AcpiPresent
= FALSE
;
35 char BootPath
[0x100] = { 0 }, BootPart
[0x100] = { 0 }, CmdLine
[0x100] = { "bootprep" };
37 volatile char *video_mem
= 0;
39 void PpcOfwPutChar( int ch
) {
41 if( ch
== 0x0a ) { buf
[0] = 0x0d; buf
[1] = 0x0a; }
42 else { buf
[0] = ch
; buf
[1] = 0; }
44 ofw_write(stdout_handle
, buf
, strlen(buf
));
47 int PpcFindDevice( int depth
, int parent
, char *devname
, int *nth
) {
54 next
= ofw_child( parent
);
56 //printf( "next = %x\n", next );
58 gotname
= ofw_getprop(parent
, "name", buf
, 256);
60 //printf( "gotname = %d\n", gotname );
62 match
= !strncmp(buf
, devname
, strlen(devname
));
64 if( !nth
&& match
) return parent
;
66 for( i
= 0; i
< depth
; i
++ ) PpcOfwPutChar( ' ' );
70 printf( "%c Name: %s\n", match
? '*' : ' ', buf
);
72 printf( "- No name attribute for %x\n", parent
);
76 while( !match
&& next
) {
77 i
= PpcFindDevice( depth
+1, next
, devname
, nth
);
79 next
= ofw_peer( next
);
85 BOOLEAN
PpcConsKbHit() {
91 ofw_read( stdin_handle
, &buf
, 1 );
95 void PpcVideoClearScreen( UCHAR Attr
) {
98 VOID
PpcVideoGetDisplaySize( PULONG Width
, PULONG Height
, PULONG Depth
) {
104 ULONG
PpcVideoGetBufferSize() {
105 ULONG Width
, Height
, Depth
;
106 MachVideoGetDisplaySize( &Width
, &Height
, &Depth
);
107 return Width
* Height
* Depth
/ 8;
110 VIDEODISPLAYMODE
PpcVideoSetDisplayMode( char *DisplayMode
, BOOLEAN Init
) {
111 //printf( "DisplayMode: %s %s\n", DisplayMode, Init ? "true" : "false" );
112 if( Init
&& !video_mem
) {
113 video_mem
= MmAllocateMemory( PpcVideoGetBufferSize() );
115 return VideoTextMode
;
118 VOID
PpcVideoSetTextCursorPosition( ULONG X
, ULONG Y
) {
119 printf("SetTextCursorPosition(%d,%d)\n", X
,Y
);
122 VOID
PpcVideoHideShowTextCursor( BOOLEAN Show
) {
123 printf("HideShowTextCursor(%s)\n", Show
? "true" : "false");
126 VOID
PpcVideoPutChar( int Ch
, UCHAR Attr
, unsigned X
, unsigned Y
) {
127 printf( "\033[%d;%dH%c", Y
, X
, Ch
);
130 VOID
PpcVideoCopyOffScreenBufferToVRAM( PVOID Buffer
) {
133 PCHAR ChBuf
= Buffer
;
136 MachVideoGetDisplaySize( &w
, &h
, &d
);
138 for( i
= 0; i
< h
; i
++ ) {
139 for( j
= 0; j
< w
; j
++ ) {
140 offset
= (j
* 2) + (i
* w
* 2);
141 if( ChBuf
[offset
] != video_mem
[offset
] ) {
142 video_mem
[offset
] = ChBuf
[offset
];
143 MachVideoPutChar(ChBuf
[offset
],0,j
+1,i
+1);
149 BOOLEAN
PpcVideoIsPaletteFixed() {
153 VOID
PpcVideoSetPaletteColor( UCHAR Color
,
154 UCHAR Red
, UCHAR Green
, UCHAR Blue
) {
155 printf( "SetPaletteColor(%x,%x,%x,%x)\n", Color
, Red
, Green
, Blue
);
158 VOID
PpcVideoGetPaletteColor( UCHAR Color
,
159 UCHAR
*Red
, UCHAR
*Green
, UCHAR
*Blue
) {
160 printf( "GetPaletteColor(%x)\n", Color
);
163 VOID
PpcVideoSync() {
167 int mmu_initialized
= 0;
169 VOID
PpcInitializeMmu()
174 MmuDbgInit(0, 0x800003f8);
175 MmuSetMemorySize(mem_range_end
);
181 ULONG
PpcPrepGetMemoryMap( PBIOS_MEMORY_MAP BiosMemoryMap
,
182 ULONG MaxMemoryMapSize
);
185 * Get memory the proper openfirmware way
187 ULONG
PpcGetMemoryMap( PBIOS_MEMORY_MAP BiosMemoryMap
,
188 ULONG MaxMemoryMapSize
) {
189 int i
, memhandle
, total
= 0, slots
= 0, last
= 0x40000, allocstart
= 0x1000000;
192 printf("PpcGetMemoryMap(%d)\n", MaxMemoryMapSize
);
194 memhandle
= ofw_finddevice("/memory");
196 ofw_getprop(memhandle
, "reg", (char *)regdata
, sizeof(regdata
));
198 /* Try to claim some memory in usable blocks. Try to get some 8mb bits */
199 for( i
= 0; i
< sizeof(claimed
) / sizeof(claimed
[0]); ) {
201 claimed
[i
] = ofw_claim(allocstart
, 8 * 1024 * 1024, 0x1000);
203 allocstart
+= 8 * 1024 * 1024;
206 if (last
< claimed
[i
]) {
207 BiosMemoryMap
[slots
].Type
= BiosMemoryAcpiReclaim
;
208 BiosMemoryMap
[slots
].BaseAddress
= last
;
209 BiosMemoryMap
[slots
].Length
= claimed
[i
] - last
;
213 BiosMemoryMap
[slots
].Type
= BiosMemoryUsable
;
214 BiosMemoryMap
[slots
].BaseAddress
= claimed
[i
];
215 BiosMemoryMap
[slots
].Length
= 8 * 1024 * 1024;
217 total
+= BiosMemoryMap
[slots
].Length
;
219 BiosMemoryMap
[slots
].BaseAddress
+
220 BiosMemoryMap
[slots
].Length
;
226 /* Get the rest until the end of the memory object as we see it */
227 if (last
< regdata
[1]) {
228 BiosMemoryMap
[slots
].Type
= BiosMemoryAcpiReclaim
;
229 BiosMemoryMap
[slots
].BaseAddress
= last
;
230 BiosMemoryMap
[slots
].Length
= regdata
[1] - last
;
234 for (i
= 0; i
< slots
; i
++) {
235 printf("MemoryMap[%d] = (%x:%x)\n",
237 (int)BiosMemoryMap
[i
].BaseAddress
,
238 (int)BiosMemoryMap
[i
].Length
);
242 mem_range_end
= regdata
[1];
244 printf( "Returning memory map (%d entries, %dk free, %dk total ram)\n",
245 slots
, total
/ 1024, regdata
[1] / 1024 );
250 BOOLEAN
PpcDiskGetBootPath( char *OutBootPath
, unsigned Size
) {
251 strncpy( OutBootPath
, BootPath
, Size
);
255 BOOLEAN
PpcDiskReadLogicalSectors( ULONG DriveNumber
, ULONGLONG SectorNumber
,
256 ULONG SectorCount
, PVOID Buffer
) {
259 if( part_handle
== -1 ) {
260 part_handle
= ofw_open( BootPart
);
262 if( part_handle
== -1 ) {
263 printf("Could not open any disk devices we know about\n");
268 if( part_handle
== -1 ) {
269 printf("Got partition handle %x\n", part_handle
);
273 if( ofw_seek( part_handle
,
274 (ULONG
)(SectorNumber
>> 25),
275 (ULONG
)((SectorNumber
* 512) & 0xffffffff) ) ) {
276 printf("Seek to %x failed\n", (ULONG
)(SectorNumber
* 512));
280 rlen
= ofw_read( part_handle
, Buffer
, (ULONG
)(SectorCount
* 512) );
284 BOOLEAN
PpcDiskGetDriveGeometry( ULONG DriveNumber
, PGEOMETRY DriveGeometry
) {
285 printf("GetGeometry(%d)\n", DriveNumber
);
286 DriveGeometry
->BytesPerSector
= 512;
287 DriveGeometry
->Heads
= 16;
288 DriveGeometry
->Sectors
= 63;
292 ULONG
PpcDiskGetCacheableBlockCount( ULONG DriveNumber
) {
293 printf("GetCacheableBlockCount\n");
300 static TIMEINFO TimeInfo
;
301 //printf("PpcGetTime\n");
305 VOID
NarrowToWide(WCHAR
*wide_name
, char *name
)
308 WCHAR
*wide_name_ptr
;
309 for (wide_name_ptr
= wide_name
, copy_name
= name
;
310 (*wide_name_ptr
= *copy_name
);
311 wide_name_ptr
++, copy_name
++);
314 /* Recursively copy the device tree into our representation
315 * It'll be passed to HAL.
317 * When NT was first done on PPC, it was on PReP hardware, which is very
318 * like PC hardware (really, just a PPC on a PC motherboard). HAL can guess
319 * the addresses of needed resources in this scheme as it can on x86.
321 * Most PPC hardware doesn't assign fixed addresses to hardware, which is
322 * the problem that open firmware partially solves. It allows hardware makers
323 * much more leeway in building PPC systems. Unfortunately, because
324 * openfirmware as originally specified neither captures nor standardizes
325 * all possible information, and also because of bugs, most OSs use a hybrid
326 * configuration scheme that relies both on verification of devices and
327 * recording information from openfirmware to be treated as hints.
329 VOID OfwCopyDeviceTree
330 (PCONFIGURATION_COMPONENT_DATA ParentKey
,
334 ULONG
*DiskController
,
337 int proplen
= 0, node
= innode
;
338 char *prev_name
, cur_name
[64], data
[256], *slash
, devtype
[64];
339 wchar_t wide_name
[64];
340 PCONFIGURATION_COMPONENT_DATA NewKey
;
342 NarrowToWide(wide_name
, name
);
344 /* Create a key for this device */
345 FldrCreateComponentKey
348 MultiFunctionAdapter
,
358 for (prev_name
= ""; ofw_nextprop(node
, prev_name
, cur_name
) == 1; )
360 proplen
= ofw_getproplen(node
, cur_name
);
361 if (proplen
> 256 || proplen
< 0)
363 printf("Warning: not getting prop %s (too long: %d)\n",
367 ofw_getprop(node
, cur_name
, data
, sizeof(data
));
369 /* Get device type so we can examine it */
370 if (!strcmp(cur_name
, "device_type"))
371 strcpy(devtype
, (char *)data
);
373 NarrowToWide(wide_name
, cur_name
);
374 //RegSetValue(NewKey, wide_name, REG_BINARY, data, proplen);
376 strcpy(data
, cur_name
);
381 /* Special device handling */
382 if (!strcmp(devtype
, "ata"))
384 OfwHandleDiskController(NewKey
, node
, *DiskController
);
388 else if (!strcmp(devtype
, "disk"))
390 OfwHandleDiskObject(NewKey
, node
, *DiskController
, *DiskNumber
);
396 for (node
= ofw_child(node
); node
; node
= ofw_peer(node
))
398 ofw_package_to_path(node
, data
, sizeof(data
));
399 slash
= strrchr(data
, '/');
400 if (slash
) slash
++; else continue;
402 (NewKey
, slash
, node
, BusNumber
, DiskController
, DiskNumber
);
406 PCONFIGURATION_COMPONENT_DATA
PpcHwDetect() {
407 PCONFIGURATION_COMPONENT_DATA RootKey
;
408 ULONG BusNumber
= 0, DiskController
= 0, DiskNumber
= 0;
409 int node
= ofw_finddevice("/");
411 FldrCreateSystemKey(&RootKey
);
413 OfwCopyDeviceTree(RootKey
,"/",node
,&BusNumber
,&DiskController
,&DiskNumber
);
417 /* Compatibility functions that don't do much */
418 VOID
PpcVideoPrepareForReactOS(BOOLEAN Setup
) {
421 void PpcDefaultMachVtbl()
423 MachVtbl
.ConsPutChar
= PpcOfwPutChar
;
424 MachVtbl
.ConsKbHit
= PpcConsKbHit
;
425 MachVtbl
.ConsGetCh
= PpcConsGetCh
;
426 MachVtbl
.VideoClearScreen
= PpcVideoClearScreen
;
427 MachVtbl
.VideoSetDisplayMode
= PpcVideoSetDisplayMode
;
428 MachVtbl
.VideoGetDisplaySize
= PpcVideoGetDisplaySize
;
429 MachVtbl
.VideoGetBufferSize
= PpcVideoGetBufferSize
;
430 MachVtbl
.VideoSetTextCursorPosition
= PpcVideoSetTextCursorPosition
;
431 MachVtbl
.VideoHideShowTextCursor
= PpcVideoHideShowTextCursor
;
432 MachVtbl
.VideoPutChar
= PpcVideoPutChar
;
433 MachVtbl
.VideoCopyOffScreenBufferToVRAM
=
434 PpcVideoCopyOffScreenBufferToVRAM
;
435 MachVtbl
.VideoIsPaletteFixed
= PpcVideoIsPaletteFixed
;
436 MachVtbl
.VideoSetPaletteColor
= PpcVideoSetPaletteColor
;
437 MachVtbl
.VideoGetPaletteColor
= PpcVideoGetPaletteColor
;
438 MachVtbl
.VideoSync
= PpcVideoSync
;
439 MachVtbl
.VideoPrepareForReactOS
= PpcVideoPrepareForReactOS
;
441 MachVtbl
.GetMemoryMap
= PpcGetMemoryMap
;
443 MachVtbl
.DiskNormalizeSystemPath
= DiskNormalizeSystemPath
;
444 MachVtbl
.DiskGetBootPath
= PpcDiskGetBootPath
;
445 MachVtbl
.DiskReadLogicalSectors
= PpcDiskReadLogicalSectors
;
446 MachVtbl
.DiskGetDriveGeometry
= PpcDiskGetDriveGeometry
;
447 MachVtbl
.DiskGetCacheableBlockCount
= PpcDiskGetCacheableBlockCount
;
449 MachVtbl
.GetTime
= PpcGetTime
;
451 MachVtbl
.HwDetect
= PpcHwDetect
;
456 chosen_package
= ofw_finddevice( "/chosen" );
458 ofw_getprop(chosen_package
, "bootargs",
459 CmdLine
, sizeof(CmdLine
));
460 ofw_getprop( chosen_package
, "stdin",
461 (char *)&stdin_handle
, sizeof(stdin_handle
) );
462 ofw_getprop( chosen_package
, "stdout",
463 (char *)&stdout_handle
, sizeof(stdout_handle
) );
464 ofw_getprop( chosen_package
, "mmu",
465 (char *)&mmu_handle
, sizeof(mmu_handle
) );
467 // Allow forcing prep for broken OFW
468 if(!strncmp(CmdLine
, "bootprep", 8))
470 printf("Going to PREP init...\n");
476 printf( "FreeLDR version [%s]\n", GetFreeLoaderVersionString() );
481 void PpcInit( of_proxy the_ofproxy
) {
482 // Hack to be a bit easier on ram
483 CacheSizeLimit
= 64 * 1024;
484 ofproxy
= the_ofproxy
;
485 PpcDefaultMachVtbl();
486 if(ofproxy
) PpcOfwInit();
490 void MachInit(const char *CmdLine
) {
497 printf( "Determining boot device: [%s]\n", CmdLine
);
500 for( i
= 0; i
< strlen(CmdLine
); i
++ ) {
501 if( strncmp(CmdLine
+ i
, "boot=", 5) == 0) {
502 strcpy(BootPart
, CmdLine
+ i
+ 5);
503 sep
= strchr(BootPart
, ',');
506 while(CmdLine
[i
] && CmdLine
[i
]!=',') i
++;
510 if( strlen(BootPart
) == 0 ) {
512 len
= ofw_getprop(chosen_package
, "bootpath",
513 BootPath
, sizeof(BootPath
));
516 if( len
< 0 ) len
= 0;
518 printf( "Boot Path: %s\n", BootPath
);
520 sep
= strrchr(BootPath
, ',');
522 strcpy(BootPart
, BootPath
);
524 BootPart
[sep
- BootPath
] = 0;
528 printf( "FreeLDR starting (boot partition: %s)\n", BootPart
);
534 UCHAR NTAPI
READ_PORT_UCHAR(PUCHAR Address
) {
535 return GetPhysByte(((ULONG
)Address
)+0x80000000);
538 void WRITE_PORT_UCHAR(PUCHAR Address
, UCHAR Value
) {
539 SetPhysByte(((ULONG
)Address
)+0x80000000, Value
);
542 void DiskStopFloppyMotor() {
545 void BootOldLinuxKernel( unsigned long size
) {
549 void BootNewLinuxKernel() {
553 void ChainLoadBiosBootSectorCode() {
557 void DbgBreakPoint() {
558 __asm__("twi 31,0,0");