diff options
Diffstat (limited to 'usr/src/lib/efcode/engine/mcookie.c')
-rw-r--r-- | usr/src/lib/efcode/engine/mcookie.c | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/usr/src/lib/efcode/engine/mcookie.c b/usr/src/lib/efcode/engine/mcookie.c new file mode 100644 index 0000000000..8a12bf547a --- /dev/null +++ b/usr/src/lib/efcode/engine/mcookie.c @@ -0,0 +1,237 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2000-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#include <fcdriver/fcdriver.h> + +#define MAX_MAPS 16 + +#define MAP_IS_VALID 0x01 + +struct map_table { + int map_flags; + uint64_t map_add; + size_t map_size; + uint64_t adj_virt; + size_t adj_length; +} map_table[MAX_MAPS]; + +/* + * Originally, this code translated kernel supplied virtual addresses into + * "memory cookies", which was a 32-bit number with ascii-M in the upper 8 + * bits, a 4-bit index and a 20-bit offset. However, this caused two + * problems: 1) the 20-bit offset was too small for some devices, esp. some + * with frame-buffers; 2) if the fcode used the cookie to program the + * hardware, there was no easy way for the software to detect that a + * translation needed to be done. + * + * For that reason, "memory cookies" are now just the kernel-supplied + * virtual address, and we now check each memory access to see if it's + * attempting to access kernel-supplied memory. The only important thing + * now is that "is_mcookie" returns 1 (or true) if the tested mcookie + * is a kernel virtual address. + * + * There is a potential bug if the kernel virtual address happens to + * conflict with a user virtual address. However, the current implementation + * of Solaris avoids this conflict. + */ + +fstack_t +mapping_to_mcookie(uint64_t req_add, size_t req_size, uint64_t adj_virt, + size_t adj_length) +{ + int i; + struct map_table *mp; + + for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) + if ((mp->map_flags & MAP_IS_VALID) == 0) + break; + if (i == MAX_MAPS) { + log_message(MSG_WARN, "Warning: too many mappings\n"); + return (0); + } + debug_msg(DEBUG_REG_ACCESS, "Allocating mapping: %d add: 0x%llx" + " size: 0x%x\n", i, req_add, req_size); + mp->map_flags |= MAP_IS_VALID; + mp->map_add = req_add; + mp->map_size = req_size; + mp->adj_virt = adj_virt; + mp->adj_length = adj_length; + if (mp->adj_length != 0) + return (adj_virt); + else + return (req_add); +} + +void +delete_mapping(fstack_t mcookie) +{ + int i; + struct map_table *mp; + + for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) { + if ((mp->map_flags & MAP_IS_VALID) && + mcookie >= mp->map_add && + mcookie < mp->map_add + mp->map_size) { + debug_msg(DEBUG_REG_ACCESS, "Deallocating mapping: %d" + " add: 0x%llx size: 0x%x\n", i, mp->map_add, + mp->map_size); + mp->map_flags &= ~MAP_IS_VALID; + mp->map_add = 0; + mp->map_size = 0; + mp->adj_virt = 0; + mp->adj_length = 0; + return; + } + } + log_message(MSG_WARN, "Warning: delete_mapping: invalid" + " mcookie: %llx\n", (uint64_t)mcookie); +} + +int +is_mcookie(fstack_t mcookie) +{ + struct map_table *mp; + int i; + + for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) + if ((mp->map_flags & MAP_IS_VALID) && + mcookie >= mp->map_add && + mcookie < mp->map_add + mp->map_size) + return (1); + return (0); +} + +uint64_t +mcookie_to_addr(fstack_t mcookie) +{ + return (mcookie); +} + +fstack_t +mcookie_to_rlen(fstack_t mcookie) +{ + int i; + struct map_table *mp; + + for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) { + if ((mp->map_flags & MAP_IS_VALID) && + mcookie >= mp->map_add && + mcookie < mp->map_add + mp->map_size) { + return (mp->map_size); + } + } + log_message(MSG_WARN, "Warning: mcookie_to_rlen: invalid" + " mcookie: %llx\n", (uint64_t)mcookie); +} + +fstack_t +mcookie_to_rvirt(fstack_t mcookie) +{ + int i; + struct map_table *mp; + + for (i = 0, mp = map_table; i < MAX_MAPS; i++, mp++) { + if ((mp->map_flags & MAP_IS_VALID) && + mcookie >= mp->map_add && + mcookie < mp->map_add + mp->map_size) { + return (mp->map_add); + } + } + log_message(MSG_WARN, "Warning: mcookie_to_rvirt: invalid" + " mcookie: %llx\n", (uint64_t)mcookie); +} + +static void +dot_maps(fcode_env_t *env) +{ + int i; + + log_message(MSG_DEBUG, "idx base-addr size\n"); + for (i = 0; i < MAX_MAPS; i++) { + if (map_table[i].map_flags & MAP_IS_VALID) + log_message(MSG_DEBUG, "%3d %016llx %8x\n", i, + map_table[i].map_add, map_table[i].map_size); + } +} + +static void +map_qmark(fcode_env_t *env) +{ + fstack_t d = POP(DS); + + if (!is_mcookie(d)) + log_message(MSG_INFO, "%llx: not mcookie\n", (uint64_t)d); + else + log_message(MSG_INFO, "%llx -> %llx\n", (uint64_t)d, + mcookie_to_addr(d)); +} + +static void +add_map(fcode_env_t *env) +{ + fstack_t size, addr; + + size = POP(DS); + addr = POP(DS); + addr = mapping_to_mcookie(addr, size, NULL, NULL); + PUSH(DS, addr); +} + +static void +del_map(fcode_env_t *env) +{ + fstack_t addr; + + addr = POP(DS); + delete_mapping(addr); +} + + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + FORTH(0, ".maps", dot_maps); + FORTH(0, "map?", map_qmark); + FORTH(0, "add-map", add_map); + FORTH(0, "del-map", del_map); +} |