要在显示屏显示图像,方法有两种,mmio pio。现在的显卡都应当支持vbe。
vbe 提供了保护模式的接口,bios方式太旧了,且保护模式操作太复杂,故想找个简单的方式,但这方面的资料太少,花了不少时间,终于成功。
利用bios 10号中断取得保护接口信息,除5、7、9号程序,还有几个端口信息,好不容易找到保护模式切换显示模式的使用方法。不过还不确定bios返回端口的具体用途,但显示设置的函数实验成功。
显存的访问,在低分辨率及字符模式,地址在0xa0000---0xbffff之间,但到了高分辨率就一般在高端内存。网上查的说可以直接访问,我怎么实验都没成功。搞了一个星期,终于可以正确显示。
要想访问显存,有3步:
1. 显存的物理地址,英文叫LFB,可以bios 1号中段获取,资料上说可以自主设置,不过我在bochs上没成功,不知哪里出错了,后来没搞了。
2. MTRR,说起来有点复杂,意思就是把显存地址注册到地址空间。独显、核显、仿真对地址分配有没区别,还待实验。
3. 显卡设置,开启lfb。好象只能显示真彩色,低色彩的还没成功。
开启之后,就显存地址就是物理地址了,统一在4G之内,读写也正常,屏幕显示正常,不过bochs显示内存指令不能显示,不知道是bochs的问题,还是本来就这样。关键代码在下面
void BgaSetVideoMode(unsigned int Width, unsigned int Height, unsigned int BitDepth, int UseLinearFrameBuffer, int ClearVideoMemory)
{
// VBE disabling
BgaWriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
//
BgaWriteRegister(VBE_DISPI_INDEX_XRES, Width);
BgaWriteRegister(VBE_DISPI_INDEX_YRES, Height);
BgaWriteRegister(VBE_DISPI_INDEX_BPP, BitDepth);
BgaWriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED |
(UseLinearFrameBuffer ? VBE_DISPI_LFB_ENABLED : 0) |
(ClearVideoMemory ? 0 : VBE_DISPI_NOCLEARMEM));
}
DWORD find_empty_mtrr()
{
//RDMSR将64位由ECX寄存器指定的MSR(model specific register,
//模式指定寄存器)的内容读出至寄存器EDX:EAX中
//(在支持intel64架构的处理器中RCX的高32位忽略)。
//MSR的高32位内容存放在EDX寄存器中,
//MSR的低32位内容存放在EAX寄存器中
//(在支持intel64架构的处理器中RDX和RAX的高32位忽略)。
//如果MSR中没有64位(有些位没有实现),
//则EDX:EAX中没有实现的位置则未定义。
//寄存器2个一组
DWORD empmtrr,port,val1,val2;
empmtrr=0;
for (port=0x201;port<0x200+16;port=port+2)
{
rdmsr(port,val1,val2);
if (!(val1&0x0800))
{
port--;
empmtrr=port;
break;
}
}
return empmtrr;
}
void enableMtrr(DWORD addr)
{
DWORD mttr,val1,val2;
mttr = find_empty_mtrr();
// ; LFB , +8 M , write combine
//|64 保留 | 物理地址 12|11 8|7 type |0
//|64 保留 | 掩码|Valid 11|10 保留 |0
wrmsr(mttr,addr | 1,0);
wrmsr(mttr+1,0xff800800,0xf);
// enable mtrr's
rdmsr(0x2ff,val1,val2);
wrmsr(0x2ff,val1 | 0x800 ,val2);
}