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