| // SPDX-License-Identifier: GPL-2.0 |
| /* This utility makes a bootblock suitable for the SRM console/miniloader */ |
| |
| /* Usage: |
| * mkbb <device> <lxboot> |
| * |
| * Where <device> is the name of the device to install the bootblock on, |
| * and <lxboot> is the name of a bootblock to merge in. This bootblock |
| * contains the offset and size of the bootloader. It must be exactly |
| * 512 bytes long. |
| */ |
| |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| |
| /* Minimal definition of disklabel, so we don't have to include |
| * asm/disklabel.h (confuses make) |
| */ |
| #ifndef MAXPARTITIONS |
| #define MAXPARTITIONS 8 /* max. # of partitions */ |
| #endif |
| |
| #ifndef u8 |
| #define u8 unsigned char |
| #endif |
| |
| #ifndef u16 |
| #define u16 unsigned short |
| #endif |
| |
| #ifndef u32 |
| #define u32 unsigned int |
| #endif |
| |
| struct disklabel { |
| u32 d_magic; /* must be DISKLABELMAGIC */ |
| u16 d_type, d_subtype; |
| u8 d_typename[16]; |
| u8 d_packname[16]; |
| u32 d_secsize; |
| u32 d_nsectors; |
| u32 d_ntracks; |
| u32 d_ncylinders; |
| u32 d_secpercyl; |
| u32 d_secprtunit; |
| u16 d_sparespertrack; |
| u16 d_sparespercyl; |
| u32 d_acylinders; |
| u16 d_rpm, d_interleave, d_trackskew, d_cylskew; |
| u32 d_headswitch, d_trkseek, d_flags; |
| u32 d_drivedata[5]; |
| u32 d_spare[5]; |
| u32 d_magic2; /* must be DISKLABELMAGIC */ |
| u16 d_checksum; |
| u16 d_npartitions; |
| u32 d_bbsize, d_sbsize; |
| struct d_partition { |
| u32 p_size; |
| u32 p_offset; |
| u32 p_fsize; |
| u8 p_fstype; |
| u8 p_frag; |
| u16 p_cpg; |
| } d_partitions[MAXPARTITIONS]; |
| }; |
| |
| |
| typedef union __bootblock { |
| struct { |
| char __pad1[64]; |
| struct disklabel __label; |
| } __u1; |
| struct { |
| unsigned long __pad2[63]; |
| unsigned long __checksum; |
| } __u2; |
| char bootblock_bytes[512]; |
| unsigned long bootblock_quadwords[64]; |
| } bootblock; |
| |
| #define bootblock_label __u1.__label |
| #define bootblock_checksum __u2.__checksum |
| |
| int main(int argc, char ** argv) |
| { |
| bootblock bootblock_from_disk; |
| bootblock bootloader_image; |
| int dev, fd; |
| int i; |
| int nread; |
| |
| /* Make sure of the arg count */ |
| if(argc != 3) { |
| fprintf(stderr, "Usage: %s device lxboot\n", argv[0]); |
| exit(0); |
| } |
| |
| /* First, open the device and make sure it's accessible */ |
| dev = open(argv[1], O_RDWR); |
| if(dev < 0) { |
| perror(argv[1]); |
| exit(0); |
| } |
| |
| /* Now open the lxboot and make sure it's reasonable */ |
| fd = open(argv[2], O_RDONLY); |
| if(fd < 0) { |
| perror(argv[2]); |
| close(dev); |
| exit(0); |
| } |
| |
| /* Read in the lxboot */ |
| nread = read(fd, &bootloader_image, sizeof(bootblock)); |
| if(nread != sizeof(bootblock)) { |
| perror("lxboot read"); |
| fprintf(stderr, "expected %zd, got %d\n", sizeof(bootblock), nread); |
| exit(0); |
| } |
| |
| /* Read in the bootblock from disk. */ |
| nread = read(dev, &bootblock_from_disk, sizeof(bootblock)); |
| if(nread != sizeof(bootblock)) { |
| perror("bootblock read"); |
| fprintf(stderr, "expected %zd, got %d\n", sizeof(bootblock), nread); |
| exit(0); |
| } |
| |
| /* Swap the bootblock's disklabel into the bootloader */ |
| bootloader_image.bootblock_label = bootblock_from_disk.bootblock_label; |
| |
| /* Calculate the bootblock checksum */ |
| bootloader_image.bootblock_checksum = 0; |
| for(i = 0; i < 63; i++) { |
| bootloader_image.bootblock_checksum += |
| bootloader_image.bootblock_quadwords[i]; |
| } |
| |
| /* Write the whole thing out! */ |
| lseek(dev, 0L, SEEK_SET); |
| if(write(dev, &bootloader_image, sizeof(bootblock)) != sizeof(bootblock)) { |
| perror("bootblock write"); |
| exit(0); |
| } |
| |
| close(fd); |
| close(dev); |
| exit(0); |
| } |
| |
| |