Page 1 of 1

How to trap PCI config space access

Posted: Thu Mar 06, 2008 2:52 pm
by sawdust
Hi,
What is a good way to trap PCI config space access? If someone tries to read PCI config space for a particular device, I want to return invalid values.

My CPU is ADM Opteron.

TIA :)

Posted: Thu Mar 06, 2008 3:06 pm
by JamesM
Don't map that particular device into virtual memory? Remember that the pci config space exists in physical memory only. You have the choice of what you expose to a user program.

Posted: Thu Mar 06, 2008 4:21 pm
by sawdust
Don't map that particular device into virtual memory
My experiment is different. Pl. assume that the device is already setup and someone is trying to access its config space.

Posted: Thu Mar 06, 2008 4:53 pm
by exkor
JamesM wrote:Remember that the pci config space exists in physical memory only.
And remeber that you can use I/O(inportp,outportb). The guy didn't say who, from where, how and with which privilege device gets accessed.
Not sure but think that up to PCI 2.2 devices are accessed only with I/O. (Would like to write enumeration thru memory someday)

Re: How to trap PCI config space access

Posted: Thu Mar 06, 2008 9:53 pm
by Brendan
Hi,
sawdust wrote:What is a good way to trap PCI config space access? If someone tries to read PCI config space for a particular device, I want to return invalid values.
Using kernel API function/s for PCI configuration space access is a very good idea, because there's reentrancy problems (e.g. device driver #1 sets the "address" I/O port, then device driver #2 sets the "address" I/O port, then device driver #1 reads from the "data" I/O port and gets data from the wrong place). It's also good to have some abstraction, because there's 3 different ways to access PCI configuration space - "mechanism #1" and "mechanism #2" (which are similar but incompatible) and the new method introduced with PCI Express (where PCI configuration space is mapped into the physical address space and "mechanism #1" is used for backward compatability).

If you need to prevent device drivers from bypassing the kernel API functions and accessing PCI configuration space directly, then you need to control which I/O ports (and which parts of the physical address space) the device drivers, etc can access, and then give them no access to PCI configuration space.

In general this is impossible to do if device drivers run at CPL=0, because it's impossible to prevent any CPL=0 code from accessing any I/O ports (or anything else). Note: there are ways (e.g. write your own secure compiler and force people to use it, or use virtualisation) but they are extrememly difficult and time consuming to implement.

If device drivers don't run at CPL=0 then you can set IOPL and either use the I/O permission bitmap in the TSS or emulate I/O port instructions in the general protection fault handler, so that the kernel can control which I/O ports each device driver can access.


Cheers,

Brendan

Posted: Thu Mar 06, 2008 10:38 pm
by sawdust
Brendan,
Just now I looked in 'AMD Bios Dev manual' that an MSR could be used to trap config space access and generate an SMI (SmiOnRdEn). But I'm not sure how to implement an SMI handler. Any thoughts?
TIA

Posted: Fri Mar 07, 2008 2:03 pm
by Brendan
Hi,

sawdust wrote:Just now I looked in 'AMD Bios Dev manual' that an MSR could be used to trap config space access and generate an SMI (SmiOnRdEn). But I'm not sure how to implement an SMI handler. Any thoughts?
Sure... :D

Once upon a time there was nice little fairy called APM, who would handle things like power management and expect very little from others. An SMI from the chipset would wake up the APM fairy, and it'd do whatever it needed to do without bothering anyone, and in this way everything worked well (but the SMI sent the CPU/s into a special mode called SMM that only the APM fairy could use).

Then, along came a big hairy monster called ACPI. This monster is so messy that only the richest knights (and the most insane drunkards) are willing to go near it. The ACPI monster spends most of it's time asleep. To wake it up you need to cast the curse of a thousand curse words. Once it's awake, it eats the APM fairy. Then, when an SMI occurs it eats them too and spits out something called an SCI instead. The OS needs to handle these SCIs (which is a lot of work - it involves running through an obstacle course created by the ACPI monster whilst trying not to be crushed by the ACPI monsters giant tentacles).

Ok - time to be serious...

To get the chipset to generate an SMI you'd first have to make sure the chipset isn't already using the I/O port access trap/s for other purposes (like emulating PS/2 keyboard when a USB keyboard is present, or emulating a PIT when only HPET is present, etc). This alone means you must support USB, HPET, etc natively, so that emulation (for backward compatability purposes) isn't necessary.

Then you'd need to enable ACPI so that your code can get the SCI (instead of having APM handle the SMI). Then you'd need to support ACPI's AML code (which is an interpretted byte-code that does what APM used to do, and some other stuff), so that the computer still works (e.g. doesn't overheat because power management stopped working). After all this you could add your own code to detect if the I/O port trap caused the SCI (if the trap isn't used for something else) and emulate the I/O port access.

Finally, after years of work, it'd only work computers with modern AMD CPUs. AFAIK there's similar I/O port traps in Intel chipsets, but it's "chipset specific" (and not "CPU model" specific), so it'd be harder to setup. I'm also not sure how you'd go with other manufacturers (e.g. VIA's chipsets and CPUs).

Of course with device drivers running at CPL=0, a device driver could just disable your trap anyway, so it's only useful when it's not useful (ie. if device drivers can be trusted to do the right thing then the trap isn't necessary, and if device drivers can't be trusted to do the right thing then they can't be trusted to leave your trap alone).

Basically, if you trust device drivers then you don't need to trap PCI configuration space access or worry about them doing anything else that could be considered malicious, and you could run them at CPL=0 in kernel space (e.g. monolithic kernel). Otherwise, if you don't trust device drivers then you're screwed unless you run them at CPL=3 (e.g. micro-kernel).

So, the real question here is: do you trust the device drivers?

For me the answer is "no, I don't trust the device drivers". This is because (regardless of whether I like it or not) some companies will only provide binary device drivers (due to intellectual property reasons, patents, etc). Therefore I need to be prepared to handle anonymous binary blobs written by people I've never even met, and need a micro-kernel because I can't really trust these anonymous binary blobs.

For Linux the answer is "yes, we trust the device drivers", which is why they really need open source device drivers that actually can be trusted (not "anonymous binary blobs" that could smash their poor defenseless little kernel into millions of bits faster than you can blink). :roll:


Cheers,

Brendan

Posted: Fri Mar 07, 2008 2:15 pm
by bewing
Awwwww! The poor little APM fairy! :bigcry:
And the curse of a thousand curse words? :shock:

Hehe! You've definitely got a talent for that, Brendan. I still think you should do a cost/benefit analysis before stripping the insulation off your wires, though.

Posted: Thu Mar 13, 2008 5:58 am
by zaleschiemilgabriel
Brendan wrote:Ok - time to be serious...
But I liked the story. :cry:

Posted: Thu Mar 13, 2008 10:02 am
by lukem95
zaleschiemilgabriel wrote:
Brendan wrote:Ok - time to be serious...
But I liked the story. :cry:
same!