riscv-probe

code
extern char _rodata_end;
extern char _data_start;
extern char _bss_end;
#define KB (0x1 << 10)
static uintptr_t uart_keys[] = {
        SIFIVE_UART0_CTRL_ADDR,
        NS16550A_UART0_CTRL_ADDR,
        RISCV_HTIF_BASE_ADDR,
        0
};

#ifdef __riscv
#include "arch/riscv/encoding.h"
#include "arch/riscv/machine.h"
#include "arch/riscv/csr.h"
#endif
unsigned char RO_Array[1 * KB] __attribute__((aligned(2 * KB)));
int main()
{
        uintptr_t uart = 0;
        uintptr_t *uart_k = uart_keys;
        const uintptr_t uartlen = 32;

        /* locate UART address using known configuration keys */
        while (*uart_k && !(uart = getauxval(*uart_k++)));

        /* locate ROM/Flash (text+rodata) and RAM (data+bss) */
        uintptr_t rx_s = (uintptr_t)&_text_start;
        uintptr_t rx_l = roundpow2((uintptr_t)(&_rodata_end - &_text_start));
        uintptr_t rw_s = (uintptr_t)&_data_start;
        uintptr_t rw_l = roundpow2((uintptr_t)(&_bss_end - &_data_start));

        uintptr_t rd_s = (uintptr_t)&RO_Array[0];
        uintptr_t rd_l = roundpow2((uintptr_t)((&RO_Array[0] + sizeof(RO_Array))));

        /* print our findings */
        printf("text: 0x%x - 0x%x\n", rx_s, rx_s + rx_l - 1);
        printf("data: 0x%x - 0x%x\n", rw_s, rw_s + rw_l - 1);
        if (uart) {
                printf("uart: 0x%x - 0x%x\n", uart, uart + uartlen - 1);
        }

    #ifdef __riscv

        pmp_info_t info = pmp_probe();
        if (info.count == 0) {
                puts("pmp-not-supported");
                return 0;
        } else {
                printf("pmp.count: %d\n", info.count);
                printf("pmp.width: %d\n", info.width);
                printf("pmp.granularity: %d\n", info.granularity);
        }
        /* set up physical memory protection */
        pmp_entry_set(0, PMP_R | PMP_X, rx_s, rx_l);
        pmp_entry_set(1, PMP_R | PMP_W, rw_s, rw_l);
        if (uart) {
                pmp_entry_set(2, PMP_R | PMP_W, uart, uartlen);
        }
        pmp_entry_set(3, PMP_R , rd_s,rd_l);
        RO_Array[0]=1;
        printf("p.count: %d\n",  RO_Array[0]);

        /* switch to user mode enclave */
        mode_set_and_continue(PRV_U);
        puts("riscv-enclave");
        RO_Array[0]=2;

        printf("p.count: %d\n",  RO_Array[0]);
#else
        RO_Array[0]=2;
        printf("p.count: %d\n",  RO_Array[0]);
        puts("architecture-not-supported");
#endif
}
code
$ spike --isa=RV32IMAFDC build/bin/rv32imac/spike/probe
$ spike --isa=RV64IMAFDC build/bin/rv64imac/spike/probe
$ qemu-system-riscv32 -nographic -machine spike -kernel build/bin/rv32imac/spike/probe -bios none
$ qemu-system-riscv64 -nographic -machine spike -kernel build/bin/rv64imac/spike/probe -bios none
$ qemu-system-riscv32 -nographic -machine virt -kernel build/bin/rv32imac/virt/probe -bios none
$ qemu-system-riscv64 -nographic -machine virt -kernel build/bin/rv64imac/virt/probe -bios none
$ qemu-system-riscv32 -nographic -machine sifive_e -kernel build/bin/rv32imac/qemu-sifive_e/probe -bios none
$ qemu-system-riscv64 -nographic -machine sifive_e -kernel build/bin/rv64imac/qemu-sifive_e/probe -bios none
$ qemu-system-riscv32 -nographic -machine sifive_u -kernel build/bin/rv32imac/qemu-sifive_u/probe -bios none
$ qemu-system-riscv64 -nographic -machine sifive_u -kernel build/bin/rv64imac/qemu-sifive_u/probe -bios none

