1*29023497Smanu /* $NetBSD: exec_multiboot1.c,v 1.3 2019/10/18 01:09:46 manu Exp $ */
25e073c03Smanu
35e073c03Smanu /*
45e073c03Smanu * Copyright (c) 2019 The NetBSD Foundation, Inc.
55e073c03Smanu * All rights reserved.
65e073c03Smanu *
75e073c03Smanu * Redistribution and use in source and binary forms, with or without
85e073c03Smanu * modification, are permitted provided that the following conditions
95e073c03Smanu * are met:
105e073c03Smanu * 1. Redistributions of source code must retain the above copyright
115e073c03Smanu * notice, this list of conditions and the following disclaimer.
125e073c03Smanu * 2. Redistributions in binary form must reproduce the above copyright
135e073c03Smanu * notice, this list of conditions and the following disclaimer in the
145e073c03Smanu * documentation and/or other materials provided with the distribution.
155e073c03Smanu *
165e073c03Smanu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
175e073c03Smanu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
185e073c03Smanu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
195e073c03Smanu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
205e073c03Smanu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
215e073c03Smanu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
225e073c03Smanu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
235e073c03Smanu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
245e073c03Smanu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
255e073c03Smanu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
265e073c03Smanu * POSSIBILITY OF SUCH DAMAGE.
275e073c03Smanu */
285e073c03Smanu
295e073c03Smanu #include <sys/param.h>
305e073c03Smanu #include <sys/reboot.h>
315e073c03Smanu
325e073c03Smanu #include <i386/multiboot.h>
335e073c03Smanu
345e073c03Smanu #include <lib/libsa/stand.h>
355e073c03Smanu #include <lib/libkern/libkern.h>
365e073c03Smanu
375e073c03Smanu #include "loadfile.h"
385e073c03Smanu #include "libi386.h"
395e073c03Smanu #include "bootinfo.h"
405e073c03Smanu #include "bootmod.h"
415e073c03Smanu #include "vbe.h"
425e073c03Smanu
435e073c03Smanu extern struct btinfo_modulelist *btinfo_modulelist;
445e073c03Smanu
45*29023497Smanu void
ksyms_addr_set(void * ehdr,void * shdr,void * symbase)46*29023497Smanu ksyms_addr_set(void *ehdr, void *shdr, void *symbase)
47*29023497Smanu {
48*29023497Smanu int class;
49*29023497Smanu Elf32_Ehdr *ehdr32 = NULL;
50*29023497Smanu Elf64_Ehdr *ehdr64 = NULL;
51*29023497Smanu uint64_t shnum;
52*29023497Smanu int i;
53*29023497Smanu
54*29023497Smanu class = ((Elf_Ehdr *)ehdr)->e_ident[EI_CLASS];
55*29023497Smanu
56*29023497Smanu switch (class) {
57*29023497Smanu case ELFCLASS32:
58*29023497Smanu ehdr32 = (Elf32_Ehdr *)ehdr;
59*29023497Smanu shnum = ehdr32->e_shnum;
60*29023497Smanu break;
61*29023497Smanu case ELFCLASS64:
62*29023497Smanu ehdr64 = (Elf64_Ehdr *)ehdr;
63*29023497Smanu shnum = ehdr64->e_shnum;
64*29023497Smanu break;
65*29023497Smanu default:
66*29023497Smanu panic("Unexpected ELF class");
67*29023497Smanu break;
68*29023497Smanu }
69*29023497Smanu
70*29023497Smanu for (i = 0; i < shnum; i++) {
71*29023497Smanu Elf64_Shdr *shdrp64 = NULL;
72*29023497Smanu Elf32_Shdr *shdrp32 = NULL;
73*29023497Smanu uint64_t shtype, shaddr, shsize, shoffset;
74*29023497Smanu
75*29023497Smanu switch(class) {
76*29023497Smanu case ELFCLASS64:
77*29023497Smanu shdrp64 = &((Elf64_Shdr *)shdr)[i];
78*29023497Smanu shtype = shdrp64->sh_type;
79*29023497Smanu shaddr = shdrp64->sh_addr;
80*29023497Smanu shsize = shdrp64->sh_size;
81*29023497Smanu shoffset = shdrp64->sh_offset;
82*29023497Smanu break;
83*29023497Smanu case ELFCLASS32:
84*29023497Smanu shdrp32 = &((Elf32_Shdr *)shdr)[i];
85*29023497Smanu shtype = shdrp32->sh_type;
86*29023497Smanu shaddr = shdrp32->sh_addr;
87*29023497Smanu shsize = shdrp32->sh_size;
88*29023497Smanu shoffset = shdrp32->sh_offset;
89*29023497Smanu break;
90*29023497Smanu default:
91*29023497Smanu panic("Unexpected ELF class");
92*29023497Smanu break;
93*29023497Smanu }
94*29023497Smanu
95*29023497Smanu if (shtype != SHT_SYMTAB && shtype != SHT_STRTAB)
96*29023497Smanu continue;
97*29023497Smanu
98*29023497Smanu if (shaddr != 0 || shsize == 0)
99*29023497Smanu continue;
100*29023497Smanu
101*29023497Smanu shaddr = (uint64_t)(uintptr_t)(symbase + shoffset);
102*29023497Smanu
103*29023497Smanu switch(class) {
104*29023497Smanu case ELFCLASS64:
105*29023497Smanu shdrp64->sh_addr = shaddr;
106*29023497Smanu break;
107*29023497Smanu case ELFCLASS32:
108*29023497Smanu shdrp32->sh_addr = shaddr;
109*29023497Smanu break;
110*29023497Smanu default:
111*29023497Smanu panic("Unexpected ELF class");
112*29023497Smanu break;
113*29023497Smanu }
114*29023497Smanu }
115*29023497Smanu
116*29023497Smanu return;
117*29023497Smanu }
118*29023497Smanu
1195e073c03Smanu static int
exec_multiboot1(struct multiboot_package * mbp)1205e073c03Smanu exec_multiboot1(struct multiboot_package *mbp)
1215e073c03Smanu {
1225e073c03Smanu struct multiboot_info *mbi;
1235e073c03Smanu struct multiboot_module *mbm;
1245e073c03Smanu int i, len;
1255e073c03Smanu char *cmdline;
1265e073c03Smanu struct bi_modulelist_entry *bim;
1275e073c03Smanu
1285e073c03Smanu mbi = alloc(sizeof(struct multiboot_info));
1295e073c03Smanu mbi->mi_flags = MULTIBOOT_INFO_HAS_MEMORY;
1305e073c03Smanu
1315e073c03Smanu mbi->mi_mem_upper = mbp->mbp_extmem;
1325e073c03Smanu mbi->mi_mem_lower = mbp->mbp_basemem;
1335e073c03Smanu
1345e073c03Smanu if (mbp->mbp_args) {
1355e073c03Smanu mbi->mi_flags |= MULTIBOOT_INFO_HAS_CMDLINE;
1365e073c03Smanu len = strlen(mbp->mbp_file) + 1 + strlen(mbp->mbp_args) + 1;
1375e073c03Smanu cmdline = alloc(len);
1385e073c03Smanu snprintf(cmdline, len, "%s %s", mbp->mbp_file, mbp->mbp_args);
1395e073c03Smanu mbi->mi_cmdline = (char *) vtophys(cmdline);
1405e073c03Smanu }
1415e073c03Smanu
1425e073c03Smanu /* pull in any modules if necessary */
1435e073c03Smanu if (btinfo_modulelist) {
1445e073c03Smanu mbm = alloc(sizeof(struct multiboot_module) *
1455e073c03Smanu btinfo_modulelist->num);
1465e073c03Smanu
1475e073c03Smanu bim = (struct bi_modulelist_entry *)
1485e073c03Smanu (((char *) btinfo_modulelist) +
1495e073c03Smanu sizeof(struct btinfo_modulelist));
1505e073c03Smanu for (i = 0; i < btinfo_modulelist->num; i++) {
1515e073c03Smanu mbm[i].mmo_start = bim->base;
1525e073c03Smanu mbm[i].mmo_end = bim->base + bim->len;
1535e073c03Smanu mbm[i].mmo_string = (char *)vtophys(bim->path);
1545e073c03Smanu mbm[i].mmo_reserved = 0;
1555e073c03Smanu bim++;
1565e073c03Smanu }
1575e073c03Smanu mbi->mi_flags |= MULTIBOOT_INFO_HAS_MODS;
1585e073c03Smanu mbi->mi_mods_count = btinfo_modulelist->num;
1595e073c03Smanu mbi->mi_mods_addr = vtophys(mbm);
1605e073c03Smanu }
1615e073c03Smanu
162*29023497Smanu if (mbp->mbp_marks[MARK_SYM] != 0) {
163*29023497Smanu Elf32_Ehdr ehdr;
164*29023497Smanu void *shbuf;
165*29023497Smanu size_t shlen;
166*29023497Smanu u_long shaddr;
167*29023497Smanu
168*29023497Smanu pvbcopy((void *)mbp->mbp_marks[MARK_SYM], &ehdr, sizeof(ehdr));
169*29023497Smanu
170*29023497Smanu if (memcmp(&ehdr.e_ident, ELFMAG, SELFMAG) != 0)
171*29023497Smanu goto skip_ksyms;
172*29023497Smanu
173*29023497Smanu shaddr = mbp->mbp_marks[MARK_SYM] + ehdr.e_shoff;
174*29023497Smanu
175*29023497Smanu shlen = ehdr.e_shnum * ehdr.e_shentsize;
176*29023497Smanu shbuf = alloc(shlen);
177*29023497Smanu
178*29023497Smanu pvbcopy((void *)shaddr, shbuf, shlen);
179*29023497Smanu ksyms_addr_set(&ehdr, shbuf,
180*29023497Smanu (void *)(KERNBASE + mbp->mbp_marks[MARK_SYM]));
181*29023497Smanu vpbcopy(shbuf, (void *)shaddr, shlen);
182*29023497Smanu
183*29023497Smanu dealloc(shbuf, shlen);
184*29023497Smanu
185*29023497Smanu mbi->mi_elfshdr_num = ehdr.e_shnum;
186*29023497Smanu mbi->mi_elfshdr_size = ehdr.e_shentsize;
187*29023497Smanu mbi->mi_elfshdr_addr = shaddr;
188*29023497Smanu mbi->mi_elfshdr_shndx = ehdr.e_shstrndx;
189*29023497Smanu
190*29023497Smanu mbi->mi_flags |= MULTIBOOT_INFO_HAS_ELF_SYMS;
191*29023497Smanu }
192*29023497Smanu skip_ksyms:
193*29023497Smanu
1945e073c03Smanu #ifdef DEBUG
1955e073c03Smanu printf("Start @ 0x%lx [%ld=0x%lx-0x%lx]...\n",
1965e073c03Smanu mbp->mbp_marks[MARK_ENTRY],
1975e073c03Smanu mbp->mbp_marks[MARK_NSYM],
1985e073c03Smanu mbp->mbp_marks[MARK_SYM],
1995e073c03Smanu mbp->mbp_marks[MARK_END]);
2005e073c03Smanu #endif
2015e073c03Smanu
2025e073c03Smanu /* Does not return */
2035e073c03Smanu multiboot(mbp->mbp_marks[MARK_ENTRY], vtophys(mbi),
2045e073c03Smanu x86_trunc_page(mbi->mi_mem_lower * 1024), MULTIBOOT_INFO_MAGIC);
2055e073c03Smanu
2065e073c03Smanu return 0;
2075e073c03Smanu }
2085e073c03Smanu
2095e073c03Smanu static void
cleanup_multiboot1(struct multiboot_package * mbp)2105e073c03Smanu cleanup_multiboot1(struct multiboot_package *mbp)
2115e073c03Smanu {
2125e073c03Smanu dealloc(mbp->mbp_header, sizeof(*mbp->mbp_header));
2135e073c03Smanu dealloc(mbp, sizeof(*mbp));
2145e073c03Smanu
2155e073c03Smanu return;
2165e073c03Smanu }
2175e073c03Smanu
2185e073c03Smanu
2195e073c03Smanu struct multiboot_package *
probe_multiboot1(const char * path)2205e073c03Smanu probe_multiboot1(const char *path)
2215e073c03Smanu {
2225e073c03Smanu int fd = -1;
2235e073c03Smanu size_t i;
2245e073c03Smanu char buf[8192 + sizeof(struct multiboot_header)];
2255e073c03Smanu ssize_t readen;
2265e073c03Smanu struct multiboot_package *mbp = NULL;
2275e073c03Smanu
2285e073c03Smanu if ((fd = open(path, 0)) == -1)
2295e073c03Smanu goto out;
2305e073c03Smanu
2315e073c03Smanu readen = read(fd, buf, sizeof(buf));
2325e073c03Smanu if (readen < sizeof(struct multiboot_header))
2335e073c03Smanu goto out;
2345e073c03Smanu
2356868572cSmanu for (i = 0; i < readen; i += 4) {
2365e073c03Smanu struct multiboot_header *mbh;
2375e073c03Smanu
2385e073c03Smanu mbh = (struct multiboot_header *)(buf + i);
2395e073c03Smanu
2405e073c03Smanu if (mbh->mh_magic != MULTIBOOT_HEADER_MAGIC)
2415e073c03Smanu continue;
2425e073c03Smanu
2435e073c03Smanu if (mbh->mh_magic + mbh->mh_flags + mbh->mh_checksum)
2445e073c03Smanu continue;
2455e073c03Smanu
2465e073c03Smanu mbp = alloc(sizeof(*mbp));
2475e073c03Smanu mbp->mbp_version = 1;
2485e073c03Smanu mbp->mbp_file = path;
2495e073c03Smanu mbp->mbp_header = alloc(sizeof(*mbp->mbp_header));
2505e073c03Smanu mbp->mbp_probe = *probe_multiboot1;
2515e073c03Smanu mbp->mbp_exec = *exec_multiboot1;
2525e073c03Smanu mbp->mbp_cleanup = *cleanup_multiboot1;
2535e073c03Smanu
2545e073c03Smanu memcpy(mbp->mbp_header, mbh, sizeof(*mbp->mbp_header));
2555e073c03Smanu
2565e073c03Smanu goto out;
2575e073c03Smanu
2585e073c03Smanu }
2595e073c03Smanu
2605e073c03Smanu out:
2615e073c03Smanu if (fd != -1)
2625e073c03Smanu close(fd);
2635e073c03Smanu
2645e073c03Smanu return mbp;
2655e073c03Smanu }
266