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