void grub_reboot (void) { struct grub_relocator *relocator = NULL; grub_relocator_chunk_t ch; grub_err_t err; void *buf; struct grub_relocator16_state state; grub_uint16_t segment; relocator = grub_relocator_new (); if (!relocator) while (1); err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000, 0x1000, grub_reboot_end - grub_reboot_start, 16, GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) while (1); buf = get_virtual_current_address (ch); grub_memcpy (buf, grub_reboot_start, grub_reboot_end - grub_reboot_start); segment = ((grub_addr_t) get_physical_target_address (ch)) >> 4; state.gs = state.fs = state.es = state.ds = state.ss = segment; state.sp = 0; state.cs = segment; state.ip = 0; state.a20 = 0; grub_stop_floppy (); err = grub_relocator16_boot (relocator, state); while (1); }
static grub_err_t load_kernel (grub_file_t file, const char *filename, char *buffer, struct multiboot_header *header) { grub_err_t err; if (grub_multiboot_quirks & GRUB_MULTIBOOT_QUIRK_BAD_KLUDGE) { err = grub_multiboot_load_elf (file, filename, buffer); if (err == GRUB_ERR_NONE) { return GRUB_ERR_NONE; } if (err == GRUB_ERR_UNKNOWN_OS && (header->flags & MULTIBOOT_AOUT_KLUDGE)) grub_errno = err = GRUB_ERR_NONE; } if (header->flags & MULTIBOOT_AOUT_KLUDGE) { int offset = ((char *) header - buffer - (header->header_addr - header->load_addr)); int load_size = ((header->load_end_addr == 0) ? file->size - offset : header->load_end_addr - header->load_addr); grub_size_t code_size; void *source; grub_relocator_chunk_t ch; if (header->bss_end_addr) code_size = (header->bss_end_addr - header->load_addr); else code_size = load_size; err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, &ch, header->load_addr, code_size); if (err) { grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); return err; } source = get_virtual_current_address (ch); if ((grub_file_seek (file, offset)) == (grub_off_t) -1) { return grub_errno; } grub_file_read (file, source, load_size); if (grub_errno) return grub_errno; if (header->bss_end_addr) grub_memset ((grub_uint8_t *) source + load_size, 0, header->bss_end_addr - header->load_addr - load_size); grub_multiboot_payload_eip = header->entry_addr; return GRUB_ERR_NONE; } return grub_multiboot_load_elf (file, filename, buffer); }
grub_err_t grub_relocator16_boot (struct grub_relocator *rel, struct grub_relocator16_state state) { grub_err_t err; void *relst; grub_relocator_chunk_t ch; /* Put it higher than the byte it checks for A20 check. */ err = grub_relocator_alloc_chunk_align (rel, &ch, 0x8010, 0xa0000 - RELOCATOR_SIZEOF (16) - GRUB_RELOCATOR16_STACK_SIZE, RELOCATOR_SIZEOF (16) + GRUB_RELOCATOR16_STACK_SIZE, 16, GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) return err; grub_relocator16_cs = state.cs; grub_relocator16_ip = state.ip; grub_relocator16_ds = state.ds; grub_relocator16_es = state.es; grub_relocator16_fs = state.fs; grub_relocator16_gs = state.gs; grub_relocator16_ss = state.ss; grub_relocator16_sp = state.sp; grub_relocator16_ebp = state.ebp; grub_relocator16_ebx = state.ebx; grub_relocator16_edx = state.edx; grub_relocator16_esi = state.esi; #ifdef GRUB_MACHINE_PCBIOS grub_relocator16_idt = *grub_realidt; #else grub_relocator16_idt.base = 0; grub_relocator16_idt.limit = 0; #endif grub_relocator16_keep_a20_enabled = state.a20; grub_memmove (get_virtual_current_address (ch), &grub_relocator16_start, RELOCATOR_SIZEOF (16)); err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), &relst, NULL); if (err) return err; asm volatile ("cli"); ((void (*) (void)) relst) (); /* Not reached. */ return GRUB_ERR_NONE; }
grub_err_t grub_relocator32_boot (struct grub_relocator *rel, struct grub_relocator32_state state, int avoid_efi_bootservices) { grub_err_t err; void *relst; grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_align (rel, &ch, 0, (0xffffffff - RELOCATOR_SIZEOF (32)) + 1, RELOCATOR_SIZEOF (32), 16, GRUB_RELOCATOR_PREFERENCE_NONE, avoid_efi_bootservices); if (err) return err; grub_relocator32_eax = state.eax; grub_relocator32_ebx = state.ebx; grub_relocator32_ecx = state.ecx; grub_relocator32_edx = state.edx; grub_relocator32_eip = state.eip; grub_relocator32_esp = state.esp; grub_relocator32_ebp = state.ebp; grub_relocator32_esi = state.esi; grub_relocator32_edi = state.edi; grub_memmove (get_virtual_current_address (ch), &grub_relocator32_start, RELOCATOR_SIZEOF (32)); err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), &relst, NULL); if (err) return err; asm volatile ("cli"); ((void (*) (void)) relst) (); /* Not reached. */ return GRUB_ERR_NONE; }
grub_err_t grub_relocator64_boot (struct grub_relocator *rel, struct grub_relocator64_state state, grub_addr_t min_addr, grub_addr_t max_addr) { grub_err_t err; void *relst; grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_align (rel, &ch, min_addr, max_addr - RELOCATOR_SIZEOF (64), RELOCATOR_SIZEOF (64), 16, GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) return err; grub_relocator64_rax = state.rax; grub_relocator64_rbx = state.rbx; grub_relocator64_rcx = state.rcx; grub_relocator64_rdx = state.rdx; grub_relocator64_rip = state.rip; grub_relocator64_rsp = state.rsp; grub_relocator64_rsi = state.rsi; grub_relocator64_cr3 = state.cr3; grub_memmove (get_virtual_current_address (ch), &grub_relocator64_start, RELOCATOR_SIZEOF (64)); err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), &relst, NULL); if (err) return err; asm volatile ("cli"); ((void (*) (void)) relst) (); /* Not reached. */ return GRUB_ERR_NONE; }
static grub_err_t grub_chain_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr, int *do_load) { grub_err_t err; grub_relocator_chunk_t ch; if (phdr->p_type != PT_LOAD) { *do_load = 0; return 0; } *do_load = 1; err = grub_relocator_alloc_chunk_addr (relocator, &ch, phdr->p_paddr, phdr->p_memsz); if (err) return err; *addr = (grub_addr_t) get_virtual_current_address (ch); return GRUB_ERR_NONE; }
grub_err_t SUFFIX (grub_netbsd_load_elf_meta) (struct grub_relocator *relocator, grub_file_t file, grub_addr_t *kern_end) { grub_err_t err; Elf_Ehdr e; Elf_Shdr *s, *symsh, *strsh; char *shdr = NULL; unsigned symsize, strsize; void *sym_chunk; grub_uint8_t *curload; grub_size_t chunk_size; Elf_Ehdr *e2; struct grub_netbsd_btinfo_symtab symtab; grub_addr_t symtarget; err = read_headers (file, &e, &shdr); if (err) return err; for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) if (s->sh_type == SHT_SYMTAB) break; if (s >= (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize)) return GRUB_ERR_NONE; symsize = s->sh_size; symsh = s; s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link); strsize = s->sh_size; strsh = s; chunk_size = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t)) + ALIGN_UP (strsize, sizeof (grub_freebsd_addr_t)) + sizeof (e) + e.e_shnum * e.e_shentsize; symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t)); { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, symtarget, chunk_size); if (err) return err; sym_chunk = get_virtual_current_address (ch); } symtab.nsyms = 1; symtab.ssyms = symtarget; symtab.esyms = symtarget + chunk_size; curload = sym_chunk; e2 = (Elf_Ehdr *) curload; grub_memcpy (curload, &e, sizeof (e)); e2->e_phoff = 0; e2->e_phnum = 0; e2->e_phentsize = 0; e2->e_shstrndx = 0; e2->e_shoff = sizeof (e); curload += sizeof (e); for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) { Elf_Shdr *s2; s2 = (Elf_Shdr *) curload; grub_memcpy (curload, s, e.e_shentsize); if (s == symsh) s2->sh_offset = sizeof (e) + e.e_shnum * e.e_shentsize; else if (s == strsh) s2->sh_offset = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t)) + sizeof (e) + e.e_shnum * e.e_shentsize; else s2->sh_offset = 0; s2->sh_addr = s2->sh_offset; curload += e.e_shentsize; } if (grub_file_seek (file, symsh->sh_offset) == (grub_off_t) -1) return grub_errno; if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize) { if (! grub_errno) return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); return grub_errno; } curload += ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t)); if (grub_file_seek (file, strsh->sh_offset) == (grub_off_t) -1) return grub_errno; if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize) { if (! grub_errno) return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); return grub_errno; } err = grub_bsd_add_meta (NETBSD_BTINFO_SYMTAB, &symtab, sizeof (symtab)); if (err) return err; *kern_end = ALIGN_PAGE (symtarget + chunk_size); return GRUB_ERR_NONE; }
grub_err_t SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator, grub_file_t file, grub_addr_t *kern_end) { grub_err_t err; Elf_Ehdr e; Elf_Shdr *s; char *shdr = 0; unsigned symoff, stroff, symsize, strsize; grub_freebsd_addr_t symstart, symend, symentsize, dynamic; Elf_Sym *sym; void *sym_chunk; grub_uint8_t *curload; grub_freebsd_addr_t symtarget; const char *str; unsigned i; grub_size_t chunk_size; err = read_headers (file, &e, &shdr); if (err) return err; err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ELFHDR, &e, sizeof (e)); if (err) return err; for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) if (s->sh_type == SHT_SYMTAB) break; if (s >= (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize)) return grub_error (GRUB_ERR_BAD_OS, "no symbol table"); symoff = s->sh_offset; symsize = s->sh_size; symentsize = s->sh_entsize; s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link); stroff = s->sh_offset; strsize = s->sh_size; chunk_size = ALIGN_UP (symsize + strsize, sizeof (grub_freebsd_addr_t)) + 2 * sizeof (grub_freebsd_addr_t); symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t)); { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, symtarget, chunk_size); if (err) return err; sym_chunk = get_virtual_current_address (ch); } symstart = symtarget; symend = symstart + chunk_size; curload = sym_chunk; *((grub_freebsd_addr_t *) curload) = symsize; curload += sizeof (grub_freebsd_addr_t); if (grub_file_seek (file, symoff) == (grub_off_t) -1) return grub_errno; sym = (Elf_Sym *) curload; if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize) { if (! grub_errno) return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); return grub_errno; } curload += symsize; *((grub_freebsd_addr_t *) curload) = strsize; curload += sizeof (grub_freebsd_addr_t); if (grub_file_seek (file, stroff) == (grub_off_t) -1) return grub_errno; str = (char *) curload; if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize) { if (! grub_errno) return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); return grub_errno; } for (i = 0; i * symentsize < symsize; i++, sym = (Elf_Sym *) ((char *) sym + symentsize)) { const char *name = str + sym->st_name; if (grub_strcmp (name, "_DYNAMIC") == 0) break; } if (i * symentsize < symsize) { dynamic = sym->st_value; grub_dprintf ("bsd", "dynamic = %llx\n", (unsigned long long) dynamic); err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_DYNAMIC, &dynamic, sizeof (dynamic)); if (err) return err; } err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_SSYM, &symstart, sizeof (symstart)); if (err) return err; err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ESYM, &symend, sizeof (symend)); if (err) return err; *kern_end = ALIGN_PAGE (symend); return GRUB_ERR_NONE; }
grub_err_t SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, grub_file_t file, int argc, char *argv[], grub_addr_t *kern_end) { Elf_Ehdr e; Elf_Shdr *s; char *shdr = 0; grub_addr_t curload, module; grub_err_t err; grub_size_t chunk_size = 0; void *chunk_src; err = read_headers (file, &e, &shdr); if (err) return err; curload = module = ALIGN_PAGE (*kern_end); for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; if (! (s->sh_flags & SHF_ALLOC)) continue; if (chunk_size < s->sh_addr + s->sh_size) chunk_size = s->sh_addr + s->sh_size; } if (chunk_size < sizeof (e)) chunk_size = sizeof (e); chunk_size += e.e_phnum * e.e_phentsize; chunk_size += e.e_shnum * e.e_shentsize; { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, module, chunk_size); if (err) return err; chunk_src = get_virtual_current_address (ch); } for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; if (! (s->sh_flags & SHF_ALLOC)) continue; grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n", (unsigned) curload, (int) s->sh_size, (int) s->sh_addralign); switch (s->sh_type) { default: case SHT_PROGBITS: err = load (file, (grub_uint8_t *) chunk_src + module + s->sh_addr - *kern_end, s->sh_offset, s->sh_size); if (err) return err; break; case SHT_NOBITS: grub_memset ((grub_uint8_t *) chunk_src + module + s->sh_addr - *kern_end, 0, s->sh_size); break; } if (curload < module + s->sh_addr + s->sh_size) curload = module + s->sh_addr + s->sh_size; } load (file, UINT_TO_PTR (module), 0, sizeof (e)); if (curload < module + sizeof (e)) curload = module + sizeof (e); load (file, UINT_TO_PTR (curload), e.e_shoff, e.e_shnum * e.e_shentsize); e.e_shoff = curload - module; curload += e.e_shnum * e.e_shentsize; load (file, UINT_TO_PTR (curload), e.e_phoff, e.e_phnum * e.e_phentsize); e.e_phoff = curload - module; curload += e.e_phnum * e.e_phentsize; *kern_end = curload; grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE, argc - 1, argv + 1, module, curload - module); return SUFFIX (grub_freebsd_load_elf_meta) (relocator, file, kern_end); }
grub_err_t grub_multiboot_make_mbi (grub_uint32_t *target) { grub_properly_aligned_t *ptrorig; grub_properly_aligned_t *mbistart; grub_err_t err; grub_size_t bufsize; grub_relocator_chunk_t ch; bufsize = grub_multiboot_get_mbi_size (); COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % sizeof (grub_properly_aligned_t) == 0); err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, 0, 0xffffffff - bufsize, bufsize, MULTIBOOT_TAG_ALIGN, GRUB_RELOCATOR_PREFERENCE_NONE, 1); if (err) return err; ptrorig = get_virtual_current_address (ch); #if defined (__i386__) || defined (__x86_64__) *target = get_physical_target_address (ch); #elif defined (__mips) *target = get_physical_target_address (ch) | 0x80000000; #else #error Please complete this #endif mbistart = ptrorig; COMPILE_TIME_ASSERT ((2 * sizeof (grub_uint32_t)) % sizeof (grub_properly_aligned_t) == 0); COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % sizeof (grub_properly_aligned_t) == 0); ptrorig += (2 * sizeof (grub_uint32_t)) / sizeof (grub_properly_aligned_t); { struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_CMDLINE; tag->size = sizeof (struct multiboot_tag_string) + cmdline_size; grub_memcpy (tag->string, cmdline, cmdline_size); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } { struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME; tag->size = sizeof (struct multiboot_tag_string) + sizeof (PACKAGE_STRING); grub_memcpy (tag->string, PACKAGE_STRING, sizeof (PACKAGE_STRING)); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } #ifdef GRUB_MACHINE_PCBIOS { struct grub_apm_info info; if (grub_apm_get_info (&info)) { struct multiboot_tag_apm *tag = (struct multiboot_tag_apm *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_APM; tag->size = sizeof (struct multiboot_tag_apm); tag->cseg = info.cseg; tag->offset = info.offset; tag->cseg_16 = info.cseg_16; tag->dseg = info.dseg; tag->flags = info.flags; tag->cseg_len = info.cseg_len; tag->dseg_len = info.dseg_len; tag->cseg_16_len = info.cseg_16_len; tag->version = info.version; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } } #endif { unsigned i; struct module *cur; for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) { struct multiboot_tag_module *tag = (struct multiboot_tag_module *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_MODULE; tag->size = sizeof (struct multiboot_tag_module) + cur->cmdline_size; tag->mod_start = cur->start; tag->mod_end = tag->mod_start + cur->size; grub_memcpy (tag->cmdline, cur->cmdline, cur->cmdline_size); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } } { struct multiboot_tag_mmap *tag = (struct multiboot_tag_mmap *) ptrorig; grub_fill_multiboot_mmap (tag); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } { struct multiboot_tag_elf_sections *tag = (struct multiboot_tag_elf_sections *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_ELF_SECTIONS; tag->size = sizeof (struct multiboot_tag_elf_sections) + elf_sec_entsize * elf_sec_num; grub_memcpy (tag->sections, elf_sections, elf_sec_entsize * elf_sec_num); tag->num = elf_sec_num; tag->entsize = elf_sec_entsize; tag->shndx = elf_sec_shstrndx; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } { struct multiboot_tag_basic_meminfo *tag = (struct multiboot_tag_basic_meminfo *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO; tag->size = sizeof (struct multiboot_tag_basic_meminfo); /* Convert from bytes to kilobytes. */ tag->mem_lower = grub_mmap_get_lower () / 1024; tag->mem_upper = grub_mmap_get_upper () / 1024; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } { struct grub_net_network_level_interface *net; FOR_NET_NETWORK_LEVEL_INTERFACES(net) if (net->dhcp_ack) { struct multiboot_tag_network *tag = (struct multiboot_tag_network *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_NETWORK; tag->size = sizeof (struct multiboot_tag_network) + net->dhcp_acklen; grub_memcpy (tag->dhcpack, net->dhcp_ack, net->dhcp_acklen); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } } if (bootdev_set) { struct multiboot_tag_bootdev *tag = (struct multiboot_tag_bootdev *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_BOOTDEV; tag->size = sizeof (struct multiboot_tag_bootdev); tag->biosdev = biosdev; tag->slice = slice; tag->part = part; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } { err = retrieve_video_parameters (&ptrorig); if (err) { grub_print_error (); grub_errno = GRUB_ERR_NONE; } } #if defined (GRUB_MACHINE_EFI) && defined (__x86_64__) { struct multiboot_tag_efi64 *tag = (struct multiboot_tag_efi64 *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_EFI64; tag->size = sizeof (*tag); tag->pointer = (grub_addr_t) grub_efi_system_table; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } #endif #if defined (GRUB_MACHINE_EFI) && defined (__i386__) { struct multiboot_tag_efi32 *tag = (struct multiboot_tag_efi32 *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_EFI32; tag->size = sizeof (*tag); tag->pointer = (grub_addr_t) grub_efi_system_table; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } #endif #if GRUB_MACHINE_HAS_ACPI { struct multiboot_tag_old_acpi *tag = (struct multiboot_tag_old_acpi *) ptrorig; struct grub_acpi_rsdp_v10 *a = grub_acpi_get_rsdpv1 (); if (a) { tag->type = MULTIBOOT_TAG_TYPE_ACPI_OLD; tag->size = sizeof (*tag) + sizeof (*a); grub_memcpy (tag->rsdp, a, sizeof (*a)); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } } { struct multiboot_tag_new_acpi *tag = (struct multiboot_tag_new_acpi *) ptrorig; struct grub_acpi_rsdp_v20 *a = grub_acpi_get_rsdpv2 (); if (a) { tag->type = MULTIBOOT_TAG_TYPE_ACPI_NEW; tag->size = sizeof (*tag) + a->length; grub_memcpy (tag->rsdp, a, a->length); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } } #endif #ifdef GRUB_MACHINE_EFI { struct multiboot_tag_efi_mmap *tag = (struct multiboot_tag_efi_mmap *) ptrorig; grub_efi_uintn_t efi_desc_size; grub_efi_uint32_t efi_desc_version; tag->type = MULTIBOOT_TAG_TYPE_EFI_MMAP; tag->size = sizeof (*tag) + efi_mmap_size; if (!keep_bs) err = grub_efi_finish_boot_services (&efi_mmap_size, tag->efi_mmap, NULL, &efi_desc_size, &efi_desc_version); else { if (grub_efi_get_memory_map (&efi_mmap_size, (void *) tag->efi_mmap, NULL, &efi_desc_size, &efi_desc_version) <= 0) err = grub_error (GRUB_ERR_IO, "couldn't retrieve memory map"); } if (err) return err; tag->descr_size = efi_desc_size; tag->descr_vers = efi_desc_version; tag->size = sizeof (*tag) + efi_mmap_size; ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } if (keep_bs) { struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_EFI_BS; tag->size = sizeof (struct multiboot_tag); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } #endif { struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_END; tag->size = sizeof (struct multiboot_tag); ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / sizeof (grub_properly_aligned_t); } ((grub_uint32_t *) mbistart)[0] = (char *) ptrorig - (char *) mbistart; ((grub_uint32_t *) mbistart)[1] = 0; return GRUB_ERR_NONE; }
grub_err_t grub_multiboot_load (grub_file_t file, const char *filename) { grub_properly_aligned_t *buffer; grub_ssize_t len; struct multiboot_header *header; grub_err_t err; struct multiboot_header_tag *tag; struct multiboot_header_tag_address *addr_tag = NULL; int entry_specified = 0; grub_addr_t entry = 0; grub_uint32_t console_required = 0; struct multiboot_header_tag_framebuffer *fbtag = NULL; int accepted_consoles = GRUB_MULTIBOOT_CONSOLE_EGA_TEXT; buffer = grub_malloc (MULTIBOOT_SEARCH); if (!buffer) return grub_errno; len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); if (len < 32) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), filename); } COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0); grub_tpm_measure ((unsigned char *)buffer, len, GRUB_BINARY_PCR, "grub_multiboot", filename); header = find_header (buffer, len); if (header == 0) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); } COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % 4 == 0); keep_bs = 0; for (tag = (struct multiboot_header_tag *) (header + 1); tag->type != MULTIBOOT_TAG_TYPE_END; tag = (struct multiboot_header_tag *) ((grub_uint32_t *) tag + ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / 4)) switch (tag->type) { case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST: { unsigned i; struct multiboot_header_tag_information_request *request_tag = (struct multiboot_header_tag_information_request *) tag; if (request_tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL) break; for (i = 0; i < (request_tag->size - sizeof (*request_tag)) / sizeof (request_tag->requests[0]); i++) switch (request_tag->requests[i]) { case MULTIBOOT_TAG_TYPE_END: case MULTIBOOT_TAG_TYPE_CMDLINE: case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: case MULTIBOOT_TAG_TYPE_MODULE: case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: case MULTIBOOT_TAG_TYPE_BOOTDEV: case MULTIBOOT_TAG_TYPE_MMAP: case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: case MULTIBOOT_TAG_TYPE_VBE: case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: case MULTIBOOT_TAG_TYPE_APM: case MULTIBOOT_TAG_TYPE_EFI32: case MULTIBOOT_TAG_TYPE_EFI64: case MULTIBOOT_TAG_TYPE_ACPI_OLD: case MULTIBOOT_TAG_TYPE_ACPI_NEW: case MULTIBOOT_TAG_TYPE_NETWORK: case MULTIBOOT_TAG_TYPE_EFI_MMAP: case MULTIBOOT_TAG_TYPE_EFI_BS: break; default: grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "unsupported information tag: 0x%x", request_tag->requests[i]); } break; } case MULTIBOOT_HEADER_TAG_ADDRESS: addr_tag = (struct multiboot_header_tag_address *) tag; break; case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS: entry_specified = 1; entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr; break; case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS: if (!(((struct multiboot_header_tag_console_flags *) tag)->console_flags & MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED)) accepted_consoles &= ~GRUB_MULTIBOOT_CONSOLE_EGA_TEXT; if (((struct multiboot_header_tag_console_flags *) tag)->console_flags & MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED) console_required = 1; break; case MULTIBOOT_HEADER_TAG_FRAMEBUFFER: fbtag = (struct multiboot_header_tag_framebuffer *) tag; accepted_consoles |= GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER; break; /* GRUB always page-aligns modules. */ case MULTIBOOT_HEADER_TAG_MODULE_ALIGN: break; case MULTIBOOT_HEADER_TAG_EFI_BS: keep_bs = 1; break; default: if (! (tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL)) { grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "unsupported tag: 0x%x", tag->type); } break; } if (addr_tag && !entry_specified) { grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "load address tag without entry address tag"); } if (addr_tag) { grub_uint64_t load_addr = (addr_tag->load_addr + 1) ? addr_tag->load_addr : (addr_tag->header_addr - ((char *) header - (char *) buffer)); int offset = ((char *) header - (char *) buffer - (addr_tag->header_addr - load_addr)); int load_size = ((addr_tag->load_end_addr == 0) ? file->size - offset : addr_tag->load_end_addr - addr_tag->load_addr); grub_size_t code_size; void *source; grub_relocator_chunk_t ch; if (addr_tag->bss_end_addr) code_size = (addr_tag->bss_end_addr - load_addr); else code_size = load_size; err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, &ch, load_addr, code_size); if (err) { grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); grub_free (buffer); return err; } source = get_virtual_current_address (ch); if ((grub_file_seek (file, offset)) == (grub_off_t) -1) { grub_free (buffer); return grub_errno; } grub_file_read (file, source, load_size); if (grub_errno) { grub_free (buffer); return grub_errno; } if (addr_tag->bss_end_addr) grub_memset ((grub_uint8_t *) source + load_size, 0, addr_tag->bss_end_addr - load_addr - load_size); } else { err = grub_multiboot_load_elf (file, filename, buffer); if (err) { grub_free (buffer); return err; } } if (entry_specified) grub_multiboot_payload_eip = entry; if (fbtag) err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, accepted_consoles, fbtag->width, fbtag->height, fbtag->depth, console_required); else err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, accepted_consoles, 0, 0, 0, console_required); return err; }
static grub_err_t grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; grub_ssize_t size; void *module = NULL; grub_addr_t target; grub_err_t err; int nounzip = 0; grub_uint64_t lowest_addr = 0; if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); if (grub_strcmp (argv[0], "--nounzip") == 0) { argv++; argc--; nounzip = 1; } if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); if (!grub_multiboot_relocator) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); if (nounzip) grub_file_filter_disable_compression (); file = grub_file_open (argv[0]); if (! file) return grub_errno; #ifndef GRUB_USE_MULTIBOOT2 lowest_addr = 0x100000; if (grub_multiboot_quirks & GRUB_MULTIBOOT_QUIRK_MODULES_AFTER_KERNEL) lowest_addr = ALIGN_UP (highest_load + 1048576, 4096); #endif size = grub_file_size (file); if (size) { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, lowest_addr, (0xffffffff - size) + 1, size, MULTIBOOT_MOD_ALIGN, GRUB_RELOCATOR_PREFERENCE_NONE, 1); if (err) { grub_file_close (file); return err; } module = get_virtual_current_address (ch); target = get_physical_target_address (ch); } else { module = 0; target = 0; } err = grub_multiboot_add_module (target, size, argc - 1, argv + 1); if (err) { grub_file_close (file); return err; } if (size && grub_file_read (file, module, size) != size) { grub_file_close (file); if (!grub_errno) grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), argv[0]); return grub_errno; } /* Begin TCG Extension */ DEBUG_PRINT( ("measured multiboot module: %s \n", argv[0]) ); grub_TPM_measure_buffer( module, size, TPM_LOADER_MEASUREMENT_PCR ); /* End TCG Extension */ grub_file_close (file); return GRUB_ERR_NONE; }
static grub_err_t grub_linux_boot (void) { grub_err_t err = 0; const char *modevar; char *tmp; struct grub_relocator32_state state; void *real_mode_mem; struct grub_linux_boot_ctx ctx = { .real_mode_target = 0 }; grub_size_t mmap_size; grub_size_t cl_offset; #ifdef GRUB_MACHINE_IEEE1275 { const char *bootpath; grub_ssize_t len; bootpath = grub_env_get ("root"); if (bootpath) grub_ieee1275_set_property (grub_ieee1275_chosen, "bootpath", bootpath, grub_strlen (bootpath) + 1, &len); linux_params.ofw_signature = GRUB_LINUX_OFW_SIGNATURE; linux_params.ofw_num_items = 1; linux_params.ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn; linux_params.ofw_idt = 0; } #endif modevar = grub_env_get ("gfxpayload"); /* Now all graphical modes are acceptable. May change in future if we have modes without framebuffer. */ if (modevar && *modevar != 0) { tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); if (! tmp) return grub_errno; #if ACCEPTS_PURE_TEXT err = grub_video_set_mode (tmp, 0, 0); #else err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); #endif grub_free (tmp); } else /* We can't go back to text mode from coreboot fb. */ #ifdef GRUB_MACHINE_COREBOOT if (grub_video_get_driver_id () == GRUB_VIDEO_DRIVER_COREBOOT) err = GRUB_ERR_NONE; else #endif { #if ACCEPTS_PURE_TEXT err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); #else err = grub_video_set_mode (DEFAULT_VIDEO_MODE, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); #endif } if (err) { grub_print_error (); grub_puts_ (N_("Booting in blind mode")); grub_errno = GRUB_ERR_NONE; } if (grub_linux_setup_video (&linux_params)) { #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) linux_params.have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT; linux_params.video_mode = 0x3; #else linux_params.have_vga = 0; linux_params.video_mode = 0; linux_params.video_width = 0; linux_params.video_height = 0; #endif } #ifndef GRUB_MACHINE_IEEE1275 if (linux_params.have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT) #endif { grub_term_output_t term; int found = 0; FOR_ACTIVE_TERM_OUTPUTS(term) if (grub_strcmp (term->name, "vga_text") == 0 || grub_strcmp (term->name, "console") == 0 || grub_strcmp (term->name, "ofconsole") == 0) { struct grub_term_coordinate pos = grub_term_getxy (term); linux_params.video_cursor_x = pos.x; linux_params.video_cursor_y = pos.y; linux_params.video_width = grub_term_width (term); linux_params.video_height = grub_term_height (term); found = 1; break; } if (!found) { linux_params.video_cursor_x = 0; linux_params.video_cursor_y = 0; linux_params.video_width = 80; linux_params.video_height = 25; } } mmap_size = find_mmap_size (); /* Make sure that each size is aligned to a page boundary. */ cl_offset = ALIGN_UP (mmap_size + sizeof (linux_params), 4096); if (cl_offset < ((grub_size_t) linux_params.setup_sects << GRUB_DISK_SECTOR_BITS)) cl_offset = ALIGN_UP ((grub_size_t) (linux_params.setup_sects << GRUB_DISK_SECTOR_BITS), 4096); ctx.real_size = ALIGN_UP (cl_offset + maximal_cmdline_size, 4096); #ifdef GRUB_MACHINE_EFI efi_mmap_size = find_efi_mmap_size (); if (efi_mmap_size == 0) return grub_errno; #endif grub_dprintf ("linux", "real_size = %x, mmap_size = %x\n", (unsigned) ctx.real_size, (unsigned) mmap_size); #ifdef GRUB_MACHINE_EFI grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 1); if (! ctx.real_mode_target) grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 0); #else grub_mmap_iterate (grub_linux_boot_mmap_find, &ctx); #endif grub_dprintf ("linux", "real_mode_target = %lx, real_size = %x, efi_mmap_size = %x\n", (unsigned long) ctx.real_mode_target, (unsigned) ctx.real_size, (unsigned) efi_mmap_size); if (! ctx.real_mode_target) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, ctx.real_mode_target, (ctx.real_size + efi_mmap_size)); if (err) return err; real_mode_mem = get_virtual_current_address (ch); } efi_mmap_buf = (grub_uint8_t *) real_mode_mem + ctx.real_size; grub_dprintf ("linux", "real_mode_mem = %p\n", real_mode_mem); ctx.params = real_mode_mem; *ctx.params = linux_params; ctx.params->cmd_line_ptr = ctx.real_mode_target + cl_offset; grub_memcpy ((char *) ctx.params + cl_offset, linux_cmdline, maximal_cmdline_size); grub_dprintf ("linux", "code32_start = %x\n", (unsigned) ctx.params->code32_start); ctx.e820_num = 0; if (grub_mmap_iterate (grub_linux_boot_mmap_fill, &ctx)) return grub_errno; ctx.params->mmap_size = ctx.e820_num; #ifdef GRUB_MACHINE_EFI { grub_efi_uintn_t efi_desc_size; grub_size_t efi_mmap_target; grub_efi_uint32_t efi_desc_version; err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL, &efi_desc_size, &efi_desc_version); if (err) return err; /* Note that no boot services are available from here. */ efi_mmap_target = ctx.real_mode_target + ((grub_uint8_t *) efi_mmap_buf - (grub_uint8_t *) real_mode_mem); /* Pass EFI parameters. */ if (grub_le_to_cpu16 (ctx.params->version) >= 0x0208) { ctx.params->v0208.efi_mem_desc_size = efi_desc_size; ctx.params->v0208.efi_mem_desc_version = efi_desc_version; ctx.params->v0208.efi_mmap = efi_mmap_target; ctx.params->v0208.efi_mmap_size = efi_mmap_size; #ifdef __x86_64__ ctx.params->v0208.efi_mmap_hi = (efi_mmap_target >> 32); #endif } else if (grub_le_to_cpu16 (ctx.params->version) >= 0x0206)
/* Allocate pages for the real mode code and the protected mode code for linux as well as a memory map buffer. */ static grub_err_t allocate_pages (grub_size_t prot_size, grub_size_t *align, grub_size_t min_align, int relocatable, grub_uint64_t preferred_address) { grub_err_t err; if (prot_size == 0) prot_size = 1; prot_size = page_align (prot_size); /* Initialize the memory pointers with NULL for convenience. */ free_pages (); relocator = grub_relocator_new (); if (!relocator) { err = grub_errno; goto fail; } /* FIXME: Should request low memory from the heap when this feature is implemented. */ { grub_relocator_chunk_t ch; if (relocatable) { err = grub_relocator_alloc_chunk_align (relocator, &ch, preferred_address, preferred_address, prot_size, 1, GRUB_RELOCATOR_PREFERENCE_LOW, 1); for (; err && *align + 1 > min_align; (*align)--) { grub_errno = GRUB_ERR_NONE; err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000, 0xffffffff & ~prot_size, prot_size, 1 << *align, GRUB_RELOCATOR_PREFERENCE_LOW, 1); } if (err) goto fail; } else err = grub_relocator_alloc_chunk_addr (relocator, &ch, preferred_address, prot_size); if (err) goto fail; prot_mode_mem = get_virtual_current_address (ch); prot_mode_target = get_physical_target_address (ch); } grub_dprintf ("linux", "prot_mode_mem = %p, prot_mode_target = %lx, prot_size = %x\n", prot_mode_mem, (unsigned long) prot_mode_target, (unsigned) prot_size); return GRUB_ERR_NONE; fail: free_pages (); return err; }
static grub_err_t grub_cmd_ntldr (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; grub_err_t err; void *bs, *ntldr; grub_size_t ntldrsize; grub_device_t dev; if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); grub_dl_ref (my_mod); rel = grub_relocator_new (); if (!rel) goto fail; file = grub_file_open (argv[0]); if (! file) goto fail; { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (rel, &ch, 0x7C00, GRUB_DISK_SECTOR_SIZE); if (err) goto fail; bs = get_virtual_current_address (ch); } edx = grub_get_root_biosnumber (); dev = grub_device_open (0); if (dev && dev->disk) { err = grub_disk_read (dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, bs); if (err) { grub_device_close (dev); goto fail; } grub_chainloader_patch_bpb (bs, dev, edx); } if (dev) grub_device_close (dev); ntldrsize = grub_file_size (file); { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_NTLDR_SEGMENT << 4, ntldrsize); if (err) goto fail; ntldr = get_virtual_current_address (ch); } if (grub_file_read (file, ntldr, ntldrsize) != (grub_ssize_t) ntldrsize) goto fail; grub_loader_set (grub_ntldr_boot, grub_ntldr_unload, 1); /* Begin TCG Extension */ if (grub_TPM_isAvailable()) grub_TPM_measureFile( argv[0], TPM_LOADED_FILES_PCR ); /* End TCG Extension */ return GRUB_ERR_NONE; fail: if (file) grub_file_close (file); grub_ntldr_unload (); return grub_errno; }
grub_err_t SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, grub_file_t file, int argc, char *argv[], grub_addr_t *kern_end) { Elf_Ehdr e; Elf_Shdr *s; char *shdr = 0; grub_addr_t curload, module; grub_err_t err; grub_size_t chunk_size = 0; void *chunk_src; err = read_headers (file, &e, &shdr); if (err) return err; curload = module = ALIGN_PAGE (*kern_end); for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; if (s->sh_addralign) chunk_size = ALIGN_UP (chunk_size + *kern_end, s->sh_addralign) - *kern_end; chunk_size += s->sh_size; } { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, module, chunk_size); if (err) return err; chunk_src = get_virtual_current_address (ch); } for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; if (s->sh_addralign) curload = ALIGN_UP (curload, s->sh_addralign); s->sh_addr = curload; grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n", (unsigned) curload, (int) s->sh_size, (int) s->sh_addralign); switch (s->sh_type) { default: case SHT_PROGBITS: err = load (file, (grub_uint8_t *) chunk_src + curload - *kern_end, s->sh_offset, s->sh_size); if (err) return err; break; case SHT_NOBITS: grub_memset ((grub_uint8_t *) chunk_src + curload - *kern_end, 0, s->sh_size); break; } curload += s->sh_size; } *kern_end = ALIGN_PAGE (curload); err = grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE_OBJ, argc - 1, argv + 1, module, curload - module); if (! err) err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ELFHDR, &e, sizeof (e)); if (! err) err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_SHDR, shdr, e.e_shnum * e.e_shentsize); return err; }
static grub_err_t grub_cmd_freedos (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; grub_err_t err; void *bs, *kernelsys; grub_size_t kernelsyssize; grub_device_t dev; if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); grub_dl_ref (my_mod); rel = grub_relocator_new (); if (!rel) goto fail; file = grub_file_open (argv[0]); if (! file) goto fail; { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_FREEDOS_BPB_ADDR, GRUB_DISK_SECTOR_SIZE); if (err) goto fail; bs = get_virtual_current_address (ch); } ebx = grub_get_root_biosnumber (); dev = grub_device_open (0); if (dev && dev->disk) { err = grub_disk_read (dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, bs); if (err) { grub_device_close (dev); goto fail; } grub_chainloader_patch_bpb (bs, dev, ebx); } if (dev) grub_device_close (dev); kernelsyssize = grub_file_size (file); if (kernelsyssize > GRUB_FREEDOS_MAX_SIZE) { grub_error (GRUB_ERR_BAD_OS, N_("the size of `%s' is too large"), argv[0]); goto fail; } { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_FREEDOS_ADDR, kernelsyssize); if (err) goto fail; kernelsys = get_virtual_current_address (ch); } if (grub_file_read (file, kernelsys, kernelsyssize) != (grub_ssize_t) kernelsyssize) goto fail; grub_loader_set (grub_freedos_boot, grub_freedos_unload, 1); return GRUB_ERR_NONE; fail: if (file) grub_file_close (file); grub_freedos_unload (); return grub_errno; }
static grub_err_t grub_cmd_ntldr (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; grub_err_t err; void *bs, *ntldr; grub_size_t ntldrsize; grub_device_t dev; if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); grub_dl_ref (my_mod); rel = grub_relocator_new (); if (!rel) goto fail; file = grub_file_open (argv[0]); if (! file) goto fail; { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (rel, &ch, 0x7C00, GRUB_DISK_SECTOR_SIZE); if (err) goto fail; bs = get_virtual_current_address (ch); } edx = grub_get_root_biosnumber (); dev = grub_device_open (0); if (dev && dev->disk) { err = grub_disk_read (dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, bs); if (err) { grub_device_close (dev); goto fail; } } if (dev) grub_device_close (dev); ntldrsize = grub_file_size (file); { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_NTLDR_SEGMENT << 4, ntldrsize); if (err) goto fail; ntldr = get_virtual_current_address (ch); } if (grub_file_read (file, ntldr, ntldrsize) != (grub_ssize_t) ntldrsize) goto fail; grub_loader_set (grub_ntldr_boot, grub_ntldr_unload, 1); return GRUB_ERR_NONE; fail: if (file) grub_file_close (file); grub_ntldr_unload (); return grub_errno; }
grub_err_t grub_multiboot_make_mbi (grub_uint32_t *target) { struct multiboot_info *mbi; struct multiboot_mod_list *modlist; unsigned i; struct module *cur; grub_size_t mmap_size; grub_uint8_t *ptrorig; grub_addr_t ptrdest; grub_err_t err; grub_size_t bufsize; grub_relocator_chunk_t ch; bufsize = grub_multiboot_get_mbi_size (); err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, 0x10000, 0xa0000 - bufsize, bufsize, 4, GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) return err; ptrorig = get_virtual_current_address (ch); ptrdest = get_physical_target_address (ch); *target = ptrdest; mbi = (struct multiboot_info *) ptrorig; ptrorig += sizeof (*mbi); ptrdest += sizeof (*mbi); grub_memset (mbi, 0, sizeof (*mbi)); grub_memcpy (ptrorig, cmdline, cmdline_size); mbi->flags |= MULTIBOOT_INFO_CMDLINE; mbi->cmdline = ptrdest; ptrorig += ALIGN_UP (cmdline_size, 4); ptrdest += ALIGN_UP (cmdline_size, 4); grub_memcpy (ptrorig, PACKAGE_STRING, sizeof(PACKAGE_STRING)); mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME; mbi->boot_loader_name = ptrdest; ptrorig += ALIGN_UP (sizeof(PACKAGE_STRING), 4); ptrdest += ALIGN_UP (sizeof(PACKAGE_STRING), 4); #ifdef GRUB_MACHINE_PCBIOS { struct grub_apm_info info; if (grub_apm_get_info (&info)) { struct multiboot_apm_info *mbinfo = (void *) ptrorig; mbinfo->cseg = info.cseg; mbinfo->offset = info.offset; mbinfo->cseg_16 = info.cseg_16; mbinfo->dseg = info.dseg; mbinfo->flags = info.flags; mbinfo->cseg_len = info.cseg_len; mbinfo->dseg_len = info.dseg_len; mbinfo->cseg_16_len = info.cseg_16_len; mbinfo->version = info.version; ptrorig += ALIGN_UP (sizeof (struct multiboot_apm_info), 4); ptrdest += ALIGN_UP (sizeof (struct multiboot_apm_info), 4); } } #endif if (modcnt) { mbi->flags |= MULTIBOOT_INFO_MODS; mbi->mods_addr = ptrdest; mbi->mods_count = modcnt; modlist = (struct multiboot_mod_list *) ptrorig; ptrorig += modcnt * sizeof (struct multiboot_mod_list); ptrdest += modcnt * sizeof (struct multiboot_mod_list); for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) { modlist[i].mod_start = cur->start; modlist[i].mod_end = modlist[i].mod_start + cur->size; modlist[i].cmdline = ptrdest; grub_memcpy (ptrorig, cur->cmdline, cur->cmdline_size); ptrorig += ALIGN_UP (cur->cmdline_size, 4); ptrdest += ALIGN_UP (cur->cmdline_size, 4); } } else { mbi->mods_addr = 0; mbi->mods_count = 0; } mmap_size = grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry); grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig); mbi->mmap_length = mmap_size; mbi->mmap_addr = ptrdest; mbi->flags |= MULTIBOOT_INFO_MEM_MAP; ptrorig += mmap_size; ptrdest += mmap_size; /* Convert from bytes to kilobytes. */ mbi->mem_lower = grub_mmap_get_lower () / 1024; mbi->mem_upper = grub_mmap_get_upper () / 1024; mbi->flags |= MULTIBOOT_INFO_MEMORY; if (bootdev_set) { mbi->boot_device = bootdev; mbi->flags |= MULTIBOOT_INFO_BOOTDEV; } { struct grub_net_network_level_interface *net; FOR_NET_NETWORK_LEVEL_INTERFACES(net) if (net->dhcp_ack) { grub_memcpy (ptrorig, net->dhcp_ack, net->dhcp_acklen); mbi->drives_addr = ptrdest; mbi->drives_length = net->dhcp_acklen; ptrorig += net->dhcp_acklen; ptrdest += net->dhcp_acklen; break; } } if (elf_sec_num) { mbi->u.elf_sec.addr = ptrdest; grub_memcpy (ptrorig, elf_sections, elf_sec_entsize * elf_sec_num); mbi->u.elf_sec.num = elf_sec_num; mbi->u.elf_sec.size = elf_sec_entsize; mbi->u.elf_sec.shndx = elf_sec_shstrndx; mbi->flags |= MULTIBOOT_INFO_ELF_SHDR; ptrorig += elf_sec_entsize * elf_sec_num; ptrdest += elf_sec_entsize * elf_sec_num; } err = retrieve_video_parameters (mbi, ptrorig, ptrdest); if (err) { grub_print_error (); grub_errno = GRUB_ERR_NONE; } if ((mbi->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO) && mbi->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) { ptrorig += mbi->framebuffer_palette_num_colors * sizeof (struct multiboot_color); ptrdest += mbi->framebuffer_palette_num_colors * sizeof (struct multiboot_color); } #if GRUB_MACHINE_HAS_VBE ptrorig += sizeof (struct grub_vbe_info_block); ptrdest += sizeof (struct grub_vbe_info_block); ptrorig += sizeof (struct grub_vbe_mode_info_block); ptrdest += sizeof (struct grub_vbe_mode_info_block); #endif #ifdef GRUB_MACHINE_EFI err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); if (err) return err; #endif return GRUB_ERR_NONE; }
static grub_err_t grub_cmd_pxechain (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; grub_err_t err; void *image; grub_size_t imagesize; char *fname; if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); grub_dl_ref (my_mod); rel = grub_relocator_new (); if (!rel) goto fail; file = grub_file_open (argv[0]); if (! file) goto fail; if (file->device->net && file->device->net->name) fname = file->device->net->name; else { fname = argv[0]; if (fname[0] == '(') { fname = grub_strchr (fname, ')'); if (fname) fname++; else fname = argv[0]; } } grub_memset (boot_file, 0, sizeof (boot_file)); grub_strncpy (boot_file, fname, sizeof (boot_file)); grub_memset (server_name, 0, sizeof (server_name)); if (file->device->net && file->device->net->server) grub_strncpy (server_name, file->device->net->server, sizeof (server_name)); edx = grub_get_root_biosnumber (); imagesize = grub_file_size (file); { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (rel, &ch, 0x7c00, imagesize); if (err) goto fail; image = get_virtual_current_address (ch); } if (grub_file_read (file, image, imagesize) != (grub_ssize_t) imagesize) goto fail; grub_loader_set (grub_pxechain_boot, grub_pxechain_unload, GRUB_LOADER_FLAG_NORETURN | GRUB_LOADER_FLAG_PXE_NOT_UNLOAD); return GRUB_ERR_NONE; fail: if (file) grub_file_close (file); grub_pxechain_unload (); return grub_errno; }
grub_err_t grub_multiboot_load (grub_file_t file) { char *buffer; grub_ssize_t len; struct multiboot_header *header; grub_err_t err; buffer = grub_malloc (MULTIBOOT_SEARCH); if (!buffer) return grub_errno; len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); if (len < 32) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_OS, "file too small"); } /* Look for the multiboot header in the buffer. The header should be at least 12 bytes and aligned on a 4-byte boundary. */ for (header = (struct multiboot_header *) buffer; ((char *) header <= buffer + len - 12) || (header = 0); header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN)) { if (header->magic == MULTIBOOT_HEADER_MAGIC && !(header->magic + header->flags + header->checksum)) break; } if (header == 0) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); } if (header->flags & UNSUPPORTED_FLAGS) { grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "unsupported flag: 0x%x", header->flags); } if (header->flags & MULTIBOOT_AOUT_KLUDGE) { int offset = ((char *) header - buffer - (header->header_addr - header->load_addr)); int load_size = ((header->load_end_addr == 0) ? file->size - offset : header->load_end_addr - header->load_addr); grub_size_t code_size; void *source; grub_relocator_chunk_t ch; if (header->bss_end_addr) code_size = (header->bss_end_addr - header->load_addr); else code_size = load_size; err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, &ch, header->load_addr, code_size); if (err) { grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); grub_free (buffer); return err; } source = get_virtual_current_address (ch); if ((grub_file_seek (file, offset)) == (grub_off_t) -1) { grub_free (buffer); return grub_errno; } grub_file_read (file, source, load_size); if (grub_errno) { grub_free (buffer); return grub_errno; } if (header->bss_end_addr) grub_memset ((grub_uint8_t *) source + load_size, 0, header->bss_end_addr - header->load_addr - load_size); grub_multiboot_payload_eip = header->entry_addr; } else { err = grub_multiboot_load_elf (file, buffer); if (err) { grub_free (buffer); return err; } } if (header->flags & MULTIBOOT_VIDEO_MODE) { switch (header->mode_type) { case 1: err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, 0, 0, 0, 0); break; case 0: err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, header->width, header->height, header->depth, 0); break; default: err = grub_error (GRUB_ERR_BAD_OS, "unsupported graphical mode type %d", header->mode_type); break; } } else err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, 0, 0, 0, 0); return err; }
static grub_err_t CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, const char *filename, void *buffer) { Elf_Ehdr *ehdr = (Elf_Ehdr *) buffer; char *phdr_base; int i; if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || ehdr->e_ident[EI_MAG1] != ELFMAG1 || ehdr->e_ident[EI_MAG2] != ELFMAG2 || ehdr->e_ident[EI_MAG3] != ELFMAG3 || ehdr->e_ident[EI_DATA] != ELFDATA2LSB) return grub_error(GRUB_ERR_UNKNOWN_OS, N_("invalid arch-independent ELF magic")); if (ehdr->e_ident[EI_CLASS] != ELFCLASSXX || ehdr->e_machine != E_MACHINE || ehdr->e_version != EV_CURRENT) return grub_error (GRUB_ERR_UNKNOWN_OS, N_("invalid arch-dependent ELF magic")); if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) return grub_error (GRUB_ERR_UNKNOWN_OS, N_("this ELF file is not of the right type")); /* FIXME: Should we support program headers at strange locations? */ if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > MULTIBOOT_SEARCH) return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset"); phdr_base = (char *) buffer + ehdr->e_phoff; #define phdr(i) ((Elf_Phdr *) (phdr_base + (i) * ehdr->e_phentsize)) /* Load every loadable segment in memory. */ for (i = 0; i < ehdr->e_phnum; i++) { if (phdr(i)->p_type == PT_LOAD) { grub_err_t err; void *source; grub_dprintf ("multiboot_loader", "segment %d: paddr=0x%lx, memsz=0x%lx, vaddr=0x%lx\n", i, (long) phdr(i)->p_paddr, (long) phdr(i)->p_memsz, (long) phdr(i)->p_vaddr); { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, &ch, phdr(i)->p_paddr, phdr(i)->p_memsz); if (err) { grub_dprintf ("multiboot_loader", "Error loading phdr %d\n", i); return err; } source = get_virtual_current_address (ch); } if (phdr(i)->p_filesz != 0) { if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset) == (grub_off_t) -1) return grub_errno; if (grub_file_read (file, source, phdr(i)->p_filesz) != (grub_ssize_t) phdr(i)->p_filesz) { if (!grub_errno) grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), filename); return grub_errno; } } if (phdr(i)->p_filesz < phdr(i)->p_memsz) grub_memset ((grub_uint8_t *) source + phdr(i)->p_filesz, 0, phdr(i)->p_memsz - phdr(i)->p_filesz); } } for (i = 0; i < ehdr->e_phnum; i++) if (phdr(i)->p_vaddr <= ehdr->e_entry && phdr(i)->p_vaddr + phdr(i)->p_memsz > ehdr->e_entry) { grub_multiboot_payload_eip = (ehdr->e_entry - phdr(i)->p_vaddr) + phdr(i)->p_paddr; #ifdef MULTIBOOT_LOAD_ELF64 # ifdef __mips /* We still in 32-bit mode. */ if ((ehdr->e_entry - phdr(i)->p_vaddr) + phdr(i)->p_paddr < 0xffffffff80000000ULL) return grub_error (GRUB_ERR_BAD_OS, "invalid entry point for ELF64"); # else /* We still in 32-bit mode. */ if ((ehdr->e_entry - phdr(i)->p_vaddr) + phdr(i)->p_paddr > 0xffffffff) return grub_error (GRUB_ERR_BAD_OS, "invalid entry point for ELF64"); # endif #endif break; } if (i == ehdr->e_phnum) return grub_error (GRUB_ERR_BAD_OS, "entry point isn't in a segment"); #if defined (__i386__) || defined (__x86_64__) #elif defined (__mips) grub_multiboot_payload_eip |= 0x80000000; #else #error Please complete this #endif if (ehdr->e_shnum) { grub_uint8_t *shdr, *shdrptr; shdr = grub_malloc (ehdr->e_shnum * ehdr->e_shentsize); if (!shdr) return grub_errno; if (grub_file_seek (file, ehdr->e_shoff) == (grub_off_t) -1) return grub_errno; if (grub_file_read (file, shdr, ehdr->e_shnum * ehdr->e_shentsize) != (grub_ssize_t) ehdr->e_shnum * ehdr->e_shentsize) { if (!grub_errno) grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), filename); return grub_errno; } for (shdrptr = shdr, i = 0; i < ehdr->e_shnum; shdrptr += ehdr->e_shentsize, i++) { Elf_Shdr *sh = (Elf_Shdr *) shdrptr; void *src; grub_addr_t target; grub_err_t err; /* This section is a loaded section, so we don't care. */ if (sh->sh_addr != 0) continue; /* This section is empty, so we don't care. */ if (sh->sh_size == 0) continue; { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, 0, (0xffffffff - sh->sh_size) + 1, sh->sh_size, sh->sh_addralign, GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) { grub_dprintf ("multiboot_loader", "Error loading shdr %d\n", i); return err; } src = get_virtual_current_address (ch); target = get_physical_target_address (ch); } if (grub_file_seek (file, sh->sh_offset) == (grub_off_t) -1) return grub_errno; if (grub_file_read (file, src, sh->sh_size) != (grub_ssize_t) sh->sh_size) { if (!grub_errno) grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), filename); return grub_errno; } sh->sh_addr = target; } grub_multiboot_add_elfsyms (ehdr->e_shnum, ehdr->e_shentsize, ehdr->e_shstrndx, shdr); } #undef phdr return grub_errno; }