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