160 lines
3.6 KiB
C
160 lines
3.6 KiB
C
#include <assert.h>
|
||
#include <mmu.h>
|
||
#include <x86.h>
|
||
|
||
#include <kern/stdio.h>
|
||
#include <kern/kmalloc.h>
|
||
#include <kern/sche.h>
|
||
#include <kern/trap.h>
|
||
|
||
static u32 phy_malloc_4k_lock;
|
||
static phyaddr_t phy_malloc_4k_p = 96 * MB;
|
||
|
||
// 96MB~128MB = 0x0600_0000 ~ 0x0800_0000
|
||
// 32MB = 32 * 1024 / 4 = 8192 PAGES
|
||
#define PHY_START (96 * MB)
|
||
#define PHY_END (128 * MB)
|
||
#define PHY_PAGENUM ((PHY_END - PHY_START) / PGSIZE)
|
||
// map them to 8192 slots
|
||
#define PHY_INDEX(paddr) ((paddr - PHY_START) >> 12)
|
||
#define PHY_PADDR(idx) ((idx << 12) + PHY_START)
|
||
// we have a head index point to the lowest free slot
|
||
// if slot[i] is free, slot[i] = the index of the next free slot
|
||
// else, slot[i] = -1
|
||
// when initialize, slots are initialized to {1, 2, 3, ...}
|
||
// when alloc, head mov to slot[i], then set slot[i] = 0
|
||
// when free, set slot[i]=head, head = i
|
||
|
||
static int phy_free_head;
|
||
static int phy_free_table[PHY_PAGENUM];
|
||
|
||
void phy_init_4k() {
|
||
for (int i = 0; i < PHY_PAGENUM - 1; ++ i) {
|
||
phy_free_table[i] = i + 1;
|
||
}
|
||
phy_free_table[PHY_PAGENUM-1] = -1;
|
||
phy_free_head = 0;
|
||
}
|
||
|
||
/*
|
||
* 释放物理页面,这里并没有为你实现好free_4k的代码,
|
||
* 你需要自己实现一个数据结构用于维护释放的页面,
|
||
* 需要有回收资源的意识,这是一个系统必须有的功能。
|
||
*/
|
||
void
|
||
phy_free_4k(phyaddr_t paddr)
|
||
{
|
||
assert(paddr % PGSIZE == 0);
|
||
assert(96 * MB <= paddr && paddr < 128 * MB);
|
||
while(xchg(&phy_malloc_4k_lock, 1) == 1)
|
||
schedule();
|
||
phy_free_table[PHY_INDEX(paddr)] = phy_free_head;
|
||
phy_free_head = PHY_INDEX(paddr);
|
||
xchg(&phy_malloc_4k_lock, 0);
|
||
}
|
||
/*
|
||
* 分配物理页面,每次分配4kb,一页
|
||
* 分配的物理内存区间为96MB~128MB
|
||
*/
|
||
phyaddr_t
|
||
phy_malloc_4k(void)
|
||
{
|
||
while(xchg(&phy_malloc_4k_lock, 1) == 1)
|
||
schedule();
|
||
assert(0 <= phy_free_head && phy_free_head < PHY_PAGENUM);
|
||
phyaddr_t paddr = PHY_PADDR(phy_free_head);
|
||
phy_free_head = phy_free_table[phy_free_head];
|
||
phy_free_table[PHY_INDEX(paddr)] = -1;
|
||
// assert(phy_malloc_4k_p < 128 * MB);
|
||
// phyaddr_t paddr = phy_malloc_4k_p;
|
||
// phy_malloc_4k_p += PGSIZE;
|
||
free:
|
||
xchg(&phy_malloc_4k_lock, 0);
|
||
return paddr;
|
||
}
|
||
|
||
struct kmalloc_header {
|
||
struct kmalloc_header *ptr;
|
||
size_t size;
|
||
};
|
||
|
||
static struct kmalloc_header *freePtr;
|
||
static u32 malloc_lock;
|
||
|
||
/*
|
||
* 释放kmalloc申请的内存
|
||
*/
|
||
void
|
||
kfree(void *v)
|
||
{
|
||
struct kmalloc_header *bp, *p;
|
||
bp = (struct kmalloc_header*)v - 1;
|
||
|
||
while(xchg(&malloc_lock, 1) == 1)
|
||
schedule();
|
||
|
||
for (p = freePtr; !(bp > p && bp < p->ptr); p = p->ptr) {
|
||
if (p >= p->ptr && (bp > p || bp < p->ptr)) {
|
||
break;
|
||
}
|
||
}
|
||
if (bp + bp->size == p->ptr) {
|
||
bp->size += p->ptr->size;
|
||
bp->ptr = p->ptr->ptr;
|
||
} else {
|
||
bp->ptr = p->ptr;
|
||
}
|
||
if (p + p->size == bp) {
|
||
p->size += bp->size;
|
||
p->ptr = bp->ptr;
|
||
} else {
|
||
p->ptr = bp;
|
||
}
|
||
freePtr = p;
|
||
free:
|
||
xchg(&malloc_lock, 0);
|
||
}
|
||
|
||
/*
|
||
* 分配内存,大小为n字节。
|
||
* 分配物理内存区间为64MB~96MB
|
||
*/
|
||
void *
|
||
kmalloc(size_t n)
|
||
{
|
||
struct kmalloc_header *p, *prevP;
|
||
size_t nUnits;
|
||
void *ret;
|
||
|
||
while(xchg(&malloc_lock, 1) == 1)
|
||
schedule();
|
||
|
||
nUnits = (n + sizeof(struct kmalloc_header) - 1)
|
||
/ sizeof(struct kmalloc_header) + 1;
|
||
if ((prevP = freePtr) == 0) {
|
||
freePtr = prevP = (void *)K_PHY2LIN(64 * MB);
|
||
freePtr->ptr = freePtr;
|
||
freePtr->size = (32 * MB) / sizeof(struct kmalloc_header);
|
||
}
|
||
for (p = prevP->ptr ; ; prevP = p, p = p->ptr) {
|
||
if (p->size >= nUnits) {
|
||
if (p->size == nUnits) {
|
||
prevP->ptr = p->ptr;
|
||
} else {
|
||
p->size -= nUnits;
|
||
p += p->size;
|
||
p->size = nUnits;
|
||
}
|
||
freePtr = prevP;
|
||
ret = (void*)(p + 1);
|
||
goto free;
|
||
}
|
||
if (p == freePtr) {
|
||
panic("malloc failed!");
|
||
}
|
||
}
|
||
free:
|
||
xchg(&malloc_lock, 0);
|
||
return ret;
|
||
}
|