Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: fallen/milkymist-mmu
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: c8308d8
Choose a base ref
...
head repository: fallen/milkymist-mmu
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 795cb9d
Choose a head ref
  • 5 commits
  • 8 files changed
  • 1 contributor

Commits on May 21, 2012

  1. Copy the full SHA
    1e1d128 View commit details

Commits on Jun 1, 2012

  1. Increase stack size

    fallen committed Jun 1, 2012
    Copy the full SHA
    11ea31e View commit details
  2. Copy the full SHA
    a7f2c35 View commit details
  3. Copy the full SHA
    70b0966 View commit details
  4. Copy the full SHA
    795cb9d View commit details
13 changes: 13 additions & 0 deletions software/include/base/mmu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef __BASE_MMU_H__
#define __BASE_MMU_H__

#include <hal/mmu.h>

unsigned int mmu_map(unsigned int vaddr, unsigned int paddr);
unsigned int get_mmu_mapping_for(unsigned int vaddr);
unsigned char remove_mmu_mapping_for(unsigned int vaddr);
void panic(void);
void check_for_error(int ret);
unsigned int read_word_with_mmu_enabled(unsigned int vaddr);

#endif
19 changes: 19 additions & 0 deletions software/include/hal/mmu.h
Original file line number Diff line number Diff line change
@@ -15,6 +15,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __MMU_H__
#define __MMU_H__

#define PAGE_SIZE (4096)
#define MAX_MMU_SLOTS 10
#define NO_EMPTY_SLOT (MAX_MMU_SLOTS + 1)
#define A_BAD_ADDR 0xffffffff
#define NULL (0)
#define get_pfn(x) (x & ~(PAGE_SIZE - 1))

struct mmu_mapping {

unsigned int vaddr;
unsigned int paddr;
char valid;

};

#define enable_dtlb() do { \
asm volatile ("xor r11, r11, r11\n\t" \
@@ -33,3 +50,5 @@
} while(0);

void mmu_dtlb_map(unsigned int vpfn, unsigned int pfn);

#endif
2 changes: 1 addition & 1 deletion software/mmu-bios/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
MMDIR=../..
include $(MMDIR)/software/include.mak

OBJECTS=crt0.o main.o dtlb_load_test.o mmu.o isr.o vsnprintf-nofloat.o dtlb_miss_handler.o
OBJECTS=crt0.o main.o dtlb_load_test.o mmu.o isr.o vsnprintf-nofloat.o dtlb_miss_handler.o dtlb_exception_handling_tests.o
SEGMENTS=-j .text -j .data -j .rodata

all: bios.bin
60 changes: 60 additions & 0 deletions software/mmu-bios/dtlb_exception_handling_tests.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <hal/mmu.h>
#include <base/mmu.h>

void dtlb_exception_handling_tests() {

register unsigned int stack, addr;
unsigned int data;
int ret;

asm volatile("mv %0, sp" : "=r"(stack) :: );

ret = mmu_map(stack, stack);
check_for_error(ret);

ret = mmu_map(stack-0x1000, stack-0x1000);
check_for_error(ret);

printf("stack == 0x%08X\n", stack);

addr = 0x44004004;

printf("\n=> Mapping 0x%08X to 0x%08X\n", addr, addr);
ret = mmu_map(addr, addr);
check_for_error(ret);

data = 42;
printf("=> Writing %d to physical address 0x%08X\n", data, addr);
*(unsigned int *)addr = data;

printf("=> Activating the MMU and reading form virtual address 0x%08X\n", addr);
data = read_word_with_mmu_enabled(addr);
printf("\n<= Reading %d from virtual address 0x%08X\n\n", data, addr);

printf("=> Invalidating the mapping of virtual address 0x%08X in the TLB\n", addr);
mmu_dtlb_invalidate(addr);

data = 43;
printf("=> Writing %d to physical address 0x%08X\n", data, addr);
*(unsigned int *)addr = data;

printf("=> Activating the MMU and reading form virtual address 0x%08X\n", addr);
data = read_word_with_mmu_enabled(addr);
printf("\n<= Reading %d from virtual address 0x%08X\n\n", data, addr);

printf("=> Mapping 0x%08X to 0%08X\n", addr, addr+0x1000);
ret = mmu_map(addr, addr+0x1000); // Map to something else
check_for_error(ret);

printf("=> Invalidating the mapping of virtual address 0x%08X in the TLB\n", addr);
mmu_dtlb_invalidate(addr); // AND invalidate the mapping

data = 44;
printf("=> Writting %d to physical address 0x%08X\n", data, addr+0x1000);
*(unsigned int *)(addr + 0x1000) = data;

printf("=> Activating the MMU and reading form virtual address 0x%08X\n", addr);
data = read_word_with_mmu_enabled(addr);
printf("\n<= Reading %d from virtual address 0x%08X\n\n", data, addr);

}
22 changes: 21 additions & 1 deletion software/mmu-bios/dtlb_miss_handler.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
#include <hal/mmu.h>
#include <base/mmu.h>

