Root/
Source at commit HEAD created 5 years 6 days ago. By ifabio, Few update to kernelPatcher (Credits to CrazyBirdy) | |
---|---|
1 | /*␊ |
2 | File added by David F. Elliott <dfe@cox.net> on 2007/06/26␊ |
3 | */␊ |
4 | ␊ |
5 | #include "libsaio.h"␊ |
6 | #include "boot.h"␊ |
7 | #include "bootstruct.h"␊ |
8 | ␊ |
9 | #include "mboot.h"␊ |
10 | ␊ |
11 | int multiboot_timeout=0;␊ |
12 | int multiboot_timeout_set=0;␊ |
13 | int multiboot_partition=0;␊ |
14 | int multiboot_partition_set=0;␊ |
15 | int multiboot_skip_partition=0;␊ |
16 | int multiboot_skip_partition_set=0;␊ |
17 | ␊ |
18 | // Global multiboot info, if using multiboot.␊ |
19 | struct multiboot_info *gMI;␊ |
20 | ␊ |
21 | extern void continue_at_low_address(void);␊ |
22 | ␊ |
23 | // prototype hi_multiboot and keep its implementation below multiboot_to_boot␊ |
24 | // to ensure that it doesn't get inlined by the compiler␊ |
25 | // We don't want it inlined because we specifically want the stack frame␊ |
26 | // pointer to be as high as possible and the hi_multiboot function␊ |
27 | // copies multiboot_info onto its stack.␊ |
28 | uint64_t hi_multiboot(int multiboot_magic, struct multiboot_info *mi_orig);␊ |
29 | // prototype dochainload for the same reason.␊ |
30 | void dochainload();␊ |
31 | ␊ |
32 | #define OFFSET_1MEG 0x100000␊ |
33 | #define BAD_BOOT_DEVICE 0xffffffff␊ |
34 | ␊ |
35 | // This assumes that the address of the first argument to the function will␊ |
36 | // be exactly 4 bytes above the address of the return address.␊ |
37 | // It is intended to be used as an lvalue with a statement like this -= OFFSET_1MEG;␊ |
38 | #define RETURN_ADDRESS_USING_FIRST_ARG(arg) \␊ |
39 | (*(uint32_t*)((char*)&(arg) - 4))␊ |
40 | ␊ |
41 | #define FIX_RETURN_ADDRESS_USING_FIRST_ARG(arg) \␊ |
42 | RETURN_ADDRESS_USING_FIRST_ARG(arg) -= OFFSET_1MEG␊ |
43 | ␊ |
44 | extern void jump_to_chainbooter() __attribute__((noreturn));␊ |
45 | extern unsigned char chainbootdev;␊ |
46 | extern unsigned char chainbootflag;␊ |
47 | ␊ |
48 | void chainLoad();␊ |
49 | void waitThenReload();␊ |
50 | ␊ |
51 | int multibootRamdiskReadBytes( int biosdev, unsigned int blkno,␊ |
52 | unsigned int byteoff,␊ |
53 | unsigned int byteCount, void * buffer );␊ |
54 | int multiboot_get_ramdisk_info(int biosdev, struct driveInfo *dip);␊ |
55 | static long multiboot_LoadExtraDrivers(FileLoadDrivers_t FileLoadDrivers_p);␊ |
56 | ␊ |
57 | void chainLoad()␊ |
58 | {␊ |
59 | /* TODO: We ought to load the appropriate partition table, for example␊ |
60 | the MBR if booting a primary partition or the particular extended␊ |
61 | partition table if booting a logical drive. For example, the␊ |
62 | regular MS MBR booter will relocate itself (e.g. the MBR) from␊ |
63 | 0:7C00 to 0:0600 and will use SI as the offset when reading␊ |
64 | the partition data from itself. Thus when it jumps to the partition␊ |
65 | boot sector, SI will be 0x600 + 446 + i<<4 where i is the partition␊ |
66 | table index.␊ |
67 | ␊ |
68 | On the other hand, our code for the non-Multiboot case doesn't do␊ |
69 | this either, although GRUB does.␊ |
70 | */␊ |
71 | ␊ |
72 | const unsigned char *bootcode = (const unsigned char*)0x7c00;␊ |
73 | if(bootcode[0x1fe] == 0x55 && bootcode[0x1ff] == 0xaa)␊ |
74 | {␊ |
75 | printf("Calling chainbooter\n");␊ |
76 | jump_to_chainbooter();␊ |
77 | /* NORETURN */␊ |
78 | }␊ |
79 | else␊ |
80 | {␊ |
81 | printf("Bad chain boot sector magic: %02x%02x\n", bootcode[0x1fe], bootcode[0x1ff]);␊ |
82 | }␊ |
83 | }␊ |
84 | ␊ |
85 | void waitThenReload()␊ |
86 | {␊ |
87 | /* FIXME: Ctrl+Alt+Del does not work under Boot Camp */␊ |
88 | printf("Darwin booter exited for some reason.\n");␊ |
89 | printf("Please reboot (Ctrl+Alt+Del) your machine.\n");␊ |
90 | printf("Restarting Darwin booter in 5 seconds...");␊ |
91 | sleep(1);␊ |
92 | printf("4...");␊ |
93 | sleep(1);␊ |
94 | printf("3...");␊ |
95 | sleep(1);␊ |
96 | printf("2...");␊ |
97 | sleep(1);␊ |
98 | printf("1...");␊ |
99 | sleep(1);␊ |
100 | printf("0\n");␊ |
101 | }␊ |
102 | ␊ |
103 | // Declare boot2_sym as an opaque struct so it can't be converted to a pointer␊ |
104 | // i.e. ensure the idiot programmer (me) makes sure to use address-of␊ |
105 | // Technically it's a function but it's real mode code and we sure don't␊ |
106 | // want to call it under any circumstances.␊ |
107 | extern struct {} boot2_sym asm("boot2");␊ |
108 | ␊ |
109 | // prototype multiboot and keep its implementation below hi_multiboot to␊ |
110 | // ensure that it doesn't get inlined by the compiler␊ |
111 | static inline uint32_t multiboot(int multiboot_magic, struct multiboot_info *mi);␊ |
112 | ␊ |
113 | ␊ |
114 | /*!␊ |
115 | Returns a pointer to the first safe address we can use for stowing the multiboot info.␊ |
116 | This might actually be a bit pedantic because mboot.c32 and GRUB both stow the multiboot␊ |
117 | info in low memory meaning that the >= 128 MB location we choose is plenty high enough.␊ |
118 | */␊ |
119 | void *determine_safe_hi_addr(int multiboot_magic, struct multiboot_info *mi_orig)␊ |
120 | {␊ |
121 | // hi_addr must be at least up in 128MB+ space so it doesn't get clobbered␊ |
122 | void *hi_addr = (void*)PREBOOT_DATA;␊ |
123 | ␊ |
124 | // Fail if the magic isn't correct. We'll complain later.␊ |
125 | if(multiboot_magic != MULTIBOOT_INFO_MAGIC)␊ |
126 | return NULL;␊ |
127 | // Make sure the command-line isn't in high memory.␊ |
128 | if(mi_orig->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)␊ |
129 | {␊ |
130 | char *end = mi_orig->mi_cmdline;␊ |
131 | if(end != NULL)␊ |
132 | {␊ |
133 | for(; *end != '\0'; ++end)␊ |
134 | ;␊ |
135 | ++end;␊ |
136 | if( (void*)end > hi_addr)␊ |
137 | hi_addr = end;␊ |
138 | }␊ |
139 | }␊ |
140 | // Make sure the module information isn't in high memory␊ |
141 | if(mi_orig->mi_flags & MULTIBOOT_INFO_HAS_MODS)␊ |
142 | {␊ |
143 | struct multiboot_module *modules = (void*)mi_orig->mi_mods_addr;␊ |
144 | int i;␊ |
145 | for(i=0; i < mi_orig->mi_mods_count; ++i)␊ |
146 | {␊ |
147 | // make sure the multiboot_module struct itself won't get clobbered␊ |
148 | void *modinfo_end = modules+i+1;␊ |
149 | if(modinfo_end > hi_addr)␊ |
150 | hi_addr = modinfo_end;␊ |
151 | // make sure the module itself won't get clobbered␊ |
152 | modinfo_end = (void*)modules[i].mm_mod_end;␊ |
153 | if(modinfo_end > hi_addr)␊ |
154 | hi_addr = modinfo_end;␊ |
155 | // make sure the module string doesn't get clobbered␊ |
156 | char *end = modules[i].mm_string;␊ |
157 | for(; *end != '\0'; ++end)␊ |
158 | ;␊ |
159 | ++end;␊ |
160 | modinfo_end = end;␊ |
161 | if(modinfo_end > hi_addr)␊ |
162 | hi_addr = modinfo_end;␊ |
163 | }␊ |
164 | }␊ |
165 | // TODO: Copy syms (never needed), mmap, drives, config table, loader name, apm table, VBE info␊ |
166 | ␊ |
167 | // Round up to page size␊ |
168 | hi_addr = (void*)(((uint32_t)hi_addr + 0xfff) & ~(uint32_t)0xfff);␊ |
169 | return hi_addr;␊ |
170 | }␊ |
171 | ␊ |
172 | /*!␊ |
173 | Like malloc but with a preceding input/output parameter which points to the next available␊ |
174 | location for data. The original value of *hi_addr is returned and *hi_addr is incremented␊ |
175 | by size bytes.␊ |
176 | */␊ |
177 | void * _hi_malloc(void **hi_addr, size_t size)␊ |
178 | {␊ |
179 | void *ret = *hi_addr;␊ |
180 | *hi_addr += size;␊ |
181 | return ret;␊ |
182 | }␊ |
183 | ␊ |
184 | /*!␊ |
185 | Like strdup but with a preceding input/output parameter. The original value of *hi_addr is␊ |
186 | returned and *hi_addr is incremented by the number of bytes necessary to complete the string␊ |
187 | copy including its NUL terminator.␊ |
188 | */␊ |
189 | char * _hi_strdup(void **hi_addr, char *src)␊ |
190 | {␊ |
191 | char *dstStart;␊ |
192 | char *dst = dstStart = *hi_addr;␊ |
193 | for(; *src != '\0'; ++src, ++dst, ++(*hi_addr))␊ |
194 | *dst = *src;␊ |
195 | *dst = '\0';␊ |
196 | ++(*hi_addr);␊ |
197 | return dstStart;␊ |
198 | }␊ |
199 | ␊ |
200 | // Convenience macros␊ |
201 | #define hi_malloc(size) _hi_malloc(&hi_addr, (size))␊ |
202 | #define hi_strdup(src) _hi_strdup(&hi_addr, (src))␊ |
203 | ␊ |
204 | /*!␊ |
205 | Copies the Multiboot info and any associated data (e.g. various strings and any multiboot modules)␊ |
206 | up to very high RAM (above 128 MB) to ensure it doesn't get clobbered by the booter.␊ |
207 | */␊ |
208 | struct multiboot_info * copyMultibootInfo(int multiboot_magic, struct multiboot_info *mi_orig)␊ |
209 | {␊ |
210 | void *hi_addr = determine_safe_hi_addr(multiboot_magic, mi_orig);␊ |
211 | if(hi_addr == NULL)␊ |
212 | return NULL;␊ |
213 | ␊ |
214 | struct multiboot_info *mi_copy = hi_malloc(sizeof(*mi_copy));␊ |
215 | memcpy(mi_copy, mi_orig, sizeof(*mi_copy));␊ |
216 | ␊ |
217 | // Copy the command line␊ |
218 | if(mi_orig->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)␊ |
219 | {␊ |
220 | mi_copy->mi_cmdline = hi_strdup(mi_orig->mi_cmdline);␊ |
221 | }␊ |
222 | // Copy the loader name␊ |
223 | if(mi_orig->mi_flags & MULTIBOOT_INFO_HAS_LOADER_NAME)␊ |
224 | {␊ |
225 | mi_copy->mi_loader_name = hi_strdup(mi_orig->mi_loader_name);␊ |
226 | }␊ |
227 | // Copy the module info␊ |
228 | if(mi_orig->mi_flags & MULTIBOOT_INFO_HAS_MODS)␊ |
229 | {␊ |
230 | struct multiboot_module *dst_modules = hi_malloc(sizeof(*dst_modules)*mi_orig->mi_mods_count);␊ |
231 | struct multiboot_module *src_modules = (void*)mi_orig->mi_mods_addr;␊ |
232 | mi_copy->mi_mods_addr = (uint32_t)dst_modules;␊ |
233 | ␊ |
234 | // Copy all of the module info plus the actual module into high memory␊ |
235 | int i;␊ |
236 | for(i=0; i < mi_orig->mi_mods_count; ++i)␊ |
237 | {␊ |
238 | // Assume mod_end is 1 past the actual end (i.e. it is start + size, not really end (i.e. start + size - 1))␊ |
239 | // This is what GRUB and mboot.c32 do although the spec is unclear on this.␊ |
240 | uint32_t mod_length = src_modules[i].mm_mod_end - src_modules[i].mm_mod_start;␊ |
241 | ␊ |
242 | dst_modules[i].mm_mod_start = (uint32_t)hi_malloc(mod_length);␊ |
243 | dst_modules[i].mm_mod_end = (uint32_t)dst_modules[i].mm_mod_start + mod_length;␊ |
244 | memcpy((char*)dst_modules[i].mm_mod_start, (char*)src_modules[i].mm_mod_start, mod_length);␊ |
245 | ␊ |
246 | dst_modules[i].mm_string = hi_strdup(src_modules[i].mm_string);␊ |
247 | dst_modules[i].mm_reserved = src_modules[i].mm_reserved;␊ |
248 | }␊ |
249 | }␊ |
250 | // Make sure that only stuff that didn't need to be copied or that we did deep copy is indicated in the copied struct.␊ |
251 | mi_copy->mi_flags &= MULTIBOOT_INFO_HAS_MEMORY | MULTIBOOT_INFO_HAS_BOOT_DEVICE | MULTIBOOT_INFO_HAS_CMDLINE | MULTIBOOT_INFO_HAS_LOADER_NAME | MULTIBOOT_INFO_HAS_MODS;␊ |
252 | ␊ |
253 | return mi_copy;␊ |
254 | }␊ |
255 | ␊ |
256 | // This is the meat of our implementation. It grabs the boot device from␊ |
257 | // the multiboot_info and returns it as is. If it fails it returns␊ |
258 | // BAD_BOOT_DEVICE. We can call an awful lot of libsa and libsaio but␊ |
259 | // we need to take care not to call anything that requires malloc because␊ |
260 | // it won't be initialized until boot() does it.␊ |
261 | static inline uint32_t multiboot(int multiboot_magic, struct multiboot_info *mi)␊ |
262 | {␊ |
263 | if(multiboot_magic != MULTIBOOT_INFO_MAGIC)␊ |
264 | {␊ |
265 | printf("Wrong Multiboot magic\n");␊ |
266 | sleep(2);␊ |
267 | return BAD_BOOT_DEVICE;␊ |
268 | }␊ |
269 | printf("Multiboot info @0x%x\n", (uint32_t)mi);␊ |
270 | if(mi->mi_flags & MULTIBOOT_INFO_HAS_LOADER_NAME)␊ |
271 | printf("Loaded by %s\n", mi->mi_loader_name);␊ |
272 | ␊ |
273 | // Multiboot puts boot device in high byte␊ |
274 | // Normal booter wants it in low byte␊ |
275 | int bootdevice = mi->mi_boot_device_drive;␊ |
276 | ␊ |
277 | bool doSelectDevice = false;␊ |
278 | if(mi->mi_flags & MULTIBOOT_INFO_HAS_BOOT_DEVICE)␊ |
279 | {␊ |
280 | printf("Boot device 0x%x\n", bootdevice);␊ |
281 | }␊ |
282 | else␊ |
283 | {␊ |
284 | printf("Multiboot info does not include chosen boot device\n");␊ |
285 | doSelectDevice = true;␊ |
286 | bootdevice = BAD_BOOT_DEVICE;␊ |
287 | }␊ |
288 | if(mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)␊ |
289 | {␊ |
290 | const char *val;␊ |
291 | int size;␊ |
292 | ␊ |
293 | if(getValueForBootKey(mi->mi_cmdline, "biosdev", &val, &size))␊ |
294 | {␊ |
295 | char *endptr;␊ |
296 | int intVal = strtol(val, &endptr, 16 /* always hex */);␊ |
297 | if(*val != '\0' && (*endptr == '\0' || *endptr == ' ' || *endptr == '\t'))␊ |
298 | {␊ |
299 | printf("Boot device overridden to %02x with biosdev=%s\n", intVal, val);␊ |
300 | bootdevice = intVal;␊ |
301 | doSelectDevice = false;␊ |
302 | }␊ |
303 | else␊ |
304 | doSelectDevice = true;␊ |
305 | }␊ |
306 | ␊ |
307 | if(getValueForBootKey(mi->mi_cmdline, "timeout", &val, &size))␊ |
308 | {␊ |
309 | char *endptr;␊ |
310 | int intVal = strtol(val, &endptr, 0);␊ |
311 | if(*val != '\0' && (*endptr == '\0' || *endptr == ' ' || *endptr == '\t'))␊ |
312 | {␊ |
313 | printf("Timeout overridden to %d with timeout=%s\n", intVal, val);␊ |
314 | multiboot_timeout = intVal;␊ |
315 | multiboot_timeout_set = 1;␊ |
316 | }␊ |
317 | }␊ |
318 | ␊ |
319 | if(getValueForBootKey(mi->mi_cmdline, "partno", &val, &size))␊ |
320 | {␊ |
321 | char *endptr;␊ |
322 | int intVal = strtol(val, &endptr, 0);␊ |
323 | if(*val != '\0' && (*endptr == '\0' || *endptr == ' ' || *endptr == '\t'))␊ |
324 | {␊ |
325 | printf("Default partition overridden to %d with partno=%s\n", intVal, val);␊ |
326 | multiboot_partition = intVal;␊ |
327 | multiboot_partition_set = 1;␊ |
328 | }␊ |
329 | }␊ |
330 | if(getValueForBootKey(mi->mi_cmdline, "skip_partno", &val, &size))␊ |
331 | {␊ |
332 | char *endptr;␊ |
333 | int intVal = strtol(val, &endptr, 0);␊ |
334 | if(*val != '\0' && (*endptr == '\0' || *endptr == ' ' || *endptr == '\t'))␊ |
335 | {␊ |
336 | printf("Skipping partition %d with skip_partno=%s\n", intVal, val);␊ |
337 | multiboot_skip_partition = intVal;␊ |
338 | multiboot_skip_partition_set = 1;␊ |
339 | }␊ |
340 | }␊ |
341 | }␊ |
342 | if(doSelectDevice)␊ |
343 | {␊ |
344 | bootdevice = selectAlternateBootDevice(bootdevice);␊ |
345 | }␊ |
346 | if(bootdevice == BAD_BOOT_DEVICE)␊ |
347 | sleep(2); // pause for a second before halting␊ |
348 | return bootdevice;␊ |
349 | }␊ |
350 | ␊ |
351 | // When we enter, we're actually 1 MB high.␊ |
352 | // Fortunately, memcpy is position independent, and it's all we need␊ |
353 | uint64_t hi_multiboot(int multiboot_magic, struct multiboot_info *mi_orig)␊ |
354 | {␊ |
355 | // Copy the multiboot info out of the way.␊ |
356 | // We can't bitch about the magic yet because printf won't work␊ |
357 | // because it contains an absolute location of putchar which␊ |
358 | // contains absolute locations to other things which eventually␊ |
359 | // makes a BIOS call from real mode which of course won't work␊ |
360 | // because we're stuck in extended memory at this point.␊ |
361 | struct multiboot_info *mi_p = copyMultibootInfo(multiboot_magic, mi_orig);␊ |
362 | ␊ |
363 | // Get us in to low memory so we can run everything␊ |
364 | ␊ |
365 | // We cannot possibly be more than 447k and copying extra won't really hurt anything␊ |
366 | // We use the address of the assembly entrypoint to get our starting location.␊ |
367 | memcpy(&boot2_sym, (char*)&boot2_sym + OFFSET_1MEG, BOOT2_MAX_LENGTH /* 447k */);␊ |
368 | ␊ |
369 | // This is a little assembler routine that returns to us in the correct selector␊ |
370 | // instead of the kernel selector we're running in now and at the correct␊ |
371 | // instruction pointer ( current minus 1 MB ). It does not fix our return␊ |
372 | // address nor does it fix the return address of our caller.␊ |
373 | continue_at_low_address();␊ |
374 | ␊ |
375 | // Now fix our return address.␊ |
376 | // JrCs: this macro should be rewritten because the code generated by XCode 4.x␊ |
377 | // change the value of the argument passed as parameter (multiboot_magic)␊ |
378 | // FIX_RETURN_ADDRESS_USING_FIRST_ARG(multiboot_magic);␊ |
379 | ␊ |
380 | // We can now do just about anything, including return to our caller correctly.␊ |
381 | // However, our caller must fix his return address if he wishes to return to␊ |
382 | // his caller and so on and so forth.␊ |
383 | ␊ |
384 | /* Zero the BSS and initialize malloc */␊ |
385 | initialize_runtime();␊ |
386 | ␊ |
387 | gMI = mi_p;␊ |
388 | ␊ |
389 | /* Set up a temporary bootArgs so we can call console output routines␊ |
390 | like printf that check the v_display. Note that we purposefully␊ |
391 | do not initialize anything else at this early stage.␊ |
392 | ␊ |
393 | We are reasonably sure we're already in text mode if GRUB booted us.␊ |
394 | This is the same assumption that initKernBootStruct makes.␊ |
395 | We could check the multiboot info I guess, but why bother?␊ |
396 | */␊ |
397 | boot_args temporaryBootArgsData;␊ |
398 | bzero(&temporaryBootArgsData, sizeof(boot_args));␊ |
399 | bootArgs = &temporaryBootArgsData;␊ |
400 | bootArgs->Video.v_display = VGA_TEXT_MODE;␊ |
401 | ␊ |
402 | // Install ramdisk and extra driver hooks␊ |
403 | p_get_ramdisk_info = &multiboot_get_ramdisk_info;␊ |
404 | p_ramdiskReadBytes = &multibootRamdiskReadBytes;␊ |
405 | LoadExtraDrivers_p = &multiboot_LoadExtraDrivers;␊ |
406 | ␊ |
407 | // Since we call multiboot ourselves, its return address will be correct.␊ |
408 | // That is unless it's inlined in which case it does not matter.␊ |
409 | uint64_t bootdevice = multiboot( multiboot_magic, mi_orig); // mi_p);␊ |
410 | ␊ |
411 | ␉if(bootdevice != BAD_BOOT_DEVICE)␊ |
412 | ␉{␊ |
413 | ␉␉// boot only returns to do a chain load.␊ |
414 | ␉␉for(;;)␊ |
415 | ␉␉{ // NOTE: boot only uses the last byte (the drive number)␊ |
416 | ␉␉␉common_boot(bootdevice);␊ |
417 | ␉␉␉if(chainbootflag)␊ |
418 | ␉␉␉␉chainLoad();␊ |
419 | ␉␉␉else␊ |
420 | ␉␉␉␉waitThenReload();␊ |
421 | ␉␉}␊ |
422 | ␉}␊ |
423 | ␊ |
424 | // We're about to exit and temporaryBootArgs will no longer be valid␊ |
425 | bootArgs = NULL;␊ |
426 | return bootdevice;␊ |
427 | }␊ |
428 | ␊ |
429 | // Starts off in the multiboot context 1 MB high but eventually gets into low memory␊ |
430 | // and winds up with a bootdevice in eax which is all that boot() wants␊ |
431 | // This lets the stack pointer remain very high.␊ |
432 | // If we were to call boot directly from multiboot then the whole multiboot_info␊ |
433 | // would be on the stack which would possibly be using way too much stack.␊ |
434 | void multiboot_to_boot(int multiboot_magic, struct multiboot_info *mi_orig)␊ |
435 | {␊ |
436 | ␉hi_multiboot(multiboot_magic, mi_orig);␊ |
437 | ␊ |
438 | ␉// Avoid returning to high-memory address which isn't valid in the segment␊ |
439 | ␉// we are now in.␊ |
440 | ␉// Calling sleep() ensures the user ought to be able to use Ctrl+Alt+Del␊ |
441 | ␉// because the BIOS will have interrupts on.␊ |
442 | ␉for(;;)␊ |
443 | ␉␉sleep(10);␊ |
444 | ␉// NOTE: *IF* we needed to return we'd have to fix up our return address to␊ |
445 | ␉// be in low memory using the same trick as below.␊ |
446 | ␉// However, there doesn't seem to be any point in returning to assembly␊ |
447 | ␉// particularly when the remaining code merely halts the processor.␊ |
448 | ␊ |
449 | }␊ |
450 | ␊ |
451 | ///////////////////////////////////////////////////////////////////////////␊ |
452 | // Ramdisk and extra drivers code␊ |
453 | ␊ |
454 | int multibootRamdiskReadBytes( int biosdev, unsigned int blkno,␊ |
455 | unsigned int byteoff,␊ |
456 | unsigned int byteCount, void * buffer )␊ |
457 | {␊ |
458 | int module_count = gMI->mi_mods_count;␊ |
459 | struct multiboot_module *modules = (void*)gMI->mi_mods_addr;␊ |
460 | if(biosdev < 0x100)␊ |
461 | return -1;␊ |
462 | if(biosdev >= (0x100 + module_count))␊ |
463 | return -1;␊ |
464 | struct multiboot_module *module = modules + (biosdev - 0x100);␊ |
465 | ␊ |
466 | void *p_initrd = (void*)module->mm_mod_start;␊ |
467 | bcopy(p_initrd + blkno*512 + byteoff, buffer, byteCount);␊ |
468 | return 0;␊ |
469 | }␊ |
470 | ␊ |
471 | int multiboot_get_ramdisk_info(int biosdev, struct driveInfo *dip)␊ |
472 | {␊ |
473 | int module_count = gMI->mi_mods_count;␊ |
474 | struct multiboot_module *modules = (void*)gMI->mi_mods_addr;␊ |
475 | if(biosdev < 0x100)␊ |
476 | return -1;␊ |
477 | if(biosdev >= (0x100 + module_count))␊ |
478 | return -1;␊ |
479 | struct multiboot_module *module = modules + (biosdev - 0x100);␊ |
480 | dip->biosdev = biosdev;␊ |
481 | dip->uses_ebios = true;␉// XXX aserebln uses_ebios isn't a boolean at all␊ |
482 | dip->di.params.phys_sectors = (module->mm_mod_end - module->mm_mod_start + 511) / 512;␊ |
483 | dip->valid = true;␊ |
484 | return 0;␊ |
485 | }␊ |
486 | ␊ |
487 | static long multiboot_LoadExtraDrivers(FileLoadDrivers_t FileLoadDrivers_p)␊ |
488 | {␊ |
489 | char extensionsSpec[1024];␊ |
490 | int ramdiskUnit;␊ |
491 | for(ramdiskUnit = 0; ramdiskUnit < gMI->mi_mods_count; ++ramdiskUnit)␊ |
492 | {␊ |
493 | int partCount; // unused␊ |
494 | BVRef ramdiskChain = diskScanBootVolumes(0x100 + ramdiskUnit, &partCount);␊ |
495 | if(ramdiskChain == NULL)␊ |
496 | {␊ |
497 | verbose("Ramdisk contains no partitions\n");␊ |
498 | continue;␊ |
499 | }␊ |
500 | for(; ramdiskChain != NULL; ramdiskChain = ramdiskChain->next)␊ |
501 | {␊ |
502 | sprintf(extensionsSpec, "rd(%d,%d)/Extra/", ramdiskUnit, ramdiskChain->part_no);␊ |
503 | struct dirstuff *extradir = opendir(extensionsSpec);␊ |
504 | closedir(extradir);␊ |
505 | if(extradir != NULL)␊ |
506 | {␊ |
507 | int ret = FileLoadDrivers_p(extensionsSpec, 0 /* this is a kext root dir, not a kext with plugins */);␊ |
508 | if(ret != 0)␊ |
509 | {␊ |
510 | verbose("FileLoadDrivers failed on a ramdisk\n");␊ |
511 | return ret;␊ |
512 | }␊ |
513 | }␊ |
514 | }␊ |
515 | }␊ |
516 | return 0;␊ |
517 | }␊ |
518 |