1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <stdarg.h> 33 34 #include <fcode/private.h> 35 #include <fcode/log.h> 36 37 #include <fcdriver/fcdriver.h> 38 39 #define MAX_MAPS 16 40 41 #define MAP_IS_VALID 0x01 42 43 struct map_table { 44 int map_flags; 45 uint64_t map_add; 46 size_t map_size; 47 uint64_t adj_virt; 48 size_t adj_length; 49 } map_table[MAX_MAPS]; 50 51 /* 52 * Originally, this code translated kernel supplied virtual addresses into 53 * "memory cookies", which was a 32-bit number with ascii-M in the upper 8 54 * bits, a 4-bit index and a 20-bit offset. However, this caused two 55 * problems: 1) the 20-bit offset was too small for some devices, esp. some 56 * with frame-buffers; 2) if the fcode used the cookie to program the 57 * hardware, there was no easy way for the software to detect that a 58 * translation needed to be done. 59 * 60 * For that reason, "memory cookies" are now just the kernel-supplied 61 * virtual address, and we now check each memory access to see if it's 62 * attempting to access kernel-supplied memory. The only important thing 63 * now is that "is_mcookie" returns 1 (or true) if the tested mcookie 64 * is a kernel virtual address. 65 * 66 * There is a potential bug if the kernel virtual address happens to 67 * conflict with a user virtual address. However, the current implementation 68 * of Solaris avoids this conflict. 69 */ 70 71 fstack_t 72 mapping_to_mcookie(uint64_t req_add, size_t req_size, uint64_t adj_virt, 73 size_t adj_length) 74 { 75 int i; 76 struct map_table *mp; 77 78 for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) 79 if ((mp->map_flags & MAP_IS_VALID) == 0) 80 break; 81 if (i == MAX_MAPS) { 82 log_message(MSG_WARN, "Warning: too many mappings\n"); 83 return (0); 84 } 85 debug_msg(DEBUG_REG_ACCESS, "Allocating mapping: %d add: 0x%llx" 86 " size: 0x%x\n", i, req_add, req_size); 87 mp->map_flags |= MAP_IS_VALID; 88 mp->map_add = req_add; 89 mp->map_size = req_size; 90 mp->adj_virt = adj_virt; 91 mp->adj_length = adj_length; 92 if (mp->adj_length != 0) 93 return (adj_virt); 94 else 95 return (req_add); 96 } 97 98 void 99 delete_mapping(fstack_t mcookie) 100 { 101 int i; 102 struct map_table *mp; 103 104 for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) { 105 if ((mp->map_flags & MAP_IS_VALID) && 106 mcookie >= mp->map_add && 107 mcookie < mp->map_add + mp->map_size) { 108 debug_msg(DEBUG_REG_ACCESS, "Deallocating mapping: %d" 109 " add: 0x%llx size: 0x%x\n", i, mp->map_add, 110 mp->map_size); 111 mp->map_flags &= ~MAP_IS_VALID; 112 mp->map_add = 0; 113 mp->map_size = 0; 114 mp->adj_virt = 0; 115 mp->adj_length = 0; 116 return; 117 } 118 } 119 log_message(MSG_WARN, "Warning: delete_mapping: invalid" 120 " mcookie: %llx\n", (uint64_t)mcookie); 121 } 122 123 int 124 is_mcookie(fstack_t mcookie) 125 { 126 struct map_table *mp; 127 int i; 128 129 for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) 130 if ((mp->map_flags & MAP_IS_VALID) && 131 mcookie >= mp->map_add && 132 mcookie < mp->map_add + mp->map_size) 133 return (1); 134 return (0); 135 } 136 137 uint64_t 138 mcookie_to_addr(fstack_t mcookie) 139 { 140 return (mcookie); 141 } 142 143 fstack_t 144 mcookie_to_rlen(fstack_t mcookie) 145 { 146 int i; 147 struct map_table *mp; 148 149 for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) { 150 if ((mp->map_flags & MAP_IS_VALID) && 151 mcookie >= mp->map_add && 152 mcookie < mp->map_add + mp->map_size) { 153 return (mp->map_size); 154 } 155 } 156 log_message(MSG_WARN, "Warning: mcookie_to_rlen: invalid" 157 " mcookie: %llx\n", (uint64_t)mcookie); 158 159 return (0); 160 } 161 162 fstack_t 163 mcookie_to_rvirt(fstack_t mcookie) 164 { 165 int i; 166 struct map_table *mp; 167 168 for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) { 169 if ((mp->map_flags & MAP_IS_VALID) && 170 mcookie >= mp->map_add && 171 mcookie < mp->map_add + mp->map_size) { 172 return (mp->map_add); 173 } 174 } 175 log_message(MSG_WARN, "Warning: mcookie_to_rvirt: invalid" 176 " mcookie: %llx\n", (uint64_t)mcookie); 177 178 return (0); 179 } 180 181 static void 182 dot_maps(fcode_env_t *env) 183 { 184 int i; 185 186 log_message(MSG_DEBUG, "idx base-addr size\n"); 187 for (i = 0; i < MAX_MAPS; i++) { 188 if (map_table[i].map_flags & MAP_IS_VALID) 189 log_message(MSG_DEBUG, "%3d %016llx %8x\n", i, 190 map_table[i].map_add, map_table[i].map_size); 191 } 192 } 193 194 static void 195 map_qmark(fcode_env_t *env) 196 { 197 fstack_t d = POP(DS); 198 199 if (!is_mcookie(d)) 200 log_message(MSG_INFO, "%llx: not mcookie\n", (uint64_t)d); 201 else 202 log_message(MSG_INFO, "%llx -> %llx\n", (uint64_t)d, 203 mcookie_to_addr(d)); 204 } 205 206 static void 207 add_map(fcode_env_t *env) 208 { 209 fstack_t size, addr; 210 211 size = POP(DS); 212 addr = POP(DS); 213 addr = mapping_to_mcookie(addr, size, NULL, NULL); 214 PUSH(DS, addr); 215 } 216 217 static void 218 del_map(fcode_env_t *env) 219 { 220 fstack_t addr; 221 222 addr = POP(DS); 223 delete_mapping(addr); 224 } 225 226 227 #pragma init(_init) 228 229 static void 230 _init(void) 231 { 232 fcode_env_t *env = initial_env; 233 234 ASSERT(env); 235 NOTICE; 236 237 FORTH(0, ".maps", dot_maps); 238 FORTH(0, "map?", map_qmark); 239 FORTH(0, "add-map", add_map); 240 FORTH(0, "del-map", del_map); 241 } 242