1 /*
2  * Copyright (C) 2020-2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 
8 /*
9 * Emulate GPIO registers which are only accessible through Primary to Sideband Bridge (P2SB).
10 *
11 * Intercept accesses to MISCCFG.GPDMINTSEL[31:24] and PADCFG1.INTSEL[7:0] GPIO registers which hold physical interrupt
12 * lines and return virtualized values upon read in accordance with the gsi to vgsi mappings given by the VM config.
13 *
14 * P2SB_BAR_ADDR: 0xFD000000 (fixed by BIOS)
15 *
16 *
17 *	--------------------------------------------------------------------------------------
18 *		SideBand Endpoint Name		|	Port ID
19 *	--------------------------------------------------------------------------------------
20 *		GPIO Community 5		|	0x69
21 *		GPIO Community 4		|	0x6A
22 *		GPIO Community 3		|	0x6B
23 *		GPIO Community 2		|	0x6C
24 *		GPIO Community 1		|	0x6D
25 *		GPIO Community 0		|	0x6E
26 *	--------------------------------------------------------------------------------------
27 *
28 * Private Configuration Register (PCR) Address = P2SB_BAR_ADDR + (Port ID << 16) + Register Offset
29 * e.g.)
30 *	GPIO_COMMUNITY_5_PCR_BASE  = P2SB_BAR_ADDR + (0x69 << 16) = 0xFD690000
31 *	GPIO_COMMUNITY_5_MISCCFG   = GPIO_COMMUNITY_5_PCR_BASE + 0x010 = 0xFD690010
32 *	GPIO_COMMUNITY_5_PAD0_CFG1 = GPIO_COMMUNITY_5_PCR_BASE + 0x704 = 0xFD690704
33 *	GPIO_COMMUNITY_5_PAD1_CFG1 = GPIO_COMMUNITY_5_PCR_BASE + 0x714 = 0xFD690714
34 *	GPIO_COMMUNITY_5_PAD2_CFG1 = GPIO_COMMUNITY_5_PCR_BASE + 0x724 = 0xFD690724
35 *	....
36 *
37 */
38 
39 #include <types.h>
40 #include <errno.h>
41 #include <asm/guest/vm.h>
42 #include <asm/guest/ept.h>
43 #include <asm/guest/assign.h>
44 #include <asm/io.h>
45 #include <asm/mmu.h>
46 
47 #ifdef P2SB_VGPIO_DM_ENABLED
48 
49 #define P2SB_PORTID_SHIFT		16U
50 #define P2SB_AGENT_NUM			256U
51 #define P2SB_PCR_SPACE_SIZE_PER_AGENT	0x10000U
52 #define P2SB_PCR_SPACE_SIZE_TOTAL	(P2SB_AGENT_NUM * P2SB_PCR_SPACE_SIZE_PER_AGENT)
53 #define P2SB_PCR_SPACE_MASK		((1UL << P2SB_PORTID_SHIFT) - 1UL)
54 
55 #define GPIO_MISCCFG			0x010U
56 #define GPIO_MISGCFG_GPDMINTSEL_SHIFT	24U
57 #define GPIO_PADBAR			0x00CU
58 #define GPIO_PADCFG1			0x004U
59 #define GPIO_PADCFG1_INTSEL_SHIFT	0U
60 
61 #define GPIO_INVALID_PIN		0xFFU
62 
63 /**
64  * @return vpin mapped to the given phys_pin in accordance with the VM config, if not found return 0xFF as invalid pin
65  */
ioapic_pin_to_vpin(struct acrn_vm * vm,const struct acrn_vm_config * vm_config,const uint32_t phys_pin)66 static uint32_t ioapic_pin_to_vpin(struct acrn_vm *vm, const struct acrn_vm_config *vm_config, const uint32_t phys_pin)
67 {
68 	uint32_t i;
69 	uint32_t vpin = GPIO_INVALID_PIN;
70 	struct acrn_single_vioapic *vioapic;
71 
72 	for (i = 0U; i < vm_config->pt_intx_num; i++) {
73 		if (phys_pin == gsi_to_ioapic_pin(vm_config->pt_intx[i].phys_gsi)) {
74 			vioapic = vgsi_to_vioapic_and_vpin(vm, vm_config->pt_intx[i].virt_gsi, &vpin);
75 			if (!vioapic) {
76 				vpin = GPIO_INVALID_PIN;
77 			}
78 			break;
79 		}
80 	}
81 
82 	return vpin;
83 }
84 
vgpio_mmio_handler(struct io_request * io_req,void * data)85 static int32_t vgpio_mmio_handler(struct io_request *io_req, void *data)
86 {
87 	struct acrn_mmio_request *mmio = &io_req->reqs.mmio_request;
88 	struct acrn_vm *vm = (struct acrn_vm *) data;
89 	struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
90 	int32_t ret = 0;
91 
92 	uint64_t hpa = P2SB_BAR_ADDR + (mmio->address & (uint64_t)(P2SB_PCR_SPACE_SIZE_TOTAL - 1));
93 	void    *hva = hpa2hva(hpa);
94 	uint64_t reg_offset = hpa & P2SB_PCR_SPACE_MASK;
95 
96 	uint32_t value, shift;
97 	uint32_t padbar, pad0;
98 	uint32_t phys_pin, virt_pin;
99 
100 	/* all gpio registers have 4 bytes size */
101 	if (mmio->size == 4U) {
102 		if (mmio->direction == ACRN_IOREQ_DIR_READ) {
103 			padbar = mmio_read32((const void *)hpa2hva((hpa & ~P2SB_PCR_SPACE_MASK) + GPIO_PADBAR));
104 			pad0   = padbar & P2SB_PCR_SPACE_MASK;
105 			value  = mmio_read32((const void *)hva);
106 
107 			if ((reg_offset == GPIO_MISCCFG) ||
108 				((reg_offset >= pad0) && ((reg_offset & 0x0FU) == GPIO_PADCFG1))) {
109 				shift = (reg_offset == GPIO_MISCCFG) ? GPIO_MISGCFG_GPDMINTSEL_SHIFT :
110 									GPIO_PADCFG1_INTSEL_SHIFT;
111 				phys_pin = (value >> shift) & 0xFFU;
112 				virt_pin = ioapic_pin_to_vpin(vm, vm_config, phys_pin);
113 				value = (value & ~(0xFFU << shift)) | (virt_pin << shift);
114 			}
115 			mmio->value = (uint64_t)value;
116 		} else {
117 			value = (uint32_t)mmio->value;
118 			if (reg_offset == GPIO_MISCCFG) { /* discard writes to MISCCFG.GPDMINTSEL[31:24] */
119 				value = (value & ~(0xFFU << GPIO_MISGCFG_GPDMINTSEL_SHIFT)) |
120 					(mmio_read32((const void *)hva) & (0xFFU << GPIO_MISGCFG_GPDMINTSEL_SHIFT));
121 			}
122 			mmio_write32(value, (void *)hva);
123 		}
124 	} else {
125 		ret = -EINVAL;
126 	}
127 
128     return ret;
129 }
130 
131 /**
132  * @pre vm != NULL && res != NULL
133  */
register_vgpio_handler(struct acrn_vm * vm,const struct acrn_mmiores * res)134 void register_vgpio_handler(struct acrn_vm *vm, const struct acrn_mmiores *res)
135 {
136 	uint64_t gpa_start, gpa_end, gpio_pcr_sz;
137 	uint64_t base_hpa;
138 
139 	gpa_start   = res->user_vm_pa + (P2SB_BASE_GPIO_PORT_ID << P2SB_PORTID_SHIFT);
140 	gpio_pcr_sz = P2SB_PCR_SPACE_SIZE_PER_AGENT * P2SB_MAX_GPIO_COMMUNITIES;
141 	gpa_end     = gpa_start + gpio_pcr_sz;
142 	base_hpa    = res->host_pa + (P2SB_BASE_GPIO_PORT_ID << P2SB_PORTID_SHIFT);
143 
144 	/* emulate MMIO access to the GPIO private configuration space registers */
145 	set_paging_supervisor((uint64_t)hpa2hva(base_hpa), gpio_pcr_sz);
146 	register_mmio_emulation_handler(vm, vgpio_mmio_handler, gpa_start, gpa_end, (void *)vm, false);
147 	ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, gpa_start, gpio_pcr_sz);
148 }
149 
150 #endif
151