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.