xref: /netbsd-src/sys/arch/i386/stand/lib/exec_multiboot1.c (revision 29023497620a907f793d9640c508bf188a07e1f8)
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