Sync with trunk r43123
[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 BOOLEAN PpcDiskGetBootPath( char *OutBootPath, unsigned Size ) {
251 strncpy( OutBootPath, BootPath, Size );
252 return TRUE;
253 }
254
255 VOID PpcDiskGetBootDevice( PULONG BootDevice ) {
256 BootDevice[0] = BootDevice[1] = 0;
257 }
258
259 BOOLEAN PpcDiskBootingFromFloppy(VOID) {
260 return FALSE;
261 }
262
263 BOOLEAN PpcDiskReadLogicalSectors( ULONG DriveNumber, ULONGLONG SectorNumber,
264 ULONG SectorCount, PVOID Buffer ) {
265 int rlen = 0;
266
267 if( part_handle == -1 ) {
268 part_handle = ofw_open( BootPart );
269
270 if( part_handle == -1 ) {
271 printf("Could not open any disk devices we know about\n");
272 return FALSE;
273 }
274 }
275
276 if( part_handle == -1 ) {
277 printf("Got partition handle %x\n", part_handle);
278 return FALSE;
279 }
280
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));
285 return FALSE;
286 }
287
288 rlen = ofw_read( part_handle, Buffer, (ULONG)(SectorCount * 512) );
289 return rlen > 0;
290 }
291
292 BOOLEAN PpcDiskGetPartitionEntry( ULONG DriveNumber, ULONG PartitionNumber,
293 PPARTITION_TABLE_ENTRY PartitionTableEntry ) {
294 printf("GetPartitionEntry(%d,%d)\n", DriveNumber, PartitionNumber);
295 return FALSE;
296 }
297
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;
303 return TRUE;
304 }
305
306 ULONG PpcDiskGetCacheableBlockCount( ULONG DriveNumber ) {
307 printf("GetCacheableBlockCount\n");
308 return 1;
309 }
310
311 TIMEINFO*
312 PpcGetTime(VOID)
313 {
314 static TIMEINFO TimeInfo;
315 //printf("PpcGetTime\n");
316 return &TimeInfo;
317 }
318
319 VOID NarrowToWide(WCHAR *wide_name, char *name)
320 {
321 char *copy_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++);
326 }
327
328 /* Recursively copy the device tree into our representation
329 * It'll be passed to HAL.
330 *
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.
334 *
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.
342 */
343 VOID OfwCopyDeviceTree
344 (PCONFIGURATION_COMPONENT_DATA ParentKey,
345 char *name,
346 int innode,
347 ULONG *BusNumber,
348 ULONG *DiskController,
349 ULONG *DiskNumber)
350 {
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;
355
356 NarrowToWide(wide_name, name);
357
358 /* Create a key for this device */
359 FldrCreateComponentKey
360 (ParentKey,
361 AdapterClass,
362 MultiFunctionAdapter,
363 0,
364 0,
365 (ULONG)-1,
366 NULL,
367 NULL,
368 0,
369 &NewKey);
370
371 /* Add properties */
372 for (prev_name = ""; ofw_nextprop(node, prev_name, cur_name) == 1; )
373 {
374 proplen = ofw_getproplen(node, cur_name);
375 if (proplen > 256 || proplen < 0)
376 {
377 printf("Warning: not getting prop %s (too long: %d)\n",
378 cur_name, proplen);
379 continue;
380 }
381 ofw_getprop(node, cur_name, data, sizeof(data));
382
383 /* Get device type so we can examine it */
384 if (!strcmp(cur_name, "device_type"))
385 strcpy(devtype, (char *)data);
386
387 NarrowToWide(wide_name, cur_name);
388 //RegSetValue(NewKey, wide_name, REG_BINARY, data, proplen);
389
390 strcpy(data, cur_name);
391 prev_name = data;
392 }
393
394 #if 0
395 /* Special device handling */
396 if (!strcmp(devtype, "ata"))
397 {
398 OfwHandleDiskController(NewKey, node, *DiskController);
399 (*DiskController)++;
400 *DiskNumber = 0;
401 }
402 else if (!strcmp(devtype, "disk"))
403 {
404 OfwHandleDiskObject(NewKey, node, *DiskController, *DiskNumber);
405 (*DiskNumber)++;
406 }
407 #endif
408
409 /* Subdevices */
410 for (node = ofw_child(node); node; node = ofw_peer(node))
411 {
412 ofw_package_to_path(node, data, sizeof(data));
413 slash = strrchr(data, '/');
414 if (slash) slash++; else continue;
415 OfwCopyDeviceTree
416 (NewKey, slash, node, BusNumber, DiskController, DiskNumber);
417 }
418 }
419
420 PCONFIGURATION_COMPONENT_DATA PpcHwDetect() {
421 PCONFIGURATION_COMPONENT_DATA RootKey;
422 ULONG BusNumber = 0, DiskController = 0, DiskNumber = 0;
423 int node = ofw_finddevice("/");
424
425 FldrCreateSystemKey(&RootKey);
426
427 OfwCopyDeviceTree(RootKey,"/",node,&BusNumber,&DiskController,&DiskNumber);
428 return RootKey;
429 }
430
431 BOOLEAN PpcDiskNormalizeSystemPath(char *SystemPath, unsigned Size) {
432 CHAR BootPath[256];
433 ULONG PartitionNumber;
434 ULONG DriveNumber;
435 PARTITION_TABLE_ENTRY PartEntry;
436 char *p;
437
438 if (!DissectArcPath(SystemPath, BootPath, &DriveNumber, &PartitionNumber))
439 {
440 return FALSE;
441 }
442
443 if (0 != PartitionNumber)
444 {
445 return TRUE;
446 }
447
448 if (! DiskGetActivePartitionEntry(DriveNumber,
449 &PartEntry,
450 &PartitionNumber) ||
451 PartitionNumber < 1 || 9 < PartitionNumber)
452 {
453 return FALSE;
454 }
455
456 p = SystemPath;
457 while ('\0' != *p && 0 != _strnicmp(p, "partition(", 10)) {
458 p++;
459 }
460 p = strchr(p, ')');
461 if (NULL == p || '0' != *(p - 1)) {
462 return FALSE;
463 }
464 *(p - 1) = '0' + PartitionNumber;
465
466 return TRUE;
467 }
468
469 /* Compatibility functions that don't do much */
470 VOID PpcVideoPrepareForReactOS(BOOLEAN Setup) {
471 }
472
473 void PpcDefaultMachVtbl()
474 {
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;
492
493 MachVtbl.GetMemoryMap = PpcGetMemoryMap;
494
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;
503
504 MachVtbl.GetTime = PpcGetTime;
505
506 MachVtbl.HwDetect = PpcHwDetect;
507 }
508
509 void PpcOfwInit()
510 {
511 chosen_package = ofw_finddevice( "/chosen" );
512
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) );
521
522 // Allow forcing prep for broken OFW
523 if(!strncmp(CmdLine, "bootprep", 8))
524 {
525 printf("Going to PREP init...\n");
526 ofproxy = NULL;
527 PpcPrepInit();
528 return;
529 }
530
531 printf( "FreeLDR version [%s]\n", GetFreeLoaderVersionString() );
532
533 BootMain( CmdLine );
534 }
535
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();
542 else PpcPrepInit();
543 }
544
545 void MachInit(const char *CmdLine) {
546 int i, len;
547 char *sep;
548
549 BootPart[0] = 0;
550 BootPath[0] = 0;
551
552 printf( "Determining boot device: [%s]\n", CmdLine );
553
554 sep = NULL;
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, ',');
559 if( sep )
560 *sep = 0;
561 while(CmdLine[i] && CmdLine[i]!=',') i++;
562 }
563 }
564
565 if( strlen(BootPart) == 0 ) {
566 if (ofproxy)
567 len = ofw_getprop(chosen_package, "bootpath",
568 BootPath, sizeof(BootPath));
569 else
570 len = 0;
571 if( len < 0 ) len = 0;
572 BootPath[len] = 0;
573 printf( "Boot Path: %s\n", BootPath );
574
575 sep = strrchr(BootPath, ',');
576
577 strcpy(BootPart, BootPath);
578 if( sep ) {
579 BootPart[sep - BootPath] = 0;
580 }
581 }
582
583 printf( "FreeLDR starting (boot partition: %s)\n", BootPart );
584 }
585
586 void beep() {
587 }
588
589 UCHAR NTAPI READ_PORT_UCHAR(PUCHAR Address) {
590 return GetPhysByte(((ULONG)Address)+0x80000000);
591 }
592
593 void WRITE_PORT_UCHAR(PUCHAR Address, UCHAR Value) {
594 SetPhysByte(((ULONG)Address)+0x80000000, Value);
595 }
596
597 void DiskStopFloppyMotor() {
598 }
599
600 void BootOldLinuxKernel( unsigned long size ) {
601 ofw_exit();
602 }
603
604 void BootNewLinuxKernel() {
605 ofw_exit();
606 }
607
608 void ChainLoadBiosBootSectorCode() {
609 ofw_exit();
610 }
611
612 void DbgBreakPoint() {
613 __asm__("twi 31,0,0");
614 }