#include #include #include #include "8i.h" #define WORD(p) ((p)[0] | ((p)[1]<<8)) #define LONG(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24)) #define PWORD(p, v) (p)[0] = (v); (p)[1] = (v)>>8 #define PLONG(p, v) (p)[0] = (v); (p)[1] = (v)>>8; (p)[2] = (v)>>16; (p)[3] = (v)>>24 typedef struct Vbe Vbe; struct Vbe { ushort rax; ushort rbx; ushort rcx; ushort rdx; uchar buf[1024]; }; int nflag; uchar *ivec; Cpu cpu; typedef struct Flag Flag; struct Flag { int bit; char *desc; }; void printflags(char *s, Flag *f, int b) { int i; print("%s", s); for(i=0; f[i].bit; i++) if(f[i].bit & b) print(" %s", f[i].desc); print("\n"); } void vbetrap(Cpu *cpu, Inst *inst, int t) { uchar *m; ushort cs, pc; fprint(2, "vbetrap 0x%x\n", t); if(t == 0x20) longjmp(cpu->exitjmp, 1); if(t <= 0xFF){ m = &cpu->mem[4*t]; cs = WORD(m+2); pc = WORD(m+0); print("trap %d cs %x pc %x\n", t, cs, pc); if(cs != 0 || pc != 0){ if(cs&0xFFF){ print("tried mem+0x%x %x:%x\n", 4*t, cs, pc); abort(); } push(cpu, 16, cpu->flags); push(cpu, 16, cpu->reg[RCS]); push(cpu, 16, cpu->npc); cpu->ncs = cs; cpu->npc = pc; longjmp(cpu->jmp, 1); } } dumpreg(cpu); print("%.5P %I\n", cpu, inst); print("unknown trap %d\n", t); abort(); } int vbecall(Vbe *vbe) { uchar *buf; uchar *sp; /* * the first 64k of memory is the stack segment * and also the place we return to. */ sp = cpu.mem+0x10000; *--sp = 0x20; /* INT 20: exit */ *--sp = 0xCD; *--sp = 0x00; /* ret segment */ *--sp = 0x00; *--sp = 0xFF; /* ret offset */ *--sp = 0xFE; cpu.reg[RSP] = sp - cpu.mem; cpu.reg[RAX] = vbe->rax; cpu.reg[RBX] = vbe->rbx; cpu.reg[RCX] = vbe->rcx; cpu.reg[RDX] = vbe->rdx; /* * the second 64k of memory holds our buffer. */ buf = cpu.mem+0x10000; cpu.reg[RES] = 0x1000; cpu.reg[RDI] = 0x0000; cpu.reg[RCS] = WORD(ivec+0x10*4+2); cpu.pc = WORD(ivec+0x10*4); memmove(buf, vbe->buf, sizeof(vbe->buf)); run(&cpu); memmove(vbe->buf, buf, sizeof(vbe->buf)); vbe->rax = cpu.reg[RAX]; vbe->rbx = cpu.reg[RBX]; vbe->rcx = cpu.reg[RCX]; vbe->rdx = cpu.reg[RDX]; if(vbe->rax&0xFF00) return -1; return 0; } void interrupt(void *a, char *msg) { USED(a); if(strcmp(msg, "interrupt") == 0) { print("INTERRUPT -- inst count = %d\n", cpu.instcount); dumpreg(&cpu); exits(msg); } noted(NDFLT); } void usage(void) { fprint(2, "usage: vbe [-t]\n"); exits("usage"); } void cmdtrace(int, char**) { cpu.trace = !cpu.trace; print("trace %s\n", cpu.trace ? "on" : "off"); } void* unfarptr(uchar *m) { int seg, off; seg = (m[2]<<4)|(m[3]<<12); off = m[0]|(m[1]<<8); if(seg == 0 && off == 0) return nil; return (char*)cpu.mem+seg+off; } void videomodes(uchar *m) { print("\t"); while(m[0] != 0xFF || m[1] != 0xFF) { print("%.4ux ", WORD(m)); m += 2; } print("\n"); } Flag capabilityflag[] = { 0x01, "8-bit-dac", 0x02, "not-vga", 0x04, "ramdac-needs-blank", 0x08, "stereoscopic", 0x10, "stereo-evc", 0 }; void cmdinfo(int, char**) { uchar *p; Vbe vbe; memset(&vbe, 0, sizeof vbe); p = vbe.buf; strcpy((char*)p, "VBE2"); vbe.rax = 0x4F00; if(vbecall(&vbe) < 0){ fprint(2, "vbe error %.4ux\n", vbe.rax); return; } print("signature: %.4s\n", (char*)p); print("version: %d.%d\n", p[5], p[4]); if(p[5] < 2) return; print("oem string: %s\n", unfarptr(p+6)); printflags("capabilities:", capabilityflag, p[10]); print("video modes:\n"); videomodes(unfarptr(p+14)); print("total memory: %lud\n", WORD(p+18)*0x10000UL); print("oem software rev: %d.%d\n", p[21], p[20]); print("vendor name: %s\n", unfarptr(p+22)); print("product name: %s\n", unfarptr(p+26)); print("product rev: %s\n", unfarptr(p+30)); } Flag modeattributesflags[] = { 1<<0, "supported", 1<<2, "tty", 1<<3, "color", 1<<4, "graphics", 1<<5, "not-vga", 1<<6, "no-windowed-vga", 1<<7, "linear", 1<<8, "double-scan", 1<<9, "interlace", 1<<10, "triple-buffer", 1<<11, "stereoscopic", 1<<12, "dual-start-addr", 0 }; Flag winattributesflags[] = { 1<<0, "relocatable", 1<<1, "readable", 1<<2, "writeable", 0 }; Flag directcolorflags[] = { 1<<0, "programmable-color-ramp", 1<<1, "x-usable", 0 }; char *modelstr[] = { "text", "cga", "hercules", "planar", "packed", "non-chain4", "direct", "YUV" }; void cmdmodeinfo(int argc, char **argv) { int i; uchar *p; Vbe vbe; if(argc != 2){ fprint(2, "?usage: modeinfo 0xMODE\n"); return; } memset(&vbe, 0, sizeof vbe); p = vbe.buf; vbe.rax = 0x4F01; vbe.rcx = atoi(argv[1]); if(vbecall(&vbe) < 0){ fprint(2, "vbe error %.4ux\n", vbe.rax); return; } for(i=0; i<18; i++) print("%2.2ux ", p[i]); print("\n"); for(; i<31; i++) print("%2.2ux ", p[i]); print("\n"); for(; i<40; i++) print("%2.2ux ", p[i]); print("\n"); for(; i<50; i++) print("%2.2ux ", p[i]); print("\n"); printflags("mode attributes:", modeattributesflags, WORD(p)); print("bytes per scan line: %d\n", WORD(p+16)); print("resolution: %dx%d\n", WORD(p+18), WORD(p+20)); print("charsize: %dx%d\n", p[22], p[23]); print("%d planes, %d bpp, %d banks @ %d kb each\n", p[24], p[25], p[26], p[28]); print("memory model %d (%s)\n", p[27], p[27] < nelem(modelstr) ? modelstr[p[27]] : "unknown"); print("r%dg%db%dx%d r@%d g@%d b@%d x@%d\n", p[31], p[33], p[35], p[37], p[32], p[34], p[36], p[38]); printflags("directcolor:", directcolorflags, p[39]); print("physptr: 0x%uX\n", LONG(p+40)); } void cmdsetmode(int argc, char **argv) { int n; uchar *p; Vbe vbe; if(argc != 2 && argc != 2+9){ fprint(2, "?usage: setmode 0xMODE\n"); return; } memset(&vbe, 0, sizeof vbe); vbe.rax = 0x4F02; vbe.rcx = atoi(argv[1]); vbe.rcx |= 3<<14; // use linear, don't clear memory p = vbe.buf; if(argc == 2+9){ vbe.rcx |= 1<<11; n = atoi(argv[2]); PWORD(p, n); p+=2; n = atoi(argv[3]); PWORD(p, n); p+=2; n = atoi(argv[4]); PWORD(p, n); p+=2; n = atoi(argv[5]); PWORD(p, n); p+=2; n = atoi(argv[6]); PWORD(p, n); p+=2; n = atoi(argv[7]); PWORD(p, n); p+=2; *p++ = atoi(argv[8]); n = atoi(argv[9]); PLONG(p, n); p += 4; n = atoi(argv[10]); PWORD(p, n); p += 2; if(p != vbe.buf+19){ fprint(2, "prog error\n"); return; } } if(vbecall(&vbe) < 0){ fprint(2, "vbe error %.4ux\n", vbe.rax); return; } } void cmdgetmode(int argc, char**) { Vbe vbe; if(argc != 1){ fprint(2, "?usage: getmode\n"); return; } memset(&vbe, 0, sizeof vbe); vbe.rax = 0x4F03; if(vbecall(&vbe) < 0){ fprint(2, "vbe error %.4ux\n", vbe.rax); return; } print("mode %x%s%s\n", vbe.rbx&0x3FFF, (vbe.rbx&(1<<14)) ? " linear" : " windowed", (vbe.rbx&(1<<15)) ? " notcleared" : " cleared"); } struct { char *s; void (*fn)(int, char**); } cmd[] = { "trace", cmdtrace, "info", cmdinfo, "modeinfo", cmdmodeinfo, "getmode", cmdgetmode, "setmode", cmdsetmode, }; #define LOWMEM ((uchar*)(0x50000000)) enum { MEMSIZE = (0xFFFF<<4)+0xFFFF+1, VECSIZE = 0x400, }; static int iobfd=-1, iowfd=-1, iolfd=-1; static int devopen(char* device, int mode) { int fd; if((fd = open(device, mode)) < 0) sysfatal("devopen(%s, %d): %r\n", device, mode); return fd; } int inportb(int port) { uchar data; if(iobfd == -1) iobfd = devopen("#P/iob", ORDWR); seek(iobfd, port, 0); if(read(iobfd, &data, sizeof(data)) != sizeof(data)) sysfatal("inportb(0x%4.4x): %r\n", port); return data; } void outportb(int port, int d) { uchar data; if(iobfd == -1) iobfd = devopen("#P/iob", ORDWR); data = d; seek(iobfd, port, 0); if(write(iobfd, &data, sizeof(data)) != sizeof(data)) sysfatal("outportb(0x%4.4x, 0x%2.2X): %r\n", port, data); } int inportw(int port) { uchar data[2]; if(iowfd == -1) iowfd = devopen("#P/iow", ORDWR); seek(iowfd, port, 0); if(read(iowfd, data, sizeof(data)) != sizeof(data)) sysfatal("inportw(0x%4.4x): %r\n", port); return data[0]|(data[1]<<8); } void outportw(int port, int d) { uchar data[2]; if(iowfd == -1) iowfd = devopen("#P/iow", ORDWR); data[0] = d; data[1] = d>>8; seek(iowfd, port, 0); if(write(iowfd, data, sizeof(data)) != sizeof(data)) sysfatal("outportw(0x%4.4x, 0x%4.4uX): %r\n", port, d); } long inportl(int port) { uchar data[4]; if(iolfd == -1) iolfd = devopen("#P/iol", ORDWR); seek(iolfd, port, 0); if(read(iolfd, data, sizeof(data)) != sizeof(data)) sysfatal("inportl(0x%4.4x): %r\n", port); return data[0]|(data[1]<<8)|(data[2]<<16)|(data[3]<<24); } void outportl(int port, long d) { uchar data[4]; if(iolfd == -1) iolfd = devopen("#P/iol", ORDWR); data[0] = d; data[1] = d>>8; data[2] = d>>16; data[3] = d>>24; seek(iolfd, port, 0); if(write(iolfd, data, sizeof(data)) != sizeof(data)) sysfatal("outportl(0x%4.4x, 0x%8.8lX): %r\n", port, d); } void main(int argc, char **argv) { char buf[40], *p, *f[10]; int fd, i, nf; Biobuf bin; ARGBEGIN{ case 't': cpu.trace = 1; break; default: usage(); }ARGEND if(argc != 0) usage(); if(segattach(0, "memory", LOWMEM, MEMSIZE) < 0) sysfatal("segattach: low memory: %r"); cpu.mem = LOWMEM; sprint(buf, "/proc/%d/mem", getpid()); if((fd = open(buf, OREAD)) < 0) sysfatal("cannot open %s: %r", buf); if(seek(fd, 0x80000000U+0xC0000, 0) < 0 || readn(fd, cpu.mem+0xC0000, 0x10000) != 0x10000) sysfatal("cannot read bios memory: %r"); if(seek(fd, 0x80000000U+0xF0000, 0) < 0 || readn(fd, cpu.mem+0xF0000, 0x10000) != 0x10000) sysfatal("cannot read bios memory: %r"); if(seek(fd, 0x80000000U+0, 0) < 0 || readn(fd, cpu.mem+0, 0x10000) != 0x10000) sysfatal("cannot read bios memory: %r"); ivec = cpu.mem; cpu.present64k = (1<<0) | (1<<1) | (1<<0xC) | (1<<0xF); notify(interrupt); cpu.trap = vbetrap; cpu.inb = inportb; cpu.inw = inportw; cpu.inl = inportl; cpu.outb = outportb; cpu.outw = outportw; cpu.outl = outportl; Binit(&bin, 0, OREAD); while((p = Brdline(&bin, '\n')) != nil){ p[Blinelen(&bin)-1] = '\0'; nf = tokenize(p, f, nelem(f)); if(nf == 0) continue; for(i=0; i