aux/vga: add fixbios() for patching bogus vesa bios

This commit is contained in:
cinap_lenrek 2013-01-07 20:59:50 +01:00
parent db581d2fe6
commit 960a04bfec

View file

@ -25,7 +25,6 @@ struct Vbe
int memfd; /* /dev/realmem */ int memfd; /* /dev/realmem */
uchar *mem; /* copy of memory; 1MB */ uchar *mem; /* copy of memory; 1MB */
uchar *isvalid; /* 1byte per 4kB in mem */ uchar *isvalid; /* 1byte per 4kB in mem */
uchar *buf;
uchar *modebuf; uchar *modebuf;
}; };
@ -105,14 +104,17 @@ int vbesnarf(Vbe*, Vga*);
void vesaddc(void); void vesaddc(void);
int vbeddcedid(Vbe *vbe, Edid *e); int vbeddcedid(Vbe *vbe, Edid *e);
void printedid(Edid*); void printedid(Edid*);
void fixbios(Vbe*);
int int
dbvesa(Vga* vga) dbvesa(Vga* vga)
{ {
vbe = mkvbe();
if(vbe == nil){ if(vbe == nil){
fprint(2, "mkvbe: %r\n"); vbe = mkvbe();
return 0; if(vbe == nil){
fprint(2, "mkvbe: %r\n");
return 0;
}
} }
if(vbecheck(vbe) < 0){ if(vbecheck(vbe) < 0){
fprint(2, "dbvesa: %r\n"); fprint(2, "dbvesa: %r\n");
@ -230,9 +232,9 @@ havemode:
static void static void
snarf(Vga* vga, Ctlr* ctlr) snarf(Vga* vga, Ctlr* ctlr)
{ {
if(!vbe) if(vbe == nil)
vbe = mkvbe(); vbe = mkvbe();
if(vbe) if(vbe != nil)
vga->vesa = ctlr; vga->vesa = ctlr;
vbesnarf(vbe, vga); vbesnarf(vbe, vga);
vga->linear = 1; vga->linear = 1;
@ -414,21 +416,43 @@ mkvbe(void)
return nil; return nil;
vbe->mem = alloc(MemSize); vbe->mem = alloc(MemSize);
vbe->isvalid = alloc(MemSize/PageSize); vbe->isvalid = alloc(MemSize/PageSize);
vbe->buf = alloc(PageSize);
vbe->modebuf = alloc(PageSize); vbe->modebuf = alloc(PageSize);
fixbios(vbe);
return vbe; return vbe;
} }
static void static void
loadpage(Vbe *vbe, int p) loadpage(Vbe *vbe, int p, int wr)
{ {
if(p >= MemSize/PageSize || vbe->isvalid[p]) if(p >= MemSize/PageSize)
return; return;
if(pread(vbe->memfd, vbe->mem+p*PageSize, PageSize, p*PageSize) != PageSize) if(vbe->isvalid[p] == 0)
error("read /dev/realmodemem: %r\n"); if(pread(vbe->memfd, vbe->mem+p*PageSize, PageSize, p*PageSize) != PageSize)
error("read /dev/realmodemem: %r\n");
vbe->isvalid[p] = 1+wr;
}
static void
flushpage(Vbe *vbe, int p)
{
if(p >= MemSize/PageSize || vbe->isvalid[p]!=2)
return;
if(pwrite(vbe->memfd, vbe->mem+p*PageSize, PageSize, p*PageSize) != PageSize)
error("write /dev/realmodemem: %r\n");
vbe->isvalid[p] = 1; vbe->isvalid[p] = 1;
} }
static void*
getmem(Vbe *vbe, int off, int wr)
{
if(off == 0 || off >= MemSize)
return nil;
loadpage(vbe, off/PageSize, wr);
if(off % PageSize)
loadpage(vbe, (off/PageSize)+1, wr);
return vbe->mem+off;
}
static void* static void*
unfarptr(Vbe *vbe, uchar *p) unfarptr(Vbe *vbe, uchar *p)
{ {
@ -436,44 +460,53 @@ unfarptr(Vbe *vbe, uchar *p)
seg = WORD(p+2); seg = WORD(p+2);
off = WORD(p); off = WORD(p);
if(seg==0 && off==0)
return nil;
off += seg<<4; off += seg<<4;
if(off >= MemSize) return getmem(vbe, off, 0);
return nil;
loadpage(vbe, off/PageSize);
loadpage(vbe, off/PageSize+1); /* just in case */
return vbe->mem+off;
} }
uchar* uchar*
vbesetup(Vbe *vbe, Ureg *u, int ax) vbesetup(Vbe *vbe, Ureg *u, int ax)
{ {
memset(vbe->buf, 0, PageSize); uchar *p;
memset(u, 0, sizeof *u); memset(u, 0, sizeof *u);
u->ax = ax; u->ax = ax;
u->es = (RealModeBuf>>4)&0xF000; u->es = (RealModeBuf>>4)&0xF000;
u->di = RealModeBuf&0xFFFF; u->di = RealModeBuf&0xFFFF;
return vbe->buf; p = getmem(vbe, RealModeBuf, 1);
memset(p, 0, PageSize);
return p;
}
void
vbeflush(Vbe *vbe)
{
int p;
for(p=0; p<MemSize/PageSize; p++)
flushpage(vbe, p);
memset(vbe->isvalid, 0, MemSize/PageSize);
} }
int int
vbecall(Vbe *vbe, Ureg *u) vbecall(Vbe *vbe, Ureg *u)
{ {
u->trap = 0x10; u->trap = 0x10;
if(pwrite(vbe->memfd, vbe->buf, PageSize, RealModeBuf) != PageSize)
error("write /dev/realmodemem: %r\n"); vbeflush(vbe);
if(pwrite(vbe->rmfd, u, sizeof *u, 0) != sizeof *u) if(pwrite(vbe->rmfd, u, sizeof *u, 0) != sizeof *u)
error("write /dev/realmode: %r\n"); error("write /dev/realmode: %r\n");
if(pread(vbe->rmfd, u, sizeof *u, 0) != sizeof *u) if(pread(vbe->rmfd, u, sizeof *u, 0) != sizeof *u)
error("read /dev/realmode: %r\n"); error("read /dev/realmode: %r\n");
if(pread(vbe->memfd, vbe->buf, PageSize, RealModeBuf) != PageSize)
error("read /dev/realmodemem: %r\n"); getmem(vbe, RealModeBuf, 0);
if((u->ax&0xFFFF) != 0x004F){ if((u->ax&0xFFFF) != 0x004F){
werrstr("VBE error %#.4lux", u->ax&0xFFFF); werrstr("VBE error %#.4lux", u->ax&0xFFFF);
return -1; return -1;
} }
memset(vbe->isvalid, 0, MemSize/PageSize);
return 0; return 0;
} }
@ -703,7 +736,7 @@ vesatextmode(void)
{ {
if(vbe == nil){ if(vbe == nil){
vbe = mkvbe(); vbe = mkvbe();
if(!vbe) if(vbe == nil)
error("mkvbe: %r\n"); error("mkvbe: %r\n");
} }
if(vbecheck(vbe) < 0) if(vbecheck(vbe) < 0)
@ -1142,3 +1175,29 @@ fprint(2, "%.8H\n", p);
assert(p == (uchar*)v+8+10+2+5+10+3+16+72); assert(p == (uchar*)v+8+10+2+5+10+3+16+72);
return 0; return 0;
} }
void
fixbios(Vbe *vbe)
{
uchar *p;
int i;
/*
* Intel(r) Cantiga Graphics Chip Accelerated VGA BIOS 1.0 has
* a wrong entry in mode alias table at c000:7921 for mode 0x16b
* (1440x900x32) wrongly replacing it with mode 0x162 (768x480x32).
*/
p = getmem(vbe, 0xc7921, 0);
if(p != nil && p[0] == 0x01 && p[1] == 0xff && p[2] == 0xff){
for(i=1; i<64; i++){
p = getmem(vbe, 0xc7921 + 3*i, 0);
if(p == nil || p[0] == 0xff)
break;
if(p[0] == 0x6b && p[1] == 0x6b && p[2] == 0x62){
p = getmem(vbe, 0xc7921 + 3*i, 1);
p[2] = 0x6b; /* fix */
break;
}
}
}
}