https://github.com/michaeljclark/riscv-probe 這邊改了一些小地方,增加對RO_Array的保護,補充一下,mini-riscv-os 為什麼qemu 5.x用的好好的到了qemu 6,7 都會出現卡死的情況

因為qemu 6,7預設都要對pmpcfg0進行初始化才行

code
    li      t0, 0x0                     #pmp config
    csrw    pmpaddr0, t0
    li      t0, 0xf
    csrw    pmpcfg0, t0
    csrw satp, zero

再來的話,還在排除有可能因為qemu的版本導致我沒辦法設置pmp的value達成記憶體保護, 參考riscv-probe其實可以發現qemu 可以指定 machine type 或許換成相同machine 就可以pmp了

code
#include "os.h"
extern void trap_init(void);
extern void trap_init(void);
extern void kernelvec();
extern void trap_vector();
extern int gethid();
extern int rko;
extern int taskTop;
extern int current_task;
extern struct context ctx_tasks[MAX_TASK];
extern void task_flush(int i, struct context *ctx_old, struct context *ctx_new);
extern void task_flush2();
void start();
extern int prev_task;
int init_main(void);
uint32_t sepc2 = 0;
struct context ctx_tmp;
void os_kernel()
{
    task_os();
}
#define EILM_SIZE 0x40000
/* Check platform support which PMP scheme!
 * CLIC platform only support NAPOT scheme! */
#define USE_NAPOT 1
#define USE_TOR !(USE_NAPOT)
#define SCHEME_NAPOT 3
#define SCHEME_NA4 2
#define SCHEME_TOR 1
#define SCHEME_OFF 0
#define NAPOT(base, size) (unsigned long)(((size) > 0) ? ((((unsigned long)(base) & (~((unsigned long)(size)-1))) >> 2) | (((unsigned long)(size)-1) >> 3)) : 0)
#define PMP_L_OFF 0
#define PMP_L_ON 1
#define PMP_A_OFF 0
#define PMP_A_TOR SCHEME_TOR
#define PMP_A_NA4 SCHEME_NA4
#define PMP_A_NAPOT SCHEME_NAPOT
#define PMP_X_OFF 0
#define PMP_X_ON 1
#define PMP_W_OFF 0
#define PMP_W_ON 1
#define PMP_R_OFF 0
#define PMP_R_ON 1
#define KB (0x1 << 10)
#define read_csr(reg) ({ unsigned int __tmp; \
  asm volatile ("csrr %0, " #reg : "=r"(__tmp)); __tmp; })
volatile unsigned int g_testmodify = 0;
unsigned char RO_Array[1 * KB] __attribute__((aligned(2 * KB)));
#define write_csr(reg, val) ({ asm volatile("csrw " #reg ", %0" ::"rK"(val)); })
void tmp()
{
}
#define TOR(top) (uint32_t)((uint32_t)(top) >> 2)
void pmp_napot_config(char entry, void *va, unsigned long size, char pmpcfg)
{
#pragma optimize("", off);
    unsigned long size2 = (unsigned long)((((unsigned long)(va) & (~((unsigned long)(size)-1))) >> 2) | (((unsigned long)(size)-1) >> 3));
#pragma optimize("", on);
    // printf("%ld\n",va);
    // printf("%ld\n",size);
    // printf("%ld\n",size2);
    switch (entry)
    {
    case 0:
        //      unsigned long tmp = (unsigned long)((((unsigned long)(va) & (~((unsigned long)(size) - 1))) >> 2) | (((unsigned long)(size) - 1) >> 3) );
        write_csr(pmpaddr0, size2);
        break;
    case 1:
        write_csr(pmpaddr1, size2);
        break;
    case 2:
        write_csr(pmpaddr2, size2);
        break;
    case 3:
        write_csr(pmpaddr3, size2);
        break;
    case 4:
        write_csr(pmpaddr4, size2);
        break;
    case 5:
        write_csr(pmpaddr5, size2);
        break;
    case 6:
        write_csr(pmpaddr6, size2);
        break;
    case 7:
        write_csr(pmpaddr7, size2);
        break;
    case 8:
        write_csr(pmpaddr8, size2);
        break;
    case 9:
        write_csr(pmpaddr9, size2);
        break;
    case 10:
        write_csr(pmpaddr10, size2);
        break;
    case 11:
        write_csr(pmpaddr11, size2);
        break;
    case 12:
        write_csr(pmpaddr12, size2);
        break;
    case 13:
        write_csr(pmpaddr13, size2);
        break;
    case 14:
        write_csr(pmpaddr14, size2);
        break;
    case 15:
        write_csr(pmpaddr15, size2);
        break;
    }

#if __riscv_xlen == 64
    switch (entry >> 3)
    {
    case 0:
        write_csr(pmpcfg0, ((read_csr(pmpcfg0) & (~(0xFFLL << ((long)(entry % 8) << 3)))) | (((long)pmpcfg) << ((long)(entry % 8) << 3))));
        break;
    case 1:
        write_csr(pmpcfg2, ((read_csr(pmpcfg2) & (~(0xFFLL << ((long)(entry % 8) << 3)))) | (((long)pmpcfg) << ((long)(entry % 8) << 3))));
        break;
    }
#else
    switch (entry >> 2)
    {
    case 0:
        write_csr(pmpcfg0, ((read_csr(pmpcfg0) & (~((0xFF) << ((entry % 4) << 3)))) | (((long)pmpcfg) << ((entry % 4) << 3))));
        break;
    case 1:
        write_csr(pmpcfg1, ((read_csr(pmpcfg1) & (~((0xFF) << ((entry % 4) << 3)))) | (((long)pmpcfg) << ((entry % 4) << 3))));
        break;
    case 2:
        write_csr(pmpcfg2, ((read_csr(pmpcfg2) & (~((0xFF) << ((entry % 4) << 3)))) | (((long)pmpcfg) << ((entry % 4) << 3))));
        break;
    case 3:
        write_csr(pmpcfg3, ((read_csr(pmpcfg3) & (~((0xFF) << ((entry % 4) << 3)))) | (((long)pmpcfg) << ((entry % 4) << 3))));
        break;
    }
#endif
}

void do_syscall(int syscall_num, int syscall_value)
{
    switch (syscall_num)
    {
    case 1:
        lib_printf("hello%d\n", syscall_value);
        ctx_tasks[current_task].a0 = syscall_value + 2;
        break;
    case 2:
        break;
    }
}
// interrupts and exceptions from kernel code go here via kernelvec,
// on whatever the current kernel stack is.
reg_t kerneltrap(reg_t epc, reg_t cause)
{
    intr_off();
    int which_dev = 0;
    uint32_t sepc = r_sepc();

    uint32_t sstatus = r_sstatus();
    uint32_t scause = r_scause();
    reg_t return_pc = sepc;
    reg_t cause_code = scause & 0xfff;
    // if(sepc2==0)
    // sepc2=r_sepc();
    // else
    //  w_sepc(0x80008038);
    // sepc2=
    // w_sie(r_sie() & ~SIE_SSIE);
    if ((sstatus & SSTATUS_SPP) == 0)
        lib_puts("kerneltrap: not from supervisor mode\n");
    if (intr_get() != 0)
        lib_puts("kerneltrap: interrupts enabled\n");
    // lib_printf("%x\n", r_sepc());
    // lib_printf("%x\n", scause);
    lib_printf("%x\n", cause_code);
    if (cause & 0x80000000)
    {
        // lib_printf("spec %x\n", r_sepc());
        // lib_printf("%x\n", scause);
        // lib_printf("%x\n", cause_code);
        /* Asynchronous trap - interrupt */
        switch (cause_code)
        {
        case 1:
            lib_puts("Supervisor software interrupt!\n");
            // return_pc += 4;
            break;
        case 3:
            lib_puts("software interruption!\n");
            break;
        case 7:
            lib_puts("timer interruption!\n");
            // disable machine-mode timer interrupts.
            w_mie(~((~r_mie()) | (1 << 7)));
            timer_handler();
            return_pc = (reg_t)&os_kernel;
            // enable machine-mode timer interrupts.
            w_mie(r_mie() | MIE_MTIE);
            break;
        case 8:
            lib_puts("user extern interruption!\n");
            // sepc += 4;
            return_pc += 4;
            // w_sepc(sepc+4);
            // w_mepc(sepc+8);
            break;
        case 11:
            lib_puts("external interruption!\n");
            break;
        default:
            lib_puts("unknown async exception!\n");
            break;
        }
    }
    else
    {

        /* Synchronous trap - exception */
        // lib_puts("Sync exceptions2!\n");
        // lib_printf("%x\n", scause);
        // lib_printf("%x\n", cause_code);
        switch (cause_code)
        {
        case 2:
            lib_puts("Illegal instruction!\n");
            return_pc += 4;
            break;
        case 8:
            lib_puts("Environment call from U-mode!\n");
            // intr_off();
            // do_syscall(ctx);
            // task_syscall(current_task);
            // task_os();
            struct context *ctx_now;
            ctx_now = &ctx_tasks[current_task];

            sys_switch(&ctx_now[current_task], &ctx_now[current_task]);

            lib_printf("%d\n", current_task);
            lib_printf("%d\n", ctx_now[current_task].s11);
            do_syscall(ctx_now[current_task].a7, ctx_now[current_task].s11);

            lib_printf("%d\n", ctx_tasks[current_task].a0);
            // task_flush2();
            return_pc += 4;
            // intr_on();
            break;
        case 9:
            lib_puts("Environment call from S-mode!\n");
            // suinter();
            return_pc += 4;

            break;

        default:
            /* Synchronous trap - exception */
            lib_printf("Sync exceptions! cause code: %d\n", cause_code);
            break;
        }
        // w_sepc(suinter);
        // w_mtvec((reg_t)trap_vector);
        //   w_mepc((uint64)main);
        // enable sup-mode interrupts.
        // w_sepc(init_main);
        // asm volatile("sret");
        // return_pc += 4;

        // while (1)
        // {
        //  // break;
        //  /* code */
        // }
    }

    unsigned long x2 = r_sstatus();
    // x2 &= ~SSTATUS_SIE;
    x2 &= ~SSTATUS_SPP; // clear SPP to 0 for user mode
    x2 |= SSTATUS_SPIE; // enable interrupts in user mode
    w_sstatus(x2);
    intr_on();
    return return_pc;
}
/* attribute is used for PA */
#define PMPCFG_ALXWR(a, l, x, w, r) (((a) << 3) | ((l) << 7) | ((x) << 2) | ((w) << 1) | ((r) << 0))
#define MSTATUS_MPRV_MASK (1 << 17) // previous mode.
void supmod()
{
    lib_puts("sup mod\n");
    // w_mip(r_mip() | MIP_MSIP);
    // w_mip(r_mip() | MIP_MSIP2);
    // w_mie(r_mie() | MIE_MSIE);
    uint32_t x = r_mstatus();
    x &= ~MSTATUS_MPP_MASK;
    // x | MSTATUS_MPRV_MASK;
    x |= MSTATUS_MPP_U;
    w_mstatus(x);

    w_medeleg(0xffff);
    w_mideleg(0xffff);
    w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE | SIE_SEIE2 | SIE_STIE2 | SIE_SSIE2);
    //  w_sie(r_sie() & SIE_SEIE2);
    // set the sup-mode trap handler.
    w_stvec((reg_t)kernelvec);

    //   w_mepc((uint64)main);
    // enable sup-mode interrupts.
    // w_sepc(init_main);

    // set S Previous Privilege mode to User.
    // set S Previous Privilege mode to User.
    // unsigned long x2 = r_sstatus();
    // // x2 |= SSTATUS_SIE;
    // x2 &= ~SSTATUS_SPP; // clear SPP to 0 for user mode
    // x2 |= SSTATUS_SPIE; // enable interrupts in user mode
    // w_sstatus(x2);
    // asm volatile("ecall");

    // asm volatile("sret");
    // asm volatile("ecall");
    // suinter();
}
#define U32 *(volatile uint32_t *)
// static inline void w_pmpcfg(reg_t x)
// {
//   asm volatile("csrw pmpcfg1, 0xf");

// }

void pmpconfig()
{
    extern char _start;
    extern char __data_start;
    extern char stacks;
    // write_csr(pmpcfg0, 0x);
    // w_pmpcfg(0xf);
    // if (!read_csr(pmpcfg0)) {
    //  lib_printf("PMP entries is 0, CPU does NOT support PMP.\n");
    //  while(1);
    // }else
    //  lib_printf("support PMP.\n");
    // lib_printf("support PMP. %x\n" ,&RO_Array[0]);
    // lib_printf("support PMP. %x\n" ,(&RO_Array[0] + sizeof(RO_Array)));


    /* PMP addresses are 4-byte aligned, drop the bottom two bits */
    size_t protected_addr = ((size_t) &RO_Array[0]) ;

    /* Clear the bit corresponding with alignment */
    // protected_addr &= ~(NAPOT_SIZE >> 3);

    /* Set the bits up to the alignment bit */
    // protected_addr |= ((NAPOT_SIZE >> 3) - 1);

    write_csr(pmpaddr0, TOR( (void*)&RO_Array[0]));
    write_csr(pmpaddr1, TOR((void *)&RO_Array[0])+1);
    write_csr(pmpaddr2, TOR((void *)(&RO_Array[0] + sizeof(RO_Array))));
    lib_printf("support PMP. %x\n", read_csr(pmpaddr1));
    lib_printf("support PMP. %x\n", read_csr(pmpaddr2));
    write_csr(pmpcfg0, 0x00880F0F);
        // write_csr(pmpcfg0, 0x0008ffff&read_csr(pmpcfg0));

    lib_printf("support PMP. %x\n", read_csr(pmpcfg0));
    // write_csr(pmpcfg1, PMPCFG_ALXWR(PMP_A_TOR, PMP_L_OFF, PMP_X_OFF, PMP_W_ON, PMP_R_ON));
    // write_csr(pmpcfg2, PMPCFG_ALXWR(PMP_A_TOR, PMP_L_ON, PMP_X_OFF, PMP_W_OFF, PMP_R_ON));

    lib_puts("OS start\n");
}
// #define KERNBASE 0x80101000
void os_start()
{
    lib_puts("OS start\n");
    user_init();
    trap_init();
    timer_init(); // start timer interrupt ...
    supmod();
    // pmpconfig();

    // lib_printf("kernel stap. %x\n",  (KERNBASE >> 12));
    (*((unsigned long *)((long)&RO_Array[0]))) = 0x5555AAAA;
    g_testmodify = 0x5555AAAA;
    if (0x5555AAAA == (*((unsigned long *)((long)&RO_Array[0]))))
    {
        lib_printf("[Store Pass]\n");
        // printf("[Store Pass]\n");
    }
    else
    {
        lib_printf("[Store Fail]\n");
    }
    asm volatile("li   a1,1");
    asm volatile("csrw sip, a1");

    w_mepc((reg_t)start);
    asm volatile("mret");
    //  li   a1,1
    // csrw sip, a1
}

int os_main(void)
{
    os_start();

    return 0;
}
void start()
{

    (*((unsigned long *)((long)&RO_Array[0]))) = 0x5555AAA2;
    g_testmodify = 0x5555AAAA;
    if (0x5555AAA2 == (*((unsigned long *)((long)&RO_Array[0]))))
    {
        lib_printf("[Store Pass]\n");
        // printf("[Store Pass]\n");
    }
    else
    {
        lib_printf("[Store Fail]\n");
    }
    // (*((unsigned long*)((long)&RO_Array[0]))) = 0x5555AAAA;
    // while(1){}
    int current_task = 0;
    while (1)
    {
        lib_puts("OS: Activate next task\n");
        task_go(current_task);
        lib_puts("OS: Back to OS\n");
        current_task = (current_task + 1) % taskTop; // Round Robin Scheduling
        lib_puts("\n");
    }
}

這邊查看蠻多次確定沒什麼問題,可能一些小細節沒注意到 或許是qemu -machine virt 換成spike 就ok ,這可能要找時間再試了近期不會再更新.