second try at no-driver loader. renamed to "ipl*", but i'm not sure how to recind the old patch. the fat and iso bootloader are no longer built by default, but that can be changed easily if required. - erik Reference: /n/patches.lsub.org/patch/pcipl Date: Fri Jun 22 21:45:02 CES 2012 Signed-off-by: quanstro@quanstro.net --- /sys/src/boot/pcipl/a20.s Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/a20.s Fri Jun 22 20:33:06 2012 @@ -0,0 +1,70 @@ +#include "x16.h" + +#undef ORB + +TEXT a20(SB), $0 + CALL rmode16(SB) + STI + LWI(0x2401, rAX) + BIOSCALL(0x15) + JC _biosfail + CALL16(pmode32(SB)) + RET + +_biosfail: + CALL16(pmode32(SB)) + + /* fast a20 */ + MOVL $0x92, DX + INB + ANDB $0xFE, AX + ORB $0x02, AX + OUTB + + /* slow a20 */ + CALL a20wait(SB) + MOVL $0x64, DX + MOVB $0xAD, AL + OUTB + + CALL a20wait(SB) + MOVL $0x64, DX + MOVB $0xD0, AL + OUTB + + CALL a20wait2(SB) + MOVL $0x60, DX + INB + PUSHL AX + + CALL a20wait(SB) + MOVL $0x64, DX + MOVB $0xD1, AL + OUTB + + CALL a20wait(SB) + MOVL $0x60, DX + POPL AX + ORB $2, AL + OUTB + + CALL a20wait(SB) + MOVL $0x64, DX + MOVB $0xAE, AL + OUTB + +TEXT a20wait(SB), $0 +_a20wait: + MOVL $0x64, DX + INB + TESTB $1, AL + JZ _a20wait2 + RET + +TEXT a20wait2(SB), $0 +_a20wait2: + MOVL $0x64, DX + INB + TESTB $2, AL + JNZ _a20wait + RET --- /sys/src/boot/pcipl/apm.s Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/apm.s Fri Jun 22 20:33:06 2012 @@ -0,0 +1,51 @@ +#include "x16.h" +#include "mem.h" + +TEXT apm(SB), $0 + MOVL id+4(SP), BX + CALL rmode16(SB) + + PUSHR(rBX) + LWI(0x5300, rAX) + BIOSCALL(0x15) + POPR(rBX) + JC noapm + + PUSHR(rBX) + LWI(0x5304, rAX) + BIOSCALL(0x15) + POPR(rBX) + CLC + + /* connect */ + LWI(0x5303, rAX) + BIOSCALL(0x15) + JC noapm + + OPSIZE; PUSHR(rSI) + OPSIZE; PUSHR(rBX) + PUSHR(rDI) + PUSHR(rDX) + PUSHR(rCX) + PUSHR(rAX) + + LWI(CONFADDR, rDI) + + /* + * write APM data. first four bytes are APM\0. + */ + LWI(0x5041, rAX) + STOSW + + LWI(0x004d, rAX) + STOSW + + LWI(8, rCX) +apmmove: + POPR(rAX) + STOSW + LOOP apmmove + +noapm: + CALL16(pmode32(SB)) + RET --- /sys/src/boot/pcipl/e820.s Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/e820.s Fri Jun 22 20:33:06 2012 @@ -0,0 +1,32 @@ +#include "x16.h" +#include "mem.h" + +TEXT e820(SB), $0 + MOVL bx+4(SP), BX + MOVL p+8(SP), DI + MOVL $0xE820, AX + MOVL $0x534D4150, DX + CALL rmode16(SB) + LWI(24, rCX) + BIOSCALL(0x15) + JC _bad + CALL16(pmode32(SB)) + CMPB CL, $24 + JZ _ret + MOVL $1, AX + MOVL p+8(SP), DI + MOVL AX, 20(DI) +_ret: + MOVL BX, AX + RET +_bad: + CALL16(pmode32(SB)) + XORL AX, AX + MOVL p+8(SP), DI + MOVL AX, 0(DI) + MOVL AX, 4(DI) + MOVL AX, 8(DI) + MOVL AX, 12(DI) + MOVL AX, 16(DI) + MOVL AX, 20(DI) + RET --- /sys/src/boot/pcipl/fat.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/fat.c Fri Jun 22 20:33:06 2012 @@ -0,0 +1,393 @@ +#include +#include "fns.h" + +#define GETSHORT(p) (*(ushort *)(p)) +#define GETLONG(p) (*(uint *)(p)) + +enum { + Sectsz = 0x200, + Dirsz = 0x20, + Maxpath = 64, + Fat12 = 1, + Fat16 = 2, + Fat32 = 4, +}; + +typedef struct File File; +typedef struct Dir Dir; +typedef struct Pbs Pbs; +typedef struct Fat Fat; + +struct Fat +{ + ulong ver; + int drive; + ulong clustsize; + ulong eofmark; + ulong partlba; + ulong fatlba; + ulong dirstart; /* LBA for FAT16, cluster for FAT32 */ + ulong dirents; + ulong datalba; +}; + +struct File +{ + Fat *fat; + ulong lba; + ulong clust; + ulong lbaoff; + ulong len; + uchar *rp; + uchar *ep; + uchar buf[Sectsz]; +}; + +struct Dir +{ + char name[11]; + uchar attr; + uchar reserved; + uchar ctime; + uchar ctime[2]; + uchar cdate[2]; + uchar adate[2]; + uchar starthi[2]; + uchar mtime[2]; + uchar mdate[2]; + uchar startlo[2]; + uchar len[4]; +}; + +struct Pbs +{ + uchar magic[3]; + uchar version[8]; + uchar sectsize[2]; + uchar clustsize; + uchar nreserv[2]; + uchar nfats; + uchar rootsize[2]; + uchar volsize[2]; + uchar mediadesc; + uchar fatsize[2]; + uchar trksize[2]; + uchar nheads[2]; + uchar nhidden[4]; + uchar bigvolsize[4]; + union + { + struct + { + uchar driveno; + uchar reserved0; + uchar bootsig; + uchar volid[4]; + uchar label[11]; + uchar type[8]; + } fat16; + struct + { + uchar fatsize[4]; + uchar flags[2]; + uchar ver[2]; + uchar rootclust[4]; + uchar fsinfo[2]; + uchar bootbak[2]; + uchar reserved0[12]; + uchar driveno; + uchar reserved1; + uchar bootsig; + uchar volid[4]; + uchar label[11]; + uchar type[8]; + } fat32; + }; +}; + +int readsect(ulong drive, ulong lba, void *buf); + +void +unload(void) +{ +} + +static ulong +readnext(File *fp, ulong clust) +{ + Fat *fat = fp->fat; + uint b = fat->ver; + ulong sect, off; + + sect = clust * b / Sectsz; + off = clust * b % Sectsz; + if(readsect(fat->drive, fat->fatlba + sect, fp->buf)) + memset(fp->buf, 0xff, 4); + switch(fat->ver){ + case Fat16: + return GETSHORT(&fp->buf[off]); + case Fat32: + return GETLONG(&fp->buf[off])& 0x0fffffff; + } + return 0; +} + +int +read(void *f, void *data, int len) +{ + File *fp = f; + Fat *fat = fp->fat; + + if(fp->len > 0 && fp->rp >= fp->ep){ + if(fp->clust != ~0U){ + if(fp->lbaoff % fat->clustsize == 0){ + if((fp->clust >> 4) == fat->eofmark) + return -1; + fp->lbaoff = (fp->clust - 2) * fat->clustsize; + fp->clust = readnext(fp, fp->clust); + fp->lba = fp->lbaoff + fat->datalba; + } + fp->lbaoff++; + } + if(readsect(fat->drive, fp->lba++, fp->rp = fp->buf)) + return -1; + } + if(fp->len < len) + len = fp->len; + if(len > (fp->ep - fp->rp)) + len = fp->ep - fp->rp; + memmove(data, fp->rp, len); + fp->rp += len; + fp->len -= len; + return len; +} + +void +close(void *) +{ +} + +static int +dirname(Dir *d, char buf[Maxpath]) +{ + char c, *x; + + if(d->attr == 0x0F || *d->name <= 0) + return -1; + memmove(buf, d->name, 8); + x = buf+8; + while(x > buf && x[-1] == ' ') + x--; + if(d->name[8] != ' '){ + *x++ = '.'; + memmove(x, d->name+8, 3); + x += 3; + } + while(x > buf && x[-1] == ' ') + x--; + *x = 0; + x = buf; + while(c = *x){ + if(c >= 'A' && c <= 'Z'){ + c -= 'A'; + c += 'a'; + } + *x++ = c; + } + return x - buf; +} + +static ulong +dirclust(Dir *d) +{ + return *((ushort*)d->starthi)<<16 | *((ushort*)d->startlo); +} + +static void +fileinit(File *fp, Fat *fat, ulong lba) +{ + fp->fat = fat; + fp->lba = lba; + fp->len = 0; + fp->lbaoff = 0; + fp->clust = ~0U; + fp->rp = fp->ep = fp->buf + Sectsz; +} + +static int +fatwalk(File *fp, Fat *fat, char *path) +{ + char name[Maxpath], *end; + int i, j; + Dir d; + + if(fat->ver == Fat32){ + fileinit(fp, fat, 0); + fp->clust = fat->dirstart; + fp->len = ~0U; + }else{ + fileinit(fp, fat, fat->dirstart); + fp->len = fat->dirents * Dirsz; + } + for(;;){ + if(readn(fp, &d, Dirsz) != Dirsz) + break; + if((i = dirname(&d, name)) <= 0) + continue; + while(*path == '/') + path++; + if((end = strchr(path, '/')) == 0) + end = path + strlen(path); + j = end - path; + if(i == j && memcmp(name, path, j) == 0){ + fileinit(fp, fat, 0); + fp->clust = dirclust(&d); + fp->len = *((ulong*)d.len); + if(*end == 0) + return 0; + else if(d.attr & 0x10){ + fp->len = fat->clustsize * Sectsz; + path = end; + continue; + } + break; + } + } + return -1; +} + +static int +conffat(Fat *fat, void *buf) +{ + Pbs *p = buf; + uint fatsize, volsize, datasize, reserved; + uint ver, dirsize, dirents, clusters; + + /* sanity check */ + if(GETSHORT(p->sectsize) != Sectsz){ + print("sectsize != 512\r\n"); + halt(); + } + + /* load values from fat */ + fatsize = GETSHORT(p->fatsize); + if(fatsize == 0) + fatsize = GETLONG(p->fat32.fatsize); + volsize = GETSHORT(p->volsize); + if(volsize == 0) + volsize = GETLONG(p->bigvolsize); + reserved = GETSHORT(p->nreserv); + dirents = GETSHORT(p->rootsize); + dirsize = (dirents * Dirsz + Sectsz - 1) / Sectsz; + datasize = volsize - (reserved + fatsize * p->nfats + dirsize); + clusters = datasize / p->clustsize; + + /* determine fat type */ + if(clusters < 4085) + ver = Fat12; + else if(clusters < 65525) + ver = Fat16; + else + ver = Fat32; + + /* another check */ + if(ver == Fat12){ + print("TODO: implement FAT12\r\n"); + halt(); + } + + /* fill FAT descriptor */ + fat->ver = ver; + fat->dirents = dirents; + fat->clustsize = p->clustsize; + fat->fatlba = fat->partlba + reserved; + fat->dirstart = fat->fatlba + fatsize * p->nfats; + if(ver == Fat32){ + fat->datalba = fat->dirstart; + fat->dirstart = GETLONG(p->fat32.rootclust); + fat->eofmark = 0xffffff; + }else{ + fat->datalba = fat->dirstart + dirsize; + fat->eofmark = 0xfff; + } + return 0; +} + +static int +findfat(Fat *fat, int drive, ulong xbase, ulong lba) +{ + struct { + uchar status; + uchar bchs[3]; + uchar typ; + uchar echs[3]; + uchar lba[4]; + uchar len[4]; + } *p; + uchar buf[Sectsz]; + int i; + + if(xbase == 0) + xbase = lba; + if(readsect(drive, lba, buf)) + return -1; + if(buf[0x1fe] != 0x55 || buf[0x1ff] != 0xAA) + return -1; + p = (void*)&buf[0x1be]; + for(i=0; i<4; i++){ + switch(p[i].typ){ + case 0x05: + case 0x0f: + case 0x85: + /* extended partitions */ + if(!findfat(fat, drive, xbase, xbase + GETLONG(p[i].lba))) + return 0; + /* no break */ + case 0x00: + continue; + default: + if(p[i].status != 0x80) + continue; + fat->drive = drive; + fat->partlba = lba + GETLONG(p[i].lba); + if(readsect(drive, fat->partlba, buf)) + continue; + if(conffat(fat, buf)) + continue; + return 0; + } + } + return -1; +} + +void +start(void *sp) +{ + char path[Maxpath], *kern; + int drive; + File fi; + Fat fat; + void *f; + + /* drive passed in DL */ + drive = ((ushort*)sp)[5] & 0xFF; + + if(findfat(&fat, drive, 0, 0)){ + print("no fat\r\n"); + halt(); + } + if(fatwalk(f = &fi, &fat, "plan9.ini")){ + print("no config\r\n"); + f = 0; + } + for(;;){ + kern = configure(f, path); f = 0; + if(fatwalk(&fi, &fat, kern)){ + print("not found\r\n"); + continue; + } + print(bootkern(&fi)); + print(crnl); + } +} + --- /sys/src/boot/pcipl/fns.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/fns.h Fri Jun 22 20:33:06 2012 @@ -0,0 +1,32 @@ +/* handy strings in l.s */ +extern char origin[]; +extern char hex[]; +extern char crnl[]; +extern char bootname[]; + +/* l.s */ +void start(void *sp); +int getc(void); +int gotc(void); +void cgaputc(int c); +void usleep(int t); +void halt(void); +void jump(void *pc); + +int read(void *f, void *data, int len); +int readn(void *f, void *data, int len); +void close(void *f); +void unload(void); + +void memset(void *p, int v, int n); +void memmove(void *dst, void *src, int n); +int memcmp(void *src, void *dst, int n); +int strlen(char *s); +char *strchr(char *s, int c); +char *strrchr(char *s, int c); +void putc(int); +void print(char *s); + +char *configure(void *f, char *path); +char *bootkern(void *f); + --- /sys/src/boot/pcipl/iso.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/iso.c Fri Jun 22 20:33:06 2012 @@ -0,0 +1,177 @@ +#include +#include "fns.h" + +enum { + Sectsz = 0x800, + Maxpath = 256, + Dirsz = 33, +}; + +typedef struct Extend Extend; +typedef struct Dir Dir; + +struct Extend +{ + int drive; + ulong lba; + ulong len; + uchar *rp; + uchar *ep; + uchar buf[Sectsz]; +}; + +struct Dir +{ + uchar dirlen; + uchar extlen; + + uchar lba[8]; + uchar len[8]; + + uchar date[7]; + + uchar flags[3]; + + uchar seq[4]; + + uchar namelen; +}; + +int readsect(ulong drive, ulong lba, void *buf); + +void +unload(void) +{ +} + +int +read(void *f, void *data, int len) +{ + Extend *ex = f; + + if(ex->len > 0 && ex->rp >= ex->ep) + if(readsect(ex->drive, ex->lba++, ex->rp = ex->buf)) + return -1; + if(ex->len < len) + len = ex->len; + if(len > (ex->ep - ex->rp)) + len = ex->ep - ex->rp; + memmove(data, ex->rp, len); + ex->rp += len; + ex->len -= len; + return len; +} + +void +close(void *f) +{ + Extend *ex = f; + + ex->drive = 0; + ex->lba = 0; + ex->len = 0; + ex->rp = ex->ep = ex->buf + Sectsz; +} + +static int +isowalk(Extend *ex, int drive, char *path) +{ + char name[Maxpath], c, *end; + int i; + Dir d; + + close(ex); + ex->drive = drive; + + /* find pvd */ + for(i=0x10; i<0x1000; i++){ + if(readsect(drive, i, ex->buf)) + return -1; + if(*ex->buf == 1) + break; + } + ex->lba = *((ulong*)(ex->buf + 156 + 2)); + ex->len = *((ulong*)(ex->buf + 156 + 10)); + + for(;;){ + if(readn(ex, &d, Dirsz) != Dirsz) + break; + if(d.dirlen == 0) + break; + if(readn(ex, name, d.namelen) != d.namelen) + break; + i = d.dirlen - (Dirsz + d.namelen); + while(i-- > 0) + read(ex, &c, 1); + for(i=0; i= 'A' && c <= 'Z'){ + c -= 'A'; + c += 'a'; + } + name[i] = c; + } + name[i] = 0; + while(*path == '/') + path++; + if((end = strchr(path, '/')) == 0) + end = path + strlen(path); + i = end - path; + if(d.namelen == i && memcmp(name, path, i) == 0){ + ex->rp = ex->ep; + ex->lba = *((ulong*)d.lba); + ex->len = *((ulong*)d.len); + if(*end == 0) + return 0; + else if(d.flags[0] & 2){ + path = end; + continue; + } + break; + } + } + close(ex); + return -1; +} + +void +start(void *sp) +{ + char path[Maxpath], *kern; + int drive; + Extend ex; + void *f; + + /* drive passed in DL */ + drive = ((ushort*)sp)[5] & 0xFF; + + /* + * load full bootblock as only the frist 2K get + * loaded from bios. the code is specially arranged + * to have all the important routines in the first + * 2K of the 9bootiso image. (strings have been + * placed in l.s to make sure they will be < 2K) + */ + if(isowalk(&ex, drive, bootname)){ + print(bootname); + putc('?'); + halt(); + } + readn(&ex, origin, ex.len); + close(&ex); + + if(isowalk(f = &ex, drive, "/cfg/plan9.ini")){ + print("no config\r\n"); + f = 0; + } + for(;;){ + kern = configure(f, path); f = 0; + if(isowalk(&ex, drive, kern)){ + print("not found\r\n"); + continue; + } + print(bootkern(&ex)); + print(crnl); + } +} + --- /sys/src/boot/pcipl/l.s Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/l.s Fri Jun 22 20:33:06 2012 @@ -0,0 +1,317 @@ +#include "x16.h" +#include "mem.h" + +#undef ORB + +#define DATA32SEL SELECTOR(1, SELGDT, 0) +#define EXEC32SEL SELECTOR(2, SELGDT, 0) +#define DATA16SEL SELECTOR(3, SELGDT, 0) +#define EXEC16SEL SELECTOR(4, SELGDT, 0) + +#define SEGSS BYTE $0x36 +#define SEGES BYTE $0x26 +#define FARRET BYTE $0xCB + +TEXT origin(SB), $0 + CLI + CLR(rCX) + MTSR(rCX, rSS) + OPSIZE; MOVL $origin(SB), SP + PUSHA + OPSIZE; ADSIZE; PUSHL SP + OPSIZE; ADSIZE; PUSHL CX + PUSHI(start(SB)) + +TEXT pmode32(SB), $0 + CLI + + /* get return pc */ + POPR(rDI) + + /* make sure stack is at 0000: */ + CLR(rCX) + MTSR(rCX, rSS) + OPSIZE; ANDL $0xFFFF, SP + + /* convert 16-bit return pc to far pointer */ + PUSHI(EXEC32SEL) + PUSHR(rDI) + + /* load gdt */ + SEGSS; LGDT(tgdtptr(SB)) + + /* enable protected mode */ + MFCR(rCR0, rCX) + ORB $1, CL + MTCR(rCX, rCR0) + + /* flush */ + FARJUMP16(EXEC16SEL, pmode32flush(SB)); +TEXT pmode32flush(SB), $0 + + /* load 32-bit protected mode data selector */ + LWI(DATA32SEL, rCX) + +_segret: + /* load all data segments */ + MTSR(rCX, rDS) + MTSR(rCX, rES) + MTSR(rCX, rFS) + MTSR(rCX, rGS) + MTSR(rCX, rSS) + FARRET + +TEXT rmode16(SB), $0 + /* setup farret to rmode16x */ + PUSHL $EXEC16SEL + PUSHL $rmode16x(SB) + + /* load 16-bit protected mode data selector */ + MOVL $DATA16SEL, CX + JMP _segret + +TEXT rmode16x(SB), $0 + /* disable protected mode */ + MFCR(rCR0, rCX) + ANDB $0xfe, CL + MTCR(rCX, rCR0) + + /* flush */ + FARJUMP16(0, rmode16flush(SB)); +TEXT rmode16flush(SB), $0 + + /* + * load 16-bit realmode data segment 0000: and + * return to 32 bit return pc interpreted + * as 16 bit far pointer. + */ + CLR(rCX) + JMP _segret + +TEXT tgdt(SB), $0 + /* null descriptor */ + LONG $0 + LONG $0 + + /* data segment descriptor for 4 gigabytes (PL 0) */ + LONG $(0xFFFF) + LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW) + + /* exec segment descriptor for 4 gigabytes (PL 0) */ + LONG $(0xFFFF) + LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR) + + /* data segment descriptor for (PL 0) 16-bit */ + LONG $(0xFFFF) + LONG $((0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW) + + /* exec segment descriptor for (PL 0) 16-bit */ + LONG $(0xFFFF) + LONG $((0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR) + +TEXT tgdtptr(SB), $0 + WORD $(5*8) + LONG $tgdt(SB) + +TEXT jump(SB), $0 + MOVL 4(SP), AX + JMP *AX + +TEXT halt(SB), $0 +_halt: + JMP _halt + +TEXT getc(SB), $0 + CALL rmode16(SB) + STI + MOVB $0x00, AH + BIOSCALL(0x16) +_getcret: + CALL16(pmode32(SB)) + ANDL $0xFF, AX + RET + +TEXT gotc(SB), $0 + CALL rmode16(SB) + STI + MOVB $0x01, AH + BIOSCALL(0x16) + JNZ _getcret + CLR(rAX) + JMP _getcret + +TEXT cgaputc(SB), $0 + MOVL 4(SP),AX + CALL rmode16(SB) + STI + MOVB $0x0E, AH + BIOSCALL(0x10) +_pret32: + CALL16(pmode32(SB)) + ANDL $0xFFFF, AX + RET + +TEXT usleep(SB), $0 + MOVL t+4(SP), AX + PUSHL AX + CALL rmode16(SB) + STI + POPR(rDX) + POPR(rCX) + MOVB $0x86, AH + BIOSCALL(0x15) + JMP _pret32 + +#ifdef PXE + +TEXT pxeinit(SB), $0 + CALL rmode16(SB) + + /* get pxe env structure in ES:BX */ + LWI(0x5650, rAX) + BIOSCALL(0x1A) + JC _pret32 + + /* !PXE or PXEENV+ signature */ + SEGES; LXW(0, xBX, rAX) + CMPI((('!'<<0)|('P'<<8)), rAX) + JEQ _getentry + CMPI((('P'<<0)|('X'<<8)), rAX) + JNE _pret32 + + SEGES; LXW(0x2A, xBX, rAX) + SEGES; LXW(0x28, xBX, rBX) + MTSR(rAX, rES) + +_getentry: + SEGES; LXW(0x12, xBX, rAX) + SW(rAX, pxepseg(SB)) + SEGES; LXW(0x10, xBX, rAX) + SW(rAX, pxepoff(SB)) + CLR(rAX) + JMP _pret32 + +TEXT pxecallret(SB), $0 + ADDI(6, rSP) + JMP _pret32 + +TEXT pxecall(SB), $0 + MOVL op+4(SP),AX + MOVL buf+8(SP),SI + CALL rmode16(SB) + + CLR(rCX) + PUSHR(rCX) + PUSHR(rSI) + + /* opcode */ + PUSHR(rAX) + + /* farcall */ + PUSHR(rCX) + PUSHI(pxecallret(SB)) + + LW(pxepseg(SB), rAX) + PUSHR(rAX) + LW(pxepoff(SB), rAX) + PUSHR(rAX) + + STI + + CLR(rAX) + CLR(rBX) + CLR(rCX) + CLR(rDX) + CLR(rDI) + CLR(rSI) + FARRET + +TEXT pxepseg(SB), $0 + WORD $0 +TEXT pxepoff(SB), $0 + WORD $0 + +#else /* PXE */ + +/* + * in: + * DL drive + * AX:BX lba32, + * 0000:SI buffer + */ +TEXT readsect16(SB), $0 + PUSHA + CLR(rCX) + + PUSHR(rCX) /* qword lba */ + PUSHR(rCX) + PUSHR(rBX) + PUSHR(rAX) + + PUSHR(rCX) /* dword buffer */ + PUSHR(rSI) + + INC(rCX) + PUSHR(rCX) /* word # of sectors */ + + PUSHI(0x0010) /* byte reserved, byte packet size */ + + MW(rSP, rSI) + LWI(0x4200, rAX) + BIOSCALL(0x13) + JCC _readok + ADDI(0x10, rSP) + POPA + CLR(rAX) + DEC(rAX) + RET +_readok: + ADDI(0x10, rSP) + POPA + CLR(rAX) + RET + +TEXT readsect(SB), $0 + MOVL 4(SP), DX + MOVW 8(SP), AX + MOVW 10(SP), BX + MOVL 12(SP), SI + CALL rmode16(SB) + STI + CALL16(readsect16(SB)) + CALL16(pmode32(SB)) + ANDL $0xFFFF, AX + RET + +#endif + +#ifdef ISO + +TEXT bootname(SB), $0 + BYTE $'3'; BYTE $'8'; BYTE $'6'; BYTE $'/'; + BYTE $'9'; BYTE $'b'; BYTE $'o'; BYTE $'o'; + BYTE $'t'; BYTE $'i'; BYTE $'s'; BYTE $'o'; + BYTE $0 + +#endif + +TEXT outb(SB), 1, $0 + MOVL port+0(FP), DX + MOVL byte+4(FP), AX + OUTB + RET + +TEXT inb(SB),$0 + MOVL p+0(FP),DX + XORL AX,AX + INB + RET + +TEXT crnl(SB), $0 + BYTE $'\r'; BYTE $'\n'; BYTE $0 + +TEXT hex(SB), $0 + BYTE $'0'; BYTE $'1'; BYTE $'2'; BYTE $'3'; + BYTE $'4'; BYTE $'5'; BYTE $'6'; BYTE $'7'; + BYTE $'8'; BYTE $'9'; BYTE $'a'; BYTE $'b'; + BYTE $'c'; BYTE $'d'; BYTE $'e'; BYTE $'f' --- /sys/src/boot/pcipl/mbr.s Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/mbr.s Fri Jun 22 20:33:06 2012 @@ -0,0 +1,259 @@ +/* + * Hard disc boot block. Loaded at 0x7C00, relocates to 0x0600: + * 8a mbr.s; 8l -o mbr -l -H3 -T0x0600 mbr.8 + */ +#include "x16.h" +#include "mem.h" + +/*#define FLOPPY 1 /* test on a floppy */ +#define TRACE(C) PUSHA;\ + CLR(rBX);\ + MOVB $C, AL;\ + LBI(0x0E, rAH);\ + BIOSCALL(0x10);\ + POPA + +/* + * We keep data on the stack, indexed by BP. + */ +#define Xdap 0x00 /* disc address packet */ +#define Xtable 0x10 /* partition table entry */ +#define Xdrive 0x12 /* starting disc */ +#define Xtotal 0x14 /* sum of allocated data above */ + +/* + * Start: loaded at 0000:7C00, relocate to 0000:0600. + * Boot drive is in rDL. + */ +TEXT _start(SB), $0 + CLI + CLR(rAX) + MTSR(rAX, rSS) /* 0000 -> rSS */ + LWI((0x7C00-Xtotal), rSP) /* 7Bxx -> rSP */ + MW(rSP, rBP) /* set the indexed-data pointer */ + + MTSR(rAX, rDS) /* 0000 -> rDS, source segment */ + LWI(0x7C00, rSI) /* 7C00 -> rSI, source offset */ + MTSR(rAX, rES) /* 0000 -> rES, destination segment */ + LWI(0x600, rDI) /* 0600 -> rDI, destination offset */ + LWI(0x100, rCX) /* 0100 -> rCX, loop count (words) */ + + CLD + REP; MOVSL /* MOV DS:[(E)SI] -> ES:[(E)DI] */ + + FARJUMP16(0x0000, _start0600(SB)) + +TEXT _start0600(SB), $0 +#ifdef FLOPPY + LBI(0x80, rDL) +#else + CLRB(rAL) /* some systems pass 0 */ + CMPBR(rAL, rDL) + JNE _save + LBI(0x80, rDL) +#endif /* FLOPPY */ +_save: + SXB(rDL, Xdrive, xBP) /* save disc */ + + LWI(confidence(SB), rSI) /* for that warm, fuzzy feeling */ + CALL16(BIOSputs(SB)) + + LWI(_start+0x01BE(SB), rSI) /* address of partition table */ + LWI(0x04, rCX) /* 4 entries in table */ + LBI(0x80, rAH) /* active entry value */ + CLRB(rAL) /* inactive entry value */ + +_activeloop0: + LXB(0x00, xSI, rBL) /* get active entry from table */ + CMPBR(rBL, rAH) /* is this an active entry? */ + JEQ _active + + CMPBR(rBL, rAL) /* if not active it should be 0 */ + JNE _invalidMBR + + ADDI(0x10, rSI) /* next table entry */ + DEC(rCX) + JNE _activeloop0 + + LWI(noentry(SB), rSI) + CALL16(buggery(SB)) + +_active: + MW(rSI, rDI) /* save table address */ + +_activeloop1: + ADDI(0x10, rSI) /* next table entry */ + DEC(rCX) + JEQ _readsector + + LXB(0x00, xSI, rBL) /* get active entry from table */ + CMPBR(rBL, rAH) /* is this an active entry? */ + JNE _activeloop1 /* should only be one active */ + +_invalidMBR: + LWI(invalidMBR(SB), rSI) + CALL16(buggery(SB)) + +_readsector: + LBI(0x41, rAH) /* check extensions present */ + LWI(0x55AA, rBX) + LXB(Xdrive, xBP, rDL) /* drive */ + BIOSCALL(0x13) /* CF set on failure */ + JCS _readsector2 + CMPI(0xAA55, rBX) + JNE _readsector2 + ANDI(0x0001, rCX) + JEQ _readsector2 + +_readsector42: + SBPBI(0x10, Xdap+0) /* packet size */ + SBPBI(0x00, Xdap+1) /* reserved */ + SBPBI(0x01, Xdap+2) /* number of blocks to transfer */ + SBPBI(0x00, Xdap+3) /* reserved */ + SBPWI(0x7C00, Xdap+4) /* transfer buffer :offset */ + SBPWI(0x0000, Xdap+6) /* transfer buffer seg: */ + LXW(0x08, xDI, rAX) /* LBA (64-bits) */ + SBPW(rAX, Xdap+8) + LXW(0x0A, xDI, rAX) + SBPW(rAX, Xdap+10) + SBPWI(0x0000, Xdap+12) + SBPWI(0x0000, Xdap+14) + + MW(rBP, rSI) /* disk address packet */ + LBI(0x42, rAH) /* extended read */ + BIOSCALL(0x13) /* CF set on failure */ + JCC _readsectorok + + LWI(ioerror(SB), rSI) + CALL16(buggery(SB)) + +/* + * Read a sector from a disc using the traditional BIOS call. + * For BIOSCALL(0x13/AH=0x02): + * rAH 0x02 + * rAL number of sectors to read (1) + * rCH low 8 bits of cylinder + * rCL high 2 bits of cylinder (7-6), sector (5-0) + * rDH head + * rDL drive + * rES:rBX buffer address + */ +_readsector2: + LXB(0x01, xDI, rDH) /* head */ + LXW(0x02, xDI, rCX) /* save active cylinder/sector */ + + LWI(0x0201, rAX) /* read one sector */ + LXB(Xdrive, xBP, rDL) /* drive */ + LWI(0x7C00, rBX) /* buffer address (rES already OK) */ + BIOSCALL(0x13) /* CF set on failure */ + JCC _readsectorok + + LWI(ioerror(SB), rSI) + CALL16(buggery(SB)) + +_readsectorok: + LWI(0x7C00, rBX) /* buffer address (rES already OK) */ + LXW(0x1FE, xBX, rAX) + CMPI(0xAA55, rAX) + JNE _bbnotok + + /* + * Jump to the loaded PBS. + * rDL and rSI should still contain the drive + * and partition table pointer respectively. + */ + MW(rDI, rSI) + FARJUMP16(0x0000, 0x7C00) + +_bbnotok: + LWI(invalidPBS(SB), rSI) + +TEXT buggery(SB), $0 + CALL16(BIOSputs(SB)) + LWI(reboot(SB), rSI) + CALL16(BIOSputs(SB)) + +_wait: + CLR(rAX) /* wait for any key */ + BIOSCALL(0x16) + +_reset: + CLR(rBX) /* set ES segment for BIOS area */ + MTSR(rBX, rES) + + LWI(0x0472, rBX) /* warm-start code address */ + LWI(0x1234, rAX) /* warm-start code */ + POKEW /* MOVW AX, ES:[BX] */ + + FARJUMP16(0xFFFF, 0x0000) /* reset */ + +/* + * Output a string to the display. + * String argument is in rSI. + */ +TEXT BIOSputs(SB), $0 + PUSHA + CLR(rBX) +_BIOSputs: + LODSB + ORB(rAL, rAL) + JEQ _BIOSputsret + + LBI(0x0E, rAH) + BIOSCALL(0x10) + JMP _BIOSputs + +_BIOSputsret: + POPA + RET + +/* "No active entry in MBR" */ +TEXT noentry(SB), $0 + BYTE $'N'; BYTE $'o'; BYTE $' '; BYTE $'a'; + BYTE $'c'; BYTE $'t'; BYTE $'i'; BYTE $'v'; + BYTE $'e'; BYTE $' '; BYTE $'e'; BYTE $'n'; + BYTE $'t'; BYTE $'r'; BYTE $'y'; BYTE $' '; + BYTE $'i'; BYTE $'n'; BYTE $' '; BYTE $'M'; + BYTE $'B'; BYTE $'R'; + BYTE $'\z'; + +/* "Invalid MBR" */ +TEXT invalidMBR(SB), $0 + BYTE $'I'; BYTE $'n'; BYTE $'v'; BYTE $'a'; + BYTE $'l'; BYTE $'i'; BYTE $'d'; BYTE $' '; + BYTE $'M'; BYTE $'B'; BYTE $'R'; + BYTE $'\z'; + +/* "I/O error" */ +TEXT ioerror(SB), $0 + BYTE $'I'; BYTE $'/'; BYTE $'O'; BYTE $' '; + BYTE $'e'; BYTE $'r'; BYTE $'r'; BYTE $'o'; + BYTE $'r'; + BYTE $'\z'; + +/* "Invalid PBS" */ +TEXT invalidPBS(SB), $0 + BYTE $'I'; BYTE $'n'; BYTE $'v'; BYTE $'a'; + BYTE $'l'; BYTE $'i'; BYTE $'d'; BYTE $' '; + BYTE $'P'; BYTE $'B'; BYTE $'S'; + BYTE $'\z'; + +/* "\r\nPress almost any key to reboot..." */ +TEXT reboot(SB), $0 + BYTE $'\r';BYTE $'\n'; + BYTE $'P'; BYTE $'r'; BYTE $'e'; BYTE $'s'; + BYTE $'s'; BYTE $' '; BYTE $'a'; BYTE $'l'; + BYTE $'m'; BYTE $'o'; BYTE $'s'; BYTE $'t'; + BYTE $' '; BYTE $'a'; BYTE $'n'; BYTE $'y'; + BYTE $' '; BYTE $'k'; BYTE $'e'; BYTE $'y'; + BYTE $' '; BYTE $'t'; BYTE $'o'; BYTE $' '; + BYTE $'r'; BYTE $'e'; BYTE $'b'; BYTE $'o'; + BYTE $'o'; BYTE $'t'; BYTE $'.'; BYTE $'.'; + BYTE $'.'; + BYTE $'\z'; + +/* "MBR..." */ +TEXT confidence(SB), $0 + BYTE $'M'; BYTE $'B'; BYTE $'R'; BYTE $'.'; + BYTE $'.'; BYTE $'.'; + BYTE $'\z'; --- /sys/src/boot/pcipl/mem.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/mem.h Fri Jun 22 20:33:06 2012 @@ -0,0 +1,46 @@ +/* + * Memory and machine-specific definitions. Used in C and assembler. + */ + +/* + * Sizes + */ +#define BI2BY 8 /* bits per byte */ +#define BI2WD 32 /* bits per word */ +#define BY2WD 4 /* bytes per word */ +#define BY2PG 4096 /* bytes per page */ +#define WD2PG (BY2PG/BY2WD) /* words per page */ +#define PGSHIFT 12 /* log(BY2PG) */ +#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1)) + +/* + * Fundamental addresses + */ +#define CONFADDR 0x1200 /* info passed from boot loader */ +#define BIOSXCHG 0x6000 /* To exchange data with the BIOS */ + +#define SELGDT (0<<3) /* selector is in gdt */ +#define SELLDT (1<<3) /* selector is in ldt */ + +#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p)) + +/* + * fields in segment descriptors + */ +#define SEGDATA (0x10<<8) /* data/stack segment */ +#define SEGEXEC (0x18<<8) /* executable segment */ +#define SEGTSS (0x9<<8) /* TSS segment */ +#define SEGCG (0x0C<<8) /* call gate */ +#define SEGIG (0x0E<<8) /* interrupt gate */ +#define SEGTG (0x0F<<8) /* task gate */ +#define SEGTYPE (0x1F<<8) + +#define SEGP (1<<15) /* segment present */ +#define SEGPL(x) ((x)<<13) /* priority level */ +#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */ +#define SEGG (1<<23) /* granularity 1==4k (for other) */ +#define SEGE (1<<10) /* expand down */ +#define SEGW (1<<9) /* writable (for data/stack) */ +#define SEGR (1<<9) /* readable (for code) */ +#define SEGD (1<<22) /* default 1==32bit (for code) */ + --- /sys/src/boot/pcipl/mkfile Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/mkfile Fri Jun 22 20:41:39 2012 @@ -0,0 +1,85 @@ +objtype=386 +>tmp/cfg/plan9.ini + disk/mk9660 -B 386/ipliso -p /sys/lib/sysconfig/proto/allproto -s tmp $target + rm -fr tmp + +test.dsk: iplfat mbr pbs test.iso + rm -fr tmp $target + mkdir tmp + cp test.iso iplfat tmp + mkdir tmp/386 + cp /386/9pcf tmp/386 + echo 'bootfile=/386/9pcf' >tmp/plan9.ini + dd -if /dev/zero -of $target -bs 512 -count 32768 + disk/partfs -m /n/$target $target + disk=/n/$target/sdXX + disk/mbr -m mbr $disk/data + disk/fdisk -baw $disk/data + disk/prep -bw -a 9fat $disk/plan9 + disk/format -b pbs -d -r 2 $disk/9fat + s=$target.dos + m=/n/$target.9fat + rm -f /srv/$s + dossrv -f $disk/9fat $s + mount -c /srv/$s $m + @{cd tmp; tar c .} | @{cd $m; tar xv} + unmount $m + rm -f /srv/$s + unmount /n/$target + rm -fr tmp --- /sys/src/boot/pcipl/pbs.s Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/pbs.s Fri Jun 22 20:33:06 2012 @@ -0,0 +1,288 @@ +#include "x16.h" +#include "mem.h" + +#define RELOC 0x7c00 + +TEXT _magic(SB), $0 + BYTE $0xEB; BYTE $0x58; /* jmp .+ 0x58 (_start0x5A) */ + BYTE $0x90 /* nop */ +TEXT _version(SB), $0 + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 +TEXT _sectsize(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _clustsize(SB), $0 + BYTE $0x00 +TEXT _nresrv(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _nfats(SB), $0 + BYTE $0x00 +TEXT _rootsize(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _volsize(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _mediadesc(SB), $0 + BYTE $0x00 +TEXT _fatsize(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _trksize(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _nheads(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _nhiddenlo(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _nhiddenhi(SB), $0 + BYTE $0x00; BYTE $0x00; +TEXT _bigvolsize(SB), $0 + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; +/* FAT32 structure, starting @0x24 */ +TEXT _fatsz32lo(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _fatsz32hi(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _extflags(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _fsver(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _rootclust(SB), $0 + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 +TEXT _fsinfo(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _bkboot(SB), $0 + BYTE $0x00; BYTE $0x00 +TEXT _reserved0(SB), $0 + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 +TEXT _driveno(SB), $0 + BYTE $0x00 +TEXT _reserved1(SB), $0 + BYTE $0x00 +TEXT _bootsig(SB), $0 + BYTE $0x00 +TEXT _volid(SB), $0 + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; +TEXT _label(SB), $0 + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 + BYTE $0x00; BYTE $0x00; BYTE $0x00 +TEXT _type(SB), $0 + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; + BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 + +_start0x5A: + CLI + CLR(rAX) + MTSR(rAX, rSS) /* 0000 -> rSS */ + MTSR(rAX, rDS) /* 0000 -> rDS, source segment */ + MTSR(rAX, rES) + + LWI(0x100, rCX) + LWI(RELOC, rSI) + MW(rSI, rSP) + LWI(_magic(SB), rDI) + CLD + REP; MOVSL /* MOV DS:[(E)SI] -> ES:[(E)DI] */ + + MW(rSP, rBP) + + PUSHR(rCX) + PUSHI(start16(SB)) + BYTE $0xCB /* FAR RET */ + +TEXT start16(SB), $0 + STI + + LWI(hello(SB), rSI) + CALL16(print16(SB)) + + STB(rDL, _driveno(SB)) + + CLR(rDX) + LW(_fatsize(SB), rAX) + CLR(rCX) + LB(_nfats(SB), rCL) + MUL(rCX) + OR(rAX, rAX) + JNE _fatszok /* zero? it's FAT32 */ + + LW(_fatsz32hi(SB), rBX) + IMUL(rCX, rBX) + LW(_fatsz32lo(SB), rAX) + MUL(rCX) + ADD(rBX, rDX) + +_fatszok: + LW(_nhiddenlo(SB), rCX) + ADD(rCX, rAX) + LW(_nhiddenhi(SB), rCX) + ADC(rCX, rDX) + + CLR(rBX) + LW(_nresrv(SB), rCX) + ADD(rCX, rAX) + ADC(rDX, rBX) + + SW(rAX, _volid(SB)) /* save for later use */ + SW(rBX, _volid+2(SB)) + + PUSHR(rBP) + LW(_sectsize(SB), rCX) + SUB(rCX, rSP) + MW(rSP, rBP) + MW(rSP, rSI) + +_nextsect: + CALL16(readsect16(SB)) + LW(_sectsize(SB), rCX) + SHRI(5, rCX) + +_nextdir: + PUSHR(rCX) + PUSHR(rSI) /* save for later if it matches */ + LWI(bootname(SB), rDI) + LW(bootnamelen(SB), rCX) + CLD + REP + CMPSB + POPR(rSI) + POPR(rCX) + JEQ _found + ADDI(0x20, rSI) + LOOP _nextdir + ADDI(1, rAX) + ADC(rCX, rBX) + JMP _nextsect + +_found: + CLR(rBX) + + LW(_rootsize(SB), rAX) /* calculate and save Xrootsz */ + LWI(0x20, rCX) + MUL(rCX) + LW(_sectsize(SB), rCX) + PUSHR(rCX) + DEC(rCX) + ADD(rCX, rAX) + ADC(rBX, rDX) + POPR(rCX) /* _sectsize(SB) */ + DIV(rCX) + PUSHR(rAX) /* Xrootsz */ + + LXW(0x1a, xSI, rAX) /* starting sector address */ + DEC(rAX) /* that's just the way it is */ + DEC(rAX) + LB(_clustsize(SB), rCL) + CLRB(rCH) + MUL(rCX) + LW(_volid(SB), rCX) /* Xrootlo */ + ADD(rCX, rAX) + LW(_volid+2(SB), rCX) /* Xroothi */ + ADC(rCX, rDX) + POPR(rCX) /* Xrootsz */ + ADD(rCX, rAX) + ADC(rBX, rDX) + + PUSHR(rAX) /* calculate how many sectors to read */ + PUSHR(rDX) + LXW(0x1c, xSI, rAX) + LXW(0x1e, xSI, rDX) + LW(_sectsize(SB), rCX) + PUSHR(rCX) + DEC(rCX) + ADD(rCX, rAX) + ADC(rBX, rDX) + POPR(rCX) /* _sectsize(SB) */ + DIV(rCX) + MW(rAX, rCX) + POPR(rBX) + POPR(rAX) + + LWI(RELOC, rSI) + PUSHR(rSI) /* entry */ + +_loadnext: + CALL16(readsect16(SB)) + + LW(_sectsize(SB), rDX) + ADD(rDX, rSI) + + CLR(rDX) + ADDI(1, rAX) + ADC(rDX, rBX) + + LOOP _loadnext + + LWI(ok(SB), rSI) + CALL16(print16(SB)) + + LB(_driveno(SB), rDL) + CLI + RET + +TEXT print16(SB), $0 + PUSHA + CLR(rBX) +_printnext: + LODSB + ORB(rAL, rAL) + JEQ _printret + LBI(0x0E, rAH) + BIOSCALL(0x10) + JMP _printnext +_printret: + POPA + RET + +/* + * in: + * AX:BX lba32, + * 0000:SI buffer + */ +TEXT readsect16(SB), $0 +_retry: + PUSHA + CLR(rDX) + + PUSHR(rDX) /* qword lba */ + PUSHR(rDX) + PUSHR(rBX) + PUSHR(rAX) + + PUSHR(rDX) /* dword buffer */ + PUSHR(rSI) + + INC(rDX) + PUSHR(rDX) /* word # of sectors */ + + PUSHI(0x0010) /* byte reserved, byte packet size */ + + MW(rSP, rSI) + LB(_driveno(SB), rDL) + LWI(0x4200, rAX) + BIOSCALL(0x13) + JCC _readok + LWI((0x0E00|'!'), rAX) + BIOSCALL(0x10) + ADDI(0x10, rSP) + POPA + JMP _retry +_readok: + LWI((0x0E00|'.'), rAX) + BIOSCALL(0x10) + ADDI(0x10, rSP) + POPA + RET + +TEXT bootnamelen(SB), $0 + WORD $8 +TEXT bootname(SB), $0 + BYTE $'9'; BYTE $'B'; BYTE $'O'; BYTE $'O'; + BYTE $'T'; BYTE $'F'; BYTE $'A'; BYTE $'T'; + BYTE $0 + +TEXT hello(SB), $0 + BYTE $'p'; BYTE $'b'; BYTE $'s'; BYTE $0 +TEXT ok(SB), $0 + BYTE $'o'; BYTE $'k'; BYTE $'\r'; BYTE $'\n'; + BYTE $0 --- /sys/src/boot/pcipl/pxe.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/pxe.c Fri Jun 22 20:33:06 2012 @@ -0,0 +1,359 @@ +#include +#include "fns.h" + +enum { + Tftp_READ = 1, + Tftp_WRITE = 2, + Tftp_DATA = 3, + Tftp_ACK = 4, + Tftp_ERROR = 5, + Tftp_OACK = 6, + + TftpPort = 69, + + Segsize = 512, + Maxpath = 64, +}; + +typedef uchar IP4[4]; + +typedef struct Tftp Tftp; +typedef struct Dhcp Dhcp; + +struct Tftp +{ + IP4 sip; + IP4 dip; + IP4 gip; + + int sport; + int dport; + + char *rp; + char *ep; + + int seq; + int eof; + + char pkt[2+2+Segsize]; + char nul; +}; + +struct Dhcp +{ + uchar opcode; + uchar hardware; + uchar hardlen; + uchar gatehops; + uchar ident[4]; + uchar seconds[2]; + uchar flags[2]; + uchar cip[4]; + uchar yip[4]; + uchar sip[4]; + uchar gip[4]; + uchar mac[16]; + char sname[64]; + char bootfile[128]; +}; + +int pxeinit(void); +int pxecall(int op, void *buf); + +static void* +unfar(ulong seg, ulong off) +{ + return (void*)((off & 0xFFFF) + (seg & 0xFFFF)*16); +} + +static void +puts(void *x, ushort v) +{ + uchar *p = x; + + p[1] = (v>>8) & 0xFF; + p[0] = v & 0xFF; +} + +static ushort +gets(void *x) +{ + uchar *p = x; + + return p[1]<<8 | p[0]; +} + +static void +hnputs(void *x, ushort v) +{ + uchar *p = x; + + p[0] = (v>>8) & 0xFF; + p[1] = v & 0xFF; +} + +static ushort +nhgets(void *x) +{ + uchar *p = x; + + return p[0]<<8 | p[1]; +} + +static void +moveip(IP4 d, IP4 s) +{ + memmove(d, s, sizeof(d)); +} + +void +unload(void) +{ + struct { + uchar status[2]; + uchar junk[10]; + } buf; + uchar *o; + static uchar shutdown[] = { 0x05, 0x070, 0x02, 0 }; + + for(o = shutdown; *o; o++){ + memset(&buf, 0, sizeof(buf)); + if(pxecall(*o, &buf)) + break; + } +} + +static int +getip(IP4 yip, IP4 sip, IP4 gip, char mac[16]) +{ + struct { + uchar status[2]; + uchar pkttype[2]; + uchar bufsize[2]; + uchar off[2]; + uchar seg[2]; + uchar lim[2]; + } buf; + int i, r; + Dhcp *p; + + memset(&buf, 0, sizeof(buf)); + puts(buf.pkttype, 3); + + if(r = pxecall(0x71, &buf)) + return -r; + if((p = unfar(gets(buf.seg), gets(buf.off))) == 0) + return -1; + moveip(yip, p->yip); + moveip(sip, p->sip); + moveip(gip, p->gip); + mac[12] = 0; + for(i=0; i<6; i++){ + mac[i*2] = hex[p->mac[i]>>4]; + mac[i*2+1] = hex[p->mac[i]&15]; + } + return 0; +} + +static int +udpopen(IP4 sip) +{ + struct { + uchar status[2]; + uchar sip[4]; + } buf; + + puts(buf.status, 0); + moveip(buf.sip, sip); + return pxecall(0x30, &buf); +} + +static int +udpclose(void) +{ + uchar status[2]; + + puts(status, 0); + return pxecall(0x31, status); +} + +static int +udpread(IP4 sip, IP4 dip, int *sport, int dport, int *len, void *data) +{ + struct { + uchar status[2]; + uchar sip[4]; + uchar dip[4]; + uchar sport[2]; + uchar dport[2]; + uchar len[2]; + uchar off[2]; + uchar seg[2]; + } buf; + int r; + + puts(buf.status, 0); + moveip(buf.sip, sip); + moveip(buf.dip, dip); + hnputs(buf.sport, *sport); + hnputs(buf.dport, dport); + puts(buf.len, *len); + puts(buf.off, (long)data); + puts(buf.seg, 0); + if(r = pxecall(0x32, &buf)) + return r; + moveip(sip, buf.sip); + *sport = nhgets(buf.sport); + *len = gets(buf.len); + return 0; +} + +static int +udpwrite(IP4 ip, IP4 gw, int sport, int dport, int len, void *data) +{ + struct { + uchar status[2]; + uchar ip[4]; + uchar gw[4]; + uchar sport[2]; + uchar dport[2]; + uchar len[2]; + uchar off[2]; + uchar seg[2]; + } buf; + + puts(buf.status, 0); + moveip(buf.ip, ip); + moveip(buf.gw, gw); + hnputs(buf.sport, sport); + hnputs(buf.dport, dport); + puts(buf.len, len); + puts(buf.off, (long)data); + puts(buf.seg, 0); + return pxecall(0x33, &buf); +} + +int +read(void *f, void *data, int len) +{ + int seq, n; + Tftp *t; + + for(t = f; !t->eof && t->rp >= t->ep; ){ + for(;;){ + n = sizeof(t->pkt); + if(udpread(t->dip, t->sip, &t->dport, t->sport, &n, t->pkt)) + continue; + if(n >= 4) + break; + } + switch(nhgets(t->pkt)){ + case Tftp_DATA: + seq = nhgets(t->pkt+2); + if(seq <= t->seq){ + putc('@'); + continue; + } + hnputs(t->pkt, Tftp_ACK); + while(udpwrite(t->dip, t->gip, t->sport, t->dport, 4, t->pkt)) + putc('!'); + t->seq = seq; + t->rp = t->pkt + 4; + t->ep = t->pkt + n; + t->eof = n < Segsize; + break; + case Tftp_ERROR: + print(t->pkt+4); + print(crnl); + default: + t->eof = 1; + return -1; + } + break; + } + n = t->ep - t->rp; + if(len > n) + len = n; + memmove(data, t->rp, len); + t->rp += len; + return len; +} + +void +close(void *f) +{ + Tftp *t; + + t = f; + t->eof = 1; + udpclose(); +} + + +static int +tftpopen(Tftp *t, char *path, IP4 sip, IP4 dip, IP4 gip) +{ + int r, n; + char *p; + static ushort xport = 6666; + + moveip(t->sip, sip); + moveip(t->gip, gip); + memset(t->dip, 0, sizeof(t->dip)); + t->sport = xport++; + t->dport = 0; + t->rp = t->ep = 0; + t->seq = -1; + t->eof = 0; + t->nul = 0; + if(r = udpopen(t->sip)) + return r; + p = t->pkt; + hnputs(p, Tftp_READ); p += 2; + n = strlen(path)+1; + memmove(p, path, n); p += n; + memmove(p, "octet", 6); p += 6; + n = p - t->pkt; + for(;;){ + if(r = udpwrite(dip, t->gip, t->sport, TftpPort, n, t->pkt)) + break; + if(r = read(t, 0, 0)) + break; + return 0; + } + close(t); + return r; +} + +void +start(void *) +{ + char mac[16], path[Maxpath], *kern; + void *f; + IP4 yip, sip, gip; + Tftp t; + + if(pxeinit()){ + print("pxe init\r\n"); + halt(); + } + if(getip(yip, sip, gip, mac)){ + print("bad dhcp\r\n"); + halt(); + } + memmove(path, "/cfg/pxe/", 9); + memmove(path+9, mac, 13); + if(tftpopen(f = &t, path, yip, sip, gip)){ + print("no config\r\n"); + f = 0; + } + for(;;){ + kern = configure(f, path); f = 0; + if(tftpopen(&t, kern, yip, sip, gip)){ + print("not found\r\n"); + continue; + } + print(bootkern(&t)); + print(crnl); + } +} --- /sys/src/boot/pcipl/sub.c Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/sub.c Fri Jun 22 20:33:06 2012 @@ -0,0 +1,457 @@ +#include +#include +#include "fns.h" +#include "mem.h" + +void +memset(void *dst, int v, int n) +{ + uchar *d; + + d = dst; + while(n > 0){ + *d++ = v; + n--; + } +} + +void +memmove(void *dst, void *src, int n) +{ + uchar *d, *s; + + d = dst; + s = src; + if(d < s){ + while(n-- > 0) + *d++ = *s++; + } else if(d > s){ + s += n; + d += n; + while(n-- > 0) + *--d = *--s; + } +} + +int +memcmp(void *src, void *dst, int n) +{ + uchar *d, *s; + int r; + + d = dst; + s = src; + while(n-- > 0) + if(r = (*d++ - *s++)) + return r; + return 0; +} + +int +strlen(char *s) +{ + char *p; + + for(p = s; *p; p++) + ; + return p - s; +} + +char* +strchr(char *s, int c) +{ + for(; *s; s++) + if(*s == c) + return s; + return 0; +} + +char* +strrchr(char *s, int c) +{ + char *r = 0; + + while(s = strchr(s, c)) + r = s++; + + return r; +} + +/* 115200 8ns1 */ +extern void outb(int, int); + +void +uartinit(void) +{ + outb(0x3f8 + 3, 0x80 | 7); + outb(0x3f8 + 0, 1); + outb(0x3f8 + 1, 0); + outb(0x3f8 + 3, 7); +} + +void +uartputc(int c) +{ + int i; + static int once; + + if(once == 0){ + // uartinit(); + once = 1; + } + outb(0x3f8 + 0, c); + for(i = 0; i < 10*26042; i++) + ; +} + +void +putc(int c) +{ + cgaputc(c); + uartputc(c); +} + +void +print(char *s) +{ + while(*s){ + if(*s == '\r' && s[1] == '\n') + s++; + if(*s == '\n') + putc('\r'); + putc(*s++); + } +} + +int +readn(void *f, void *data, int len) +{ + uchar *p, *e; + + p = data; + e = p + len; + while(p < e){ + if((len = read(f, p, e - p)) <= 0) + break; + p += len; + } + + return p - (uchar*)data; +} + +static int +readline(void *f, char buf[64]) +{ + char *p; + static char white[] = "\t "; + + p = buf; + do{ + if(!f) + putc('>'); + while(p < buf + 64-1){ + if(!f){ + putc(*p = getc()); + if(*p == '\r') + putc('\n'); + else if(*p == '\b' && p > buf){ + p--; + continue; + } + }else if(read(f, p, 1) <= 0) + return 0; + if(p == buf && strchr(white, *p)) + continue; + if(strchr(crnl, *p)) + break; + p++; + } + while(p > buf && strchr(white, p[-1])) + p--; + }while(p == buf); + *p = 0; + + return p - buf; +} + +static int +timeout(int ms) +{ + while(ms > 0){ + if(gotc()) + return 1; + usleep(100000); + ms -= 100; + } + return 0; +} + +#define BOOTLINE ((char*)CONFADDR) +#define BOOTLINELEN 64 +#define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN)) +#define BOOTARGSLEN (4096-0x200-BOOTLINELEN) + +char *confend; + +static void e820conf(void); + +static int +delconf(char *s) +{ + char *p, *e; + + for(p = BOOTARGS; p < confend; p = e){ + for(e = p+1; e < confend; e++){ + if(*e == '\n'){ + e++; + break; + } + } + if(!memcmp(p, s, strlen(s))){ + memmove(p, e, confend - e); + confend -= e - p; + *confend = 0; + return 1; + } + } + return 0; +} + +char* +configure(void *f, char *path) +{ + char line[64], *kern, *s, *p; + int inblock, nowait, n; + +Clear: + kern = 0; + nowait = 1; + inblock = 0; + + memset(BOOTLINE, 0, BOOTLINELEN); + + confend = BOOTARGS; + memset(confend, 0, BOOTARGSLEN); + + e820conf(); +Loop: + while(readline(f, line) > 0){ + if(*line == 0 || strchr("#;=", *line)) + continue; + if(*line == '['){ + inblock = memcmp("[common]", line, 8); + continue; + } + if(!memcmp("boot", line, 5)){ + nowait = 1; + break; + } + if(!memcmp("wait", line, 5)){ + nowait = 0; + continue; + } + if(!memcmp("clear", line, 5)){ + if(line[5] == 0){ + print("ok\n"); + goto Clear; + } else if(line[5] == ' ' && delconf(line+6)){ + print("ok\n"); + } + continue; + } + if(inblock || (p = strchr(line, '=')) == nil) + continue; + *p++ = 0; + delconf(line); + if(!memcmp("bootfile", line, 8)) + memmove(kern = path, p, strlen(p)+1); + + s = confend; + memmove(confend, line, n = strlen(line)); confend += n; + *confend++ = '='; + memmove(confend, p, n = strlen(p)); confend += n; + *confend = 0; + + print(s); print("\n"); + + *confend++ = '\n'; + *confend = 0; + } + + if(f){ + close(f); + f = 0; + + if(kern && (nowait==0 || timeout(1000))) + goto Loop; + } + + if(!kern){ + print("no bootfile\r\n"); + goto Loop; + } + if(p = strrchr(kern, '!')) + kern = p+1; + + return kern; +} + +static void +confappend(char *s, int n) +{ + memmove(confend, s, n); + confend += n; + *confend = 0; +} + +static void +vaddconf(uvlong v, uint base) +{ + char *p, *e, buf[24]; + + p = e = buf + sizeof buf - 1; + for(; v; v >>= 4) // v /= base) can't use this due to _vasop missing. + *p-- = hex[(uint)v%base]; + if(p == e) + *p-- = '0'; + switch(base){ + case 16: + confappend("0x", 2); + break; + } + confappend(p + 1, e - p); + confappend(" ", 1); +} + +uint e820(uint bx, void *p); + +static void +e820conf(void) +{ + char *s; + uint bx; + struct { + uvlong base; + uvlong len; + uint type; + uint ext; + } e; + + /* *e820 */ + s = confend; + confappend("*e820=", 6); + bx = 0; + do{ + bx = e820(bx, &e); + vaddconf(e.type, 10); + vaddconf(e.base, 16); + vaddconf(e.base+e.len, 16); + } while(bx); + + *confend = 0; + print(s); print("\n"); + + *confend++ = '\n'; + *confend = 0; +} + +static uvlong border = 0x0001020304050607ull; +uvlong +_getbe(uchar *t, int w) +{ + uint i; + uvlong r; + + r = 0; + for(i = 0; i < w; i++) + r = r<<8 | t[i]; + return r; +} + +uvlong +getbe(void *t, int w) +{ + return _getbe(t, w); +} + +char* +warp32(Exec ex, void *f) +{ + uchar *e, *d, *t; + ulong n; + + e = (uchar*)(getbe(&ex.entry, 4) & ~0xF0000000UL); + t = e; + n = getbe(&ex.text, 4); + + if(readn(f, t, n) != n) + goto Error; + d = (uchar*)PGROUND((ulong)t + n); + n = getbe(&ex.data, 4); + + if(readn(f, d, n) != n) + goto Error; + close(f); + unload(); + + print("warp32\n"); + + jump(e); + +Error: + return "i/o error"; +} + +char* +warp64(Exec ex, void *f) +{ + uchar *e, *d, *b, *t, ulv[8]; + ulong n; + + if(readn(f, ulv, 8) != 8) + return "bad header"; + e = (uchar*)(getbe(&ex.entry, 4) & ~0xF0000000UL); + t = e; + n = getbe(&ex.text, 4); + if(readn(f, t, n) != n) + goto Error; + + d = (uchar*)PGROUND((uint)(t + n)); + n = getbe(&ex.data, 4); + if(readn(f, d, n) != n) + goto Error; + + b = (uchar*)PGROUND((uint)(d + n)); + n = getbe(&ex.bss, 4); + memset(b, 0, n); + + close(f); + unload(); + + print("warp64\n"); + jump(e); + +Error: + return "i/o error"; +} + +char* +bootkern(void *f) +{ + Exec ex; + extern void a20(void); + + a20(); + + if(readn(f, &ex, sizeof(ex)) != sizeof(ex)) + return "bad header"; + + switch(getbe(&ex.magic, 4)){ + case I_MAGIC: + return warp32(ex, f); + case S_MAGIC: + return warp64(ex, f); + default: + return "bad magic"; + } +} --- /sys/src/boot/pcipl/x16.h Thu Jan 1 00:00:00 1970 +++ /sys/src/boot/pcipl/x16.h Fri Jun 22 20:33:06 2012 @@ -0,0 +1,162 @@ +/* + * Can't write 16-bit code for 8a without getting into + * lots of bother, so define some simple commands and + * output the code directly. + * + * N.B. CALL16(x) kills DI, so don't expect it to be + * saved across calls. + */ +#define rAX 0 /* rX */ +#define rCX 1 +#define rDX 2 +#define rBX 3 +#define rSP 4 /* SP */ +#define rBP 5 /* BP */ +#define rSI 6 /* SI */ +#define rDI 7 /* DI */ + +#define rAL 0 /* rL */ +#define rCL 1 +#define rDL 2 +#define rBL 3 +#define rAH 4 /* rH */ +#define rCH 5 +#define rDH 6 +#define rBH 7 + +#define rES 0 /* rS */ +#define rCS 1 +#define rSS 2 +#define rDS 3 +#define rFS 4 +#define rGS 5 + +#define xSI 4 /* rI (index) */ +#define xDI 5 +#define xBP 6 +#define xBX 7 + +#define rCR0 0 /* rC */ +#define rCR2 2 +#define rCR3 3 +#define rCR4 4 + +#define OP(o, m, ro, rm) BYTE $o; /* op + modr/m byte */ \ + BYTE $(((m)<<6)|((ro)<<3)|(rm)) +#define OPrm(o, r, m) OP(o, 0x00, r, 0x06); /* general r <-> m */ \ + WORD $m; +#define OPrr(o, r0, r1) OP(o, 0x03, r0, r1); /* general r -> r */ + +#define LW(m, rX) OPrm(0x8B, rX, m) /* m -> rX */ +#define LXW(x, rI, r) OP(0x8B, 0x02, r, rI); /* x(rI) -> r */ \ + WORD $x +#define LBPW(x, r) OP(0x8B, 0x02, r, xBP); /* x(rBP) -> r */ \ + WORD $x +#define LB(m, rB) OPrm(0x8A, rB, m) /* m -> r[HL] */ +#define LXB(x, rI, r) OP(0x8A, 0x01, r, rI); /* x(rI) -> r */ \ + BYTE $x +#define LBPB(x, r) OP(0x8A, 0x01, r, xBP); /* x(rBP) -> r */ \ + BYTE $x +#define SW(rX, m) OPrm(0x89, rX, m) /* rX -> m */ +#define SXW(r, x, rI) OP(0x89, 0x02, r, rI); /* r -> x(rI) */ \ + WORD $x +#define SBPW(r, x) OP(0x89, 0x02, r, xBP); /* r -> x(rBP) */ \ + WORD $(x) +#define SBPWI(i, x) OP(0xC7, 0x01, 0, xBP); /* i -> x(rBP) */ \ + BYTE $(x); WORD $(i) +#define STB(rB, m) OPrm(0x88, rB, m) /* rB -> m */ +#define SXB(r, x, rI) OP(0x88, 0x01, r, rI); /* rB -> x(rI) */ \ + BYTE $x +#define SBPB(r, x) OP(0x88, 0x01, r, xBP); /* r -> x(rBP) */ \ + BYTE $x +#define SBPBI(i, x) OP(0xC6, 0x01, 0, xBP); /* i -> x(rBP) */ \ + BYTE $(x); BYTE $(i) +#define LWI(i, rX) BYTE $(0xB8+rX); /* i -> rX */ \ + WORD $i; +#define LBI(i, rB) BYTE $(0xB0+rB); /* i -> r[HL] */ \ + BYTE $i + +#define MW(r0, r1) OPrr(0x89, r0, r1) /* r0 -> r1 */ +#define MFSR(rS, rX) OPrr(0x8C, rS, rX) /* rS -> rX */ +#define MTSR(rX, rS) OPrr(0x8E, rS, rX) /* rX -> rS */ +#define MFCR(rC, rX) BYTE $0x0F; /* rC -> rX */ \ + OP(0x20, 0x03, rC, rX) +#define MTCR(rX, rC) BYTE $0x0F; /* rX -> rC */ \ + OP(0x22, 0x03, rC, rX) + +#define ADC(r0, r1) OPrr(0x11, r0, r1) /* r0 + r1 -> r1 */ +#define ADD(r0, r1) OPrr(0x01, r0, r1) /* r0 + r1 -> r1 */ +#define ADDI(i, r) OP(0x81, 0x03, 0x00, r);/* i+r -> r */ \ + WORD $i; +#define AND(r0, r1) OPrr(0x21, r0, r1) /* r0&r1 -> r1 */ +#define ANDI(i, r) OP(0x81, 0x03, 0x04, r);/* i&r -> r */ \ + WORD $i; +#define CLR(r) OPrr(0x31, r, r) /* r^r -> r */ +#define CLRB(r) OPrr(0x30, r, r) /* r^r -> r */ +#define CMP(r0, r1) OPrr(0x39, r0, r1) /* r1-r0 -> flags */ +#define CMPI(i, r) OP(0x81, 0x03, 0x07, r);/* r-i -> flags */ \ + WORD $i; +#define CMPBR(r0, r1) OPrr(0x38, r0, r1) /* r1-r0 -> flags */ +#define DEC(r) BYTE $(0x48|r) /* r-1 -> r */ +#define DIV(r) OPrr(0xF7, 0x06, r) /* rDX:rAX/r -> rAX, rDX:rAX%r -> rDX */ +#define INC(r) BYTE $(0x40|r) /* r+1 -> r */ +#define MUL(r) OPrr(0xF7, 0x04, r) /* r*rAX -> rDX:rAX */ +#define IMUL(r0, r1) BYTE $0x0F; /* r0*r1 -> r1 */ \ + OPrr(0xAF, r1, r0) /* (signed) */ +#define OR(r0, r1) OPrr(0x09, r0, r1) /* r0|r1 -> r1 */ +#define ORB(r0, r1) OPrr(0x08, r0, r1) /* r0|r1 -> r1 */ +#define ORI(i, r) OP(0x81, 0x03, 0x01, r);/* i|r -> r */ \ + WORD $i; +#define ROLI(i, r) OPrr(0xC1, 0x00, r); /* r<<>>i -> r */ \ + BYTE $i; +#define SHLI(i, r) OPrr(0xC1, 0x04, r); /* r< r */ \ + BYTE $i; +#define SHLBI(i, r) OPrr(0xC0, 0x04, r); /* r< r */ \ + BYTE $i; +#define SHRI(i, r) OPrr(0xC1, 0x05, r); /* r>>i -> r */ \ + BYTE $i; +#define SHRBI(i, r) OPrr(0xC0, 0x05, r); /* r>>i -> r */ \ + BYTE $i; +#define SUB(r0, r1) OPrr(0x29, r0, r1) /* r1-r0 -> r1 */ +#define SUBI(i, r) OP(0x81, 0x03, 0x05, r);/* r-i -> r */ \ + WORD $i; + +#define STOSW STOSL + +#define CALL16(f) LWI(f, rDI); /* &f -> rDI */ \ + BYTE $0xFF; /* (*rDI) */ \ + BYTE $0xD7; +#define FARJUMP16(s, o) BYTE $0xEA; /* jump to ptr16:16 */ \ + WORD $o; WORD $s +#define FARJUMP32(s, o) BYTE $0x66; /* jump to ptr32:16 */ \ + BYTE $0xEA; LONG $o; WORD $s +#define DELAY BYTE $0xEB; /* jmp .+2 */ \ + BYTE $0x00 +#define BIOSCALL(b) INT $b /* INT $b */ + +#define PEEKW BYTE $0x26; /* MOVW rES:[rBX], rAX */ \ + BYTE $0x8B; BYTE $0x07 +#define POKEW BYTE $0x26; /* MOVW rAX, rES:[rBX] */ \ + BYTE $0x89; BYTE $0x07 +#define OUTPORTB(p, d) LBI(d, rAL); /* d -> I/O port p */ \ + BYTE $0xE6; \ + BYTE $p; DELAY +#define PUSHA BYTE $0x60 +#define PUSHR(r) BYTE $(0x50|r) /* r -> (--rSP) */ +#define PUSHS(rS) BYTE $(0x06|((rS)<<3)) /* rS -> (--rSP) */ +#define PUSHI(i) BYTE $0x68; WORD $i; /* i -> --(rSP) */ +#define POPA BYTE $0x61 +#define POPR(r) BYTE $(0x58|r) /* (rSP++) -> r */ +#define POPS(rS) BYTE $(0x07|((rS)<<3)) /* (rSP++) -> r */ +#define NOP BYTE $0x90 /* nop */ + +#define LGDT(gdtptr) BYTE $0x0F; /* LGDT */ \ + BYTE $0x01; BYTE $0x16; \ + WORD $gdtptr +#define LIDT(idtptr) BYTE $0x0F; /* LIDT */ \ + BYTE $0x01; BYTE $0x1e; \ + WORD $idtptr + +/* operand size switch. */ +#define OPSIZE BYTE $0x66 +#define ADSIZE BYTE $0x67