Accessing VBE mode after paging

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Accessing VBE mode after paging

Post by Creature »

Hello,

I have another question for you (this might sound crappy though); I've been searching for a while for this and it's probably right under my nose but I just can't seem to find it; I had VBE mode a while back (it worked), but this was before I set up paging and the stack. When I try to access the linear framebuffer address of VBE mode (0xE0000000) now, I get a page fault (page wasn't present). I've tried making the page table and allocating frames for it (I used JamesM's tutorials) and this does take care of the page fault, but still nothing is drawn on the screen (I can switch video modes).

What am I doing wrong? If you would like to see the code, please do ask for it and I will post it.

Thanks for your time,
Creature
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
giszo
Member
Member
Posts: 124
Joined: Tue Nov 06, 2007 2:37 pm
Location: Hungary

Re: Accessing VBE mode after paging

Post by giszo »

Hi!

You have to select a memory region that is unmapped and fits the size of the VBE framebuffer. After this, create the page table(s) for this memory region. And as the last step you have to map the pages in this memory region to the VBE address (0xE0000000) by putting the right addresses with the right flags to the create page table(s).

giszo
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: Accessing VBE mode after paging

Post by Creature »

So basically what you're saying is that instead of this (rewritten version of JamesM's paging initialization function):

Code: Select all

unsigned i = 0;

for(i = HEAP_STARTADDRESS; i < HEAP_STARTADDRESS + HEAP_START_SIZE; i += PAGE_SIZE)
	GetPage(i, true, KernelDir);

i = 0;

while(i < (CurMemAddress + PAGE_SIZE))
{
	AllocFrame(GetPage(i, true, KernelDir), 0, 0);
	i += PAGE_SIZE;
}

for(i = HEAP_STARTADDRESS; i < HEAP_STARTADDRESS + HEAP_START_SIZE; i += PAGE_SIZE)
	AllocFrame(GetPage(i, true, KernelDir), 0, 0);
I should also map the memory addresses of the VBE linear framebuffer (640 * 320 * 4 are the amount of bytes occupied by the screen, my screen is 640x320x32)?

Code: Select all

for(i = HEAP_STARTADDRESS; i < HEAP_STARTADDRESS + HEAP_START_SIZE; i += PAGE_SIZE)
	GetPage(i, true, KernelDir);

for(i = VBE_LFB_PHYSICAL_ADDRESS; i < VBE_LFB_PHYSICAL_ADDRESS + 640 * 320 * 4; i += PAGE_SIZE)
	GetPage(i, true, KernelDir);

i = 0;

while(i < (CurMemAddress + PAGE_SIZE))
{
	AllocFrame(GetPage(i, true, KernelDir), 0, 0);
	i += PAGE_SIZE;
}

for(i = VBE_LFB_PHYSICAL_ADDRESS; i < VBE_LFB_PHYSICAL_ADDRESS + 640 * 320 * 4; i += PAGE_SIZE)
	AllocFrame(GetPage(i, true, KernelDir), 0, true);

for(i = HEAP_STARTADDRESS; i < HEAP_STARTADDRESS + HEAP_START_SIZE; i += PAGE_SIZE)
	AllocFrame(GetPage(i, true, KernelDir), 0, 0);
This does indeed fix the page-fault, but still nothing seems to appear on my screen. I'm also not sure what you mean with
giszo wrote: And as the last step you have to map the pages in this memory region to the VBE address (0xE0000000) by putting the right addresses with the right flags to the create page table(s).
How would I go about doing that? Can you post an example?

Thanks again for your patience,
Creature
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
giszo
Member
Member
Posts: 124
Joined: Tue Nov 06, 2007 2:37 pm
Location: Hungary

Re: Accessing VBE mode after paging

Post by giszo »

Unfortunately I've never read JamesM's tutorial so I don't know what GetPage() and AllocFrame() functions do.

But what you should do is basically this (the page table(s) have to be allocated before this):

Code: Select all

addr = 0xE0000000;
map_to = address_you_found_unmapped;

for ( i = 0; i < size_to_map; i += PAGE_SIZE, addr += PAGE_SIZE, map_to += PAGE_SIZE ) {
    page_table = get_page_table( page_directory, map_to );
    page_table[ map_to >> 22 ] = addr | PRESENT;
}
giszo
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: Accessing VBE mode after paging

Post by Creature »

In case it's of any assistance (while I'm trying out what you said), here's the code for GetPage:

Code: Select all

Page *GetPage(unsigned Address, bool Make, PageDirectory *Dir)
{
	Address /= PAGE_SIZE;					/* Convert Address to an ID. */

	unsigned TableID = Address / 1024;		/* Find the page table with this address. */

	/* Is this table already assigned? */
	if(Dir->Tables[TableID])
		return (&Dir->Tables[TableID]->Table[Address % 1024]);

	/* Should the page table be created? */
	else if(Make)
	{
		unsigned Tmp = 0;

		Dir->Tables[TableID] = reinterpret_cast<PageTable *>(Memory->AllocAlignPhys(sizeof(PageTable), &Tmp));

		Memory->Set(Dir->Tables[TableID], 0, PAGE_SIZE);

		/* Pass the physical address and enable the first 7 bits (1 = Present, 2 = PAGE_ACCESS_READWRITE, 4 = UserMode). */
		Dir->TablesPhysAddr[TableID] = Tmp | 0x7;

		return &Dir->Tables[TableID]->Table[Address % 1024];
	}

	return 0;
}
And for AllocFrame:

