Page 1 of 2
How to map vbe buffer
Posted: Fri Aug 12, 2016 7:15 am
by Askodem
Hello, i'm just implemented basic paging, but i don't know how to map my vbe buffer(1024x768x32).
I tried to do this:
Code: Select all
for(uint32_t i = vbe_buff; i < vbe_buff + vbe_height * vbe_width * (vbe_bpp / 8); i++)
{
page_table[i] = (i * 0x1000) | 0b111;
}
But qemu restarts.
Re: How to map vbe buffer
Posted: Fri Aug 12, 2016 7:48 am
by Ch4ozz
Start your QEMU with -d int,cpu_reset and it will create a log file telling you why it tripple faults.
A tripple fault happens when the first exception couldnt get handled, so it will send it again.
If the second exception cant be handled either it will tripplefault and reset the CPU.
Make sure you mapped your whole kernel code.
Re: How to map vbe buffer
Posted: Fri Aug 12, 2016 8:07 am
by Askodem
Ch4ozz wrote:Start your QEMU with -d int,cpu_reset and it will create a log file telling you why it tripple faults.
A tripple fault happens when the first exception couldnt get handled, so it will send it again.
If the second exception cant be handled either it will tripplefault and reset the CPU.
Make sure you mapped your whole kernel code.
Here's the log:
Code: Select all
CPU Reset (CPU 0)
EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
EIP=00000000 EFL=00000000 [-------] CPL=0 II=0 A20=0 SMM=0 HLT=0
ES =0000 00000000 00000000 00000000
CS =0000 00000000 00000000 00000000
SS =0000 00000000 00000000 00000000
DS =0000 00000000 00000000 00000000
FS =0000 00000000 00000000 00000000
GS =0000 00000000 00000000 00000000
LDT=0000 00000000 00000000 00000000
TR =0000 00000000 00000000 00000000
GDT= 00000000 00000000
IDT= 00000000 00000000
CR0=00000000 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=00000000 DR7=00000000
CCS=00000000 CCD=00000000 CCO=DYNAMIC
EFER=0000000000000000
FCW=0000 FSW=0000 [ST=0] FTW=ff MXCSR=00000000
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
CPU Reset (CPU 0)
EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000663
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
EIP=0000fff0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0000 00000000 0000ffff 00009300
CS =f000 ffff0000 0000ffff 00009b00
SS =0000 00000000 0000ffff 00009300
DS =0000 00000000 0000ffff 00009300
FS =0000 00000000 0000ffff 00009300
GS =0000 00000000 0000ffff 00009300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT= 00000000 0000ffff
IDT= 00000000 0000ffff
CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000000 CCD=00000000 CCO=DYNAMIC
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
SMM: enter
EAX=00000001 EBX=0000000b ECX=02000000 EDX=00000cfc
ESI=00000000 EDI=02000000 EBP=00000000 ESP=00006d20
EIP=000f14f5 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 000f6be8 00000037
IDT= 000f6c26 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=000f1030 CCD=00000001 CCO=LOGICB
EFER=0000000000000000
SMM: after RSM
EAX=00000001 EBX=0000000b ECX=02000000 EDX=00000cfc
ESI=00000000 EDI=02000000 EBP=00000000 ESP=00006d20
EIP=000f14f5 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 000f6be8 00000037
IDT= 000f6c26 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000000 CCD=ffffff9c CCO=EFLAGS
EFER=0000000000000000
Re: How to map vbe buffer
Posted: Fri Aug 12, 2016 8:57 am
by sleephacker
It looks like you're treating every single byte in the framebuffer as a page. The number of pages should be the number of bytes / 4096. In your case this should be:
Code: Select all
vbe_height * vbe_width * (vbe_bpp / 8) / 4096
Also, what is vbe_buff? I assume it is the physical address of the framebuffer, in that case you shouldn't multiply by 0x1000 to calculate the physical address, because it already is the physical address, and to calculate the index in your page table you should divide it by 0x1000 (or 4096) instead of leaving it unchanged.
Re: How to map vbe buffer
Posted: Fri Aug 12, 2016 9:32 am
by Askodem
sleephacker wrote:It looks like you're treating every single byte in the framebuffer as a page. The number of pages should be the number of bytes / 4096. In your case this should be:
Code: Select all
vbe_height * vbe_width * (vbe_bpp / 8) / 4096
Also, what is vbe_buff? I assume it is the physical address of the framebuffer, in that case you shouldn't multiply by 0x1000 to calculate the physical address, because it already is the physical address, and to calculate the index in your page table you should divide it by 0x1000 (or 4096) instead of leaving it unchanged.
Thank you for reply. Here's the definitions of vbe stuff:
Code: Select all
uint32_t vbe_width, vbe_height, vbe_bpp, vbe_pitch;
uint8_t* vbe_buff;
I tried the following code:
Code: Select all
for(uint32_t i = vbe_buff; i < vbe_buff + vbe_height * vbe_width * (vbe_bpp / 8) / 4096; i++)
{
page_table[i] = i | 1 | 2 | 4;
}
But it still triple faulting.
Re: How to map vbe buffer
Posted: Fri Aug 12, 2016 10:48 am
by sleephacker
Askodem wrote:I tried the following code:
Code: Select all
for(uint32_t i = vbe_buff; i < vbe_buff + vbe_height * vbe_width * (vbe_bpp / 8) / 4096; i++)
{
page_table[i] = i | 1 | 2 | 4;
}
But it still triple faulting.
If you want "i" to initially be the first page of the framebuffer, you should do:
To then fill in the corresponding address in the page_table you can do:
Code: Select all
page_table[i] = i *0x1000 | 1 | 2 | 4;
But maybe to make your code a bit more readable you could define some "helper" variables to make things less cryptic, like:
Code: Select all
vbe_buff_size = vbe_height * vbe_width * (vbe_bpp / 8)
vbe_first_page = vbe_buff / 0x1000
vbe_page_count = vbe_buff_size / 0x1000
Your for-loop would then end up like:
Code: Select all
for(i = vbe_first_page; i < vbe_first_page + vbe_page_count; i++)
{
page_table[i] = i * 0x1000 | 7; //7 == 1 | 2 | 4
}
EDIT: VBE also gives you a "BytesPerScanLine" variable which you should use to calculate the size of the screen, so the code changes to:
Code: Select all
vbe_buff_size = vbe_height * BytesPerScanLine
see the wiki for more info
Re: How to map vbe buffer
Posted: Fri Aug 12, 2016 11:17 am
by Askodem
Unfortunately, it still doesn't work.
BytesPerScanLine == vbe_pitch, right?
Code: Select all
vbe_pitch = multiboot->framebuffer_pitch;
Here's the full code:
Code: Select all
extern void switch_page_dir(uint32_t*);
extern void enable_paging();
uint32_t page_directory[1024] __attribute__((aligned(4096)));
uint32_t page_table[1024] __attribute__((aligned(4096)));
void init_paging()
{
uint32_t vbe_buff_size = vbe_height * vbe_width * (vbe_bpp / 8) * vbe_pitch;
uint32_t vbe_first_page = (int)vbe_buff / 0x1000;
uint32_t vbe_page_count = vbe_buff_size / 0x1000;
for(int i = 0; i < 1024; i++)
{
page_directory[i] = 0x00000002;
}
for(uint32_t i = 0; i < 1024; i++)
{
page_table[i] = (i * 0x1000) | 3;
}
for(uint32_t i = vbe_first_page; i < vbe_first_page + vbe_page_count; i++)
{
page_table[i] = i * 0x1000 | 7; //7 == 1 | 2 | 4
}
page_directory[0] = ((uint32_t)page_table) | 3;
switch_page_dir(page_directory);
enable_paging();
}
Re: How to map vbe buffer
Posted: Fri Aug 12, 2016 3:47 pm
by sleephacker
Askodem wrote:BytesPerScanLine == vbe_pitch, right?
yep
One issue with this code is the fact that you only have one page table, meaning you can only identity-map the lowest 4MB of memory, while your framebuffer is likely to be located elsewhere.
So you need to be able to map all 4GB (assuming you're using a 32bit address space) in order to map your framebuffer.
Re: How to map vbe buffer
Posted: Fri Aug 12, 2016 11:25 pm
by Askodem
sleephacker wrote:Askodem wrote:BytesPerScanLine == vbe_pitch, right?
yep
One issue with this code is the fact that you only have one page table, meaning you can only identity-map the lowest 4MB of memory, while your framebuffer is likely to be located elsewhere.
So you need to be able to map all 4GB (assuming you're using a 32bit address space) in order to map your framebuffer.
I created 1024 page tables(4096 * 1024 = 4194304 = 4 GB):
Code: Select all
uint32_t page_table[1024][1024] __attribute__((aligned(4096)));
.
Here's the edited code:
Code: Select all
extern void switch_page_dir(uint32_t*);
extern void enable_paging();
uint32_t page_directory[1024] __attribute__((aligned(4096)));
uint32_t page_table[1024][1024] __attribute__((aligned(4096)));
void init_paging()
{
uint32_t vbe_buff_size = vbe_height * vbe_width * (vbe_bpp / 8) * vbe_pitch;
uint32_t vbe_first_page = (int)vbe_buff / 0x1000;
uint32_t vbe_page_count = vbe_buff_size / 0x1000;
for(int i = 0; i < 1024; i++)
page_directory[i] = 0x00000002;
for(uint32_t i = 0; i < 1024; i++)
for(uint32_t j = 0; j < 1024; j++)
page_table[i][j] = (i * 0x1000) | 3;
for(uint32_t i = vbe_first_page; i < vbe_first_page + vbe_page_count; i++)
{
page_table[0][i] = i * 0x1000 | 7; //7 == 1 | 2 | 4
}
for(int i = 0; i < 1024; i++)
page_directory[i] = ((uint32_t)page_table[i]) | 3;
switch_page_dir(page_directory);
enable_paging();
}
Qemu no more restarts. It's just black screen.
Re: How to map vbe buffer
Posted: Sat Aug 13, 2016 1:02 am
by Octacone
Askodem wrote:
Qemu no more restarts. It's just black screen.
That means that the mode has been set successfully, just to make sure compare Qemu's screen size after and before switching.
Try putting some pixels and see if that works (just don't put black ones because you won't be able to see them
)
Re: How to map vbe buffer
Posted: Sat Aug 13, 2016 1:13 am
by Askodem
octacone wrote:Askodem wrote:
Qemu no more restarts. It's just black screen.
That means that the mode has been set successfully, just to make sure compare Qemu's screen size after and before switching.
Try putting some pixels and see if that works (just don't put black ones because you won't be able to see them
)
It doesn't works. I have the working VBE shell. It works without paging.
Re: How to map vbe buffer
Posted: Sat Aug 13, 2016 2:30 am
by Octacone
Askodem wrote:octacone wrote:Askodem wrote:
Qemu no more restarts. It's just black screen.
That means that the mode has been set successfully, just to make sure compare Qemu's screen size after and before switching.
Try putting some pixels and see if that works (just don't put black ones because you won't be able to see them
)
It doesn't works. I have the working VBE shell. It works without paging.
Wait, what doesn't work? Your shell or setting mode?
Re: How to map vbe buffer
Posted: Sat Aug 13, 2016 2:48 am
by Askodem
Wait, what doesn't work? Your shell or setting mode?
All of the above works. Screen resolution changes, but i have black screen.
EDIT: It restarts after 10 seconds.
Re: How to map vbe buffer
Posted: Sat Aug 13, 2016 11:36 am
by sleephacker
Code: Select all
for(uint32_t i = 0; i < 1024; i++)
for(uint32_t j = 0; j < 1024; j++)
page_table[i][j] = (i * 0x1000) | 3;
Should be:
Code: Select all
for(uint32_t i = 0; i < 1024; i++)
for(uint32_t j = 0; j < 1024; j++)
page_table[i][j] = ((i * 1024 + j) * 0x1000) | 3;
Because 'i' only goes up to 1023, so the highest (i * 0x1000) is 0x003FF000, but you want to go all the way up to 0xFFFFF000.
Also, since you have a working shell maybe you can print some of the values to screen. For exemple, the first 4 entries in the page directory, the first 4 entries in the first page table and the first 4 entries after vbe_first_page.
You can print those and then enter an infinite loop before/instead of switching and enabling paging. That way you can see what your code is actually doing, before it enables paging and restarts.
BTW, I noticed that you enable the user bit in all the VBE pages but all the page directory entries don't have this bit set, so usermode still can't access the framebuffer.
Check the wiki for more info.
Re: How to map vbe buffer
Posted: Sat Aug 13, 2016 1:21 pm
by Askodem
Thank you! VBE is now working fine.
Here's the code:
Code: Select all
printf("Before enabling paging:\n");
printf("The first 4 entries in the page directory:\n");
for(int i = 0; i < 4; i++)
printf("Hex: 0x%h, Dec: %d\n", page_directory[i], page_directory[i]);
printf("\nthe first 4 entries in the first page table\n");
for(int i = 0; i < 4; i++)
printf("Hex: 0x%h, Dec: %d\n", page_table[0][i], page_table[0][i]);
printf("\nthe first 4 entries after vbe_first_page:\n");
for(uint32_t i = vbe_first_page; i < vbe_first_page + 4; i++)
printf("Hex: 0x%h, Dec: %d\n", page_table[0][i], page_table[0][i]);
switch_page_dir(page_directory);
enable_paging();
printf("\nAfter enabling paging:\n\n");
printf("The first 4 entries in the page directory:\n");
for(int i = 0; i < 4; i++)
printf("Hex: 0x%h, Dec: %d\n", page_directory[i], page_directory[i]);
printf("\nthe first 4 entries in the first page table\n");
for(int i = 0; i < 4; i++)
printf("Hex: 0x%h, Dec: %d\n", page_table[0][i], page_table[0][i]);
printf("\nthe first 4 entries after vbe_first_page:\n");
for(uint32_t i = vbe_first_page; i < vbe_first_page + 4; i++)
printf("Hex: 0x%h, Dec: %d\n", page_table[0][i], page_table[0][i]);
Here's the output:
http://img4.imagetitan.com/img.php?imag ... per_ru.png
EDIT: updated code and screen.