75#ifdef LOSCFG_KERNEL_VM
82 .
start = SYS_MEM_BASE,
83 .size = SYS_MEM_SIZE_DEFAULT,
136 VM_ERR(
"create phys seg failed");
173 for (i = 0; i < VM_LIST_ORDER_MAX; i++) {
190 nPages += seg->
size >> PAGE_SHIFT;
201 if (page->
segID >= VM_PHYS_SEG_MAX) {
218 if ((page->
segID >= VM_PHYS_SEG_MAX) || (page->
order >= VM_LIST_ORDER_MAX)) {
226 page->
order = VM_LIST_ORDER_MAX;
242 for (order = newOrder; order > oldOrder;) {
244 buddyPage = &page[VM_ORDER_TO_PAGES(order)];
245 LOS_ASSERT(buddyPage->
order == VM_LIST_ORDER_MAX);
255 if (segID >= VM_PHYS_SEG_MAX) {
256 LOS_Panic(
"The page segment id(%d) is invalid\n", segID);
263 offset = pa - seg->
start;
264 return (seg->
pageBase + (offset >> PAGE_SHIFT));
274 if (vmPage != NULL) {
291 vaddr = KERNEL_ASPACE_BASE + page->
physAddr - SYS_MEM_BASE;
313 if (startPage >= endPage) {
327 size_t size = nPages << PAGE_SHIFT;
329 list = &seg->
freeList[VM_LIST_ORDER_MAX - 1];
332 paEnd = paStart + size;
338 paStart += PAGE_SIZE << (VM_LIST_ORDER_MAX - 1);
339 if ((paStart >= paEnd) || (paStart < seg->
start) ||
344 if (tmp->
order != (VM_LIST_ORDER_MAX - 1)) {
348 if (paStart >= paEnd) {
365 if (order < VM_LIST_ORDER_MAX) {
366 for (newOrder = order; newOrder < VM_LIST_ORDER_MAX; newOrder++) {
375 newOrder = VM_LIST_ORDER_MAX - 1;
384 for (tmp = page; tmp < &page[nPages]; tmp = &tmp[1 << newOrder]) {
398 if ((page == NULL) || (order >= VM_LIST_ORDER_MAX)) {
402 if (order < VM_LIST_ORDER_MAX - 1) {
403 pa = VM_PAGE_TO_PHYS(page);
405 pa ^= VM_ORDER_TO_PHYS(order);
407 if ((buddyPage == NULL) || (buddyPage->
order != order)) {
412 pa &= ~(VM_ORDER_TO_PHYS(order) - 1);
414 }
while (order < VM_LIST_ORDER_MAX - 1);
427 pa = VM_PAGE_TO_PHYS(page);
428 order = VM_PHYS_TO_ORDER(pa);
429 n = VM_ORDER_TO_PAGES(order);
440 n = VM_ORDER_TO_PAGES(order);
506 VM_ERR(
"vm page of ptr(%#x) is null", ptr);
524 return (kvaddr - KERNEL_ASPACE_BASE + SYS_MEM_BASE);
538 if ((paddr >= seg->
start) && (paddr < (seg->
start + seg->
size))) {
539 return (
VADDR_T *)(
UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);
543 return (
VADDR_T *)(
UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);
586 if ((list == NULL) || (nPages == 0)) {
610 if ((newPage == NULL) || (newPaddr == NULL)) {
611 VM_ERR(
"new Page invalid");
616 if (oldPage == NULL) {
617 VM_ERR(
"invalid oldPaddr %p", oldPaddr);
624 *newPaddr = oldPaddr;
628 if ((newMem == NULL) || (oldMem == NULL)) {
632 if (memcpy_s(newMem, PAGE_SIZE, oldMem, PAGE_SIZE) != EOK) {
633 VM_ERR(
"memcpy_s failed");
645 if ((page == NULL) || (page->
segID >= VM_PHYS_SEG_MAX)) {
656 for (order = 0; VM_ORDER_TO_PAGES(order) < nPages; order++);
673 LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(page, nPage, list,
LosVmPage, node) {
690 if ((paddr < DDR_MEM_ADDR) || (paddr >= ((
PADDR_T)DDR_MEM_ADDR + DDR_MEM_SIZE))) {
694 return (
VADDR_T *)DMA_TO_VMM_ADDR(paddr);
STATIC INLINE VOID LOS_AtomicInc(Atomic *v)
Atomic addSelf.
STATIC INLINE INT32 LOS_AtomicRead(const Atomic *v)
Atomic read. | 读取32bit原子数据
STATIC INLINE VOID LOS_AtomicSet(Atomic *v, INT32 setVal)
Atomic setting.
STATIC INLINE VOID LOS_AtomicDec(Atomic *v)
Atomic auto-decrement. | 对32bit原子数据做减1
STATIC INLINE INT32 LOS_AtomicDecRet(Atomic *v)
Atomic auto-decrement. | 对内存数据减1并返回运算结果
UINT16 LOS_HighBitGet(UINT32 bitmap)
获取参数位图中最高位为1的索引位 例如: 00110110 返回 5
NORETURN VOID LOS_Panic(const CHAR *fmt,...)
Kernel panic function.
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListTailInsert(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a node to the tail of a doubly linked list.
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
LITE_OS_SEC_ALW_INLINE STATIC INLINE BOOL LOS_ListEmpty(LOS_DL_LIST *list)
Identify whether a specified doubly linked list is empty. | 判断链表是否为空
VOID LOS_SpinUnlockRestore(SPIN_LOCK_S *lock, UINT32 intSave)
VOID LOS_SpinLockSave(SPIN_LOCK_S *lock, UINT32 *intSave)
VOID LOS_SpinInit(SPIN_LOCK_S *lock)
PADDR_T LOS_PaddrQuery(VOID *vaddr)
通过虚拟地址查询映射的物理地址
LosVmPage * g_vmPageArray
物理页框(page frame)池,在g_vmPageArray中:不可能存在两个物理地址一样的物理页框,
LosVmPage * LOS_VmPageGet(PADDR_T paddr)
通过物理地址获取页框
STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size)
创建物理段,由区划分转成段管理
VOID * LOS_PhysPagesAllocContiguous(size_t nPages)
分配连续的物理页
STATIC struct VmPhysArea g_physArea[]
STATIC LosVmPage * OsVmPhysLargeAlloc(struct VmPhysSeg *seg, size_t nPages)
大块的物理内存分配
VOID OsPhysSharePageCopy(PADDR_T oldPaddr, PADDR_T *newPaddr, LosVmPage *newPage)
拷贝共享页面
STATIC LosVmPage * OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages)
申请物理页并挂在对应的链表上
LosVmPage * OsVmPaddrToPage(paddr_t paddr)
VOID LOS_PhysPageFree(LosVmPage *page)
释放一个物理页框
VOID OsVmPhysPagesFreeContiguous(LosVmPage *page, size_t nPages)
连续的释放物理页框, 如果8页连在一块是一起释放的
STATIC VOID OsVmPhysFreeListAddUnsafe(LosVmPage *page, UINT8 order)
将页框挂入空闲链表,分配物理页框从空闲链表里拿
STATIC VOID OsVmPhysPagesSpiltUnsafe(LosVmPage *page, UINT8 oldOrder, UINT8 newOrder)
本函数很像卖猪肉的,拿一大块肉剁,先把多余的放回到小块肉堆里去.
VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages)
释放指定页数地址连续的物理内存
size_t LOS_PhysPagesAlloc(size_t nPages, LOS_DL_LIST *list)
LOS_PhysPagesAlloc 分配nPages页个物理页框,并将页框挂入list 返回已分配的页面大小,不负责一定能分配到nPages的页框
struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX]
最大32段
STATIC INLINE VOID OsVmRecycleExtraPages(LosVmPage *page, size_t startPage, size_t endPage)
回收一定范围内的页框
PADDR_T OsKVaddrToPaddr(VADDR_T kvaddr)
VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order)
释放物理页框,所谓释放物理页就是把页挂到空闲链表中
struct VmPhysSeg * OsVmPhysSegGet(LosVmPage *page)
获取物理页框所在段
STATIC LosVmPage * OsVmPhysPagesGet(size_t nPages)
OsVmPhysPagesGet 获取一定数量的页框 LosVmPage实体是放在全局大数组中的, LosVmPage->nPages 标记了分配页数
LosVmPage * OsVmPhysToPage(paddr_t pa, UINT8 segID)
通过物理地址获取所属参数段的物理页框
LosVmPage * LOS_PhysPageAlloc(VOID)
申请一个物理页
UINT32 OsVmPhysPageNumGet(VOID)
获得物理内存的总页数
UINT32 OsVmPagesToOrder(size_t nPages)
获取参数nPages对应的块组,例如 7 -> 2^3 返回 3
VOID OsVmPhysSegAdd(VOID)
添加物理段
VOID OsVmPhysAreaSizeAdjust(size_t size)
段区域大小调整
STATIC INLINE VOID OsVmPhysFreeListInit(struct VmPhysSeg *seg)
初始化空闲链表,分配物理页框使用伙伴算法
size_t LOS_PhysPagesFree(LOS_DL_LIST *list)
释放双链表中的所有节点内存,本质是回归到伙伴orderlist中
LosVmPhysSeg * OsGVmPhysSegGet()
获取段数组,全局变量,变量放在 .bbs 区
LosVmPage * OsVmVaddrToPage(VOID *ptr)
通过虚拟地址找映射的物理页框
VOID OsVmPhysInit(VOID)
物理段初始化
VOID * OsVmPageToVaddr(LosVmPage *page)
通过page获取内核空间的虚拟地址 参考OsArchMmuInit #define SYS_MEM_BASE DDR_MEM_ADDR /* physical memory base 物理地址的起始...
STATIC VOID OsVmPhysLruInit(struct VmPhysSeg *seg)
初始化Lru置换链表
VADDR_T * LOS_PaddrToKVaddr(PADDR_T paddr)
通过物理地址获取内核虚拟地址
STATIC VOID OsVmPhysFreeListDelUnsafe(LosVmPage *page)
将物理页框从空闲链表上摘除,见于物理页框被分配的情况
LOS_DL_LIST node
双循环链表用于挂空闲物理内框节点,通过 VmPage->node 挂上来
物理页框描述符 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。 伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组
LOS_DL_LIST lruList[VM_NR_LRU_LISTS]
页面置换算法,5个双循环链表头,它们分别描述五中不同类型的链表
SPIN_LOCK_S lruLock
用于置换的自旋锁,用于操作lruList
size_t lruSize[VM_NR_LRU_LISTS]
5个双循环链表大小,如此方便得到size
struct VmFreeList freeList[VM_LIST_ORDER_MAX]