📄 arm_map.c
字号:
/* * $QNXLicenseC: * Copyright 2008, QNX Software Systems. * * Licensed under the Apache License, Version 2.0 (the "License"). You * may not reproduce, modify or distribute this software except in * compliance with the License. You may obtain a copy of the License * at: http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OF ANY KIND, either express or implied. * * This file may contain contributions from others, either as * contributors under the License or as licensors under other terms. * Please review this entire file for other proprietary rights or license * notices, as well as the QNX Development Suite License Guide at * http://licensing.qnx.com/license-guide/ for other information. * $ */#include "startup.h"#define CPU_L1_TABLE(cpu) ((L1_paddr + ((cpu) * ARM_L1_SIZE)) & ~0x1f)#define CPU_L2_TABLE(cpu) (L2_paddr + ((cpu) * __PAGESIZE))static paddr_tset_prot(paddr_t paddr, int flags){ if (flags == ARM_MAP_SYSPAGE) { if (lsp.cpuinfo.p->flags & ARM_CPU_FLAG_V6) { /* * WARNING: we assume user RW has APX/AP1/AP0=011: * - by clearing AP0 we can set user RO/priv RW * - we need to clear nG so it doesn't use an ASID */ paddr |= armv_pte->upte_rw; paddr &= ~(ARM_PTE_V6_AP0 | ARM_PTE_V6_nG); } else { /* * user RO allows privileged RW access on non-ARMv6 cpus */ paddr |= armv_pte->upte_ro; } } else if (flags & ARM_PTE_U) { paddr |= (flags & ARM_PTE_RW) ? armv_pte->upte_rw : armv_pte->upte_ro; } else { paddr |= (flags & ARM_PTE_RW) ? armv_pte->kpte_rw : armv_pte->kpte_ro; } if ((flags & ARM_PTE_CB) == 0) { paddr &= ~armv_pte->mask_nc; } return paddr;}/* * Map a 4K page table into "page directory" and L1 table for specified cpu */static voidmap_ptbl_cpu(int cpu, paddr_t ptbl, uintptr_t vaddr){ pte_t *pte = (pte_t *)CPU_L2_TABLE(cpu) + (vaddr >> 22); ptp_t *ptp = (ptp_t *)CPU_L1_TABLE(cpu) + ((vaddr >> 20) & ~3); int i; /* * Map the page table into the "page directory" page table */ *pte = (ptbl | armv_pte->kpte_rw) & ~armv_pte->mask_nc; /* * Map the page table into the L1 table */ for (i = 0; i < 4; i++, ptbl += ARM_L2_SIZE) { *ptp++ = ptbl | armv_pte->l1_pgtable; }}/* * Map a 4K page table into "page directory" and L1 table on all cpus */voidmap_ptbl(paddr_t pt, uintptr_t vaddr){ int cpu; for (cpu = 0; cpu < lsp.syspage.p->num_cpu; cpu++) { map_ptbl_cpu(cpu, pt, vaddr); }}/* * Map the "page directory" page for each CPU */voidarm_pdmap(uintptr_t vaddr){ int cpu; for (cpu = 0; cpu < lsp.syspage.p->num_cpu; cpu++) { map_ptbl_cpu(cpu, CPU_L2_TABLE(cpu), vaddr); }}/* * Map a 1MB section into the L1 table. */voidarm_scmap(uintptr_t vaddr, paddr_t paddr, int flags){ unsigned prot = (flags & ARM_PTE_RW) ? armv_pte->kscn_rw : armv_pte->kscn_ro; unsigned cpu; if (flags & ARM_PTE_CB) { prot |= armv_pte->kscn_cb; } for (cpu = 0; cpu < lsp.syspage.p->num_cpu; cpu++) { ptp_t *ptp = (ptp_t *)CPU_L1_TABLE(cpu) + (vaddr >> 20); *ptp = paddr | prot; }}/* * Unmap section entry */voidarm_scunmap(uintptr_t vaddr){ unsigned cpu; for (cpu = 0; cpu < lsp.syspage.p->num_cpu; cpu++) { ptp_t *ptp = (ptp_t *)CPU_L1_TABLE(cpu) + (vaddr >> 20); *ptp = 0; }}/* * Map [paddr, paddr+size) with ARM specific attributes in flags. * If vaddr is ~0, we assign the address, otherwise, the mapping * will be made at the specified virtual address. */paddr_tarm_map(uintptr_t vaddr, paddr_t paddr, size_t size, int flags){ static uintptr_t next_addr = ARM_STARTUP_BASE; paddr_t off = paddr & PGMASK; int cpu; if (!(shdr->flags1 & STARTUP_HDR_FLAGS1_VIRTUAL)) { return paddr; } paddr &= ~PGMASK; size = ROUNDPG(size + off); if (vaddr == ~(uintptr_t)0) { vaddr = next_addr; next_addr += size; } paddr = set_prot(paddr, flags); for (cpu = 0; cpu < lsp.syspage.p->num_cpu; cpu++) { size_t sz = size; uintptr_t va = vaddr; paddr_t pa = paddr; ptp_t *ptp = (ptp_t *)CPU_L1_TABLE(cpu) + ((va >> 20) & ~3); while (sz) { int i; pte_t *pte = (pte_t *)(*ptp & ~PGMASK); if ((*ptp & ARM_PTP_VALID) == 0) { /* * Need to allocate a page table */ pte = (pte_t *)calloc_ram(__PAGESIZE, __PAGESIZE); map_ptbl((paddr_t)pte, va); } pte += (va >> 12) & (ARM_L2_SIZE-1); for (i = (va >> 12) & (ARM_L2_SIZE-1); sz && i < ARM_L2_SIZE; i++) { *pte++ = pa; pa += __PAGESIZE; va += __PAGESIZE; sz -= __PAGESIZE; } ptp += 4; // move to next 4MB } } return vaddr + off;}/* * Map a page in a cpu-specific page table to allow the same virtual * address to map different physical pages on each cpu. */voidarm_map_cpu(int cpu, uintptr_t vaddr, paddr_t paddr, int flags){ ptp_t *ptp = (ptp_t *)CPU_L1_TABLE(cpu) + ((vaddr >> 20) & ~3); pte_t *pte = (pte_t *)(*ptp & ~PGMASK); if ((*ptp & ARM_PTP_VALID) == 0) { /* * Need to allocate a page table */ pte = (pte_t *)calloc_ram(__PAGESIZE, __PAGESIZE); map_ptbl_cpu(cpu, (paddr_t)pte, vaddr); } pte += (vaddr >> 12) & (ARM_L2_SIZE-1); *pte = set_prot(paddr, flags);}paddr_telf_vaddr_to_paddr(uintptr_t vaddr) { ptp_t *ptp; pte_t *pte; ptp = (ptp_t *)CPU_L1_TABLE(0) + ((vaddr >> 20) & ~3); if ((*ptp & ARM_PTP_VALID) == (ARM_PTP_SC & ARM_PTP_VALID)) { return (*ptp & ~ARM_SCMASK) + (vaddr & ARM_SCMASK); } else { pte = (pte_t *)(*ptp & ~PGMASK); pte += (vaddr >> 12) & (ARM_L2_SIZE-1); return (*pte & ~PGMASK) + (vaddr & PGMASK); }};__SRCVERSION("arm_map.c $Rev: 206932 $");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -