1 /*- 2 * Copyright (c) 2000 Mitsaru Iwasaki 3 * Copyright (c) 2000 Michael Smith 4 * Copyright (c) 2000 BSDi 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: src/sys/dev/acpica/Osd/OsdMemory.c,v 1.11 2004/04/14 03:39:08 njl Exp $ 29 */ 30 31 /* 32 * Memory Management 33 */ 34 35 #include "acpi.h" 36 37 #include <sys/kernel.h> 38 #include <sys/malloc.h> 39 #include <vm/vm.h> 40 #include <vm/pmap.h> 41 42 MALLOC_DEFINE(M_ACPICA, "acpica", "ACPICA memory pool"); 43 44 struct acpi_memtrack { 45 struct acpi_memtrack *next; 46 void *base; 47 ACPI_SIZE size; 48 #ifdef ACPI_DEBUG_MEMMAP 49 int freed; 50 struct { 51 const char *func; 52 int line; 53 } mapper, unmapper; 54 #endif 55 }; 56 57 typedef struct acpi_memtrack *acpi_memtrack_t; 58 59 static acpi_memtrack_t acpi_mapbase; 60 61 void * 62 AcpiOsAllocate(ACPI_SIZE Size) 63 { 64 return (kmalloc(Size, M_ACPICA, M_INTWAIT)); 65 } 66 67 void * 68 AcpiOsAllocateZeroed(ACPI_SIZE Size) 69 { 70 return (kmalloc(Size, M_ACPICA, M_INTWAIT | M_ZERO)); 71 } 72 73 void 74 AcpiOsFree(void *Memory) 75 { 76 kfree(Memory, M_ACPICA); 77 } 78 79 #ifdef ACPI_DEBUG_MEMMAP 80 void * 81 _AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length, 82 const char *caller, int line) 83 #else 84 void * 85 AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length) 86 #endif 87 { 88 acpi_memtrack_t track; 89 void *map; 90 91 map = pmap_mapdev((vm_offset_t)Where, Length); 92 if (map == NULL) 93 return(NULL); 94 else { 95 #ifdef ACPI_DEBUG_MEMMAP 96 for (track = acpi_mapbase; track != NULL; track = track->next) { 97 if (track->base == map) 98 break; 99 } 100 #else 101 track = NULL; 102 #endif 103 if (track == NULL) { 104 track = kmalloc(sizeof(*track), M_ACPICA, M_INTWAIT); 105 track->next = acpi_mapbase; 106 track->base = map; 107 } 108 track->size = Length; 109 #ifdef ACPI_DEBUG_MEMMAP 110 track->freed = 0; 111 track->mapper.func = caller; 112 track->mapper.line = line; 113 track->unmapper.func = ""; 114 track->unmapper.line = 0; 115 #endif 116 acpi_mapbase = track; 117 } 118 return(map); 119 } 120 121 #ifdef ACPI_DEBUG_MEMMAP 122 void 123 _AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Length, 124 const char *caller, int line) 125 #else 126 void 127 AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Length) 128 #endif 129 { 130 struct acpi_memtrack **ptrack; 131 acpi_memtrack_t track; 132 133 again: 134 for (ptrack = &acpi_mapbase; (track = *ptrack); ptrack = &track->next) { 135 #ifdef ACPI_DEBUG_MEMMAP 136 if (track->freed) 137 continue; 138 #endif 139 /* 140 * Exact match, degenerate case 141 */ 142 if (track->base == LogicalAddress && track->size == Length) { 143 *ptrack = track->next; 144 pmap_unmapdev((vm_offset_t)track->base, track->size); 145 #ifdef ACPI_DEBUG_MEMMAP 146 track->freed = 1; 147 track->unmapper.func = caller; 148 track->unmapper.line = line; 149 #else 150 kfree(track, M_ACPICA); 151 #endif 152 return; 153 } 154 /* 155 * Completely covered 156 */ 157 if ((char *)LogicalAddress <= (char *)track->base && 158 (char *)LogicalAddress + Length >= (char *)track->base + track->size 159 ) { 160 *ptrack = track->next; 161 pmap_unmapdev((vm_offset_t)track->base, track->size); 162 kprintf("AcpiOsUnmapMemory: Warning, deallocation request too" 163 " large! %p/%08jx (actual was %p/%08jx)\n", 164 LogicalAddress, (intmax_t)Length, 165 track->base, (intmax_t)track->size); 166 #ifdef ACPI_DEBUG_MEMMAP 167 track->freed = 1; 168 track->unmapper.func = caller; 169 track->unmapper.line = line; 170 #else 171 kfree(track, M_ACPICA); 172 #endif 173 goto again; 174 } 175 176 /* 177 * Overlapping 178 */ 179 if ((char *)LogicalAddress + Length >= (char *)track->base && 180 (char *)LogicalAddress < (char *)track->base + track->size 181 ) { 182 kprintf("AcpiOsUnmapMemory: Warning, deallocation did not " 183 "track allocation: %p/%08jx (actual was %p/%08jx)\n", 184 LogicalAddress, (intmax_t)Length, 185 track->base, (intmax_t)track->size); 186 } 187 } 188 kprintf("AcpiOsUnmapMemory: Warning, broken ACPI, bad unmap: %p/%08jx\n", 189 LogicalAddress, (intmax_t)Length); 190 #ifdef ACPI_DEBUG_MEMMAP 191 for (track = acpi_mapbase; track != NULL; track = track->next) { 192 if (track->freed && track->base == LogicalAddress) { 193 kprintf("%s: unmapping: %p/%08jx, mapped by %s:%d," 194 "last unmapped by %s:%d\n", 195 __func__, LogicalAddress, (uintmax_t)Length, 196 track->mapper.func, track->mapper.line, 197 track->unmapper.func, track->unmapper.line 198 ); 199 } 200 } 201 #endif 202 } 203 204 ACPI_STATUS 205 AcpiOsGetPhysicalAddress(void *LogicalAddress, 206 ACPI_PHYSICAL_ADDRESS *PhysicalAddress) 207 { 208 /* We can't necessarily do this, so cop out. */ 209 return (AE_BAD_ADDRESS); 210 } 211 212 /* 213 * There is no clean way to do this. We make the charitable assumption 214 * that callers will not pass garbage to us. 215 */ 216 BOOLEAN 217 AcpiOsReadable (void *Pointer, ACPI_SIZE Length) 218 { 219 return (TRUE); 220 } 221 222 BOOLEAN 223 AcpiOsWritable (void *Pointer, ACPI_SIZE Length) 224 { 225 return (TRUE); 226 } 227 228 ACPI_STATUS 229 AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 *Value, UINT32 Width) 230 { 231 void *LogicalAddress; 232 233 LogicalAddress = AcpiOsMapMemory(Address, Width / 8); 234 if (LogicalAddress == NULL) 235 return (AE_NOT_EXIST); 236 237 switch (Width) { 238 case 8: 239 *Value = *(volatile uint8_t *)LogicalAddress; 240 break; 241 case 16: 242 *Value = *(volatile uint16_t *)LogicalAddress; 243 break; 244 case 32: 245 *Value = *(volatile uint32_t *)LogicalAddress; 246 break; 247 case 64: 248 *Value = *(volatile uint64_t *)LogicalAddress; 249 break; 250 } 251 252 AcpiOsUnmapMemory(LogicalAddress, Width / 8); 253 254 return (AE_OK); 255 } 256 257 ACPI_STATUS 258 AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 Value, UINT32 Width) 259 { 260 void *LogicalAddress; 261 262 LogicalAddress = AcpiOsMapMemory(Address, Width / 8); 263 if (LogicalAddress == NULL) 264 return (AE_NOT_EXIST); 265 266 switch (Width) { 267 case 8: 268 *(volatile uint8_t *)LogicalAddress = Value; 269 break; 270 case 16: 271 *(volatile uint16_t *)LogicalAddress = Value; 272 break; 273 case 32: 274 *(volatile uint32_t *)LogicalAddress = Value; 275 break; 276 case 64: 277 *(volatile uint64_t *)LogicalAddress = Value; 278 break; 279 } 280 281 AcpiOsUnmapMemory(LogicalAddress, Width / 8); 282 283 return (AE_OK); 284 } 285