📄 mmu.c
字号:
#include "mmu.h"
#include "cpu.h"
#include "types.h"
void clear_mem(u32 addr_start,u32 addr_end)
{
asm volatile(
"ldr r0,%0 \n\t"
"ldr r1,%1 \n\t"
"ldr r2,=0x00000000 \n\t"
"1: str r2,[r0],#4 \n\t"
"cmp r0,r1 \n\t"
"bne 1b \n\t"
:
:"m"(addr_start),"m"(addr_end)
:"r0","r1","r2"
);
}
/*
* 页目录设置函数,页目录总共有4096个目录项。
* base和limit虚拟地址的基地址和范围。
* pg_table是页表基地址,pg_table必须是1kb的边界
*/
int setup_directory(u32 base,u32 limit,u32 pg_table,u32 attr)
{
//页目录项
u32 *dir_entry=(unsigned int *)DIRECTORY_BASE+(base>>20);
u32 dirs;
u32 dir_count;
//pg_table不是1kb的边界,返回-1
if(pg_table&0x3ff)
{
return -1;
}
//总共要多设置多少个目录项
dirs=(limit-base)>>20;
for(dir_count=0;dir_count<=dirs;dir_count++)
{
*dir_entry=pg_table|attr;
pg_table+=PAGE_TABLE_SIZE;
dir_entry++;
}
return 1;
}
/*
* 页表设置函数,每页表总共有256个页表项。
* base和limit虚拟地址的基地址和范围。
* phy_addr是要映射的物理地址,phy_addr必须是4kb的边界
*/
int paging(u32 base,u32 limit,u32 phy_addr,u32 attr)
{
u32 *dir_entry =(unsigned int *)DIRECTORY_BASE+(base>>20);
u32 *page_entry;
u32 dir_count;
u32 page_count;
//phy_addr不是4kb的边界,返回-1
if((phy_addr&0xfff))
{
return -1;
}
//总共要多设置的目录项个数为 (limit-base)>>20
for(dir_count=0;dir_count<=(limit-base)>>20;dir_count++)
{
page_entry =(unsigned int *)(*dir_entry&0xFFFFFC00);
//每个页表有256个页表项
for(page_count=0;page_count<256;page_count++)
{
*page_entry=phy_addr|attr;
phy_addr+=SMALL_PAGE_SIZE;
page_entry++;
}
dir_entry++;
}
return 1;
}
/*
* 本函数将指定的虚拟地址映射到指定的物理地址
* 是很好用的一个工具函数 : )
*/u32 address_map(u32 v_addr,u32 p_addr,u32 attr)
{
u32 *dir_entry=(unsigned int *)DIRECTORY_BASE+(v_addr>>20);
u32 *page_entry;
if(p_addr&0xfff)
{
return -1;
}
page_entry=(unsigned int*)(*dir_entry&0xFFFFFC00)+((v_addr>>12)&0xff);
*page_entry=p_addr|attr;
return 1;
}
//设置sdram页目录项
void setup_sdram_directory()
{
/*
* CLIENT 将使分配的内存在被访问的时候进行权限检测
*/
setup_directory(SDRAM_BASE,(SDRAM_LIMIT-1),
RAM_PAGE_TABLE_BASE,
COARSE_PAGE_DESC|CLIENT);
}
//设置sfr页目录项
void setup_sfr_directory()
{
/*
* CLIENT 将使分配的内存在被访问的时候进行权限检测
*/
setup_directory(SFR_BASE,(SFR_LIMIT-1),
SFR_PAGE_TABLE_BASE,
COARSE_PAGE_DESC|CLIENT);
}
//设置异常向量表页目录项
void setup_exception_directory()
{
/*
* CLIENT 将使分配的内存在被访问的时候进行权限检测
*/
setup_directory(0xfff00000,0xffffffff,
VECTOR_PAGE_TABLE_BASE,
COARSE_PAGE_DESC|CLIENT);
}
//设置DSP表页目录项
void setup_dsp_directory()
{
/*
* CLIENT 将使分配的内存在被访问的时候进行权限检测
*/
setup_directory(DSP_BASE,(DSP_LIMIT-1),
DSP_PAGE_TABLE_BASE,
COARSE_PAGE_DESC|CLIENT);
}
/*
* sdram进行分页
*/
void setup_sdram_page()
{
/*
* SMALL_PAGE_DESC为SMALL_PAGE|AP0|AP1|AP2|AP3
* 其中AP0,AP1,Ap2,AP3使该页面对内核级的程序具
* 有读写许可,而对用户级的程序只具有读许可
*/
paging(SDRAM_BASE,(SDRAM_LIMIT-1),
0x30000000,
SMALL_PAGE_DESC|CACHEABLE);//CACHEABLE开启内存加速功能
}
/*
* sfr进行分页
*/
void setup_sfr_page()
{
/*
* SMALL_PAGE_DESC为SMALL_PAGE|AP0|AP1|AP2|AP3
* 其中AP0,AP1,Ap2,AP3使该页面对内核级的程序具
* 有读写许可,而对用户级的程序只具有读许可
*/
paging(SFR_BASE,(SFR_LIMIT-1),
0x48000000,
SMALL_PAGE_DESC);
}
/*
* DSP地址进行分页
*/
void setup_dsp_page()
{
/*
* SMALL_PAGE_DESC为SMALL_PAGE|AP0|AP1|AP2|AP3
* 其中AP0,AP1,Ap2,AP3使该页面对内核级的程序具
* 有读写许可,而对用户级的程序只具有读许可
*/
paging(DSP_BASE,(DSP_LIMIT-1),
DSP_BASE,
SMALL_PAGE_DESC);
}
/*
* 设置中断向量的映射关系,本系统的中断向量采用高端模式(0xffff0000),
* 故需要把0xffff0000映射到物理地址0x30075000(KERNEL_BASE)
*/
void setup_exception_vector()
{
address_map(0xffff0000,KERNEL_BASE,SMALL_PAGE_DESC|CACHEABLE);
}
void init_page_directory()
{
setup_sdram_directory();
setup_sfr_directory();
setup_exception_directory();
setup_dsp_directory();
}
void mem_map()
{
setup_sdram_page();
setup_sfr_page();
setup_exception_vector();
setup_dsp_page();
}
void setup_ttb()
{
invalidate_IDCache();
invalidate_TLBs();
//对页目录和页表所在内存区域清0
clear_mem(DIRECTORY_BASE,KERNEL_BASE);
init_page_directory();
mem_map();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -