zoukankan      html  css  js  c++  java
  • Illegal instruction mret mret指令返回异常

    lesson7 

    qemu-system-riscv64 --version
    QEMU emulator version 6.1.0
    Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers

    执行mret  抛异常 Illegal instruction

    qemu-system-riscv64 -machine virt -bios none -kernel kernelimage -m 128M -smp 1 -nographic
    start 58.
    Exception : Illegal instruction.
    tval = 0x0000000000000000
    mepc = 0x00000000800000f2
    static void machine_switchto_supervisor(void)
    {
        // set M Previous Privilege mode to Supervisor, for mret.
        unsigned long x = mstatus_get();
        x &= ~MSTATUS_MPP_MASK;x |= MSTATUS_MPP_S;
        mstatus_set(x);
    
        // set M Exception Program Counter to main, for mret.
        // requires gcc -mcmodel=medany
        mepc_set((unsigned long)main);
    
        // disable paging for now.
        satp_set(0);
    
        // delegate interrupts and exceptions to supervisor mode.
        medeleg_set(0xb109);
        mideleg_set(0x222);
    
        printf("%s %d.\r\n", __func__, __LINE__);
        // switch to supervisor mode and jump to main().
        asm volatile("mret");  //抛异常
    }

    改成

    static void machine_switchto_supervisor(void)
    {
        // set M Previous Privilege mode to Supervisor, for mret.
        unsigned long x = mstatus_get();
        x &= ~MSTATUS_MPP_MASK;
        x |= MSTATUS_MPP_M;
     
        mstatus_set(x);
    
        // set M Exception Program Counter to main, for mret.
        // requires gcc -mcmodel=medany
        mepc_set((unsigned long)main);
    
        // disable paging for now.
        satp_set(0);
    
        // delegate interrupts and exceptions to supervisor mode.
        medeleg_set(0xb109);
        mideleg_set(0x222);
    
        printf("%s %d.\r\n", __func__, __LINE__);
        // switch to supervisor mode and jump to main().
        asm volatile("mret");
    }

    The issue turned out to be RISC-V's Physical Memory Protection (PMP). QEMU will raise an illegal instruction exception when executing an MRET instruction if no PMP rules have been defined. Adding a PMP entry resolved the issue.

    在硬件设计里,PMP (Phsical Memory Protection) 是可选项,但在大部分地方我们都可以见到它的身影。PMP 检查一般用于 hart 在监管者模式或用户模式下的所有访问;或者在 mstatus.MPRV = 1 时的 load 和 store 等情况。一旦触发 PMP 保护,RISC-V 要求产生精确中断并处理。

    PMP 允许机器模式指定用户模式下可以访问的内存地址。PMP entry 由一个 8-bit 的 PMP 配置寄存器和一个 32/64 位长的 PMP 地址寄存器组成。整个 PMP 包括若干个(通常为 8 到 16 组)PMP entry 。配置寄存器可以配置读、写和执行权限,地址寄存器用来划定界限。

    下两图显示了 PMP 地址寄存器和配置寄存器的布局。pmpxxcfg 表示了 PMP 配置寄存器,pmpxxaddr 表示了 PMP 地址寄存器。

    当处于用户模式的处理器尝试 load 或 store 操作时,将地址和所有的 PMP 地址寄存器比较。如果地 址大于等于 PMP 地址 i,但小于 PMP 地址 i+1,则 PMP i+1 的配置寄存器决定该访问是否可以继续,如果不能将会引发访问异常。

    R,W,X 位分别指示了 PMP 入口允许读、写、执行权限。A 域解释了 PMP 寄存器的编码情况。

    void setup_pmp(void)
    {
      // Set up a PMP to permit access to all of memory.
      // Ignore the illegal-instruction trap if PMPs aren't supported.
      uintptr_t pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X;
      asm volatile ("la t0, 1f\n\t"
                    "csrrw t0, mtvec, t0\n\t"
                    "csrw pmpaddr0, %1\n\t"
                    "csrw pmpcfg0, %0\n\t"
                    ".align 2\n\t"
                    "1: csrw mtvec, t0"
                    : : "r" (pmpc), "r" (-1UL) : "t0");
    }

    设置setup_pmp之后,异常解除

    void setup_pmp(void)
    {
      // Set up a PMP to permit access to all of memory.
      // Ignore the illegal-instruction trap if PMPs aren't supported.
      unsigned long pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X;
      asm volatile ("la t0, 1f\n\t"
                    "csrrw t0, mtvec, t0\n\t"
                    "csrw pmpaddr0, %1\n\t"
                    "csrw pmpcfg0, %0\n\t"
                    ".align 2\n\t"
                    "1: csrw mtvec, t0"
                    : : "r" (pmpc), "r" (-1UL) : "t0");
    }
    static void machine_switchto_supervisor(void)
    {
        setup_pmp();
        // set M Previous Privilege mode to Supervisor, for mret.
        unsigned long x = mstatus_get();
        x &= ~MSTATUS_MPP_MASK;
        //x |= MSTATUS_MPP_M;
        x |= MSTATUS_MPP_S;
        mstatus_set(x);
    
        // set M Exception Program Counter to main, for mret.
        // requires gcc -mcmodel=medany
        mepc_set((unsigned long)main);
    
        // disable paging for now.
        satp_set(0);
    
        // delegate interrupts and exceptions to supervisor mode.
        medeleg_set(0xb109);
        mideleg_set(0x222);
    
        printf("%s %d.\r\n", __func__, __LINE__);
        // switch to supervisor mode and jump to main().
        asm volatile("mret");
    }
    qemu-system-riscv64 -machine virt -bios none -kernel kernelimage -m 128M -smp 1 -nographic
    start 74.
    machine_switchto_supervisor 67.
    main 28.
  • 相关阅读:
    单例模式(Singleton)的6种实现
    深入浅出单实例Singleton设计模式
    Singleton单例模式
    面试中的Singleton
    海量数据存储之Key-Value存储简介
    大数据时代的 9 大Key-Value存储数据库
    python 多线程两种实现方式,Python多线程下的_strptime问题,
    pycURL的内存问题
    百万级访问网站前期的技术准备
    IPv6 tutorial – Part 6: Site-local addresses and link-local addresses
  • 原文地址:https://www.cnblogs.com/dream397/p/15718835.html
Copyright © 2011-2022 走看看