#include <u.h>
#include <libc.h>
#include <bio.h>
#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<nelem(cmd); i++){
if(strcmp(f[0], cmd[i].s) == 0){
cmd[i].fn(nf, f);
break;
}
}
if(i==nelem(cmd))
fprint(2, "?\n");
}
}
|