Trust uboot's device list only if it does not look suspicious.
[AROS.git] / arch / all-pc / bootstrap / multiboot2.c
blobf14432bd88fa07935aa217ced33a43064821e5c3
1 /*
2 Copyright © 2011, 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.
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
45 * temporary storage.
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;
54 mmap->addr = addr;
55 mmap->len = len;
56 mmap->type = type;
58 mmap++;
59 mmap2 = (void *)mmap2 + tag->entry_size;
60 mmap2_len -= tag->entry_size;
63 *mmap_len = (char *)mmap - (char *)ret;
64 return 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);
80 Hello();
81 D(kprintf("[Multiboot2] Multiboot v2 data @ 0x%p [%u bytes]\n", mb, *(unsigned int *)mb));
83 AllocFB();
86 * The supplied pointer points to an UQUAD value specifying total length of the
87 * whole data array.
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
94 * to a multiple of 8.
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));
100 switch (mbtag->type)
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));
105 break;
107 case MB2_TAG_MMAP:
108 mmap = mmap_convert((struct mb2_tag_mmap *)mbtag, mmap_len);
109 D(kprintf("[Multiboot2] Memory map @ 0x%p\n", mmap));
110 break;
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;
119 tag++;
121 tag->ti_Tag = KRN_MEMUpper;
122 tag->ti_Data = memupper;
123 tag++;
125 break;
127 case MB2_TAG_FRAMEBUFFER:
128 fb = (struct mb2_tag_framebuffer *)mbtag;
129 break;
131 case MB2_TAG_VBE:
132 vbe = (struct mb2_tag_vbe *)mbtag;
133 break;
135 case MB2_TAG_BOOTLOADER_NAME:
136 tag->ti_Tag = KRN_BootLoader;
137 tag->ti_Data = (unsigned long)((struct mb2_tag_string *)mbtag)->string;
138 tag++;
140 break;
142 #ifdef MULTIBOOT_64BIT
143 case MB2_TAG_EFI64:
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;
148 #else
149 case MB2_TAG_EFI32:
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;
154 #endif
155 tag++;
157 break;
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))
169 if (vbe)
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;
179 tag++;
181 tag->ti_Tag = KRN_VBEControllerInfo;
182 tag->ti_Data = (unsigned long)&vbe->vbe_control_info;
183 tag++;
185 tag->ti_Tag = KRN_VBEMode;
186 tag->ti_Data = vbe->vbe_mode;
187 tag++;
189 else if (fb)
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;
232 tag++;
237 /* Return memory map address. Length is already provided by either mmap_make() or mmap_convert() */
238 *mmap_addr = mmap;
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);
247 return usable;