void dtlb_miss_handler(void)
{
mmu_dtlb_map(0x44000000, 0x44003000);
unsigned int vaddr, paddr;

// retrieve virtual address which caused the page fault
asm volatile("rcsr %0, dtlbma" : "=r"(vaddr) :: );

/*
* check if there is an existing mapping for that virtual address
* if yes: refill the DTLB with it
* if not: we panic() !
*/
paddr = get_mmu_mapping_for(vaddr);
if (paddr == A_BAD_ADDR)
{
puts("Unrecoverable page fault !");
panic();
}

printf("Refilling DTLB with mapping 0x%08X->0x%08X\n", vaddr, paddr);
mmu_dtlb_map(vaddr, paddr);

}
2 changes: 1 addition & 1 deletion software/mmu-bios/linker.ld
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ ENTRY(_start)
__DYNAMIC = 0;

MEMORY {
sram : ORIGIN = 0x44000000, LENGTH = 0x4100
sram : ORIGIN = 0x44000000, LENGTH = 0x7100
}

SECTIONS
4 changes: 2 additions & 2 deletions software/mmu-bios/main.c
Original file line number Diff line number Diff line change
@@ -75,8 +75,8 @@ int printf(const char *fmt, ...)
int main(int argc, char **argv)
{
asm volatile("wcsr IE, r0");
// asm volatile("scall");
dtlb_load_test();
// dtlb_load_test();
dtlb_exception_handling_tests();

while (1)
{
139 changes: 139 additions & 0 deletions software/mmu-bios/mmu.c
Original file line number Diff line number Diff line change
@@ -18,6 +18,10 @@
/* @vpfn : virtual page frame number
* @pfn : physical page frame number
*/

#include <hal/mmu.h>
#include <base/mmu.h>

inline void mmu_dtlb_map(unsigned int vpfn, unsigned int pfn)
{

@@ -32,3 +36,138 @@ inline void mmu_dtlb_map(unsigned int vpfn, unsigned int pfn)
"wcsr tlbctrl, r11":::"r11");

}

inline void mmu_dtlb_invalidate(unsigned int vaddr)
{
asm volatile ("ori %0, %0, 1\n\t"
"wcsr tlbvaddr, %0"::"r"(vaddr):);

asm volatile ("xor r11, r11, r11\n\t"
"ori r11, r11, 0x21\n\t"
"wcsr tlbctrl, r11":::"r11");
}

struct mmu_mapping mappings[MAX_MMU_SLOTS];


/*
* This records in a global structure all MMU mappings
* If such a mapping already exists the function returns immediately.
* If such a mapping does not exist yet, vaddr is mapped to paddr and
* the mapping is recorded in the mappings[] global structure array in
* an empty slot.
* If there is no empty slot anymore then we fail
*/

unsigned int mmu_map(unsigned int vaddr, unsigned int paddr) {
int i;
register unsigned int stack;
int empty_slot = NO_EMPTY_SLOT;
vaddr = get_pfn(vaddr);
paddr = get_pfn(paddr);

asm volatile("mv %0, sp" : "=r"(stack) :: );
printf("stack == 0x%08X\n", stack);

for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
{
if (!mappings[i].valid)
empty_slot = i;
if ((vaddr == mappings[i].vaddr) && (paddr == mappings[i].paddr) && mappings[i].valid)
{
puts("Already mapped !");
return 1;
}
}

if (empty_slot == NO_EMPTY_SLOT)
{
puts("No more slots !");
return empty_slot;
}

mappings[empty_slot].vaddr = vaddr;
mappings[empty_slot].paddr = paddr;
mappings[empty_slot].valid = 1;
mmu_dtlb_map(vaddr, paddr);
printf("mapping 0x%08X->0x%08X in slot %d [0x%p]\n", vaddr, paddr, empty_slot, &mappings[empty_slot]);

return 1;
}

unsigned int get_mmu_mapping_for(unsigned int vaddr) {
int i;
vaddr = get_pfn(vaddr);

for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
if (mappings[i].valid && (vaddr == mappings[i].vaddr))
return mappings[i].paddr;

return A_BAD_ADDR;
}

unsigned char remove_mmu_mapping_for(unsigned int vaddr) {
int i;
vaddr = get_pfn(vaddr);

for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
{
if (mappings[i].valid && (vaddr == mappings[i].vaddr))
{
mmu_dtlb_invalidate(vaddr);
mappings[i].valid = 0;
return 1;
}
}
return 0;
}

void panic(void) {
puts("PANIC !");
while(1)
asm volatile("nop");
}

void check_for_error(int ret) {
if (ret == 1)
return;

if (ret == NO_EMPTY_SLOT)
{
puts("No empty slot in MMU mappings structure anymore");
panic();
}

if ( !ret )
{
puts("Unknown issue");
panic();
}
}

/* This function activates the MMU
* then reads from virtual address "vaddr"
* and store the result in temporary variable "data".
* Then MMU is disactivated and the content of "data"
* is returned.
*/

unsigned int read_word_with_mmu_enabled(unsigned int vaddr)
{
register unsigned int data;
asm volatile(
"xor r11, r11, r11\n\t"
"ori r11, r11, 0x11\n\t"
"wcsr tlbctrl, r11\n\t" // Activates the MMU
"xor r0, r0, r0\n\t"
"xor r11, r11, r11\n\t"
"or r11, r11, %1\n\t"
"lw %0, (r11+0)\n\t" // Reads from virtual address "addr"
"xor r11, r11, r11\n\t"
"ori r11, r11, 0x9\n\t"
"wcsr tlbctrl, r11\n\t" // Disactivates the MMU
"xor r0, r0, r0\n\t" : "=&r"(data) : "r"(vaddr) : "r11"
);

return data;
}