2 Copyright (C) 2006-2011 The AROS Development Team. All rights reserved.
5 Desc: 32-bit bootstrap code used to boot the 64-bit AROS kernel.
11 //#define DEBUG_MEM_TYPE MMAP_TYPE_RAM
12 //#define DEBUG_TAGLIST
14 #include <aros/kernel.h>
15 #include <aros/multiboot.h>
16 #include <asm/x86_64/cpu.h>
18 #include <bootconsole.h>
22 #include "bootstrap.h"
23 #include "elfloader.h"
28 The Multiboot-compliant header has to be within the first 4KB (1KB??) of ELF file,
29 therefore it will be packed into the .aros.startup section. I hope, that turning debug on
30 will not shift it into some distinct location.
33 #define MB_FLAGS (MB_PAGE_ALIGN|MB_MEMORY_INFO|MB_VIDEO_MODE)
35 static const struct multiboot_header __header
__attribute__((used
,section(".aros.startup"))) =
39 -(MB_MAGIC
+ MB_FLAGS
),
45 1, /* We prefer text mode, but will accept also framebuffer */
52 First portion of code, called from GRUB dirrectly. It has to set the stack up, disable interrupts
53 and jump to the regular C code
56 " .globl kernel_bootstrap\n\t"
57 " .type kernel_bootstrap,@function\n"
58 "kernel_bootstrap: movl $__stack+65536, %esp\n\t" /* Load stack pointer */
59 " pushl %ebx\n\t" /* store parameters passed by GRUB in registers */
63 " cli\n\t" /* Lock interrupts (by flag)... */
65 " outb %al, $0x21\n\t" /* And disable them physically */
66 " outb %al, $0xa1\n\t"
73 * Stack is used only by bootstrap and is located just "somewhere" in memory.
74 * Boot taglist, BSS list, GDT and MMU tables (see cpu.c) are stored in .bss.aros.tables
75 * section which is remapped to the begin of 0x00100000. Therefore these data
76 * may be re-used by the 64-bit kickstart (we pass this area using KRN_ProtAreaStart
77 * and KRN_ProtAreaEnd).
78 * It's up to the kickstart to preserve data pointed to by boot taglist (memory map,
79 * drive tables, VBE structures, etc), because they may originate from the machine's
80 * firmware and not from us.
82 extern char *_prot_lo
, *_prot_hi
;
84 /* Structures to be passed to the kickstart */
85 static unsigned char __bss_track
[32768] __attribute__((section(".bss.aros.tables")));
86 struct TagItem64 km
[32] __attribute__((section(".bss.aros.tables")));
87 static struct mb_mmap MemoryMap
[2];
88 static struct vbe_mode VBEModeInfo
;
89 static struct vbe_controller VBEControllerInfo
;
91 /* A pointer used for building a taglist */
92 struct TagItem64
*tag
= &km
[0];
94 static unsigned char __stack
[65536] __attribute__((used
));
96 static const char default_mod_name
[] = "<unknown>";
101 * If GRUB has loaded any external modules, they will be loaded here. The modules to be loaded
102 * are stored in a list. If a module with given name is loaded more than once, the last version
103 * loaded by GRUB is used.
105 * Once the list is ready, the modules will be loaded and linked with kernel one after another. Please
106 * note that no information exchange between the modules is allowed. Each of them is absolutely
107 * independent and has to care about itself (it has to clear its own .bss region itself). Kernel knows
108 * about all modules only thanks to the list of resident modules, which is created during a memory scan
109 * over the whole kernel.
111 * Theoretically, such behaviour can guarantee us, that the GPL'ed modules do not conflict with kernel
112 * and may be "part" of it, but since I am not a lawyer, I may be wrong.
116 * Find the storage for module with given name. If such module already exists, return a pointer to it,
117 * so that it can be overridden by the new one. Otherwise, alloc space for new module.
119 static struct module
*module_prepare(const char *s
, const struct module
*m
, int *count
)
121 struct module
*mo
= (struct module
*)m
;
124 /* Repeat for every module in the list */
127 /* Module exists? Break here to allow overriding it */
129 // FIXME: we do not know the names of ELF modules
130 if (strcmp(s
, mo
->name
) == 0)
139 /* If the module has not been found on the list, increase the counter */
140 if (c
==0) *count
= *count
+ 1;
148 static int find_modules(struct multiboot
*mb
, const struct module
*m
)
152 /* Are there any modules at all? */
153 if (mb
->flags
&& MB_FLAGS_MODS
)
156 struct mb_module
*mod
= (struct mb_module
*)mb
->mods_addr
;
157 D(kprintf("[BOOT] GRUB has loaded %d files\n", mb
->mods_count
));
159 /* Go through the list of modules loaded by GRUB */
160 for (i
=0; i
< mb
->mods_count
; i
++, mod
++)
162 char *p
= (char *)mod
->mod_start
;
164 if (p
[0] == 0x7f && p
[1] == 'E' && p
[2] == 'L' && p
[3] == 'F')
167 * The loaded file is an ELF object. It may be put directly into our list of modules
169 const char *s
= default_mod_name
;
170 struct module
*mo
= module_prepare(s
, m
, &count
);
173 mo
->address
= (void*)mod
->mod_start
;
175 D(kprintf("[BOOT] * ELF module %s @ %p\n", mo
->name
, mo
->address
));
177 else if (p
[0] == 'P' && p
[1] == 'K' && p
[2] == 'G' && p
[3] == 0x01)
180 * The loaded file is an PKG\0 archive. Scan it to find all modules which are
185 D(kprintf("[BOOT] * package %s @ %p:\n", __bs_remove_path((char *)mod
->cmdline
), mod
->mod_start
));
187 while (file
< (void*)mod
->mod_end
)
189 int len
= LONG2BE(*(int *)file
);
190 const char *s
= __bs_remove_path(file
+4);
191 struct module
*mo
= module_prepare(s
, m
, &count
);
194 len
= LONG2BE(*(int *)file
);
199 D(kprintf("[BOOT] * PKG module %s @ %p\n", mo
->name
, mo
->address
));
207 /* Return the real amount of modules to load */
211 static void setupVESA(char *vesa
)
216 void *vesa_start
= &_binary_vesa_start
;
217 unsigned long vesa_size
= (unsigned long)&_binary_vesa_size
;
219 x
= strtoul(vesa
, &vesa
, 10);
222 y
= strtoul(vesa
, &vesa
, 10);
225 d
= strtoul(vesa
, &vesa
, 10);
228 * 16-bit VBE trampoline is needed only once only here, so
229 * we can simply copy it to some address, do what we need, and
232 kprintf("[BOOT] setupVESA: vesa.bin @ %p [size=%d]\n", &_binary_vesa_start
, &_binary_vesa_size
);
233 __bs_memcpy((void *)0x1000, vesa_start
, vesa_size
);
235 kprintf("[BOOT] setupVESA: BestModeMatch for %dx%dx%d = ",x
,y
,d
);
236 mode
= findMode(x
,y
,d
);
238 /* Get information and copy it from 16-bit memory space to our 32-bit memory */
240 __bs_memcpy(&VBEModeInfo
, modeinfo
, sizeof(struct vbe_mode
));
242 __bs_memcpy(&VBEControllerInfo
, controllerinfo
, sizeof(struct vbe_controller
));
244 /* Activate linear framebuffer is supported by the mode */
245 if (VBEModeInfo
.mode_attributes
& VM_LINEAR_FB
)
246 mode
|= VBE_MODE_LINEAR_FB
;
248 kprintf("%x\n",mode
);
250 if (setVbeMode(mode
) == VBE_RC_SUPPORTED
)
252 unsigned char palwidth
= 6;
254 /* Try to switch palette width to 8 bits if possible */
255 if (VBEControllerInfo
.capabilities
& VC_PALETTE_WIDTH
)
256 paletteWidth(0x0800, &palwidth
);
258 /* Reinitialize our console */
259 con_InitVESA(VBEControllerInfo
.version
, &VBEModeInfo
);
261 tag
->ti_Tag
= KRN_VBEModeInfo
;
262 tag
->ti_Data
= KERNEL_OFFSET
| (unsigned long)&VBEModeInfo
;
265 tag
->ti_Tag
= KRN_VBEControllerInfo
;
266 tag
->ti_Data
= KERNEL_OFFSET
| (unsigned long)&VBEControllerInfo
;
269 tag
->ti_Tag
= KRN_VBEMode
;
273 tag
->ti_Tag
= KRN_VBEPaletteWidth
;
274 tag
->ti_Data
= palwidth
;
278 kprintf("[BOOT] setupVESA: VESA setup complete\n");
281 static void setupFB(struct multiboot
*mb
)
283 if (mb
->flags
& MB_FLAGS_GFX
)
285 kprintf("[BOOT] Got VESA display mode 0x%x from the bootstrap\n", mb
->vbe_mode
);
287 * We are already running in VESA mode set by the bootloader.
288 * Pass on the mode information to AROS.
290 tag
->ti_Tag
= KRN_VBEModeInfo
;
291 tag
->ti_Data
= KERNEL_OFFSET
| mb
->vbe_mode_info
;
294 tag
->ti_Tag
= KRN_VBEControllerInfo
;
295 tag
->ti_Data
= KERNEL_OFFSET
| mb
->vbe_control_info
;
298 tag
->ti_Tag
= KRN_VBEMode
;
299 tag
->ti_Data
= mb
->vbe_mode
;
305 if (mb
->flags
& MB_FLAGS_FB
)
307 kprintf("[BOOT] Got framebuffer display %dx%dx%d from the bootstrap\n",
308 mb
->framebuffer_width
, mb
->framebuffer_height
, mb
->framebuffer_bpp
);
309 D(kprintf("[BOOT] Address 0x%llp, type %d, %d bytes per line\n", mb
->framebuffer_addr
, mb
->framebuffer_type
, mb
->framebuffer_pitch
));
312 * AROS VESA driver supports only RGB framebuffer because we are
313 * unlikely to have VGA palette registers for other cases.
314 * FIXME: we have some pointer to palette registers. We just need to
315 * pass it to the bootstrap and handle it there (how? Is it I/O port
316 * address or memory-mapped I/O address?)
318 if (mb
->framebuffer_type
!= MB_FRAMEBUFFER_RGB
)
322 * We have a framebuffer but no VBE information.
323 * Looks like we are running on EFI machine with no VBE support (Mac).
324 * Convert framebuffer data to VBEModeInfo and hand it to AROS.
326 VBEModeInfo
.mode_attributes
= VM_SUPPORTED
|VM_COLOR
|VM_GRAPHICS
|VM_NO_VGA_HW
|VM_NO_VGA_MEM
|VM_LINEAR_FB
;
327 VBEModeInfo
.bytes_per_scanline
= mb
->framebuffer_pitch
;
328 VBEModeInfo
.x_resolution
= mb
->framebuffer_width
;
329 VBEModeInfo
.y_resolution
= mb
->framebuffer_height
;
330 VBEModeInfo
.bits_per_pixel
= mb
->framebuffer_bpp
;
331 VBEModeInfo
.memory_model
= VMEM_RGB
;
332 VBEModeInfo
.red_mask_size
= mb
->framebuffer_red_mask_size
;
333 VBEModeInfo
.red_field_position
= mb
->framebuffer_red_field_position
;
334 VBEModeInfo
.green_mask_size
= mb
->framebuffer_green_mask_size
;
335 VBEModeInfo
.green_field_position
= mb
->framebuffer_green_field_position
;
336 VBEModeInfo
.blue_mask_size
= mb
->framebuffer_blue_mask_size
;
337 VBEModeInfo
.blue_field_position
= mb
->framebuffer_blue_field_position
;
338 VBEModeInfo
.phys_base
= mb
->framebuffer_addr
;
339 VBEModeInfo
.linear_bytes_per_scanline
= mb
->framebuffer_pitch
;
340 VBEModeInfo
.linear_red_mask_size
= mb
->framebuffer_red_mask_size
;
341 VBEModeInfo
.linear_red_field_position
= mb
->framebuffer_red_field_position
;
342 VBEModeInfo
.linear_green_mask_size
= mb
->framebuffer_green_mask_size
;
343 VBEModeInfo
.linear_green_field_position
= mb
->framebuffer_green_field_position
;
344 VBEModeInfo
.linear_blue_mask_size
= mb
->framebuffer_blue_mask_size
;
345 VBEModeInfo
.linear_blue_field_position
= mb
->framebuffer_blue_field_position
;
347 tag
->ti_Tag
= KRN_VBEModeInfo
;
348 tag
->ti_Data
= KERNEL_OFFSET
| (unsigned long)&VBEModeInfo
;
353 static void prepare_message(void *kick_base
)
355 D(kprintf("[BOOT] Kickstart 0x%p - 0x%p (entry 0x%p), protection 0x%p - 0x%p\n", kernel_lowest(), kernel_highest(), kick_base
,
356 &_prot_lo
, &_prot_hi
));
358 tag
->ti_Tag
= KRN_KernelBase
;
359 tag
->ti_Data
= KERNEL_OFFSET
| (unsigned long)kick_base
;
362 tag
->ti_Tag
= KRN_KernelLowest
;
363 tag
->ti_Data
= KERNEL_OFFSET
| (unsigned long)kernel_lowest();
366 tag
->ti_Tag
= KRN_KernelHighest
;
367 tag
->ti_Data
= KERNEL_OFFSET
| (unsigned long)kernel_highest();
370 tag
->ti_Tag
= KRN_KernelBss
;
371 tag
->ti_Data
= KERNEL_OFFSET
| (unsigned long)__bss_track
;
374 tag
->ti_Tag
= KRN_ProtAreaStart
;
375 tag
->ti_Data
= (unsigned long)&_prot_lo
;
378 tag
->ti_Tag
= KRN_ProtAreaEnd
;
379 tag
->ti_Data
= (unsigned long)&_prot_hi
;
382 tag
->ti_Tag
= TAG_DONE
;
385 static void panic(const char *str
)
387 kprintf("%s\n", str
);
388 kprintf("*** SYSTEM PANIC!!! ***\n");
395 * The entry point in C.
397 * The bootstrap routine has to load the kickstart at 0x01000000, with RO sections growing up the memory and
398 * RW sections stored beneath the 0x01000000 address. It is supposed to transfer the GRUB information further
399 * into the 64-bit kickstart.
401 * The kickstart is assembled from modules which have been loaded by GRUB. The modules may be loaded separately,
402 * or as a collection in PKG file. If some file is specified in both PKG file and list of separate modules, the
403 * copy in PKG will be skipped.
405 static void __attribute__((used
)) __bootstrap(unsigned int magic
, unsigned int addr
)
407 struct multiboot
*mb
= (struct multiboot
*)addr
;/* Multiboot structure from GRUB */
408 struct module
*mod
= (struct module
*)__stack
; /* The list of modules at the bottom of stack */
410 int module_count
= 0;
411 void *kick_base
= (void *)KERNEL_TARGET_ADDRESS
;
413 const char *cmdline
= NULL
;
414 struct mb_mmap
*mmap
= NULL
;
415 unsigned long len
= 0;
418 * We are loaded at 0x200000, so we can use one megabyte at 0x100000
419 * as our working area. Let's put console mirror there.
420 * I hope every PC has memory at this address.
422 fb_Mirror
= (char *)0x100000;
423 con_InitMultiboot(mb
);
425 kprintf("[BOOT] Entered AROS Bootstrap @ %p\n", __bootstrap
);
426 D(kprintf("[BOOT] Stack @ %p, [%d bytes]\n", __stack
, sizeof(__stack
)));
427 D(kprintf("[BOOT] Multiboot structure @ %p\n", mb
));
429 if (mb
->flags
& MB_FLAGS_CMDLINE
)
431 cmdline
= (const char *)mb
->cmdline
;
432 D(kprintf("[BOOT] Command line @ %p : '%s'\n", mb
->cmdline
, cmdline
));
437 char *kern
= strstr(cmdline
, "base_address=");
441 unsigned long p
= strtoul(&kern
[13], NULL
, 0);
445 kick_base
= (void *)p
;
446 kprintf("[BOOT] Kernel base address changed to %p\n", kick_base
);
449 kprintf("[BOOT] Kernel base address too low (%p). Keeping default.\n", p
);
452 vesa
= strstr(cmdline
, "vesa=");
454 tag
->ti_Tag
= KRN_CmdLine
;
455 tag
->ti_Data
= KERNEL_OFFSET
| (unsigned long)cmdline
;
459 if ((mb
->flags
& MB_FLAGS_MMAP
))
461 mmap
= (struct mb_mmap
*)mb
->mmap_addr
;
462 len
= mb
->mmap_length
;
465 kprintf("[BOOT] Memory map at 0x%p:\n", mmap
);
466 while (len
>= sizeof(struct mb_mmap
))
468 #ifdef DEBUG_MEM_TYPE
469 if (mmap
->type
== DEBUG_MEM_TYPE
)
471 kprintf("[BOOT] Type %d addr %llp len %llp\n", mmap
->type
, mmap
->addr
, mmap
->len
);
474 mmap
= (struct mb_mmap
*)(mmap
->size
+ (unsigned long)mmap
+4);
477 mmap
= (struct mb_mmap
*)mb
->mmap_addr
;
478 len
= mb
->mmap_length
;
483 if (mb
->flags
& MB_FLAGS_MEM
)
485 D(kprintf("[BOOT] Low memory %u KB, upper memory %u KB\n", mb
->mem_lower
, mb
->mem_upper
));
490 * To simplify things down, memory map is mandatory for our kickstart.
491 * So we create an implicit one if the bootloader didn't supply it.
493 D(kprintf("[BOOT] No memory map supplied by the bootloader, using defaults\n"));
495 MemoryMap
[0].size
= 20;
496 MemoryMap
[0].addr
= 0;
497 MemoryMap
[0].len
= mb
->mem_lower
<< 10;
498 MemoryMap
[0].type
= MMAP_TYPE_RAM
;
500 MemoryMap
[1].size
= 20;
501 MemoryMap
[1].addr
= 0x100000;
502 MemoryMap
[1].len
= mb
->mem_upper
<< 10;
503 MemoryMap
[1].type
= MMAP_TYPE_RAM
;
506 len
= sizeof(MemoryMap
);
509 /* Kickstart wants size in bytes */
510 tag
->ti_Tag
= KRN_MEMLower
;
511 tag
->ti_Data
= mb
->mem_lower
<< 10;
514 tag
->ti_Tag
= KRN_MEMUpper
;
515 tag
->ti_Data
= mb
->mem_upper
<< 10;
520 panic("No memory information provided by the bootloader");
522 tag
->ti_Tag
= KRN_MMAPAddress
;
523 tag
->ti_Data
= KERNEL_OFFSET
| (unsigned long)mmap
;
526 tag
->ti_Tag
= KRN_MMAPLength
;
531 * If vesa= option was given, set up the specified video mode explicitly.
532 * Otherwise specify to AROS what has been passed to us by the bootloader.
539 /* Setup stage - prepare the environment */
540 setup_mmu(kick_base
);
542 kprintf("[BOOT] Loading kickstart...\n");
543 set_base_address(kick_base
, __bss_track
);
545 /* Search for external modules loaded by GRUB */
546 module_count
= find_modules(mb
, mod
);
548 if (module_count
== 0)
549 panic("No kickstart modules found, nothing to run");
551 /* If any external modules are found, load them now */
552 for (m
= mod
; module_count
> 0; module_count
--, m
++)
554 kprintf("[BOOT] Loading %s... ", m
->name
);
555 load_elf_file(m
->address
, 0);
559 /* Prepare the rest of boot taglist */
560 prepare_message(kick_base
);
563 kprintf("[BOOT] Boot taglist:\n");
564 for (tag
= km
; tag
->ti_Tag
!= TAG_DONE
; tag
++)
565 kprintf("[BOOT] 0x%llp 0x%llp\n", tag
->ti_Tag
, tag
->ti_Data
);
568 /* Jump to the kickstart */
571 panic("Failed to run the kickstart");