Code: Select all

bool AllocFrame(Page *ThePage, bool Kernel, bool Writable)
{
	/* Has the page already been allocated? */
	if(ThePage->FrameAddress)
		return false;

	unsigned Index = FindFirstFreeFrame();

	/* Do some crazy unsigned Magic to see if there any free frames. */
	if(Index == (unsigned) -1)
		return false;

	SetFrameBit(Index * PAGE_SIZE);

	ThePage->Present = true;
	ThePage->Access = (Writable? PAGE_ACCESS_READWRITE : PAGE_ACCESS_READONLY);
	ThePage->UserMode = (Kernel? false : true);
	ThePage->FrameAddress = Index;
	ThePage->Size = PAGE_SIZE;

	return true;
}
And my structures look like this:

Code: Select all

/* Bitfield structure representing a page. */
struct Page
{
	unsigned Present		: 1;		/* Indicicates whether the Page is present. */
	unsigned Access			: 1;		/* In what ways is this Page accessible? See PageAccessMode for values. */
	unsigned UserMode		: 1;		/* Indicates whether the Page is supervisor mode only (Cleared) or not (Set). */
	unsigned WriteThrough	: 1;		/* Controls whether write-through caching is enabled (set to 0 for write-back caching). */
	unsigned DisableCache	: 1;		/* Can the page be cached? */
	unsigned Accessed		: 1;		/* Indicates whether the Page has been accessed (since the last refresh). */
	unsigned Dirty			: 1;		/* Indicates whether the Page is dirty (has been written to [since the last refresh]). */
	unsigned Size			: 1;		/* Size of the page. If 0, the size is 4 kB (PAGE_SIZE). */
	unsigned Global			: 1;		/* Is this page global (can be used to prevent flushing when i.e. task-switching occurs). */
	unsigned Unused			: 3;		/* 3 Unused bits, can be used for other purposes. */
	unsigned FrameAddress	: 20;		/* 20 Bits representing the frame address of the page (shifted 12 bits to the right). */
} ;

/* Represents a page table (table of 1024 PageS). */
struct PageTable
{
	Page Table[1024];
};

/* Represent an entire page directory. */
struct PageDirectory
{
	PageTable *Tables[1024];			/* Holds the page tables. */
	unsigned TablesPhysAddr[1024];		/* Holds the physical addresses of the page tables. */
	unsigned PhysAddr;					/* The physical address of the 'TablesPhysAddr' variable. */
};
Creature
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Accessing VBE mode after paging

Post by Combuster »

What you're doing is allocating RAM and putting it on the virtual location of the video card, then access it.
That means that the area is present, but goes to RAM rather than the video card.

Instead you will have to create your own paging function that maps a given area of virtual memory to a given area of physical memory. In other words, you define a range, say 0xD000000-0xD0400000 where you want to be accessing the video card, then set up the page tables so that e.g. 0xD0000000-0xD0400000 point to 0xE0000000-0xE0400000 or wherever else VBE told you the framebuffer is
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: Accessing VBE mode after paging

Post by Creature »

Combuster wrote:What you're doing is allocating RAM and putting it on the virtual location of the video card, then access it.
That means that the area is present, but goes to RAM rather than the video card.

Instead you will have to create your own paging function that maps a given area of virtual memory to a given area of physical memory. In other words, you define a range, say 0xD000000-0xD0400000 where you want to be accessing the video card, then set up the page tables so that e.g. 0xD0000000-0xD0400000 point to 0xE0000000-0xE0400000 or wherever else VBE told you the framebuffer is
I understand most of what you're saying the only thing that's getting me stuck is the mapping. I have no idea how to go about mapping page tables to memory addresses. You're probably thinking I should read the manual over (maybe I should, memory isn't really my thing).
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
giszo
Member
Member
Posts: 124
Joined: Tue Nov 06, 2007 2:37 pm
Location: Hungary

Re: Accessing VBE mode after paging

Post by giszo »

Creature wrote:
Combuster wrote:What you're doing is allocating RAM and putting it on the virtual location of the video card, then access it.
That means that the area is present, but goes to RAM rather than the video card.

Instead you will have to create your own paging function that maps a given area of virtual memory to a given area of physical memory. In other words, you define a range, say 0xD000000-0xD0400000 where you want to be accessing the video card, then set up the page tables so that e.g. 0xD0000000-0xD0400000 point to 0xE0000000-0xE0400000 or wherever else VBE told you the framebuffer is
I understand most of what you're saying the only thing that's getting me stuck is the mapping. I have no idea how to go about mapping page tables to memory addresses. You're probably thinking I should read the manual over (maybe I should, memory isn't really my thing).
The way how you should do the mapping is basically described by the above code from me ;)
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: Accessing VBE mode after paging

