Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add refcount tracking for ACPICA's mappings and use VIRT_KERNEL_MAP area #241

Merged
merged 4 commits into from
Jan 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ endif
ifeq ($(HAVE_KVM), kvm)
QEMU_PARAMS += -enable-kvm
endif # HAVE_KVM
QEMU_PARAMS += -m 8192
QEMU_PARAMS += -m 128
QEMU_PARAMS += -display none -vga none -vnc none
QEMU_PARAMS += -serial stdio
QEMU_PARAMS += -smp cpus=2
Expand Down
75 changes: 68 additions & 7 deletions drivers/acpi/acpica/osl.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,35 @@

#include "acpi.h"

struct mapped_frame {
struct list_head list;
mfn_t mfn;
uint64_t refcount;
};
typedef struct mapped_frame mapped_frame_t;

static list_head_t mapped_frames;

static spinlock_t map_lock = SPINLOCK_INIT;

/* General OS functions */

ACPI_STATUS AcpiOsInitialize(void) {
dprintk("ACPI OS Initialization:\n");

list_init(&mapped_frames);
return AE_OK;
}

ACPI_STATUS AcpiOsTerminate(void) {
mapped_frame_t *frame;

dprintk("ACPI OS Termination:\n");

list_for_each_entry (frame, &mapped_frames, list) {
list_unlink(&frame->list);
kfree(frame);
}
return AE_OK;
}

Expand Down Expand Up @@ -214,7 +232,7 @@ BOOLEAN AcpiOsReadable(void *Memory, ACPI_SIZE Length) {
for (mfn_t mfn = virt_to_mfn(Memory); mfn <= virt_to_mfn((char *) Memory + Length);
++mfn) {
success = false;
mem = mfn_to_virt_kern(mfn);
mem = mfn_to_virt_map(mfn);
asm volatile("1: movq ( %[mem] ), %%rax; movq $1, %[success];"
"2:" ASM_EXTABLE(1b, 2b)
: [ success ] "=m"(success)
Expand All @@ -233,7 +251,7 @@ BOOLEAN AcpiOsWriteable(void *Memory, ACPI_SIZE Length) {
for (mfn_t mfn = virt_to_mfn(Memory); mfn <= virt_to_mfn((char *) Memory + Length);
++mfn) {
success = false;
mem = mfn_to_virt_kern(mfn);
mem = mfn_to_virt_map(mfn);
asm volatile("1: orq $0, ( %[mem] ); movq $1, %[success];"
"2:" ASM_EXTABLE(1b, 2b)
: [ success ] "=m"(success), [ mem ] "=r"(mem)
Expand All @@ -246,20 +264,52 @@ BOOLEAN AcpiOsWriteable(void *Memory, ACPI_SIZE Length) {
return success;
}

static inline mapped_frame_t *find_mapped_frame(mfn_t mfn) {
mapped_frame_t *frame;

list_for_each_entry (frame, &mapped_frames, list) {
if (frame->mfn == mfn)
return frame;
}

return NULL;
}

static inline void new_mapped_frame(mfn_t mfn) {
mapped_frame_t *frame = kzalloc(sizeof(*frame));
frame->mfn = mfn;
frame->refcount = 1;
list_add(&frame->list, &mapped_frames);
}

void *AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress, ACPI_SIZE Length) {
unsigned offset = PhysicalAddress & ~PAGE_MASK;
unsigned num_pages = ((offset + Length) / PAGE_SIZE) + 1;
mfn_t mfn = paddr_to_mfn(PhysicalAddress);
void *va = NULL;

spin_lock(&map_lock);
for (unsigned i = 0; i < num_pages; i++, mfn++) {
void *_va = kmap_4k(mfn, L1_PROT);
if (!_va)
return NULL;
mapped_frame_t *frame = find_mapped_frame(mfn);
void *_va;

if (!frame) {
_va = mmap_4k(mfn, L1_PROT);
if (!_va) {
spin_unlock(&map_lock);
return NULL;
}
new_mapped_frame(mfn);
}
else {
frame->refcount++;
wipawel marked this conversation as resolved.
Show resolved Hide resolved
_va = mfn_to_virt_map(mfn);
}

if (!va)
va = _ptr(_ul(_va) + offset);
}
spin_unlock(&map_lock);

return va;
}
Expand All @@ -269,8 +319,19 @@ void AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Length) {
unsigned num_pages = ((offset + Length) / PAGE_SIZE) + 1;
mfn_t mfn = virt_to_mfn(LogicalAddress);

for (unsigned i = 0; i < num_pages; i++, mfn++)
vunmap(mfn_to_virt_kern(mfn), PAGE_ORDER_4K);
spin_lock(&map_lock);
for (unsigned i = 0; i < num_pages; i++, mfn++) {
mapped_frame_t *frame = find_mapped_frame(mfn);
BUG_ON(!frame || frame->refcount == 0);

if (--frame->refcount > 0)
continue;
wipawel marked this conversation as resolved.
Show resolved Hide resolved

vunmap(mfn_to_virt_map(mfn), PAGE_ORDER_4K);
list_unlink(&frame->list);
kfree(frame);
}
spin_unlock(&map_lock);
}

/* Task management functions */
Expand Down