#include "acpi.h"
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <vm/vm.h>
#include <vm/pmap.h>
MALLOC_DEFINE(M_ACPICA, "acpica", "ACPICA memory pool");
struct acpi_memtrack {
struct acpi_memtrack *next;
void *base;
ACPI_SIZE size;
#ifdef ACPI_DEBUG_MEMMAP
int freed;
struct {
const char *func;
int line;
} mapper, unmapper;
#endif
};
typedef struct acpi_memtrack *acpi_memtrack_t;
static acpi_memtrack_t acpi_mapbase;
void *
AcpiOsAllocate(ACPI_SIZE Size)
{
return (kmalloc(Size, M_ACPICA, M_INTWAIT));
}
void *
AcpiOsAllocateZeroed(ACPI_SIZE Size)
{
return (kmalloc(Size, M_ACPICA, M_INTWAIT | M_ZERO));
}
void
AcpiOsFree(void *Memory)
{
kfree(Memory, M_ACPICA);
}
#ifdef ACPI_DEBUG_MEMMAP
void *
_AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length,
const char *caller, int line)
#else
void *
AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length)
#endif
{
acpi_memtrack_t track;
void *map;
map = pmap_mapdev((vm_offset_t)Where, Length);
if (map == NULL)
return(NULL);
else {
#ifdef ACPI_DEBUG_MEMMAP
for (track = acpi_mapbase; track != NULL; track = track->next) {
if (track->base == map)
break;
}
#else
track = NULL;
#endif
if (track == NULL) {
track = kmalloc(sizeof(*track), M_ACPICA, M_INTWAIT);
track->next = acpi_mapbase;
track->base = map;
}
track->size = Length;
#ifdef ACPI_DEBUG_MEMMAP
track->freed = 0;
track->mapper.func = caller;
track->mapper.line = line;
track->unmapper.func = "";
track->unmapper.line = 0;
#endif
acpi_mapbase = track;
}
return(map);
}
#ifdef ACPI_DEBUG_MEMMAP
void
_AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Length,
const char *caller, int line)
#else
void
AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Length)
#endif
{
struct acpi_memtrack **ptrack;
acpi_memtrack_t track;
again:
for (ptrack = &acpi_mapbase; (track = *ptrack); ptrack = &track->next) {
#ifdef ACPI_DEBUG_MEMMAP
if (track->freed)
continue;
#endif
if (track->base == LogicalAddress && track->size == Length) {
*ptrack = track->next;
pmap_unmapdev((vm_offset_t)track->base, track->size);
#ifdef ACPI_DEBUG_MEMMAP
track->freed = 1;
track->unmapper.func = caller;
track->unmapper.line = line;
#else
kfree(track, M_ACPICA);
#endif
return;
}
if ((char *)LogicalAddress <= (char *)track->base &&
(char *)LogicalAddress + Length >= (char *)track->base + track->size
) {
*ptrack = track->next;
pmap_unmapdev((vm_offset_t)track->base, track->size);
kprintf("AcpiOsUnmapMemory: Warning, deallocation request too"
" large! %p/%08jx (actual was %p/%08jx)\n",
LogicalAddress, (intmax_t)Length,
track->base, (intmax_t)track->size);
#ifdef ACPI_DEBUG_MEMMAP
track->freed = 1;
track->unmapper.func = caller;
track->unmapper.line = line;
#else
kfree(track, M_ACPICA);
#endif
goto again;
}
if ((char *)LogicalAddress + Length >= (char *)track->base &&
(char *)LogicalAddress < (char *)track->base + track->size
) {
kprintf("AcpiOsUnmapMemory: Warning, deallocation did not "
"track allocation: %p/%08jx (actual was %p/%08jx)\n",
LogicalAddress, (intmax_t)Length,
track->base, (intmax_t)track->size);
}
}
kprintf("AcpiOsUnmapMemory: Warning, broken ACPI, bad unmap: %p/%08jx\n",
LogicalAddress, (intmax_t)Length);
#ifdef ACPI_DEBUG_MEMMAP
for (track = acpi_mapbase; track != NULL; track = track->next) {
if (track->freed && track->base == LogicalAddress) {
kprintf("%s: unmapping: %p/%08jx, mapped by %s:%d,"
"last unmapped by %s:%d\n",
__func__, LogicalAddress, (uintmax_t)Length,
track->mapper.func, track->mapper.line,
track->unmapper.func, track->unmapper.line
);
}
}
#endif
}
ACPI_STATUS
AcpiOsGetPhysicalAddress(void *LogicalAddress,
ACPI_PHYSICAL_ADDRESS *PhysicalAddress)
{
return (AE_BAD_ADDRESS);
}
BOOLEAN
AcpiOsReadable (void *Pointer, ACPI_SIZE Length)
{
return (TRUE);
}
BOOLEAN
AcpiOsWritable (void *Pointer, ACPI_SIZE Length)
{
return (TRUE);
}
ACPI_STATUS
AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 *Value, UINT32 Width)
{
void *LogicalAddress;
LogicalAddress = AcpiOsMapMemory(Address, Width / 8);
if (LogicalAddress == NULL)
return (AE_NOT_EXIST);
switch (Width) {
case 8:
*Value = *(volatile uint8_t *)LogicalAddress;
break;
case 16:
*Value = *(volatile uint16_t *)LogicalAddress;
break;
case 32:
*Value = *(volatile uint32_t *)LogicalAddress;
break;
case 64:
*Value = *(volatile uint64_t *)LogicalAddress;
break;
}
AcpiOsUnmapMemory(LogicalAddress, Width / 8);
return (AE_OK);
}
ACPI_STATUS
AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 Value, UINT32 Width)
{
void *LogicalAddress;
LogicalAddress = AcpiOsMapMemory(Address, Width / 8);
if (LogicalAddress == NULL)
return (AE_NOT_EXIST);
switch (Width) {
case 8:
*(volatile uint8_t *)LogicalAddress = Value;
break;
case 16:
*(volatile uint16_t *)LogicalAddress = Value;
break;
case 32:
*(volatile uint32_t *)LogicalAddress = Value;
break;
case 64:
*(volatile uint64_t *)LogicalAddress = Value;
break;
}
AcpiOsUnmapMemory(LogicalAddress, Width / 8);
return (AE_OK);
}