提交 4e89c02a 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析
上级 8042bd84
......@@ -434,7 +434,7 @@ STATIC UINT32 OsMapSection(const LosArchMmu *archMmu, UINT32 flags, VADDR_T *vad
{
UINT32 mmuFlags = 0;
mmuFlags |= OsCvtSecFlagsToAttrs(flags);
mmuFlags |= OsCvtSecFlagsToAttrs(flags);//flag转成L1层描述flag,场景不同说法得跟着变啦
OsSavePte1(OsGetPte1Ptr(archMmu->virtTtb, *vaddr),
OsTruncPte1(*paddr) | mmuFlags | MMU_DESCRIPTOR_L1_TYPE_SECTION);//保存L1页表项至L1页表
*count -= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;//1M
......
......@@ -192,7 +192,7 @@ UINT32 OsArmSharedPageFault(UINT32 excType, ExcContext *frame, UINT32 far, UINT3
UINT32 fsrFlag;
BOOL write = FALSE;
if (OsGetSystemStatus() == OS_SYSTEM_EXC_CURR_CPU) {
if (OsGetSystemStatus() == OS_SYSTEM_EXC_CURR_CPU) {//当前CPU core
return LOS_ERRNO_VM_NOT_FOUND;
}
......@@ -217,7 +217,7 @@ UINT32 OsArmSharedPageFault(UINT32 excType, ExcContext *frame, UINT32 far, UINT3
pfFlags |= user ? VM_MAP_PF_FLAG_USER : 0;
pfFlags |= instruction_fault ? VM_MAP_PF_FLAG_INSTRUCTION : 0;
pfFlags |= VM_MAP_PF_FLAG_NOT_PRESENT;
return OsVmPageFaultHandler(far, pfFlags, frame);
return OsVmPageFaultHandler(far, pfFlags, frame);//中断处理程序
}
default:
return LOS_ERRNO_VM_NOT_FOUND;
......
......@@ -93,6 +93,8 @@ typedef struct VmFault {
unsigned long pgoff; /* Logical page offset based on region */
VADDR_T vaddr; /* Faulting virtual address */
VADDR_T *pageKVaddr; /* KVaddr of pagefault's vm page's paddr */
//pageKVaddr为缺页的vm页面物理地址对应的内核虚拟地址,这里要说明下啥意思,缺页的意思是此进程的虚拟空间中没有这个虚拟地址的映射,
//但并不代表物理页框没有被别的进程虚拟空间所映射.一定要理解这里!
} LosVmPgFault;
//虚拟内存文件操作函数指针,上层开发可理解为 class 里的方法,注意是对线性区的操作
struct VmFileOps {// 文件操作
......@@ -160,15 +162,15 @@ typedef struct VmSpace {
#define VM_MAP_REGION_FLAG_UNCACHED_DEVICE (2<<0) /* only exists on some arches, otherwise UNCACHED */
#define VM_MAP_REGION_FLAG_WRITE_COMBINING (3<<0) /* only exists on some arches, otherwise UNCACHED */
#define VM_MAP_REGION_FLAG_CACHE_MASK (3<<0) //缓冲区掩码
#define VM_MAP_REGION_FLAG_PERM_USER (1<<2) //用户态
#define VM_MAP_REGION_FLAG_PERM_USER (1<<2) //可使用
#define VM_MAP_REGION_FLAG_PERM_READ (1<<3) //可读取区
#define VM_MAP_REGION_FLAG_PERM_WRITE (1<<4) //可写入区
#define VM_MAP_REGION_FLAG_PERM_EXECUTE (1<<5) //可被执行区
#define VM_MAP_REGION_FLAG_PROT_MASK (0xF<<2) //访问权限掩码
#define VM_MAP_REGION_FLAG_NS (1<<6) /* NON-SECURE */
#define VM_MAP_REGION_FLAG_SHARED (1<<7) //共享区
#define VM_MAP_REGION_FLAG_PRIVATE (1<<8) //私有区
#define VM_MAP_REGION_FLAG_FLAG_MASK (3<<7) //掩码用途
#define VM_MAP_REGION_FLAG_SHARED (1<<7) //MAP_SHARED:把对该内存段的修改保存到磁盘文件中 详见 OsCvtProtFlagsToRegionFlags ,要和 VM_MAP_REGION_FLAG_SHM区别理解
#define VM_MAP_REGION_FLAG_PRIVATE (1<<8) //MAP_PRIVATE:内存段私有,对它的修改值仅对本进程有效,详见 OsCvtProtFlagsToRegionFlags。
#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) //data数据区 编译在ELF中
......@@ -176,14 +178,14 @@ typedef struct VmSpace {
#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_SHM (1<<16) //共享内存区,和代码区同级概念,意思是整个线性区被贴上共享标签
#define VM_MAP_REGION_FLAG_INVALID (1<<17) /* indicates that flags are not specified */
STATIC INLINE UINT32 OsCvtProtFlagsToRegionFlags(unsigned long prot, unsigned long flags)
{
UINT32 regionFlags = 0;
regionFlags |= VM_MAP_REGION_FLAG_PERM_USER;
regionFlags |= VM_MAP_REGION_FLAG_PERM_USER; //必须得是可用区先
regionFlags |= (prot & PROT_READ) ? VM_MAP_REGION_FLAG_PERM_READ : 0; //映射区可被读
regionFlags |= (prot & PROT_WRITE) ? VM_MAP_REGION_FLAG_PERM_WRITE : 0; //映射区可被写
regionFlags |= (prot & PROT_EXEC) ? VM_MAP_REGION_FLAG_PERM_EXECUTE : 0; //映射区可被执行
......
......@@ -209,7 +209,7 @@ STATIC UINT32 OsCheckMutexAttr(const LosMuxAttr *attr)
}
return LOS_OK;
}
//初始化互斥
LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
{
UINT32 intSave;
......
......@@ -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;
}
......
......@@ -111,7 +111,7 @@ STATIC STATUS_T OsDoReadFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
VADDR_T vaddr = (VADDR_T)vmPgFault->vaddr;
LosVmSpace *space = region->space;
ret = LOS_ArchMmuQuery(&space->archMmu, vaddr, NULL, NULL);
ret = LOS_ArchMmuQuery(&space->archMmu, vaddr, NULL, NULL);//查询是否缺页
if (ret == LOS_OK) {
return LOS_OK;
}
......@@ -121,16 +121,16 @@ STATIC STATUS_T OsDoReadFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
}
(VOID)LOS_MuxAcquire(&region->unTypeData.rf.file->f_mapping->mux_lock);
ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);
ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);// 函数指针 g_commVmOps.OsVmmFileFault
if (ret == LOS_OK) {
paddr = LOS_PaddrQuery(vmPgFault->pageKVaddr);
page = LOS_VmPageGet(paddr);
paddr = LOS_PaddrQuery(vmPgFault->pageKVaddr);//查询物理地址
page = LOS_VmPageGet(paddr);//获取page
if (page != NULL) { /* just incase of page null */
LOS_AtomicInc(&page->refCounts);
LOS_AtomicInc(&page->refCounts);//ref 自增
OsCleanPageLocked(page);
}
ret = LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, 1,
region->regionFlags & (~VM_MAP_REGION_FLAG_PERM_WRITE));
region->regionFlags & (~VM_MAP_REGION_FLAG_PERM_WRITE));//重新映射为非可写
if (ret < 0) {
VM_ERR("LOS_ArchMmuMap fial");
OsDelMapInfo(region, vmPgFault, false);
......@@ -174,7 +174,7 @@ STATIC LosVmPage *OsCowUnmapOrg(LosArchMmu *archMmu, LosVmMapRegion *region, Los
return oldPage;
}
#endif
//写入私有空间时的缺页处理
status_t OsDoCowFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
{
STATUS_T ret;
......@@ -192,23 +192,23 @@ status_t OsDoCowFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
}
space = region->space;
ret = LOS_ArchMmuQuery(&space->archMmu, (VADDR_T)vmPgFault->vaddr, &oldPaddr, NULL);
ret = LOS_ArchMmuQuery(&space->archMmu, (VADDR_T)vmPgFault->vaddr, &oldPaddr, NULL);//查询出老物理地址
if (ret == LOS_OK) {
oldPage = OsCowUnmapOrg(&space->archMmu, region, vmPgFault);
oldPage = OsCowUnmapOrg(&space->archMmu, region, vmPgFault);//取消页面映射
}
newPage = LOS_PhysPageAlloc();
newPage = LOS_PhysPageAlloc();//分配一个新页面
if (newPage == NULL) {
VM_ERR("pmm_alloc_page fail");
ret = LOS_ERRNO_VM_NO_MEMORY;
goto ERR_OUT;
}
newPaddr = VM_PAGE_TO_PHYS(newPage);
kvaddr = OsVmPageToVaddr(newPage);
newPaddr = VM_PAGE_TO_PHYS(newPage);//拿到新的物理地址
kvaddr = OsVmPageToVaddr(newPage);//拿到新的虚拟地址
(VOID)LOS_MuxAcquire(&region->unTypeData.rf.file->f_mapping->mux_lock);
ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);
ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);// 函数指针 g_commVmOps.OsVmmFileFault
if (ret != LOS_OK) {
VM_ERR("call region->vm_ops->fault fail");
(VOID)LOS_MuxRelease(&region->unTypeData.rf.file->f_mapping->mux_lock);
......@@ -220,20 +220,20 @@ status_t OsDoCowFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
* we can take it as a normal file cow map. 2.this page has done file cow map,
* we can take it as a anonymous cow map.
*/
if ((oldPaddr == 0) || (LOS_PaddrToKVaddr(oldPaddr) == vmPgFault->pageKVaddr)) {
(VOID)memcpy_s(kvaddr, PAGE_SIZE, vmPgFault->pageKVaddr, PAGE_SIZE);
LOS_AtomicInc(&newPage->refCounts);
OsCleanPageLocked(LOS_VmPageGet(LOS_PaddrQuery(vmPgFault->pageKVaddr)));
if ((oldPaddr == 0) || (LOS_PaddrToKVaddr(oldPaddr) == vmPgFault->pageKVaddr)) {//没有映射或者 已在pagecache有映射
(VOID)memcpy_s(kvaddr, PAGE_SIZE, vmPgFault->pageKVaddr, PAGE_SIZE);//直接copy到新页
LOS_AtomicInc(&newPage->refCounts);//引用ref++
OsCleanPageLocked(LOS_VmPageGet(LOS_PaddrQuery(vmPgFault->pageKVaddr)));//解锁
} else {
OsPhysSharePageCopy(oldPaddr, &newPaddr, newPage);
OsPhysSharePageCopy(oldPaddr, &newPaddr, newPage);//调用之前 oldPaddr肯定不等于newPaddr
/* use old page free the new one */
if (newPaddr == oldPaddr) {
LOS_PhysPageFree(newPage);
if (newPaddr == oldPaddr) {//注意这里newPaddr可能已经被改变了,参数传入的是 &newPaddr
LOS_PhysPageFree(newPage);//释放新页,别浪费的内存,内核使用内存是一分钱当十块用.
newPage = NULL;
}
}
ret = LOS_ArchMmuMap(&space->archMmu, (VADDR_T)vmPgFault->vaddr, newPaddr, 1, region->regionFlags);
ret = LOS_ArchMmuMap(&space->archMmu, (VADDR_T)vmPgFault->vaddr, newPaddr, 1, region->regionFlags);//把新物理地址映射给缺页的虚拟地址,这样就不会缺页啦
if (ret < 0) {
VM_ERR("LOS_ArchMmuMap fial");
ret = LOS_ERRNO_VM_NO_MEMORY;
......@@ -274,10 +274,10 @@ status_t OsDoSharedFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
return LOS_ERRNO_VM_INVALID_ARGS;
}
ret = LOS_ArchMmuQuery(&space->archMmu, vmPgFault->vaddr, &paddr, NULL);
ret = LOS_ArchMmuQuery(&space->archMmu, vmPgFault->vaddr, &paddr, NULL);//先能否查出地理地址
if (ret == LOS_OK) {
LOS_ArchMmuUnmap(&space->archMmu, vmPgFault->vaddr, 1);
ret = LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, 1, region->regionFlags);
LOS_ArchMmuUnmap(&space->archMmu, vmPgFault->vaddr, 1);//先取消映射
ret = LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, 1, region->regionFlags);//再重新映射,为啥这么干,是因为regionFlags变了,
if (ret < 0) {
VM_ERR("LOS_ArchMmuMap failed. ret=%d", ret);
return LOS_ERRNO_VM_NO_MEMORY;
......@@ -286,7 +286,7 @@ status_t OsDoSharedFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
LOS_SpinLockSave(&region->unTypeData.rf.file->f_mapping->list_lock, &intSave);
fpage = OsFindGetEntry(region->unTypeData.rf.file->f_mapping, vmPgFault->pgoff);
if (fpage) {
OsMarkPageDirty(fpage, region, 0, 0);
OsMarkPageDirty(fpage, region, 0, 0);//标记为脏页
}
LOS_SpinUnlockRestore(&region->unTypeData.rf.file->f_mapping->list_lock, intSave);
......@@ -332,12 +332,12 @@ STATIC STATUS_T OsDoFileFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault, U
if (flags & VM_MAP_PF_FLAG_WRITE) {
if (region->regionFlags & VM_MAP_REGION_FLAG_SHARED) {
ret = OsDoSharedFault(region, vmPgFault);
ret = OsDoSharedFault(region, vmPgFault);//写操作时的共享缺页,最复杂,此页上的更改将写入磁盘文件
} else {
ret = OsDoCowFault(region, vmPgFault);
ret = OsDoCowFault(region, vmPgFault);//写操作时的私有缺页,pagecache被复制到私有的任意一个页面上,并在此页面上进行更改,不会直接写入磁盘文件
}
} else {
ret = OsDoReadFault(region, vmPgFault);
ret = OsDoReadFault(region, vmPgFault);//读时缺页,读最简单 只需共享页面缓存
}
return ret;
}
......
......@@ -343,7 +343,7 @@ VOID OsMarkPageDirty(LosFilePage *fpage, LosVmMapRegion *region, INT32 off, INT3
fpage->dirtyOff = off;//脏页偏移位置
fpage->dirtyEnd = len;//脏页结束位置
} else {
OsSetPageDirty(fpage->vmPage);////设置为脏页
OsSetPageDirty(fpage->vmPage);//设置为脏页
if ((off + len) > fpage->dirtyEnd) {
fpage->dirtyEnd = off + len;
}
......@@ -407,13 +407,13 @@ STATIC INT32 OsFlushDirtyPage(LosFilePage *fpage)
if (file->f_inode && file->f_inode->u.i_mops->writepage) {//null
ret = file->f_inode->u.i_mops->writepage(file, (buff + fpage->dirtyOff), len);
} else {
ret = file_write(file, (VOID *)buff, len);//nuttx 中对应 fat_operations.fatfs_write 请自行查看
ret = file_write(file, (VOID *)buff, len);//脏页数据写入磁盘文件,nuttx 中对应 fat_operations.fatfs_write 请自行查看
}
if (ret <= 0) {
VM_ERR("WritePage error ret %d", ret);
}
ret = (ret <= 0) ? LOS_NOK : LOS_OK;
OsCleanPageDirty(fpage->vmPage);//臣妾又干净了
OsCleanPageDirty(fpage->vmPage);//还清白之身,哈哈,臣妾又干净了.
(VOID)file_seek(file, oldPos, SEEK_SET);//写完了脏数据,切回到老位置,一定要回到老位置,因为回写脏数据是内核的行为,而不是用户的行为
return ret;
......@@ -627,7 +627,7 @@ VOID OsFileCacheRemove(struct page_mapping *mapping)
}
}
LosVmFileOps g_commVmOps = {
LosVmFileOps g_commVmOps = {//
.open = NULL,
.close = NULL,
.fault = OsVmmFileFault, //缺页处理
......
......@@ -512,23 +512,23 @@ VOID OsPhysSharePageCopy(PADDR_T oldPaddr, PADDR_T *newPaddr, LosVmPage *newPage
return;
}
seg = &g_vmPhysSeg[oldPage->segID];
seg = &g_vmPhysSeg[oldPage->segID];//拿到段
LOS_SpinLockSave(&seg->freeListLock, &intSave);
if (LOS_AtomicRead(&oldPage->refCounts) == 1) {
if (LOS_AtomicRead(&oldPage->refCounts) == 1) {//页面引用次数仅一次,说明还没有被其他进程所使用过
*newPaddr = oldPaddr;
} else {
newMem = LOS_PaddrToKVaddr(*newPaddr);
oldMem = LOS_PaddrToKVaddr(oldPaddr);
newMem = LOS_PaddrToKVaddr(*newPaddr); //新页虚拟地址
oldMem = LOS_PaddrToKVaddr(oldPaddr); //老页虚拟地址
if ((newMem == NULL) || (oldMem == NULL)) {
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
return;
}
if (memcpy_s(newMem, PAGE_SIZE, oldMem, PAGE_SIZE) != EOK) {
if (memcpy_s(newMem, PAGE_SIZE, oldMem, PAGE_SIZE) != EOK) {//老页内容复制给新页
VM_ERR("memcpy_s failed");
}
LOS_AtomicInc(&newPage->refCounts);
LOS_AtomicDec(&oldPage->refCounts);
LOS_AtomicInc(&newPage->refCounts);//新页ref++
LOS_AtomicDec(&oldPage->refCounts);//老页ref--
}
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
return;
......
......@@ -55,19 +55,19 @@ extern "C" {
STATIC LosMux g_sysvShmMux;
/* private macro */
#define SYSV_SHM_LOCK() (VOID)LOS_MuxLock(&g_sysvShmMux, LOS_WAIT_FOREVER)
#define SYSV_SHM_UNLOCK() (VOID)LOS_MuxUnlock(&g_sysvShmMux)
#define SYSV_SHM_LOCK() (VOID)LOS_MuxLock(&g_sysvShmMux, LOS_WAIT_FOREVER) //拿永久等待锁
#define SYSV_SHM_UNLOCK() (VOID)LOS_MuxUnlock(&g_sysvShmMux) //释放锁
#define SHM_MAX_PAGES 12800
#define SHM_MAX (SHM_MAX_PAGES * PAGE_SIZE)
#define SHM_MAX_PAGES 12800 //共享最大页
#define SHM_MAX (SHM_MAX_PAGES * PAGE_SIZE) // 12800*4K = 50M
#define SHM_MIN 1
#define SHM_MNI 192
#define SHM_SEG 128
#define SHM_ALL (SHM_MAX_PAGES)
#define SHM_SEG_FREE 0x2000
#define SHM_SEG_USED 0x4000
#define SHM_SEG_REMOVE 0x8000
#define SHM_SEG_FREE 0x2000 //空闲未使用
#define SHM_SEG_USED 0x4000 //已使用
#define SHM_SEG_REMOVE 0x8000 //删除
#ifndef SHM_M
#define SHM_M 010000
......@@ -85,7 +85,7 @@ struct shmSegMap {
vaddr_t vaddr;
INT32 shmID;
};
//结构体定义可见于..\vendor_hisi_hi3861_hi3861\hi3861\platform\os\Huawei_LiteOS\components\lib\libc\musl\arch\generic\bits\shm.h
struct shmIDSource {
struct shmid_ds ds;
UINT32 status;
......@@ -94,21 +94,21 @@ struct shmIDSource {
/* private data */
STATIC struct shminfo g_shmInfo = {
.shmmax = SHM_MAX,
.shmmin = SHM_MIN,
.shmmni = SHM_MNI,
.shmseg = SHM_SEG,
.shmmax = SHM_MAX,//最大的内存segment的大小
.shmmin = SHM_MIN,//最小的内存segment的大小
.shmmni = SHM_MNI,//整个系统的内存segment的总个数
.shmseg = SHM_SEG,//每个进程可以使用的内存segment的最大个数
.shmall = SHM_ALL,
};
STATIC struct shmIDSource *g_shmSegs = NULL;
//共享内存初始化
INT32 ShmInit(VOID)
{
UINT32 ret;
UINT32 i;
ret = LOS_MuxInit(&g_sysvShmMux, NULL);
ret = LOS_MuxInit(&g_sysvShmMux, NULL);//初始化互斥锁
if (ret != LOS_OK) {
return -1;
}
......@@ -344,7 +344,7 @@ VOID OsShmRegionFree(LosVmSpace *space, LosVmMapRegion *region)
}
SYSV_SHM_UNLOCK();
}
//是否为共享线性区
BOOL OsIsShmRegion(LosVmMapRegion *region)
{
return (region->regionFlags & VM_MAP_REGION_FLAG_SHM) ? TRUE : FALSE;
......@@ -403,7 +403,12 @@ STATIC INT32 ShmPermCheck(struct shmIDSource *seg, mode_t mode)
return EACCES;
}
}
/*
得到一个共享内存标识符或创建一个共享内存对象
key_t:建立新共享内存对象
size: 新建的共享内存大小,以字节为单位
shmflg: IPC_CREAT IPC_EXCL
*/
INT32 ShmGet(key_t key, size_t size, INT32 shmflg)
{
INT32 ret;
......
git add -A
git commit -m "鸿蒙内核源码分析系列篇 https://blog.csdn.net/kuangyufei"
git push
git add -A
git commit -m "鸿蒙源码分析系列篇 https://blog.csdn.net/kuangyufei https://my.oschina.net/u/3751245"
git push
gcc -o main main.c
.\main.out
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册