1199767f8SToomas Soome /*
2199767f8SToomas Soome  * This file and its contents are supplied under the terms of the
3199767f8SToomas Soome  * Common Development and Distribution License ("CDDL"), version 1.0.
4199767f8SToomas Soome  * You may only use this file in accordance with the terms of version
5199767f8SToomas Soome  * 1.0 of the CDDL.
6199767f8SToomas Soome  *
7199767f8SToomas Soome  * A full copy of the text of the CDDL should have accompanied this
8199767f8SToomas Soome  * source.  A copy of the CDDL is also available via the Internet at
9199767f8SToomas Soome  * http://www.illumos.org/license/CDDL.
10199767f8SToomas Soome  */
11199767f8SToomas Soome 
12199767f8SToomas Soome /*
13199767f8SToomas Soome  * Copyright 2015 Toomas Soome <tsoome@me.com>
14199767f8SToomas Soome  */
15199767f8SToomas Soome 
16199767f8SToomas Soome /*
17199767f8SToomas Soome  * Primitive linux loader, at the moment only intended to load memtest86+.bin.
18199767f8SToomas Soome  *
19199767f8SToomas Soome  * Note the linux kernel location conflicts with loader, so we need to
20199767f8SToomas Soome  * read in to temporary space and relocate on exec, when btx is stopped.
21199767f8SToomas Soome  */
22199767f8SToomas Soome #include <sys/cdefs.h>
23199767f8SToomas Soome #include <sys/stat.h>
24199767f8SToomas Soome #include <stand.h>
25199767f8SToomas Soome #include <machine/metadata.h>
26199767f8SToomas Soome #include <machine/pc/bios.h>
27199767f8SToomas Soome 
28199767f8SToomas Soome #include "linux.h"
29199767f8SToomas Soome #include "bootstrap.h"
309890ff83SToomas Soome #include "vbe.h"
31199767f8SToomas Soome #include "libi386.h"
32199767f8SToomas Soome #include "btxv86.h"
33199767f8SToomas Soome 
34199767f8SToomas Soome static int linux_loadkernel(char *, u_int64_t, struct preloaded_file **);
35199767f8SToomas Soome static int linux_loadinitrd(char *, u_int64_t, struct preloaded_file **);
36199767f8SToomas Soome static int linux_exec(struct preloaded_file *);
37199767f8SToomas Soome static int linux_execinitrd(struct preloaded_file *);
38199767f8SToomas Soome 
39199767f8SToomas Soome struct file_format linux = { linux_loadkernel, linux_exec };
40199767f8SToomas Soome struct file_format linux_initrd = { linux_loadinitrd, linux_execinitrd };
41199767f8SToomas Soome 
42199767f8SToomas Soome uint32_t linux_text_len;
43199767f8SToomas Soome uint32_t linux_data_tmp_addr;
44199767f8SToomas Soome uint32_t linux_data_real_addr;
45199767f8SToomas Soome static size_t max_cmdline_size;
46199767f8SToomas Soome 
47199767f8SToomas Soome static void
test_addr(uint64_t addr,uint64_t length,vm_offset_t * result)48199767f8SToomas Soome test_addr(uint64_t addr, uint64_t length, vm_offset_t *result)
49199767f8SToomas Soome {
50199767f8SToomas Soome 	vm_offset_t candidate;
51199767f8SToomas Soome 
52199767f8SToomas Soome 	if (addr + length >= 0xa0000)
53199767f8SToomas Soome 		length = 0xa0000 - addr;
54199767f8SToomas Soome 
55199767f8SToomas Soome 	candidate = addr + length - (LINUX_CL_OFFSET + max_cmdline_size);
56199767f8SToomas Soome 	if (candidate > LINUX_OLD_REAL_MODE_ADDR)
57199767f8SToomas Soome 		candidate = LINUX_OLD_REAL_MODE_ADDR;
58199767f8SToomas Soome 	if (candidate < addr)
59199767f8SToomas Soome 		return;
60199767f8SToomas Soome 
61199767f8SToomas Soome 	if (candidate > *result || *result == (vm_offset_t)-1)
62199767f8SToomas Soome 		*result = candidate;
63199767f8SToomas Soome }
64199767f8SToomas Soome 
65199767f8SToomas Soome static vm_offset_t
find_real_addr(struct preloaded_file * fp)66199767f8SToomas Soome find_real_addr(struct preloaded_file *fp)
67199767f8SToomas Soome {
68199767f8SToomas Soome 	struct bios_smap *smap;
69199767f8SToomas Soome 	struct file_metadata *md;
70199767f8SToomas Soome 	int entries, i;
71199767f8SToomas Soome 	vm_offset_t candidate = -1;
72199767f8SToomas Soome 
73199767f8SToomas Soome 	md = file_findmetadata(fp, MODINFOMD_SMAP);
74199767f8SToomas Soome 	if (md == NULL) {
75199767f8SToomas Soome 		printf("no memory smap\n");
76199767f8SToomas Soome 		return (candidate);
77199767f8SToomas Soome 	}
78199767f8SToomas Soome 	entries = md->md_size / sizeof (struct bios_smap);
79199767f8SToomas Soome 	smap = (struct bios_smap *)md->md_data;
80199767f8SToomas Soome 	for (i = 0; i < entries; i++) {
81199767f8SToomas Soome 		if (smap[i].type != SMAP_TYPE_MEMORY)
82199767f8SToomas Soome 			continue;
83199767f8SToomas Soome 		if (smap[i].base >= 0xa0000)
84199767f8SToomas Soome 			continue;
85199767f8SToomas Soome 		test_addr(smap[i].base, smap[i].length, &candidate);
86199767f8SToomas Soome 	}
87199767f8SToomas Soome 	return (candidate);
88199767f8SToomas Soome }
89199767f8SToomas Soome 
90199767f8SToomas Soome static int
linux_loadkernel(char * filename,uint64_t dest __unused,struct preloaded_file ** result)91*8eef2ab6SToomas Soome linux_loadkernel(char *filename, uint64_t dest __unused,
92*8eef2ab6SToomas Soome     struct preloaded_file **result)
93199767f8SToomas Soome {
94199767f8SToomas Soome 	struct linux_kernel_header lh;
95199767f8SToomas Soome 	struct preloaded_file *fp;
96199767f8SToomas Soome 	struct stat sb;
97199767f8SToomas Soome 	ssize_t n;
98199767f8SToomas Soome 	int fd, error = 0;
99199767f8SToomas Soome 	int setup_sects, linux_big;
100199767f8SToomas Soome 	unsigned long data, text;
101199767f8SToomas Soome 	vm_offset_t mem;
102199767f8SToomas Soome 
103199767f8SToomas Soome 	if (filename == NULL)
104199767f8SToomas Soome 		return (EFTYPE);
105199767f8SToomas Soome 
106199767f8SToomas Soome 	/* is kernel already loaded? */
107199767f8SToomas Soome 	fp = file_findfile(NULL, NULL);
108199767f8SToomas Soome 	if (fp != NULL)
109199767f8SToomas Soome 		return (EFTYPE);
110199767f8SToomas Soome 
111199767f8SToomas Soome 	if ((fd = open(filename, O_RDONLY)) == -1)
112199767f8SToomas Soome 		return (errno);
113199767f8SToomas Soome 
114199767f8SToomas Soome 	if (fstat(fd, &sb) != 0) {
115199767f8SToomas Soome 		printf("stat failed\n");
116199767f8SToomas Soome 		error = errno;
117199767f8SToomas Soome 		close(fd);
118199767f8SToomas Soome 		return (error);
119199767f8SToomas Soome 	}
120199767f8SToomas Soome 
121199767f8SToomas Soome 	n = read(fd, &lh, sizeof (lh));
122199767f8SToomas Soome 	if (n != sizeof (lh)) {
123199767f8SToomas Soome 		printf("error reading kernel header\n");
124199767f8SToomas Soome 		error = EIO;
125199767f8SToomas Soome 		goto end;
126199767f8SToomas Soome 	}
127199767f8SToomas Soome 
128199767f8SToomas Soome 	if (lh.boot_flag != BOOTSEC_SIGNATURE) {
129199767f8SToomas Soome 		printf("invalid magic number\n");
130199767f8SToomas Soome 		error = EFTYPE;
131199767f8SToomas Soome 		goto end;
132199767f8SToomas Soome 	}
133199767f8SToomas Soome 
134199767f8SToomas Soome 	setup_sects = lh.setup_sects;
135199767f8SToomas Soome 	linux_big = 0;
136199767f8SToomas Soome 	max_cmdline_size = 256;
137199767f8SToomas Soome 
138199767f8SToomas Soome 	if (setup_sects > LINUX_MAX_SETUP_SECTS) {
139199767f8SToomas Soome 		printf("too many setup sectors\n");
140199767f8SToomas Soome 		error = EFTYPE;
141199767f8SToomas Soome 		goto end;
142199767f8SToomas Soome 	}
143199767f8SToomas Soome 
144199767f8SToomas Soome 	fp = file_alloc();
145199767f8SToomas Soome 	if (fp == NULL) {
146199767f8SToomas Soome 		error = ENOMEM;
147199767f8SToomas Soome 		goto end;
148199767f8SToomas Soome 	}
149199767f8SToomas Soome 
150199767f8SToomas Soome 	bios_addsmapdata(fp);
151199767f8SToomas Soome 
152199767f8SToomas Soome 	if (lh.header == LINUX_MAGIC_SIGNATURE && lh.version >= 0x0200) {
153199767f8SToomas Soome 		linux_big = lh.loadflags & LINUX_FLAG_BIG_KERNEL;
154199767f8SToomas Soome 		lh.type_of_loader = LINUX_BOOT_LOADER_TYPE;
155199767f8SToomas Soome 
156199767f8SToomas Soome 		if (lh.version >= 0x0206)
157199767f8SToomas Soome 			max_cmdline_size = lh.cmdline_size + 1;
158199767f8SToomas Soome 
159199767f8SToomas Soome 		linux_data_real_addr = find_real_addr(fp);
160199767f8SToomas Soome 		if (linux_data_real_addr == -1) {
161199767f8SToomas Soome 			printf("failed to detect suitable low memory\n");
162199767f8SToomas Soome 			file_discard(fp);
163199767f8SToomas Soome 			error = ENOMEM;
164199767f8SToomas Soome 			goto end;
165199767f8SToomas Soome 		}
166199767f8SToomas Soome 		if (lh.version >= 0x0201) {
167199767f8SToomas Soome 			lh.heap_end_ptr = LINUX_HEAP_END_OFFSET;
168199767f8SToomas Soome 			lh.loadflags |= LINUX_FLAG_CAN_USE_HEAP;
169199767f8SToomas Soome 		}
170199767f8SToomas Soome 		if (lh.version >= 0x0202) {
171199767f8SToomas Soome 			lh.cmd_line_ptr = linux_data_real_addr +
172199767f8SToomas Soome 			    LINUX_CL_OFFSET;
173199767f8SToomas Soome 		} else {
174199767f8SToomas Soome 			lh.cl_magic = LINUX_CL_MAGIC;
175199767f8SToomas Soome 			lh.cl_offset = LINUX_CL_OFFSET;
176199767f8SToomas Soome 			lh.setup_move_size = LINUX_CL_OFFSET + max_cmdline_size;
177199767f8SToomas Soome 		}
178199767f8SToomas Soome 	} else {
179199767f8SToomas Soome 		/* old kernel */
180199767f8SToomas Soome 		lh.cl_magic = LINUX_CL_MAGIC;
181199767f8SToomas Soome 		lh.cl_offset = LINUX_CL_OFFSET;
182199767f8SToomas Soome 		setup_sects = LINUX_DEFAULT_SETUP_SECTS;
183199767f8SToomas Soome 		linux_data_real_addr = LINUX_OLD_REAL_MODE_ADDR;
184199767f8SToomas Soome 	}
185199767f8SToomas Soome 	if (setup_sects == 0)
186199767f8SToomas Soome 		setup_sects = LINUX_DEFAULT_SETUP_SECTS;
187199767f8SToomas Soome 
188199767f8SToomas Soome 	data = setup_sects << 9;
189199767f8SToomas Soome 	text = sb.st_size - data - 512;
190199767f8SToomas Soome 
191199767f8SToomas Soome 	/* temporary location of real mode part */
192199767f8SToomas Soome 	linux_data_tmp_addr = LINUX_BZIMAGE_ADDR + text;
193199767f8SToomas Soome 
194199767f8SToomas Soome 	if (!linux_big && text > linux_data_real_addr - LINUX_ZIMAGE_ADDR) {
195199767f8SToomas Soome 		printf("Linux zImage is too big, use bzImage instead\n");
196199767f8SToomas Soome 		file_discard(fp);
197199767f8SToomas Soome 		error = EFBIG;
198199767f8SToomas Soome 		goto end;
199199767f8SToomas Soome 	}
200b075503fSToomas Soome 	printf("   [Linux-%s, setup=0x%lx, size=0x%lx]\n",
201199767f8SToomas Soome 	    (linux_big ? "bzImage" : "zImage"), data, text);
202199767f8SToomas Soome 
203199767f8SToomas Soome 	/* copy real mode part to place */
204199767f8SToomas Soome 	i386_copyin(&lh, linux_data_tmp_addr, sizeof (lh));
205199767f8SToomas Soome 	n = data + 512 - sizeof (lh);
206199767f8SToomas Soome 	if (archsw.arch_readin(fd, linux_data_tmp_addr+sizeof (lh), n) != n) {
207199767f8SToomas Soome 		printf("failed to read %s\n", filename);
208199767f8SToomas Soome 		file_discard(fp);
209199767f8SToomas Soome 		error = errno;
210199767f8SToomas Soome 		goto end;
211199767f8SToomas Soome 	}
212199767f8SToomas Soome 
213199767f8SToomas Soome 	/* Clear the heap space. */
214199767f8SToomas Soome 	if (lh.header != LINUX_MAGIC_SIGNATURE || lh.version < 0x0200) {
215199767f8SToomas Soome 		memset(PTOV(linux_data_tmp_addr + ((setup_sects + 1) << 9)),
216199767f8SToomas Soome 		    0, (LINUX_MAX_SETUP_SECTS - setup_sects - 1) << 9);
217199767f8SToomas Soome 	}
218199767f8SToomas Soome 
219199767f8SToomas Soome 	mem = LINUX_BZIMAGE_ADDR;
220199767f8SToomas Soome 
221199767f8SToomas Soome 	if (archsw.arch_readin(fd, mem, text) != text) {
222199767f8SToomas Soome 		printf("failed to read %s\n", filename);
223199767f8SToomas Soome 		file_discard(fp);
224199767f8SToomas Soome 		error = EIO;
225199767f8SToomas Soome 		goto end;
226199767f8SToomas Soome 	}
227199767f8SToomas Soome 
228199767f8SToomas Soome 	fp->f_name = strdup(filename);
229199767f8SToomas Soome 	if (linux_big)
230199767f8SToomas Soome 		fp->f_type = strdup("Linux bzImage");
231199767f8SToomas Soome 	else
232199767f8SToomas Soome 		fp->f_type = strdup("Linux zImage");
233199767f8SToomas Soome 
234199767f8SToomas Soome 	/*
235199767f8SToomas Soome 	 * NOTE: f_addr and f_size is used here as hint for module
236199767f8SToomas Soome 	 * allocation, as module location will be f_addr + f_size.
237199767f8SToomas Soome 	 */
238199767f8SToomas Soome 	fp->f_addr = linux_data_tmp_addr;
239199767f8SToomas Soome 	fp->f_size = LINUX_SETUP_MOVE_SIZE;
240199767f8SToomas Soome 	linux_text_len = text;
241199767f8SToomas Soome 
2427b2aa502SToomas Soome 	/*
2437b2aa502SToomas Soome 	 * relocater_data is space allocated in relocater_tramp.S
2447b2aa502SToomas Soome 	 * There is space for 3 instances + terminating zero in case
2457b2aa502SToomas Soome 	 * all 3 entries are used.
2467b2aa502SToomas Soome 	 */
247199767f8SToomas Soome 	if (linux_big == 0) {
2487b2aa502SToomas Soome 		relocater_data[0].src = LINUX_BZIMAGE_ADDR;
2497b2aa502SToomas Soome 		relocater_data[0].dest = LINUX_ZIMAGE_ADDR;
2507b2aa502SToomas Soome 		relocater_data[0].size = text;
2517b2aa502SToomas Soome 		relocater_data[1].src = linux_data_tmp_addr;
2527b2aa502SToomas Soome 		relocater_data[1].dest = linux_data_real_addr;
2537b2aa502SToomas Soome 		relocater_data[1].size = LINUX_SETUP_MOVE_SIZE;
254199767f8SToomas Soome 		/* make sure the next entry is zeroed */
2557b2aa502SToomas Soome 		relocater_data[2].src = 0;
2567b2aa502SToomas Soome 		relocater_data[2].dest = 0;
2577b2aa502SToomas Soome 		relocater_data[2].size = 0;
258199767f8SToomas Soome 	} else {
2597b2aa502SToomas Soome 		relocater_data[0].src = linux_data_tmp_addr;
2607b2aa502SToomas Soome 		relocater_data[0].dest = linux_data_real_addr;
2617b2aa502SToomas Soome 		relocater_data[0].size = LINUX_SETUP_MOVE_SIZE;
262199767f8SToomas Soome 		/* make sure the next entry is zeroed */
2637b2aa502SToomas Soome 		relocater_data[1].src = 0;
2647b2aa502SToomas Soome 		relocater_data[1].dest = 0;
2657b2aa502SToomas Soome 		relocater_data[1].size = 0;
266199767f8SToomas Soome 	}
267199767f8SToomas Soome 
268199767f8SToomas Soome 	*result = fp;
269199767f8SToomas Soome 	setenv("kernelname", fp->f_name, 1);
270199767f8SToomas Soome end:
271199767f8SToomas Soome 	close(fd);
272199767f8SToomas Soome 	return (error);
273199767f8SToomas Soome }
274199767f8SToomas Soome 
275199767f8SToomas Soome static int
linux_exec(struct preloaded_file * fp)276199767f8SToomas Soome linux_exec(struct preloaded_file *fp)
277199767f8SToomas Soome {
278199767f8SToomas Soome 	struct linux_kernel_header *lh = (struct linux_kernel_header *)
279199767f8SToomas Soome 	    PTOV(linux_data_tmp_addr);
280199767f8SToomas Soome 	struct preloaded_file *mfp = fp->f_next;
281199767f8SToomas Soome 	char *arg, *vga;
282199767f8SToomas Soome 	char *src, *dst;
283199767f8SToomas Soome 	int linux_big;
284199767f8SToomas Soome 	uint32_t moveto, max_addr;
285199767f8SToomas Soome 	uint16_t segment;
286199767f8SToomas Soome 	struct i386_devdesc *rootdev;
287199767f8SToomas Soome 
288199767f8SToomas Soome 	if (strcmp(fp->f_type, "Linux bzImage") == 0)
289199767f8SToomas Soome 		linux_big = 1;
290199767f8SToomas Soome 	else if (strcmp(fp->f_type, "Linux zImage") == 0)
291199767f8SToomas Soome 		linux_big = 0;
292199767f8SToomas Soome 	else
293199767f8SToomas Soome 		return (EFTYPE);
294199767f8SToomas Soome 
295199767f8SToomas Soome 	i386_getdev((void **)(&rootdev), fp->f_name, NULL);
296199767f8SToomas Soome 	if (rootdev != NULL)
297863275a4SToomas Soome 		relocator_edx = bd_unit2bios(rootdev);
298199767f8SToomas Soome 
299199767f8SToomas Soome 	/*
300199767f8SToomas Soome 	 * command line
301199767f8SToomas Soome 	 * if not set in fp, read from boot-args env
302199767f8SToomas Soome 	 */
303199767f8SToomas Soome 	if (fp->f_args == NULL)
304199767f8SToomas Soome 		fp->f_args = getenv("boot-args");
305199767f8SToomas Soome 	arg = fp->f_args;		/* it can still be NULL */
306199767f8SToomas Soome 
307199767f8SToomas Soome 	/* video mode selection */
308199767f8SToomas Soome 	if (arg && (vga = strstr(arg, "vga=")) != NULL) {
309199767f8SToomas Soome 		char *value = vga + 4;
310199767f8SToomas Soome 		uint16_t vid_mode;
311199767f8SToomas Soome 
312199767f8SToomas Soome 		if (strncmp(value, "normal", 6) < 1)
313199767f8SToomas Soome 			vid_mode = LINUX_VID_MODE_NORMAL;
314199767f8SToomas Soome 		else if (strncmp(value, "ext", 3) < 1)
315199767f8SToomas Soome 			vid_mode = LINUX_VID_MODE_EXTENDED;
316199767f8SToomas Soome 		else if (strncmp(value, "ask", 3) < 1)
317199767f8SToomas Soome 			vid_mode = LINUX_VID_MODE_ASK;
318199767f8SToomas Soome 		else {
319199767f8SToomas Soome 			long mode;
320199767f8SToomas Soome 			errno = 0;
321199767f8SToomas Soome 
322199767f8SToomas Soome 			/*
323199767f8SToomas Soome 			 * libstand sets ERANGE as only error case;
324199767f8SToomas Soome 			 * however, the actual value is 16bit, so
325199767f8SToomas Soome 			 * additional check is needed.
326199767f8SToomas Soome 			 */
327199767f8SToomas Soome 			mode = strtol(value, NULL, 0);
328199767f8SToomas Soome 			if (errno != 0 || mode >> 16 != 0 || mode == 0) {
329199767f8SToomas Soome 				printf("bad value for video mode\n");
330199767f8SToomas Soome 				return (EINTR);
331199767f8SToomas Soome 			}
332199767f8SToomas Soome 			vid_mode = (uint16_t) mode;
333199767f8SToomas Soome 		}
334199767f8SToomas Soome 		lh->vid_mode = vid_mode;
335199767f8SToomas Soome 	}
336199767f8SToomas Soome 
337199767f8SToomas Soome 	src = arg;
338199767f8SToomas Soome 	dst = (char *)PTOV(linux_data_tmp_addr + LINUX_CL_OFFSET);
339199767f8SToomas Soome 	if (src != NULL) {
340199767f8SToomas Soome 		while (*src != 0 && dst < (char *)
341199767f8SToomas Soome 		    PTOV(linux_data_tmp_addr + LINUX_CL_END_OFFSET))
342199767f8SToomas Soome 			*(dst++) = *(src++);
343199767f8SToomas Soome 	}
344199767f8SToomas Soome 	*dst = 0;
345199767f8SToomas Soome 
346199767f8SToomas Soome 	/* set up module relocation */
347199767f8SToomas Soome 	if (mfp != NULL) {
348199767f8SToomas Soome 		moveto = (bios_extmem / 1024 + 0x400) << 10;
349199767f8SToomas Soome 		moveto = (moveto - mfp->f_size) & 0xfffff000;
350199767f8SToomas Soome 		max_addr = (lh->header == LINUX_MAGIC_SIGNATURE &&
351199767f8SToomas Soome 		    lh->version >= 0x0203 ?
352199767f8SToomas Soome 		    lh->initrd_addr_max : LINUX_INITRD_MAX_ADDRESS);
353199767f8SToomas Soome 		if (moveto + mfp->f_size >= max_addr)
354199767f8SToomas Soome 			moveto = (max_addr - mfp->f_size) & 0xfffff000;
355199767f8SToomas Soome 
356199767f8SToomas Soome 		/*
357199767f8SToomas Soome 		 * XXX: Linux 2.3.xx has a bug in the memory range check,
358199767f8SToomas Soome 		 * so avoid the last page.
359199767f8SToomas Soome 		 * XXX: Linux 2.2.xx has a bug in the memory range check,
360199767f8SToomas Soome 		 * which is worse than that of Linux 2.3.xx, so avoid the
361199767f8SToomas Soome 		 * last 64kb. *sigh*
362199767f8SToomas Soome 		 */
363199767f8SToomas Soome 		moveto -= 0x10000;
364199767f8SToomas Soome 
365199767f8SToomas Soome 		/* need to relocate initrd first */
366199767f8SToomas Soome 		if (linux_big == 0) {
3677b2aa502SToomas Soome 			relocater_data[2].src = relocater_data[1].src;
3687b2aa502SToomas Soome 			relocater_data[2].dest = relocater_data[1].dest;
3697b2aa502SToomas Soome 			relocater_data[2].size = relocater_data[1].size;
3707b2aa502SToomas Soome 			relocater_data[1].src = relocater_data[0].src;
3717b2aa502SToomas Soome 			relocater_data[1].dest = relocater_data[0].dest;
3727b2aa502SToomas Soome 			relocater_data[1].size = relocater_data[0].size;
3737b2aa502SToomas Soome 			relocater_data[0].src = mfp->f_addr;
3747b2aa502SToomas Soome 			relocater_data[0].dest = moveto;
3757b2aa502SToomas Soome 			relocater_data[0].size = mfp->f_size;
376199767f8SToomas Soome 		} else {
3777b2aa502SToomas Soome 			relocater_data[1].src = relocater_data[0].src;
3787b2aa502SToomas Soome 			relocater_data[1].dest = relocater_data[0].dest;
3797b2aa502SToomas Soome 			relocater_data[1].size = relocater_data[0].size;
3807b2aa502SToomas Soome 			relocater_data[0].src = mfp->f_addr;
3817b2aa502SToomas Soome 			relocater_data[0].dest = moveto;
3827b2aa502SToomas Soome 			relocater_data[0].size = mfp->f_size;
383199767f8SToomas Soome 		}
384199767f8SToomas Soome 		lh->ramdisk_image = moveto;
385199767f8SToomas Soome 		lh->ramdisk_size = mfp->f_size;
386199767f8SToomas Soome 	}
387199767f8SToomas Soome 
388199767f8SToomas Soome 	segment = linux_data_real_addr >> 4;
389199767f8SToomas Soome 	relocator_ds = segment;
390199767f8SToomas Soome 	relocator_es = segment;
391199767f8SToomas Soome 	relocator_fs = segment;
392199767f8SToomas Soome 	relocator_gs = segment;
393199767f8SToomas Soome 	relocator_ss = segment;
394199767f8SToomas Soome 	relocator_sp = LINUX_ESP;
395199767f8SToomas Soome 	relocator_ip = 0;
396199767f8SToomas Soome 	relocator_cs = segment + 0x20;
397199767f8SToomas Soome 	relocator_a20_enabled = 1;
398199767f8SToomas Soome 	i386_copyin(relocater, 0x600, relocater_size);
399199767f8SToomas Soome 
4009890ff83SToomas Soome 	/* Set VGA text mode */
4019890ff83SToomas Soome 	bios_set_text_mode(3);
402199767f8SToomas Soome 	dev_cleanup();
403199767f8SToomas Soome 
404199767f8SToomas Soome 	__exec((void *)0x600);
405199767f8SToomas Soome 
406199767f8SToomas Soome 	panic("exec returned");
407199767f8SToomas Soome 
408199767f8SToomas Soome 	return (EINTR);		/* not reached */
409199767f8SToomas Soome }
410199767f8SToomas Soome 
411199767f8SToomas Soome static int
linux_loadinitrd(char * filename,uint64_t dest __unused,struct preloaded_file ** result)412*8eef2ab6SToomas Soome linux_loadinitrd(char *filename, uint64_t dest __unused,
413*8eef2ab6SToomas Soome     struct preloaded_file **result)
414199767f8SToomas Soome {
415199767f8SToomas Soome 	struct preloaded_file *mfp;
416199767f8SToomas Soome 
417199767f8SToomas Soome 	if (filename == NULL)
418199767f8SToomas Soome 		return (EFTYPE);
419199767f8SToomas Soome 
420199767f8SToomas Soome 	/* check if the kernel is loaded */
421199767f8SToomas Soome 	mfp = file_findfile(NULL, "Linux bzImage");
422199767f8SToomas Soome 	if (mfp == NULL)
423199767f8SToomas Soome 		mfp = file_findfile(NULL, "Linux zImage");
424199767f8SToomas Soome 	if (mfp == NULL)
425199767f8SToomas Soome 		return (EFTYPE);
426199767f8SToomas Soome 
427199767f8SToomas Soome 	mfp = file_loadraw(filename, "module", 0, NULL, 0);
428199767f8SToomas Soome 	if (mfp == NULL)
429199767f8SToomas Soome 		return (EFTYPE);
430199767f8SToomas Soome 	*result = mfp;
431199767f8SToomas Soome 	return (0);
432199767f8SToomas Soome }
433199767f8SToomas Soome 
linux_execinitrd(struct preloaded_file * pf __unused)434*8eef2ab6SToomas Soome static int linux_execinitrd(struct preloaded_file *pf __unused)
435199767f8SToomas Soome {
436199767f8SToomas Soome 	return (EFTYPE);
437199767f8SToomas Soome }