Problem with PCI on QEMU

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
wxwisiasdf
Member
Member
Posts: 34
Joined: Sat Sep 07, 2019 5:17 pm
Libera.chat IRC: Superleaf1995

Problem with PCI on QEMU

Post by wxwisiasdf »

I'm enumerating PCI by myself, configuring buses like there was no tommorrow, and playing a game called "Who is behind that PCI bus?".

However, i started writing some drivers, and then when i wrote the rtl driver:..

Code: Select all

(qemu) info pci
  Bus  0, device   0, function 0:
    Host bridge: PCI device 1b36:0008
      PCI subsystem 1af4:1100
      id ""
  Bus  0, device   1, function 0:
    VGA controller: PCI device 1234:1111
      PCI subsystem 1af4:1100
      BAR0: 32 bit prefetchable memory at 0x4b000000 [0x4bffffff].
      BAR2: 32 bit memory at 0x40001000 [0x40001fff].
      BAR6: 32 bit memory at 0xffffffffffffffff [0x0000fffe].
      id ""
  Bus  0, device   2, function 0:
    Ethernet controller: PCI device 10ec:8139
      PCI subsystem 1af4:1100
      IRQ 0, pin A
      BAR0: I/O at 0x45000100 [0x450001ff].
      BAR1: 32 bit memory at 0x40002100 [0x400021ff].
      BAR6: 32 bit memory at 0xffffffffffffffff [0x0003fffe].
      id ""
This is fine at first point, but oh no, qemu hates me now:

Code: Select all

(qemu) Invalid access at addr 0x45000152, size 1, region '(null)', reason: rejected
I honestly want to believe this is a bug with QEMU and not my OS PCI BAR allocator being weird.
No paging is enabled, kernel is multitasking but PCI enumeration occurs before scheduling the kernel.
I don't see any heap corruption. The BARs cannot be faulty tho, because they do not overlap.
The BARs are correctly aligned (the spec says that BARs must be aligned to their size, so 4096 byte bar is aligned to 4096 bytes).
The device is not behind a PCI bridge, this is managed by the root PCI controller, which spans the whole MMIO area, enough right?
Yes, bus mastering is enabled, and yes, IO and MEM register accesses are enabled too.
This is the first command send - write 0x00 to register 0x52 of the RTL to power it on.
And this is not x86, this is RISC-V (64 bits), So no BIOS or ACPI.

If this is a IO error, then why does my VGA driver work?, It can initialize anything and (sucessfuly) manage to resize the screen to any resolution.

In the other part, the rtl8139 driver dies like there was no tommorrow.

The code who causes this is here:

Code: Select all

	case PCI_TURN_ON:
		/* Turn on the device */
		mmio_write8(io+0x52,0x00);
Which in turn calls:

Code: Select all

void mmio_write8(uint8_t * port, uint8_t value) {
	(*port) = value;
}
And this causes a load fault :)
:-)
User avatar
qookie
Member
Member
Posts: 72
Joined: Sun Apr 30, 2017 12:16 pm
Libera.chat IRC: qookie
Location: Poland

Re: Problem with PCI on QEMU

Post by qookie »

As far as I can see you allocated 0x45000152 for the IO bar and are trying to access it as if it's MMIO. To access it (on x86) you have to use in/out instructions (which limits the max address to 0xFFFF), or on other architectures, access them through the host bridge IO window (IO window host addr + IO port) if one exists.

BTW, what are you targeting that requires you to allocate BARs manually?
EDIT: oops, missed the part where you said you're targeting RISC-V, sorry.
Working on managarm.
User avatar
Demindiro
Member
Member
Posts: 96
Joined: Fri Jun 11, 2021 6:02 am
Libera.chat IRC: demindiro
Location: Belgium
Contact:

Re: Problem with PCI on QEMU

Post by Demindiro »

I've stumbled upon this issue and after some hairloss I've figured out what to do (I think). I'm aware this thread is several months old but it shows up in Google searches so I figure it's still worth answering.

First: RISC-V doesn't have I/O ports, it only has MMIO. You should ignore any I/O space BARs as you can't use them and stick to memory space BARs.

Second: maybe you got this right, but you have to ensure the addresses are in a valid MMIO range, which you can get from the

Code: Select all

ranges
property in the FDT.

As for why BARs need to be set manually: they're 0 (minus flags) by default in QEMU at least, so you need to set them yourself.
My OS is Norost B (website, Github, sourcehut)
My filesystem is NRFS (Github, sourcehut)
User avatar
qookie
Member
Member
Posts: 72
Joined: Sun Apr 30, 2017 12:16 pm
Libera.chat IRC: qookie
Location: Poland

Re: Problem with PCI on QEMU

Post by qookie »

Demindiro wrote: You should ignore any I/O space BARs as you can't use them and stick to memory space BARs.
This is not quite right. The device tree "ranges" property may also specify a window that's MMIO on the parent (CPU) side, but port IO on the child (PCI bus) side. This is accomplished by having bits 65-64 (since for PCI nodes child addresses are 96 bits long) of the child address be set to 01 (as opposed to 10 or 11 for memory windows).

To take advantage of this, use the child address as the base of the port you write into the BAR, then when you want to access the "ports" just write to window at the specified host address + any offset you also applied on the child side.
Working on managarm.
Post Reply