Files
mkrtos-real/mkrtos_knl/knl/mm_page.c
2023-09-29 01:03:19 +08:00

130 lines
3.2 KiB
C

/**
* @file mm_page.c
* @author zhangzheng (1358745329@qq.com)
* @brief
* @version 0.1
* @date 2023-09-29
*
* @copyright Copyright (c) 2023
*
*/
#include "types.h"
#include "mm_space.h"
#include "mm_wrap.h"
#include "assert.h"
#include "err.h"
#include "mm_page.h"
#include "mm_space.h"
#include "mpu.h"
static mm_entry_t *mm_pages_entry_alloc(mm_pages_t *mm, addr_t new_addr)
{
for (int i = 0; i < PAGE_NR; i++)
{
if (mm->list[i].addr == 0)
{
mm_entry_set_addr(&mm->list[i].addr, new_addr);
return &mm->list[i];
}
}
return NULL;
}
static void mm_pages_entry_free(mm_pages_t *mm, addr_t free_addr)
{
for (int i = 0; i < PAGE_NR; i++)
{
if (mm_entry_get_addr(mm->list[i].addr) == free_addr)
{
mm->list[i].addr = 0;
}
}
}
static mm_entry_t *mm_pages_find_first(mm_pages_t *mm, addr_t free_addr)
{
for (int i = 0; i < PAGE_NR; i++)
{
if (mm_entry_get_addr(mm->list[i].addr) == free_addr && mm_entry_get_first(mm->list[i].addr))
{
return &mm->list[i];
}
}
return NULL;
}
void mm_pages_init(mm_pages_t *mm, region_info_t *regi)
{
for (int i = 0; i < PAGE_NR; i++)
{
mm->list[i].addr = 0;
}
mm->region = regi;
}
int mm_pages_alloc_page(mm_pages_t *mm, ram_limit_t *lim, size_t pnf_nr, addr_t *alloc_addr, uint8_t attrs)
{
assert(mm);
assert(alloc_addr);
void *mem = mm_limit_alloc_align(lim, pnf_nr * PAGE_SIZE, PAGE_SIZE);
if (!mem)
{
return -ENOMEM;
}
for (int i = 0; i < pnf_nr; i++)
{
mm_entry_t *mm_entry = mm_pages_entry_alloc(mm, (addr_t)mem + i * PAGE_SIZE);
if (mm_entry == NULL)
{
mm_limit_free_align(lim, mem, pnf_nr * PAGE_SIZE);
/*TODO:清除申请的所有*/
return -ENOMEM;
}
if (i == 0)
{
mm_entry_set_first(&mm_entry->addr);
mm_entry->attrs = attrs;
mm_entry->pfn_nr = pnf_nr;
}
else
{
mm_entry->attrs = attrs;
mm_entry->pfn_nr = 1;
}
}
*alloc_addr = (addr_t)mem;
return 0;
}
void mm_pages_free_page(mm_pages_t *mm, ram_limit_t *lim, addr_t addr, size_t pfn_nr)
{
addr = ALIGN_DOWN(addr, PAGE_SIZE);
mm_entry_t *mm_entry = mm_pages_find_first(mm, addr);
if (!mm_entry)
{
return;
}
addr_t start_addr = mm_entry_get_addr(mm_entry->addr);
mm_limit_free_align(lim, (void *)start_addr, PAGE_SIZE * mm_entry->pfn_nr);
for (int i = 0; i < pfn_nr; i++)
{
mm_pages_entry_free(mm, start_addr);
start_addr += PAGE_SIZE;
}
mpu_region_clr(mm->region->region_inx);
}
void *mm_page_alloc_fault(mm_pages_t *mm, addr_t addr)
{
addr = ALIGN_DOWN(addr, PAGE_SIZE);
for (int i = 0; i < PAGE_NR; i++)
{
if (mm_entry_get_addr(mm->list[i].addr) == addr)
{
mpu_calc_regs(mm->region, addr, ffs(PAGE_SIZE),
mm->list[i].attrs, 0x0);
mpu_region_set(mm->region->region_inx, mm->region->rbar,
mm->region->rasr);
return (void *)(mm->list[i].addr);
}
}
return NULL;
}