SVGA in 32bit protected mode ?
Re: Compiling VGABIOS
My own sentence made me think and I came up with an idea. For now it actually seems to work:Walling wrote:I might contribute. It can't be that difficult to code an entrypoint. It is 16 bit protected mode, so it could just call the current implementation I think. Of course I would have to look into that and the VBE3 specification.
- Setup a GDT with 16 bit data selectors where needed (ex. selector 0x40 pointing at a segment starting 0x400 and spanding 64K, ie. a simulation of real mode segments).
- Look up in the real mode IVT to find the location of INT 0x10.
- Relocate the VGABIOS (it seems you don't have read/write access to that memory area?) and the VBE3 document specific tells you to relocate it.
- Find IRET instructions and replace them with a32 RETF – problem: the last is 2 bytes and IRET is only 1. You might overwrite something. (Edit: Solved. Only replacing IRET by RETF)
- CALL where the INT 0x10 entry point is with correct parameters.
In fact you might be able to call a lot of BIOS interrupts that way? However a lot of things could go wrong in theory.
Could you possibly set interrupt 10h to point to the actual location in the IVT, that way you could actually call int 10h, and not have to replace the iret's? That would definitely be nifty, and you wouldn't have to worry about overwriting anything important. The only problem you may run into depending on the video card, is if it uses any other 16-bit interrupts or similar when you call it (which it shouldn't, but you never know). By the way, if you're worried about losing the functionality of int 10h, you can always overwrite and change back after the int 10h call for the video.
Maybe you could try something like this:
http://www.osdev.org/phpBB2/viewtopic.php?t=10321 ?
http://www.osdev.org/phpBB2/viewtopic.php?t=10321 ?
Actually. I've just got it to work without replacing anything. The solution is to push flags just before you call the interrupt entry point, because IRET is similar to RETF / POPF. It's nice. You can actually call BIOS code from protected mode I have to try it on other interrupt functions as well later. But now I'm going to bed (it's late here in Denmark).Ready4Dis wrote:Could you possibly set interrupt 10h to point to the actual location in the IVT, that way you could actually call int 10h, and not have to replace the iret's?
Looks interesting at first glance. Have to look a bit closer on it.. tomorrow.bubach wrote:Maybe you could try something like this:
http://www.osdev.org/phpBB2/viewtopic.php?t=10321 ?
Hi,
here is the code for VMware:
here is the code for VMware:
Code: Select all
#define PCI_CONFIG_ADDRESS 0xcf8
#define PCI_CONFIG_DATA 0xcfc
#define PCI_IO 1
#define PCI_MEM 2
#define SVGA_INDEX_PORT 0x0
#define SVGA_VALUE_PORT 0x1
#define VMWARE_VENDOR_ID 0x15AD
#define SVGA_VERSION_2 2
#define SVGA_ID_2 SVGA_MAKE_ID(SVGA_VERSION_2)
#define SVGA_VERSION_1 1
#define SVGA_ID_1 SVGA_MAKE_ID(SVGA_VERSION_1)
#define SVGA_MAGIC 0x900000
#define SVGA_MAKE_ID(ver) (SVGA_MAGIC << 8 | (ver))
#define SVGA_VERSION_0 0
#define SVGA_ID_0 SVGA_MAKE_ID(SVGA_VERSION_0)
enum {
SVGA_REG_ID = 0,
SVGA_REG_ENABLE = 1,
SVGA_REG_WIDTH = 2,
SVGA_REG_HEIGHT = 3,
SVGA_REG_MAX_WIDTH = 4,
SVGA_REG_MAX_HEIGHT = 5,
SVGA_REG_DEPTH = 6,
SVGA_REG_BITS_PER_PIXEL = 7,
SVGA_REG_PSEUDOCOLOR = 8,
SVGA_REG_RED_MASK = 9,
SVGA_REG_GREEN_MASK = 10,
SVGA_REG_BLUE_MASK = 11,
SVGA_REG_BYTES_PER_LINE = 12,
SVGA_REG_FB_START = 13,
SVGA_REG_FB_OFFSET = 14,
SVGA_REG_VRAM_SIZE = 15,
SVGA_REG_FB_SIZE = 16,
SVGA_REG_CAPABILITIES = 17,
SVGA_REG_MEM_START = 18,
SVGA_REG_MEM_SIZE = 19,
SVGA_REG_CONFIG_DONE = 20,
SVGA_REG_SYNC = 21,
SVGA_REG_BUSY = 22,
SVGA_REG_GUEST_ID = 23,
SVGA_REG_CURSOR_ID = 24,
SVGA_REG_CURSOR_X = 25,
SVGA_REG_CURSOR_Y = 26,
SVGA_REG_CURSOR_ON = 27,
SVGA_REG_HOST_BITS_PER_PIXEL = 28,
SVGA_REG_TOP = 30,
SVGA_PALETTE_BASE = 1024
};
#define PCI_SPACE_MEMORY 0
#define PCI_SPACE_IO 1
#define SVGA_CMD_INVALID_CMD 0
#define SVGA_CMD_UPDATE 1
#define SVGA_CMD_RECT_FILL 2
#define SVGA_CMD_RECT_COPY 3
#define SVGA_CMD_DEFINE_BITMAP 4
#define SVGA_CMD_DEFINE_BITMAP_SCANLINE 5
#define SVGA_CMD_DEFINE_PIXMAP 6
#define SVGA_CMD_DEFINE_PIXMAP_SCANLINE 7
#define SVGA_CMD_RECT_BITMAP_FILL 8
#define SVGA_CMD_RECT_PIXMAP_FILL 9
#define SVGA_CMD_RECT_BITMAP_COPY 10
#define SVGA_CMD_RECT_PIXMAP_COPY 11
#define SVGA_CMD_FREE_OBJECT 12
#define SVGA_CMD_RECT_ROP_FILL 13
#define SVGA_CMD_RECT_ROP_COPY 14
#define SVGA_CMD_RECT_ROP_BITMAP_FILL 15
#define SVGA_CMD_RECT_ROP_PIXMAP_FILL 16
#define SVGA_CMD_RECT_ROP_BITMAP_COPY 17
#define SVGA_CMD_RECT_ROP_PIXMAP_COPY 18
#define SVGA_CMD_DEFINE_CURSOR 19
#define SVGA_CMD_DISPLAY_CURSOR 20
#define SVGA_CMD_MOVE_CURSOR 21
#define SVGA_CMD_DEFINE_ALPHA_CURSOR 22
#define SVGA_CMD_DRAW_GLYPH 23
#define SVGA_CMD_DRAW_GLYPH_CLIPPED 24
#define SVGA_CMD_UPDATE_VERBOSE 25
#define SVGA_CMD_SURFACE_FILL 26
#define SVGA_CMD_SURFACE_COPY 27
#define SVGA_CMD_SURFACE_ALPHA_BLEND 28
#define SVGA_CMD_MAX 29
#define SVGA_CMD_MAX_ARGS 12
#define SVGA_FIFO_MIN 0
#define SVGA_FIFO_MAX 1
#define SVGA_FIFO_NEXT_CMD 2
#define SVGA_FIFO_STOP 3
typedef struct PCI_BASE
{
BYTE Space;
BYTE Type;
BYTE Prefetch;
DWORD Address;
}PCI_BASE, *PPCI_BASE;
typedef struct PCI_DEVICE_INFO
{
USHORT DeviceId;
USHORT VendorId;
int ClassCode;
int SubClass;
int Bus;
int Device;
int Function;
PCI_BASE Bases[6];
}PCI_DEVICE_INFO, *PPCI_DEVICE_INFO;
#pragma pack(push, 1)
typedef struct PCI_CONFIG
{
UCHAR Reg : 8;
UCHAR Func : 3;
UCHAR Dev : 5;
UCHAR Bus : 8;
UCHAR Rsvd : 7;
UCHAR Enable : 1;
}PCI_CONFIG, *PPCI_CONFIG;
#pragma pack(pop)
ULONG PciReadConfig(ULONG bus, ULONG device,
ULONG function, ULONG reg)
{
PCI_CONFIG c;
PULONG n;
USHORT base;
c.Enable = 1;
c.Rsvd = 0;
c.Bus = bus;
c.Dev = device;
c.Func = function;
c.Reg = reg & 0xfc;
n = (PULONG)((PVOID)&c);
WRITE_PORT_ULONG(0xcf8, *n);
base = 0xcfc + (reg & 0x03);
return READ_PORT_ULONG(base);
}
VOID PciWriteConfig(ULONG bus, ULONG device,
ULONG function, ULONG reg,
ULONG value)
{
PCI_CONFIG c;
PULONG n;
USHORT base;
c.Enable = 1;
c.Rsvd = 0;
c.Bus = bus;
c.Dev = device;
c.Func = function;
c.Reg = reg & 0xfc;
n = (PULONG)((PVOID)&c);
WRITE_PORT_ULONG(0xcf8, *n);
base = 0xcfc + (reg & 0x03);
WRITE_PORT_ULONG(base, value);
}
VOID PciGetDeviceInfo(PPCI_DEVICE_INFO info,
ULONG bus,
ULONG device,
ULONG function)
{
ULONG r;
r = PciReadConfig(bus, device, function, 0);
info->VendorId = r & 0xffff;
info->DeviceId = (r >> 16) & 0xffff;
r = PciReadConfig(bus, device, function, 8);
info->ClassCode = r >> 24;
info->SubClass = (r >> 16) & 0xff;
info->Bus = bus;
info->Device = device;
info->Function = function;
}
VOID PciReadBases(PPCI_DEVICE_INFO Info)
{
int i;
ULONG l;
for (i = 0; i < 6; i++) {
l = PciReadConfig(Info->Bus, Info->Device, Info->Function, 0x10 + i*4);
if (l & 0x01) {
Info->Bases[i].Space = PCI_SPACE_IO;
Info->Bases[i].Type = 0;
Info->Bases[i].Prefetch = 0;
Info->Bases[i].Address = l & (~0x03);
}
else {
Info->Bases[i].Space = PCI_SPACE_MEMORY;
Info->Bases[i].Type = (l >> 1)&0x03;
Info->Bases[i].Prefetch = (l >> 3)&0x01;
Info->Bases[i].Address = l & (~0x0f);
}
}
}
BOOL PciFindDeviceByVendorId(USHORT VendorId,
int index,
PPCI_DEVICE_INFO Info)
{
PCI_DEVICE_INFO info;
int bus;
int fun;
int dev;
for (bus = 0; bus < 256; bus++) {
for (dev = 0; dev < 32; dev++) {
for (fun = 0; fun < 8; fun++) {
PciGetDeviceInfo(&info, bus, dev, fun);
if (info.VendorId == VendorId) {
if (!index) {
Info->Bus = bus;
Info->Device = dev;
Info->Function = fun;
Info->DeviceId = info.DeviceId;
Info->VendorId = info.VendorId;
Info->ClassCode = info.ClassCode;
Info->SubClass = info.SubClass;
return TRUE;
}
else
index--;
}
}
}
}
return FALSE;
}
USHORT VmwSvgaIndex;
USHORT VmwSvgaValue;
PULONG VmwFramebuffer;
PULONG VmwFifo;
BOOL DetectVmwareVideoAdapter(PPCI_DEVICE_INFO Info)
{
PCI_DEVICE_INFO dev;
int index = 0;
while (1) {
if (!PciFindDeviceByVendorId(VMWARE_VENDOR_ID, index, &dev))
break;
else {
if (dev.DeviceId == 0x405) {
if (Info != NULL)
memcpy(Info, &dev, sizeof(PCI_DEVICE_INFO));
return TRUE;
}
index++;
}
}
return FALSE;
}
VOID VmwSvgaOut(USHORT Index, ULONG Value)
{
WRITE_PORT_ULONG(VmwSvgaIndex, Index);
WRITE_PORT_ULONG(VmwSvgaValue, Value);
}
ULONG VmwSvgaIn(USHORT Index)
{
WRITE_PORT_ULONG(VmwSvgaIndex, Index);
return READ_PORT_ULONG(VmwSvgaValue);
}
BOOL VmwSetVideoMode(ULONG Width, ULONG Height, ULONG Bpp)
{
PCI_DEVICE_INFO dev;
if (DetectVmwareVideoAdapter(&dev))
{
ULONG fb;
PciReadBases(&dev);
VmwSvgaIndex = dev.Bases[0].Address + SVGA_INDEX_PORT;
VmwSvgaValue = dev.Bases[0].Address + SVGA_VALUE_PORT;
VmwSvgaOut(SVGA_REG_ID, SVGA_ID_2);
if (VmwSvgaIn(SVGA_REG_ID) != SVGA_ID_2)
{
VmwSvgaOut(SVGA_REG_ID, SVGA_ID_1);
if (VmwSvgaIn(SVGA_REG_ID) != SVGA_ID_1)
{
VmwSvgaOut(SVGA_REG_ID, SVGA_ID_0);
if (VmwSvgaIn(SVGA_REG_ID) != SVGA_ID_0)
{
return FALSE;
}
}
}
VmwFramebuffer = (PULONG)VmwSvgaIn(SVGA_REG_FB_START);
VmwSvgaIn(SVGA_REG_FB_SIZE);
VmwFifo = (PULONG)VmwSvgaIn(SVGA_REG_MEM_START);
VmwSvgaIn(SVGA_REG_MEM_SIZE);
VmwSvgaOut(SVGA_REG_WIDTH, Width);
VmwSvgaOut(SVGA_REG_HEIGHT, Height);
VmwSvgaOut(SVGA_REG_BITS_PER_PIXEL, Bpp);
/*
* Read additional informations.
*/
VmwSvgaIn(SVGA_REG_FB_OFFSET);
VmwSvgaIn(SVGA_REG_BYTES_PER_LINE);
VmwSvgaIn(SVGA_REG_DEPTH);
VmwSvgaIn(SVGA_REG_PSEUDOCOLOR);
VmwSvgaIn(SVGA_REG_RED_MASK);
VmwSvgaIn(SVGA_REG_GREEN_MASK);
VmwSvgaIn(SVGA_REG_BLUE_MASK);
VmwSvgaOut(SVGA_REG_ENABLE, 1);
return TRUE;
}
else
{
return FALSE;
}
}
BIOS interrupts from 32-bit pmode
You're right. To solve that I fill up my GDT with selectors like this: On location 0xC000 it points to 0x2C0000 (I relocate the BIOS to 0x200000). But if the code tries to load a real mode segment like 0xC001 it is stuck, because you can't create a GDT entry on that location. And certainly not in advance.Ready4Dis wrote:One thing I wanted to bring up for calling bios int's from 16-bit pmode, be careful, because if it tries to modify DS it will crash your system if that DS isn't a valid descriptor in your GDT! Same goes for es, ss, et al.
I actually got this to work from 32-bit protected mode. It automaticly jumps into 16-bit mode and executes the BIOS interrupt and returns in 32-bit mode:
Code: Select all
MOV AX, 0x4F00
MOV DI, 0x7000
INT 0x10
; A VESA information structure is now location at 0x7000.
I am not sure how int 16h works, but i'm sure it polls the interrupts to check when a key is hit, so there isn't really any way around this. I would not use it for things like this anyways, it's simple enough to write a keyboard driver, ide driver, etc. The only elusive driver in pmode is a standard vesa driver, although vesa 3.0 supports 16-bit pmode, basically the same as you are doing, relocates the code, and you call it in 16-bit pmode. My vesa driver drops to real mode, calls interrupt and returns to pmode, I only use it to set video mode and grab info, so it is plenty fast in that I don't call it very often.
Please get real, stop living in fantasy land, its very simple, you can do VGA without BIOS see here: http://bos.asmhackers.net/docs/vga_without_bios/
For VESA you need to go back to realmode like i demo , or code V86 that it. What you may of read about 16bit pmode and vesa is ****, if you can not show its can be done, then it most likely can not.
Emulators are just that, they are emulators, If you are making a OS, it needs to work on a real PC, if not and it only runs on one type of emulator, its a app.
I am telling you all this for your own good, if you do not want to listen its your problem.
For VESA you need to go back to realmode like i demo , or code V86 that it. What you may of read about 16bit pmode and vesa is ****, if you can not show its can be done, then it most likely can not.
Emulators are just that, they are emulators, If you are making a OS, it needs to work on a real PC, if not and it only runs on one type of emulator, its a app.
I am telling you all this for your own good, if you do not want to listen its your problem.
pessimist!Dex wrote:Please get real, stop living in fantasy land, its very simple, you can do VGA without BIOS see here: http://bos.asmhackers.net/docs/vga_without_bios/
For VESA you need to go back to realmode like i demo , or code V86 that it. What you may of read about 16bit pmode and vesa is ****, if you can not show its can be done, then it most likely can not.
Emulators are just that, they are emulators, If you are making a OS, it needs to work on a real PC, if not and it only runs on one type of emulator, its a app.
I am telling you all this for your own good, if you do not want to listen its your problem.
VESA is great and easy (to handle)
the only reasonable way to use the functions is the vm86, to switch to the [Un]real Mode is an very odd way...
of course you can't make drivers for every graphic card, but on a good OS the vm86 _should_ be implemented...
greetings,
Toaster
Thank you,
http://bos.asmhackers.net/docs/vga_without_bios/
I have been hounting for it whole my life.
Now it is time to study this code.
I will try to find some other links of that.
I am interested just in putting display to about 1280x1024 32-bit and to use AGP or PCI-express basic features directly without BIOS or VESA.
I noticed when i upload frame buffer by
mov dword[0ed000000h], RGBA
it goes four time faster than
mov byte[0ed000000h], A
mov byte[0ed000001h], G
mov byte[0ed000002h], B
mov byte[0ed000003h], R
Of course it is 1clock 32-bit vs 4clocks of 8 - bit.
So i am wondered if AGP is 64-bit wide how can i use that. It would be 2x faster. Does GPU or Motherboard-Chipset-AGP-Part have some kind of DMA. Or can i use MMX registers
mov xmm1, RGBARGBA
mov qword[0ed000000h], xmm1
Righ now i am doing it this way
mov esi,MemBuffer
mov edi,FrameBuffer
mov ecx, 1024*768
cld
rep movsd
How to use FULL SPEED which Agp or Pci-e can give.
http://bos.asmhackers.net/docs/vga_without_bios/
I have been hounting for it whole my life.
Now it is time to study this code.
I will try to find some other links of that.
I am interested just in putting display to about 1280x1024 32-bit and to use AGP or PCI-express basic features directly without BIOS or VESA.
I noticed when i upload frame buffer by
mov dword[0ed000000h], RGBA
it goes four time faster than
mov byte[0ed000000h], A
mov byte[0ed000001h], G
mov byte[0ed000002h], B
mov byte[0ed000003h], R
Of course it is 1clock 32-bit vs 4clocks of 8 - bit.
So i am wondered if AGP is 64-bit wide how can i use that. It would be 2x faster. Does GPU or Motherboard-Chipset-AGP-Part have some kind of DMA. Or can i use MMX registers
mov xmm1, RGBARGBA
mov qword[0ed000000h], xmm1
Righ now i am doing it this way
mov esi,MemBuffer
mov edi,FrameBuffer
mov ecx, 1024*768
cld
rep movsd
How to use FULL SPEED which Agp or Pci-e can give.
Hi,
This still leaves a few options. First, modern video cards do support bus mastering, so you can get the video card to do the transfer while the CPU goes and does other work.
Second, you can hide the transfer so that it looks faster than it actually is using "page flipping". The basic idea is to split display memory into 2 areas, where one area is being displayed and the other isn't. You'd transfer your data to the area that isn't currently being displayed, then tell the video card to start displaying the new data.
Lastly, it's possible to put all sorts of data into "unseen" display memory and construct new video frames of by transfering data from display memory to display memory (without using any AGP/PCI bus bandwidth).
Cheers,
Brendan
You are aware of the difference between SVGA and VGA?AirFlight wrote:I am interested just in putting display to about 1280x1024 32-bit and to use AGP or PCI-express basic features directly without BIOS or VESA.
No - for a default (BIOS) configuration (i.e. without "write combining" caching), it's one 32-bit transfer plus the bus overhead for one transfer over the AGP/PCI bus, compared to 4 seperate 8-bit transfers plus the overhead for 4 transfers over the AGP/PCI bus.AirFlight wrote:I noticed when i upload frame buffer by
mov dword[0ed000000h], RGBA
it goes four time faster than
mov byte[0ed000000h], A
mov byte[0ed000001h], G
mov byte[0ed000002h], B
mov byte[0ed000003h], R
Of course it is 1clock 32-bit vs 4clocks of 8 - bit.
For "rep movsd", if the source and destination are aligned on cache line boundaries (e.g. on a 64 byte boundary) the CPU will automatically transfer entire cache lines. Enabling "write combining" caching won't help here because the CPU's write combining buffers would fill up extremely fast, and multiple writes won't be combined into a single bus transaction because they're already the same size as a cache line. I would suggest that the bottleneck is in the AGP/PCI bus, and nothing you do with code will help improve the speed of the transfer.AirFlight wrote:So i am wondered if AGP is 64-bit wide how can i use that. It would be 2x faster. Does GPU or Motherboard-Chipset-AGP-Part have some kind of DMA. Or can i use MMX registers
mov xmm1, RGBARGBA
mov qword[0ed000000h], xmm1
Righ now i am doing it this way
mov esi,MemBuffer
mov edi,FrameBuffer
mov ecx, 1024*768
cld
rep movsd
This still leaves a few options. First, modern video cards do support bus mastering, so you can get the video card to do the transfer while the CPU goes and does other work.
Second, you can hide the transfer so that it looks faster than it actually is using "page flipping". The basic idea is to split display memory into 2 areas, where one area is being displayed and the other isn't. You'd transfer your data to the area that isn't currently being displayed, then tell the video card to start displaying the new data.
Lastly, it's possible to put all sorts of data into "unseen" display memory and construct new video frames of by transfering data from display memory to display memory (without using any AGP/PCI bus bandwidth).
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.