From 3544c39d3a383c07c4b8d452b6bb25ba639e042f Mon Sep 17 00:00:00 2001 From: ment Date: Thu, 28 Apr 2011 00:05:36 +0200 Subject: [PATCH] unix tool for making bootable plan9 disks. --- sys/src/cmd/unix/mbrfix.c | 196 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 sys/src/cmd/unix/mbrfix.c diff --git a/sys/src/cmd/unix/mbrfix.c b/sys/src/cmd/unix/mbrfix.c new file mode 100644 index 000000000..2b32de5cb --- /dev/null +++ b/sys/src/cmd/unix/mbrfix.c @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long long vlong; + + +enum { + Sectsz = 0x200, + Psectsz = 11, + Pclustsc = 13, + Presvd = 14, + Pnumfat = 16, + Pfatsz = 22, + Pfatsz32 = 36, + Pvolid = 67, +}; + +int +readn(int f, void *av, int n) +{ + char *a; + int m, t; + a = av; + t = 0; + while(t < n){ + m = read(f, a+t, n-t); + if(m <= 0){ + if(t == 0) + return m; + break; + } + t += m; + } + return t; +} + +void +sysfatal(char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + vfprintf(stderr, fmt, va); + va_end(va); + fprintf(stderr, "\n"); + exit(1); +} + +void +readsect(int fd, uint n, void *data) +{ + loff_t off; + + off = (loff_t) n * Sectsz; + if(llseek(fd, off, SEEK_SET) != off) + sysfatal("seek to sector 0x%x failed", n); + if(readn(fd, data, Sectsz) != Sectsz) + sysfatal("short read: %m"); +} + +void +writesect(int fd, uint n, void *data) +{ + loff_t off; + + off = (loff_t) n * Sectsz; + if(llseek(fd, off, SEEK_SET) != off) + sysfatal("seek to sector 0x%x failed", n); + if(write(fd, data, Sectsz) != Sectsz) + sysfatal("short write: %m"); +} + +uint +getulong(uchar *s) +{ + return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); +} + +void +putulong(uchar *s, uint n) +{ + *s++ = n & 0xff; + *s++ = (n >> 8) & 0xff; + *s++ = (n >> 16) & 0xff; + *s++ = (n >> 24) & 0xff; +} + + +uint +getushort(uchar *s) +{ + return s[0] | (s[1] << 8); +} + +int +checksig(uchar *s) +{ + return s[0x1fe] == 0x55 && s[0x1ff] == 0xaa; +} + +void +fixpbs(uchar *pbs, uchar *pbs9, uint lba) +{ + uint a; + uint fatsz, resvd, numfat; + + numfat = pbs[Pnumfat]; + fatsz = getushort(&pbs[Pfatsz]); + if(fatsz == 0) + fatsz = getulong(&pbs[Pfatsz32]); + resvd = getushort(&pbs[Presvd]); + + a = pbs9[1] + 2; + memcpy(pbs, pbs9, 3); + memcpy(pbs+a, pbs9+a, Sectsz-a-2); + a = lba + numfat * fatsz + resvd; + printf("Xroot=%x\n", a); + putulong(&pbs[Pvolid], a); +} + + +int +main(int argc, char *argv[]) +{ + int dev, fd, i; + uchar mbr9[Sectsz], pbs9[Sectsz]; + uchar mbr[Sectsz], pbs[Sectsz]; + uint lba; + int part, want; + char *mbrfn, *pbsfn, *devfn; + + if(argc < 4) + sysfatal("usage: [part]"); + devfn = argv[1]; + mbrfn = argv[2]; + pbsfn = argv[3]; + want = argc >= 5 ? atoi(argv[4]) : -1; + part = -1; + + dev = open(devfn, O_RDWR); + if(dev < 0) + sysfatal("%s: %m", devfn); + + if((fd = open(mbrfn, O_RDONLY)) < 0) + sysfatal("%s: %m", mbrfn); + if(readn(fd, mbr9, Sectsz) < 3) + sysfatal("%s: too short", mbrfn); + close(fd); + + fd = open(pbsfn, O_RDONLY); + if(fd < 0) + sysfatal("%s: %m", pbsfn); + if(readn(fd, pbs9, Sectsz) < 3) + sysfatal("%s: too short", pbsfn); + if(pbs9[0] != 0xeb) + sysfatal("first byte of pbs not a short jump"); + close(fd); + + readsect(dev, 0, mbr); + if(!checksig(mbr)) + sysfatal("sector 0 is missing signature"); + for(i=0; i<4; i++){ + if(mbr[0x1be + i*16] == 0x80 && (part == -1 || i == want)) + part = i; + } + if(part == -1) + sysfatal("no bootable partitions found"); + if(want != -1 && part != want) + sysfatal("partition %d is not bootable", want); + + lba = getulong(&mbr[0x1be + part*16 + 8]); + if(lba == 0) + sysfatal("partition %d has zero LBA", part); + + readsect(dev, lba, pbs); + if(!checksig(pbs)) + sysfatal("partition %d (LBA=0x%x) is missing signaure", part, lba); + if(getushort(&pbs[Psectsz]) != 512) + sysfatal("sector size not 512"); + + printf("using partition %d, LBA=0x%x\n", part, lba); + memcpy(mbr, mbr9, 446); + fixpbs(pbs, pbs9, lba); + + writesect(dev, 0, mbr); + writesect(dev, lba, pbs); + + close(dev); + return 0; +}