• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
set_bit(volatile uint32_t * flag,int bit,int value)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 
configspace_matches_ids(void * config,uint32_t vendor_id,uint32_t device_id)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 
is_device(EFI_PCI_IO * pciio,uint16_t vendor_id,uint16_t device_id)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 
find_pci_device(uint16_t vendor_id,uint16_t device_id,EFI_PCI_IO ** pciio)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
efi_main(EFI_HANDLE image_handle,EFI_SYSTEM_TABLE * systab)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