Page 2 of 3

Posted: Wed Dec 06, 2006 12:53 pm
by AirFlight
Yes you are right. You could jump into V86 too, but i just don't like V86 they could make it better.

Re: Compiling VGABIOS

Posted: Wed Dec 06, 2006 5:33 pm
by Walling
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.
My own sentence made me think and I came up with an idea. For now it actually seems to work:
  • 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.
I have some sort of working code... in Bochs. I managed to call the GET SVGA INFORMATION function and get a structure back filled with info. Don't know if it works for real systems though. But it is exciting. :)

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.

Posted: Wed Dec 06, 2006 7:07 pm
by Ready4Dis
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.

Posted: Wed Dec 06, 2006 7:08 pm
by bubach
Maybe you could try something like this:
http://www.osdev.org/phpBB2/viewtopic.php?t=10321 ?

Posted: Wed Dec 06, 2006 7:14 pm
by Walling
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?
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).
bubach wrote:Maybe you could try something like this:
http://www.osdev.org/phpBB2/viewtopic.php?t=10321 ?
Looks interesting at first glance. Have to look a bit closer on it.. tomorrow.

Posted: Thu Dec 07, 2006 7:30 am
by Ready4Dis
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.

Posted: Thu Dec 07, 2006 10:09 am
by xdopamine
Hi,

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

Posted: Thu Dec 07, 2006 10:51 am
by Walling
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.
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.

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.
You can also call other sub-functions of interrupt 0x10. But then I tried to call INT 0x16, AH = 0x00 (read character input from keyboard). It does not work because it enables interrupts (the STI instruction). Then hell breaks loose... :? I don't know if it can be solved. For now hardware interrupts must be disabled at all time. I have to test some more VESA functions. And still.. I have only tried it in Bochs.

Posted: Thu Dec 07, 2006 1:55 pm
by Ready4Dis
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.

Posted: Thu Dec 07, 2006 2:32 pm
by AirFlight
Hey, OMG Core did you just did it without BIOS and VESA. :shock: .

Posted: Thu Dec 07, 2006 3:32 pm
by Walling
AirFlight wrote:Hey, OMG Core did you just did it without BIOS and VESA. :shock: .
Because he accesses the "VMWare graphics card" directly, I think. Like you can access the VGABIOS in Bochs directly. But I don't think it works in general.

Posted: Thu Dec 07, 2006 5:02 pm
by Dex
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 :roll: , 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.

Posted: Fri Dec 08, 2006 5:44 am
by Toaster
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 :roll: , 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! :wink:
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

Posted: Fri Dec 08, 2006 10:58 am
by AirFlight
Thank you,
http://bos.asmhackers.net/docs/vga_without_bios/
I have been hounting for it whole my life. :D
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.

Posted: Fri Dec 08, 2006 12:07 pm
by Brendan
Hi,
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.
You are aware of the difference between SVGA and VGA?
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.
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: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
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.

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