提交 0ebba54c 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

鸿蒙内核源码分析系列篇 https://blog.csdn.net/kuangyufei

上级 213c8c47
......@@ -171,10 +171,10 @@ typedef struct VmSpace {
#define VM_MAP_REGION_FLAG_FLAG_MASK (3<<7) //掩码用途
#define VM_MAP_REGION_FLAG_STACK (1<<9) //栈区
#define VM_MAP_REGION_FLAG_HEAP (1<<10) //堆区
#define VM_MAP_REGION_FLAG_DATA (1<<11) //数据区
#define VM_MAP_REGION_FLAG_DATA (1<<11) //data数据区 编译在ELF中
#define VM_MAP_REGION_FLAG_TEXT (1<<12) //代码区
#define VM_MAP_REGION_FLAG_BSS (1<<13) //bbs数据区
#define VM_MAP_REGION_FLAG_VDSO (1<<14) //映射区
#define VM_MAP_REGION_FLAG_BSS (1<<13) //bbs数据区 由运行时动态分配
#define VM_MAP_REGION_FLAG_VDSO (1<<14) //虚拟动态链接对象(Virtual Dynamically Shared Object、vDSO
#define VM_MAP_REGION_FLAG_MMAP (1<<15) //映射区
#define VM_MAP_REGION_FLAG_SHM (1<<16) //共享内存区
#define VM_MAP_REGION_FLAG_INVALID (1<<17) /* indicates that flags are not specified */
......@@ -224,7 +224,7 @@ STATIC INLINE BOOL LOS_IsRegionPermUserReadOnly(LosVmMapRegion* region)
return ((region->regionFlags & VM_MAP_REGION_FLAG_PROT_MASK) ==
(VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ));
}
//私有线性区
//是否为私有线性区
STATIC INLINE BOOL LOS_IsRegionFlagPrivateOnly(LosVmMapRegion* region)
{
return ((region->regionFlags & VM_MAP_REGION_FLAG_FLAG_MASK) == VM_MAP_REGION_FLAG_PRIVATE);
......@@ -234,33 +234,33 @@ STATIC INLINE VOID LOS_SetRegionTypeFile(LosVmMapRegion* region)
{
region->regionType = VM_MAP_REGION_TYPE_FILE;
}
//是否为设备映射线性区
STATIC INLINE BOOL LOS_IsRegionTypeDev(LosVmMapRegion* region)
{
return region->regionType == VM_MAP_REGION_TYPE_DEV;
}
//设为设备映射线性区
STATIC INLINE VOID LOS_SetRegionTypeDev(LosVmMapRegion* region)
{
region->regionType = VM_MAP_REGION_TYPE_DEV;
}
//是否为匿名swap映射线性区
STATIC INLINE BOOL LOS_IsRegionTypeAnon(LosVmMapRegion* region)
{
return region->regionType == VM_MAP_REGION_TYPE_ANON;
}
//设为匿名swap映射线性区
STATIC INLINE VOID LOS_SetRegionTypeAnon(LosVmMapRegion* region)
{
region->regionType = VM_MAP_REGION_TYPE_ANON;
}
//虚拟地址是否在用户空间
STATIC INLINE BOOL LOS_IsUserAddress(VADDR_T vaddr)
{
return ((vaddr >= USER_ASPACE_BASE) &&
(vaddr <= (USER_ASPACE_BASE + (USER_ASPACE_SIZE - 1))));
}
//从vaddr 到 vaddr + len 这段虚拟地址是否在用户空间
STATIC INLINE BOOL LOS_IsUserAddressRange(VADDR_T vaddr, size_t len)
{
return (vaddr + len > vaddr) && LOS_IsUserAddress(vaddr) && (LOS_IsUserAddress(vaddr + len - 1));
......
......@@ -54,8 +54,8 @@ typedef struct VmPage {
UINT16 nPages; /**< the vm page is used for kernel heap */
} LosVmPage;
extern LosVmPage *g_vmPageArray;//物理内存所有页记录数组
extern size_t g_vmPageArraySize;//物理内存总页数
extern LosVmPage *g_vmPageArray;//物理内存所有页框(page frame)记录数组
extern size_t g_vmPageArraySize;//物理内存总页框(page frame)
LosVmPage *LOS_VmPageGet(PADDR_T paddr);
VOID OsVmPageStartup(VOID);
......
......@@ -52,12 +52,12 @@ extern "C" {
#define VM_PAGE_TO_PHYS(page) (page->physAddr)//获取页面物理地址
#define VM_ORDER_TO_PAGES(order) (1 << (order))//伙伴算法由order 定位到该块组的页面单位,例如:order=2时,page[4]
#define VM_ORDER_TO_PHYS(order) (1 << (PAGE_SHIFT + (order)))//通过order找物理地址
#define VM_ORDER_TO_PHYS(order) (1 << (PAGE_SHIFT + (order)))//跳块例如 order=2 就是跳4页
#define VM_PHYS_TO_ORDER(phys) (min(LOS_LowBitGet((phys) >> PAGE_SHIFT), VM_LIST_ORDER_MAX - 1))//通过物理地址定位到order
struct VmFreeList {
LOS_DL_LIST node;
UINT32 listCnt;
LOS_DL_LIST node; //双循环链表
UINT32 listCnt; //双循环链表节点总数
};
//针对匿名页和文件页各拆分成一个活跃,一个不活跃的链表。
enum OsLruList {
......
......@@ -1561,7 +1561,7 @@ STATIC INLINE INT32 OsMemPoolExpand(VOID *pool, UINT32 size, UINT32 intSave)
endNode = (LosMemDynNode *)OS_MEM_END_NODE(pool, poolInfo->poolSize);
RETRY:
newNode = (LosMemDynNode *)LOS_PhysPagesAllocContiguous(size >> PAGE_SHIFT);
newNode = (LosMemDynNode *)LOS_PhysPagesAllocContiguous(size >> PAGE_SHIFT);//分配连续的物理内存
if (newNode == NULL) {
if (tryCount > 0) {
tryCount--;
......
......@@ -44,9 +44,9 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
UINTPTR g_vmBootMemBase = (UINTPTR)&__bss_end;//内核空间
UINTPTR g_vmBootMemBase = (UINTPTR)&__bss_end;//内核空间可用于分配的区域
BOOL g_kHeapInited = FALSE;//内核堆区初始化变量
//虚拟内存区间检查, 需理解 los_vm_zone.h 中画出的鸿蒙虚拟内存全景图
UINT32 OsVmAddrCheck(size_t tempAddr, size_t length)
{
if ((tempAddr >= KERNEL_VMM_BASE) && ((tempAddr + length) <= (PERIPH_UNCACHED_BASE + PERIPH_UNCACHED_SIZE))) {
......@@ -60,7 +60,7 @@ VOID *OsVmBootMemAlloc(size_t len)
{
UINTPTR ptr;
if (g_kHeapInited) {//g_kHeapInited 在什么时候会变成 true?没找到代码
if (g_kHeapInited) {// ??? g_kHeapInited 在什么时候会变成 true,没找到代码
VM_ERR("kernel heap has been inited, should not to use boot mem alloc!");
return NULL;
}
......
......@@ -94,8 +94,8 @@ LosVmPage *LOS_VmPageGet(PADDR_T paddr)
INT32 segID;
LosVmPage *page = NULL;
for (segID = 0; segID < g_vmPhysSegNum; segID++) {
page = OsVmPhysToPage(paddr, segID);
for (segID = 0; segID < g_vmPhysSegNum; segID++) {//物理内存采用段页管理
page = OsVmPhysToPage(paddr, segID);//通过物理地址和段ID找出物理页框
if (page != NULL) {
break;
}
......
......@@ -45,35 +45,35 @@ extern "C" {
#define ONE_PAGE 1
/* Physical memory area array */
STATIC struct VmPhysArea g_physArea[] = {
STATIC struct VmPhysArea g_physArea[] = {//这里只整了一个区域,即只生成一个段,鸿蒙物理内存采用段页式管理
{
.start = SYS_MEM_BASE, //整个物理内存基地址
.size = SYS_MEM_SIZE_DEFAULT,//整个物理内存总大小
},
};
struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX];//32段
INT32 g_vmPhysSegNum = 0;
struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX];//最大32段
INT32 g_vmPhysSegNum = 0; //段数
//获取段数组,全局变量,变量放在 .bbs 区
LosVmPhysSeg *OsGVmPhysSegGet()
{
return g_vmPhysSeg;
}
//初始化Lru置换 LRU list 在 VmPhysSeg中管理
STATIC VOID OsVmPhysLruInit(struct VmPhysSeg *seg)
{
INT32 i;
UINT32 intSave;
LOS_SpinInit(&seg->lruLock);
LOS_SpinInit(&seg->lruLock);//自旋锁,自旋锁用户CPU多核同步
LOS_SpinLockSave(&seg->lruLock, &intSave);
for (i = 0; i < VM_NR_LRU_LISTS; i++) {
seg->lruSize[i] = 0;
LOS_ListInit(&seg->lruList[i]);
for (i = 0; i < VM_NR_LRU_LISTS; i++) { //五个双循环链表
seg->lruSize[i] = 0; //记录链表节点数
LOS_ListInit(&seg->lruList[i]);//初始化LRU链表
}
LOS_SpinUnlockRestore(&seg->lruLock, intSave);
}
//创建物理段
STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size)
{
struct VmPhysSeg *seg = NULL;
......@@ -98,14 +98,14 @@ VOID OsVmPhysSegAdd(VOID)
LOS_ASSERT(g_vmPhysSegNum <= VM_PHYS_SEG_MAX);
for (i = 0; i < (sizeof(g_physArea) / sizeof(g_physArea[0])); i++) {
for (i = 0; i < (sizeof(g_physArea) / sizeof(g_physArea[0])); i++) {//将g_physArea转化成段
ret = OsVmPhysSegCreate(g_physArea[i].start, g_physArea[i].size);//一个区对应一个段
if (ret != 0) {
VM_ERR("create phys seg failed");
}
}
}
//段区域大小调整
VOID OsVmPhysAreaSizeAdjust(size_t size)
{
INT32 i;
......@@ -127,24 +127,24 @@ UINT32 OsVmPhysPageNumGet(VOID)
return nPages;
}
//初始化空闲链表,分配页框使用伙伴算法
STATIC INLINE VOID OsVmPhysFreeListInit(struct VmPhysSeg *seg)
{
int i;
UINT32 intSave;
struct VmFreeList *list = NULL;
LOS_SpinInit(&seg->freeListLock);
LOS_SpinInit(&seg->freeListLock);//自旋锁
LOS_SpinLockSave(&seg->freeListLock, &intSave);
for (i = 0; i < VM_LIST_ORDER_MAX; i++) {
list = &seg->freeList[i];
LOS_ListInit(&list->node);
LOS_ListInit(&list->node);//初始化9个链表 2|0,2|1,2|2 分配页框 |代表次方的意思
list->listCnt = 0;
}
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
}
//段初始化
VOID OsVmPhysInit(VOID)
{
struct VmPhysSeg *seg = NULL;
......@@ -153,13 +153,13 @@ VOID OsVmPhysInit(VOID)
for (i = 0; i < g_vmPhysSegNum; i++) {
seg = &g_vmPhysSeg[i];
seg->pageBase = &g_vmPageArray[nPages];
nPages += seg->size >> PAGE_SHIFT;
OsVmPhysFreeListInit(seg);
OsVmPhysLruInit(seg);
seg->pageBase = &g_vmPageArray[nPages];//
nPages += seg->size >> PAGE_SHIFT;//偏移12位,因以页管理,本段总页数
OsVmPhysFreeListInit(seg); //初始化空闲链表,分配页框使用伙伴算法
OsVmPhysLruInit(seg); //初始化LRU置换链表
}
}
//将页框挂入空闲链表,供分配
STATIC VOID OsVmPhysFreeListAdd(LosVmPage *page, UINT8 order)
{
struct VmPhysSeg *seg = NULL;
......@@ -169,12 +169,12 @@ STATIC VOID OsVmPhysFreeListAdd(LosVmPage *page, UINT8 order)
LOS_Panic("The page segment id(%d) is invalid\n", page->segID);
}
page->order = order;
seg = &g_vmPhysSeg[page->segID];
page->order = order;// page记录 块组号
seg = &g_vmPhysSeg[page->segID];//先找到所属段
list = &seg->freeList[order];
LOS_ListTailInsert(&list->node, &page->node);
list->listCnt++;
list = &seg->freeList[order];//找到对应List
LOS_ListTailInsert(&list->node, &page->node);//将page节点挂入链表
list->listCnt++;//链表内的节点总数++
}
STATIC VOID OsVmPhysFreeListAddUnsafe(LosVmPage *page, UINT8 order)
......@@ -264,23 +264,23 @@ VOID *OsVmPageToVaddr(LosVmPage *page)//
//内核空间的vmPage是不会被置换的,所以是常驻内存,内核空间初始化mmu时就映射好了L1表
return (VOID *)(UINTPTR)vaddr;
}
//通过虚拟地址找映射的物理页框
LosVmPage *OsVmVaddrToPage(VOID *ptr)
{
struct VmPhysSeg *seg = NULL;
PADDR_T pa = LOS_PaddrQuery(ptr);
PADDR_T pa = LOS_PaddrQuery(ptr);//通过虚拟地址查询物理地址
UINT32 segID;
for (segID = 0; segID < g_vmPhysSegNum; segID++) {
seg = &g_vmPhysSeg[segID];
if ((pa >= seg->start) && (pa < (seg->start + seg->size))) {
return seg->pageBase + ((pa - seg->start) >> PAGE_SHIFT);
return seg->pageBase + ((pa - seg->start) >> PAGE_SHIFT);//段基地址+页偏移索引 得到虚拟地址经映射所在物理页框
}
}
return NULL;
}
//从段中分配指定页框数
LosVmPage *OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages)
{
struct VmFreeList *list = NULL;
......@@ -293,7 +293,7 @@ LosVmPage *OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages)
}
order = OsVmPagesToOrder(nPages);//根据页数计算出用哪个块组
if (order < VM_LIST_ORDER_MAX) {
if (order < VM_LIST_ORDER_MAX) {//order不能大于9 即:256*4K = 1M 可理解为向内核堆申请内存一次不能超过1M
for (newOrder = order; newOrder < VM_LIST_ORDER_MAX; newOrder++) {//没有就找更大块
list = &seg->freeList[newOrder];//从最合适的块处开始找
if (LOS_ListEmpty(&list->node)) {//没找到
......@@ -309,7 +309,7 @@ DONE:
OsVmPhysPagesSpiltUnsafe(page, order, newOrder);
return page;
}
//释放物理页,所谓释放物理页就是把页挂到空闲链表中
VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order)
{
paddr_t pa;
......@@ -320,14 +320,14 @@ VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order)
}
if (order < VM_LIST_ORDER_MAX - 1) {//order[0,7]
pa = VM_PAGE_TO_PHYS(page);
pa = VM_PAGE_TO_PHYS(page);//获取物理地址
do {
pa ^= VM_ORDER_TO_PHYS(order);
buddyPage = OsVmPhysToPage(pa, page->segID);
pa ^= VM_ORDER_TO_PHYS(order);//注意这里是高位和低位的^=,也就是说跳到 order块组 物理地址处,此处处理甚妙!
buddyPage = OsVmPhysToPage(pa, page->segID);//如此就能拿到以2的order次方跳的buddyPage
if ((buddyPage == NULL) || (buddyPage->order != order)) {
break;
}
OsVmPhysFreeListDel(buddyPage);
OsVmPhysFreeListDel(buddyPage);//注意buddypage是连续的物理页框 例如order=2时,连续的4页就是一个块组 |_|_|_|_|
order++;
pa &= ~(VM_ORDER_TO_PHYS(order) - 1);
page = OsVmPhysToPage(pa, page->segID);
......@@ -363,7 +363,7 @@ VOID OsVmPhysPagesFreeContiguous(LosVmPage *page, size_t nPages)
page += n;
}
}
//获取一定数量的页框
STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages)
{
UINT32 intSave;
......@@ -378,11 +378,11 @@ STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages)
for (segID = 0; segID < g_vmPhysSegNum; segID++) {
seg = &g_vmPhysSeg[segID];
LOS_SpinLockSave(&seg->freeListLock, &intSave);
page = OsVmPhysPagesAlloc(seg, nPages);
page = OsVmPhysPagesAlloc(seg, nPages);//分配指定页数的物理页, 可分析出 nPages 不能大于 256个
if (page != NULL) {
/* */
LOS_AtomicSet(&page->refCounts, 0);//设置引用次数为0
page->nPages = nPages;
page->nPages = nPages;//页数
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
return page;
}
......@@ -398,7 +398,7 @@ VOID *LOS_PhysPagesAllocContiguous(size_t nPages)
if (nPages == 0) {
return NULL;
}
//鸿蒙 nPages 不能大于 2的8 次方,即256个页,1M内存,仅限于内核态,用户态不限制分配大小.
page = OsVmPhysPagesGet(nPages);//通过伙伴算法获取物理上连续的页
if (page == NULL) {
return NULL;
......@@ -542,7 +542,7 @@ struct VmPhysSeg *OsVmPhysSegGet(LosVmPage *page)
return (OsGVmPhysSegGet() + page->segID);
}
//通过总页数 ,获取块组 ,例如需要分配 8个页,返回就是 3 ,例如 1023个 返回就是 10
UINT32 OsVmPagesToOrder(size_t nPages)
{
UINT32 order;
......
......@@ -5,6 +5,8 @@ typedef unsigned long PTE_T;
typedef unsigned long VADDR_T;
#define IS_ALIGNED(a, b) (!(((UINTPTR)(a)) & (((UINTPTR)(b)) - 1)))
//鸿蒙内核源码分析系列篇 https://blog.csdn.net/kuangyufei
void b(){
UINT8 w[3]={0};
PTE_T pte1BasePtr = 0x11100000;
......
git add -A
git commit -m "鸿蒙内核源码分析系列篇 https://blog.csdn.net/kuangyufei"
git push
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册