]>
Commit | Line | Data |
---|---|---|
cd051479 VS |
1 | /* |
2 | * GRUB -- GRand Unified Bootloader | |
3 | * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc. | |
4 | * | |
5 | * GRUB is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * GRUB is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
cd051479 VS |
19 | #include <grub/memory.h> |
20 | #ifdef GRUB_MACHINE_PCBIOS | |
21 | #include <grub/machine/biosnum.h> | |
890c9fa5 | 22 | #include <grub/machine/apm.h> |
f218b09c | 23 | #include <grub/machine/memory.h> |
cd051479 VS |
24 | #endif |
25 | #include <grub/multiboot.h> | |
b1f6f35a | 26 | #include <grub/cpu/relocator.h> |
cd051479 VS |
27 | #include <grub/disk.h> |
28 | #include <grub/device.h> | |
29 | #include <grub/partition.h> | |
30 | #include <grub/mm.h> | |
31 | #include <grub/misc.h> | |
32 | #include <grub/env.h> | |
5c8e58b0 | 33 | #include <grub/relocator.h> |
884ade56 | 34 | #include <grub/video.h> |
b1f6f35a | 35 | #include <grub/file.h> |
779e9dc4 | 36 | #include <grub/net.h> |
9c4b5c13 | 37 | #include <grub/i18n.h> |
1a46a3a4 | 38 | #include <grub/lib/cmdline.h> |
884ade56 | 39 | |
329550c4 VS |
40 | #ifdef GRUB_MACHINE_EFI |
41 | #include <grub/efi/efi.h> | |
42 | #endif | |
43 | ||
b1f6f35a VS |
44 | /* The bits in the required part of flags field we don't support. */ |
45 | #define UNSUPPORTED_FLAGS 0x0000fff8 | |
cd051479 VS |
46 | |
47 | struct module | |
48 | { | |
49 | struct module *next; | |
50 | grub_addr_t start; | |
51 | grub_size_t size; | |
52 | char *cmdline; | |
53 | int cmdline_size; | |
54 | }; | |
55 | ||
7d4e39d6 | 56 | static struct module *modules, *modules_last; |
cd051479 VS |
57 | static grub_size_t cmdline_size; |
58 | static grub_size_t total_modcmd; | |
59 | static unsigned modcnt; | |
60 | static char *cmdline = NULL; | |
61 | static grub_uint32_t bootdev; | |
62 | static int bootdev_set; | |
865a0f8a VS |
63 | static grub_size_t elf_sec_num, elf_sec_entsize; |
64 | static unsigned elf_sec_shstrndx; | |
65 | static void *elf_sections; | |
00bfa988 | 66 | grub_multiboot_quirks_t grub_multiboot_quirks; |
884ade56 | 67 | |
00bfa988 VS |
68 | static grub_err_t |
69 | load_kernel (grub_file_t file, const char *filename, | |
70 | char *buffer, struct multiboot_header *header) | |
71 | { | |
72 | grub_err_t err; | |
a620876e DK |
73 | mbi_load_data_t mld; |
74 | ||
75 | mld.file = file; | |
76 | mld.filename = filename; | |
77 | mld.buffer = buffer; | |
78 | mld.mbi_ver = 1; | |
79 | mld.relocatable = 0; | |
80 | mld.avoid_efi_boot_services = 0; | |
81 | ||
00bfa988 VS |
82 | if (grub_multiboot_quirks & GRUB_MULTIBOOT_QUIRK_BAD_KLUDGE) |
83 | { | |
a620876e | 84 | err = grub_multiboot_load_elf (&mld); |
95ba0460 VS |
85 | if (err == GRUB_ERR_NONE) { |
86 | return GRUB_ERR_NONE; | |
87 | } | |
00bfa988 VS |
88 | if (err == GRUB_ERR_UNKNOWN_OS && (header->flags & MULTIBOOT_AOUT_KLUDGE)) |
89 | grub_errno = err = GRUB_ERR_NONE; | |
90 | } | |
91 | if (header->flags & MULTIBOOT_AOUT_KLUDGE) | |
92 | { | |
93 | int offset = ((char *) header - buffer - | |
94 | (header->header_addr - header->load_addr)); | |
95 | int load_size = ((header->load_end_addr == 0) ? file->size - offset : | |
96 | header->load_end_addr - header->load_addr); | |
97 | grub_size_t code_size; | |
98 | void *source; | |
99 | grub_relocator_chunk_t ch; | |
100 | ||
101 | if (header->bss_end_addr) | |
102 | code_size = (header->bss_end_addr - header->load_addr); | |
103 | else | |
104 | code_size = load_size; | |
105 | ||
106 | err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, | |
107 | &ch, header->load_addr, | |
108 | code_size); | |
109 | if (err) | |
110 | { | |
111 | grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); | |
112 | return err; | |
113 | } | |
114 | source = get_virtual_current_address (ch); | |
115 | ||
116 | if ((grub_file_seek (file, offset)) == (grub_off_t) -1) | |
117 | { | |
118 | return grub_errno; | |
119 | } | |
120 | ||
121 | grub_file_read (file, source, load_size); | |
122 | if (grub_errno) | |
123 | return grub_errno; | |
124 | ||
125 | if (header->bss_end_addr) | |
126 | grub_memset ((grub_uint8_t *) source + load_size, 0, | |
127 | header->bss_end_addr - header->load_addr - load_size); | |
128 | ||
129 | grub_multiboot_payload_eip = header->entry_addr; | |
130 | return GRUB_ERR_NONE; | |
131 | } | |
132 | ||
a620876e | 133 | return grub_multiboot_load_elf (&mld); |
00bfa988 | 134 | } |
cd051479 | 135 | |
ef02b4ca VS |
136 | static struct multiboot_header * |
137 | find_header (char *buffer, grub_ssize_t len) | |
138 | { | |
139 | struct multiboot_header *header; | |
140 | ||
141 | /* Look for the multiboot header in the buffer. The header should | |
142 | be at least 12 bytes and aligned on a 4-byte boundary. */ | |
143 | for (header = (struct multiboot_header *) buffer; | |
144 | ((char *) header <= buffer + len - 12); | |
145 | header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN)) | |
146 | { | |
147 | if (header->magic == MULTIBOOT_HEADER_MAGIC | |
148 | && !(header->magic + header->flags + header->checksum)) | |
149 | return header; | |
150 | } | |
151 | return NULL; | |
152 | } | |
153 | ||
b1f6f35a | 154 | grub_err_t |
9c4b5c13 | 155 | grub_multiboot_load (grub_file_t file, const char *filename) |
cd051479 | 156 | { |
b1f6f35a VS |
157 | char *buffer; |
158 | grub_ssize_t len; | |
159 | struct multiboot_header *header; | |
160 | grub_err_t err; | |
cd051479 | 161 | |
b1f6f35a VS |
162 | buffer = grub_malloc (MULTIBOOT_SEARCH); |
163 | if (!buffer) | |
164 | return grub_errno; | |
165 | ||
166 | len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); | |
167 | if (len < 32) | |
cd051479 | 168 | { |
b1f6f35a | 169 | grub_free (buffer); |
9c4b5c13 VS |
170 | if (!grub_errno) |
171 | grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), | |
172 | filename); | |
173 | return grub_errno; | |
cd051479 VS |
174 | } |
175 | ||
ef02b4ca | 176 | header = find_header (buffer, len); |
b1f6f35a VS |
177 | |
178 | if (header == 0) | |
179 | { | |
180 | grub_free (buffer); | |
181 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); | |
182 | } | |
cd051479 | 183 | |
b1f6f35a VS |
184 | if (header->flags & UNSUPPORTED_FLAGS) |
185 | { | |
186 | grub_free (buffer); | |
187 | return grub_error (GRUB_ERR_UNKNOWN_OS, | |
188 | "unsupported flag: 0x%x", header->flags); | |
189 | } | |
190 | ||
00bfa988 VS |
191 | err = load_kernel (file, filename, buffer, header); |
192 | if (err) | |
b1f6f35a | 193 | { |
00bfa988 VS |
194 | grub_free (buffer); |
195 | return err; | |
b1f6f35a VS |
196 | } |
197 | ||
198 | if (header->flags & MULTIBOOT_VIDEO_MODE) | |
199 | { | |
200 | switch (header->mode_type) | |
201 | { | |
202 | case 1: | |
203 | err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, | |
204 | GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | |
205 | | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, | |
c3a8dfc8 | 206 | 0, 0, 0, 0); |
b1f6f35a VS |
207 | break; |
208 | case 0: | |
209 | err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, | |
210 | GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | |
211 | | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, | |
212 | header->width, header->height, | |
c3a8dfc8 | 213 | header->depth, 0); |
b1f6f35a | 214 | break; |
974ac4f7 VS |
215 | default: |
216 | err = grub_error (GRUB_ERR_BAD_OS, | |
217 | "unsupported graphical mode type %d", | |
218 | header->mode_type); | |
219 | break; | |
b1f6f35a VS |
220 | } |
221 | } | |
222 | else | |
223 | err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, | |
224 | GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, | |
c3a8dfc8 | 225 | 0, 0, 0, 0); |
b1f6f35a | 226 | return err; |
cd051479 VS |
227 | } |
228 | ||
57994012 VS |
229 | #if GRUB_MACHINE_HAS_VBE || GRUB_MACHINE_HAS_VGA_TEXT |
230 | #include <grub/i386/pc/vbe.h> | |
231 | #endif | |
232 | ||
5c8e58b0 | 233 | static grub_size_t |
cd051479 VS |
234 | grub_multiboot_get_mbi_size (void) |
235 | { | |
779e9dc4 VS |
236 | grub_size_t ret; |
237 | struct grub_net_network_level_interface *net; | |
238 | ||
239 | ret = sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4) | |
cd051479 | 240 | + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd |
8eb567e6 VS |
241 | + ALIGN_UP (sizeof(PACKAGE_STRING), 4) |
242 | + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry) | |
26235524 | 243 | + elf_sec_entsize * elf_sec_num |
890c9fa5 | 244 | + 256 * sizeof (struct multiboot_color) |
57994012 | 245 | #if GRUB_MACHINE_HAS_VBE || GRUB_MACHINE_HAS_VGA_TEXT |
57e41c71 VS |
246 | + sizeof (struct grub_vbe_info_block) |
247 | + sizeof (struct grub_vbe_mode_info_block) | |
248 | #endif | |
890c9fa5 | 249 | + ALIGN_UP (sizeof (struct multiboot_apm_info), 4); |
779e9dc4 VS |
250 | |
251 | FOR_NET_NETWORK_LEVEL_INTERFACES(net) | |
252 | if (net->dhcp_ack) | |
253 | { | |
254 | ret += net->dhcp_acklen; | |
255 | break; | |
256 | } | |
257 | ||
258 | return ret; | |
cd051479 VS |
259 | } |
260 | ||
d0d4b8a0 CW |
261 | /* Helper for grub_fill_multiboot_mmap. */ |
262 | static int | |
263 | grub_fill_multiboot_mmap_iter (grub_uint64_t addr, grub_uint64_t size, | |
264 | grub_memory_type_t type, void *data) | |
265 | { | |
266 | struct multiboot_mmap_entry **mmap_entry = data; | |
267 | ||
268 | (*mmap_entry)->addr = addr; | |
269 | (*mmap_entry)->len = size; | |
6de9ee86 | 270 | (*mmap_entry)->type = type; |
d0d4b8a0 CW |
271 | (*mmap_entry)->size = sizeof (struct multiboot_mmap_entry) - sizeof ((*mmap_entry)->size); |
272 | (*mmap_entry)++; | |
273 | ||
274 | return 0; | |
275 | } | |
276 | ||
cd051479 VS |
277 | /* Fill previously allocated Multiboot mmap. */ |
278 | static void | |
279 | grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) | |
280 | { | |
281 | struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry; | |
282 | ||
d0d4b8a0 | 283 | grub_mmap_iterate (grub_fill_multiboot_mmap_iter, &mmap_entry); |
cd051479 VS |
284 | } |
285 | ||
57994012 VS |
286 | #if GRUB_MACHINE_HAS_VBE || GRUB_MACHINE_HAS_VGA_TEXT |
287 | ||
57e41c71 VS |
288 | static grub_err_t |
289 | fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig, | |
01740292 | 290 | grub_uint32_t ptrdest, int fill_generic) |
57e41c71 | 291 | { |
57e41c71 | 292 | grub_uint32_t vbe_mode; |
01740292 | 293 | struct grub_vbe_mode_info_block *mode_info; |
57994012 VS |
294 | #if GRUB_MACHINE_HAS_VBE |
295 | grub_vbe_status_t status; | |
296 | void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; | |
57e41c71 VS |
297 | |
298 | status = grub_vbe_bios_get_controller_info (scratch); | |
299 | if (status != GRUB_VBE_STATUS_OK) | |
300 | return grub_error (GRUB_ERR_IO, "Can't get controller info."); | |
301 | ||
302 | mbi->vbe_control_info = ptrdest; | |
303 | grub_memcpy (ptrorig, scratch, sizeof (struct grub_vbe_info_block)); | |
304 | ptrorig += sizeof (struct grub_vbe_info_block); | |
305 | ptrdest += sizeof (struct grub_vbe_info_block); | |
57994012 VS |
306 | #else |
307 | mbi->vbe_control_info = 0; | |
308 | #endif | |
309 | ||
310 | #if GRUB_MACHINE_HAS_VBE | |
57e41c71 VS |
311 | status = grub_vbe_bios_get_mode (scratch); |
312 | vbe_mode = *(grub_uint32_t *) scratch; | |
313 | if (status != GRUB_VBE_STATUS_OK) | |
01740292 | 314 | return grub_error (GRUB_ERR_IO, "can't get VBE mode"); |
57994012 VS |
315 | #else |
316 | vbe_mode = 3; | |
317 | #endif | |
57e41c71 VS |
318 | mbi->vbe_mode = vbe_mode; |
319 | ||
01740292 | 320 | mode_info = (struct grub_vbe_mode_info_block *) ptrorig; |
57e41c71 | 321 | mbi->vbe_mode_info = ptrdest; |
01740292 VS |
322 | /* get_mode_info isn't available for mode 3. */ |
323 | if (vbe_mode == 3) | |
324 | { | |
325 | grub_memset (mode_info, 0, sizeof (struct grub_vbe_mode_info_block)); | |
326 | mode_info->memory_model = GRUB_VBE_MEMORY_MODEL_TEXT; | |
327 | mode_info->x_resolution = 80; | |
328 | mode_info->y_resolution = 25; | |
329 | } | |
330 | else | |
331 | { | |
57994012 | 332 | #if GRUB_MACHINE_HAS_VBE |
01740292 VS |
333 | status = grub_vbe_bios_get_mode_info (vbe_mode, scratch); |
334 | if (status != GRUB_VBE_STATUS_OK) | |
335 | return grub_error (GRUB_ERR_IO, "can't get mode info"); | |
336 | grub_memcpy (mode_info, scratch, | |
337 | sizeof (struct grub_vbe_mode_info_block)); | |
57994012 | 338 | #endif |
01740292 | 339 | } |
57e41c71 VS |
340 | ptrorig += sizeof (struct grub_vbe_mode_info_block); |
341 | ptrdest += sizeof (struct grub_vbe_mode_info_block); | |
57994012 VS |
342 | |
343 | #if GRUB_MACHINE_HAS_VBE | |
0b37526a VS |
344 | grub_vbe_bios_get_pm_interface (&mbi->vbe_interface_seg, |
345 | &mbi->vbe_interface_off, | |
346 | &mbi->vbe_interface_len); | |
57994012 | 347 | #endif |
57e41c71 VS |
348 | |
349 | mbi->flags |= MULTIBOOT_INFO_VBE_INFO; | |
350 | ||
01740292 VS |
351 | if (fill_generic && mode_info->memory_model == GRUB_VBE_MEMORY_MODEL_TEXT) |
352 | { | |
353 | mbi->framebuffer_addr = 0xb8000; | |
354 | ||
355 | mbi->framebuffer_pitch = 2 * mode_info->x_resolution; | |
356 | mbi->framebuffer_width = mode_info->x_resolution; | |
357 | mbi->framebuffer_height = mode_info->y_resolution; | |
358 | ||
359 | mbi->framebuffer_bpp = 16; | |
360 | ||
361 | mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; | |
362 | ||
363 | mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO; | |
364 | } | |
365 | ||
57e41c71 VS |
366 | return GRUB_ERR_NONE; |
367 | } | |
368 | #endif | |
369 | ||
884ade56 VS |
370 | static grub_err_t |
371 | retrieve_video_parameters (struct multiboot_info *mbi, | |
372 | grub_uint8_t *ptrorig, grub_uint32_t ptrdest) | |
373 | { | |
374 | grub_err_t err; | |
375 | struct grub_video_mode_info mode_info; | |
376 | void *framebuffer; | |
377 | grub_video_driver_id_t driv_id; | |
378 | struct grub_video_palette_data palette[256]; | |
379 | ||
5408044f | 380 | err = grub_multiboot_set_video_mode (); |
884ade56 VS |
381 | if (err) |
382 | { | |
383 | grub_print_error (); | |
384 | grub_errno = GRUB_ERR_NONE; | |
385 | } | |
386 | ||
387 | grub_video_get_palette (0, ARRAY_SIZE (palette), palette); | |
388 | ||
389 | driv_id = grub_video_get_driver_id (); | |
9ba27423 | 390 | #if GRUB_MACHINE_HAS_VGA_TEXT |
01740292 VS |
391 | if (driv_id == GRUB_VIDEO_DRIVER_NONE) |
392 | return fill_vbe_info (mbi, ptrorig, ptrdest, 1); | |
393 | #else | |
884ade56 VS |
394 | if (driv_id == GRUB_VIDEO_DRIVER_NONE) |
395 | return GRUB_ERR_NONE; | |
57e41c71 | 396 | #endif |
884ade56 VS |
397 | |
398 | err = grub_video_get_info_and_fini (&mode_info, &framebuffer); | |
399 | if (err) | |
400 | return err; | |
401 | ||
402 | mbi->framebuffer_addr = (grub_addr_t) framebuffer; | |
403 | mbi->framebuffer_pitch = mode_info.pitch; | |
404 | ||
405 | mbi->framebuffer_width = mode_info.width; | |
406 | mbi->framebuffer_height = mode_info.height; | |
407 | ||
408 | mbi->framebuffer_bpp = mode_info.bpp; | |
409 | ||
410 | if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) | |
411 | { | |
412 | struct multiboot_color *mb_palette; | |
413 | unsigned i; | |
414 | mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED; | |
415 | mbi->framebuffer_palette_addr = ptrdest; | |
416 | mbi->framebuffer_palette_num_colors = mode_info.number_of_colors; | |
417 | if (mbi->framebuffer_palette_num_colors > ARRAY_SIZE (palette)) | |
418 | mbi->framebuffer_palette_num_colors = ARRAY_SIZE (palette); | |
419 | mb_palette = (struct multiboot_color *) ptrorig; | |
420 | for (i = 0; i < mbi->framebuffer_palette_num_colors; i++) | |
421 | { | |
422 | mb_palette[i].red = palette[i].r; | |
423 | mb_palette[i].green = palette[i].g; | |
424 | mb_palette[i].blue = palette[i].b; | |
425 | } | |
426 | ptrorig += mbi->framebuffer_palette_num_colors | |
427 | * sizeof (struct multiboot_color); | |
428 | ptrdest += mbi->framebuffer_palette_num_colors | |
429 | * sizeof (struct multiboot_color); | |
430 | } | |
431 | else | |
432 | { | |
433 | mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; | |
e9b29642 CW |
434 | mbi->framebuffer_red_field_position = mode_info.red_field_pos; |
435 | mbi->framebuffer_red_mask_size = mode_info.red_mask_size; | |
884ade56 VS |
436 | mbi->framebuffer_green_field_position = mode_info.green_field_pos; |
437 | mbi->framebuffer_green_mask_size = mode_info.green_mask_size; | |
438 | mbi->framebuffer_blue_field_position = mode_info.blue_field_pos; | |
439 | mbi->framebuffer_blue_mask_size = mode_info.blue_mask_size; | |
440 | } | |
441 | ||
442 | mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO; | |
443 | ||
9ba27423 | 444 | #if GRUB_MACHINE_HAS_VBE |
01740292 VS |
445 | if (driv_id == GRUB_VIDEO_DRIVER_VBE) |
446 | return fill_vbe_info (mbi, ptrorig, ptrdest, 0); | |
57e41c71 VS |
447 | #endif |
448 | ||
884ade56 VS |
449 | return GRUB_ERR_NONE; |
450 | } | |
451 | ||
cd051479 | 452 | grub_err_t |
5c8e58b0 | 453 | grub_multiboot_make_mbi (grub_uint32_t *target) |
cd051479 | 454 | { |
cd051479 VS |
455 | struct multiboot_info *mbi; |
456 | struct multiboot_mod_list *modlist; | |
457 | unsigned i; | |
458 | struct module *cur; | |
459 | grub_size_t mmap_size; | |
5c8e58b0 VS |
460 | grub_uint8_t *ptrorig; |
461 | grub_addr_t ptrdest; | |
88d2919b | 462 | |
5c8e58b0 VS |
463 | grub_err_t err; |
464 | grub_size_t bufsize; | |
4b2ec20b | 465 | grub_relocator_chunk_t ch; |
cd051479 | 466 | |
5c8e58b0 VS |
467 | bufsize = grub_multiboot_get_mbi_size (); |
468 | ||
4b2ec20b | 469 | err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, |
4a70fed8 | 470 | 0x10000, 0xa0000 - bufsize, |
49a716be | 471 | bufsize, 4, |
9be4c45d | 472 | GRUB_RELOCATOR_PREFERENCE_NONE, 0); |
5c8e58b0 VS |
473 | if (err) |
474 | return err; | |
4b2ec20b | 475 | ptrorig = get_virtual_current_address (ch); |
e1dffcf2 | 476 | ptrdest = get_physical_target_address (ch); |
5c8e58b0 VS |
477 | |
478 | *target = ptrdest; | |
cd051479 VS |
479 | |
480 | mbi = (struct multiboot_info *) ptrorig; | |
481 | ptrorig += sizeof (*mbi); | |
482 | ptrdest += sizeof (*mbi); | |
483 | grub_memset (mbi, 0, sizeof (*mbi)); | |
484 | ||
485 | grub_memcpy (ptrorig, cmdline, cmdline_size); | |
486 | mbi->flags |= MULTIBOOT_INFO_CMDLINE; | |
487 | mbi->cmdline = ptrdest; | |
488 | ptrorig += ALIGN_UP (cmdline_size, 4); | |
489 | ptrdest += ALIGN_UP (cmdline_size, 4); | |
490 | ||
491 | grub_memcpy (ptrorig, PACKAGE_STRING, sizeof(PACKAGE_STRING)); | |
492 | mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME; | |
493 | mbi->boot_loader_name = ptrdest; | |
494 | ptrorig += ALIGN_UP (sizeof(PACKAGE_STRING), 4); | |
495 | ptrdest += ALIGN_UP (sizeof(PACKAGE_STRING), 4); | |
496 | ||
890c9fa5 VS |
497 | #ifdef GRUB_MACHINE_PCBIOS |
498 | { | |
499 | struct grub_apm_info info; | |
500 | if (grub_apm_get_info (&info)) | |
501 | { | |
502 | struct multiboot_apm_info *mbinfo = (void *) ptrorig; | |
503 | ||
504 | mbinfo->cseg = info.cseg; | |
505 | mbinfo->offset = info.offset; | |
506 | mbinfo->cseg_16 = info.cseg_16; | |
507 | mbinfo->dseg = info.dseg; | |
508 | mbinfo->flags = info.flags; | |
509 | mbinfo->cseg_len = info.cseg_len; | |
510 | mbinfo->dseg_len = info.dseg_len; | |
511 | mbinfo->cseg_16_len = info.cseg_16_len; | |
512 | mbinfo->version = info.version; | |
513 | ||
514 | ptrorig += ALIGN_UP (sizeof (struct multiboot_apm_info), 4); | |
515 | ptrdest += ALIGN_UP (sizeof (struct multiboot_apm_info), 4); | |
516 | } | |
517 | } | |
518 | #endif | |
519 | ||
cd051479 VS |
520 | if (modcnt) |
521 | { | |
522 | mbi->flags |= MULTIBOOT_INFO_MODS; | |
523 | mbi->mods_addr = ptrdest; | |
524 | mbi->mods_count = modcnt; | |
525 | modlist = (struct multiboot_mod_list *) ptrorig; | |
526 | ptrorig += modcnt * sizeof (struct multiboot_mod_list); | |
527 | ptrdest += modcnt * sizeof (struct multiboot_mod_list); | |
528 | ||
529 | for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) | |
530 | { | |
531 | modlist[i].mod_start = cur->start; | |
532 | modlist[i].mod_end = modlist[i].mod_start + cur->size; | |
533 | modlist[i].cmdline = ptrdest; | |
534 | grub_memcpy (ptrorig, cur->cmdline, cur->cmdline_size); | |
535 | ptrorig += ALIGN_UP (cur->cmdline_size, 4); | |
536 | ptrdest += ALIGN_UP (cur->cmdline_size, 4); | |
537 | } | |
538 | } | |
539 | else | |
540 | { | |
541 | mbi->mods_addr = 0; | |
542 | mbi->mods_count = 0; | |
543 | } | |
544 | ||
8eb567e6 VS |
545 | mmap_size = grub_get_multiboot_mmap_count () |
546 | * sizeof (struct multiboot_mmap_entry); | |
cd051479 VS |
547 | grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig); |
548 | mbi->mmap_length = mmap_size; | |
549 | mbi->mmap_addr = ptrdest; | |
550 | mbi->flags |= MULTIBOOT_INFO_MEM_MAP; | |
551 | ptrorig += mmap_size; | |
552 | ptrdest += mmap_size; | |
553 | ||
554 | /* Convert from bytes to kilobytes. */ | |
555 | mbi->mem_lower = grub_mmap_get_lower () / 1024; | |
556 | mbi->mem_upper = grub_mmap_get_upper () / 1024; | |
557 | mbi->flags |= MULTIBOOT_INFO_MEMORY; | |
558 | ||
559 | if (bootdev_set) | |
560 | { | |
561 | mbi->boot_device = bootdev; | |
562 | mbi->flags |= MULTIBOOT_INFO_BOOTDEV; | |
563 | } | |
564 | ||
779e9dc4 VS |
565 | { |
566 | struct grub_net_network_level_interface *net; | |
567 | FOR_NET_NETWORK_LEVEL_INTERFACES(net) | |
568 | if (net->dhcp_ack) | |
569 | { | |
570 | grub_memcpy (ptrorig, net->dhcp_ack, net->dhcp_acklen); | |
571 | mbi->drives_addr = ptrdest; | |
572 | mbi->drives_length = net->dhcp_acklen; | |
573 | ptrorig += net->dhcp_acklen; | |
574 | ptrdest += net->dhcp_acklen; | |
575 | break; | |
576 | } | |
577 | } | |
578 | ||
865a0f8a VS |
579 | if (elf_sec_num) |
580 | { | |
581 | mbi->u.elf_sec.addr = ptrdest; | |
582 | grub_memcpy (ptrorig, elf_sections, elf_sec_entsize * elf_sec_num); | |
583 | mbi->u.elf_sec.num = elf_sec_num; | |
584 | mbi->u.elf_sec.size = elf_sec_entsize; | |
585 | mbi->u.elf_sec.shndx = elf_sec_shstrndx; | |
586 | ||
587 | mbi->flags |= MULTIBOOT_INFO_ELF_SHDR; | |
45146057 VS |
588 | |
589 | ptrorig += elf_sec_entsize * elf_sec_num; | |
590 | ptrdest += elf_sec_entsize * elf_sec_num; | |
865a0f8a VS |
591 | } |
592 | ||
884ade56 VS |
593 | err = retrieve_video_parameters (mbi, ptrorig, ptrdest); |
594 | if (err) | |
595 | { | |
596 | grub_print_error (); | |
597 | grub_errno = GRUB_ERR_NONE; | |
598 | } | |
45146057 VS |
599 | |
600 | if ((mbi->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO) | |
601 | && mbi->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) | |
602 | { | |
603 | ptrorig += mbi->framebuffer_palette_num_colors | |
604 | * sizeof (struct multiboot_color); | |
605 | ptrdest += mbi->framebuffer_palette_num_colors | |
606 | * sizeof (struct multiboot_color); | |
607 | } | |
608 | ||
9ba27423 | 609 | #if GRUB_MACHINE_HAS_VBE |
57e41c71 VS |
610 | ptrorig += sizeof (struct grub_vbe_info_block); |
611 | ptrdest += sizeof (struct grub_vbe_info_block); | |
612 | ptrorig += sizeof (struct grub_vbe_mode_info_block); | |
613 | ptrdest += sizeof (struct grub_vbe_mode_info_block); | |
614 | #endif | |
884ade56 | 615 | |
329550c4 VS |
616 | #ifdef GRUB_MACHINE_EFI |
617 | err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); | |
618 | if (err) | |
619 | return err; | |
620 | #endif | |
621 | ||
cd051479 VS |
622 | return GRUB_ERR_NONE; |
623 | } | |
624 | ||
865a0f8a VS |
625 | void |
626 | grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize, | |
627 | unsigned shndx, void *data) | |
628 | { | |
629 | elf_sec_num = num; | |
630 | elf_sec_shstrndx = shndx; | |
631 | elf_sec_entsize = entsize; | |
632 | elf_sections = data; | |
633 | } | |
634 | ||
cd051479 VS |
635 | void |
636 | grub_multiboot_free_mbi (void) | |
637 | { | |
638 | struct module *cur, *next; | |
639 | ||
640 | cmdline_size = 0; | |
641 | total_modcmd = 0; | |
642 | modcnt = 0; | |
643 | grub_free (cmdline); | |
644 | cmdline = NULL; | |
645 | bootdev_set = 0; | |
646 | ||
647 | for (cur = modules; cur; cur = next) | |
648 | { | |
649 | next = cur->next; | |
650 | grub_free (cur->cmdline); | |
651 | grub_free (cur); | |
652 | } | |
653 | modules = NULL; | |
654 | modules_last = NULL; | |
865a0f8a VS |
655 | |
656 | grub_free (elf_sections); | |
657 | elf_sections = NULL; | |
658 | elf_sec_entsize = 0; | |
659 | elf_sec_num = 0; | |
cd051479 VS |
660 | } |
661 | ||
662 | grub_err_t | |
663 | grub_multiboot_init_mbi (int argc, char *argv[]) | |
664 | { | |
665 | grub_ssize_t len = 0; | |
cd051479 VS |
666 | |
667 | grub_multiboot_free_mbi (); | |
668 | ||
1a46a3a4 | 669 | len = grub_loader_cmdline_size (argc, argv); |
cd051479 | 670 | |
1a46a3a4 | 671 | cmdline = grub_malloc (len); |
cd051479 VS |
672 | if (! cmdline) |
673 | return grub_errno; | |
674 | cmdline_size = len; | |
675 | ||
1a46a3a4 VS |
676 | grub_create_loader_cmdline (argc, argv, cmdline, |
677 | cmdline_size); | |
cd051479 VS |
678 | |
679 | return GRUB_ERR_NONE; | |
680 | } | |
681 | ||
682 | grub_err_t | |
683 | grub_multiboot_add_module (grub_addr_t start, grub_size_t size, | |
684 | int argc, char *argv[]) | |
685 | { | |
686 | struct module *newmod; | |
1a46a3a4 | 687 | grub_size_t len = 0; |
cd051479 VS |
688 | |
689 | newmod = grub_malloc (sizeof (*newmod)); | |
690 | if (!newmod) | |
691 | return grub_errno; | |
692 | newmod->start = start; | |
693 | newmod->size = size; | |
5318fe98 | 694 | newmod->next = 0; |
cd051479 | 695 | |
1a46a3a4 | 696 | len = grub_loader_cmdline_size (argc, argv); |
cd051479 | 697 | |
1a46a3a4 | 698 | newmod->cmdline = grub_malloc (len); |
cd051479 VS |
699 | if (! newmod->cmdline) |
700 | { | |
701 | grub_free (newmod); | |
702 | return grub_errno; | |
703 | } | |
704 | newmod->cmdline_size = len; | |
705 | total_modcmd += ALIGN_UP (len, 4); | |
706 | ||
1a46a3a4 VS |
707 | grub_create_loader_cmdline (argc, argv, newmod->cmdline, |
708 | newmod->cmdline_size); | |
cd051479 VS |
709 | |
710 | if (modules_last) | |
711 | modules_last->next = newmod; | |
712 | else | |
1a46a3a4 | 713 | modules = newmod; |
cd051479 VS |
714 | modules_last = newmod; |
715 | ||
716 | modcnt++; | |
717 | ||
718 | return GRUB_ERR_NONE; | |
719 | } | |
720 | ||
721 | void | |
722 | grub_multiboot_set_bootdev (void) | |
723 | { | |
cd051479 VS |
724 | grub_uint32_t biosdev, slice = ~0, part = ~0; |
725 | grub_device_t dev; | |
726 | ||
727 | #ifdef GRUB_MACHINE_PCBIOS | |
728 | biosdev = grub_get_root_biosnumber (); | |
729 | #else | |
730 | biosdev = 0xffffffff; | |
731 | #endif | |
732 | ||
23432855 VS |
733 | if (biosdev == 0xffffffff) |
734 | return; | |
735 | ||
cd051479 VS |
736 | dev = grub_device_open (0); |
737 | if (dev && dev->disk && dev->disk->partition) | |
738 | { | |
15cb7d43 VS |
739 | if (dev->disk->partition->parent) |
740 | { | |
741 | part = dev->disk->partition->number; | |
742 | slice = dev->disk->partition->parent->number; | |
cd051479 | 743 | } |
15cb7d43 VS |
744 | else |
745 | slice = dev->disk->partition->number; | |
cd051479 VS |
746 | } |
747 | if (dev) | |
748 | grub_device_close (dev); | |
749 | ||
750 | bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) | |
751 | | ((part & 0xff) << 8) | 0xff; | |
752 | bootdev_set = 1; | |
753 | } |