t's a bit embarrasing that some of this was undone until recently, but we now
[reactos.git] / reactos / boot / freeldr / freeldr / arch / powerpc / mach.c
1 /*
2 * FreeLoader PowerPC Part
3 * Copyright (C) 2005 Art Yerkes
4 *
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.
9 *
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.
14 *
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.
18 */
19 #include "freeldr.h"
20 #include "machine.h"
21 #include "ppcmmu/mmu.h"
22 #include "of.h"
23 #include "prep.h"
24 #include "compat.h"
25
26 extern void BootMain( LPSTR CmdLine );
27 extern PCHAR GetFreeLoaderVersionString();
28 extern ULONG CacheSizeLimit;
29 of_proxy ofproxy;
30 void *PageDirectoryStart, *PageDirectoryEnd;
31 static int chosen_package, stdin_handle, stdout_handle, part_handle = -1;
32 int mmu_handle = 0;
33 int claimed[4];
34 BOOLEAN AcpiPresent = FALSE;
35 char BootPath[0x100] = { 0 }, BootPart[0x100] = { 0 }, CmdLine[0x100] = { "bootprep" };
36 jmp_buf jmp;
37 volatile char *video_mem = 0;
38
39 void PpcOfwPutChar( int ch ) {
40 char buf[3];
41 if( ch == 0x0a ) { buf[0] = 0x0d; buf[1] = 0x0a; }
42 else { buf[0] = ch; buf[1] = 0; }
43 buf[2] = 0;
44 ofw_write(stdout_handle, buf, strlen(buf));
45 }
46
47 int PpcFindDevice( int depth, int parent, char *devname, int *nth ) {
48 static char buf[256];
49 int next = 0;
50 int gotname = 0;
51 int match = 0;
52 int i;
53
54 next = ofw_child( parent );
55
56 //printf( "next = %x\n", next );
57
58 gotname = ofw_getprop(parent, "name", buf, 256);
59
60 //printf( "gotname = %d\n", gotname );
61
62 match = !strncmp(buf, devname, strlen(devname));
63
64 if( !nth && match ) return parent;
65
66 for( i = 0; i < depth; i++ ) PpcOfwPutChar( ' ' );
67
68 if( depth == 1 ) {
69 if( gotname > 0 ) {
70 printf( "%c Name: %s\n", match ? '*' : ' ', buf );
71 } else {
72 printf( "- No name attribute for %x\n", parent );
73 }
74 }
75
76 while( !match && next ) {
77 i = PpcFindDevice( depth+1, next, devname, nth );
78 if( i ) return i;
79 next = ofw_peer( next );
80 }
81
82 return 0;
83 }
84
85 BOOLEAN PpcConsKbHit() {
86 return FALSE;
87 }
88
89 int PpcConsGetCh() {
90 char buf;
91 ofw_read( stdin_handle, &buf, 1 );
92 return buf;
93 }
94
95 void PpcVideoClearScreen( UCHAR Attr ) {
96 }
97
98 VOID PpcVideoGetDisplaySize( PULONG Width, PULONG Height, PULONG Depth ) {
99 *Width = 80;
100 *Height = 25;
101 *Depth = 16;
102 }
103
104 ULONG PpcVideoGetBufferSize() {
105 ULONG Width, Height, Depth;
106 MachVideoGetDisplaySize( &Width, &Height, &Depth );
107 return Width * Height * Depth / 8;
108 }
109
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() );
114 }
115 return VideoTextMode;
116 }
117
118 VOID PpcVideoSetTextCursorPosition( ULONG X, ULONG Y ) {
119 printf("SetTextCursorPosition(%d,%d)\n", X,Y);
120 }
121
122 VOID PpcVideoHideShowTextCursor( BOOLEAN Show ) {
123 printf("HideShowTextCursor(%s)\n", Show ? "true" : "false");
124 }
125
126 VOID PpcVideoPutChar( int Ch, UCHAR Attr, unsigned X, unsigned Y ) {
127 printf( "\033[%d;%dH%c", Y, X, Ch );
128 }
129
130 VOID PpcVideoCopyOffScreenBufferToVRAM( PVOID Buffer ) {
131 int i,j;
132 ULONG w,h,d;
133 PCHAR ChBuf = Buffer;
134 int offset = 0;
135
136 MachVideoGetDisplaySize( &w, &h, &d );
137
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);
144 }
145 }
146 }
147 }
148
149 BOOLEAN PpcVideoIsPaletteFixed() {
150 return FALSE;
151 }
152
153 VOID PpcVideoSetPaletteColor( UCHAR Color,
154 UCHAR Red, UCHAR Green, UCHAR Blue ) {
155 printf( "SetPaletteColor(%x,%x,%x,%x)\n", Color, Red, Green, Blue );
156 }
157
158 VOID PpcVideoGetPaletteColor( UCHAR Color,
159 UCHAR *Red, UCHAR *Green, UCHAR *Blue ) {
160 printf( "GetPaletteColor(%x)\n", Color);
161 }
162
163 VOID PpcVideoSync() {
164 printf( "Sync\n" );
165 }
166
167 int mmu_initialized = 0;
168 int mem_range_end;
169 VOID PpcInitializeMmu()
170 {
171 if(!mmu_initialized)
172 {
173 MmuInit();
174 MmuDbgInit(0, 0x800003f8);
175 MmuSetMemorySize(mem_range_end);
176 //MmuDbgEnter(0x20);
177 mmu_initialized = 1;
178 }
179 }
180
181 ULONG PpcPrepGetMemoryMap( PBIOS_MEMORY_MAP BiosMemoryMap,
182 ULONG MaxMemoryMapSize );
183
184 /*
185 * Get memory the proper openfirmware way
186 */
187 ULONG PpcGetMemoryMap( PBIOS_MEMORY_MAP BiosMemoryMap,
188 ULONG MaxMemoryMapSize ) {
189 int i, memhandle, total = 0, slots = 0, last = 0x40000, allocstart = 0x1000000;
190 int regdata[0x40];
191
192 printf("PpcGetMemoryMap(%d)\n", MaxMemoryMapSize);
193
194 memhandle = ofw_finddevice("/memory");
195
196 ofw_getprop(memhandle, "reg", (char *)regdata, sizeof(regdata));
197
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]); ) {
200 if (!claimed[i])
201 claimed[i] = ofw_claim(allocstart, 8 * 1024 * 1024, 0x1000);
202
203 allocstart += 8 * 1024 * 1024;
204
205 if (claimed[i]) {
206 if (last < claimed[i]) {
207 BiosMemoryMap[slots].Type = BiosMemoryAcpiReclaim;
208 BiosMemoryMap[slots].BaseAddress = last;
209 BiosMemoryMap[slots].Length = claimed[i] - last;
210 slots++;
211 }
212
213 BiosMemoryMap[slots].Type = BiosMemoryUsable;
214 BiosMemoryMap[slots].BaseAddress = claimed[i];
215 BiosMemoryMap[slots].Length = 8 * 1024 * 1024;
216
217 total += BiosMemoryMap[slots].Length;
218 last =
219 BiosMemoryMap[slots].BaseAddress +
220 BiosMemoryMap[slots].Length;
221 slots++;
222 i++;
223 }
224 }
225
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;
231 slots++;
232 }
233
234 for (i = 0; i < slots; i++) {
235 printf("MemoryMap[%d] = (%x:%x)\n",
236 i,
237 (int)BiosMemoryMap[i].BaseAddress,
238 (int)BiosMemoryMap[i].Length);
239
240 }
241
242 mem_range_end = regdata[1];
243
244 printf( "Returning memory map (%d entries, %dk free, %dk total ram)\n",
245 slots, total / 1024, regdata[1] / 1024 );
246
247 return slots;
248 }
249
250 /* Strategy:
251 *
252 * For now, it'll be easy enough to use the boot command line as our boot path.
253 * Treat it as the path of a disk partition. We might even be able to get
254 * away with grabbing a partition image by tftp in this scenario.
255 */
256
257 BOOLEAN PpcDiskGetBootVolume( PULONG DriveNumber, PULONGLONG StartSector, PULONGLONG SectorCount, int *FsType ) {
258 *DriveNumber = 0;
259 *StartSector = 0;
260 *SectorCount = 0;
261 *FsType = FS_FAT;
262 return TRUE;
263 }
264
265 BOOLEAN PpcDiskGetSystemVolume( char *SystemPath,
266 char *RemainingPath,
267 PULONG Device,
268 PULONG DriveNumber,
269 PULONGLONG StartSector,
270 PULONGLONG SectorCount,
271 int *FsType ) {
272 char *remain = strchr(SystemPath, '\\');
273 if( remain ) {
274 strcpy( RemainingPath, remain+1 );
275 } else {
276 RemainingPath[0] = 0;
277 }
278 *Device = 0;
279 // Hack to be a bit easier on ram
280 CacheSizeLimit = 64 * 1024;
281 return MachDiskGetBootVolume(DriveNumber, StartSector, SectorCount, FsType);
282 }
283
284 BOOLEAN PpcDiskGetBootPath( char *OutBootPath, unsigned Size ) {
285 strncpy( OutBootPath, BootPath, Size );
286 return TRUE;
287 }
288
289 VOID PpcDiskGetBootDevice( PULONG BootDevice ) {
290 BootDevice[0] = BootDevice[1] = 0;
291 }
292
293 BOOLEAN PpcDiskBootingFromFloppy(VOID) {
294 return FALSE;
295 }
296
297 BOOLEAN PpcDiskReadLogicalSectors( ULONG DriveNumber, ULONGLONG SectorNumber,
298 ULONG SectorCount, PVOID Buffer ) {
299 int rlen = 0;
300
301 if( part_handle == -1 ) {
302 part_handle = ofw_open( BootPart );
303
304 if( part_handle == -1 ) {
305 printf("Could not open any disk devices we know about\n");
306 return FALSE;
307 }
308 }
309
310 if( part_handle == -1 ) {
311 printf("Got partition handle %x\n", part_handle);
312 return FALSE;
313 }
314
315 if( ofw_seek( part_handle,
316 (ULONG)(SectorNumber >> 25),
317 (ULONG)((SectorNumber * 512) & 0xffffffff) ) ) {
318 printf("Seek to %x failed\n", (ULONG)(SectorNumber * 512));
319 return FALSE;
320 }
321
322 rlen = ofw_read( part_handle, Buffer, (ULONG)(SectorCount * 512) );
323 return rlen > 0;
324 }
325
326 BOOLEAN PpcDiskGetPartitionEntry( ULONG DriveNumber, ULONG PartitionNumber,
327 PPARTITION_TABLE_ENTRY PartitionTableEntry ) {
328 printf("GetPartitionEntry(%d,%d)\n", DriveNumber, PartitionNumber);
329 return FALSE;
330 }
331
332 BOOLEAN PpcDiskGetDriveGeometry( ULONG DriveNumber, PGEOMETRY DriveGeometry ) {
333 printf("GetGeometry(%d)\n", DriveNumber);
334 DriveGeometry->BytesPerSector = 512;
335 DriveGeometry->Heads = 16;
336 DriveGeometry->Sectors = 63;
337 return TRUE;
338 }
339
340 ULONG PpcDiskGetCacheableBlockCount( ULONG DriveNumber ) {
341 printf("GetCacheableBlockCount\n");
342 return 1;
343 }
344
345 VOID PpcRTCGetCurrentDateTime( PULONG Hear, PULONG Month, PULONG Day,
346 PULONG Hour, PULONG Minute, PULONG Second ) {
347 //printf("RTCGeturrentDateTime\n");
348 }
349
350 VOID NarrowToWide(WCHAR *wide_name, char *name)
351 {
352 char *copy_name;
353 WCHAR *wide_name_ptr;
354 for (wide_name_ptr = wide_name, copy_name = name;
355 (*wide_name_ptr = *copy_name);
356 wide_name_ptr++, copy_name++);
357 }
358
359 /* Recursively copy the device tree into our representation
360 * It'll be passed to HAL.
361 *
362 * When NT was first done on PPC, it was on PReP hardware, which is very
363 * like PC hardware (really, just a PPC on a PC motherboard). HAL can guess
364 * the addresses of needed resources in this scheme as it can on x86.
365 *
366 * Most PPC hardware doesn't assign fixed addresses to hardware, which is
367 * the problem that open firmware partially solves. It allows hardware makers
368 * much more leeway in building PPC systems. Unfortunately, because
369 * openfirmware as originally specified neither captures nor standardizes
370 * all possible information, and also because of bugs, most OSs use a hybrid
371 * configuration scheme that relies both on verification of devices and
372 * recording information from openfirmware to be treated as hints.
373 */
374 VOID OfwCopyDeviceTree
375 (PCONFIGURATION_COMPONENT_DATA ParentKey,
376 char *name,
377 int innode,
378 ULONG *BusNumber,
379 ULONG *DiskController,
380 ULONG *DiskNumber)
381 {
382 int proplen = 0, node = innode;
383 char *prev_name, cur_name[64], data[256], *slash, devtype[64];
384 wchar_t wide_name[64];
385 PCONFIGURATION_COMPONENT_DATA NewKey;
386
387 NarrowToWide(wide_name, name);
388
389 /* Create a key for this device */
390 FldrCreateComponentKey
391 (ParentKey,
392 wide_name,
393 0,
394 AdapterClass,
395 MultiFunctionAdapter,
396 &NewKey);
397
398 FldrSetComponentInformation(NewKey, 0, 0, (ULONG)-1);
399
400 /* Add properties */
401 for (prev_name = ""; ofw_nextprop(node, prev_name, cur_name) == 1; )
402 {
403 proplen = ofw_getproplen(node, cur_name);
404 if (proplen > 256 || proplen < 0)
405 {
406 printf("Warning: not getting prop %s (too long: %d)\n",
407 cur_name, proplen);
408 continue;
409 }
410 ofw_getprop(node, cur_name, data, sizeof(data));
411
412 /* Get device type so we can examine it */
413 if (!strcmp(cur_name, "device_type"))
414 strcpy(devtype, (char *)data);
415
416 NarrowToWide(wide_name, cur_name);
417 //RegSetValue(NewKey, wide_name, REG_BINARY, data, proplen);
418
419 strcpy(data, cur_name);
420 prev_name = data;
421 }
422
423 #if 0
424 /* Special device handling */
425 if (!strcmp(devtype, "ata"))
426 {
427 OfwHandleDiskController(NewKey, node, *DiskController);
428 (*DiskController)++;
429 *DiskNumber = 0;
430 }
431 else if (!strcmp(devtype, "disk"))
432 {
433 OfwHandleDiskObject(NewKey, node, *DiskController, *DiskNumber);
434 (*DiskNumber)++;
435 }
436 #endif
437
438 /* Subdevices */
439 for (node = ofw_child(node); node; node = ofw_peer(node))
440 {
441 ofw_package_to_path(node, data, sizeof(data));
442 slash = strrchr(data, '/');
443 if (slash) slash++; else continue;
444 OfwCopyDeviceTree
445 (NewKey, slash, node, BusNumber, DiskController, DiskNumber);
446 }
447 }
448
449 VOID PpcHwDetect() {
450 PCONFIGURATION_COMPONENT_DATA RootKey;
451 ULONG BusNumber = 0, DiskController = 0, DiskNumber = 0;
452 int node = ofw_finddevice("/");
453
454 FldrCreateSystemKey(&RootKey);
455
456 FldrSetComponentInformation(RootKey, 0, 0, (ULONG)-1);
457
458 OfwCopyDeviceTree(RootKey,"/",node,&BusNumber,&DiskController,&DiskNumber);
459 }
460
461 BOOLEAN PpcDiskNormalizeSystemPath(char *SystemPath, unsigned Size) {
462 CHAR BootPath[256];
463 ULONG PartitionNumber;
464 ULONG DriveNumber;
465 PARTITION_TABLE_ENTRY PartEntry;
466 char *p;
467
468 if (!DissectArcPath(SystemPath, BootPath, &DriveNumber, &PartitionNumber))
469 {
470 return FALSE;
471 }
472
473 if (0 != PartitionNumber)
474 {
475 return TRUE;
476 }
477
478 if (! DiskGetActivePartitionEntry(DriveNumber,
479 &PartEntry,
480 &PartitionNumber) ||
481 PartitionNumber < 1 || 9 < PartitionNumber)
482 {
483 return FALSE;
484 }
485
486 p = SystemPath;
487 while ('\0' != *p && 0 != _strnicmp(p, "partition(", 10)) {
488 p++;
489 }
490 p = strchr(p, ')');
491 if (NULL == p || '0' != *(p - 1)) {
492 return FALSE;
493 }
494 *(p - 1) = '0' + PartitionNumber;
495
496 return TRUE;
497 }
498
499 /* Compatibility functions that don't do much */
500 VOID PpcVideoPrepareForReactOS(BOOLEAN Setup) {
501 }
502
503 void PpcDefaultMachVtbl()
504 {
505 MachVtbl.ConsPutChar = PpcOfwPutChar;
506 MachVtbl.ConsKbHit = PpcConsKbHit;
507 MachVtbl.ConsGetCh = PpcConsGetCh;
508 MachVtbl.VideoClearScreen = PpcVideoClearScreen;
509 MachVtbl.VideoSetDisplayMode = PpcVideoSetDisplayMode;
510 MachVtbl.VideoGetDisplaySize = PpcVideoGetDisplaySize;
511 MachVtbl.VideoGetBufferSize = PpcVideoGetBufferSize;
512 MachVtbl.VideoSetTextCursorPosition = PpcVideoSetTextCursorPosition;
513 MachVtbl.VideoHideShowTextCursor = PpcVideoHideShowTextCursor;
514 MachVtbl.VideoPutChar = PpcVideoPutChar;
515 MachVtbl.VideoCopyOffScreenBufferToVRAM =
516 PpcVideoCopyOffScreenBufferToVRAM;
517 MachVtbl.VideoIsPaletteFixed = PpcVideoIsPaletteFixed;
518 MachVtbl.VideoSetPaletteColor = PpcVideoSetPaletteColor;
519 MachVtbl.VideoGetPaletteColor = PpcVideoGetPaletteColor;
520 MachVtbl.VideoSync = PpcVideoSync;
521 MachVtbl.VideoPrepareForReactOS = PpcVideoPrepareForReactOS;
522
523 MachVtbl.GetMemoryMap = PpcGetMemoryMap;
524
525 MachVtbl.DiskNormalizeSystemPath = PpcDiskNormalizeSystemPath;
526 MachVtbl.DiskGetBootVolume = PpcDiskGetBootVolume;
527 MachVtbl.DiskGetSystemVolume = PpcDiskGetSystemVolume;
528 MachVtbl.DiskGetBootPath = PpcDiskGetBootPath;
529 MachVtbl.DiskGetBootDevice = PpcDiskGetBootDevice;
530 MachVtbl.DiskBootingFromFloppy = PpcDiskBootingFromFloppy;
531 MachVtbl.DiskReadLogicalSectors = PpcDiskReadLogicalSectors;
532 MachVtbl.DiskGetPartitionEntry = PpcDiskGetPartitionEntry;
533 MachVtbl.DiskGetDriveGeometry = PpcDiskGetDriveGeometry;
534 MachVtbl.DiskGetCacheableBlockCount = PpcDiskGetCacheableBlockCount;
535
536 MachVtbl.RTCGetCurrentDateTime = PpcRTCGetCurrentDateTime;
537
538 MachVtbl.HwDetect = PpcHwDetect;
539 }
540
541 void PpcOfwInit()
542 {
543 chosen_package = ofw_finddevice( "/chosen" );
544
545 ofw_getprop(chosen_package, "bootargs",
546 CmdLine, sizeof(CmdLine));
547 ofw_getprop( chosen_package, "stdin",
548 (char *)&stdin_handle, sizeof(stdin_handle) );
549 ofw_getprop( chosen_package, "stdout",
550 (char *)&stdout_handle, sizeof(stdout_handle) );
551 ofw_getprop( chosen_package, "mmu",
552 (char *)&mmu_handle, sizeof(mmu_handle) );
553
554 // Allow forcing prep for broken OFW
555 if(!strncmp(CmdLine, "bootprep", 8))
556 {
557 printf("Going to PREP init...\n");
558 ofproxy = NULL;
559 PpcPrepInit();
560 return;
561 }
562
563 printf( "FreeLDR version [%s]\n", GetFreeLoaderVersionString() );
564
565 BootMain( CmdLine );
566 }
567
568 void PpcInit( of_proxy the_ofproxy ) {
569 ofproxy = the_ofproxy;
570 PpcDefaultMachVtbl();
571 if(ofproxy) PpcOfwInit();
572 else PpcPrepInit();
573 }
574
575 void MachInit(const char *CmdLine) {
576 int i, len;
577 char *sep;
578
579 BootPart[0] = 0;
580 BootPath[0] = 0;
581
582 printf( "Determining boot device: [%s]\n", CmdLine );
583
584 sep = NULL;
585 for( i = 0; i < strlen(CmdLine); i++ ) {
586 if( strncmp(CmdLine + i, "boot=", 5) == 0) {
587 strcpy(BootPart, CmdLine + i + 5);
588 sep = strchr(BootPart, ',');
589 if( sep )
590 *sep = 0;
591 while(CmdLine[i] && CmdLine[i]!=',') i++;
592 }
593 }
594
595 if( strlen(BootPart) == 0 ) {
596 if (ofproxy)
597 len = ofw_getprop(chosen_package, "bootpath",
598 BootPath, sizeof(BootPath));
599 else
600 len = 0;
601 if( len < 0 ) len = 0;
602 BootPath[len] = 0;
603 printf( "Boot Path: %s\n", BootPath );
604
605 sep = strrchr(BootPath, ',');
606
607 strcpy(BootPart, BootPath);
608 if( sep ) {
609 BootPart[sep - BootPath] = 0;
610 }
611 }
612
613 printf( "FreeLDR starting (boot partition: %s)\n", BootPart );
614 }
615
616 void beep() {
617 }
618
619 UCHAR NTAPI READ_PORT_UCHAR(PUCHAR Address) {
620 return GetPhysByte(((ULONG)Address)+0x80000000);
621 }
622
623 void WRITE_PORT_UCHAR(PUCHAR Address, UCHAR Value) {
624 SetPhysByte(((ULONG)Address)+0x80000000, Value);
625 }
626
627 void DiskStopFloppyMotor() {
628 }
629
630 void BootOldLinuxKernel( unsigned long size ) {
631 ofw_exit();
632 }
633
634 void BootNewLinuxKernel() {
635 ofw_exit();
636 }
637
638 void ChainLoadBiosBootSectorCode() {
639 ofw_exit();
640 }
641
642 void DbgBreakPoint() {
643 __asm__("twi 31,0,0");
644 }