Skip to content

Commit

Permalink
MMU DTLB page fault handling working on FPGA
Browse files Browse the repository at this point in the history
fallen committed Jun 3, 2012
1 parent 23f3785 commit 790d654
Showing 10 changed files with 313 additions and 200 deletions.
2 changes: 1 addition & 1 deletion cores/lm32/rtl/lm32_cpu.v
Original file line number Diff line number Diff line change
@@ -2143,7 +2143,7 @@ begin
`LM32_CSR_JRX: csr_read_data_x = jrx_csr_read_data;
`endif
`LM32_CSR_CFG2: csr_read_data_x = cfg2;
`LM32_CSR_TLB_DBG: csr_read_data_x = load_store_csr_read_data_x;
`LM32_CSR_TLB_VADDRESS: csr_read_data_x = load_store_csr_read_data_x;

default: csr_read_data_x = {`LM32_WORD_WIDTH{1'bx}};
endcase
73 changes: 19 additions & 54 deletions cores/lm32/rtl/lm32_dcache.v
Original file line number Diff line number Diff line change
@@ -110,6 +110,7 @@ module lm32_dcache (
csr_write_enable,
exception_x,
eret_q_x,
exception_m,
// ----- Outputs -----
stall_request,
restart_request,
@@ -118,7 +119,7 @@ module lm32_dcache (
refilling,
load_data,
// To pipeline
dtlb_miss_q,
dtlb_miss_int,
kernel_mode,
pa,
csr_read_data
@@ -138,7 +139,6 @@ parameter dtlb_sets = 1024; // Number of lines of DTLB
parameter page_size = 4096; // System page size

`define LM32_DTLB_IDX_RNG addr_dtlb_index_msb:addr_dtlb_index_lsb
//`define LM32_DTLB_INVALID_TAG { {9{1'b1}}, `FALSE}
`define LM32_DTLB_ADDRESS_PFN_RNG addr_pfn_msb:addr_pfn_lsb
`define LM32_PAGE_OFFSET_RNG addr_page_offset_msb:addr_page_offset_lsb
`define LM32_DTLB_INVALID_ADDRESS { vpfn_width{1'b1} }
@@ -206,6 +206,7 @@ input [`LM32_CSR_RNG] csr; // CSR read/write index
input [`LM32_WORD_RNG] csr_write_data; // Data to write to specified CSR
input csr_write_enable; // CSR write enable
input exception_x; // An exception occured in the X stage
input exception_m;
input eret_q_x;

/////////////////////////////////////////////////////
@@ -231,9 +232,7 @@ wire [`LM32_WORD_RNG] load_data;
output kernel_mode;
wire kernel_mode;

output dtlb_miss_q;
//output dtlb_miss;
//output dtlb_miss_int;
output dtlb_miss_int;

/////////////////////////////////////////////////////
// Internal nets and registers
@@ -294,8 +293,8 @@ reg [addr_dtlb_index_width-1:0] dtlb_update_set;
reg dtlb_flushing;
reg [addr_dtlb_index_width-1:0] dtlb_flush_set;
wire dtlb_miss;
reg dtlb_miss_q = 0;
reg dtlb_miss_int = 0;
reg dtlb_miss_q = `FALSE;
wire dtlb_miss_int;
reg [`LM32_WORD_RNG] dtlb_miss_addr;
wire dtlb_data_valid;
wire [`LM32_DTLB_LOOKUP_RANGE] dtlb_lookup;
@@ -465,27 +464,14 @@ end
generate
for (i = 0; i < associativity; i = i + 1)
begin : match
// FIXME : We need to put physical address coming out from MMU instead of address_m[]
//assign way_match[i] = ({way_tag[i], way_valid[i]} == {address_m[`LM32_DC_ADDR_TAG_RNG], `TRUE});

assign dtlb_read_tag = dtlb_read_data[`LM32_DTLB_TAG_RANGE];
assign dtlb_data_valid = dtlb_read_data[`LM32_DTLB_VALID_BIT];
assign dtlb_lookup = dtlb_read_data[`LM32_DTLB_LOOKUP_RANGE];

assign way_match[i] = (kernel_mode_reg == `LM32_KERNEL_MODE) ?
({way_tag[i], way_valid[i]} == {address_m[`LM32_DC_ADDR_TAG_RNG], `TRUE})
: /*dtlb_data_valid && (dtlb_read_tag == address_m[`LM32_DC_ADDR_TAG_RNG]) &&
*/ ({way_tag[i], way_valid[i]} == {dtlb_lookup, `TRUE});

/*always @(*)
begin
if (kernel_mode_reg == `LM32_KERNEL_MODE)
way_match[i] <= ({way_tag[i], way_valid[i]} == {address_m[`LM32_DC_ADDR_TAG_RNG], `TRUE});
else if (dtlb_read_tag == `LM32_DTLB_TAG_INVALID) // DTLB tag is invalid
way_match[i] <= `FALSE;
else
way_match[i] <= ({way_tag[i], way_valid[i]} == {dtlb_read_data, `TRUE});
end*/
: ({way_tag[i], way_valid[i]} == {dtlb_lookup, `TRUE});
end
endgenerate

@@ -555,13 +541,7 @@ assign dtlb_data_read_address = address_x[`LM32_DTLB_IDX_RNG];
assign dtlb_tag_read_address = address_x[`LM32_DTLB_IDX_RNG];

// tlb_update_address will receive data from a CSR register
assign dtlb_data_write_address = /*(dtlb_flushing == `TRUE)
? dtlb_flush_set
: */dtlb_update_vaddr_csr_reg[`LM32_DTLB_IDX_RNG];

assign dtlb_tag_write_address = (dtlb_flushing == `TRUE)
? dtlb_flush_set
: dtlb_update_vaddr_csr_reg[`LM32_DTLB_IDX_RNG];
assign dtlb_data_write_address = dtlb_update_vaddr_csr_reg[`LM32_DTLB_IDX_RNG];

assign dtlb_data_read_port_enable = (stall_x == `FALSE) || !stall_m;
assign dtlb_write_port_enable = dtlb_updating || dtlb_flushing;
@@ -610,7 +590,7 @@ assign tmem_write_data[`LM32_DC_TAGS_VALID_RNG] = ((last_refill == `TRUE) || (va
assign tmem_write_data[`LM32_DC_TAGS_TAG_RNG] = refill_address[`LM32_DC_ADDR_TAG_RNG];

// Signals that indicate which state we are in
assign flushing = state[0]; //|| dtlb_miss;
assign flushing = state[0];
assign check = state[1];
assign refill = state[2];

@@ -683,8 +663,6 @@ begin
end
else if (dflush == `TRUE)
state <= `LM32_DC_STATE_FLUSH;
// else if (dtlb_miss == `TRUE)
// refill_address <= physical_address;
end

// Refill a cache line
@@ -718,35 +696,24 @@ begin
end
end

assign csr_read_data = latest_store_tlb_lookup;
assign csr_read_data = dtlb_miss_addr;

assign dtlb_miss = (kernel_mode_reg == `LM32_USER_MODE) && (load_q_m || store_q_m) && ~(dtlb_data_valid);

always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
dtlb_miss_int <= 0;
dtlb_miss_q <= `FALSE;
else
begin
if (dtlb_miss)
dtlb_miss_int <= 1;
else
dtlb_miss_int <= 0;
if (dtlb_miss && ~dtlb_miss_q)
dtlb_miss_q <= `TRUE;
else if (dtlb_miss_q && exception_m)
dtlb_miss_q <= `FALSE;
end
end

always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
dtlb_miss_q <= 0;
else
begin
if (dtlb_miss_int)
dtlb_miss_q <= 1;
else
dtlb_miss_q <= 0;
end
end
assign dtlb_miss_int = (dtlb_miss || dtlb_miss_q);

always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
@@ -768,10 +735,8 @@ begin
dtlb_flushing <= 0;
if (dtlb_miss == `TRUE)
begin
// dtlb_flushing <= 0;
// dtlb_flush_set <= address_m[addr_dtlb_index_width-1:0];
dtlb_miss_addr <= address_m;
$display("ERROR : DTLB MISS on addr 0x%08X at time %t", address_m, $time);
$display("WARNING : DTLB MISS on addr 0x%08X at time %t", address_m, $time);
end
if (csr_write_enable && csr_write_data[0])
begin
@@ -827,9 +792,9 @@ begin
kernel_mode_reg <= `LM32_KERNEL_MODE;
else
begin
if (/*exception_x || */switch_to_kernel_mode)
if (exception_x || switch_to_kernel_mode)
kernel_mode_reg <= `LM32_KERNEL_MODE;
else if (/*eret_q_x || */switch_to_user_mode)
else if (eret_q_x || switch_to_user_mode)
kernel_mode_reg <= `LM32_USER_MODE;
end
end
4 changes: 2 additions & 2 deletions cores/lm32/rtl/lm32_load_store_unit.v
Original file line number Diff line number Diff line change
@@ -429,15 +429,15 @@ lm32_dcache #(
.csr_write_enable (csr_write_enable),
.exception_x (exception_x),
.eret_q_x (eret_q_x),
.exception_m (exception_m),
// ----- Outputs -----
.stall_request (dcache_stall_request),
.restart_request (dcache_restart_request),
.refill_request (dcache_refill_request),
.refill_address (dcache_refill_address),
.refilling (dcache_refilling),
.load_data (dcache_data_m),
// .dtlb_miss (dtlb_miss),
.dtlb_miss_q (dtlb_miss),
.dtlb_miss_int (dtlb_miss),
.kernel_mode (kernel_mode),
.pa (physical_address),
.csr_read_data (csr_read_data)
196 changes: 57 additions & 139 deletions software/bios/dtlb_exception_handling_tests.c
Original file line number Diff line number Diff line change
@@ -1,160 +1,78 @@
#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
* Milkymist SoC (Software)
* Copyright (C) 2012 Yann Sionneau <yann.sionneau@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

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;
}
#include <hal/mmu.h>
#include <base/mmu.h>
#include <base/stdio.h>

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

for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
if (mappings[i].valid && vaddr == mappings[i].vaddr)
return mappings[i].paddr;
register unsigned int stack, addr;
unsigned int data;
int ret;

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

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;
}
ret = mmu_map(stack, stack);
check_for_error(ret);

static void panic(void) {
puts("PANIC !");
while(1)
asm volatile("nop");
}
ret = mmu_map(stack-0x1000, stack-0x1000);
check_for_error(ret);

static void check_for_error(int ret) {
if (ret)
return;
printf("stack == 0x%08X\n", stack);

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

if ( !ret ) {
puts("Unknown issue");
panic();
}
}
printf("\n=> Mapping 0x%08X to 0x%08X\n", addr, addr);
ret = mmu_map(addr, addr);
check_for_error(ret);

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

register unsigned int stack, addr, data;
int ret;
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);

asm volatile("mv %0, sp" : "=r"(stack) :: );
printf("=> Invalidating the mapping of virtual address 0x%08X in the TLB\n", addr);
mmu_dtlb_invalidate(addr);

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

ret = mmu_map(stack-0x1000, stack-0x1000);
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("stack == 0x%08X\n", stack);
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;

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);
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);

}
41 changes: 38 additions & 3 deletions software/bios/dtlb_miss_handler.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,43 @@
/*
* Milkymist SoC (Software)
* Copyright (C) 2012 Yann Sionneau <yann.sionneau@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

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

void dtlb_miss_handler(void)
{
unsigned int vaddr, paddr;

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

void dtlb_miss_handler(void) {
/*
* 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("[TLB miss handler] Unrecoverable page fault !");
panic();
}

disable_dtlb();
printf("TOTO");
printf("[TLB miss handler] Refilling DTLB with mapping 0x%08X->0x%08X\n", vaddr, paddr);
mmu_dtlb_map(vaddr, paddr);

}
29 changes: 29 additions & 0 deletions software/include/base/mmu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Milkymist SoC (Software)
* Copyright (C) 2012 Yann Sionneau <yann.sionneau@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#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);

#endif
20 changes: 20 additions & 0 deletions software/include/hal/mmu.h
Original file line number Diff line number Diff line change
@@ -15,6 +15,22 @@
* 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 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 +49,7 @@
} while(0);

void mmu_dtlb_map(unsigned int vpfn, unsigned int pfn);
unsigned int read_word_with_mmu_enabled(unsigned int vaddr);
void mmu_dtlb_invalidate(unsigned int vaddr);

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

OBJECTS_ALL=divsi3.o libc.o crc16.o crc32.o console.o blockdev.o fatfs.o system.o board.o uart.o
OBJECTS_ALL=divsi3.o libc.o crc16.o crc32.o console.o blockdev.o fatfs.o system.o board.o uart.o mmu.o
OBJECTS=$(OBJECTS_ALL) softfloat.o softfloat-glue.o vsnprintf.o atof.o malloc.o
OBJECTS_LIGHT=$(OBJECTS_ALL) vsnprintf-nofloat.o

116 changes: 116 additions & 0 deletions software/libbase/mmu.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Milkymist SoC (Software)
* Copyright (C) 2012 Yann Sionneau <yann.sionneau@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/* @vpfn : virtual page frame number
* @pfn : physical page frame number
*/

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

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

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();
}
}
30 changes: 30 additions & 0 deletions software/libhal/mmu.c
Original file line number Diff line number Diff line change
@@ -15,6 +15,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

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

/* @vpfn : virtual page frame number
* @pfn : physical page frame number
*/
@@ -42,3 +45,30 @@ inline void mmu_dtlb_invalidate(unsigned int vaddr)
"ori r11, r11, 0x21\n\t"
"wcsr tlbctrl, r11":::"r11");
}

/* 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;
}

0 comments on commit 790d654

Please sign in to comment.