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