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 VOID
PpcDiskGetBootDevice( PULONG BootDevice
) {
256 BootDevice
[0] = BootDevice
[1] = 0;
259 BOOLEAN
PpcDiskBootingFromFloppy(VOID
) {
263 BOOLEAN
PpcDiskReadLogicalSectors( ULONG DriveNumber
, ULONGLONG SectorNumber
,
264 ULONG SectorCount
, PVOID Buffer
) {
267 if( part_handle
== -1 ) {
268 part_handle
= ofw_open( BootPart
);
270 if( part_handle
== -1 ) {
271 printf("Could not open any disk devices we know about\n");
276 if( part_handle
== -1 ) {
277 printf("Got partition handle %x\n", part_handle
);
281 if( ofw_seek( part_handle
,
282 (ULONG
)(SectorNumber
>> 25),
283 (ULONG
)((SectorNumber
* 512) & 0xffffffff) ) ) {
284 printf("Seek to %x failed\n", (ULONG
)(SectorNumber
* 512));
288 rlen
= ofw_read( part_handle
, Buffer
, (ULONG
)(SectorCount
* 512) );
292 BOOLEAN
PpcDiskGetPartitionEntry( ULONG DriveNumber
, ULONG PartitionNumber
,
293 PPARTITION_TABLE_ENTRY PartitionTableEntry
) {
294 printf("GetPartitionEntry(%d,%d)\n", DriveNumber
, PartitionNumber
);
298 BOOLEAN
PpcDiskGetDriveGeometry( ULONG DriveNumber
, PGEOMETRY DriveGeometry
) {
299 printf("GetGeometry(%d)\n", DriveNumber
);
300 DriveGeometry
->BytesPerSector
= 512;
301 DriveGeometry
->Heads
= 16;
302 DriveGeometry
->Sectors
= 63;
306 ULONG
PpcDiskGetCacheableBlockCount( ULONG DriveNumber
) {
307 printf("GetCacheableBlockCount\n");
314 static TIMEINFO TimeInfo
;
315 //printf("PpcGetTime\n");
319 VOID
NarrowToWide(WCHAR
*wide_name
, char *name
)
322 WCHAR
*wide_name_ptr
;
323 for (wide_name_ptr
= wide_name
, copy_name
= name
;
324 (*wide_name_ptr
= *copy_name
);
325 wide_name_ptr
++, copy_name
++);
328 /* Recursively copy the device tree into our representation
329 * It'll be passed to HAL.
331 * When NT was first done on PPC, it was on PReP hardware, which is very
332 * like PC hardware (really, just a PPC on a PC motherboard). HAL can guess
333 * the addresses of needed resources in this scheme as it can on x86.
335 * Most PPC hardware doesn't assign fixed addresses to hardware, which is
336 * the problem that open firmware partially solves. It allows hardware makers
337 * much more leeway in building PPC systems. Unfortunately, because
338 * openfirmware as originally specified neither captures nor standardizes
339 * all possible information, and also because of bugs, most OSs use a hybrid
340 * configuration scheme that relies both on verification of devices and
341 * recording information from openfirmware to be treated as hints.
343 VOID OfwCopyDeviceTree
344 (PCONFIGURATION_COMPONENT_DATA ParentKey
,
348 ULONG
*DiskController
,
351 int proplen
= 0, node
= innode
;
352 char *prev_name
, cur_name
[64], data
[256], *slash
, devtype
[64];
353 wchar_t wide_name
[64];
354 PCONFIGURATION_COMPONENT_DATA NewKey
;
356 NarrowToWide(wide_name
, name
);
358 /* Create a key for this device */
359 FldrCreateComponentKey
362 MultiFunctionAdapter
,
372 for (prev_name
= ""; ofw_nextprop(node
, prev_name
, cur_name
) == 1; )
374 proplen
= ofw_getproplen(node
, cur_name
);
375 if (proplen
> 256 || proplen
< 0)
377 printf("Warning: not getting prop %s (too long: %d)\n",
381 ofw_getprop(node
, cur_name
, data
, sizeof(data
));
383 /* Get device type so we can examine it */
384 if (!strcmp(cur_name
, "device_type"))
385 strcpy(devtype
, (char *)data
);
387 NarrowToWide(wide_name
, cur_name
);
388 //RegSetValue(NewKey, wide_name, REG_BINARY, data, proplen);
390 strcpy(data
, cur_name
);
395 /* Special device handling */
396 if (!strcmp(devtype
, "ata"))
398 OfwHandleDiskController(NewKey
, node
, *DiskController
);
402 else if (!strcmp(devtype
, "disk"))
404 OfwHandleDiskObject(NewKey
, node
, *DiskController
, *DiskNumber
);
410 for (node
= ofw_child(node
); node
; node
= ofw_peer(node
))
412 ofw_package_to_path(node
, data
, sizeof(data
));
413 slash
= strrchr(data
, '/');
414 if (slash
) slash
++; else continue;
416 (NewKey
, slash
, node
, BusNumber
, DiskController
, DiskNumber
);
420 PCONFIGURATION_COMPONENT_DATA
PpcHwDetect() {
421 PCONFIGURATION_COMPONENT_DATA RootKey
;
422 ULONG BusNumber
= 0, DiskController
= 0, DiskNumber
= 0;
423 int node
= ofw_finddevice("/");
425 FldrCreateSystemKey(&RootKey
);
427 OfwCopyDeviceTree(RootKey
,"/",node
,&BusNumber
,&DiskController
,&DiskNumber
);
431 BOOLEAN
PpcDiskNormalizeSystemPath(char *SystemPath
, unsigned Size
) {
433 ULONG PartitionNumber
;
435 PARTITION_TABLE_ENTRY PartEntry
;
438 if (!DissectArcPath(SystemPath
, BootPath
, &DriveNumber
, &PartitionNumber
))
443 if (0 != PartitionNumber
)
448 if (! DiskGetActivePartitionEntry(DriveNumber
,
451 PartitionNumber
< 1 || 9 < PartitionNumber
)
457 while ('\0' != *p
&& 0 != _strnicmp(p
, "partition(", 10)) {
461 if (NULL
== p
|| '0' != *(p
- 1)) {
464 *(p
- 1) = '0' + PartitionNumber
;
469 /* Compatibility functions that don't do much */
470 VOID
PpcVideoPrepareForReactOS(BOOLEAN Setup
) {
473 void PpcDefaultMachVtbl()
475 MachVtbl
.ConsPutChar
= PpcOfwPutChar
;
476 MachVtbl
.ConsKbHit
= PpcConsKbHit
;
477 MachVtbl
.ConsGetCh
= PpcConsGetCh
;
478 MachVtbl
.VideoClearScreen
= PpcVideoClearScreen
;
479 MachVtbl
.VideoSetDisplayMode
= PpcVideoSetDisplayMode
;
480 MachVtbl
.VideoGetDisplaySize
= PpcVideoGetDisplaySize
;
481 MachVtbl
.VideoGetBufferSize
= PpcVideoGetBufferSize
;
482 MachVtbl
.VideoSetTextCursorPosition
= PpcVideoSetTextCursorPosition
;
483 MachVtbl
.VideoHideShowTextCursor
= PpcVideoHideShowTextCursor
;
484 MachVtbl
.VideoPutChar
= PpcVideoPutChar
;
485 MachVtbl
.VideoCopyOffScreenBufferToVRAM
=
486 PpcVideoCopyOffScreenBufferToVRAM
;
487 MachVtbl
.VideoIsPaletteFixed
= PpcVideoIsPaletteFixed
;
488 MachVtbl
.VideoSetPaletteColor
= PpcVideoSetPaletteColor
;
489 MachVtbl
.VideoGetPaletteColor
= PpcVideoGetPaletteColor
;
490 MachVtbl
.VideoSync
= PpcVideoSync
;
491 MachVtbl
.VideoPrepareForReactOS
= PpcVideoPrepareForReactOS
;
493 MachVtbl
.GetMemoryMap
= PpcGetMemoryMap
;
495 MachVtbl
.DiskNormalizeSystemPath
= PpcDiskNormalizeSystemPath
;
496 MachVtbl
.DiskGetBootPath
= PpcDiskGetBootPath
;
497 MachVtbl
.DiskGetBootDevice
= PpcDiskGetBootDevice
;
498 MachVtbl
.DiskBootingFromFloppy
= PpcDiskBootingFromFloppy
;
499 MachVtbl
.DiskReadLogicalSectors
= PpcDiskReadLogicalSectors
;
500 MachVtbl
.DiskGetPartitionEntry
= PpcDiskGetPartitionEntry
;
501 MachVtbl
.DiskGetDriveGeometry
= PpcDiskGetDriveGeometry
;
502 MachVtbl
.DiskGetCacheableBlockCount
= PpcDiskGetCacheableBlockCount
;
504 MachVtbl
.GetTime
= PpcGetTime
;
506 MachVtbl
.HwDetect
= PpcHwDetect
;
511 chosen_package
= ofw_finddevice( "/chosen" );
513 ofw_getprop(chosen_package
, "bootargs",
514 CmdLine
, sizeof(CmdLine
));
515 ofw_getprop( chosen_package
, "stdin",
516 (char *)&stdin_handle
, sizeof(stdin_handle
) );
517 ofw_getprop( chosen_package
, "stdout",
518 (char *)&stdout_handle
, sizeof(stdout_handle
) );
519 ofw_getprop( chosen_package
, "mmu",
520 (char *)&mmu_handle
, sizeof(mmu_handle
) );
522 // Allow forcing prep for broken OFW
523 if(!strncmp(CmdLine
, "bootprep", 8))
525 printf("Going to PREP init...\n");
531 printf( "FreeLDR version [%s]\n", GetFreeLoaderVersionString() );
536 void PpcInit( of_proxy the_ofproxy
) {
537 // Hack to be a bit easier on ram
538 CacheSizeLimit
= 64 * 1024;
539 ofproxy
= the_ofproxy
;
540 PpcDefaultMachVtbl();
541 if(ofproxy
) PpcOfwInit();
545 void MachInit(const char *CmdLine
) {
552 printf( "Determining boot device: [%s]\n", CmdLine
);
555 for( i
= 0; i
< strlen(CmdLine
); i
++ ) {
556 if( strncmp(CmdLine
+ i
, "boot=", 5) == 0) {
557 strcpy(BootPart
, CmdLine
+ i
+ 5);
558 sep
= strchr(BootPart
, ',');
561 while(CmdLine
[i
] && CmdLine
[i
]!=',') i
++;
565 if( strlen(BootPart
) == 0 ) {
567 len
= ofw_getprop(chosen_package
, "bootpath",
568 BootPath
, sizeof(BootPath
));
571 if( len
< 0 ) len
= 0;
573 printf( "Boot Path: %s\n", BootPath
);
575 sep
= strrchr(BootPath
, ',');
577 strcpy(BootPart
, BootPath
);
579 BootPart
[sep
- BootPath
] = 0;
583 printf( "FreeLDR starting (boot partition: %s)\n", BootPart
);
589 UCHAR NTAPI
READ_PORT_UCHAR(PUCHAR Address
) {
590 return GetPhysByte(((ULONG
)Address
)+0x80000000);
593 void WRITE_PORT_UCHAR(PUCHAR Address
, UCHAR Value
) {
594 SetPhysByte(((ULONG
)Address
)+0x80000000, Value
);
597 void DiskStopFloppyMotor() {
600 void BootOldLinuxKernel( unsigned long size
) {
604 void BootNewLinuxKernel() {
608 void ChainLoadBiosBootSectorCode() {
612 void DbgBreakPoint() {
613 __asm__("twi 31,0,0");