summaryrefslogtreecommitdiff
path: root/sys/src/9/xen/dpart.c
diff options
context:
space:
mode:
authormischief <mischief@offblast.org>2014-06-24 18:02:25 -0700
committermischief <mischief@offblast.org>2014-06-24 18:02:25 -0700
commit5ba95fdb07ddc2c32111a1b2f57f17aa27fcbbf5 (patch)
treec1ec54cb9ecff85b0b820a26d26a10a32a118d0c /sys/src/9/xen/dpart.c
parentfa03455b5057675b18d1c87aef2d1071b2088de0 (diff)
import xen 32 bit paravirtual kernel from /n/sources/xen.
Diffstat (limited to 'sys/src/9/xen/dpart.c')
-rw-r--r--sys/src/9/xen/dpart.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/sys/src/9/xen/dpart.c b/sys/src/9/xen/dpart.c
new file mode 100644
index 000000000..17d3e4a3a
--- /dev/null
+++ b/sys/src/9/xen/dpart.c
@@ -0,0 +1,248 @@
+#include <u.h>
+#include <libc.h>
+#include <disk.h>
+
+typedef void Fs;
+#include "/sys/src/boot/pc/dosfs.h"
+
+enum {
+ Npart = 32
+};
+
+#define GSHORT(p) (((p)[1]<<8)|(p)[0])
+#define GLONG(p) ((GSHORT(p+2)<<16)|GSHORT(p))
+
+int
+readdisk(Disk *d, void *buf, vlong off, int len)
+{
+ if(seek(d->fd, off, 0) == -1
+ || read(d->fd, buf, len) != len)
+ return -1;
+ return 0;
+}
+
+void
+addpart(Disk *d, char *name, ulong s, ulong e)
+{
+ print("%s: part %s %lud %lud\n", d->prefix, name, s, e);
+ fprint(d->ctlfd, "part %s %lud %lud\n", name, s, e);
+}
+
+int
+isdos(int t)
+{
+ return t==FAT12 || t==FAT16 || t==FATHUGE || t==FAT32 || t==FAT32X;
+}
+
+int
+isextend(int t)
+{
+ return t==EXTEND || t==EXTHUGE || t==LEXTEND;
+}
+
+
+
+/* build a cdboot partition if there is an embedded boot floppy image */
+int
+cdpart(Disk *d)
+{
+ uchar buf[2048];
+ ulong a, n;
+ uchar *p;
+
+ if(readdisk(d, buf, 17*2048, 2048) == -1
+ || strcmp((char*)buf+1, "CD001\x01EL TORITO SPECIFICATION") != 0)
+ return 0;
+
+ p = buf + 0x47;
+ a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
+
+ if(readdisk(d, buf, a*2048, 2048) == -1
+ || memcmp((char*)buf, "\x01\x00\x00\x00", 4) != 0
+ || memcmp((char*)buf+30, "\x55\xAA", 2) != 0
+ || buf[0x20] != 0x88)
+ return 0;
+
+ p = buf+0x28;
+ a = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+
+ switch(buf[0x21]) {
+ case 1: n = 1200*1024; break;
+ case 2: n = 1440*1024; break;
+ case 3: n = 2880*1024; break;
+ default: return 0;
+ }
+
+ a = a * (uvlong)2048 / d->secsize;
+ n /= d->secsize;
+ addpart(d, "cdboot", a, a+n);
+ return 1;
+}
+
+int
+p9part(Disk *d, char *name, ulong pstart)
+{
+ char partbuf[512];
+ char *field[4], *line[Npart+1], *name2;
+ ulong start, end;
+ int i, n;
+
+ name2 = smprint("%s%s", d->prefix, name);
+ d = opendisk(name2, 1, 0);
+ if(!d) {
+ fprint(2, "%s: %r\n", name2);
+ free(name2);
+ return 0;
+ }
+ free(name2);
+
+ if(readdisk(d, partbuf, 512, sizeof partbuf) == -1)
+ return 0;
+ partbuf[sizeof partbuf - 1] = '\0';
+ if(strncmp(partbuf, "part ", 5) != 0
+ || (n = getfields(partbuf, line, Npart+1, 0, "\n")) == 0)
+ return 0;
+ for(i = 0; i < n; i++) {
+ if(strncmp(line[i], "part ", 5) != 0)
+ break;
+ if(getfields(line[i], field, 4, 0, " ") != 4)
+ break;
+ start = strtoul(field[2], 0, 0);
+ end = strtoul(field[3], 0, 0);
+ if(start >= end)
+ break;
+ addpart(d, field[1], pstart+start, pstart+end);
+ }
+ return 0;
+}
+
+int
+mbrpart(Disk *d)
+{
+ uchar mbrbuf[512];
+ char name[10];
+ Dospart *dp;
+ ulong taboffset, start, end;
+ ulong firstxpart, nxtxpart;
+ int i, nplan9, havedos;
+
+#define readmbr() \
+ if(readdisk(d, mbrbuf, (uvlong)taboffset*512, sizeof mbrbuf) == -1 \
+ || mbrbuf[0x1FE] != 0x55 || mbrbuf[0x1FF] != 0xAA) \
+ return 0
+
+ if(d->secsize > 512)
+ return 0;
+ dp = (Dospart*)&mbrbuf[0x1BE];
+ taboffset = 0;
+
+ if(1) {
+ /* get the MBR (allowing for DMDDO) */
+ readmbr();
+ for(i = 0; i < 4; i++) {
+ if(dp[i].type == DMDDO) {
+ taboffset = 63;
+ readmbr();
+ i = -1; /* start over */
+ }
+ }
+ }
+
+ /*
+ * Read the partitions, first from the MBR and then
+ * from successive extended partition tables.
+ */
+ nplan9 = 0;
+ havedos = 0;
+ firstxpart = 0;
+ for(;;) {
+ readmbr();
+ nxtxpart = 0;
+ for(i = 0; i < 4; i++) {
+ /* partition offsets are relative to taboffset */
+ start = taboffset+GLONG(dp[i].start);
+ end = start+GLONG(dp[i].len);
+ if(dp[i].type == PLAN9) {
+ if(nplan9 == 0)
+ strcpy(name, "plan9");
+ else
+ sprint(name, "plan9.%d", nplan9);
+ addpart(d, name, start, end);
+ p9part(d, name, start);
+ nplan9++;
+ }
+
+ if(!havedos && isdos(dp[i].type)) {
+ havedos = 1;
+ addpart(d, "dos", start, end);
+ }
+
+ /* nxtxpart is relative to firstxpart (or 0), not taboffset */
+ if(isextend(dp[i].type))
+ nxtxpart = start-taboffset+firstxpart;
+ }
+ if(!nxtxpart)
+ break;
+ if(!firstxpart)
+ firstxpart = nxtxpart;
+ taboffset = nxtxpart;
+ }
+ return nplan9 + havedos;
+}
+
+void
+partall(void)
+{
+ Disk *d;
+ Dir *ent;
+ char *name;
+ int fd, i, n;
+
+ fd = open("#S", OREAD);
+ if(fd == -1) {
+ fprint(2, "No disk\n");
+ return;
+ }
+
+ while((n = dirread(fd, &ent)) > 0) {
+ for(i = 0; i < n; i++) {
+ if(ent[i].mode & DMDIR) {
+ name = smprint("#S/%s/data", ent[i].name);
+ d = opendisk(name, 1, 0);
+ if(!d) {
+ fprint(2, "%s: %r\n", name);
+ continue;
+ }
+ // XXX not safe yet: if(!mbrpart(d) && !cdpart(d) && !p9part(d, "data", 0))
+ if(!mbrpart(d) && !cdpart(d))
+ fprint(2, "%s: no partitions\n", name);
+ close(d->fd);
+ }
+ }
+ }
+ close(fd);
+}
+
+
+void
+main(int argc, char **argv)
+{
+ USED(argc, argv);
+
+ fmtinstall('r', errfmt);
+
+ bind("#c", "/dev", MBEFORE);
+ open("/dev/cons", OREAD);
+ open("/dev/cons", OWRITE);
+ open("/dev/cons", OWRITE);
+
+ partall();
+
+ close(0);
+ close(1);
+ close(2);
+
+ exec("/boot/boot2", argv);
+
+ exits(0);
+}