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) 44static 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 51static int mem_fd = -1; /* file descriptor to /dev/mem */ 52static void *bwx_int1_ports = MAP_FAILED; /* mapped int1 io ports */ 53static void *bwx_int2_ports = MAP_FAILED; /* mapped int2 io ports */ 54static void *bwx_int4_ports = MAP_FAILED; /* mapped int4 io ports */ 55static u_int64_t bwx_io_base; /* physical address of ports */ 56static u_int64_t bwx_mem_base; /* physical address of bwx mem */ 57 58static void 59bwx_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 72static void 73bwx_close_mem(void) 74{ 75 76 if (mem_fd != -1) { 77 close(mem_fd); 78 mem_fd = -1; 79 } 80} 81 82static void 83bwx_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 101static int 102bwx_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 134static u_int8_t 135bwx_inb(u_int32_t port) 136{ 137 mb(); 138 return alpha_ldbu(bwx_int1_ports + port); 139} 140 141static u_int16_t 142bwx_inw(u_int32_t port) 143{ 144 mb(); 145 return alpha_ldwu(bwx_int2_ports + port); 146} 147 148static u_int32_t 149bwx_inl(u_int32_t port) 150{ 151 mb(); 152 return alpha_ldlu(bwx_int4_ports + port); 153} 154 155static void 156bwx_outb(u_int32_t port, u_int8_t val) 157{ 158 alpha_stb(bwx_int1_ports + port, val); 159 mb(); 160 wmb(); 161} 162 163static void 164bwx_outw(u_int32_t port, u_int16_t val) 165{ 166 alpha_stw(bwx_int2_ports + port, val); 167 mb(); 168 wmb(); 169} 170 171static void 172bwx_outl(u_int32_t port, u_int32_t val) 173{ 174 alpha_stl(bwx_int4_ports + port, val); 175 mb(); 176 wmb(); 177} 178 179struct 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 185static void * 186bwx_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 222static void 223bwx_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 234static u_int8_t 235bwx_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 242static u_int16_t 243bwx_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 250static u_int32_t 251bwx_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 258static void 259bwx_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 266static void 267bwx_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 274static void 275bwx_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 282struct 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