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 *
AcpiOsAllocate(ACPI_SIZE Size)62 AcpiOsAllocate(ACPI_SIZE Size)
63 {
64 return (kmalloc(Size, M_ACPICA, M_INTWAIT));
65 }
66
67 void *
AcpiOsAllocateZeroed(ACPI_SIZE Size)68 AcpiOsAllocateZeroed(ACPI_SIZE Size)
69 {
70 return (kmalloc(Size, M_ACPICA, M_INTWAIT | M_ZERO));
71 }
72
73 void
AcpiOsFree(void * Memory)74 AcpiOsFree(void *Memory)
75 {
76 kfree(Memory, M_ACPICA);
77 }
78
79 #ifdef ACPI_DEBUG_MEMMAP
80 void *
_AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where,ACPI_SIZE Length,const char * caller,int line)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
_AcpiOsUnmapMemory(void * LogicalAddress,ACPI_SIZE Length,const char * caller,int line)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
AcpiOsGetPhysicalAddress(void * LogicalAddress,ACPI_PHYSICAL_ADDRESS * PhysicalAddress)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
AcpiOsReadable(void * Pointer,ACPI_SIZE Length)217 AcpiOsReadable (void *Pointer, ACPI_SIZE Length)
218 {
219 return (TRUE);
220 }
221
222 BOOLEAN
AcpiOsWritable(void * Pointer,ACPI_SIZE Length)223 AcpiOsWritable (void *Pointer, ACPI_SIZE Length)
224 {
225 return (TRUE);
226 }
227
228 ACPI_STATUS
AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address,UINT64 * Value,UINT32 Width)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
AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address,UINT64 Value,UINT32 Width)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