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