Skip to content
This repository
  • 5 commits
  • 8 files changed
  • 0 comments
  • 1 contributor
13  software/include/base/mmu.h
... ...
@@ -0,0 +1,13 @@
  1
+#ifndef __BASE_MMU_H__
  2
+#define __BASE_MMU_H__
  3
+
  4
+#include <hal/mmu.h>
  5
+
  6
+unsigned int mmu_map(unsigned int vaddr, unsigned int paddr);
  7
+unsigned int get_mmu_mapping_for(unsigned int vaddr);
  8
+unsigned char remove_mmu_mapping_for(unsigned int vaddr);
  9
+void panic(void);
  10
+void check_for_error(int ret);
  11
+unsigned int read_word_with_mmu_enabled(unsigned int vaddr);
  12
+
  13
+#endif
19  software/include/hal/mmu.h
@@ -15,6 +15,23 @@
15 15
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16
  */
17 17
 
  18
+#ifndef __MMU_H__
  19
+#define __MMU_H__
  20
+
  21
+#define PAGE_SIZE	(4096)
  22
+#define MAX_MMU_SLOTS	10
  23
+#define NO_EMPTY_SLOT	(MAX_MMU_SLOTS + 1)
  24
+#define A_BAD_ADDR	0xffffffff
  25
+#define NULL 		(0)
  26
+#define get_pfn(x)	(x & ~(PAGE_SIZE - 1))
  27
+
  28
+struct mmu_mapping {
  29
+
  30
+	unsigned int vaddr;
  31
+	unsigned int paddr;
  32
+	char valid;
  33
+
  34
+};
18 35
 
19 36
 #define enable_dtlb() do { \
20 37
 	asm volatile	("xor r11, r11, r11\n\t" \
@@ -33,3 +50,5 @@
33 50
 } while(0);
34 51
 
35 52
 void mmu_dtlb_map(unsigned int vpfn, unsigned int pfn);
  53
+
  54
+#endif
2  software/mmu-bios/Makefile
... ...
@@ -1,7 +1,7 @@
1 1
 MMDIR=../..
2 2
 include $(MMDIR)/software/include.mak
3 3
 
4  
-OBJECTS=crt0.o main.o dtlb_load_test.o mmu.o isr.o vsnprintf-nofloat.o dtlb_miss_handler.o
  4
+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
5 5
 SEGMENTS=-j .text -j .data -j .rodata
6 6
 
7 7
 all: bios.bin
60  software/mmu-bios/dtlb_exception_handling_tests.c
... ...
@@ -0,0 +1,60 @@
  1
+#include <hal/mmu.h>
  2
+#include <base/mmu.h>
  3
+
  4
+void dtlb_exception_handling_tests() {
  5
+
  6
+	register unsigned int stack, addr;
  7
+	unsigned int data;
  8
+	int ret;
  9
+
  10
+	asm volatile("mv %0, sp" : "=r"(stack) :: );
  11
+
  12
+	ret = mmu_map(stack, stack);
  13
+	check_for_error(ret);
  14
+
  15
+	ret = mmu_map(stack-0x1000, stack-0x1000);
  16
+	check_for_error(ret);
  17
+
  18
+	printf("stack == 0x%08X\n", stack);
  19
+
  20
+	addr = 0x44004004;
  21
+
  22
+	printf("\n=> Mapping 0x%08X to 0x%08X\n", addr, addr);
  23
+	ret = mmu_map(addr, addr);
  24
+	check_for_error(ret);
  25
+
  26
+	data = 42;
  27
+	printf("=> Writing %d to physical address 0x%08X\n", data, addr);
  28
+	*(unsigned int *)addr = data;
  29
+
  30
+	printf("=> Activating the MMU and reading form virtual address 0x%08X\n", addr);
  31
+	data = read_word_with_mmu_enabled(addr);
  32
+	printf("\n<= Reading %d from virtual address 0x%08X\n\n", data, addr);
  33
+
  34
+	printf("=> Invalidating the mapping of virtual address 0x%08X in the TLB\n", addr);
  35
+	mmu_dtlb_invalidate(addr);
  36
+
  37
+	data = 43;
  38
+	printf("=> Writing %d to physical address 0x%08X\n", data, addr);
  39
+	*(unsigned int *)addr = data;
  40
+
  41
+	printf("=> Activating the MMU and reading form virtual address 0x%08X\n", addr);
  42
+	data = read_word_with_mmu_enabled(addr);
  43
+	printf("\n<= Reading %d from virtual address 0x%08X\n\n", data, addr);
  44
+
  45
+	printf("=> Mapping 0x%08X to 0%08X\n", addr, addr+0x1000);
  46
+	ret = mmu_map(addr, addr+0x1000); // Map to something else
  47
+	check_for_error(ret);
  48
+
  49
+	printf("=> Invalidating the mapping of virtual address 0x%08X in the TLB\n", addr);
  50
+	mmu_dtlb_invalidate(addr); // AND invalidate the mapping
  51
+
  52
+	data = 44;
  53
+	printf("=> Writting %d to physical address 0x%08X\n", data, addr+0x1000);
  54
+	*(unsigned int *)(addr + 0x1000) = data;
  55
+
  56
+	printf("=> Activating the MMU and reading form virtual address 0x%08X\n", addr);
  57
+	data = read_word_with_mmu_enabled(addr);
  58
+	printf("\n<= Reading %d from virtual address 0x%08X\n\n", data, addr);
  59
+
  60
+}
22  software/mmu-bios/dtlb_miss_handler.c
... ...
@@ -1,6 +1,26 @@
1 1
 #include <hal/mmu.h>
  2
+#include <base/mmu.h>
2 3
 
3 4
 void dtlb_miss_handler(void)
4 5
 {
5  
-	mmu_dtlb_map(0x44000000, 0x44003000);
  6
+	unsigned int vaddr, paddr;
  7
+
  8
+	// retrieve virtual address which caused the page fault
  9
+	asm volatile("rcsr %0, dtlbma" : "=r"(vaddr) :: );
  10
+
  11
+	/*
  12
+	* check if there is an existing mapping for that virtual address
  13
+	* if yes: refill the DTLB with it
  14
+	* if not: we panic() !
  15
+	*/
  16
+	paddr = get_mmu_mapping_for(vaddr);
  17
+	if (paddr == A_BAD_ADDR)
  18
+	{
  19
+		puts("Unrecoverable page fault !");
  20
+		panic();
  21
+	}
  22
+
  23
+	printf("Refilling DTLB with mapping 0x%08X->0x%08X\n", vaddr, paddr);
  24
+	mmu_dtlb_map(vaddr, paddr);
  25
+
6 26
 }
2  software/mmu-bios/linker.ld
@@ -4,7 +4,7 @@ ENTRY(_start)
4 4
 __DYNAMIC = 0;
5 5
 
6 6
 MEMORY {
7  
-	sram : ORIGIN = 0x44000000, LENGTH = 0x4100
  7
+	sram : ORIGIN = 0x44000000, LENGTH = 0x7100
8 8
 }
9 9
 
10 10
 SECTIONS
4  software/mmu-bios/main.c
@@ -75,8 +75,8 @@ int printf(const char *fmt, ...)
75 75
 int main(int argc, char **argv)
