Hi OS developers,
I have a question about writing to the BGA frame buffer.
With PCI I get 0xFD000008 as an address to write do I have to map this first or can I access it with P2V(...) just as 0xA0000?
Thank you in advance.
Kind regards,
Robert
writing to BGA frame buffer
- JackScott
- Member

- Posts: 1054
- Joined: Thu Dec 21, 2006 3:03 am
- Location: Hobart, Australia
- Mastodon: https://aus.social/@jackscottau
- Matrix: @JackScottAU:matrix.org
- GitHub: https://github.com/JackScottAU
- Contact:
Re: writing to BGA frame buffer
If you're using paging, you'll need to map both the framebuffer and MMIO regions into virtual memory before use, as the PCI BARs are physical addresses. How you achieve this is up to you and your kernel.
Also, are you absolutely sure the PCI BAR ends with an 8? BARs use the lower bits for flags.
Also, are you absolutely sure the PCI BAR ends with an 8? BARs use the lower bits for flags.
Re: writing to BGA frame buffer
Hi Scott,
Thank you for answering. Yes I am sure that it ends with an 8. But what I saw that the real address should be 0xFD000000. Maybe a bug in QEMU.
I am going to try it out to map it.
Kind Regards,
Robert
Thank you for answering. Yes I am sure that it ends with an 8. But what I saw that the real address should be 0xFD000000. Maybe a bug in QEMU.
I am going to try it out to map it.
Kind Regards,
Robert
Re: writing to BGA frame buffer
Hi,
The lowest 4 bits of a memory space BAR (such as a framebuffer) are used for flags. A consequence of this is that the address has to be aligned on a 16-byte boundary, just as the flags in paging structures force the address to be aligned to the system’s page size. In your case, 8 (the fourth bit set) corresponds to the Prefetchable flag, which indicates how you should handle caching, merging accesses, etc. of the mapped memory. You should mask out the flags if you’re just looking for the address. For a complete explanation, see https://wiki.osdev.org/PCI, under the BAR section. In short, the values you are getting are valid, you just need to separate out the address from the extra metadata.
The lowest 4 bits of a memory space BAR (such as a framebuffer) are used for flags. A consequence of this is that the address has to be aligned on a 16-byte boundary, just as the flags in paging structures force the address to be aligned to the system’s page size. In your case, 8 (the fourth bit set) corresponds to the Prefetchable flag, which indicates how you should handle caching, merging accesses, etc. of the mapped memory. You should mask out the flags if you’re just looking for the address. For a complete explanation, see https://wiki.osdev.org/PCI, under the BAR section. In short, the values you are getting are valid, you just need to separate out the address from the extra metadata.
Re: writing to BGA frame buffer
Thank you Ashy5000 for your answer and I going look into the article.
Kind regards,
Robert
Kind regards,
Robert
Re: writing to BGA frame buffer
Hi OS developers,
I still have some problems with mapping BGA physical address to a virtual address. Via PCI I know that the physical address is 0xFD000000 and I have to map this a virtual address.
I tried the following code but OS is crashing.
#define BGA_FB_PADDR 0xFD000000
#define BGA_FB_VADDR 0xFD000000 // Or any unused virtual address (must be 4KB aligned)
#define BGA_FB_SIZE 0x4000000
//#define BGA_FB_SIZE 1024 * 768
void
map_bga (pde_t *pgdir)
{
// Map the frame buffer physical address to a virtual address
// PTE_W = writeable, PTE_U = user mode accessible (if rendering in user space)
if (mappages (pgdir, (void *) BGA_FB_VADDR, BGA_FB_SIZE,
BGA_FB_PADDR, PTE_A | PTE_W) != 0) {
panic("BGA frame buffer mapping failed");
}
}
Do I have to do a kalloc() or has the PCI already reserve physical memory?
I am using xv6 64 bit as the OS to test with.
Can someone tell me what I am doing wrong.
Thanks in advance.
Kind regards,
Robert
I still have some problems with mapping BGA physical address to a virtual address. Via PCI I know that the physical address is 0xFD000000 and I have to map this a virtual address.
I tried the following code but OS is crashing.
#define BGA_FB_PADDR 0xFD000000
#define BGA_FB_VADDR 0xFD000000 // Or any unused virtual address (must be 4KB aligned)
#define BGA_FB_SIZE 0x4000000
//#define BGA_FB_SIZE 1024 * 768
void
map_bga (pde_t *pgdir)
{
// Map the frame buffer physical address to a virtual address
// PTE_W = writeable, PTE_U = user mode accessible (if rendering in user space)
if (mappages (pgdir, (void *) BGA_FB_VADDR, BGA_FB_SIZE,
BGA_FB_PADDR, PTE_A | PTE_W) != 0) {
panic("BGA frame buffer mapping failed");
}
}
Do I have to do a kalloc() or has the PCI already reserve physical memory?
I am using xv6 64 bit as the OS to test with.
Can someone tell me what I am doing wrong.
Thanks in advance.
Kind regards,
Robert
Re: writing to BGA frame buffer
Where in your code is the OS crashing?
If you are using an emulator, or if you have exception handlers set up, what exceptions are generated?
Is your code crashing (I assume you are referring to a triple-fault) when you map the framebuffer, or when you try to access it?
More likely than not, this is an issue with your paging code. If you are using an emulator, can you inspect the TLB to see what your code actually mapped?
You are passing in “pgdir” to mappages. Is this a pointer to a virtual address?
If you are using an emulator, or if you have exception handlers set up, what exceptions are generated?
Is your code crashing (I assume you are referring to a triple-fault) when you map the framebuffer, or when you try to access it?
More likely than not, this is an issue with your paging code. If you are using an emulator, can you inspect the TLB to see what your code actually mapped?
You are passing in “pgdir” to mappages. Is this a pointer to a virtual address?
Re: writing to BGA frame buffer
Hi ashy5000,
Thank you for answering.
I have a xv6 64 bit kernel which things a bit different I think and testing this on a Mac M4 (silicon) with qemu.
I have changed the addressed to:
#define BGA_FB_PADDR 0xFD000000
#define BGA_FB_VADDR 0xFFFFFFFF90000000 // Or any unused virtual address (must be 4KB aligned)
//#define BGA_FB_SIZE 0x4000000
#define BGA_FB_SIZE 1024 * 768
void
map_bga (pde_t *pgdir)
{
// Map the frame buffer physical address to a virtual address
// PTE_W = writeable, PTE_U = user mode accessible (if rendering in user space)
//if (mappages (pgdir, (void *) BGA_FB_VADDR, BGA_FB_SIZE,
if (mappages (pgdir, (void *) BGA_FB_VADDR, BGA_FB_SIZE,
BGA_FB_PADDR, PTE_W | PTE_P) != 0) {
panic("BGA frame buffer mapping failed");
}
}
And it is not crashing anymore but I not seeing a pixel at the screen.
My test is in kernel mode like this in main.c at the main function. I did it also in user mode and have the same problem.
pci_init ();
map_io ();
cprintf ("Status %d\n", BgaIsAvailable ());
// Switch to graphics mode.
BgaSetVideoMode (1024, 768, 8, 1, 1);
unsigned char * lfb = (unsigned char *) (0xFFFFFFFF90000000);
for (int i=100; i<2000; i++)
*(lfb+i) = 40;
I pci enable bga and I get the next message:
cpu0: starting xv6
0 0 0 0
PCI: 0:0.0: 8086
class: 6.0 (Bridge device) irq: 0
0 0 0 0
PCI: 0:1.0: 8086:7000: class: 6.1 (Bridge device) irq: 0
0 0 0 0
PCI: 0:1.1: 8086:7010: class: 1.1 (Mass storage controller) irq: 0
0 0 0 0
PCI: 0:1.3: 8086:7113: class: 6.80 (Bridge device) irq: 9
fd 0 0 8
PCI: 0:2.0: 1234
class: 3.0 (Display controller) irq: 0
Enable BGA
pcicmd reg:0x7
mem region 0: 16777216 bytes at 0xfd000000
mem region 2: 4096 bytes at 0xfebf0000
maybe it has to do with qemu in combination with pci (something with 64 bit or so)?
In a way when I write bytes to 0x90000000 or 0xFFFFFFFF90000000 (virtual address) it does not work.
When I write bytes in banked mode it is working and getting nice results but I want to have a frame buffer because it is way faster.
Could it be a problem in qemu on macOS ?
Thank you in advance,
Kind regards,
Robert
Thank you for answering.
I have a xv6 64 bit kernel which things a bit different I think and testing this on a Mac M4 (silicon) with qemu.
I have changed the addressed to:
#define BGA_FB_PADDR 0xFD000000
#define BGA_FB_VADDR 0xFFFFFFFF90000000 // Or any unused virtual address (must be 4KB aligned)
//#define BGA_FB_SIZE 0x4000000
#define BGA_FB_SIZE 1024 * 768
void
map_bga (pde_t *pgdir)
{
// Map the frame buffer physical address to a virtual address
// PTE_W = writeable, PTE_U = user mode accessible (if rendering in user space)
//if (mappages (pgdir, (void *) BGA_FB_VADDR, BGA_FB_SIZE,
if (mappages (pgdir, (void *) BGA_FB_VADDR, BGA_FB_SIZE,
BGA_FB_PADDR, PTE_W | PTE_P) != 0) {
panic("BGA frame buffer mapping failed");
}
}
And it is not crashing anymore but I not seeing a pixel at the screen.
My test is in kernel mode like this in main.c at the main function. I did it also in user mode and have the same problem.
pci_init ();
map_io ();
cprintf ("Status %d\n", BgaIsAvailable ());
// Switch to graphics mode.
BgaSetVideoMode (1024, 768, 8, 1, 1);
unsigned char * lfb = (unsigned char *) (0xFFFFFFFF90000000);
for (int i=100; i<2000; i++)
*(lfb+i) = 40;
I pci enable bga and I get the next message:
cpu0: starting xv6
0 0 0 0
PCI: 0:0.0: 8086
0 0 0 0
PCI: 0:1.0: 8086:7000: class: 6.1 (Bridge device) irq: 0
0 0 0 0
PCI: 0:1.1: 8086:7010: class: 1.1 (Mass storage controller) irq: 0
0 0 0 0
PCI: 0:1.3: 8086:7113: class: 6.80 (Bridge device) irq: 9
fd 0 0 8
PCI: 0:2.0: 1234
Enable BGA
pcicmd reg:0x7
mem region 0: 16777216 bytes at 0xfd000000
mem region 2: 4096 bytes at 0xfebf0000
maybe it has to do with qemu in combination with pci (something with 64 bit or so)?
In a way when I write bytes to 0x90000000 or 0xFFFFFFFF90000000 (virtual address) it does not work.
When I write bytes in banked mode it is working and getting nice results but I want to have a frame buffer because it is way faster.
Could it be a problem in qemu on macOS ?
Thank you in advance,
Kind regards,
Robert