[SOLVED] Not enough size to map BAR5.

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
avcado
Member
Member
Posts: 55
Joined: Wed Jan 20, 2021 11:32 am
GitHub: https://codeberg.org/minguss

[SOLVED] Not enough size to map BAR5.

Post by avcado »

Hi all,

I'm working on an AHCI driver for some firmware I've been writing the past few weeks. I read the OSDev wiki page for AHCI and implemented an identification procedure. However, I'm running into a problem where the HBA port 0's signature is 0xFFFFFFFF. I realized that the offset of the signature is past how much I can map (by 0x400).

Essentially, I map BAR5 to 0xFA000000 (to 0xFA000FFF). I realized that port 0's signature is at 0xFA001400, which is past how much I map. How am I supposed to map more space, i.e. 8kb? Shouldn't the BAR size be 0x2000? (or something else bigger than 0x1000?)

Debug logs:

Code: Select all

ahci: pci address is 8000fa00 (bus 0 dev 31 fn 0)
pci: BAR size is 00001000
ahci: mapped BAR5 to fa000000
ahci: port 00000000 is good
ahci: port signature is ffffffff
Code:

PCI mapping:

Code: Select all

// Function is called like this in my AHCI init code:
// pci_map_bar(addr, PCI_BAR5, AHCI_BASE_MEM, (1<<2) | (1<<1), PCIBARTYPE_MEMSPACE); 
// which translates to
// pci_map_bar(0x8000fa00, 36, 0xfa000000, (1<<2) | (1<<1), 1); (i think, i may have done the conversion of PCI_BAR5 wrong)
void pci_map_bar(uint32_t pci_addr, uint8_t bar, uint32_t val, uint32_t flags, uint8_t type){
  // Get size of the bar
  uint32_t og_bar = pci_read_dword(pci_addr+bar);
  pci_write_dword(pci_addr+bar, 0xffffffff); // Write all 1s
  uint32_t size = (~(pci_read_dword(pci_addr+bar)))+1;
  dprintf(DEBUG_VERBOSE, "pci: BAR size is %x\n", size);

  // Restore the original bar.
  pci_write_dword(pci_addr+bar, og_bar);

  if(type == PCIBARTYPE_IO){
    pci_write_dword(pci_addr + bar, val | (1<<0)); // Bit 0 always set.
    goto flush;
  }
  pci_write_dword(pci_addr + bar, val); // Tell the PCI config space we want
                                        // to set the BAR to this.

flush:
  // Tell the PCI bus this is correct!
  uint16_t command = pci_read_word(pci_addr + PCI_COMMAND) | flags;
  pci_write_word(pci_addr + PCI_COMMAND, command);
}
AHCI initialization code:

Code: Select all

uint32_t ahci__init(){
  uint32_t addr = pci_does_device_exist(0x01, 0x06); // TODO: some may show themselves as subclass=0x01. Unimplemented.
  dprintf(DEBUG_INFO, "ahci: pci address is %x\n", addr);

  // Map BAR5 to 0xfa000000. This is the start of the host bus adapter memory space.
  pci_map_bar(addr, PCI_BAR5, AHCI_BASE_MEM, (1<<2) | (1<<1), PCIBARTYPE_MEMSPACE);
  dprintf(DEBUG_VERBOSE, "ahci: mapped BAR5 to %x\n", AHCI_BASE_MEM);

  HBA_MEM* mem = (HBA_MEM*)AHCI_BASE_MEM;
  uint32_t pi = mem->pi;
  for(int i = 0; i < 32; i++){
    if(pi & 1){
      uint32_t v = ahci__checktype(&mem->ports[i]); // Get signature of
                                                    // the disk on this port.
      if(v == 0) goto cont; // Not a device, skip!

      dprintf(DEBUG_VERBOSE, "ahci: port %x is good\n", i);
      dprintf(DEBUG_VERBOSE, "ahci: port signature is %x\n", v);

      if(v != IDENT_SATAPI && v != IDENT_SEMB && v != IDENT_PM) return IDENT_SATA;
    }

cont:
    pi >>= 1;
  }
}

uint32_t ahci__checktype(HBA_PORT* port){
  uint32_t ssts = port->ssts;

  uint8_t ipm = (ssts >> 8) & 0x0F;
  uint8_t det = ssts & 0x0F;

  if(ipm != 1 && det != 3) return 0; // No device!

  return port->sig;
}
Why is this happening? Thanks in advance!
Last edited by avcado on Fri Aug 28, 2026 4:18 pm, edited 1 time in total.
projects: minguss/skvn
ashy5000
Posts: 8
Joined: Tue Jun 09, 2026 12:48 am

Re: Not enough size to map BAR5.

Post by ashy5000 »

Hi,

