2 Copyright © 2011-2012, The AROS Development Team. All rights reserved.
5 Desc: Multiboot v2 parser
13 #include <aros/kernel.h>
14 #include <aros/multiboot.h>
15 #include <aros/multiboot2.h>
17 #include <bootconsole.h>
18 #include <elfloader.h>
21 #include "bootstrap.h"
25 * AROS expects memory map in original format. However, we won't bother
26 * adding more and more new kernel tags. We convert the memory map instead.
27 * The conversion happens in place. We use the fact that the layout of
28 * mb2_mmap is the same as mb_mmap except for the missing 'size' field. An
29 * mb_mmap can therefore be created by subtracting four bytes from the base
30 * address and filling in the 'size' field (mb2_mmap's 'pad' field, or the
31 * end of the tag structure) with the provided entry size. This will still
32 * work if mb2_mmap is extended in future, but we assume the old mb_mmap
33 * will not be extended.
35 static struct mb_mmap
*mmap_convert(struct mb2_tag_mmap
*tag
, unsigned long *mmap_len
)
37 volatile struct mb2_mmap
*mmap2
= tag
->mmap
;
38 volatile struct mb_mmap
*mmap
= (void *)tag
->mmap
- 4;
39 int mmap2_len
= tag
->size
- sizeof(struct mb2_tag_mmap
);
40 struct mb_mmap
*ret
= (struct mb_mmap
*)mmap
;
42 DMMAP(kprintf("[Multiboot2] Memory map at 0x%p, total size %u, entry size %u\n", mmap2
, mmap2_len
, tag
->entry_size
));
44 while (mmap2_len
>= sizeof(struct mb2_mmap
))
46 mmap
->size
= sizeof(struct mb_mmap
) - 4;
49 mmap2
= (void *)mmap2
+ tag
->entry_size
;
50 mmap2_len
-= tag
->entry_size
;
53 *mmap_len
= (char *)mmap
- (char *)ret
;
57 unsigned long mb2_parse(void *mb
, struct mb_mmap
**mmap_addr
, unsigned long *mmap_len
)
59 struct mb2_tag
*mbtag
;
60 struct mb2_tag_framebuffer
*fb
= NULL
;
61 struct mb2_tag_vbe
*vbe
= NULL
;
62 struct mb2_tag_module
*mod
;
63 const char *cmdline
= NULL
;
64 struct mb_mmap
*mmap
= NULL
;
65 unsigned long memlower
= 0;
66 unsigned long long memupper
= 0;
67 unsigned long usable
= (unsigned long)&_end
;
69 con_InitMultiboot2(mb
);
71 D(kprintf("[Multiboot2] Multiboot v2 data @ 0x%p [%u bytes]\n", mb
, *(unsigned int *)mb
));
76 * The supplied pointer points to a UQUAD value specifying total length of the
79 usable
= TOP_ADDR(usable
, mb
+ *(unsigned long long *)mb
);
82 * Iterate all tags and retrieve the information we want.
83 * Every next tag is UQUAD-aligned. 'size' field doesn't include padding, so we round it up
86 for (mbtag
= mb
+ 8; mbtag
->type
!= MB2_TAG_END
; mbtag
= (void *)mbtag
+ AROS_ROUNDUP2(mbtag
->size
, 8))
88 DTAGS(kprintf("[Multiboot2] Tag %u, size %u\n", mbtag
->type
, mbtag
->size
));
93 cmdline
= ((struct mb2_tag_string
*)mbtag
)->string
;
94 D(kprintf("[Multiboot2] Command line @ 0x%p : '%s'\n", cmdline
, cmdline
));
98 mmap
= mmap_convert((struct mb2_tag_mmap
*)mbtag
, mmap_len
);
99 D(kprintf("[Multiboot2] Memory map @ 0x%p\n", mmap
));
102 case MB2_TAG_BASIC_MEMINFO
:
103 /* Got lower/upper memory size */
104 memlower
= ((struct mb2_tag_basic_meminfo
*)mbtag
)->mem_lower
<< 10;
105 memupper
= (unsigned long long)((struct mb2_tag_basic_meminfo
*)mbtag
)->mem_upper
<< 10;
107 tag
->ti_Tag
= KRN_MEMLower
;
108 tag
->ti_Data
= memlower
;
111 tag
->ti_Tag
= KRN_MEMUpper
;
112 tag
->ti_Data
= memupper
;
117 case MB2_TAG_FRAMEBUFFER
:
118 fb
= (struct mb2_tag_framebuffer
*)mbtag
;
122 vbe
= (struct mb2_tag_vbe
*)mbtag
;
125 case MB2_TAG_BOOTLOADER_NAME
:
126 tag
->ti_Tag
= KRN_BootLoader
;
127 tag
->ti_Data
= (unsigned long)((struct mb2_tag_string
*)mbtag
)->string
;
132 #ifdef MULTIBOOT_64BIT
134 D(kprintf("[Multiboot2] EFI 64-bit System table 0x%016llX\n", ((struct mb2_tag_efi64
*)mbtag
)->pointer
));
136 tag
->ti_Tag
= KRN_EFISystemTable
;
137 tag
->ti_Data
= ((struct mb2_tag_efi64
*)mbtag
)->pointer
;
140 D(kprintf("[Multiboot2] EFI 32-bit System table 0x%08X\n", ((struct mb2_tag_efi32
*)mbtag
)->pointer
));
142 tag
->ti_Tag
= KRN_EFISystemTable
;
143 tag
->ti_Data
= ((struct mb2_tag_efi32
*)mbtag
)->pointer
;
151 if (!mmap
&& memlower
&& memupper
)
153 /* Build a memory map if we haven't got one */
154 mmap
= mmap_make(mmap_len
, memlower
, memupper
);
157 if (ParseCmdLine(cmdline
))
161 kprintf("[Multiboot2] Got VESA display mode 0x%x from the bootstrap\n", vbe
->vbe_mode
);
164 * We are already running in VESA mode set by the bootloader.
165 * Pass on the mode information to AROS.
167 tag
->ti_Tag
= KRN_VBEModeInfo
;
168 tag
->ti_Data
= (unsigned long)&vbe
->vbe_mode_info
;
171 tag
->ti_Tag
= KRN_VBEControllerInfo
;
172 tag
->ti_Data
= (unsigned long)&vbe
->vbe_control_info
;
175 tag
->ti_Tag
= KRN_VBEMode
;
176 tag
->ti_Data
= vbe
->vbe_mode
;
181 kprintf("[Multiboot2] Got framebuffer display %dx%dx%d from the bootstrap\n",
182 fb
->common
.framebuffer_width
, fb
->common
.framebuffer_height
, fb
->common
.framebuffer_bpp
);
183 D(kprintf("[Multiboot2] Address 0x%016llX, type %d, %d bytes per line\n", fb
->common
.framebuffer_addr
, fb
->common
.framebuffer_type
, fb
->common
.framebuffer_pitch
));
186 * AROS VESA driver supports only RGB framebuffer because we are
187 * unlikely to have VGA palette registers for other cases.
188 * FIXME: we have some pointer to palette registers. We just need to
189 * pass it to the bootstrap and handle it there (how? Is it I/O port
190 * address or memory-mapped I/O address?)
192 if (fb
->common
.framebuffer_type
== MB2_FRAMEBUFFER_RGB
)
195 * We have a framebuffer but no VBE information.
196 * Looks like we are running on EFI machine with no VBE support (Mac).
197 * Convert framebuffer data to VBEModeInfo and hand it to AROS.
199 VBEModeInfo
.mode_attributes
= VM_SUPPORTED
|VM_COLOR
|VM_GRAPHICS
|VM_NO_VGA_HW
|VM_NO_VGA_MEM
|VM_LINEAR_FB
;
200 VBEModeInfo
.bytes_per_scanline
= fb
->common
.framebuffer_pitch
;
201 VBEModeInfo
.x_resolution
= fb
->common
.framebuffer_width
;
202 VBEModeInfo
.y_resolution
= fb
->common
.framebuffer_height
;
203 VBEModeInfo
.bits_per_pixel
= fb
->common
.framebuffer_bpp
;
204 VBEModeInfo
.memory_model
= VMEM_RGB
;
205 VBEModeInfo
.red_mask_size
= fb
->framebuffer_red_mask_size
;
206 VBEModeInfo
.red_field_position
= fb
->framebuffer_red_field_position
;
207 VBEModeInfo
.green_mask_size
= fb
->framebuffer_green_mask_size
;
208 VBEModeInfo
.green_field_position
= fb
->framebuffer_green_field_position
;
209 VBEModeInfo
.blue_mask_size
= fb
->framebuffer_blue_mask_size
;
210 VBEModeInfo
.blue_field_position
= fb
->framebuffer_blue_field_position
;
211 VBEModeInfo
.phys_base
= fb
->common
.framebuffer_addr
;
212 VBEModeInfo
.linear_bytes_per_scanline
= fb
->common
.framebuffer_pitch
;
213 VBEModeInfo
.linear_red_mask_size
= fb
->framebuffer_red_mask_size
;
214 VBEModeInfo
.linear_red_field_position
= fb
->framebuffer_red_field_position
;
215 VBEModeInfo
.linear_green_mask_size
= fb
->framebuffer_green_mask_size
;
216 VBEModeInfo
.linear_green_field_position
= fb
->framebuffer_green_field_position
;
217 VBEModeInfo
.linear_blue_mask_size
= fb
->framebuffer_blue_mask_size
;
218 VBEModeInfo
.linear_blue_field_position
= fb
->framebuffer_blue_field_position
;
220 tag
->ti_Tag
= KRN_VBEModeInfo
;
221 tag
->ti_Data
= KERNEL_OFFSET
| (unsigned long)&VBEModeInfo
;
227 /* Return memory map address. Length is already provided by either mmap_make() or mmap_convert() */
230 /* Search for external modules loaded by GRUB */
231 for (mod
= mb
+ 8; mod
->type
!= MB2_TAG_END
; mod
= (void *)mod
+ AROS_ROUNDUP2(mod
->size
, 8))
233 if (mod
->type
== MB2_TAG_MODULE
)
234 usable
= AddModule(mod
->mod_start
, mod
->mod_end
, usable
);