Successful (?) Read from the PCI Bus Configuration

Trying to access PCI bus configuration on Lenovo T60 laptop from BYOK Forth

It looks like if I’m going to get the AHCI SATA access I want, then I’m going to have to learn how to interact with the PCI bus. And I wanted to interact with the bus from Forth itself, rather than having to debug C code. First baby step: to see if I could pull any information from a PCI bus configuration register.

This seems to be fairly simple in principle: configuration access is port-based, with a 32 bit address memory location (CONFIG ADDRESS), and a 32 bit data memory location (CONFIG DATA). Put the correct request information in CA, and pull the data from CD. https://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231.

The tricky part: since this is I/O memory, you have to access it using the Pentium INL and OUTL instructions. BYOK had implemented INB and OUTB, but these are not quite the instructions we wanted, and also they weren’t mapped to Forth words. But thankfully nice examples are available in a gcc library. So, I expanded BYOK’s io.h to…

static inline unsigned char inportb (uint16_t port)
{
    unsigned char rv;
    __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (port));
    return rv;
}

static inline void outportb (uint16_t port, unsigned char data)
{
    __asm__ __volatile__ ("outb %1, %0" : : "dN" (port), "a" (data));
}

/* inport, outportl added by Christopher Howard 2020 */

static inline unsigned int inportl (unsigned short int port)
{
    unsigned int rv;
    __asm__ __volatile__ ("inl %w1, %0" : "=a" (rv) : "dN" (port));
    return rv;
}

static inline void outportl (unsigned int value, unsigned short int port)
{
    __asm__ __volatile__ ("outl %0, %w1" : : "a" (value), "dN" (port));
}

So, then I need to map this to Forth words, and I wasn’t sure where to do that. So, I added them to BYOK’s primitive word list. I wasn’t sure if the author of BYOK would have approved of that particular approach, but better to ask forgiveness later. Inserted the following into io.c:

state_t __INL(context_t *ctx)
{
    unsigned int port;
    if (popnum(ctx->ds, &port))
    {
        port = inportl (port);
        pushnum(ctx->ds, port);
        return OK;
    }
    else
    {
        return stack_underflow(ctx);
    }
}

state_t __OUTL(context_t *ctx)
{
    unsigned short int port;
    unsigned int value;
    if (popnum(ctx->ds, &port) && popnum(ctx->ds, &value))
    {
        outportl (value, port);
        return OK;
    }
    else
    {
        return stack_underflow(ctx);
    }
}

void init_io_words(context_t *ctx)
{
    hashtable_t *htbl = ctx->exe_tok;
    add_primitive(htbl, ".",      __DOT,    "( n -- )", "convert signed number n to string of digits, and output.");
 <...snip...>
    add_primitive(htbl, "INL",   __INL,   "( port -- )", "x86 32-bit read from i/o port");
    add_primitive(htbl, "OUTL",   __OUTL,   "( value port -- )", "x86 32-bit output to i/o port");
}

To my surprise, the code compiled. Now, I needed a Forth function to figure out what is the correct data to put into CA. This is the part I currently am manually typing into the laptop after boot:

hex

cf8 constant CA
cfc constant CD

: pci-cfg-word ( bus slot func offset -- u )
    -80000000
    swap fc and or
    swap 8 lshift or
    swap 11 lshift or
    swap 16 lshift or ;

decimal

In the laptop terminal I entered the following to get the (hopefully) correct address for CA on the stack, which is intended to pull the vendor code from the PCI bus:

0 0 0 0 pci-cfg-word
  ok...

Then load and read:

ca outl
  ok
cd inl
  ok.

Result in hexadecimal:

hex .s
27a08086

Is that information, or garbage? I found the PCI ID Repository on the Internet. If I make the reasonable assumption that the vendor code is in the 16 LSBs, that gives vendor code 0x8086, which matches to “Intel Corporation”. That sounds plausible!

Intel Corporation listing in The PCI ID Repository

Fun stuff!

Advertisement

3 thoughts on “Successful (?) Read from the PCI Bus Configuration”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s