• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2012 Intel Corporation, author: H. Peter Anvin
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
8  *   Boston MA 02110-1301, USA; either version 2 of the License, or
9  *   (at your option) any later version; incorporated herein by reference.
10  *
11  * ----------------------------------------------------------------------- */
12 
13 /*
14  * chainbooting - replace the current bootloader completely.  This
15  * is BIOS-specific.
16  */
17 
18 #include <fcntl.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <dprintf.h>
23 
24 #include <com32.h>
25 #include <sys/exec.h>
26 #include <sys/io.h>
27 #include "core.h"
28 #include "menu.h"
29 #include "fs.h"
30 #include "config.h"
31 #include "localboot.h"
32 #include "bios.h"
33 
34 #include <syslinux/boot.h>
35 #include <syslinux/bootrm.h>
36 #include <syslinux/movebits.h>
37 #include <syslinux/config.h>
38 
chainboot_file(const char * file,uint32_t type)39 void chainboot_file(const char *file, uint32_t type)
40 {
41     uint8_t keeppxe = 0;
42     const union syslinux_derivative_info *sdi;
43     struct syslinux_rm_regs regs;
44     struct syslinux_movelist *fraglist = NULL;
45     struct syslinux_memmap *mmap = NULL;
46     struct com32_filedata fd;
47     com32sys_t reg;
48     char *stack;
49     void *buf;
50     int rv, max, size;
51 
52     max = 0xA0000;		/* Maximum load */
53     buf = malloc(max);
54     if (!buf)
55 	goto bail;
56 
57     rv = open_file(file, O_RDONLY, &fd);
58     if (rv == -1)
59 	goto bail;
60 
61     reg.eax.l = max;
62     reg.ebx.l = 0;
63     reg.edx.w[0] = 0;
64     reg.edi.l = (uint32_t)buf;
65     reg.ebp.l = -1;	/* XXX: limit? */
66     reg.esi.w[0] = rv;
67 
68     pm_load_high(&reg);
69 
70     size = reg.edi.l - (unsigned long)buf;
71     if (size > 0xA0000 - 0x7C00) {
72 	printf("Too large for a boostrap (need LINUX instead of KERNEL?)\n");
73 	goto bail;
74     }
75 
76     mmap = syslinux_memory_map();
77     if (!mmap)
78 	goto bail;
79 
80     sdi = syslinux_derivative_info();
81 
82     memset(&regs, 0, sizeof(regs));
83     regs.ip = 0x7c00;
84 
85     if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX ||
86 	sdi->c.filesystem == SYSLINUX_FS_EXTLINUX) {
87 	if (syslinux_add_movelist(&fraglist, 0x800 - 18,
88 				  (addr_t)sdi->r.esbx, 16))
89 	    goto bail;
90 
91 	/* DS:SI points to partition info */
92 	regs.esi.l = 0x800 - 18;
93     }
94 
95     /*
96      * For a BSS boot sector we have to transfer the
97      * superblock.
98      */
99     if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX &&
100 	type == IMAGE_TYPE_BSS && this_fs->fs_ops->copy_super(buf))
101 	goto bail;
102 
103     if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) {
104 	keeppxe = 0x03;		/* Chainloading + keep PXE */
105 	stack = (char *)sdi->r.fssi;
106 
107 	/*
108 	 * Set up the registers with their initial values
109 	 */
110 
111 	regs.eax.l = *(uint32_t *)&stack[36];
112 	regs.ecx.l = *(uint32_t *)&stack[32];
113 	regs.edx.l = *(uint32_t *)&stack[28];
114 	regs.ebx.l = *(uint32_t *)&stack[24];
115 	regs.esp.l = sdi->rr.r.esi.w[0] + 44;
116 	regs.ebp.l = *(uint32_t *)&stack[16];
117 	regs.esi.l = *(uint32_t *)&stack[12];
118 	regs.edi.l = *(uint32_t *)&stack[8];
119 	regs.es = *(uint16_t *)&stack[4];
120 	regs.ss = sdi->rr.r.fs;
121 	regs.ds = *(uint16_t *)&stack[6];
122 	regs.fs = *(uint16_t *)&stack[2];
123 	regs.gs = *(uint16_t *)&stack[0];
124     } else {
125 	const uint16_t *esdi = (const uint16_t *)sdi->disk.esdi_ptr;
126 
127 	regs.esp.l = (uint16_t)(unsigned long)StackBuf + 44;
128 
129 	/*
130 	 * DON'T DO THIS FOR PXELINUX...
131 	 * For PXE, ES:BX -> PXENV+, and this would
132 	 * corrupt that use.
133 	 *
134 	 * Restore ES:DI -> $PnP (if we were ourselves
135 	 * called that way...)
136 	 */
137 	regs.edi.w[0] = esdi[0]; /* New DI */
138 	regs.es       = esdi[2]; /* New ES */
139 
140 	regs.edx.l    = sdi->rr.r.edx.b[0]; /* Drive number -> DL */
141     }
142 
143     if (syslinux_add_movelist(&fraglist, 0x7c00, (addr_t)buf, size))
144 	goto bail;
145 
146     syslinux_shuffle_boot_rm(fraglist, mmap, keeppxe, &regs);
147 
148 bail:
149     if (fraglist)
150 	syslinux_free_movelist(fraglist);
151     if (mmap)
152 	syslinux_free_memmap(mmap);
153     if (buf)
154 	free(buf);
155     return;
156 }
157