Why are you altering the BAR? Correct me if I’m wrong, but I think those registers are memory mapped I/O and can’t be in main memory. Also, are you using paging? If so, BARs store physical addresses, so you can’t use AHCI_BASE_MEM for PCI and as a virtual memory ptr. Remember that all a PCI device typically sees is physical mem. They don’t know or care about virtualization.

Instead of what you are doing now, you should leave the BARs alone, just allocate some virtual memory and map it via paging to the specified address.

Again, if I am mistaken about any of this, please let me know.
Best of luck!
- Ashy5000
https://github.com/Ashy5000/muse

Live long and prosper!
avcado
Member
Member
Posts: 55
Joined: Wed Jan 20, 2021 11:32 am
GitHub: https://codeberg.org/minguss

Re: Not enough size to map BAR5.

Post by avcado »

Hi,
ashy5000 wrote: Wed Aug 26, 2026 6:12 pm Why are you altering the BAR? Correct me if I’m wrong, but I think those registers are memory mapped I/O and can’t be in main memory.
I'm altering the BAR because they are not mapped.

Code: Select all

  Bus  0, device  31, function 2:
    SATA controller: PCI device 8086:2922
      PCI subsystem 1af4:1100
      IRQ 0, pin A
      BAR4: I/O (not mapped)
      BAR5: 32 bit memory (not mapped)
      id ""
SeaBIOS maps it to 0xfebc4000 so I don't see the problem mapping it to 0xfa000000.
ashy5000 wrote: Wed Aug 26, 2026 6:12 pm Also, are you using paging? If so, BARs store physical addresses, so you can’t use AHCI_BASE_MEM for PCI and as a virtual memory ptr. Remember that all a PCI device typically sees is physical mem. They don’t know or care about virtualization.
No, as I currently don't see a use for paging -- I'm in 32-bit mode.
projects: minguss/skvn
ashy5000
Posts: 8
Joined: Tue Jun 09, 2026 12:48 am

Re: Not enough size to map BAR5.

Post by ashy5000 »

Hi,

I'm pretty sure the ABAR should be mapped without you needing to do anything. Is the log output you gave from before or after you initialized PCI? If you haven't already, I'd recommend setting a breakpoint (or something similar) to check what the BARs look like before your kernel runs. It looks like the logs you provided are from QEMU, which I am also using, but I get a different output:

Code: Select all

Bus  0, device   4, function 0:
  SATA controller: PCI device 8086:2922
    PCI subsystem 1af4:1100
    IRQ 11, pin A
    BAR4: I/O at 0xc040 [0xc05f]
    BAR5: 32 bit memory at 0x81060000 [0x81060fff]
    id "ahci"
I'm using UEFI to boot. You mentioned something about SeaBIOS- is that what you're using? If so, if you say that it sets up the AHCI controller BARs, you can just leave them as they are.
- Ashy5000
https://github.com/Ashy5000/muse

Live long and prosper!
avcado
Member
Member
Posts: 55
Joined: Wed Jan 20, 2021 11:32 am
GitHub: https://codeberg.org/minguss

Re: Not enough size to map BAR5.

Post by avcado »

ashy5000 wrote: Wed Aug 26, 2026 8:14 pm I'm pretty sure the ABAR should be mapped without you needing to do anything. Is the log output you gave from before or after you initialized PCI?
The log output is from before the PCI is mapped or initialized in any way.
ashy5000 wrote: Wed Aug 26, 2026 8:14 pm I'm using UEFI to boot. You mentioned something about SeaBIOS- is that what you're using? If so, if you say that it sets up the AHCI controller BARs, you can just leave them as they are.
As I said in my original post, I'm writing a 32-bit legacy BIOS firmware. SeaBIOS was just an example. QEMU does not set up the BARs, and everything is unmapped when my code is running.
projects: minguss/skvn
avcado
Member
Member
Posts: 55
Joined: Wed Jan 20, 2021 11:32 am
GitHub: https://codeberg.org/minguss

Re: Not enough size to map BAR5.

Post by avcado »

Well. Slight update.

Code: Select all

  return port->sig;
For some reason, this was encoding the WRONG offset! The offset of the port is 0x100, and the signature is at offset 0x24:

Code: Select all

(uint32_t)AHCI_BASE_MEM + port;    // 0xFA000100
offsetof(HBA_PORT, sig);  // 0x24
So, I fixed the code so now it's reading from the proper offset (0xFA000124):

Code: Select all

uint32_t offset = (uint32_t)port + offsetof(HBA_PORT, sig);
// offset is debug printed and is known to be 0x124
return *offset;
However, this still returns 0xFFFFFFFF.

Code: Select all

ahci: port signature is ffffffff
So, now the issue seems to be with my BAR mapping code, I think. I don't see what's wrong with it, but then again the OSDev Wiki didn't provide that much info on how to actually do it -- just a little paragraph...
projects: minguss/skvn
Post Reply