1 1.1 jakllsch /* $NetBSD: route80h.c,v 1.1.1.2 2018/08/16 18:17:47 jmcneill Exp $ */ 2 1.1 jakllsch 3 1.1 jakllsch #include <efi.h> 4 1.1 jakllsch #include <efilib.h> 5 1.1 jakllsch 6 1.1 jakllsch /* this example program changes the Reserved Page Route (RPR) bit on ICH10's General 7 1.1 jakllsch * Control And Status Register (GCS) from LPC to PCI. In practical terms, it routes 8 1.1 jakllsch * outb to port 80h to the PCI bus. */ 9 1.1 jakllsch 10 1.1 jakllsch #define GCS_OFFSET_ADDR 0x3410 11 1.1 jakllsch #define GCS_RPR_SHIFT 2 12 1.1 jakllsch #define GCS_RPR_PCI 1 13 1.1 jakllsch #define GCS_RPR_LPC 0 14 1.1 jakllsch 15 1.1 jakllsch #define VENDOR_ID_INTEL 0x8086 16 1.1 jakllsch #define DEVICE_ID_LPCIF 0x3a16 17 1.1 jakllsch #define DEVICE_ID_COUGARPOINT_LPCIF 0x1c56 18 1.1 jakllsch 19 1.1 jakllsch static EFI_HANDLE ImageHandle; 20 1.1 jakllsch 21 1.1 jakllsch typedef struct { 22 1.1 jakllsch uint16_t vendor_id; /* 00-01 */ 23 1.1 jakllsch uint16_t device_id; /* 02-03 */ 24 1.1 jakllsch char pad[0xEB]; /* 04-EF */ 25 1.1 jakllsch uint32_t rcba; /* F0-F3 */ 26 1.1 jakllsch uint32_t reserved[3]; /* F4-FF */ 27 1.1 jakllsch } lpcif_t; 28 1.1 jakllsch 29 1.1 jakllsch static inline void set_bit(volatile uint32_t *flag, int bit, int value) 30 1.1 jakllsch { 31 1.1 jakllsch uint32_t val = *flag; 32 1.1 jakllsch Print(L"current value is 0x%2x\n", val); 33 1.1 jakllsch 34 1.1 jakllsch if (value) { 35 1.1 jakllsch val |= (1 << bit); 36 1.1 jakllsch } else { 37 1.1 jakllsch val &= ~(1 << bit); 38 1.1 jakllsch } 39 1.1 jakllsch Print(L"setting value to 0x%2x\n", val); 40 1.1 jakllsch *flag = val; 41 1.1 jakllsch val = *flag; 42 1.1 jakllsch Print(L"new value is 0x%2x\n", val); 43 1.1 jakllsch } 44 1.1 jakllsch 45 1.1 jakllsch static int is_device(EFI_PCI_IO *pciio, uint16_t vendor_id, uint16_t device_id) 46 1.1 jakllsch { 47 1.1 jakllsch lpcif_t lpcif; 48 1.1 jakllsch EFI_STATUS rc; 49 1.1 jakllsch 50 1.1 jakllsch rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint16, 0, 2, &lpcif); 51 1.1 jakllsch if (EFI_ERROR(rc)) 52 1.1 jakllsch return 0; 53 1.1 jakllsch 54 1.1 jakllsch if (vendor_id == lpcif.vendor_id && device_id == lpcif.device_id) 55 1.1 jakllsch return 1; 56 1.1 jakllsch return 0; 57 1.1 jakllsch } 58 1.1 jakllsch 59 1.1 jakllsch static EFI_STATUS find_pci_device(uint16_t vendor_id, uint16_t device_id, 60 1.1 jakllsch EFI_PCI_IO **pciio) 61 1.1 jakllsch { 62 1.1 jakllsch EFI_STATUS rc; 63 1.1 jakllsch EFI_HANDLE *Handles; 64 1.1.1.2 jmcneill UINTN NoHandles, i; 65 1.1 jakllsch 66 1.1 jakllsch if (!pciio) 67 1.1 jakllsch return EFI_INVALID_PARAMETER; 68 1.1 jakllsch 69 1.1 jakllsch rc = LibLocateHandle(ByProtocol, &PciIoProtocol, NULL, &NoHandles, 70 1.1 jakllsch &Handles); 71 1.1 jakllsch if (EFI_ERROR(rc)) 72 1.1 jakllsch return rc; 73 1.1 jakllsch 74 1.1 jakllsch for (i = 0; i < NoHandles; i++) { 75 1.1 jakllsch void *pciio_tmp = NULL; 76 1.1 jakllsch rc = uefi_call_wrapper(BS->OpenProtocol, 6, Handles[i], 77 1.1 jakllsch &PciIoProtocol, &pciio_tmp, ImageHandle, 78 1.1 jakllsch NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 79 1.1 jakllsch if (EFI_ERROR(rc)) 80 1.1 jakllsch continue; 81 1.1 jakllsch *pciio = pciio_tmp; 82 1.1 jakllsch if (!is_device(*pciio, vendor_id, device_id)) { 83 1.1 jakllsch *pciio = NULL; 84 1.1 jakllsch continue; 85 1.1 jakllsch } 86 1.1 jakllsch 87 1.1 jakllsch return EFI_SUCCESS; 88 1.1 jakllsch } 89 1.1 jakllsch return EFI_NOT_FOUND; 90 1.1 jakllsch } 91 1.1 jakllsch 92 1.1 jakllsch EFI_STATUS 93 1.1 jakllsch efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab) 94 1.1 jakllsch { 95 1.1 jakllsch InitializeLib(image_handle, systab); 96 1.1 jakllsch EFI_PCI_IO *pciio = NULL; 97 1.1 jakllsch lpcif_t lpcif; 98 1.1.1.2 jmcneill EFI_STATUS rc = EFI_SUCCESS; 99 1.1 jakllsch struct { 100 1.1 jakllsch uint16_t vendor; 101 1.1 jakllsch uint16_t device; 102 1.1 jakllsch } devices[] = { 103 1.1 jakllsch { VENDOR_ID_INTEL, DEVICE_ID_LPCIF }, 104 1.1 jakllsch { VENDOR_ID_INTEL, DEVICE_ID_COUGARPOINT_LPCIF }, 105 1.1 jakllsch { 0, 0 } 106 1.1 jakllsch }; 107 1.1 jakllsch int i; 108 1.1 jakllsch 109 1.1 jakllsch ImageHandle = image_handle; 110 1.1 jakllsch for (i = 0; devices[i].vendor != 0; i++) { 111 1.1 jakllsch rc = find_pci_device(devices[i].vendor, devices[i].device, &pciio); 112 1.1 jakllsch if (EFI_ERROR(rc)) 113 1.1 jakllsch continue; 114 1.1 jakllsch } 115 1.1 jakllsch 116 1.1 jakllsch if (rc == EFI_NOT_FOUND) { 117 1.1 jakllsch Print(L"Device not found.\n"); 118 1.1 jakllsch return rc; 119 1.1 jakllsch } else if (EFI_ERROR(rc)) { 120 1.1 jakllsch return rc; 121 1.1 jakllsch } 122 1.1 jakllsch 123 1.1 jakllsch rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint32, 124 1.1 jakllsch EFI_FIELD_OFFSET(lpcif_t, rcba), 1, &lpcif.rcba); 125 1.1 jakllsch if (EFI_ERROR(rc)) 126 1.1 jakllsch return rc; 127 1.1 jakllsch if (!(lpcif.rcba & 1)) { 128 1.1 jakllsch Print(L"rcrb is not mapped, cannot route port 80h\n"); 129 1.1 jakllsch return EFI_UNSUPPORTED; 130 1.1 jakllsch } 131 1.1 jakllsch lpcif.rcba &= ~1UL; 132 1.1 jakllsch 133 1.1 jakllsch Print(L"rcba: 0x%8x\n", lpcif.rcba, lpcif.rcba); 134 1.1.1.2 jmcneill set_bit((uint32_t *)(intptr_t)(lpcif.rcba + GCS_OFFSET_ADDR), 135 1.1 jakllsch GCS_RPR_SHIFT, GCS_RPR_PCI); 136 1.1 jakllsch 137 1.1 jakllsch return EFI_SUCCESS; 138 1.1 jakllsch } 139