249 lines
5.9 KiB
C
249 lines
5.9 KiB
C
#include <mman.h>
|
|
#include <logger.h>
|
|
#include <errcode.h>
|
|
#include <string.h>
|
|
#include <utils.h>
|
|
#include <kmalloc.h>
|
|
#include <dtb.h>
|
|
#include <initrd.h>
|
|
|
|
extern uint64_t __kernel_start;
|
|
extern uint64_t __kernel_end;
|
|
extern uint64_t __heap_start;
|
|
extern uint64_t __stack_end;
|
|
|
|
fdt_callback_t mman_dtb_memory_cb = {
|
|
.name = "memory@0",
|
|
.func = mman_fdt_memory_cb_func,
|
|
};
|
|
|
|
void *mman_memory_start = 0x0;
|
|
void *mman_memory_end = 0x0;
|
|
size_t mman_page_cnt = 0;
|
|
page_header_t *mman_frame_array = 0x0;
|
|
|
|
void mman_fdt_memory_cb_func(const vector_t *props)
|
|
{
|
|
for (int i = 0; i < (int)props->size; ++i) {
|
|
if (!strcmp(VEC_AT(fdt_prop_t, props, i)->name, "reg")) {
|
|
mman_memory_start = (void *)(uint64_t)ntoh32(
|
|
*((uint32_t *)VEC_AT(fdt_prop_t, props, i)->value));
|
|
mman_memory_end = (void *)(uint64_t)ntoh32(
|
|
*((uint32_t *)VEC_AT(fdt_prop_t, props, i)->value + 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
// This is an array-like binary tree structure, where LCH (left-child) will
|
|
// always be the largest 2^k size block while RCH not empty.
|
|
#define CUR (&mman_frame_array[idx])
|
|
#define LIDX (((idx + 1) << 1) - 1)
|
|
#define LCH (&mman_frame_array[LIDX])
|
|
#define RIDX (((idx + 1) << 1 | 1) - 1)
|
|
#define RCH (&mman_frame_array[RIDX])
|
|
|
|
static inline
|
|
void _pull(int idx, size_t sz)
|
|
{
|
|
if (LCH->state == PAGE_FREE && RCH->state == PAGE_FREE) {
|
|
if (CUR->state != PAGE_FREE) {
|
|
LOG("node merged");
|
|
DEBUG_MEM((uint64_t)idx);
|
|
}
|
|
CUR->state = PAGE_FREE;
|
|
}
|
|
if (LCH->state != PAGE_FREE || RCH->state != PAGE_FREE)
|
|
CUR->state = PAGE_DIVIDED;
|
|
switch (CUR->state) {
|
|
case PAGE_FREE:
|
|
CUR->maxsz = sz;
|
|
break;
|
|
case PAGE_DIVIDED:
|
|
CUR->maxsz = MAX(LCH->maxsz, RCH->maxsz);
|
|
break;
|
|
case PAGE_ALLOCATED:
|
|
case PAGE_RESERVED:
|
|
CUR->maxsz = 0;
|
|
break;
|
|
default:
|
|
exit(ERR_UNREACHABLE);
|
|
}
|
|
}
|
|
|
|
void mman_init()
|
|
{
|
|
mman_memory_start = ALIGN4K(mman_memory_start);
|
|
mman_memory_end = ALIGN4K(mman_memory_end);
|
|
|
|
// 4KB per page
|
|
mman_page_cnt = (mman_memory_end - mman_memory_start) >> 12;
|
|
mman_frame_array = simple_alloc((mman_page_cnt << 1) * sizeof(page_header_t));
|
|
|
|
LOG(mman_memory_start);
|
|
LOG(mman_memory_end);
|
|
DEBUG_MEM((uint64_t)mman_page_cnt);
|
|
|
|
mman_frame_array[0] = (page_header_t){
|
|
.state = PAGE_FREE,
|
|
.maxsz = msb64(mman_page_cnt),
|
|
};
|
|
|
|
fdt_reserve_entry_t *entry = 0x0;
|
|
for (int i = 0; i < (int)dtb_reserved_entries->size; ++i) {
|
|
entry = VEC_AT(fdt_reserve_entry_t, dtb_reserved_entries, i);
|
|
LOG(ntoh64(entry->address));
|
|
DEBUG_MEM(ntoh64(entry->address) + ntoh64(entry->size));
|
|
reserve_page((void *)ntoh64(entry->address),
|
|
(void *)ntoh64(entry->address) + ntoh64(entry->size));
|
|
}
|
|
|
|
reserve_page(&__kernel_start, &__kernel_end);
|
|
reserve_page(&__heap_start, &__stack_end);
|
|
reserve_page(dtb_start, dtb_end);
|
|
reserve_page(initrd_start, initrd_end);
|
|
|
|
init_mman_kmalloc();
|
|
}
|
|
|
|
static inline
|
|
uint64_t _allocate_page(size_t req, int idx, uint64_t l, uint64_t r)
|
|
{
|
|
uint64_t sz = r - l;
|
|
if (req > sz || req > CUR->maxsz) {
|
|
return MMAN_NO_PAGE;
|
|
}
|
|
|
|
uint64_t m = l + ((msb64(sz) == sz) ? (sz >> 1) : msb64(sz));
|
|
switch (CUR->state) {
|
|
case PAGE_FREE:
|
|
if (req == sz) {
|
|
LOG("page allocated");
|
|
LOG(l);
|
|
DEBUG_MEM(r);
|
|
CUR->state = PAGE_ALLOCATED;
|
|
CUR->maxsz = 0;
|
|
return l;
|
|
}
|
|
LCH->state = RCH->state = PAGE_FREE;
|
|
LCH->maxsz = msb64(m - l);
|
|
RCH->maxsz = msb64(r - m);
|
|
break;
|
|
case PAGE_DIVIDED:
|
|
break;
|
|
case PAGE_ALLOCATED:
|
|
case PAGE_RESERVED:
|
|
return MMAN_NO_PAGE;
|
|
default:
|
|
exit(ERR_UNREACHABLE);
|
|
}
|
|
|
|
uint64_t ret = MMAN_NO_PAGE;
|
|
if (ret == MMAN_NO_PAGE && LCH->maxsz >= req)
|
|
ret = _allocate_page(req, LIDX, l, m);
|
|
if (ret == MMAN_NO_PAGE && RCH->maxsz >= req)
|
|
ret = _allocate_page(req, RIDX, m, r);
|
|
_pull(idx, sz);
|
|
return ret;
|
|
}
|
|
|
|
void *allocate_page(size_t page_cnt)
|
|
{
|
|
if (msb64(page_cnt) != page_cnt)
|
|
exit(ERR_INVALID_OP);
|
|
|
|
uint64_t offset = _allocate_page(page_cnt, 0, 0, mman_page_cnt);
|
|
|
|
if (offset == MMAN_NO_PAGE)
|
|
exit(ERR_NO_MEM);
|
|
// return (void *)0x0;
|
|
|
|
return mman_memory_start + offset * (1 << 12);
|
|
}
|
|
|
|
static inline
|
|
void _free_page(uint64_t req, int idx, uint64_t l, uint64_t r)
|
|
{
|
|
uint64_t sz = r - l;
|
|
|
|
switch (CUR->state) {
|
|
case PAGE_FREE:
|
|
return;
|
|
case PAGE_ALLOCATED:
|
|
if (req == l) {
|
|
LOG("page freed");
|
|
LOG(l);
|
|
DEBUG_MEM(r);
|
|
CUR->state = PAGE_FREE;
|
|
CUR->maxsz = sz;
|
|
return;
|
|
}
|
|
case PAGE_DIVIDED:
|
|
break;
|
|
case PAGE_RESERVED:
|
|
default:
|
|
exit(ERR_UNREACHABLE);
|
|
}
|
|
|
|
uint64_t m = l + ((msb64(sz) == sz) ? (sz >> 1) : msb64(sz));
|
|
if (l <= req && req < m)
|
|
_free_page(req, LIDX, l, m);
|
|
if (m <= req && req < r)
|
|
_free_page(req, RIDX, m, r);
|
|
_pull(idx, sz);
|
|
}
|
|
|
|
void free_page(void *page)
|
|
{
|
|
if (ALIGN4K(page) != page)
|
|
exit(ERR_INVALID_OP);
|
|
|
|
uint64_t start = ((uint64_t)page - (uint64_t)mman_memory_start) >> 12;
|
|
_free_page(start, 0, 0, mman_page_cnt);
|
|
}
|
|
|
|
static inline
|
|
void _reserve_page(uint64_t ql, uint64_t qr, int idx, uint64_t l, uint64_t r)
|
|
{
|
|
if (qr <= l || r <= ql)
|
|
return;
|
|
|
|
uint64_t sz = r - l;
|
|
if (ql <= l && r <= qr && msb64(sz) == sz) {
|
|
if (CUR->state == PAGE_RESERVED)
|
|
return;
|
|
if (CUR->state != PAGE_FREE)
|
|
exit(ERR_INVALID_MEM);
|
|
|
|
LOG("page reserved");
|
|
LOG(l);
|
|
DEBUG_MEM(r);
|
|
CUR->state = PAGE_RESERVED;
|
|
CUR->maxsz = 0;
|
|
return;
|
|
}
|
|
|
|
uint64_t m = l + ((msb64(sz) == sz) ? (sz >> 1) : msb64(sz));
|
|
if (CUR->state == PAGE_FREE) {
|
|
LCH->state = RCH->state = PAGE_FREE;
|
|
LCH->maxsz = msb64(m - l);
|
|
RCH->maxsz = msb64(r - m);
|
|
}
|
|
|
|
if (ql < m)
|
|
_reserve_page(ql, qr, LIDX, l, m);
|
|
if (m < qr)
|
|
_reserve_page(ql, qr, RIDX, m, r);
|
|
_pull(idx, sz);
|
|
}
|
|
|
|
void reserve_page(void *begin, void *end)
|
|
{
|
|
uint64_t ql = ((uint64_t)begin - (uint64_t)mman_memory_start) >> 12;
|
|
uint64_t qr = (((uint64_t)end - (uint64_t)mman_memory_start - 1) >> 12) + 1;
|
|
|
|
LOG("reserve page");
|
|
LOG(ql);
|
|
DEBUG_MEM(qr);
|
|
_reserve_page(ql, qr, 0, 0, mman_page_cnt);
|
|
}
|