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