vmx(1): linux kernel loading; PIT fixes to support linux; support VGA 0x3D4 word writes; support sending virtio ethernet packets to a file and prepending snoopy headers
This commit is contained in:
parent
ed040d676a
commit
2806a34ec0
6 changed files with 370 additions and 40 deletions
|
@ -14,6 +14,13 @@ struct ExitInfo {
|
|||
u32int ilen, iinfo;
|
||||
};
|
||||
|
||||
static char *x86reg[16] = {
|
||||
RAX, RCX, RDX, RBX,
|
||||
RSP, RBP, RSI, RDI,
|
||||
R8, R9, R10, R11,
|
||||
R12, R13, R14, R15
|
||||
};
|
||||
|
||||
static void
|
||||
skipinstr(ExitInfo *ei)
|
||||
{
|
||||
|
@ -242,7 +249,7 @@ cpuid(ExitInfo *ei)
|
|||
break;
|
||||
case 2: goto literal; /* cache stuff */
|
||||
case 3: goto zero; /* processor serial number */
|
||||
case 4: goto literal; /* cache stuff */
|
||||
case 4: goto zero; /* cache stuff */
|
||||
case 5: goto zero; /* monitor/mwait */
|
||||
case 6: goto zero; /* thermal management */
|
||||
case 7: goto zero; /* more features */
|
||||
|
@ -305,6 +312,7 @@ rdwrmsr(ExitInfo *ei)
|
|||
if(rd) val = rget("efer");
|
||||
else rset("efer", val);
|
||||
break;
|
||||
case 0x8B: val = 0; break; /* microcode update */
|
||||
default:
|
||||
if(rd){
|
||||
vmerror("read from unknown MSR %#ux ignored", cx);
|
||||
|
@ -323,12 +331,6 @@ rdwrmsr(ExitInfo *ei)
|
|||
static void
|
||||
movdr(ExitInfo *ei)
|
||||
{
|
||||
static char *reg[16] = {
|
||||
RAX, RCX, RDX, RBX,
|
||||
RSP, RBP, RSI, RDI,
|
||||
R8, R9, R10, R11,
|
||||
R12, R13, R14, R15
|
||||
};
|
||||
static char *dr[8] = { "dr0", "dr1", "dr2", "dr3", nil, nil, "dr6", "dr7" };
|
||||
int q;
|
||||
|
||||
|
@ -338,12 +340,64 @@ movdr(ExitInfo *ei)
|
|||
return;
|
||||
}
|
||||
if((q & 16) != 0)
|
||||
rset(reg[q >> 8 & 15], rget(dr[q & 7]));
|
||||
rset(x86reg[q >> 8 & 15], rget(dr[q & 7]));
|
||||
else
|
||||
rset(dr[q & 7], rget(reg[q >> 8 & 15]));
|
||||
rset(dr[q & 7], rget(x86reg[q >> 8 & 15]));
|
||||
skipinstr(ei);
|
||||
}
|
||||
|
||||
static void
|
||||
movcr(ExitInfo *ei)
|
||||
{
|
||||
u32int q;
|
||||
|
||||
q = ei->qual;
|
||||
switch(q & 15){
|
||||
case 0:
|
||||
switch(q >> 4 & 3){
|
||||
case 0:
|
||||
vmdebug("illegal CR0 write, value %#ux", rget(x86reg[q >> 8 & 15]));
|
||||
rset("cr0real", rget(x86reg[q >> 8 & 15]));
|
||||
skipinstr(ei);
|
||||
break;
|
||||
case 1:
|
||||
vmerror("shouldn't happen: trap on MOV from CR0");
|
||||
rset(x86reg[q >> 8 & 15], rget("cr0fake"));
|
||||
skipinstr(ei);
|
||||
break;
|
||||
case 2:
|
||||
vmerror("shouldn't happen: trap on CLTS");
|
||||
rset("cr0real", rget("cr0real") & ~8);
|
||||
skipinstr(ei);
|
||||
break;
|
||||
case 3:
|
||||
vmerror("LMSW handler unimplemented");
|
||||
postexc("#ud", NOERRC);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch(ei->qual >> 4 & 3){
|
||||
case 0:
|
||||
vmdebug("illegal CR4 write, value %#ux", rget(x86reg[q >> 8 & 15]));
|
||||
rset("cr4real", rget(x86reg[q >> 8 & 15]));
|
||||
skipinstr(ei);
|
||||
break;
|
||||
case 1:
|
||||
vmerror("shouldn't happen: trap on MOV from CR4");
|
||||
rset(x86reg[q >> 8 & 15], rget("cr3fake"));
|
||||
skipinstr(ei);
|
||||
break;
|
||||
default:
|
||||
vmerror("unknown CR4 operation %d", q);
|
||||
postexc("#ud", NOERRC);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vmerror("access to unknown control register CR%d", ei->qual & 15);
|
||||
postexc("#ud", NOERRC);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dbgexc(ExitInfo *ei)
|
||||
{
|
||||
|
@ -380,6 +434,7 @@ static ExitType etypes[] = {
|
|||
{".wrmsr", rdwrmsr},
|
||||
{".movdr", movdr},
|
||||
{"#db", dbgexc},
|
||||
{"movcr", movcr},
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
@ -363,6 +363,7 @@ picio(int isin, u16int port, u32int val, int sz, void *)
|
|||
p->init = 4;
|
||||
picupdate(p);
|
||||
return 0;
|
||||
case 0:
|
||||
case 4:
|
||||
p->imr = val;
|
||||
picupdate(p);
|
||||
|
@ -412,10 +413,12 @@ struct PITChannel {
|
|||
enum { READLO, READHI, READLATLO, READLATHI } readstate;
|
||||
u8int writestate;
|
||||
vlong lastnsec;
|
||||
u8int output;
|
||||
};
|
||||
PITChannel pit[3] = {
|
||||
[0] { .state 1 },
|
||||
};
|
||||
u8int port61;
|
||||
enum { PERIOD = 838 };
|
||||
|
||||
void
|
||||
|
@ -437,6 +440,18 @@ settimer(vlong targ)
|
|||
threadint(timerid);
|
||||
}
|
||||
|
||||
static void
|
||||
pitout(int n, int v)
|
||||
{
|
||||
if(n == 0)
|
||||
irqline(0, v);
|
||||
switch(v){
|
||||
case IRQLLOHI: case 1: pit[n].output = 1; break;
|
||||
case 0: pit[n].output = 0; break;
|
||||
case IRQLTOGGLE: pit[n].output ^= 1; break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pitadvance(void)
|
||||
{
|
||||
|
@ -455,11 +470,11 @@ pitadvance(void)
|
|||
case 0:
|
||||
if(p->state != 0){
|
||||
nc = t / PERIOD;
|
||||
if(p->count <= nc && i == 0)
|
||||
irqline(0, 1);
|
||||
if(p->count <= nc)
|
||||
pitout(i, 1);
|
||||
p->count -= nc;
|
||||
p->lastnsec -= t % PERIOD;
|
||||
if(i == 0 && (pic[0].lines & 1<<0) == 0)
|
||||
if(!p->output)
|
||||
settimer(p->lastnsec + p->count * PERIOD);
|
||||
}
|
||||
break;
|
||||
|
@ -474,8 +489,7 @@ pitadvance(void)
|
|||
nc -= p->count - 1;
|
||||
nc %= rel;
|
||||
p->count = rel - nc + 1;
|
||||
if(i == 0)
|
||||
irqline(0, IRQLLOHI);
|
||||
pitout(i, IRQLLOHI);
|
||||
}
|
||||
p->lastnsec -= t % PERIOD;
|
||||
settimer(p->lastnsec + p->count * PERIOD);
|
||||
|
@ -492,8 +506,7 @@ pitadvance(void)
|
|||
nc -= p->count;
|
||||
nc %= rel;
|
||||
p->count = rel - nc;
|
||||
if(i == 0)
|
||||
irqline(0, IRQLTOGGLE);
|
||||
pitout(i, IRQLTOGGLE);
|
||||
}
|
||||
p->lastnsec -= t % PERIOD;
|
||||
settimer(p->lastnsec + p->count / 2 * PERIOD);
|
||||
|
@ -515,8 +528,7 @@ pitsetreload(int n, int hi, u8int v)
|
|||
p->reload = p->reload & 0xff00 | v;
|
||||
switch(p->mode){
|
||||
case 0:
|
||||
if(n == 0)
|
||||
irqline(0, 0);
|
||||
pitout(n, 0);
|
||||
if(p->access != 3 || hi){
|
||||
p->count = p->reload;
|
||||
p->state = 1;
|
||||
|
@ -569,6 +581,7 @@ pitio(int isin, u16int port, u32int val, int sz, void *)
|
|||
return pit[n].latch >> 8;
|
||||
}
|
||||
return 0;
|
||||
case 0x10061: return port61 | pit[2].output << 5;
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
|
@ -608,16 +621,18 @@ pitio(int isin, u16int port, u32int val, int sz, void *)
|
|||
pit[n].readstate = pit[n].access == 1 ? READHI : READLO;
|
||||
pit[n].writestate = pit[n].access == 1 ? READHI : READLO;
|
||||
pit[n].lastnsec = nsec();
|
||||
if(n == 0)
|
||||
switch(pit[n].mode){
|
||||
case 0:
|
||||
irqline(0, 0);
|
||||
break;
|
||||
default:
|
||||
irqline(0, 1);
|
||||
}
|
||||
switch(pit[n].mode){
|
||||
case 0:
|
||||
pitout(n, 0);
|
||||
break;
|
||||
default:
|
||||
pitout(n, 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case 0x61:
|
||||
port61 = port61 & 0xf0 | val & 0x0f;
|
||||
return 0;
|
||||
}
|
||||
return iowhine(isin, port, val, sz, "pit");
|
||||
}
|
||||
|
@ -628,7 +643,7 @@ struct I8042 {
|
|||
int cmd;
|
||||
u16int buf; /* |0x100 == kbd, |0x200 == mouse, |0x400 == cmd */
|
||||
} i8042 = {
|
||||
.cfg 0x34,
|
||||
.cfg 0x74,
|
||||
.stat 0x10,
|
||||
.oport 0x01,
|
||||
.cmd -1,
|
||||
|
@ -809,7 +824,13 @@ mousecmd(u8int val)
|
|||
break;
|
||||
case 0xe7: mouseputc(0xfa); mouse.scaling21 = 1; break; /* set 2:1 scaling */
|
||||
case 0xe6: mouseputc(0xfa); mouse.scaling21 = 0; break; /* set 1:1 scaling */
|
||||
default: vmerror("unknown mouse command %#ux", val); mouseputc(0xfc);
|
||||
|
||||
case 0x88: case 0x00: case 0x0a: /* sentelic & cypress */
|
||||
case 0xe1: /* trackpoint */
|
||||
mouseputc(0xfe);
|
||||
break;
|
||||
|
||||
default: vmerror("unknown mouse command %#ux", val); mouseputc(0xfe);
|
||||
}
|
||||
}
|
||||
i8042kick(nil);
|
||||
|
@ -894,6 +915,12 @@ i8042io(int isin, u16int port, u32int val, int sz, void *)
|
|||
case 0x60: case 0xd1: case 0xd2: case 0xd3: case 0xd4:
|
||||
i8042.cmd = val;
|
||||
return 0;
|
||||
case 0xf0: case 0xf2: case 0xf4: case 0xf6: /* pulse reset line */
|
||||
case 0xf8: case 0xfa: case 0xfc: case 0xfe:
|
||||
sysfatal("i8042: system reset");
|
||||
case 0xf1: case 0xf3: case 0xf5: case 0xf7: /* no-op */
|
||||
case 0xf9: case 0xfb: case 0xfd: case 0xff:
|
||||
return 0;
|
||||
}
|
||||
vmerror("unknown i8042 command %#ux", val);
|
||||
return 0;
|
||||
|
@ -1204,6 +1231,7 @@ IOHandler handlers[] = {
|
|||
0x70, 0x71, rtcio, nil,
|
||||
0xa0, 0xa1, picio, nil,
|
||||
0x60, 0x60, i8042io, nil,
|
||||
0x61, 0x61, pitio, nil, /* pc speaker */
|
||||
0x64, 0x64, i8042io, nil,
|
||||
0x2f8, 0x2ff, uartio, nil,
|
||||
0x3b0, 0x3bb, vgaio, nil,
|
||||
|
@ -1219,7 +1247,7 @@ IOHandler handlers[] = {
|
|||
0x3f6, 0x3f6, ideio, nil, /* ide primary (aux) */
|
||||
0x3f0, 0x3f7, fdcio, nil, /* floppy */
|
||||
|
||||
0x061, 0x061, nopio, nil, /* pc speaker */
|
||||
0x080, 0x080, nopio, nil, /* dma -- used by linux for delay by dummy write */
|
||||
0x084, 0x084, nopio, nil, /* dma -- used by openbsd for delay by dummy read */
|
||||
0x100, 0x110, nopio, nil, /* elnk3 */
|
||||
0x240, 0x25f, nopio, nil, /* ne2000 */
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <draw.h>
|
||||
#include <libsec.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
@ -687,6 +688,208 @@ tryelf(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
linuxbootmod(char *fn, void *zp, u32int kend)
|
||||
{
|
||||
u32int addr;
|
||||
uintptr memend;
|
||||
int fd;
|
||||
vlong sz;
|
||||
void *v;
|
||||
int rc;
|
||||
|
||||
fd = open(fn, OREAD);
|
||||
if(fd < 0) sysfatal("linux: initrd: open: %r");
|
||||
sz = seek(fd, 0, 2);
|
||||
if(sz < 0) sysfatal("linux: initrd: seek: %r");
|
||||
if(sz == 0) sysfatal("linux: empty initrd");
|
||||
addr = GET32(zp, 0x22c);
|
||||
memend = (1<<20) + gavail(gptr(1<<20, 0));
|
||||
if(addr >= memend) addr = memend - 1;
|
||||
if((addr - (sz - 1) & -4) < kend) sysfatal("linux: no room for initrd");
|
||||
addr = addr - (sz - 1) & -4;
|
||||
print("%#ux %#ux\n", addr, (u32int)sz);
|
||||
v = gptr(addr, sz);
|
||||
if(v == nil) sysfatal("linux: initrd: gptr failed");
|
||||
seek(fd, 0, 0);
|
||||
rc = readn(fd, v, sz);
|
||||
if(rc < 0) sysfatal("linux: initrd: read: %r");
|
||||
if(rc < sz) sysfatal("linux: initrd: short read");
|
||||
close(fd);
|
||||
PUT32(zp, 0x218, addr);
|
||||
PUT32(zp, 0x21C, sz);
|
||||
}
|
||||
|
||||
static void
|
||||
linuxscreeninfo(void *zp)
|
||||
{
|
||||
extern VgaMode *curmode, textmode;
|
||||
extern uintptr fbaddr, fbsz;
|
||||
uintptr extmem;
|
||||
int i, p, s;
|
||||
|
||||
extmem = gavail(gptr(1<<20, 0)) >> 10;
|
||||
if(extmem >= 65535) extmem = 65535;
|
||||
PUT16(zp, 0x02, extmem);
|
||||
|
||||
if(curmode == nil) return;
|
||||
if(curmode == &textmode){
|
||||
PUT8(zp, 0x06, 3); /* mode 3 */
|
||||
PUT8(zp, 0x07, 80); /* 80 cols */
|
||||
PUT8(zp, 0x0e, 25); /* 25 rows */
|
||||
PUT8(zp, 0x0f, 0x22); /* VGA */
|
||||
PUT16(zp, 0x10, 16); /* characters are 16 pixels high */
|
||||
}else{
|
||||
PUT8(zp, 0x0f, 0x23); /* VESA linear framebuffer */
|
||||
PUT16(zp, 0x12, curmode->w);
|
||||
PUT16(zp, 0x14, curmode->h);
|
||||
PUT16(zp, 0x16, chantodepth(curmode->chan));
|
||||
PUT32(zp, 0x18, fbaddr);
|
||||
PUT32(zp, 0x1C, fbsz);
|
||||
PUT16(zp, 0x24, curmode->hbytes);
|
||||
for(i = 0, p = 0; i < 4; i++){
|
||||
s = curmode->chan >> 8 * i & 15;
|
||||
if(s == 0) continue;
|
||||
switch(curmode->chan >> 8 * i + 4 & 15){
|
||||
case CRed: PUT16(zp, 0x26, s | p << 8); break;
|
||||
case CGreen: PUT16(zp, 0x28, s | p << 8); break;
|
||||
case CBlue: PUT16(zp, 0x2a, s | p << 8); break;
|
||||
case CAlpha: case CIgnore: PUT16(zp, 0x2c, s | p << 8); ; break;
|
||||
}
|
||||
p += s;
|
||||
}
|
||||
PUT16(zp, 0x34, 1<<0|1<<1|1<<3|1<<4|1<<5|1<<6|1<<7); /* attributes */
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
GDTRW = 2<<8,
|
||||
GDTRX = 10<<8,
|
||||
GDTS = 1<<12,
|
||||
GDTP = 1<<15,
|
||||
GDT64 = 1<<21,
|
||||
GDT32 = 1<<22,
|
||||
GDTG = 1<<23,
|
||||
};
|
||||
#define GDTLIM0(l) ((l) & 0x0ffff)
|
||||
#define GDTLIM1(l) ((l) & 0xf0000)
|
||||
#define GDTBASE0(b) ((b) << 16)
|
||||
#define GDTBASE1(b) ((b) >> 16 & 0xff | (b) & 0xff000000)
|
||||
|
||||
static void
|
||||
linuxgdt(void *v)
|
||||
{
|
||||
u32int base;
|
||||
|
||||
base = gpa(v);
|
||||
rset("gdtrbase", base);
|
||||
v = pack(v, "ii", 0, 0);
|
||||
v = pack(v, "ii", 0, 0);
|
||||
v = pack(v, "ii", GDTLIM0(-1) | GDTBASE0(0), GDTLIM1(-1) | GDTBASE1(0) | GDTRX | GDTG | GDTS | GDTP | GDT32);
|
||||
v = pack(v, "ii", GDTLIM0(-1) | GDTBASE0(0), GDTLIM1(-1) | GDTBASE1(0) | GDTRW | GDTG | GDTS | GDTP | GDT32);
|
||||
rset("gdtrlimit", gpa(v) - base - 1);
|
||||
rset("cs", 0x10);
|
||||
rset("ds", 0x18);
|
||||
rset("es", 0x18);
|
||||
rset("ss", 0x18);
|
||||
}
|
||||
|
||||
static void
|
||||
linuxe820(uchar *zp)
|
||||
{
|
||||
Region *r;
|
||||
uchar *v;
|
||||
uvlong s, e;
|
||||
int n;
|
||||
|
||||
v = zp + 0x2d0;
|
||||
v = pack(v, "vvi", (uvlong)0, (uvlong)0xa0000, BIOS_MAP_FREE);
|
||||
n = 1;
|
||||
for(r = mmap; r != nil; r = r->next){
|
||||
s = r->start;
|
||||
e = r->end;
|
||||
if(s < (1<<20)) s = 1<<20;
|
||||
if(e <= s || r->type == REGFB) continue;
|
||||
v = pack(v, "vvi", s, e - s, isusermem(r) ? BIOS_MAP_FREE : BIOS_MAP_RES);
|
||||
n++;
|
||||
}
|
||||
PUT8(zp, 0x1e8, n);
|
||||
}
|
||||
|
||||
static int
|
||||
trylinux(void)
|
||||
{
|
||||
char buf[1024];
|
||||
u8int loadflags;
|
||||
u16int version;
|
||||
uchar *zp;
|
||||
void *v;
|
||||
u32int ncmdline, cmdlinemax, syssize, setupsects;
|
||||
|
||||
seek(fd, 0, 0);
|
||||
if(readn(fd, buf, sizeof(buf)) < 1024) return 0;
|
||||
if(GET16(buf, 0x1FE) != 0xAA55 || GET32(buf, 0x202) != 0x53726448) return 0;
|
||||
version = GET16(buf, 0x206);
|
||||
if(version < 0x206){
|
||||
vmerror("linux: kernel too old (boot protocol version %d.%.2d, needs to be 2.06 or newer)", version >> 8, version & 0xff);
|
||||
return 0;
|
||||
}
|
||||
loadflags = GET8(buf, 0x211);
|
||||
if((loadflags & 1) == 0){
|
||||
vmerror("linux: zImage is not supported");
|
||||
return 0;
|
||||
}
|
||||
zp = gptr(0x1000, 0x1000);
|
||||
if(zp == nil) sysfatal("linux: gptr for zeropage failed");
|
||||
rset(RSI, 0x1000);
|
||||
memset(zp, 0, 0x1000);
|
||||
memmove(zp + 0x1f1, buf + 0x1f1, 0x202 + GET8(buf, 0x201) - 0x1f1);
|
||||
setupsects = GET8(zp, 0x1F1);
|
||||
if(setupsects == 0) setupsects = 4;
|
||||
syssize = GET32(zp, 0x1F4);
|
||||
cmdlinemax = GET32(zp, 0x238);
|
||||
|
||||
v = gptr(1<<20, syssize << 4);
|
||||
if(v == nil) sysfatal("linux: not enough room for kernel");
|
||||
epreadn(v, syssize << 4, (setupsects + 1) * 512, "trylinux");
|
||||
|
||||
v = gptr(0x20000, 1);
|
||||
if(v == nil) sysfatal("linux: gptr for cmdline failed");
|
||||
ncmdline = putcmdline(v);
|
||||
if(ncmdline == 0)
|
||||
*(uchar*)v = 0;
|
||||
else
|
||||
if(ncmdline - 1 > cmdlinemax) sysfatal("linux: cmdline too long (%d > %d)", ncmdline, cmdlinemax);
|
||||
PUT32(zp, 0x228, 0x20000);
|
||||
|
||||
switch(bootmodn){
|
||||
case 0: break;
|
||||
default:
|
||||
vmerror("linux: ignoring extra boot modules (only one supported)");
|
||||
/* wet floor */
|
||||
case 1:
|
||||
linuxbootmod(*bootmod, zp, (1<<20) + (syssize << 4));
|
||||
}
|
||||
|
||||
linuxscreeninfo(zp);
|
||||
v = gptr(0x3000, 256);
|
||||
if(v == nil) sysfatal("linux: gptr for gdt failed");
|
||||
linuxgdt(v);
|
||||
|
||||
linuxe820(zp);
|
||||
|
||||
PUT16(zp, 0x1FA, 0xffff);
|
||||
PUT8(zp, 0x210, 0xFF); /* bootloader ID */
|
||||
PUT8(zp, 0x211, loadflags | 0x80); /* kernel can use heap */
|
||||
|
||||
PUT32(zp, 0x224, 0xfe00); /* kernel can use full segment */
|
||||
rset(RPC, GET32(zp, 0x214));
|
||||
rset(RBP, 0);
|
||||
rset(RDI, 0);
|
||||
rset(RBX, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
loadkernel(char *fn)
|
||||
{
|
||||
|
@ -694,7 +897,7 @@ loadkernel(char *fn)
|
|||
if(fd < 0) sysfatal("open: %r");
|
||||
if(readn(fd, hdr, sizeof(hdr)) <= 0)
|
||||
sysfatal("readn: %r");
|
||||
if(!trymultiboot() && !tryelf())
|
||||
if(!trymultiboot() && !tryelf() && !trylinux())
|
||||
sysfatal("%s: unknown format", fn);
|
||||
close(fd);
|
||||
}
|
||||
|
|
|
@ -258,6 +258,7 @@ vesamodeget(int addr, u16int mode, u16int *retv)
|
|||
pos = 0;
|
||||
for(i = 0; i < 4; i++){
|
||||
s = p->chan >> 8 * i & 15;
|
||||
if(s == 0) continue;
|
||||
switch(p->chan >> 8 * i + 4 & 15){
|
||||
case CRed: nred = s; pred = pos; break;
|
||||
case CGreen: ngreen = s; pgreen = pos; break;
|
||||
|
|
|
@ -152,6 +152,10 @@ vgaio(int isin, u16int port, u32int val, int sz, void *)
|
|||
{
|
||||
u32int m;
|
||||
|
||||
if(port == 0x3d4 && sz == 2 && !isin){
|
||||
vgaio(0, 0x3d4, (u8int)val, 1, nil);
|
||||
return vgaio(0, 0x3d5, (u8int)(val >> 8), 1, nil);
|
||||
}
|
||||
if(sz != 1) vmdebug("vga: non-byte access to port %#ux, sz=%d", port, sz);
|
||||
val = (u8int) val;
|
||||
switch(isin << 16 | port){
|
||||
|
|
|
@ -53,6 +53,8 @@ struct VIONetDev {
|
|||
VNETNOMULTI = 8,
|
||||
VNETNOUNI = 16,
|
||||
VNETNOBCAST = 32,
|
||||
|
||||
VNETHEADER = 1<<31,
|
||||
} flags;
|
||||
u64int macbloom, multibloom;
|
||||
};
|
||||
|
@ -447,6 +449,7 @@ vionetrproc(void *vp)
|
|||
threadsetname("vionetrproc");
|
||||
v = vp;
|
||||
q = &v->qu[0];
|
||||
memset(rxhead, 0, sizeof(rxhead));
|
||||
for(;;){
|
||||
rc = read(v->net.readfd, rxbuf, sizeof(rxbuf));
|
||||
if(rc == 0){
|
||||
|
@ -481,8 +484,9 @@ vionetwproc(void *vp)
|
|||
VIOQueue *q;
|
||||
VIOBuf *vb;
|
||||
uchar txhead[10];
|
||||
uchar txbuf[1600];
|
||||
uchar txbuf[1610];
|
||||
int rc, len;
|
||||
uvlong ns;
|
||||
|
||||
threadsetname("vionetwproc");
|
||||
v = vp;
|
||||
|
@ -494,8 +498,8 @@ vionetwproc(void *vp)
|
|||
threadexits("viogetbuf: %r");
|
||||
}
|
||||
vioqread(vb, txhead, sizeof(txhead));
|
||||
len = vioqread(vb, txbuf, sizeof(txbuf));
|
||||
if(len == sizeof(txbuf)){
|
||||
len = vioqread(vb, txbuf+10, sizeof(txbuf)-10);
|
||||
if(len == sizeof(txbuf)-10){
|
||||
vmerror("virtio net: ignoring excessively long packet");
|
||||
vioputbuf(vb);
|
||||
continue;
|
||||
|
@ -507,10 +511,24 @@ vionetwproc(void *vp)
|
|||
vioputbuf(vb);
|
||||
continue;
|
||||
}else if(len < 60){ /* openbsd doesn't seem to know about ethernet minimum packet lengths either */
|
||||
memset(txbuf + len, 0, 60 - len);
|
||||
memset(txbuf + 10 + len, 0, 60 - len);
|
||||
len = 60;
|
||||
}
|
||||
rc = write(v->net.writefd, txbuf, len);
|
||||
}
|
||||
if((v->net.flags & VNETHEADER) != 0){
|
||||
txbuf[0] = len >> 8;
|
||||
txbuf[1] = len;
|
||||
ns = nsec();
|
||||
txbuf[2] = ns >> 56;
|
||||
txbuf[3] = ns >> 48;
|
||||
txbuf[4] = ns >> 40;
|
||||
txbuf[5] = ns >> 32;
|
||||
txbuf[6] = ns >> 24;
|
||||
txbuf[7] = ns >> 16;
|
||||
txbuf[8] = ns >> 8;
|
||||
txbuf[9] = ns;
|
||||
rc = write(v->net.writefd, txbuf, len + 10);
|
||||
}else
|
||||
rc = write(v->net.writefd, txbuf + 10, len);
|
||||
vioputbuf(vb);
|
||||
if(rc < 0){
|
||||
vmerror("write(vionetwproc): %r");
|
||||
|
@ -607,7 +625,7 @@ vionetcmd(VIOQueue *q)
|
|||
void
|
||||
vionetreset(VIODev *d)
|
||||
{
|
||||
d->net.flags = 0;
|
||||
d->net.flags &= VNETHEADER;
|
||||
d->net.macbloom = 0;
|
||||
d->net.multibloom = 0;
|
||||
}
|
||||
|
@ -618,10 +636,30 @@ mkvionet(char *net)
|
|||
int fd, cfd;
|
||||
VIODev *d;
|
||||
int i;
|
||||
int flags;
|
||||
enum { VNETFILE = 1 };
|
||||
|
||||
fd = dial(netmkaddr("-1", net, nil), nil, nil, &cfd);
|
||||
if(fd < 0) return -1;
|
||||
if(cfd >= 0) fprint(cfd, "promiscuous");
|
||||
flags = 0;
|
||||
for(;;){
|
||||
if(strncmp(net, "hdr!", 4) == 0){
|
||||
net += 4;
|
||||
flags |= VNETHEADER;
|
||||
}else if(strncmp(net, "file!", 5) == 0){
|
||||
net += 5;
|
||||
flags |= VNETFILE;
|
||||
}else
|
||||
break;
|
||||
}
|
||||
if((flags & VNETFILE) != 0){
|
||||
flags &= ~VNETFILE;
|
||||
fd = open(net, ORDWR);
|
||||
if(fd < 0) return -1;
|
||||
}else{
|
||||
fd = dial(netmkaddr("-1", net, nil), nil, nil, &cfd);
|
||||
if(fd < 0) return -1;
|
||||
if(cfd >= 0) fprint(cfd, "promiscuous");
|
||||
}
|
||||
|
||||
d = mkviodev(0x1000, 0x020000, 1);
|
||||
mkvioqueue(d, 1024, viowakeup);
|
||||
mkvioqueue(d, 1024, viowakeup);
|
||||
|
@ -629,6 +667,7 @@ mkvionet(char *net)
|
|||
for(i = 0; i < 6; i++)
|
||||
d->net.mac[i] = rand();
|
||||
d->net.mac[0] = d->net.mac[0] & ~1 | 2;
|
||||
d->net.flags = flags;
|
||||
d->devfeat = 1<<5|1<<16|1<<17|1<<18|1<<20;
|
||||
d->io = vionetio;
|
||||
d->reset = vionetreset;
|
||||
|
|
Loading…
Reference in a new issue