1 /* $OpenBSD: bwx.c,v 1.10 2021/09/17 15:19:52 deraadt Exp $ */ 2 /*- 3 * Copyright (c) 1998 Doug Rabson 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/mman.h> 30 #include <sys/sysctl.h> 31 #include <machine/bwx.h> 32 #include <machine/cpu.h> 33 #include <machine/sysarch.h> 34 #include <err.h> 35 #include <fcntl.h> 36 #include <paths.h> 37 #include <stdlib.h> 38 #include <unistd.h> 39 40 #include "io.h" 41 42 #define round_page(x) (((x) + page_mask) & ~page_mask) 43 #define trunc_page(x) ((x) & ~page_mask) 44 static long page_mask; 45 46 #define PATH_APERTURE "/dev/xf86" 47 48 #define mb() __asm__ volatile("mb" : : : "memory") 49 #define wmb() __asm__ volatile("wmb" : : : "memory") 50 51 static int mem_fd = -1; /* file descriptor to /dev/mem */ 52 static void *bwx_int1_ports = MAP_FAILED; /* mapped int1 io ports */ 53 static void *bwx_int2_ports = MAP_FAILED; /* mapped int2 io ports */ 54 static void *bwx_int4_ports = MAP_FAILED; /* mapped int4 io ports */ 55 static u_int64_t bwx_io_base; /* physical address of ports */ 56 static u_int64_t bwx_mem_base; /* physical address of bwx mem */ 57 58 static void 59 bwx_open_mem(void) 60 { 61 62 if (mem_fd != -1) 63 return; 64 mem_fd = open(_PATH_MEM, O_RDWR); 65 if (mem_fd < 0) 66 mem_fd = open(PATH_APERTURE, O_RDWR); 67 if (mem_fd < 0) 68 err(1, "Failed to open both %s and %s", _PATH_MEM, 69 PATH_APERTURE); 70 } 71 72 static void 73 bwx_close_mem(void) 74 { 75 76 if (mem_fd != -1) { 77 close(mem_fd); 78 mem_fd = -1; 79 } 80 } 81 82 static void 83 bwx_init(void) 84 { 85 size_t len = sizeof(u_int64_t); 86 int error; 87 int mib[3]; 88 89 page_mask = getpagesize() - 1; 90 91 mib[0] = CTL_MACHDEP; 92 mib[1] = CPU_CHIPSET; 93 mib[2] = CPU_CHIPSET_PORTS; 94 if ((error = sysctl(mib, 3, &bwx_io_base, &len, NULL, 0)) < 0) 95 err(1, "machdep.chipset.ports_base"); 96 mib[2] = CPU_CHIPSET_MEM; 97 if ((error = sysctl(mib, 3, &bwx_mem_base, &len, 0, 0)) < 0) 98 err(1, "machdep.chipset.memory"); 99 } 100 101 static int 102 bwx_ioperm(u_int32_t from, u_int32_t num, int on) 103 { 104 u_int32_t start, end; 105 106 if (bwx_int1_ports == MAP_FAILED) 107 bwx_init(); 108 109 if (!on) 110 return -1; /* XXX can't unmap yet */ 111 112 if (bwx_int1_ports != MAP_FAILED) 113 return 0; 114 115 bwx_open_mem(); 116 start = trunc_page(from); 117 end = round_page(from + num); 118 if ((bwx_int1_ports = mmap(0, end-start, PROT_READ|PROT_WRITE, 119 MAP_SHARED, mem_fd, bwx_io_base + BWX_EV56_INT1 + start)) == 120 MAP_FAILED) 121 err(1, "mmap int1"); 122 if ((bwx_int2_ports = mmap(0, end-start, PROT_READ|PROT_WRITE, 123 MAP_SHARED, mem_fd, bwx_io_base + BWX_EV56_INT2 + start)) == 124 MAP_FAILED) 125 err(1, "mmap int2"); 126 if ((bwx_int4_ports = mmap(0, end-start, PROT_READ|PROT_WRITE, 127 MAP_SHARED, mem_fd, bwx_io_base + BWX_EV56_INT4 + start)) == 128 MAP_FAILED) 129 err(1, "mmap int4"); 130 bwx_close_mem(); 131 return 0; 132 } 133 134 static u_int8_t 135 bwx_inb(u_int32_t port) 136 { 137 mb(); 138 return alpha_ldbu(bwx_int1_ports + port); 139 } 140 141 static u_int16_t 142 bwx_inw(u_int32_t port) 143 { 144 mb(); 145 return alpha_ldwu(bwx_int2_ports + port); 146 } 147 148 static u_int32_t 149 bwx_inl(u_int32_t port) 150 { 151 mb(); 152 return alpha_ldlu(bwx_int4_ports + port); 153 } 154 155 static void 156 bwx_outb(u_int32_t port, u_int8_t val) 157 { 158 alpha_stb(bwx_int1_ports + port, val); 159 mb(); 160 wmb(); 161 } 162 163 static void 164 bwx_outw(u_int32_t port, u_int16_t val) 165 { 166 alpha_stw(bwx_int2_ports + port, val); 167 mb(); 168 wmb(); 169 } 170 171 static void 172 bwx_outl(u_int32_t port, u_int32_t val) 173 { 174 alpha_stl(bwx_int4_ports + port, val); 175 mb(); 176 wmb(); 177 } 178 179 struct bwx_mem_handle { 180 void *virt1; /* int1 address in user address-space */ 181 void *virt2; /* int2 address in user address-space */ 182 void *virt4; /* int4 address in user address-space */ 183 }; 184 185 static void * 186 bwx_map_memory(u_int32_t address, u_int32_t size) 187 { 188 struct bwx_mem_handle *h; 189 size_t sz = (size_t)size << 5; 190 191 h = malloc(sizeof(struct bwx_mem_handle)); 192 if (h == NULL) return NULL; 193 bwx_open_mem(); 194 h->virt1 = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED, 195 mem_fd, bwx_mem_base + BWX_EV56_INT1 + address); 196 if (h->virt1 == MAP_FAILED) { 197 bwx_close_mem(); 198 free(h); 199 return NULL; 200 } 201 h->virt2 = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED, 202 mem_fd, bwx_mem_base + BWX_EV56_INT2 + address); 203 if (h->virt2 == MAP_FAILED) { 204 munmap(h->virt1, sz); 205 bwx_close_mem(); 206 free(h); 207 return NULL; 208 } 209 h->virt4 = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED, 210 mem_fd, bwx_mem_base + BWX_EV56_INT4 + address); 211 if (h->virt4 == MAP_FAILED) { 212 munmap(h->virt1, sz); 213 munmap(h->virt2, sz); 214 bwx_close_mem(); 215 free(h); 216 return NULL; 217 } 218 bwx_close_mem(); 219 return h; 220 } 221 222 static void 223 bwx_unmap_memory(void *handle, u_int32_t size) 224 { 225 struct bwx_mem_handle *h = handle; 226 size_t sz = (size_t)size << 5; 227 228 munmap(h->virt1, sz); 229 munmap(h->virt2, sz); 230 munmap(h->virt4, sz); 231 free(h); 232 } 233 234 static u_int8_t 235 bwx_readb(void *handle, u_int32_t offset) 236 { 237 struct bwx_mem_handle *h = handle; 238 239 return alpha_ldbu(h->virt1 + offset); 240 } 241 242 static u_int16_t 243 bwx_readw(void *handle, u_int32_t offset) 244 { 245 struct bwx_mem_handle *h = handle; 246 247 return alpha_ldwu(h->virt2 + offset); 248 } 249 250 static u_int32_t 251 bwx_readl(void *handle, u_int32_t offset) 252 { 253 struct bwx_mem_handle *h = handle; 254 255 return alpha_ldlu(h->virt4 + offset); 256 } 257 258 static void 259 bwx_writeb(void *handle, u_int32_t offset, u_int8_t val) 260 { 261 struct bwx_mem_handle *h = handle; 262 263 alpha_stb(h->virt1 + offset, val); 264 } 265 266 static void 267 bwx_writew(void *handle, u_int32_t offset, u_int16_t val) 268 { 269 struct bwx_mem_handle *h = handle; 270 271 alpha_stw(h->virt2 + offset, val); 272 } 273 274 static void 275 bwx_writel(void *handle, u_int32_t offset, u_int32_t val) 276 { 277 struct bwx_mem_handle *h = handle; 278 279 alpha_stl(h->virt4 + offset, val); 280 } 281 282 struct io_ops bwx_io_ops = { 283 bwx_ioperm, 284 bwx_inb, 285 bwx_inw, 286 bwx_inl, 287 bwx_outb, 288 bwx_outw, 289 bwx_outl, 290 bwx_map_memory, 291 bwx_unmap_memory, 292 bwx_readb, 293 bwx_readw, 294 bwx_readl, 295 bwx_writeb, 296 bwx_writew, 297 bwx_writel, 298 }; 299