1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <efi/types.h> 6#include <efi/protocol/pci-root-bridge-io.h> 7 8#include <stdio.h> 9#include <xefi.h> 10 11typedef struct { 12 uint8_t descriptor; 13 uint16_t len; 14 uint8_t res_type; 15 uint8_t gen_flags; 16 uint8_t specific_flags; 17 uint64_t addrspace_granularity; 18 uint64_t addrrange_minimum; 19 uint64_t addrrange_maximum; 20 uint64_t addr_tr_offset; 21 uint64_t addr_len; 22} __attribute__((packed)) acpi_addrspace_desc64_t; 23 24#define ACPI_ADDRESS_SPACE_DESCRIPTOR 0x8A 25#define ACPI_END_TAG_DESCRIPTOR 0x79 26 27#define ACPI_ADDRESS_SPACE_TYPE_BUS 0x02 28 29typedef struct { 30 uint16_t vid; 31 uint16_t did; 32 uint16_t cmd; 33 uint16_t status; 34 uint8_t rev_id; 35 uint8_t class_code[3]; 36 uint8_t cache_line_size; 37 uint8_t primary_lat_timer; 38 uint8_t hdr_type; 39 uint8_t bist; 40 uint32_t bar[6]; 41 uint32_t cardbus_cis; 42 uint16_t subid; 43 uint16_t subvid; 44 uint32_t exprom_bar; 45 uint8_t cap_ptr; 46 uint8_t reserved[7]; 47 uint8_t irq_line; 48 uint8_t irq_pin; 49 uint8_t min_grant; 50 uint8_t max_lat; 51} __attribute__((packed)) pci_common_header_t; 52 53#define PCI_MAX_DEVICES 32 54#define PCI_MAX_FUNCS 8 55 56efi_status xefi_find_pci_mmio(efi_boot_services* bs, uint8_t cls, uint8_t sub, uint8_t ifc, uint64_t* mmio) { 57 size_t num_handles; 58 efi_handle* handles; 59 efi_status status = bs->LocateHandleBuffer(ByProtocol, &PciRootBridgeIoProtocol, 60 NULL, &num_handles, &handles); 61 if (EFI_ERROR(status)) { 62 printf("Could not find PCI root bridge IO protocol: %s\n", xefi_strerror(status)); 63 return status; 64 } 65 66 for (int i = 0; i < num_handles; i++) { 67 printf("handle %d\n", i); 68 efi_pci_root_bridge_io_protocol* iodev; 69 status = bs->HandleProtocol(handles[i], &PciRootBridgeIoProtocol, (void**)&iodev); 70 if (EFI_ERROR(status)) { 71 printf("Could not get protocol for handle %d: %s\n", i, xefi_strerror(status)); 72 continue; 73 } 74 acpi_addrspace_desc64_t* descriptors; 75 status = iodev->Configuration(iodev, (void**)&descriptors); 76 if (EFI_ERROR(status)) { 77 printf("Could not get configuration for handle %d: %s\n", i, xefi_strerror(status)); 78 continue; 79 } 80 81 uint16_t min_bus, max_bus; 82 while (descriptors->descriptor != ACPI_END_TAG_DESCRIPTOR) { 83 min_bus = (uint16_t)descriptors->addrrange_minimum; 84 max_bus = (uint16_t)descriptors->addrrange_maximum; 85 86 if (descriptors->res_type != ACPI_ADDRESS_SPACE_TYPE_BUS) { 87 descriptors++; 88 continue; 89 } 90 91 for (int bus = min_bus; bus <= max_bus; bus++) { 92 for (int dev = 0; dev < PCI_MAX_DEVICES; dev++) { 93 for (int func = 0; func < PCI_MAX_FUNCS; func++) { 94 pci_common_header_t pci_hdr; 95 bs->SetMem(&pci_hdr, sizeof(pci_hdr), 0); 96 uint64_t address = (uint64_t)((bus << 24) + (dev << 16) + (func << 8)); 97 status = iodev->Pci.Read(iodev, EfiPciWidthUint16, address, sizeof(pci_hdr) / 2, &pci_hdr); 98 if (EFI_ERROR(status)) { 99 printf("could not read pci configuration for bus %d dev %d func %d: %s\n", 100 bus, dev, func, xefi_strerror(status)); 101 continue; 102 } 103 if (pci_hdr.vid == 0xffff) break; 104 if ((pci_hdr.class_code[2] == cls) && 105 (pci_hdr.class_code[1] == sub) && 106 (pci_hdr.class_code[0] == ifc)) { 107 uint64_t n = ((uint64_t) pci_hdr.bar[0]) | 108 ((uint64_t) pci_hdr.bar[1]) << 32UL; 109 *mmio = n & 0xFFFFFFFFFFFFFFF0UL; 110 status = EFI_SUCCESS; 111 goto found_it; 112 } 113#if 0 114 printf("bus %04x dev %02x func %02x: ", bus, dev, func); 115 printf("VID: 0x%04x DID: 0x%04x Class: 0x%02x Subclass: 0x%02x Intf: 0x%02x\n", 116 pci_hdr.vid, pci_hdr.did, pci_hdr.class_code[2], pci_hdr.class_code[1], 117 pci_hdr.class_code[0]); 118 printf(" hdr_type: %02x\n", pci_hdr.hdr_type); 119 if ((pci_hdr.hdr_type & 0x7f) == 0x00) { 120 for (int bar = 0; bar < 6; bar++) { 121 if (pci_hdr.bar[bar]) { 122 printf(" bar[%d]: 0x%08x\n", bar, pci_hdr.bar[bar]); 123 } 124 bool is64bit = (pci_hdr.bar[bar] & 0x06) == 0x04; 125 if (is64bit) { 126 printf(" bar[%d]: 0x%08x\n", bar+1, pci_hdr.bar[bar+1]); 127 bar++; 128 } 129 // TODO: get the BAR size 130 // - disable IO 131 // - write 1s 132 // - read it back 133 // - reset or map to somewhere else(?) 134 } 135 } 136#endif 137 if (!(pci_hdr.hdr_type & 0x80) && func == 0) { 138 break; 139 } 140 } 141 } 142 } 143 descriptors++; 144 } 145 } 146 147 status = EFI_NOT_FOUND; 148found_it: 149 bs->FreePool(handles); 150 return status; 151} 152