Skip to content
Advertisement

Accessing memory pointers in hardware registers

I’m working on enhancing the stock ahci driver provided in Linux in order to perform some needed tasks. I’m at the point of attempting to issue commands to the AHCI HBA for the hard drive to process. However, whenever I do so, my system locks up and reboots. Trying to explain the process of issuing a command to an AHCI drive is far to much for this question. If needed, reference this link for the full discussion (the process is rather defined all over because there are several pieces, however, ch 4 has the data structures necessary).

Essentially, one writes the appropriate structures into memory regions defined by either the BIOS or the OS. The first memory region I should write to is the Command List Base Address contained in the register PxCLB (and PxCLBU if 64-bit addressing applies). My system is 64 bits and so I’m trying to getting both 32-bit registers. My code is essentially this:

void __iomem * pbase = ahci_port_base(ap);
u32 __iomem *temp = (u32*)(pbase + PORT_LST_ADDR);
struct ahci_cmd_hdr *cmd_hdr = NULL;

cmd_hdr = (struct ahci_cmd_hdr*)(u64)
    ((u64)(*(temp + PORT_LST_ADDR_HI)) << 32 | *temp);

pr_info("%s:%d cmd_list is %pn", __func__, __LINE__, cmd_hdr);
// problems with this next line, makes the system reboot
//pr_info("%s:%d cl[0]:0x%08xn", __func__, __LINE__, cmd_hdr->opts);

The function ahci_port_base() is found in the ahci driver (at least it is for CentOS 6.x). Basically, it returns the proper address for that port in the AHCI memory region. PORT_LST_ADDR and PORT_LST_ADDR_HI are both macros defined in that driver. The address that I get after getting both the high and low addresses is usually something like 0x0000000037900000. Is this memory address in a space that I cannot simply dereference it?

I’m hitting my head against the wall at this point because this link shows that accessing it in this manner is essentially how it’s done.

Advertisement

Answer

The address that I get after getting both the high and low addresses is usually something like 0x0000000037900000. Is this memory address in a space that I cannot simply dereference it?

Yes, you are correct – that’s a bus address, and you can’t just dereference it because paging is enabled. (You shouldn’t be just dereferencing the iomapped addresses either – you should be using readl() / writel() for those, but the breakage here is more subtle).

It looks like the right way to access the ahci_cmd_hdr in that driver is:

struct ahci_port_priv *pp = ap->private_data;
cmd_hdr = pp->cmd_slot;
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement