Skip to content

Executable PMP regions of size less than 4K always trigger an instruction access fault

Host environment

  • QEMU flavor: qemu-system-riscv64
  • QEMU version: master

Emulated/Virtualized environment

  • Operating system: Bare-metal
  • Architecture: RISC-V

Description of problem

When configuring a PMP region that is less than 4K in size (Page size), and then trying to execute instructions inside said region, TCG always throws a PMP exception, even though the area allows code execution.

Additional information

I've debugged the issue already, and it's happening because of the following optimization in TCG:

TCG uses get_page_addr_code_hostp in order to try and get the translation cached for a whole page of instructions; if this function is unable to translate a whole page, it's supposed to simply return -1, and then the caller is supposed to translate and execute on a per-instruction basis. In this case get_page_addr_code_hostp calls tlb_fill, which then calls riscv_cpu_tlb_fill, which then calls get_physical_address_pmp to perform the PMP access checks. When said instructions are covered by a PMP region which is smaller than a page, this check then fails, since PMP regions must cover the whole access in order to allow it. At this point riscv_cpu_tlb_fill will see that a PMP fault happened, and since probe is set to false by get_page_addr_code_hostp, it will throw a RISC-V access fault exception instead of just returning a failure that get_page_addr_code_hostp can handle (by only accessing the memory of the specific instruction instead, which will be fully covered by the PMP region).

I haven't tried to fix it myself (my first idea is to simply make get_page_addr_code_hostp set the probe flag), since I'm not sure if changing that part of TCG will affect other architectures that I'm not aware of.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information