summaryrefslogtreecommitdiff
path: root/arch/i386/kernel/pmem.c
blob: e59c80bd9d55be14ccf85406258a5d2d2b4dc070 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <kernel/pmem.h>
#include <kernel/asm.h>
#include <kernel/panic.h>
#include <kernel/paging.h>
#include <libk/io.h>
#include <libk/string.h>

struct pfa_page freelist;

void pfa_init(struct mboot_info *header) {
        struct mboot_mmap_entry *mme;
        struct mboot_mmap_entry *temp_map;
        for (uintptr_t i = 0; i < header->mmap_length; i += sizeof(struct mboot_mmap_entry)) {
                mme = (struct mboot_mmap_entry*)(header->mmap_addr + i);
                temp_map = (struct mboot_mmap_entry*)GET_VADDR(mme);
                map_page(NULL, (uintptr_t)mme, (uintptr_t)temp_map, PD_PRES);
                if (temp_map->type == MBOOT_MEM_AVAILABLE)
                        pfa_free_range(temp_map->addr_low, temp_map->addr_low + temp_map->len_low);
                unmap_page(NULL, (uintptr_t)temp_map);
        }
}

uintptr_t pfa_alloc(void) {
        struct pfa_page *ret = freelist.next;
        if (ret == NULL)
                return PFA_ALLOC_ERR;

        struct pfa_page *temp_map = (struct pfa_page*)0x1000;
        map_page(NULL, (uintptr_t)ret, (uintptr_t)temp_map, PD_PRES | PD_RW);
        memset((char*)temp_map, 0, PAGE_SIZE);
        unmap_page(NULL, (uintptr_t)temp_map);
        return (uintptr_t)ret;
}

void pfa_free(uintptr_t paddr) {
        if (paddr % PAGE_SIZE != 0)
                panic("Task attempted to free non-aligned memory");
        if (paddr == 0)
                return;
        if (paddr >= KSTART && paddr < KEND)
                return;
        if (paddr >= 0x80000 && paddr < 0x100000)
                return;

        struct pfa_page *temp_map = (struct pfa_page*)0x1000;
        map_page(NULL, paddr, (uintptr_t)temp_map, PD_PRES | PD_RW);
        memset(temp_map, 1, 32);
        temp_map->next = freelist.next;
        freelist.next = (struct pfa_page*)paddr;
        unmap_page(NULL, (uintptr_t)temp_map);
}

void pfa_free_range(uintptr_t start, uintptr_t end) {
        for (uintptr_t i = start; i < end; i += PAGE_SIZE)
                pfa_free(i);
}