1 |
|
|
/* $OpenBSD: i386_softraid.c,v 1.10 2016/04/28 16:48:18 krw Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* Copyright (c) 2012 Joel Sing <jsing@openbsd.org> |
4 |
|
|
* |
5 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
6 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
7 |
|
|
* copyright notice and this permission notice appear in all copies. |
8 |
|
|
* |
9 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 |
|
|
*/ |
17 |
|
|
|
18 |
|
|
#include <sys/param.h> /* DEV_BSIZE */ |
19 |
|
|
#include <sys/disklabel.h> |
20 |
|
|
#include <sys/dkio.h> |
21 |
|
|
#include <sys/ioctl.h> |
22 |
|
|
#include <sys/stat.h> |
23 |
|
|
|
24 |
|
|
#include <dev/biovar.h> |
25 |
|
|
#include <dev/softraidvar.h> |
26 |
|
|
#include <ufs/ufs/dinode.h> |
27 |
|
|
|
28 |
|
|
#include <err.h> |
29 |
|
|
#include <fcntl.h> |
30 |
|
|
#include <stdio.h> |
31 |
|
|
#include <stdlib.h> |
32 |
|
|
#include <string.h> |
33 |
|
|
#include <unistd.h> |
34 |
|
|
#include <util.h> |
35 |
|
|
|
36 |
|
|
#include "installboot.h" |
37 |
|
|
#include "i386_installboot.h" |
38 |
|
|
|
39 |
|
|
void sr_install_bootblk(int, int, int); |
40 |
|
|
void sr_install_bootldr(int, char *); |
41 |
|
|
|
42 |
|
|
void |
43 |
|
|
sr_install_bootblk(int devfd, int vol, int disk) |
44 |
|
|
{ |
45 |
|
|
struct bioc_disk bd; |
46 |
|
|
struct disklabel dl; |
47 |
|
|
struct partition *pp; |
48 |
|
|
uint32_t poffset; |
49 |
|
|
char *dev; |
50 |
|
|
char part, efipart; |
51 |
|
|
int diskfd; |
52 |
|
|
|
53 |
|
|
/* Get device name for this disk/chunk. */ |
54 |
|
|
memset(&bd, 0, sizeof(bd)); |
55 |
|
|
bd.bd_volid = vol; |
56 |
|
|
bd.bd_diskid = disk; |
57 |
|
|
if (ioctl(devfd, BIOCDISK, &bd) == -1) |
58 |
|
|
err(1, "BIOCDISK"); |
59 |
|
|
|
60 |
|
|
/* Check disk status. */ |
61 |
|
|
if (bd.bd_status != BIOC_SDONLINE && bd.bd_status != BIOC_SDREBUILD) { |
62 |
|
|
fprintf(stderr, "softraid chunk %u not online - skipping...\n", |
63 |
|
|
disk); |
64 |
|
|
return; |
65 |
|
|
} |
66 |
|
|
|
67 |
|
|
if (strlen(bd.bd_vendor) < 1) |
68 |
|
|
errx(1, "invalid disk name"); |
69 |
|
|
part = bd.bd_vendor[strlen(bd.bd_vendor) - 1]; |
70 |
|
|
if (part < 'a' || part >= 'a' + MAXPARTITIONS) |
71 |
|
|
errx(1, "invalid partition %c\n", part); |
72 |
|
|
bd.bd_vendor[strlen(bd.bd_vendor) - 1] = '\0'; |
73 |
|
|
|
74 |
|
|
/* Open this device and check its disklabel. */ |
75 |
|
|
if ((diskfd = opendev(bd.bd_vendor, (nowrite? O_RDONLY:O_RDWR), |
76 |
|
|
OPENDEV_PART, &dev)) < 0) |
77 |
|
|
err(1, "open: %s", dev); |
78 |
|
|
|
79 |
|
|
/* Get and check disklabel. */ |
80 |
|
|
if (ioctl(diskfd, DIOCGDINFO, &dl) != 0) |
81 |
|
|
err(1, "disklabel: %s", dev); |
82 |
|
|
if (dl.d_magic != DISKMAGIC) |
83 |
|
|
err(1, "bad disklabel magic=0x%08x", dl.d_magic); |
84 |
|
|
|
85 |
|
|
/* Warn on unknown disklabel types. */ |
86 |
|
|
if (dl.d_type == 0) |
87 |
|
|
warnx("disklabel type unknown"); |
88 |
|
|
|
89 |
|
|
efipart = findgptefisys(diskfd, &dl); |
90 |
|
|
if (efipart != -1) { |
91 |
|
|
write_efisystem(&dl, (char)efipart); |
92 |
|
|
return; |
93 |
|
|
} |
94 |
|
|
|
95 |
|
|
/* Determine poffset and set symbol value. */ |
96 |
|
|
pp = &dl.d_partitions[part - 'a']; |
97 |
|
|
if (pp->p_offseth != 0) |
98 |
|
|
errx(1, "partition offset too high"); |
99 |
|
|
poffset = pp->p_offset; /* Offset of RAID partition. */ |
100 |
|
|
poffset += SR_BOOT_LOADER_OFFSET; /* SR boot loader area. */ |
101 |
|
|
sym_set_value(pbr_symbols, "_p_offset", poffset); |
102 |
|
|
|
103 |
|
|
if (verbose) |
104 |
|
|
fprintf(stderr, "%s%c: installing boot blocks on %s, " |
105 |
|
|
"part offset %u\n", bd.bd_vendor, part, dev, poffset); |
106 |
|
|
|
107 |
|
|
/* Write boot blocks to device. */ |
108 |
|
|
write_bootblocks(diskfd, dev, &dl); |
109 |
|
|
|
110 |
|
|
close(diskfd); |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
void |
114 |
|
|
sr_install_bootldr(int devfd, char *dev) |
115 |
|
|
{ |
116 |
|
|
struct bioc_installboot bb; |
117 |
|
|
struct stat sb; |
118 |
|
|
struct ufs1_dinode *ino_p; |
119 |
|
|
uint32_t bootsize, inodeblk, inodedbl; |
120 |
|
|
uint16_t bsize = SR_FS_BLOCKSIZE; |
121 |
|
|
uint16_t nblocks; |
122 |
|
|
uint8_t bshift = 5; /* fragsize == blocksize */ |
123 |
|
|
int fd, i; |
124 |
|
|
u_char *p; |
125 |
|
|
|
126 |
|
|
/* |
127 |
|
|
* Install boot loader into softraid boot loader storage area. |
128 |
|
|
* |
129 |
|
|
* In order to allow us to reuse the existing biosboot we construct |
130 |
|
|
* a fake FFS filesystem with a single inode, which points to the |
131 |
|
|
* boot loader. |
132 |
|
|
*/ |
133 |
|
|
|
134 |
|
|
nblocks = howmany(SR_BOOT_LOADER_SIZE, SR_FS_BLOCKSIZE / DEV_BSIZE); |
135 |
|
|
inodeblk = nblocks - 1; |
136 |
|
|
bootsize = nblocks * SR_FS_BLOCKSIZE; |
137 |
|
|
|
138 |
|
|
p = calloc(1, bootsize); |
139 |
|
|
if (p == NULL) |
140 |
|
|
err(1, NULL); |
141 |
|
|
|
142 |
|
|
fd = open(stage2, O_RDONLY, 0); |
143 |
|
|
if (fd == -1) |
144 |
|
|
err(1, NULL); |
145 |
|
|
|
146 |
|
|
if (fstat(fd, &sb) == -1) |
147 |
|
|
err(1, NULL); |
148 |
|
|
|
149 |
|
|
nblocks = howmany(sb.st_blocks, SR_FS_BLOCKSIZE / DEV_BSIZE); |
150 |
|
|
if (sb.st_blocks * S_BLKSIZE > bootsize - |
151 |
|
|
(int)(sizeof(struct ufs1_dinode))) |
152 |
|
|
errx(1, "boot code will not fit"); |
153 |
|
|
|
154 |
|
|
/* We only need to fill the direct block array. */ |
155 |
|
|
ino_p = (struct ufs1_dinode *)&p[bootsize - sizeof(struct ufs1_dinode)]; |
156 |
|
|
|
157 |
|
|
ino_p->di_mode = sb.st_mode; |
158 |
|
|
ino_p->di_nlink = 1; |
159 |
|
|
ino_p->di_inumber = 0xfeebfaab; |
160 |
|
|
ino_p->di_size = read(fd, p, sb.st_blocks * S_BLKSIZE); |
161 |
|
|
ino_p->di_blocks = nblocks; |
162 |
|
|
for (i = 0; i < nblocks; i++) |
163 |
|
|
ino_p->di_db[i] = i; |
164 |
|
|
|
165 |
|
|
inodedbl = ((u_char*)&ino_p->di_db[0] - |
166 |
|
|
&p[bootsize - SR_FS_BLOCKSIZE]) + INODEOFF; |
167 |
|
|
|
168 |
|
|
memset(&bb, 0, sizeof(bb)); |
169 |
|
|
bb.bb_bootldr = p; |
170 |
|
|
bb.bb_bootldr_size = bootsize; |
171 |
|
|
bb.bb_bootblk = "XXX"; |
172 |
|
|
bb.bb_bootblk_size = sizeof("XXX"); |
173 |
|
|
strncpy(bb.bb_dev, dev, sizeof(bb.bb_dev)); |
174 |
|
|
if (!nowrite) { |
175 |
|
|
if (verbose) |
176 |
|
|
fprintf(stderr, "%s: installing boot loader on " |
177 |
|
|
"softraid volume\n", dev); |
178 |
|
|
if (ioctl(devfd, BIOCINSTALLBOOT, &bb) == -1) |
179 |
|
|
errx(1, "softraid installboot failed"); |
180 |
|
|
} |
181 |
|
|
|
182 |
|
|
/* |
183 |
|
|
* Set the values that will need to go into biosboot |
184 |
|
|
* (the partition boot record, a.k.a. the PBR). |
185 |
|
|
*/ |
186 |
|
|
sym_set_value(pbr_symbols, "_fs_bsize_p", (bsize / 16)); |
187 |
|
|
sym_set_value(pbr_symbols, "_fs_bsize_s", (bsize / 512)); |
188 |
|
|
sym_set_value(pbr_symbols, "_fsbtodb", bshift); |
189 |
|
|
sym_set_value(pbr_symbols, "_inodeblk", inodeblk); |
190 |
|
|
sym_set_value(pbr_symbols, "_inodedbl", inodedbl); |
191 |
|
|
sym_set_value(pbr_symbols, "_nblocks", nblocks); |
192 |
|
|
|
193 |
|
|
if (verbose) |
194 |
|
|
fprintf(stderr, "%s is %d blocks x %d bytes\n", |
195 |
|
|
stage2, nblocks, bsize); |
196 |
|
|
|
197 |
|
|
free(p); |
198 |
|
|
close(fd); |
199 |
|
|
} |