76 76
 {
77 77
 	asm volatile("wcsr IE, r0");
78  
-//	asm volatile("scall");
79  
-	dtlb_load_test();
  78
+//	dtlb_load_test();
  79
+	dtlb_exception_handling_tests();
80 80
 
81 81
 	while (1)
82 82
 	{
139  software/mmu-bios/mmu.c
@@ -18,6 +18,10 @@
18 18
 /* @vpfn : virtual page frame number
19 19
  * @pfn  : physical page frame number
20 20
  */
  21
+
  22
+#include <hal/mmu.h>
  23
+#include <base/mmu.h>
  24
+
21 25
 inline void mmu_dtlb_map(unsigned int vpfn, unsigned int pfn)
22 26
 {
23 27
 
@@ -32,3 +36,138 @@ inline void mmu_dtlb_map(unsigned int vpfn, unsigned int pfn)
32 36
 			 "wcsr tlbctrl, r11":::"r11");
33 37
 
34 38
 }
  39
+
  40
+inline void mmu_dtlb_invalidate(unsigned int vaddr)
  41
+{
  42
+	asm volatile ("ori %0, %0, 1\n\t"
  43
+		      "wcsr tlbvaddr, %0"::"r"(vaddr):);
  44
+
  45
+	asm volatile ("xor r11, r11, r11\n\t"
  46
+		      "ori r11, r11, 0x21\n\t"
  47
+		      "wcsr tlbctrl, r11":::"r11");
  48
+}
  49
+
  50
+struct mmu_mapping mappings[MAX_MMU_SLOTS];
  51
+
  52
+
  53
+/*
  54
+ * This records in a global structure all MMU mappings
  55
+ * If such a mapping already exists the function returns immediately.
  56
+ * If such a mapping does not exist yet, vaddr is mapped to paddr and
  57
+ * the mapping is recorded in the mappings[] global structure array in
  58
+ * an empty slot.
  59
+ * If there is no empty slot anymore then we fail
  60
+ */
  61
+
  62
+unsigned int mmu_map(unsigned int vaddr, unsigned int paddr) {
  63
+	int i;
  64
+	register unsigned int stack;
  65
+	int empty_slot = NO_EMPTY_SLOT;
  66
+	vaddr = get_pfn(vaddr);
  67
+	paddr = get_pfn(paddr);
  68
+
  69
+	asm volatile("mv %0, sp" : "=r"(stack) :: );
  70
+	printf("stack == 0x%08X\n", stack);
  71
+
  72
+	for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
  73
+	{
  74
+		if (!mappings[i].valid)
  75
+			empty_slot = i;
  76
+		if ((vaddr == mappings[i].vaddr) && (paddr == mappings[i].paddr) && mappings[i].valid)
  77
+		{
  78
+			puts("Already mapped !");
  79
+			return 1;
  80
+		}
  81
+	}
  82
+
  83
+	if (empty_slot == NO_EMPTY_SLOT)
  84
+	{
  85
+		puts("No more slots !");
  86
+		return empty_slot;
  87
+	}
  88
+
  89
+	mappings[empty_slot].vaddr = vaddr;
  90
+	mappings[empty_slot].paddr = paddr;
  91
+	mappings[empty_slot].valid = 1;
  92
+	mmu_dtlb_map(vaddr, paddr);
  93
+	printf("mapping 0x%08X->0x%08X in slot %d [0x%p]\n", vaddr, paddr, empty_slot, &mappings[empty_slot]);
  94
+
  95
+	return 1;
  96
+}
  97
+
  98
+unsigned int get_mmu_mapping_for(unsigned int vaddr) {
  99
+	int i;
  100
+	vaddr = get_pfn(vaddr);
  101
+
  102
+	for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
  103
+		if (mappings[i].valid && (vaddr == mappings[i].vaddr))
  104
+			return mappings[i].paddr;
  105
+
  106
+	return A_BAD_ADDR;
  107
+}
  108
+
  109
+unsigned char remove_mmu_mapping_for(unsigned int vaddr) {
  110
+	int i;
  111
+	vaddr = get_pfn(vaddr);
  112
+
  113
+	for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
  114
+	{
  115
+		if (mappings[i].valid && (vaddr == mappings[i].vaddr))
  116
+		{
  117
+			mmu_dtlb_invalidate(vaddr);
  118
+			mappings[i].valid = 0;
  119
+			return 1;
  120
+		}
  121
+	}
  122
+	return 0;
  123
+}
  124
+
  125
+void panic(void) {
  126
+	puts("PANIC !");
  127
+	while(1)
  128
+		asm volatile("nop");
  129
+}
  130
+
  131
+void check_for_error(int ret) {
  132
+	if (ret == 1)
  133
+		return;
  134
+
  135
+	if (ret == NO_EMPTY_SLOT)
  136
+	{
  137
+		puts("No empty slot in MMU mappings structure anymore");
  138
+		panic();
  139
+	}
  140
+
  141
+	if ( !ret )
  142
+	{
  143
+		puts("Unknown issue");
  144
+		panic();
  145
+	}
  146
+}
  147
+
  148
+/* This function activates the MMU
  149
+ * then reads from virtual address "vaddr"
  150
+ * and store the result in temporary variable "data".
  151
+ * Then MMU is disactivated and the content of "data"
  152
+ * is returned.
  153
+ */
  154
+
  155
+unsigned int read_word_with_mmu_enabled(unsigned int vaddr)
  156
+{
  157
+	register unsigned int data;
  158
+	asm volatile(
  159
+		"xor r11, r11, r11\n\t"
  160
+		"ori r11, r11, 0x11\n\t"
  161
+		"wcsr tlbctrl, r11\n\t" // Activates the MMU
  162
+		"xor r0, r0, r0\n\t"
  163
+		"xor r11, r11, r11\n\t"
  164
+		"or r11, r11, %1\n\t"
  165
+		"lw  %0, (r11+0)\n\t" // Reads from virtual address "addr"
  166
+		"xor r11, r11, r11\n\t"
  167
+		"ori r11, r11, 0x9\n\t"
  168
+		"wcsr tlbctrl, r11\n\t" // Disactivates the MMU
  169
+		"xor r0, r0, r0\n\t" : "=&r"(data) : "r"(vaddr) : "r11"
  170
+	);
  171
+
  172
+	return data;
  173
+}

No commit comments for this range

Something went wrong with that request. Please try again.