Post by Creature »

Yes, but how do I set up the page tables that way ;)? I first create the pages, then allocate frames for them, but where can I set the physical address they are pointing to? The most logic answer would be TablesPhysAddr inside the PageDirectory, but I don't know which index represents the part I've requested or how to find it.
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
giszo
Member
Member
Posts: 124
Joined: Tue Nov 06, 2007 2:37 pm
Location: Hungary

Re: Accessing VBE mode after paging

Post by giszo »

Creature wrote:Yes, but how do I set up the page tables that way ;)? I first create the pages, then allocate frames for them, but where can I set the physical address they are pointing to? The most logic answer would be TablesPhysAddr inside the PageDirectory, but I don't know which index represents the part I've requested or how to find it.
In this case maybe you should really check the Intel manuals first :)
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Accessing VBE mode after paging

Post by Combuster »

[quotez]I first create the pages, then allocate frames for them,[/quote]
You're mixing up the physical memory manager and the virtual memory manager.

The physical memory manager governs what areas of RAM are in use. RAM is divided into page-sized chunks, or frames. Video memory is not normal RAM - and therefore allocating video ram is an independent process of getting frames.
Whether or not video memory goes through the physical memory manager is up to you - you can simply have drivers use the areas of physical memory they require, or you can have some safe checking that there aren't any conflicts (i.e. overlap with RAM, or an earlier allocation).

On the other hand there is the virtual memory management. It deals with the page directories and page tables and their contents. The virtual memory manager defines where what bit of memory is pointing to.

For RAM, you define a location where you want to read and write, and then ask the physical memory manager for the physical address of a frame. The virtual memory manager will then point the entry at the virtual index to the corresponding physical address. This is what AllocFrame does: you give it a virtual address, and it will put some unused RAM in that location.

For video memory, you want to specify not only the virtual address, but also the physical address as you know exactly what part you want to have.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
gzaloprgm
Member
Member
Posts: 141
Joined: Sun Sep 23, 2007 4:53 pm
Location: Buenos Aires, Argentina
Contact:

Re: Accessing VBE mode after paging

Post by gzaloprgm »

The problem you have using your code is that JamesMolloy code maps the pages you tell to the first free frame, so if you write to video ram you won't get the error but you won't draw to screen.

To draw to screen you need to "force" the page/s from vbe memory to refer to correct physical location.

You can add try adding this function:

Code: Select all

void force_frame(page_t *page, int is_kernel, int is_writeable, unsigned int addr){
	page->present = 1;
	page->rw = (is_writeable)?1:0;
	page->user = (is_kernel)?0:1;
	page->frame = addr>>12;
	set_frame(addr);
}
And then do someting like this before switching pages:

Code: Select all

int i = 0xE0000000;
while(i<0xE00EA600){
	page_t *n = get_page(i,1,kernel_directory);
	force_frame( n,0,0, i);
	i+=0x1000;
}
Remember to create a bitset that's big enough to cover your video memory.

Cheers,
Gonzalo
Visit https://gzalo.com : my web site with electronic circuits, articles, schematics, pcb, calculators, and other things related to electronics.
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: Accessing VBE mode after paging

Post by Creature »

Yes! Thanks a lot, that's what I was looking for. I understood what you all said but wasn't really sure how to implement it in my code. Now it makes much more sense, with the frame address shifted 12 bits to right and the force frame.

For those wondering how to do this in the future, this is how I modified JamesM's code:

Code: Select all

/*
 * The heap functions are from JamesM's tutorials. VBE_LFB_PHYSICAL_ADDRESS represents 0xE0000000.
 * Display is an object holding some information about the current video mode created by the Bochs
 * graphics adapter and VBE. BytesPerPixel = (BitsPerPixel/8) -> (each pixel represents BytesPerPixel bytes).
 */

unsigned i = 0;

for(i = HEAP_STARTADDRESS; i < HEAP_STARTADDRESS + HEAP_START_SIZE; i += PAGE_SIZE)
	GetPage(i, true, KernelDir);

for(i = VBE_LFB_PHYSICAL_ADDRESS; i < VBE_LFB_PHYSICAL_ADDRESS + Display->Width * Display->Height * Display->BytesPerPixel; i += PAGE_SIZE)
{
	Page *TmpPage = GetPage(i, true, KernelDir);
	ForceFrame(TmpPage, false, true, i);
}

i = 0;

while(i < (CurMemAddress + PAGE_SIZE))
{
	AllocFrame(GetPage(i, true, KernelDir), 0, 0);
	i += PAGE_SIZE;
}

for(i = HEAP_STARTADDRESS; i < HEAP_STARTADDRESS + HEAP_START_SIZE; i += PAGE_SIZE)
	AllocFrame(GetPage(i, true, KernelDir), 0, 0);
I finally got it to work, thanks!
Creature
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
Post Reply