[FREELDR] Limit the usage of DiskStopFloppyMotor() in hardware/platform-specific...
[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 const PCSTR GetFreeLoaderVersionString(VOID);
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 FrldrBootPath[MAX_PATH] = "", BootPart[MAX_PATH] = "", CmdLine[MAX_PATH] = "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 PpcDiskReadLogicalSectors( ULONG DriveNumber, ULONGLONG SectorNumber,
251 ULONG SectorCount, PVOID Buffer ) {
252 int rlen = 0;
253
254 if( part_handle == -1 ) {
255 part_handle = ofw_open( BootPart );
256
257 if( part_handle == -1 ) {
258 printf("Could not open any disk devices we know about\n");
259 return FALSE;
260 }
261 }
262
263 if( part_handle == -1 ) {
264 printf("Got partition handle %x\n", part_handle);
265 return FALSE;
266 }
267
268 if( ofw_seek( part_handle,
269 (ULONG)(SectorNumber >> 25),
270 (ULONG)((SectorNumber * 512) & 0xffffffff) ) ) {
271 printf("Seek to %x failed\n", (ULONG)(SectorNumber * 512));
272 return FALSE;
273 }
274
275 rlen = ofw_read( part_handle, Buffer, (ULONG)(SectorCount * 512) );
276 return rlen > 0;
277 }
278
279 BOOLEAN PpcDiskGetDriveGeometry( ULONG DriveNumber, PGEOMETRY DriveGeometry ) {
280 printf("GetGeometry(%d)\n", DriveNumber);
281 DriveGeometry->BytesPerSector = 512;
282 DriveGeometry->Heads = 16;
283 DriveGeometry->Sectors = 63;
284 return TRUE;
285 }
286
287 ULONG PpcDiskGetCacheableBlockCount( ULONG DriveNumber ) {
288 printf("GetCacheableBlockCount\n");
289 return 1;
290 }
291
292 TIMEINFO*
293 PpcGetTime(VOID)
294 {
295 static TIMEINFO TimeInfo;
296 //printf("PpcGetTime\n");
297 return &TimeInfo;
298 }
299
300 VOID NarrowToWide(WCHAR *wide_name, char *name)
301 {
302 char *copy_name;
303 WCHAR *wide_name_ptr;
304 for (wide_name_ptr = wide_name, copy_name = name;
305 (*wide_name_ptr = *copy_name);
306 wide_name_ptr++, copy_name++);
307 }
308
309 /* Recursively copy the device tree into our representation
310 * It'll be passed to HAL.
311 *
312 * When NT was first done on PPC, it was on PReP hardware, which is very
313 * like PC hardware (really, just a PPC on a PC motherboard). HAL can guess
314 * the addresses of needed resources in this scheme as it can on x86.
315 *
316 * Most PPC hardware doesn't assign fixed addresses to hardware, which is
317 * the problem that open firmware partially solves. It allows hardware makers
318 * much more leeway in building PPC systems. Unfortunately, because
319 * openfirmware as originally specified neither captures nor standardizes
320 * all possible information, and also because of bugs, most OSs use a hybrid
321 * configuration scheme that relies both on verification of devices and
322 * recording information from openfirmware to be treated as hints.
323 */
324 VOID OfwCopyDeviceTree
325 (PCONFIGURATION_COMPONENT_DATA ParentKey,
326 char *name,
327 int innode,
328 ULONG *BusNumber,
329 ULONG *DiskController,
330 ULONG *DiskNumber)
331 {
332 int proplen = 0, node = innode;
333 char *prev_name, cur_name[64], data[256], *slash, devtype[64];
334 wchar_t wide_name[64];
335 PCONFIGURATION_COMPONENT_DATA NewKey;
336
337 NarrowToWide(wide_name, name);
338
339 /* Create a key for this device */
340 FldrCreateComponentKey
341 (ParentKey,
342 AdapterClass,
343 MultiFunctionAdapter,
344 0,
345 0,
346 (ULONG)-1,
347 NULL,
348 NULL,
349 0,
350 &NewKey);
351
352 /* Add properties */
353 for (prev_name = ""; ofw_nextprop(node, prev_name, cur_name) == 1; )
354 {
355 proplen = ofw_getproplen(node, cur_name);
356 if (proplen > 256 || proplen < 0)
357 {
358 printf("Warning: not getting prop %s (too long: %d)\n",
359 cur_name, proplen);
360 continue;
361 }
362 ofw_getprop(node, cur_name, data, sizeof(data));
363
364 /* Get device type so we can examine it */
365 if (!strcmp(cur_name, "device_type"))
366 strcpy(devtype, (char *)data);
367
368 NarrowToWide(wide_name, cur_name);
369 //RegSetValue(NewKey, wide_name, REG_BINARY, data, proplen);
370
371 strcpy(data, cur_name);
372 prev_name = data;
373 }
374
375 #if 0
376 /* Special device handling */
377 if (!strcmp(devtype, "ata"))
378 {
379 OfwHandleDiskController(NewKey, node, *DiskController);
380 (*DiskController)++;
381 *DiskNumber = 0;
382 }
383 else if (!strcmp(devtype, "disk"))
384 {
385 OfwHandleDiskObject(NewKey, node, *DiskController, *DiskNumber);
386 (*DiskNumber)++;
387 }
388 #endif
389
390 /* Subdevices */
391 for (node = ofw_child(node); node; node = ofw_peer(node))
392 {
393 ofw_package_to_path(node, data, sizeof(data));
394 slash = strrchr(data, '/');
395 if (slash) slash++; else continue;
396 OfwCopyDeviceTree
397 (NewKey, slash, node, BusNumber, DiskController, DiskNumber);
398 }
399 }
400
401 PCONFIGURATION_COMPONENT_DATA PpcHwDetect() {
402 PCONFIGURATION_COMPONENT_DATA RootKey;
403 ULONG BusNumber = 0, DiskController = 0, DiskNumber = 0;
404 int node = ofw_finddevice("/");
405
406 FldrCreateSystemKey(&RootKey);
407
408 OfwCopyDeviceTree(RootKey,"/",node,&BusNumber,&DiskController,&DiskNumber);
409 return RootKey;
410 }
411
412 VOID
413 PpcHwIdle(VOID)
414 {
415 /* UNIMPLEMENTED */
416 }
417
418 void PpcDefaultMachVtbl()
419 {
420 MachVtbl.ConsPutChar = PpcOfwPutChar;
421 MachVtbl.ConsKbHit = PpcConsKbHit;
422 MachVtbl.ConsGetCh = PpcConsGetCh;
423 MachVtbl.VideoClearScreen = PpcVideoClearScreen;
424 MachVtbl.VideoSetDisplayMode = PpcVideoSetDisplayMode;
425 MachVtbl.VideoGetDisplaySize = PpcVideoGetDisplaySize;
426 MachVtbl.VideoGetBufferSize = PpcVideoGetBufferSize;
427 MachVtbl.VideoSetTextCursorPosition = PpcVideoSetTextCursorPosition;
428 MachVtbl.VideoHideShowTextCursor = PpcVideoHideShowTextCursor;
429 MachVtbl.VideoPutChar = PpcVideoPutChar;
430 MachVtbl.VideoCopyOffScreenBufferToVRAM =
431 PpcVideoCopyOffScreenBufferToVRAM;
432 MachVtbl.VideoIsPaletteFixed = PpcVideoIsPaletteFixed;
433 MachVtbl.VideoSetPaletteColor = PpcVideoSetPaletteColor;
434 MachVtbl.VideoGetPaletteColor = PpcVideoGetPaletteColor;
435 MachVtbl.VideoSync = PpcVideoSync;
436
437 MachVtbl.GetMemoryMap = PpcGetMemoryMap;
438
439 MachVtbl.DiskReadLogicalSectors = PpcDiskReadLogicalSectors;
440 MachVtbl.DiskGetDriveGeometry = PpcDiskGetDriveGeometry;
441 MachVtbl.DiskGetCacheableBlockCount = PpcDiskGetCacheableBlockCount;
442
443 MachVtbl.GetTime = PpcGetTime;
444
445 MachVtbl.HwDetect = PpcHwDetect;
446 MachVtbl.HwIdle = PpcHwIdle;
447 }
448
449 void PpcOfwInit()
450 {
451 chosen_package = ofw_finddevice( "/chosen" );
452
453 ofw_getprop(chosen_package, "bootargs",
454 CmdLine, sizeof(CmdLine));
455 ofw_getprop( chosen_package, "stdin",
456 (char *)&stdin_handle, sizeof(stdin_handle) );
457 ofw_getprop( chosen_package, "stdout",
458 (char *)&stdout_handle, sizeof(stdout_handle) );
459 ofw_getprop( chosen_package, "mmu",
460 (char *)&mmu_handle, sizeof(mmu_handle) );
461
462 // Allow forcing prep for broken OFW
463 if(!strncmp(CmdLine, "bootprep", 8))
464 {
465 printf("Going to PREP init...\n");
466 ofproxy = NULL;
467 PpcPrepInit();
468 return;
469 }
470
471 printf( "FreeLDR version [%s]\n", GetFreeLoaderVersionString() );
472
473 BootMain( CmdLine );
474 }
475
476 void PpcInit( of_proxy the_ofproxy ) {
477 // Hack to be a bit easier on ram
478 CacheSizeLimit = 64 * 1024;
479 ofproxy = the_ofproxy;
480 PpcDefaultMachVtbl();
481 if(ofproxy) PpcOfwInit();
482 else PpcPrepInit();
483 }
484
485 void MachInit(const char *CmdLine) {
486 int i, len;
487 char *sep;
488
489 BootPart[0] = 0;
490 FrldrBootPath[0] = 0;
491
492 printf( "Determining boot device: [%s]\n", CmdLine );
493
494 sep = NULL;
495 for( i = 0; i < strlen(CmdLine); i++ ) {
496 if( strncmp(CmdLine + i, "boot=", 5) == 0) {
497 strcpy(BootPart, CmdLine + i + 5);
498 sep = strchr(BootPart, ',');
499 if( sep )
500 *sep = 0;
501 while(CmdLine[i] && CmdLine[i]!=',') i++;
502 }
503 }
504
505 if( strlen(BootPart) == 0 ) {
506 if (ofproxy)
507 len = ofw_getprop(chosen_package, "bootpath",
508 FrldrBootPath, sizeof(FrldrBootPath));
509 else
510 len = 0;
511 if( len < 0 ) len = 0;
512 FrldrBootPath[len] = 0;
513 printf( "Boot Path: %s\n", FrldrBootPath );
514
515 sep = strrchr(FrldrBootPath, ',');
516
517 strcpy(BootPart, FrldrBootPath);
518 if( sep ) {
519 BootPart[sep - FrldrBootPath] = 0;
520 }
521 }
522
523 printf( "FreeLDR starting (boot partition: %s)\n", BootPart );
524 }
525
526 void beep() {
527 }
528
529 UCHAR NTAPI READ_PORT_UCHAR(PUCHAR Address) {
530 return GetPhysByte(((ULONG)Address)+0x80000000);
531 }
532
533 void WRITE_PORT_UCHAR(PUCHAR Address, UCHAR Value) {
534 SetPhysByte(((ULONG)Address)+0x80000000, Value);
535 }
536
537 void BootOldLinuxKernel( unsigned long size ) {
538 ofw_exit();
539 }
540
541 void BootNewLinuxKernel() {
542 ofw_exit();
543 }
544
545 VOID __cdecl ChainLoadBiosBootSectorCode(
546 IN UCHAR BootDrive OPTIONAL,
547 IN ULONG BootPartition OPTIONAL)
548 {
549 ofw_exit();
550 }
551
552 void DbgBreakPoint() {
553 __asm__("twi 31,0,0");
554 }