diff --git a/src/hulk/pci.d b/src/hulk/pci.d index 3ce4d1b..94a1211 100644 --- a/src/hulk/pci.d +++ b/src/hulk/pci.d @@ -2,6 +2,7 @@ module hulk.pci; import hulk.cpu; import hulk.klog; +import hulk.hurl; import hulk.hurl.a1; struct Pci @@ -37,6 +38,7 @@ struct Pci void initialize(Address address, ushort vendor_id, ushort device_id) { + this.address = address; this.vendor_id = vendor_id; this.device_id = device_id; uint reg2 = read_config_register(address, 2u); @@ -50,6 +52,72 @@ struct Pci uint reg3 = read_config_register(address, 3u); header_type = (reg3 >> 16u) & 0x7Fu; 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++; + } + } } }