xref: /freebsd/sys/arm64/vmm/io/vgic_internal.h (revision 1ecf7d5b38319d110d0f5bff26d6f8a9c1042cf4)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (C) 2018 Alexandru Elisei <alexandru.elisei@gmail.com>
5  * Copyright (C) 2020-2022 Andrew Turner
6  * Copyright (C) 2023 Arm Ltd
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #ifndef _VGIC_INTERNAL_H_
31 #define	_VGIC_INTERNAL_H_
32 
33 struct vgic_v3_irq {
34 	/* List of IRQs that are active or pending */
35 	TAILQ_ENTRY(vgic_v3_irq) act_pend_list;
36 	struct mtx irq_spinmtx;
37 	uint64_t mpidr;
38 	int target_vcpu;
39 	uint32_t irq;
40 	bool active;
41 	bool pending;
42 	bool enabled;
43 	bool level;
44 	bool on_aplist;
45 	uint8_t priority;
46 	uint8_t config;
47 #define	VGIC_CONFIG_MASK	0x2
48 #define	VGIC_CONFIG_LEVEL	0x0
49 #define	VGIC_CONFIG_EDGE	0x2
50 };
51 
52 /* Global data not needed by EL2 */
53 struct vgic_v3 {
54 	struct mtx 	dist_mtx;
55 	uint64_t 	dist_start;
56 	size_t   	dist_end;
57 
58 	uint64_t 	redist_start;
59 	size_t 		redist_end;
60 
61 	uint32_t 	gicd_ctlr;	/* Distributor Control Register */
62 
63 	struct vgic_v3_irq *irqs;
64 };
65 
66 /* Per-CPU data not needed by EL2 */
67 struct vgic_v3_cpu {
68 	/*
69 	 * We need a mutex for accessing the list registers because they are
70 	 * modified asynchronously by the virtual timer.
71 	 *
72 	 * Note that the mutex *MUST* be a spin mutex because an interrupt can
73 	 * be injected by a callout callback function, thereby modifying the
74 	 * list registers from a context where sleeping is forbidden.
75 	 */
76 	struct mtx	lr_mtx;
77 
78 	struct vgic_v3_irq *private_irqs;
79 	TAILQ_HEAD(, vgic_v3_irq) irq_act_pend;
80 	u_int		ich_lr_used;
81 };
82 
83 typedef void (register_read)(struct hypctx *, u_int, uint64_t *, void *);
84 typedef void (register_write)(struct hypctx *, u_int, u_int, u_int,
85     uint64_t, void *);
86 
87 register_read vgic_zero_read;
88 register_write vgic_ignore_write;
89 
90 #define	VGIC_8_BIT	(1 << 0)
91 /* (1 << 1) is reserved for 16 bit accesses */
92 #define	VGIC_32_BIT	(1 << 2)
93 #define	VGIC_64_BIT	(1 << 3)
94 
95 struct vgic_register {
96 	u_int start;	/* Start within a memory region */
97 	u_int end;
98 	u_int size;
99 	u_int flags;
100 	register_read *read;
101 	register_write *write;
102 };
103 
104 #define	VGIC_REGISTER_RANGE(reg_start, reg_end, reg_size, reg_flags, readf, \
105     writef)								\
106 {									\
107 	.start = (reg_start),						\
108 	.end = (reg_end),						\
109 	.size = (reg_size),						\
110 	.flags = (reg_flags),						\
111 	.read = (readf),						\
112 	.write = (writef),						\
113 }
114 
115 #define	VGIC_REGISTER_RANGE_RAZ_WI(reg_start, reg_end, reg_size, reg_flags) \
116 	VGIC_REGISTER_RANGE(reg_start, reg_end, reg_size, reg_flags,	\
117 	    vgic_zero_read, vgic_ignore_write)
118 
119 #define	VGIC_REGISTER(start_addr, reg_size, reg_flags, readf, writef)	\
120 	VGIC_REGISTER_RANGE(start_addr, (start_addr) + (reg_size),	\
121 	    reg_size, reg_flags, readf, writef)
122 
123 #define	VGIC_REGISTER_RAZ_WI(start_addr, reg_size, reg_flags)		\
124 	VGIC_REGISTER_RANGE_RAZ_WI(start_addr,				\
125 	    (start_addr) + (reg_size), reg_size, reg_flags)
126 
127 bool vgic_register_read(struct hypctx *, struct vgic_register *, u_int, u_int,
128     u_int, uint64_t *, void *);
129 bool vgic_register_write(struct hypctx *, struct vgic_register *, u_int, u_int,
130     u_int, uint64_t, void *);
131 
132 #endif /* _VGIC_INTERNAL_H_ */
133