Map PCI device memory regions

This commit is contained in:
Josh Holtrop 2023-06-10 20:12:46 -04:00
parent 5179b5881b
commit 2935903bae

View File

@ -2,6 +2,7 @@ module hulk.pci;
import hulk.cpu; import hulk.cpu;
import hulk.klog; import hulk.klog;
import hulk.hurl;
import hulk.hurl.a1; import hulk.hurl.a1;
struct Pci struct Pci
@ -37,6 +38,7 @@ struct Pci
void initialize(Address address, ushort vendor_id, ushort device_id) void initialize(Address address, ushort vendor_id, ushort device_id)
{ {
this.address = address;
this.vendor_id = vendor_id; this.vendor_id = vendor_id;
this.device_id = device_id; this.device_id = device_id;
uint reg2 = read_config_register(address, 2u); uint reg2 = read_config_register(address, 2u);
@ -50,6 +52,72 @@ struct Pci
uint reg3 = read_config_register(address, 3u); uint reg3 = read_config_register(address, 3u);
header_type = (reg3 >> 16u) & 0x7Fu; header_type = (reg3 >> 16u) & 0x7Fu;
multifunction = (address.function_nr == 0u) && ((reg3 & (1u << 23u)) != 0u); multifunction = (address.function_nr == 0u) && ((reg3 & (1u << 23u)) != 0u);
if (header_type == 0u)
{
map_memory_regions();
}
}
private void map_memory_regions()
{
uint[2] r;
uint[2] s;
for (uint reg_no = 4u; reg_no <= 9u; reg_no++)
{
/* Read the BAR. */
r[0] = read_config_register(address, reg_no);
/* Skip zeroed BARs. */
if (r[0] == 0u)
{
continue;
}
/* Skip I/O BARs. */
if ((r[0] & 1u) != 0u)
{
continue;
}
bool is_64bit;
uint bar_type = (r[0] >> 1u) & 0x3u;
if (bar_type == 0u)
{
/* 32-bit region. */
r[1] = 0u;
}
else if ((bar_type == 2u) && (reg_no < 9u))
{
/* 64-bit region. */
is_64bit = true;
r[1] = read_config_register(address, reg_no + 1);
}
else
{
continue;
}
/* Determine the region length. */
write_config_register(address, reg_no, 0xFFFF_FFFFu);
s[0] = read_config_register(address, reg_no);
write_config_register(address, reg_no, r[0]);
if (is_64bit)
{
write_config_register(address, reg_no + 1, 0xFFFF_FFFFu);
s[1] = read_config_register(address, reg_no + 1);
write_config_register(address, reg_no + 1, r[1]);
}
else
{
s[1] = 0xFFFF_FFFFu;
}
ulong addr = (cast(ulong)r[0] & 0xFFFF_FFF0u) | (cast(ulong)r[1] << 32u);
ulong length = ~((cast(ulong)s[0] & 0xFFFF_FFF0u) | (cast(ulong)s[1] << 32u)) + 1u;
ulong flags = (r[0] & 0x8) != 0u ? PT_WRITE_THROUGH : 0u;
Hurl.identity_map_range(addr, length, flags);
if (is_64bit)
{
reg_no++;
}
}
} }
} }