On Fri, 25 Oct 2019 at 20:15, Keith Packard <kei...@keithp.com> wrote: > There seems to be convergence on a pretty simple interface which uses > ebreak surrounded by a couple of specific no-ops: > > slli x0, x0, 0x1f > ebreak > srai x0, x0, 0x7 > > There are implementations in rust and openocd, and I've got one for > picolibc. The risc-v semihosting code is sitting on a branch in my repo > on github: > > https://github.com/keith-packard/qemu/tree/riscv-semihost
I had an idle glance at this implementation, and this: uint32_t pre = opcode_at(&ctx->base, ctx->base.pc_next - 4); uint32_t ebreak = opcode_at(&ctx->base, ctx->base.pc_next); uint32_t post = opcode_at(&ctx->base, ctx->base.pc_next + 4); (where opcode_at() is a wrapper for cpu_ldl_code()) has some unfortunate side effects: if the previous instruction is in the previous MMU page, or the following instruction is in the next MMU page, you might incorrectly trigger an exception (where QEMU will just longjmp straight out of the cpu_ldl_code()) if that other page isn't actually mapped in the guest's page table. You need to be careful not to access code outside the page you're actually on unless you're really going to execute it and are OK with it faulting. I'm not sure what the best way on QEMU to identify this kind of multiple-instruction-sequence is -- Richard might have an idea. One approach would be to always take an exception (or call a helper function) for the 'ebreak', and then distinguish semihosting from other kinds of ebreak by doing the load of the preceding/succeeding instructions at runtime rather than translate time. Does your semihosting spec expect to have the semihosting call work if the sequence crosses a page boundary, the code is being executed by a userspace process, and one of the two pages has been paged out by the OS ? thanks -- PMM