2 Copyright © 2011, 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.
26 * We won't bother adding more and more new kernel tags. We convert the memory map instead.
27 * The conversion happens in place. We use the fact that sizeof(struct mb_mmap2) >= sizeof(struct mp_mmap).
29 static struct mb_mmap
*mmap_convert(struct mb2_tag_mmap
*tag
, unsigned long *mmap_len
)
31 struct mb2_mmap
*mmap2
= tag
->mmap
;
32 struct mb_mmap
*mmap
= (struct mb_mmap
*)tag
->mmap
;
33 int mmap2_len
= tag
->size
- sizeof(struct mb2_tag_mmap
);
34 struct mb_mmap
*ret
= mmap
;
36 DMMAP(kprintf("[Multiboot2] Memory map at 0x%p, total size %u, entry size %u\n", mmap2
, mmap2_len
, tag
->entry_size
));
38 while (mmap2_len
>= sizeof(struct mb2_mmap
))
41 * Since the conversion actually happens in place, and we use two variables
42 * (mmap and mmap2) which actually point to the same region of memory,
43 * we first need to get all values, and then store them.
44 * Compler's attempt to optimize this will ruin the idea, so we use volatile
47 volatile unsigned long long addr
= mmap2
->addr
;
48 volatile unsigned long long len
= mmap2
->len
;
49 volatile unsigned int type
= mmap2
->type
;
51 DMMAP(kprintf("[Multiboot2] Memory map entry 0x%016llX - 0x%016llX, type %u\n", addr
, addr
+ len
, type
));
53 mmap
->size
= sizeof(struct mb_mmap
) - 4;
59 mmap2
= (void *)mmap2
+ tag
->entry_size
;
60 mmap2_len
-= tag
->entry_size
;
63 *mmap_len
= (char *)mmap
- (char *)ret
;
67 unsigned long mb2_parse(void *mb
, struct mb_mmap
**mmap_addr
, unsigned long *mmap_len
)
69 struct mb2_tag
*mbtag
;
70 struct mb2_tag_framebuffer
*fb
= NULL
;
71 struct mb2_tag_vbe
*vbe
= NULL
;
72 struct mb2_tag_module
*mod
;
73 const char *cmdline
= NULL
;
74 struct mb_mmap
*mmap
= NULL
;
75 unsigned long memlower
= 0;
76 unsigned long long memupper
= 0;
77 unsigned long usable
= (unsigned long)&_end
;
79 con_InitMultiboot2(mb
);
81 D(kprintf("[Multiboot2] Multiboot v2 data @ 0x%p [%u bytes]\n", mb
, *(unsigned int *)mb
));
86 * The supplied pointer points to an UQUAD value specifying total length of the
89 usable
= TOP_ADDR(usable
, mb
+ *(unsigned long long *)mb
);
92 * Iterate all tags and retrieve the information we want.
93 * Every next tag is UQUAD-aligned. 'size' field doesn't include padding, so we round it up
96 for (mbtag
= mb
+ 8; mbtag
->type
!= MB2_TAG_END
; mbtag
= (void *)mbtag
+ AROS_ROUNDUP2(mbtag
->size
, 8))
98 DTAGS(kprintf("[Multiboot2] Tag %u, size %u\n", mbtag
->type
, mbtag
->size
));
102 case MB2_TAG_CMDLINE
:
103 cmdline
= ((struct mb2_tag_string
*)mbtag
)->string
;
104 D(kprintf("[Multiboot2] Command line @ 0x%p : '%s'\n", cmdline
, cmdline
));
108 mmap
= mmap_convert((struct mb2_tag_mmap
*)mbtag
, mmap_len
);
109 D(kprintf("[Multiboot2] Memory map @ 0x%p\n", mmap
));
112 case MB2_TAG_BASIC_MEMINFO
:
113 /* Got lower/upper memory size */
114 memlower
= ((struct mb2_tag_basic_meminfo
*)mbtag
)->mem_lower
<< 10;
115 memupper
= (unsigned long long)((struct mb2_tag_basic_meminfo
*)mbtag
)->mem_upper
<< 10;
117 tag
->ti_Tag
= KRN_MEMLower
;
118 tag
->ti_Data
= memlower
;
121 tag
->ti_Tag
= KRN_MEMUpper
;
122 tag
->ti_Data
= memupper
;
127 case MB2_TAG_FRAMEBUFFER
:
128 fb
= (struct mb2_tag_framebuffer
*)mbtag
;
132 vbe
= (struct mb2_tag_vbe
*)mbtag
;
135 case MB2_TAG_BOOTLOADER_NAME
:
136 tag
->ti_Tag
= KRN_BootLoader
;
137 tag
->ti_Data
= (unsigned long)((struct mb2_tag_string
*)mbtag
)->string
;
142 #ifdef MULTIBOOT_64BIT
144 D(kprintf("[Multiboot2] EFI 64-bit System table 0x%016llX\n", ((struct mb2_tag_efi64
*)mbtag
)->pointer
));
146 tag
->ti_Tag
= KRN_EFISystemTable
;
147 tag
->ti_Data
= ((struct mb2_tag_efi64
*)mbtag
)->pointer
;
150 D(kprintf("[Multiboot2] EFI 32-bit System table 0x%08X\n", ((struct mb2_tag_efi32
*)mbtag
)->pointer
));
152 tag
->ti_Tag
= KRN_EFISystemTable
;
153 tag
->ti_Data
= ((struct mb2_tag_efi32
*)mbtag
)->pointer
;
161 if (!mmap
&& memlower
&& memupper
)
163 /* Build a memory map if we haven't got one */
164 mmap
= mmap_make(mmap_len
, memlower
, memupper
);
167 if (ParseCmdLine(cmdline
))
171 kprintf("[Multiboot2] Got VESA display mode 0x%x from the bootstrap\n", vbe
->vbe_mode
);
174 * We are already running in VESA mode set by the bootloader.
175 * Pass on the mode information to AROS.
177 tag
->ti_Tag
= KRN_VBEModeInfo
;
178 tag
->ti_Data
= (unsigned long)&vbe
->vbe_mode_info
;
181 tag
->ti_Tag
= KRN_VBEControllerInfo
;
182 tag
->ti_Data
= (unsigned long)&vbe
->vbe_control_info
;
185 tag
->ti_Tag
= KRN_VBEMode
;
186 tag
->ti_Data
= vbe
->vbe_mode
;
191 kprintf("[Multiboot2] Got framebuffer display %dx%dx%d from the bootstrap\n",
192 fb
->common
.framebuffer_width
, fb
->common
.framebuffer_height
, fb
->common
.framebuffer_bpp
);
193 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
));
196 * AROS VESA driver supports only RGB framebuffer because we are
197 * unlikely to have VGA palette registers for other cases.
198 * FIXME: we have some pointer to palette registers. We just need to
199 * pass it to the bootstrap and handle it there (how? Is it I/O port
200 * address or memory-mapped I/O address?)
202 if (fb
->common
.framebuffer_type
== MB2_FRAMEBUFFER_RGB
)
205 * We have a framebuffer but no VBE information.
206 * Looks like we are running on EFI machine with no VBE support (Mac).
207 * Convert framebuffer data to VBEModeInfo and hand it to AROS.
209 VBEModeInfo
.mode_attributes
= VM_SUPPORTED
|VM_COLOR
|VM_GRAPHICS
|VM_NO_VGA_HW
|VM_NO_VGA_MEM
|VM_LINEAR_FB
;
210 VBEModeInfo
.bytes_per_scanline
= fb
->common
.framebuffer_pitch
;
211 VBEModeInfo
.x_resolution
= fb
->common
.framebuffer_width
;
212 VBEModeInfo
.y_resolution
= fb
->common
.framebuffer_height
;
213 VBEModeInfo
.bits_per_pixel
= fb
->common
.framebuffer_bpp
;
214 VBEModeInfo
.memory_model
= VMEM_RGB
;
215 VBEModeInfo
.red_mask_size
= fb
->framebuffer_red_mask_size
;
216 VBEModeInfo
.red_field_position
= fb
->framebuffer_red_field_position
;
217 VBEModeInfo
.green_mask_size
= fb
->framebuffer_green_mask_size
;
218 VBEModeInfo
.green_field_position
= fb
->framebuffer_green_field_position
;
219 VBEModeInfo
.blue_mask_size
= fb
->framebuffer_blue_mask_size
;
220 VBEModeInfo
.blue_field_position
= fb
->framebuffer_blue_field_position
;
221 VBEModeInfo
.phys_base
= fb
->common
.framebuffer_addr
;
222 VBEModeInfo
.linear_bytes_per_scanline
= fb
->common
.framebuffer_pitch
;
223 VBEModeInfo
.linear_red_mask_size
= fb
->framebuffer_red_mask_size
;
224 VBEModeInfo
.linear_red_field_position
= fb
->framebuffer_red_field_position
;
225 VBEModeInfo
.linear_green_mask_size
= fb
->framebuffer_green_mask_size
;
226 VBEModeInfo
.linear_green_field_position
= fb
->framebuffer_green_field_position
;
227 VBEModeInfo
.linear_blue_mask_size
= fb
->framebuffer_blue_mask_size
;
228 VBEModeInfo
.linear_blue_field_position
= fb
->framebuffer_blue_field_position
;
230 tag
->ti_Tag
= KRN_VBEModeInfo
;
231 tag
->ti_Data
= KERNEL_OFFSET
| (unsigned long)&VBEModeInfo
;
237 /* Return memory map address. Length is already provided by either mmap_make() or mmap_convert() */
240 /* Search for external modules loaded by GRUB */
241 for (mod
= mb
+ 8; mod
->type
!= MB2_TAG_END
; mod
= (void *)mod
+ AROS_ROUNDUP2(mod
->size
, 8))
243 if (mod
->type
== MB2_TAG_MODULE
)
244 usable
= AddModule(mod
->mod_start
, mod
->mod_end
, usable
);