/branches/arm/kernel/arch/arm32/src/mm/tlb.c |
---|
52,6 → 52,7 |
); |
} |
/** Invalidate all entries in TLB that belong to specified address space. |
* |
* @param asid Ignored as the ARM architecture doesn't support ASIDs. |
61,6 → 62,7 |
tlb_invalidate_all(); |
} |
/** Invalidate single entry in TLB |
* |
* @param page Virtual adress of the page |
68,19 → 70,21 |
static inline void invalidate_page(uintptr_t page) |
{ |
asm volatile ( |
"mcr p15, 0, %[page], c8, c7, 1\n" |
:: [page] "r" (page) |
"mcr p15, 0, %0, c8, c7, 1" |
: |
: "r"(page) |
); |
} |
/** Invalidate TLB entries for specified page range belonging to specified |
* address space. |
/** Invalidate TLB entries for specified page range belonging to specified address space. |
* |
* @param asid Ignored as the ARM architecture doesn't support it. |
* @param page Address of the first page whose entry is to be invalidated. |
* @param cnt Number of entries to invalidate. |
*/ |
void tlb_invalidate_pages(asid_t asid __attribute__((unused)), uintptr_t page, size_t cnt) |
void tlb_invalidate_pages(asid_t asid, uintptr_t page, count_t cnt) |
{ |
unsigned int i; |
88,13 → 92,5 |
invalidate_page(page + i * PAGE_SIZE); |
} |
void tlb_arch_init(void) |
{ |
} |
void tlb_print(void) |
{ |
} |
/** @} |
*/ |
/branches/arm/kernel/arch/arm32/src/mm/as.c |
---|
48,5 → 48,6 |
as_operations = &as_pt_operations; |
} |
/** @} |
*/ |
/branches/arm/kernel/arch/arm32/src/mm/page_fault.c |
---|
34,13 → 34,14 |
*/ |
#include <panic.h> |
#include <arch/exception.h> |
#include <arch/debug/print.h> |
#include <arch/mm/page_fault.h> |
#include <mm/as.h> |
#include <genarch/mm/page_pt.h> |
#include <arch.h> |
#include <interrupt.h> |
#include <print.h> |
/** Returns value stored in fault status register. |
* |
* @return Value stored in CP15 fault status register (FSR). |
49,62 → 50,65 |
{ |
fault_status_union_t fsu; |
/* fault status is stored in CP15 register 5 */ |
// fault status is stored in CP15 register 5 |
asm volatile ( |
"mrc p15, 0, %[dummy], c5, c0, 0" |
: [dummy] "=r" (fsu.dummy) |
"mrc p15, 0, %0, c5, c0, 0" |
: "=r"(fsu.dummy) |
); |
return fsu.fs; |
} |
/** Returns FAR (fault address register) content. |
* |
* @return FAR (fault address register) content (address that caused a page |
* fault) |
* @return FAR (fault address register) content (address that caused a page fault) |
*/ |
static inline uintptr_t read_fault_address_register(void) |
{ |
uintptr_t ret; |
/* fault adress is stored in CP15 register 6 */ |
// fault adress is stored in CP15 register 6 |
asm volatile ( |
"mrc p15, 0, %[ret], c6, c0, 0" |
: [ret] "=r" (ret) |
"mrc p15, 0, %0, c6, c0, 0" |
: "=r"(ret) |
); |
return ret; |
} |
/** Decides whether the instruction is load/store or not. |
* |
* @param instr Instruction |
* |
* @return true when instruction is load/store, false otherwise |
* |
*/ |
static inline bool is_load_store_instruction(instruction_t instr) |
{ |
/* load store immediate offset */ |
if (instr.type == 0x2) |
// load store immediate offset |
if (instr.type == 0x2) { |
return true; |
} |
/* load store register offset */ |
if ((instr.type == 0x3) && (instr.bit4 == 0)) |
// load store register offset |
if (instr.type == 0x3 && instr.bit4 == 0) { |
return true; |
} |
/* load store multiple */ |
if (instr.type == 0x4) |
// load store multiple |
if (instr.type == 0x4) { |
return true; |
} |
/* oprocessor load/store */ |
if (instr.type == 0x6) |
// coprocessor load/store |
if (instr.type == 0x6) { |
return true; |
} |
return false; |
} |
/** Decides whether the instruction is swap or not. |
/** Decides whether the instructions is swap or not. |
* |
* @param instr Instruction |
* |
112,25 → 116,25 |
*/ |
static inline bool is_swap_instruction(instruction_t instr) |
{ |
/* swap, swapb instruction */ |
if ((instr.type == 0x0) && |
((instr.opcode == 0x8) || (instr.opcode == 0xa)) && |
(instr.access == 0x0) && (instr.bits567 == 0x4) && (instr.bit4 == 1)) |
// swap, swapb instruction |
if (instr.type == 0x0 && |
(instr.opcode == 0x8 || instr.opcode == 0xa) && |
instr.access == 0x0 && instr.bits567 == 0x4 && instr.bit4 == 1) { |
return true; |
} |
return false; |
} |
/** Decides whether read or write into memory is requested. |
* |
* @param instr_addr Address of instruction which tries to access memory. |
* @param badvaddr Virtual address the instruction tries to access. |
* |
* @return Type of access into memory, PF_ACCESS_EXEC if no memory access is |
* requested. |
* @return Type of access into memmory, #PF_ACCESS_EXEC if no memory access is requested. |
*/ |
static pf_access_t get_memory_access_type(uint32_t instr_addr, |
uintptr_t badvaddr) |
static pf_access_t get_memory_access_type(uint32_t instr_addr, uintptr_t badvaddr) |
{ |
instruction_union_t instr_union; |
instr_union.pc = instr_addr; |
137,14 → 141,14 |
instruction_t instr = *(instr_union.instr); |
/* undefined instructions */ |
// undefined instructions |
if (instr.condition == 0xf) { |
panic("page_fault - instruction does not access memory " |
"(instr_code: %x, badvaddr:%x).", instr, badvaddr); |
panic("page_fault - instruction doesn't access memory (instr_code: %x, badvaddr:%x)", |
instr, badvaddr); |
return PF_ACCESS_EXEC; |
} |
/* load store instructions */ |
// load store instructions |
if (is_load_store_instruction(instr)) { |
if (instr.access == 1) { |
return PF_ACCESS_READ; |
153,13 → 157,13 |
} |
} |
/* swap, swpb instruction */ |
// swap, swpb instruction |
if (is_swap_instruction(instr)) { |
return PF_ACCESS_WRITE; |
} |
panic("page_fault - instruction doesn't access memory " |
"(instr_code: %x, badvaddr:%x).", instr, badvaddr); |
panic("page_fault - instruction doesn't access memory (instr_code: %x, badvaddr:%x)", |
instr, badvaddr); |
return PF_ACCESS_EXEC; |
} |
171,8 → 175,7 |
*/ |
void data_abort(int exc_no, istate_t *istate) |
{ |
fault_status_t fsr __attribute__ ((unused)) = |
read_fault_status_register(); |
fault_status_t fsr = read_fault_status_register(); |
uintptr_t badvaddr = read_fault_address_register(); |
pf_access_t access = get_memory_access_type(istate->pc, badvaddr); |
181,12 → 184,11 |
if (ret == AS_PF_FAULT) { |
print_istate(istate); |
printf("page fault - pc: %x, va: %x, status: %x(%x), " |
"access:%d\n", istate->pc, badvaddr, fsr.status, fsr, |
access); |
dprintf("page fault - pc: %x, va: %x, status: %x(%x), access:%d\n", |
istate->pc, badvaddr, fsr.status, fsr, access); |
fault_if_from_uspace(istate, "Page fault: %#x.", badvaddr); |
panic("Page fault."); |
fault_if_from_uspace(istate, "Page fault: %#x", badvaddr); |
panic("page fault\n"); |
} |
} |
200,12 → 202,12 |
int ret = as_page_fault(istate->pc, PF_ACCESS_EXEC, istate); |
if (ret == AS_PF_FAULT) { |
printf("prefetch_abort\n"); |
dprintf("prefetch_abort\n"); |
print_istate(istate); |
panic("page fault - prefetch_abort at address: %x.", |
istate->pc); |
panic("page fault - prefetch_abort at address: %x\n", istate->pc); |
} |
} |
/** @} |
*/ |
/branches/arm/kernel/arch/arm32/src/mm/frame.c |
---|
35,8 → 35,8 |
#include <mm/frame.h> |
#include <arch/mm/frame.h> |
#include <arch/machine.h> |
#include <config.h> |
#include <arch/debug/print.h> |
/** Address of the last frame in the memory. */ |
uintptr_t last_frame = 0; |
44,26 → 44,25 |
/** Creates memory zones. */ |
void frame_arch_init(void) |
{ |
last_frame = machine_get_memory_size(); |
/* All memory as one zone */ |
zone_create(0, ADDR2PFN(last_frame), |
// all memory as one zone |
zone_create(0, ADDR2PFN(config.memory_size), |
BOOT_PAGE_TABLE_START_FRAME + BOOT_PAGE_TABLE_SIZE_IN_FRAMES, 0); |
last_frame = config.memory_size; |
/* blacklist boot page table */ |
frame_mark_unavailable(BOOT_PAGE_TABLE_START_FRAME, |
BOOT_PAGE_TABLE_SIZE_IN_FRAMES); |
machine_frame_init(); |
// blacklist boot page table |
frame_mark_unavailable(BOOT_PAGE_TABLE_START_FRAME, BOOT_PAGE_TABLE_SIZE_IN_FRAMES); |
} |
/** Frees the boot page table. */ |
void boot_page_table_free(void) |
{ |
unsigned int i; |
for (i = 0; i < BOOT_PAGE_TABLE_SIZE_IN_FRAMES; i++) |
int i; |
for (i = 0; i < BOOT_PAGE_TABLE_SIZE_IN_FRAMES; ++i) { |
frame_free(i * FRAME_SIZE + BOOT_PAGE_TABLE_ADDRESS); |
} |
} |
/** @} |
*/ |
/branches/arm/kernel/arch/arm32/src/mm/page.c |
---|
44,6 → 44,7 |
#include <interrupt.h> |
#include <arch/mm/frame.h> |
/** Initializes page tables. |
* |
* 1:1 virtual-physical mapping is created in kernel address space. Mapping |
51,15 → 52,19 |
*/ |
void page_arch_init(void) |
{ |
int flags = PAGE_CACHEABLE; |
uintptr_t cur; |
int flags; |
page_mapping_operations = &pt_mapping_operations; |
uintptr_t cur; |
/* Kernel identity mapping */ |
for (cur = 0; cur < last_frame; cur += FRAME_SIZE) |
flags = PAGE_CACHEABLE; |
// PA2KA(identity) mapping for all frames until last_frame |
for (cur = 0; cur < last_frame; cur += FRAME_SIZE) { |
page_mapping_insert(AS_KERNEL, PA2KA(cur), cur, flags); |
} |
/* Create mapping for exception table at high offset */ |
// create mapping for exception table at high offset |
#ifdef HIGH_EXCEPTION_VECTORS |
void *virtaddr = frame_alloc(ONE_FRAME, FRAME_KA); |
page_mapping_insert(AS_KERNEL, EXC_BASE_ADDRESS, KA2PA(virtaddr), flags); |
84,17 → 89,14 |
*/ |
uintptr_t hw_map(uintptr_t physaddr, size_t size) |
{ |
if (last_frame + ALIGN_UP(size, PAGE_SIZE) > |
KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH)) { |
panic("Unable to map physical memory %p (%d bytes).", |
physaddr, size) |
if (last_frame + ALIGN_UP(size, PAGE_SIZE) > KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH)) { |
panic("Unable to map physical memory %p (%d bytes)", physaddr, size) |
} |
uintptr_t virtaddr = PA2KA(last_frame); |
pfn_t i; |
for (i = 0; i < ADDR2PFN(ALIGN_UP(size, PAGE_SIZE)); i++) { |
page_mapping_insert(AS_KERNEL, virtaddr + PFN2ADDR(i), |
physaddr + PFN2ADDR(i), |
page_mapping_insert(AS_KERNEL, virtaddr + PFN2ADDR(i), physaddr + PFN2ADDR(i), |
PAGE_NOT_CACHEABLE | PAGE_READ | PAGE_WRITE | PAGE_KERNEL); |
} |
102,5 → 104,7 |
return virtaddr; |
} |
/** @} |
*/ |
/branches/arm/kernel/arch/arm32/src/mm/memory_init.c |
---|
0,0 → 1,51 |
/* |
* Copyright (c) 2007 Pavel Jancik |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup arm32mm |
* @{ |
*/ |
/** @file |
* @brief Memory information functions. |
*/ |
#include <arch/mm/memory_init.h> |
#include <arch/mm/page.h> |
#include <arch/machine.h> |
/** Returns memory size. |
* |
* @return Memory size in bytes |
*/ |
size_t get_memory_size(void) |
{ |
return machine_get_memory_size(); |
} |
/** @} |
*/ |