552b75fd056921a0139f7cefc9bd20efec8b74f8
[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( 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(PCHAR OutBootPath, ULONG Size) {
251 strncpy( OutBootPath, BootPath, Size );
252 return TRUE;
253 }
254
255 BOOLEAN PpcDiskReadLogicalSectors( ULONG DriveNumber, ULONGLONG SectorNumber,
256 ULONG SectorCount, PVOID Buffer ) {
257 int rlen = 0;
258
259 if( part_handle == -1 ) {
260 part_handle = ofw_open( BootPart );
261
262 if( part_handle == -1 ) {
263 printf("Could not open any disk devices we know about\n");
264 return FALSE;
265 }
266 }
267
268 if( part_handle == -1 ) {
269 printf("Got partition handle %x\n", part_handle);
270 return FALSE;
271 }
272
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));
277 return FALSE;
278 }
279
280 rlen = ofw_read( part_handle, Buffer, (ULONG)(SectorCount * 512) );
281 return rlen > 0;
282 }
283
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;
289 return TRUE;
290 }
291
292 ULONG PpcDiskGetCacheableBlockCount( ULONG DriveNumber ) {
293 printf("GetCacheableBlockCount\n");
294 return 1;
295 }
296
297 TIMEINFO*
298 PpcGetTime(VOID)
299 {
300 static TIMEINFO TimeInfo;
301 //printf("PpcGetTime\n");
302 return &TimeInfo;
303 }
304
305 VOID NarrowToWide(WCHAR *wide_name, char *name)
306 {
307 char *copy_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++);
312 }
313
314 /* Recursively copy the device tree into our representation
315 * It'll be passed to HAL.
316 *
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.
320 *
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.
328 */
329 VOID OfwCopyDeviceTree
330 (PCONFIGURATION_COMPONENT_DATA ParentKey,
331 char *name,
332 int innode,
333 ULONG *BusNumber,
334 ULONG *DiskController,
335 ULONG *DiskNumber)
336 {
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;
341
342 NarrowToWide(wide_name, name);
343
344 /* Create a key for this device */
345 FldrCreateComponentKey
346 (ParentKey,
347 AdapterClass,
348 MultiFunctionAdapter,
349 0,
350 0,
351 (ULONG)-1,
352 NULL,
353 NULL,
354 0,
355 &NewKey);
356
357 /* Add properties */
358 for (prev_name = ""; ofw_nextprop(node, prev_name, cur_name) == 1; )
359 {
360 proplen = ofw_getproplen(node, cur_name);
361 if (proplen > 256 || proplen < 0)
362 {
363 printf("Warning: not getting prop %s (too long: %d)\n",
364 cur_name, proplen);
365 continue;
366 }
367 ofw_getprop(node, cur_name, data, sizeof(data));
368
369 /* Get device type so we can examine it */
370 if (!strcmp(cur_name, "device_type"))
371 strcpy(devtype, (char *)data);
372
373 NarrowToWide(wide_name, cur_name);
374 //RegSetValue(NewKey, wide_name, REG_BINARY, data, proplen);
375
376 strcpy(data, cur_name);
377 prev_name = data;
378 }
379
380 #if 0
381 /* Special device handling */
382 if (!strcmp(devtype, "ata"))
383 {
384 OfwHandleDiskController(NewKey, node, *DiskController);
385 (*DiskController)++;
386 *DiskNumber = 0;
387 }
388 else if (!strcmp(devtype, "disk"))
389 {
390 OfwHandleDiskObject(NewKey, node, *DiskController, *DiskNumber);
391 (*DiskNumber)++;
392 }
393 #endif
394
395 /* Subdevices */
396 for (node = ofw_child(node); node; node = ofw_peer(node))
397 {
398 ofw_package_to_path(node, data, sizeof(data));
399 slash = strrchr(data, '/');
400 if (slash) slash++; else continue;
401 OfwCopyDeviceTree
402 (NewKey, slash, node, BusNumber, DiskController, DiskNumber);
403 }
404 }
405
406 PCONFIGURATION_COMPONENT_DATA PpcHwDetect() {
407 PCONFIGURATION_COMPONENT_DATA RootKey;
408 ULONG BusNumber = 0, DiskController = 0, DiskNumber = 0;
409 int node = ofw_finddevice("/");
410
411 FldrCreateSystemKey(&RootKey);
412
413 OfwCopyDeviceTree(RootKey,"/",node,&BusNumber,&DiskController,&DiskNumber);
414 return RootKey;
415 }
416
417 VOID
418 PpcHwIdle(VOID)
419 {
420 /* UNIMPLEMENTED */
421 }
422
423 void PpcDefaultMachVtbl()
424 {
425 MachVtbl.ConsPutChar = PpcOfwPutChar;
426 MachVtbl.ConsKbHit = PpcConsKbHit;
427 MachVtbl.ConsGetCh = PpcConsGetCh;
428 MachVtbl.VideoClearScreen = PpcVideoClearScreen;
429 MachVtbl.VideoSetDisplayMode = PpcVideoSetDisplayMode;
430 MachVtbl.VideoGetDisplaySize = PpcVideoGetDisplaySize;
431 MachVtbl.VideoGetBufferSize = PpcVideoGetBufferSize;
432 MachVtbl.VideoSetTextCursorPosition = PpcVideoSetTextCursorPosition;
433 MachVtbl.VideoHideShowTextCursor = PpcVideoHideShowTextCursor;
434 MachVtbl.VideoPutChar = PpcVideoPutChar;
435 MachVtbl.VideoCopyOffScreenBufferToVRAM =
436 PpcVideoCopyOffScreenBufferToVRAM;
437 MachVtbl.VideoIsPaletteFixed = PpcVideoIsPaletteFixed;
438 MachVtbl.VideoSetPaletteColor = PpcVideoSetPaletteColor;
439 MachVtbl.VideoGetPaletteColor = PpcVideoGetPaletteColor;
440 MachVtbl.VideoSync = PpcVideoSync;
441
442 MachVtbl.GetMemoryMap = PpcGetMemoryMap;
443
444 MachVtbl.DiskGetBootPath = PpcDiskGetBootPath;
445 MachVtbl.DiskReadLogicalSectors = PpcDiskReadLogicalSectors;
446 MachVtbl.DiskGetDriveGeometry = PpcDiskGetDriveGeometry;
447 MachVtbl.DiskGetCacheableBlockCount = PpcDiskGetCacheableBlockCount;
448
449 MachVtbl.GetTime = PpcGetTime;
450
451 MachVtbl.HwDetect = PpcHwDetect;
452 MachVtbl.HwIdle = PpcHwIdle;
453 }
454
455 void PpcOfwInit()
456 {
457 chosen_package = ofw_finddevice( "/chosen" );
458
459 ofw_getprop(chosen_package, "bootargs",
460 CmdLine, sizeof(CmdLine));
461 ofw_getprop( chosen_package, "stdin",
462 (char *)&stdin_handle, sizeof(stdin_handle) );
463 ofw_getprop( chosen_package, "stdout",
464 (char *)&stdout_handle, sizeof(stdout_handle) );
465 ofw_getprop( chosen_package, "mmu",
466 (char *)&mmu_handle, sizeof(mmu_handle) );
467
468 // Allow forcing prep for broken OFW
469 if(!strncmp(CmdLine, "bootprep", 8))
470 {
471 printf("Going to PREP init...\n");
472 ofproxy = NULL;
473 PpcPrepInit();
474 return;
475 }
476
477 printf( "FreeLDR version [%s]\n", GetFreeLoaderVersionString() );
478
479 BootMain( CmdLine );
480 }
481
482 void PpcInit( of_proxy the_ofproxy ) {
483 // Hack to be a bit easier on ram
484 CacheSizeLimit = 64 * 1024;
485 ofproxy = the_ofproxy;
486 PpcDefaultMachVtbl();
487 if(ofproxy) PpcOfwInit();
488 else PpcPrepInit();
489 }
490
491 void MachInit(const char *CmdLine) {
492 int i, len;
493 char *sep;
494
495 BootPart[0] = 0;
496 BootPath[0] = 0;
497
498 printf( "Determining boot device: [%s]\n", CmdLine );
499
500 sep = NULL;
501 for( i = 0; i < strlen(CmdLine); i++ ) {
502 if( strncmp(CmdLine + i, "boot=", 5) == 0) {
503 strcpy(BootPart, CmdLine + i + 5);
504 sep = strchr(BootPart, ',');
505 if( sep )
506 *sep = 0;
507 while(CmdLine[i] && CmdLine[i]!=',') i++;
508 }
509 }
510
511 if( strlen(BootPart) == 0 ) {
512 if (ofproxy)
513 len = ofw_getprop(chosen_package, "bootpath",
514 BootPath, sizeof(BootPath));
515 else
516 len = 0;
517 if( len < 0 ) len = 0;
518 BootPath[len] = 0;
519 printf( "Boot Path: %s\n", BootPath );
520
521 sep = strrchr(BootPath, ',');
522
523 strcpy(BootPart, BootPath);
524 if( sep ) {
525 BootPart[sep - BootPath] = 0;
526 }
527 }
528
529 printf( "FreeLDR starting (boot partition: %s)\n", BootPart );
530 }
531
532 void beep() {
533 }
534
535 UCHAR NTAPI READ_PORT_UCHAR(PUCHAR Address) {
536 return GetPhysByte(((ULONG)Address)+0x80000000);
537 }
538
539 void WRITE_PORT_UCHAR(PUCHAR Address, UCHAR Value) {
540 SetPhysByte(((ULONG)Address)+0x80000000, Value);
541 }
542
543 void DiskStopFloppyMotor() {
544 }
545
546 void BootOldLinuxKernel( unsigned long size ) {
547 ofw_exit();
548 }
549
550 void BootNewLinuxKernel() {
551 ofw_exit();
552 }
553
554 void ChainLoadBiosBootSectorCode() {
555 ofw_exit();
556 }
557
558 void DbgBreakPoint() {
559 __asm__("twi 31,0,0");
560 }