1 /* $NetBSD: idt.c,v 1.17 2022/08/20 23:48:51 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997, 1998, 2000, 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum, by Jason R. Thorpe of the Numerical Aerospace 9 * Simulation Facility NASA Ames Research Center, and by Andrew Doran. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /*- 34 * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. 35 * All rights reserved. 36 * 37 * This code is derived from software contributed to Berkeley by 38 * William Jolitz. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * @(#)machdep.c 7.4 (Berkeley) 6/3/91 65 */ 66 67 #include <sys/cdefs.h> 68 __KERNEL_RCSID(0, "$NetBSD: idt.c,v 1.17 2022/08/20 23:48:51 riastradh Exp $"); 69 70 #include "opt_pcpu_idt.h" 71 72 #include <sys/param.h> 73 #include <sys/systm.h> 74 #include <sys/mutex.h> 75 #include <sys/cpu.h> 76 #include <sys/atomic.h> 77 78 #include <uvm/uvm.h> 79 80 #include <machine/pmap_private.h> 81 #include <machine/segments.h> 82 83 /* 84 * XEN PV and native have a different idea of what idt entries should 85 * look like. 86 */ 87 88 /* Normalise across XEN PV and native */ 89 #if defined(XENPV) 90 91 void 92 set_idtgate(struct trap_info *xen_idd, void *function, int ist, 93 int type, int dpl, int sel) 94 { 95 /* 96 * Find the page boundary in which the descriptor resides. 97 * We make an assumption here, that the descriptor is part of 98 * a table (array), which fits in a page and is page aligned. 99 * 100 * This assumption is from the usecases at early startup in 101 * machine/machdep.c 102 * 103 * Thus this function may not work in the "general" case of a 104 * randomly located idt entry template (for eg:). 105 */ 106 107 vaddr_t xen_idt_vaddr = ((vaddr_t) xen_idd) & ~PAGE_MASK; 108 109 //kpreempt_disable(); 110 #if defined(__x86_64__) 111 /* Make it writeable, so we can update the values. */ 112 pmap_changeprot_local(xen_idt_vaddr, VM_PROT_READ | VM_PROT_WRITE); 113 #endif /* __x86_64 */ 114 xen_idd->cs = sel; 115 xen_idd->address = (unsigned long) function; 116 xen_idd->flags = dpl; 117 118 /* 119 * Again we make the assumption that the descriptor is 120 * implicitly part of an idt, which we infer as 121 * xen_idt_vaddr. (See above). 122 */ 123 xen_idd->vector = xen_idd - (struct trap_info *)xen_idt_vaddr; 124 125 /* Back to read-only, as it should be. */ 126 #if defined(__x86_64__) 127 pmap_changeprot_local(xen_idt_vaddr, VM_PROT_READ); 128 #endif /* __x86_64 */ 129 //kpreempt_enable(); 130 } 131 void 132 unset_idtgate(struct trap_info *xen_idd) 133 { 134 #if defined(__x86_64__) 135 vaddr_t xen_idt_vaddr = ((vaddr_t) xen_idd) & ~PAGE_MASK; 136 137 /* Make it writeable, so we can update the values. */ 138 pmap_changeprot_local(xen_idt_vaddr, VM_PROT_READ | VM_PROT_WRITE); 139 #endif /* __x86_64 */ 140 141 /* Zero it */ 142 memset(xen_idd, 0, sizeof (*xen_idd)); 143 144 #if defined(__x86_64__) 145 /* Back to read-only, as it should be. */ 146 pmap_changeprot_local(xen_idt_vaddr, VM_PROT_READ); 147 #endif /* __x86_64 */ 148 } 149 #else /* XENPV */ 150 void 151 set_idtgate(struct gate_descriptor *idd, void *function, int ist, int type, int dpl, int sel) 152 { 153 setgate(idd, function, ist, type, dpl, sel); 154 } 155 void 156 unset_idtgate(struct gate_descriptor *idd) 157 { 158 unsetgate(idd); 159 } 160 #endif /* XENPV */ 161 162 /* 163 * Allocate an IDT vector slot within the given range. 164 * cpu_lock will be held unless single threaded during early boot. 165 */ 166 int 167 idt_vec_alloc(struct idt_vec *iv, int low, int high) 168 { 169 int vec; 170 char *idt_allocmap = iv->iv_allocmap; 171 172 KASSERT(mutex_owned(&cpu_lock) || !mp_online); 173 174 if (low < 0 || high >= __arraycount(iv->iv_allocmap)) 175 return -1; 176 177 for (vec = low; vec <= high; vec++) { 178 /* pairs with atomic_store_release in idt_vec_free */ 179 if (atomic_load_acquire(&idt_allocmap[vec]) == 0) { 180 /* 181 * No ordering needed here (`relaxed') because 182 * access to free entries is serialized by 183 * cpu_lock or single-threaded operation. 184 */ 185 atomic_store_relaxed(&idt_allocmap[vec], 1); 186 return vec; 187 } 188 } 189 190 return -1; 191 } 192 193 void 194 idt_vec_reserve(struct idt_vec *iv, int vec) 195 { 196 int result; 197 198 KASSERT(mutex_owned(&cpu_lock) || !mp_online); 199 200 result = idt_vec_alloc(iv, vec, vec); 201 if (result < 0) { 202 panic("%s: failed to reserve vec %d", __func__, vec); 203 } 204 } 205 206 void 207 idt_vec_set(struct idt_vec *iv, int vec, void (*function)(void)) 208 { 209 idt_descriptor_t *idt; 210 char *idt_allocmap __diagused = iv->iv_allocmap; 211 212 KASSERT(atomic_load_relaxed(&idt_allocmap[vec]) == 1); 213 214 idt = iv->iv_idt; 215 set_idtgate(&idt[vec], function, 0, SDT_SYS386IGT, SEL_KPL, 216 GSEL(GCODE_SEL, SEL_KPL)); 217 } 218 219 /* 220 * Free IDT vector. No locking required as release is atomic. 221 */ 222 void 223 idt_vec_free(struct idt_vec *iv, int vec) 224 { 225 idt_descriptor_t *idt; 226 char *idt_allocmap = iv->iv_allocmap; 227 228 KASSERT(atomic_load_relaxed(&idt_allocmap[vec]) == 1); 229 230 idt = iv->iv_idt; 231 unset_idtgate(&idt[vec]); 232 /* pairs with atomic_load_acquire in idt_vec_alloc */ 233 atomic_store_release(&idt_allocmap[vec], 0); 234 } 235 236 bool 237 idt_vec_is_pcpu(void) 238 { 239 240 #ifdef PCPU_IDT 241 return true; 242 #else 243 return false; 244 #endif 245 } 246 247 struct idt_vec * 248 idt_vec_ref(struct idt_vec *iv) 249 { 250 if (idt_vec_is_pcpu()) 251 return iv; 252 253 return &(cpu_info_primary.ci_idtvec); 254 } 255