xref: /dragonfly/sys/dev/acpica/Osd/OsdMemory.c (revision fbc9049b)
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