[FREELDR] Several changes regarding chainloading and Linux boot.
[reactos.git] / 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 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.
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( PSTR CmdLine );
27 extern ULONG CacheSizeLimit;
28 of_proxy ofproxy;
29 void *PageDirectoryStart, *PageDirectoryEnd;
30 static int chosen_package, stdin_handle, stdout_handle, part_handle = -1;
31 int mmu_handle = 0;
32 int claimed[4];
33 BOOLEAN AcpiPresent = FALSE;
34 CHAR FrLdrBootPath[MAX_PATH] = "", BootPart[MAX_PATH] = "", CmdLine[MAX_PATH] = "bootprep";
35 jmp_buf jmp;
36 volatile char *video_mem = 0;
37
38 void PpcOfwPutChar( int ch ) {
39 char buf[3];
40 if( ch == 0x0a ) { buf[0] = 0x0d; buf[1] = 0x0a; }
41 else { buf[0] = ch; buf[1] = 0; }
42 buf[2] = 0;
43 ofw_write(stdout_handle, buf, strlen(buf));
44 }
45
46 int PpcFindDevice( int depth, int parent, char *devname, int *nth ) {
47 static char buf[256];
48 int next = 0;
49 int gotname = 0;
50 int match = 0;
51 int i;
52
53 next = ofw_child( parent );
54
55 //printf( "next = %x\n", next );
56
57 gotname = ofw_getprop(parent, "name", buf, 256);
58
59 //printf( "gotname = %d\n", gotname );
60
61 match = !strncmp(buf, devname, strlen(devname));
62
63 if( !nth && match ) return parent;
64
65 for( i = 0; i < depth; i++ ) PpcOfwPutChar( ' ' );
66
67 if( depth == 1 ) {
68 if( gotname > 0 ) {
69 printf( "%c Name: %s\n", match ? '*' : ' ', buf );
70 } else {
71 printf( "- No name attribute for %x\n", parent );
72 }
73 }
74
75 while( !match && next ) {
76 i = PpcFindDevice( depth+1, next, devname, nth );
77 if( i ) return i;
78 next = ofw_peer( next );
79 }
80
81 return 0;
82 }
83
84 BOOLEAN PpcConsKbHit() {
85 return FALSE;
86 }
87
88 int PpcConsGetCh() {
89 char buf;
90 ofw_read( stdin_handle, &buf, 1 );
91 return buf;
92 }
93
94 void PpcVideoClearScreen( UCHAR Attr ) {
95 }
96
97 VOID PpcVideoGetDisplaySize( PULONG Width, PULONG Height, PULONG Depth ) {
98 *Width = 80;
99 *Height = 25;
100 *Depth = 16;
101 }
102
103 ULONG PpcVideoGetBufferSize() {
104 ULONG Width, Height, Depth;
105 MachVideoGetDisplaySize( &Width, &Height, &Depth );
106 return Width * Height * Depth / 8;
107 }
108
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() );
113 }
114 return VideoTextMode;
115 }
116
117 VOID PpcVideoSetTextCursorPosition( ULONG X, ULONG Y ) {
118 printf("SetTextCursorPosition(%d,%d)\n", X,Y);
119 }
120
121 VOID PpcVideoHideShowTextCursor( BOOLEAN Show ) {
122 printf("HideShowTextCursor(%s)\n", Show ? "true" : "false");
123 }
124
125 VOID PpcVideoPutChar( int Ch, UCHAR Attr, unsigned X, unsigned Y ) {
126 printf( "\033[%d;%dH%c", Y, X, Ch );
127 }
128
129 VOID PpcVideoCopyOffScreenBufferToVRAM( PVOID Buffer ) {
130 int i,j;
131 ULONG w,h,d;
132 PCHAR ChBuf = Buffer;
133 int offset = 0;
134
135 MachVideoGetDisplaySize( &w, &h, &d );
136
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);
143 }
144 }
145 }
146 }
147
148 BOOLEAN PpcVideoIsPaletteFixed() {
149 return FALSE;
150 }
151
152 VOID PpcVideoSetPaletteColor( UCHAR Color,
153 UCHAR Red, UCHAR Green, UCHAR Blue ) {
154 printf( "SetPaletteColor(%x,%x,%x,%x)\n", Color, Red, Green, Blue );
155 }
156
157 VOID PpcVideoGetPaletteColor( UCHAR Color,
158 UCHAR *Red, UCHAR *Green, UCHAR *Blue ) {
159 printf( "GetPaletteColor(%x)\n", Color);
160 }
161
162 VOID PpcVideoSync() {
163 printf( "Sync\n" );
164 }
165
166 int mmu_initialized = 0;
167 int mem_range_end;
168 VOID PpcInitializeMmu()
169 {
170 if(!mmu_initialized)
171 {
172 MmuInit();
173 MmuDbgInit(0, 0x800003f8);
174 MmuSetMemorySize(mem_range_end);
175 //MmuDbgEnter(0x20);
176 mmu_initialized = 1;
177 }
178 }
179
180 ULONG PpcPrepGetMemoryMap( PBIOS_MEMORY_MAP BiosMemoryMap,
181 ULONG MaxMemoryMapSize );
182
183 /*
184 * Get memory the proper openfirmware way
185 */
186 ULONG PpcGetMemoryMap( PBIOS_MEMORY_MAP BiosMemoryMap,
187 ULONG MaxMemoryMapSize ) {
188 int i, memhandle, total = 0, slots = 0, last = 0x40000, allocstart = 0x1000000;
189 int regdata[0x40];
190
191 printf("PpcGetMemoryMap(%d)\n", MaxMemoryMapSize);
192
193 memhandle = ofw_finddevice("/memory");
194
195 ofw_getprop(memhandle, "reg", (char *)regdata, sizeof(regdata));
196
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]); ) {
199 if (!claimed[i])
200 claimed[i] = ofw_claim(allocstart, 8 * 1024 * 1024, 0x1000);
201
202 allocstart += 8 * 1024 * 1024;
203
204 if (claimed[i]) {
205 if (last < claimed[i]) {
206 BiosMemoryMap[slots].Type = BiosMemoryAcpiReclaim;
207 BiosMemoryMap[slots].BaseAddress = last;
208 BiosMemoryMap[slots].Length = claimed[i] - last;
209 slots++;
210 }
211
212 BiosMemoryMap[slots].Type = BiosMemoryUsable;
213 BiosMemoryMap[slots].BaseAddress = claimed[i];
214 BiosMemoryMap[slots].Length = 8 * 1024 * 1024;
215
216 total += BiosMemoryMap[slots].Length;
217 last =
218 BiosMemoryMap[slots].BaseAddress +
219 BiosMemoryMap[slots].Length;
220 slots++;
221 i++;
222 }
223 }
224
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;
230 slots++;
231 }
232
233 for (i = 0; i < slots; i++) {
234 printf("MemoryMap[%d] = (%x:%x)\n",
235 i,
236 (int)BiosMemoryMap[i].BaseAddress,
237 (int)BiosMemoryMap[i].Length);
238
239 }
240
241 mem_range_end = regdata[1];
242
243 printf( "Returning memory map (%d entries, %dk free, %dk total ram)\n",
244 slots, total / 1024, regdata[1] / 1024 );
245
246 return slots;
247 }
248
249 BOOLEAN PpcDiskReadLogicalSectors( ULONG DriveNumber, ULONGLONG SectorNumber,
250 ULONG SectorCount, PVOID Buffer ) {
251 int rlen = 0;
252
253 if( part_handle == -1 ) {
254 part_handle = ofw_open( BootPart );
255
256 if( part_handle == -1 ) {
257 printf("Could not open any disk devices we know about\n");
258 return FALSE;
259 }
260 }
261
262 if( part_handle == -1 ) {
263 printf("Got partition handle %x\n", part_handle);
264 return FALSE;
265 }
266
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));
271 return FALSE;
272 }
273
274 rlen = ofw_read( part_handle, Buffer, (ULONG)(SectorCount * 512) );
275 return rlen > 0;
276 }
277
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;
283 return TRUE;
284 }
285
286 ULONG PpcDiskGetCacheableBlockCount( ULONG DriveNumber ) {
287 printf("GetCacheableBlockCount\n");
288 return 1;
289 }
290
291 TIMEINFO*
292 PpcGetTime(VOID)
293 {
294 static TIMEINFO TimeInfo;
295 //printf("PpcGetTime\n");
296 return &TimeInfo;
297 }
298
299 VOID NarrowToWide(WCHAR *wide_name, char *name)
300 {
301 char *copy_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++);
306 }
307
308 /* Recursively copy the device tree into our representation
309 * It'll be passed to HAL.
310 *
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.
314 *
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.
322 */
323 VOID OfwCopyDeviceTree
324 (PCONFIGURATION_COMPONENT_DATA ParentKey,
325 char *name,
326 int innode,
327 ULONG *BusNumber,
328 ULONG *DiskController,
329 ULONG *DiskNumber)
330 {
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;
335
336 NarrowToWide(wide_name, name);
337
338 /* Create a key for this device */
339 FldrCreateComponentKey
340 (ParentKey,
341 AdapterClass,
342 MultiFunctionAdapter,
343 0,
344 0,
345 (ULONG)-1,
346 NULL,
347 NULL,
348 0,
349 &NewKey);
350
351 /* Add properties */
352 for (prev_name = ""; ofw_nextprop(node, prev_name, cur_name) == 1; )
353 {
354 proplen = ofw_getproplen(node, cur_name);
355 if (proplen > 256 || proplen < 0)
356 {
357 printf("Warning: not getting prop %s (too long: %d)\n",
358 cur_name, proplen);
359 continue;
360 }
361 ofw_getprop(node, cur_name, data, sizeof(data));
362
363 /* Get device type so we can examine it */
364 if (!strcmp(cur_name, "device_type"))
365 strcpy(devtype, (char *)data);
366
367 NarrowToWide(wide_name, cur_name);
368 //RegSetValue(NewKey, wide_name, REG_BINARY, data, proplen);
369
370 strcpy(data, cur_name);
371 prev_name = data;
372 }
373
374 #if 0
375 /* Special device handling */
376 if (!strcmp(devtype, "ata"))
377 {
378 OfwHandleDiskController(NewKey, node, *DiskController);
379 (*DiskController)++;
380 *DiskNumber = 0;
381 }
382 else if (!strcmp(devtype, "disk"))
383 {
384 OfwHandleDiskObject(NewKey, node, *DiskController, *DiskNumber);
385 (*DiskNumber)++;
386 }
387 #endif
388
389 /* Subdevices */
390 for (node = ofw_child(node); node; node = ofw_peer(node))
391 {
392 ofw_package_to_path(node, data, sizeof(data));
393 slash = strrchr(data, '/');
394 if (slash) slash++; else continue;
395 OfwCopyDeviceTree
396 (NewKey, slash, node, BusNumber, DiskController, DiskNumber);
397 }
398 }
399
400 PCONFIGURATION_COMPONENT_DATA PpcHwDetect() {
401 PCONFIGURATION_COMPONENT_DATA RootKey;
402 ULONG BusNumber = 0, DiskController = 0, DiskNumber = 0;
403 int node = ofw_finddevice("/");
404
405 FldrCreateSystemKey(&RootKey);
406
407 OfwCopyDeviceTree(RootKey,"/",node,&BusNumber,&DiskController,&DiskNumber);
408 return RootKey;
409 }
410
411 VOID
412 PpcHwIdle(VOID)
413 {
414 /* UNIMPLEMENTED */
415 }
416
417 void PpcDefaultMachVtbl()
418 {
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;
435
436 MachVtbl.GetMemoryMap = PpcGetMemoryMap;
437
438 MachVtbl.DiskReadLogicalSectors = PpcDiskReadLogicalSectors;
439 MachVtbl.DiskGetDriveGeometry = PpcDiskGetDriveGeometry;
440 MachVtbl.DiskGetCacheableBlockCount = PpcDiskGetCacheableBlockCount;
441
442 MachVtbl.GetTime = PpcGetTime;
443
444 MachVtbl.HwDetect = PpcHwDetect;
445 MachVtbl.HwIdle = PpcHwIdle;
446 }
447
448 void PpcOfwInit()
449 {
450 chosen_package = ofw_finddevice( "/chosen" );
451
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) );
460
461 // Allow forcing prep for broken OFW
462 if(!strncmp(CmdLine, "bootprep", 8))
463 {
464 printf("Going to PREP init...\n");
465 ofproxy = NULL;
466 PpcPrepInit();
467 return;
468 }
469
470 printf( "FreeLDR version [%s]\n", FrLdrVersionString );
471
472 BootMain( CmdLine );
473 }
474
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();
481 else PpcPrepInit();
482 }
483
484 void MachInit(const char *CmdLine) {
485 int i, len;
486 char *sep;
487
488 BootPart[0] = 0;
489 FrLdrBootPath[0] = 0;
490
491 printf( "Determining boot device: [%s]\n", CmdLine );
492
493 sep = NULL;
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, ',');
498 if( sep )
499 *sep = 0;
500 while(CmdLine[i] && CmdLine[i]!=',') i++;
501 }
502 }
503
504 if( strlen(BootPart) == 0 ) {
505 if (ofproxy)
506 len = ofw_getprop(chosen_package, "bootpath",
507 FrLdrBootPath, sizeof(FrLdrBootPath));
508 else
509 len = 0;
510 if( len < 0 ) len = 0;
511 FrLdrBootPath[len] = 0;
512 printf( "Boot Path: %s\n", FrLdrBootPath );
513
514 sep = strrchr(FrLdrBootPath, ',');
515
516 strcpy(BootPart, FrLdrBootPath);
517 if( sep ) {
518 BootPart[sep - FrLdrBootPath] = 0;
519 }
520 }
521
522 printf( "FreeLDR starting (boot partition: %s)\n", BootPart );
523 }
524
525 void beep() {
526 }
527
528 UCHAR NTAPI READ_PORT_UCHAR(PUCHAR Address) {
529 return GetPhysByte(((ULONG)Address)+0x80000000);
530 }
531
532 void WRITE_PORT_UCHAR(PUCHAR Address, UCHAR Value) {
533 SetPhysByte(((ULONG)Address)+0x80000000, Value);
534 }
535
536 VOID __cdecl BootLinuxKernel(
537 IN ULONG KernelSize,
538 IN PVOID KernelCurrentLoadAddress,
539 IN PVOID KernelTargetLoadAddress,
540 IN UCHAR DriveNumber,
541 IN ULONG PartitionNumber)
542 {
543 ofw_exit();
544 }
545
546 VOID __cdecl ChainLoadBiosBootSectorCode(
547 IN UCHAR BootDrive OPTIONAL,
548 IN ULONG BootPartition OPTIONAL)
549 {
550 ofw_exit();
551 }
552
553 void DbgBreakPoint() {
554 __asm__("twi 31,0,0");
555 }