wip .. provide our bootstrap memory layout in a header for the bootstrap and kernel...
[AROS.git] / arch / all-pc / bootstrap / multiboot2.c
blob917edb246a773e85ab0c0d9404ab01eefaf45055
1 /*
2 Copyright © 2011-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Multiboot v2 parser
6 Lang: english
7 */
9 /* #define DEBUG */
10 #define DTAGS(x)
11 #define DMMAP(x)
13 #include <aros/kernel.h>
14 #include <aros/multiboot.h>
15 #include <aros/multiboot2.h>
17 #include <bootconsole.h>
18 #include <elfloader.h>
19 #include <runtime.h>
21 #include "bootstrap.h"
22 #include "support.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;
48 mmap++;
49 mmap2 = (void *)mmap2 + tag->entry_size;
50 mmap2_len -= tag->entry_size;
53 *mmap_len = (char *)mmap - (char *)ret;
54 return 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);
70 Hello();
71 D(kprintf("[Multiboot2] Multiboot v2 data @ 0x%p [%u bytes]\n", mb, *(unsigned int *)mb));
73 AllocFB();
76 * The supplied pointer points to a UQUAD value specifying total length of the
77 * whole data array.
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
84 * to a multiple of 8.
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));
90 switch (mbtag->type)
92 case MB2_TAG_CMDLINE:
93 cmdline = ((struct mb2_tag_string *)mbtag)->string;
94 D(kprintf("[Multiboot2] Command line @ 0x%p : '%s'\n", cmdline, cmdline));
95 break;
97 case MB2_TAG_MMAP:
98 mmap = mmap_convert((struct mb2_tag_mmap *)mbtag, mmap_len);
99 D(kprintf("[Multiboot2] Memory map @ 0x%p\n", mmap));
100 break;
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;
109 tag++;
111 tag->ti_Tag = KRN_MEMUpper;
112 tag->ti_Data = memupper;
113 tag++;
115 break;
117 case MB2_TAG_FRAMEBUFFER:
118 fb = (struct mb2_tag_framebuffer *)mbtag;
119 break;
121 case MB2_TAG_VBE:
122 vbe = (struct mb2_tag_vbe *)mbtag;
123 break;
125 case MB2_TAG_BOOTLOADER_NAME:
126 tag->ti_Tag = KRN_BootLoader;
127 tag->ti_Data = (unsigned long)((struct mb2_tag_string *)mbtag)->string;
128 tag++;
130 break;
132 #ifdef MULTIBOOT_64BIT
133 case MB2_TAG_EFI64:
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;
138 #else
139 case MB2_TAG_EFI32:
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;
144 #endif
145 tag++;
147 break;
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))
159 if (vbe)
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;
169 tag++;
171 tag->ti_Tag = KRN_VBEControllerInfo;
172 tag->ti_Data = (unsigned long)&vbe->vbe_control_info;
173 tag++;
175 tag->ti_Tag = KRN_VBEMode;
176 tag->ti_Data = vbe->vbe_mode;
177 tag++;
179 else if (fb)
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;
222 tag++;
227 /* Return memory map address. Length is already provided by either mmap_make() or mmap_convert() */
228 *mmap_addr = mmap;
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);
237 return usable;