Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sv39 #5

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
build/*
*~
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,18 @@ Please see https://github.com/franzflasch/linux_for_riscv_em
```sh
./build/riscv_em -f <linux_for_riscv_em-path>/output_mmu_rv32/opensbi/build/platform/generic/firmware/fw_payload.bin -d dts/riscv_em32_linux.dtb
```

### RAM disk

Make a filesystem image using the normal filesystem tools (e.g.
mkfs.ext3, mksquashfs etc) with a maximum size of 200Mb. Then run

```sh
./build/riscv_em -f <linux_for_riscv_em-path>/output/linux/loader_64.bin -d dts/riscv_em.dtb -i mydiskimage.ext3
```

The filesystem will be available as `/dev/pmem0`, which can be either
mounted from userspace, or specified as the root filesystem. Note that
this does not use the initrd or initramdisk functionality, as that has
severe size limitations (tries to unpack/copy the whole filesystem at
boot).
Binary file added dts/riscv_em.dtb
Binary file not shown.
12 changes: 9 additions & 3 deletions dts/riscv_em.dts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
model = "riscv-virtio,qemu";

chosen {
bootargs = "root=/dev/vda ro console=ttyS0";
bootargs = "root=/dev/vda ro console=ttyS0 earlycon=simple_uart";
stdout-path = "/uart@10000000";
};

Expand All @@ -31,9 +31,14 @@

sram: memory@80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x8000000>;
reg = <0x0 0x80000000 0x0 0x40000000>;
};


rom: memory@c0000000 {
compatible = "pmem-region";
reg = <0x0 0xc0000000 0x0 0xc800000>;
};

soc {
#address-cells = <2>;
#size-cells = <2>;
Expand Down Expand Up @@ -74,4 +79,5 @@
compatible = "simple-uart";
};
};

};
Binary file added dts/riscv_em32_linux.dtb
Binary file not shown.
6 changes: 3 additions & 3 deletions src/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1843,11 +1843,11 @@ void rv_core_reg_dump(rv_core_td *rv_core)

int i = 0;

DEBUG_PRINT("pc: " PRINTF_FMT "\n", rv_core->pc);
DEBUG_PRINT("instr: %08x\n", rv_core->instruction);
printf/*DEBUG_PRINT*/("pc: " PRINTF_FMT "\n", rv_core->pc);
printf/*DEBUG_PRINT*/("instr: %08x\n", rv_core->instruction);
for(i=0;i<NR_RVI_REGS;i++)
{
DEBUG_PRINT("x[%2d]: " PRINTF_FMT "\n", i, rv_core->x[i]);
printf/*DEBUG_PRINT*/("x[%2d]: " PRINTF_FMT "\n", i, rv_core->x[i]);
}
}

Expand Down
205 changes: 177 additions & 28 deletions src/core/mmu/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <mmu.h>
#include <riscv_helper.h>

// #define MMU_DEBUG_ENABLE
#define MMU_DEBUG_ENABLE
#ifdef MMU_DEBUG_ENABLE
#define MMU_DEBUG(...) do{ printf( __VA_ARGS__ ); } while( 0 )
#else
Expand All @@ -17,6 +17,8 @@
/* simple macro to tranlsate this to the mmu arrangement */
#define ACCESS_TYPE_TO_MMU(access_type) ((1 << access_type) << 1)

void dump_pagetables(mmu_td *mmu, privilege_level curr_priv);

rv_ret mmu_read_csr(void *priv, privilege_level curr_priv_mode, uint16_t reg_index, rv_uint_xlen *out_val)
{
(void)curr_priv_mode;
Expand Down Expand Up @@ -185,6 +187,7 @@ uint64_t mmu_virt_to_phys(mmu_td *mmu,
#endif

#if 1
#define MAX_LEVELS 4
uint64_t mmu_virt_to_phys(mmu_td *mmu,
privilege_level curr_priv,
rv_uint_xlen virt_addr,
Expand All @@ -208,33 +211,57 @@ uint64_t mmu_virt_to_phys(mmu_td *mmu,
*ret_val = mmu_ok;
uint8_t mode = extractxlen(mmu->satp_reg, MMU_SATP_MODE_BIT, MMU_SATP_MODE_NR_BITS);

// MMU_DEBUG("priv=%i, mode=%i: %lx\n", curr_priv, mode, virt_addr);

/* in machine mode we don't have address translation */
if( (curr_priv == machine_mode) || !mode )
{
if (!mode || !(virt_addr & 0xffffffff00000000)) {
MMU_DEBUG("=> machine mode\n");
return virt_addr;
}
}
MMU_DEBUG("!mode = %d, !(virt_addr & 0xffffffff00000000) = %d\n", !mode, !(virt_addr & 0xffffffff00000000));

rv_uint_xlen vpn[MAX_LEVELS] = {0};
uint8_t levels = 0;
uint16_t page_size = 0;
uint16_t pte_size = 0;
uint8_t bits_per_level = 0;
if (mode == supervisor_mode) {
vpn[0] = (virt_addr >> 12) & 0x3ff;
vpn[1] = (virt_addr >> 22) & 0x3ff;
levels = SV32_LEVELS;
page_size = SV32_PAGE_SIZE;
pte_size = SV32_PTESIZE;
bits_per_level = 10;
} else if (mode == supervisor_39_mode) {
vpn[0] = (virt_addr >> 12) & 0x1ff;
vpn[1] = (virt_addr >> 21) & 0x1ff;
vpn[2] = (virt_addr >> 30) & 0x1ff;
levels = SV39_LEVELS;
page_size = SV39_PAGE_SIZE;
pte_size = SV39_PTESIZE;
bits_per_level = 9;
}

rv_uint_xlen vpn[SV32_LEVELS] =
{
(virt_addr >> 12) & 0x3ff,
(virt_addr >> 22) & 0x3ff
};
// MMU_DEBUG("vpn[1] "PRINTF_FMT"\n", vpn[1]);
// MMU_DEBUG("vpn[0] "PRINTF_FMT"\n", vpn[0]);
MMU_DEBUG("vpn[2] "PRINTF_FMT"\n", vpn[2]);
MMU_DEBUG("vpn[1] "PRINTF_FMT"\n", vpn[1]);
MMU_DEBUG("vpn[0] "PRINTF_FMT"\n", vpn[0]);

/*
* 1. Let a be satp.ppn × PAGESIZE, and let i = LEVELS − 1. (For Sv32, PAGESIZE=2^12 and LEVELS=2.)
*/
a = (mmu->satp_reg & 0x3FFFFF) * SV32_PAGE_SIZE;
MMU_DEBUG("satp: %x\n", mmu->satp_reg);
a = (mmu->satp_reg & 0x3FFFFF) * page_size;
MMU_DEBUG("satp: %lx\n", mmu->satp_reg);

for(i=(SV32_LEVELS-1),j=0;i>=0;i--,j++)
for(i=(levels-1),j=0;i>=0;i--,j++)
{
/*
* 2. Let pte be the value of the PTE at address a+va.vpn[i]×PTESIZE. (For Sv32, PTESIZE=4.)
* If accessing pte violates a PMA or PMP check, raise an access exception.
*/
pte_addr = a + (vpn[i] * SV32_PTESIZE);
pte_addr = a + (vpn[i] * pte_size);
MMU_DEBUG("address a: " PRINTF_FMT " pte_addr: "PRINTF_FMT"\n", a, pte_addr);

/* Here we should raise an exception if PMP violation occurs, will be done automatically
Expand Down Expand Up @@ -265,7 +292,7 @@ uint64_t mmu_virt_to_phys(mmu_td *mmu,
break;
}

a = (pte >> 10) * SV32_PAGE_SIZE;
a = (pte >> bits_per_level) * page_size;
}

if(i<0)
Expand All @@ -289,7 +316,10 @@ uint64_t mmu_virt_to_phys(mmu_td *mmu,
}

/* Supervisor only has access to user pages if SUM = 1 */
if( (curr_priv == supervisor_mode) && user_page && !sum )
if( ( curr_priv == supervisor_mode
|| curr_priv == supervisor_39_mode)
&& user_page
&& !sum )
{
MMU_DEBUG("page fault: supervisor access to user page!\n");
goto exit_page_fault;
Expand All @@ -305,23 +335,33 @@ uint64_t mmu_virt_to_phys(mmu_td *mmu,
goto exit_page_fault;
}

pte = pte << SV32_PTESHIFT;
/* physical addresses are 34 Bit wide!!! even on RV32 systems */
rv_uint_xlen ppn[SV32_LEVELS] =
{
(pte >> 12) & 0x3ff,
(pte >> 22) & 0xfff
rv_uint_xlen ppn[MAX_LEVELS] = {0};
if (mode == supervisor_mode) {
pte = pte << SV32_PTESHIFT;
ppn[0] = (pte >> 12) & 0x3ff; // 10 bits
ppn[1] = (pte >> 22) & 0xfff; // What's going on here? Should be 10 bits here too, to make up 20 bits total (10 to 30).
} else if (mode == supervisor_39_mode) {
pte = pte << SV39_PTESHIFT;
ppn[0] = (pte >> 12) & 0x1ff; // 9 bits
ppn[1] = (pte >> 21) & 0x1ff; // 9 bits
ppn[2] = (pte >> 30) & 0x1ff; // 9 bits
};
// MMU_DEBUG("ppn[1]: %x\n", ppn[1]);
// MMU_DEBUG("ppn[0]: %x\n", ppn[0]);
MMU_DEBUG("ppn[2]: %lx\n", ppn[2]);
MMU_DEBUG("ppn[1]: %lx\n", ppn[1]);
MMU_DEBUG("ppn[0]: %lx\n", ppn[0]);

/* physical addresses are at least 34 Bits wide, so we need uint64_t here */
uint64_t phys_addr_translation[SV32_LEVELS] =
{
(ppn[1] << 22) | (ppn[0] << 12) | (virt_addr & 0xfff),
(ppn[1] << 22) | (virt_addr & 0x3fffff)
};

uint64_t phys_addr_translation[MAX_LEVELS];
if (mode == supervisor_mode) {
phys_addr_translation[0] = (ppn[1] << 22) | (ppn[0] << 12) | (virt_addr & 0xfff),
phys_addr_translation[1] = (ppn[1] << 22) | (virt_addr & 0x3fffff);
} else if (mode == supervisor_39_mode) {
phys_addr_translation[0] = (ppn[2] << 30) | (ppn[1] << 21) | (ppn[0] << 12) | (virt_addr & 0xfff);
phys_addr_translation[1] = (ppn[2] << 30) | (ppn[1] << 21) | (virt_addr & 0x1fffff);
phys_addr_translation[1] = (ppn[2] << 30) | (virt_addr & 0x3fffffff);
}

/*
* 6. If i > 0 and pa.ppn[i − 1 : 0] != 0, this is a misaligned superpage; stop and raise a page-fault exception.
*/
Expand Down Expand Up @@ -360,10 +400,119 @@ uint64_t mmu_virt_to_phys(mmu_td *mmu,
return phys_addr_translation[i];

exit_page_fault:
// printf("page fault!!!\n");
printf("page fault!!!\n");
dump_pagetables(mmu, curr_priv);
*ret_val = mmu_page_fault;
return 0;
}

void dump_pagetables_subtree(mmu_td *mmu,
privilege_level curr_priv,
rv_uint_xlen table,
int level,
uint8_t mode,
uint8_t levels,
uint16_t page_size,
uint16_t pte_size,
uint8_t bits_per_level
) {
int i, addr;
rv_uint_xlen pte;
rv_uint_xlen ppn[MAX_LEVELS] = {0};
// int res;

for (i = 0; i < level; i++) { printf(" "); } printf("%lx BEGIN\n", table);

// printf("(1<<(bits_per_level=%x-1))-1 = %lx\n", bits_per_level, (((rv_uint_xlen)1) << bits_per_level) - 1);
for(addr=0;addr < (1<<bits_per_level)-1;addr++)
{
//res =
mmu->bus_access(mmu->priv, curr_priv, bus_read_access, table + (addr * pte_size), &pte, sizeof(rv_uint_xlen));
// printf(" %x @ %lx: %i / %lx\n", addr, table + (addr * pte_size), res, pte);

if( (!(pte & MMU_PAGE_VALID)) || ((!(pte & MMU_PAGE_READ)) && (pte & MMU_PAGE_WRITE)) ) continue;

if (mode == supervisor_mode) {
pte = pte << SV32_PTESHIFT;
ppn[0] = (pte >> 12) & 0x3ff; // 10 bits
ppn[1] = (pte >> 22) & 0xfff; // What's going on here? Should be 10 bits here too, to make up 20 bits total (10 to 30).
} else if (mode == supervisor_39_mode) {
pte = pte << SV39_PTESHIFT;
ppn[0] = (pte >> 12) & 0x1ff; // 9 bits
ppn[1] = (pte >> 21) & 0x1ff; // 9 bits
ppn[2] = (pte >> 30) & 0x1ff; // 9 bits
};
uint64_t phys_addr_translation[MAX_LEVELS] = { 0 };
if (mode == supervisor_mode) {
phys_addr_translation[0] = (ppn[1] << 22) | (ppn[0] << 12);
phys_addr_translation[1] = (ppn[1] << 22);
} else if (mode == supervisor_39_mode) {
phys_addr_translation[0] = (ppn[2] << 30) | (ppn[1] << 21) | (ppn[0] << 12);
phys_addr_translation[1] = (ppn[2] << 30) | (ppn[1] << 21);
phys_addr_translation[2] = (ppn[2] << 30);
}

for (i = 0; i < level + 1; i++) { printf(" "); }
if (level + 1 >= levels) {
printf("%x: %lx LEAF\n", addr, phys_addr_translation[level]);
} else if(pte & 0xA) {
printf("%x: %lx SUPERPAGE\n", addr, phys_addr_translation[level]);
} else {
printf("%x: %lx\n", addr, (pte >> bits_per_level) * page_size);
dump_pagetables_subtree(mmu,
curr_priv,
phys_addr_translation[0], //(pte >> bits_per_level) * page_size,
level+2,
mode,
levels,
page_size,
pte_size,
bits_per_level
);
}
}
for (i = 0; i < level; i++) { printf(" "); } printf("%lx END\n", table);
}

void dump_pagetables(mmu_td *mmu,
privilege_level curr_priv
) {
uint8_t mode = extractxlen(mmu->satp_reg, MMU_SATP_MODE_BIT, MMU_SATP_MODE_NR_BITS);
uint8_t levels = 0;
uint16_t page_size = 0;
uint16_t pte_size = 0;
uint8_t bits_per_level = 0;
if (mode == supervisor_mode) {
levels = SV32_LEVELS;
page_size = SV32_PAGE_SIZE;
pte_size = SV32_PTESIZE;
bits_per_level = 10;
} else if (mode == supervisor_39_mode) {
levels = SV39_LEVELS;
page_size = SV39_PAGE_SIZE;
pte_size = SV39_PTESIZE;
bits_per_level = 9;
}
printf("curr_priv: %x\nmode: %x\nlevels: %x\npage_size: %x\npte_size: %x\nbits_per_level: %x\n",
curr_priv,
mode,
levels,
page_size,
pte_size,
bits_per_level
);
dump_pagetables_subtree(mmu,
curr_priv,
(mmu->satp_reg & ((((rv_uint_xlen) 1)<<44) - 1)) * page_size,
0,
mode,
levels,
page_size,
pte_size,
bits_per_level
);
}

#endif

void mmu_dump(mmu_td *mmu)
Expand Down
7 changes: 7 additions & 0 deletions src/core/mmu/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
#define SV32_PTESIZE 4
#define SV32_PTESHIFT 2

#define SV39_LEVELS 3
#define SV39_PAGE_SIZE 4096
#define SV39_PAGE_TABLE_ENTRIES 512
#define SV39_PTESIZE 8
#define SV39_PTESHIFT 2


#ifdef RV64
#define MMU_SATP_MODE_BIT 60
#define MMU_SATP_MODE_NR_BITS 4
Expand Down
9 changes: 7 additions & 2 deletions src/core/riscv_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
#define MROM_BASE_ADDR 0x1000UL
#define MROM_SIZE_BYTES 0xf000UL

#define RAM_BASE_ADDR 0x80000000UL
#define RAM_SIZE_BYTES 0x8000000UL /* 128MB such as the default for the qemu virt machine */
// #define RAM_BASE_ADDR 0x80000000UL
// #define RAM_SIZE_BYTES 0x8000000UL /* 128MB such as the default for the qemu virt machine */
#define RAM_BASE_ADDR 0x80000000UL
#define RAM_SIZE_BYTES 0x40000000UL

#define CLINT_BASE_ADDR 0x2000000UL
#define CLINT_SIZE_BYTES 0x10000UL
Expand All @@ -30,4 +32,7 @@
RV_EXTENSION_TO_MISA('S') | \
RV_EXTENSION_TO_MISA('U') )

#define FROM_BASE_ADDR 0xc0000000UL
#define FROM_SIZE_BYTES 0xc800000UL

#endif /* RISCV_CONFIG_H */
1 change: 1 addition & 0 deletions src/core/riscv_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ typedef enum
supervisor_mode = 1,
reserved_mode = 2, /* Hypervisor ?? */
machine_mode = 3,
supervisor_39_mode = 8,
priv_level_max = 4

} privilege_level;
Expand Down
Loading