Skip to content

Commit

Permalink
Add a test for DTLB exception handling in Milkymist BIOS
Browse files Browse the repository at this point in the history
  • Loading branch information
fallen committed May 30, 2012
1 parent 43f6245 commit 23f3785
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 2 deletions.
2 changes: 1 addition & 1 deletion software/bios/Makefile
@@ -1,7 +1,7 @@
MMDIR=../..
include $(MMDIR)/software/include.mak

OBJECTS=crt0.o isr.o main.o unlzma.o boot.o boot-helper.o splash.o dtlb_load_test.o
OBJECTS=crt0.o isr.o main.o unlzma.o boot.o boot-helper.o splash.o dtlb_load_test.o dtlb_exception_handling_tests.o dtlb_miss_handler.o
SEGMENTS=-j .text -j .data -j .rodata
LIBS=$(MMDIR)/software/libhpdmc/libhpdmc.a $(MMDIR)/software/libbase/libbase-light.a \
$(MMDIR)/software/libhal/libhal.a $(MMDIR)/software/libnet/libnet.a
Expand Down
20 changes: 20 additions & 0 deletions software/bios/crt0.S
Expand Up @@ -97,6 +97,26 @@ _interrupt_handler:
nop
nop

_scall_handler:
bi _scall_handler
nop
nop
nop
nop
nop
nop
nop

_dtlb_miss_exception_handler:
sw (sp+0), ra
addi ea, ea, -4
calli .save_all
calli dtlb_miss_handler
bi .restore_all_and_eret
nop
nop
nop

macaddress:
.byte 0x10
.byte 0xe2
Expand Down
160 changes: 160 additions & 0 deletions software/bios/dtlb_exception_handling_tests.c
@@ -0,0 +1,160 @@
#include <hal/mmu.h>

#define PAGE_SIZE (4096)

#define MAX_MMU_SLOTS 10
#define NO_EMPTY_SLOT (MAX_MMU_SLOTS + 1)

#define A_BAD_ADDR (0)

#define NULL (0)

#define get_pfn(x) (x & ~(PAGE_SIZE - 1))

struct mmu_mapping {

unsigned int vaddr;
unsigned int paddr;
char valid;

} mappings[10];

/*
* 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;
int empty_slot = NO_EMPTY_SLOT;
vaddr = get_pfn(vaddr);

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

if (empty_slot == NO_EMPTY_SLOT)
return empty_slot;

mappings[empty_slot].vaddr = vaddr;
mappings[empty_slot].paddr = paddr;
mappings[empty_slot].valid = 1;
mmu_dtlb_map(vaddr, paddr);

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 int invalidate_mmu_mapping(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;
}

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

static void check_for_error(int ret) {
if (ret)
return;

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

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

void dtlb_exception_handling_tests() {

register unsigned int stack, addr, 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 = 0x44002342; // Random address
*(unsigned int *)addr = 42;
// mmu_map(addr, addr);

printf("Address 0x%08X mapped to itself, value : ", addr);

asm volatile(
"xor r11, r11, r11\n\t"
"ori r11, r11, 0x11\n\t"
"wcsr tlbctrl, r11\n\t" // this 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"
"xor r11, r11, r11\n\t"
"ori r11, r11, 0x9\n\t"
"wcsr tlbctrl, r11\n\t" // this disactivates the mmu
"xor r0, r0, r0" : "=&r"(data) : "r"(addr) : "r11"
);

printf("%d\n", data);

invalidate_mmu_mapping(addr);

printf("DTLB has just been invalidated, next access to 0x%08X should trigger a DTLB exception\n", addr);

printf("Address 0x%08X not mapped, value : ", addr);

asm volatile(
"xor r11, r11, r11\n\t"
"ori r11, r11, 0x11\n\t"
"wcsr tlbctrl, r11\n\t" // this 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"
"xor r11, r11, r11\n\t"
"ori r11, r11, 0x9\n\t"
"wcsr tlbctrl, r11\n\t" // this disactivates the mmu
"xor r0, r0, r0" : "=&r"(data) : "r"(addr) : "r11"
);

printf("%d\n", data);

}
8 changes: 8 additions & 0 deletions software/bios/dtlb_miss_handler.c
@@ -0,0 +1,8 @@
#include <hal/mmu.h>

void dtlb_miss_handler(void) {

disable_dtlb();
printf("TOTO");

}
4 changes: 3 additions & 1 deletion software/bios/main.c
Expand Up @@ -422,7 +422,8 @@ static void help()
puts("version - display version");
puts("reboot - system reset");
puts("reconf - reload FPGA configuration");
puts("dtlbtest - runs DTLB MMU test");
puts("dtlbtest - runs DTLB MMU load store tests");
puts("detest - runs DTLB MMU exception handling tests");
}

static char *get_token(char **str)
Expand Down Expand Up @@ -538,6 +539,7 @@ static void do_command(char *c)
else if(strcmp(token, "rcsr") == 0) rcsr(get_token(&c));
else if(strcmp(token, "wcsr") == 0) wcsr(get_token(&c), get_token(&c));
else if(strcmp(token, "dtlbtest") == 0) dtlbtest();
else if(strcmp(token, "detest") == 0) dtlb_exception_handling_tests();

else if(strcmp(token, "") != 0)
printf("Command not found\n");
Expand Down
10 changes: 10 additions & 0 deletions software/libhal/mmu.c
Expand Up @@ -32,3 +32,13 @@ 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");
}

0 comments on commit 23f3785

Please sign in to comment.