xref: /freebsd/stand/i386/loader/chain.c (revision 3e15b01d6914c927e37d1699645783acf286655c)
1ca987d46SWarner Losh /*-
2ca987d46SWarner Losh  * Copyright 2015 Toomas Soome <tsoome@me.com>
3ca987d46SWarner Losh  * All rights reserved.
4ca987d46SWarner Losh  *
5ca987d46SWarner Losh  * Redistribution and use in source and binary forms, with or without
6ca987d46SWarner Losh  * modification, are permitted provided that the following conditions
7ca987d46SWarner Losh  * are met:
8ca987d46SWarner Losh  * 1. Redistributions of source code must retain the above copyright
9ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer.
10ca987d46SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
11ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
12ca987d46SWarner Losh  *    documentation and/or other materials provided with the distribution.
13ca987d46SWarner Losh  *
14ca987d46SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ca987d46SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ca987d46SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ca987d46SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ca987d46SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ca987d46SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ca987d46SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ca987d46SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ca987d46SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ca987d46SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ca987d46SWarner Losh  * SUCH DAMAGE.
25ca987d46SWarner Losh  */
26ca987d46SWarner Losh 
27ca987d46SWarner Losh /*
28ca987d46SWarner Losh  * Chain loader to load BIOS boot block either from MBR or PBR.
29ca987d46SWarner Losh  *
30ca987d46SWarner Losh  * Note the boot block location 0000:7c000 conflicts with loader, so we need to
31ca987d46SWarner Losh  * read in to temporary space and relocate on exec, when btx is stopped.
32ca987d46SWarner Losh  */
33ca987d46SWarner Losh 
34ca987d46SWarner Losh #include <stand.h>
35ca987d46SWarner Losh #include <sys/param.h>
36ca987d46SWarner Losh #include <sys/linker.h>
37ca987d46SWarner Losh #include <sys/diskmbr.h>
38ca987d46SWarner Losh 
39ca987d46SWarner Losh #include "bootstrap.h"
40ca987d46SWarner Losh #include "libi386/libi386.h"
41ca987d46SWarner Losh #include "btxv86.h"
42ca987d46SWarner Losh 
43afc571b1SSimon J. Gerraty #ifdef LOADER_VERIEXEC_VECTX
44afc571b1SSimon J. Gerraty #define VECTX_HANDLE(x) vctx
45afc571b1SSimon J. Gerraty #else
46afc571b1SSimon J. Gerraty #define VECTX_HANDLE(x) x
47afc571b1SSimon J. Gerraty #endif
48afc571b1SSimon J. Gerraty 
49ca987d46SWarner Losh /*
50ca987d46SWarner Losh  * The MBR/VBR is located in first sector of disk/partition.
51ca987d46SWarner Losh  * Read 512B to temporary location and set up relocation. Then
52ca987d46SWarner Losh  * exec relocator.
53ca987d46SWarner Losh  */
54ca987d46SWarner Losh #define	SECTOR_SIZE	(512)
55ca987d46SWarner Losh 
56ca987d46SWarner Losh COMMAND_SET(chain, "chain", "chain load boot block from device", command_chain);
57ca987d46SWarner Losh 
58ca987d46SWarner Losh static int
command_chain(int argc,char * argv[])59ca987d46SWarner Losh command_chain(int argc, char *argv[])
60ca987d46SWarner Losh {
61ca987d46SWarner Losh 	int fd, len, size = SECTOR_SIZE;
62ca987d46SWarner Losh 	struct stat st;
63ca987d46SWarner Losh 	vm_offset_t mem = 0x100000;
64ca987d46SWarner Losh 	struct i386_devdesc *rootdev;
65afc571b1SSimon J. Gerraty #ifdef LOADER_VERIEXEC_VECTX
66afc571b1SSimon J. Gerraty 	struct vectx *vctx;
67afc571b1SSimon J. Gerraty 	int verror;
68afc571b1SSimon J. Gerraty #endif
69ca987d46SWarner Losh 
70ca987d46SWarner Losh 	if (argc == 1) {
71ca987d46SWarner Losh 		command_errmsg = "no device or file name specified";
72ca987d46SWarner Losh 		return (CMD_ERROR);
73ca987d46SWarner Losh 	}
74ca987d46SWarner Losh 	if (argc != 2) {
75ca987d46SWarner Losh 		command_errmsg = "invalid trailing arguments";
76ca987d46SWarner Losh 		return (CMD_ERROR);
77ca987d46SWarner Losh 	}
78ca987d46SWarner Losh 
79ca987d46SWarner Losh 	fd = open(argv[1], O_RDONLY);
80ca987d46SWarner Losh 	if (fd == -1) {
81ca987d46SWarner Losh 		command_errmsg = "open failed";
82ca987d46SWarner Losh 		return (CMD_ERROR);
83ca987d46SWarner Losh 	}
84ca987d46SWarner Losh 
85afc571b1SSimon J. Gerraty #ifdef LOADER_VERIEXEC_VECTX
86afc571b1SSimon J. Gerraty 	vctx = vectx_open(fd, argv[1], 0L, NULL, &verror, __func__);
87afc571b1SSimon J. Gerraty 	if (verror) {
88afc571b1SSimon J. Gerraty 		sprintf(command_errbuf, "can't verify: %s", argv[1]);
89afc571b1SSimon J. Gerraty 		close(fd);
90afc571b1SSimon J. Gerraty 		free(vctx);
91afc571b1SSimon J. Gerraty 		return (CMD_ERROR);
92afc571b1SSimon J. Gerraty 	}
93afc571b1SSimon J. Gerraty #else
94435672e3SMarcin Wojtas #ifdef LOADER_VERIEXEC
95*91cd69eeSSimon J. Gerraty 	if (verify_file(fd, argv[1], 0, VE_MUST, __func__) < 0) {
96435672e3SMarcin Wojtas 		sprintf(command_errbuf, "can't verify: %s", argv[1]);
97435672e3SMarcin Wojtas 		close(fd);
98435672e3SMarcin Wojtas 		return (CMD_ERROR);
99435672e3SMarcin Wojtas 	}
100435672e3SMarcin Wojtas #endif
101afc571b1SSimon J. Gerraty #endif
102ca987d46SWarner Losh 	len = strlen(argv[1]);
103ca987d46SWarner Losh 	if (argv[1][len-1] != ':') {
104ca987d46SWarner Losh 		if (fstat(fd, &st) == -1) {
105ca987d46SWarner Losh 			command_errmsg = "stat failed";
106ca987d46SWarner Losh 			close(fd);
107ca987d46SWarner Losh 			return (CMD_ERROR);
108ca987d46SWarner Losh 		}
109ca987d46SWarner Losh 		size = st.st_size;
110ca987d46SWarner Losh 	} else if (strncmp(argv[1], "disk", 4) != 0) {
111ca987d46SWarner Losh 		command_errmsg = "can only use disk device";
112ca987d46SWarner Losh 		close(fd);
113ca987d46SWarner Losh 		return (CMD_ERROR);
114ca987d46SWarner Losh 	}
115ca987d46SWarner Losh 
116ca987d46SWarner Losh 	i386_getdev((void **)(&rootdev), argv[1], NULL);
117ca987d46SWarner Losh 	if (rootdev == NULL) {
118ca987d46SWarner Losh 		command_errmsg = "can't determine root device";
11945a3e13cSToomas Soome 		close(fd);
120ca987d46SWarner Losh 		return (CMD_ERROR);
121ca987d46SWarner Losh 	}
122ca987d46SWarner Losh 
123afc571b1SSimon J. Gerraty 	if (archsw.arch_readin(VECTX_HANDLE(fd), mem, size) != size) {
124ca987d46SWarner Losh 		command_errmsg = "failed to read disk";
125ca987d46SWarner Losh 		close(fd);
126ca987d46SWarner Losh 		return (CMD_ERROR);
127ca987d46SWarner Losh 	}
128ca987d46SWarner Losh 	close(fd);
129afc571b1SSimon J. Gerraty #ifdef LOADER_VERIEXEC_VECTX
130afc571b1SSimon J. Gerraty 	verror = vectx_close(vctx, VE_MUST, __func__);
131afc571b1SSimon J. Gerraty 	if (verror) {
132afc571b1SSimon J. Gerraty 		free(vctx);
133afc571b1SSimon J. Gerraty 		return (CMD_ERROR);
134afc571b1SSimon J. Gerraty 	}
135afc571b1SSimon J. Gerraty #endif
13645a3e13cSToomas Soome 	if (argv[1][len-1] == ':' &&
13745a3e13cSToomas Soome 	    *((uint16_t *)PTOV(mem + DOSMAGICOFFSET)) != DOSMAGIC) {
138ca987d46SWarner Losh 		command_errmsg = "wrong magic";
139ca987d46SWarner Losh 		return (CMD_ERROR);
140ca987d46SWarner Losh 	}
141ca987d46SWarner Losh 
142ca987d46SWarner Losh 	relocater_data[0].src = mem;
143ca987d46SWarner Losh 	relocater_data[0].dest = 0x7C00;
14445a3e13cSToomas Soome 	relocater_data[0].size = size;
145ca987d46SWarner Losh 
146cdff1036SToomas Soome 	relocator_edx = bd_unit2bios(rootdev);
147ca987d46SWarner Losh 	relocator_esi = relocater_size;
148ca987d46SWarner Losh 	relocator_ds = 0;
149ca987d46SWarner Losh 	relocator_es = 0;
150ca987d46SWarner Losh 	relocator_fs = 0;
151ca987d46SWarner Losh 	relocator_gs = 0;
152ca987d46SWarner Losh 	relocator_ss = 0;
153ca987d46SWarner Losh 	relocator_cs = 0;
154ca987d46SWarner Losh 	relocator_sp = 0x7C00;
155ca987d46SWarner Losh 	relocator_ip = 0x7C00;
156ca987d46SWarner Losh 	relocator_a20_enabled = 0;
157ca987d46SWarner Losh 
158ca987d46SWarner Losh 	i386_copyin(relocater, 0x600, relocater_size);
159ca987d46SWarner Losh 
160ca987d46SWarner Losh 	dev_cleanup();
161ca987d46SWarner Losh 
162ca987d46SWarner Losh 	__exec((void *)0x600);
163ca987d46SWarner Losh 
164ca987d46SWarner Losh 	panic("exec returned");
165ca987d46SWarner Losh 	return (CMD_ERROR);		/* not reached */
166ca987d46SWarner Losh }
167