Implement semi hosting in RISCV gcc

622 views
Skip to first unread message

Vibhor Rajvanshi

unread,
Nov 16, 2018, 2:10:29 AM11/16/18
to RISC-V SW Dev
Hi All,

we have compiled the binaries using riscv gcc toolchain to run the generated elf file on our inhouse risc-v simulatior. 
Basic test are running fine. Now we want to add support for printf . For this we need to understand how the semi-hosting is implemented in libc sources of riscv?

Can I get some pointers on how I should proceed to implement semi-hosting?

Thanks,
Vibhor

Liviu Ionescu

unread,
Nov 16, 2018, 3:37:03 AM11/16/18
to Vibhor Rajvanshi, RISC-V SW Dev


> On 16 Nov 2018, at 09:10, Vibhor Rajvanshi <vibhor...@gmail.com> wrote:
>
> Can I get some pointers on how I should proceed to implement semi-hosting?

it depends on the scope of your project.

a semihosting library can be part of the toolchain, as in the ARM embedded toolchain, where libgloss forwards all system calls to the debugger. if you want to contribute a semihosting library to the RISC-V toolchain, I suggest you copy/paste the ARM libgloss and update the assembly code to call the debugger, based on the notes you can find in riscv-spec-2.pdf, chapter 2.8, or you cake a look at my implementation (https://github.com/micro-os-plus/riscv-arch-xpack/blob/xpack/include/riscv-arch/arch-semihosting-inlines.h)

alternatively you can include the semihosting functions in your application; for this you can also take a look at my code in

https://github.com/micro-os-plus/semihosting-xpack/blob/xpack/src/syscalls-semihosting.cpp

project templates that generate fully functional application using semihosting can be found at

https://github.com/micro-os-plus/sifive-templates-xpack/blob/xpack/README.md

alternatively you can generate the same projects with the Eclipse SiFive project plugins.


to run the semi-hosted application you can use OpenOCD, it has full semi-hosting support for RISC-V 32-bit and 64-bit targets.


regards,

Liviu


Jim Wilson

unread,
Nov 16, 2018, 11:48:16 AM11/16/18
to Vibhor Rajvanshi, sw-...@groups.riscv.org
There are many different ways to do semi-hosting. How you do this
will depend in part on the C library that you are using which you
didn't specify.

If you are using newlib&libgloss, then this implementation assumes
that when the simulator sees an ecall instruction, it makes a call to
the corresponding linux syscall. You can see one implementation in
the gdb simulator, see for instance riscv-gdb/sim/riscv/sim-main.c and
riscv-gdb/sim/common/sim-syscall.c.

JIm

Liviu Ionescu

unread,
Nov 16, 2018, 4:58:47 PM11/16/18
to Jim Wilson, Vibhor Rajvanshi, sw-...@groups.riscv.org


> On 16 Nov 2018, at 18:48, Jim Wilson <ji...@sifive.com> wrote:
>
> If you are using newlib&libgloss, then this implementation assumes
> that when the simulator sees an ecall instruction, it makes a call to
> the corresponding linux syscall. You can see one implementation in
> the gdb simulator, see for instance riscv-gdb/sim/riscv/sim-main.c and
> riscv-gdb/sim/common/sim-syscall.c.

I'm afraid you just aren't familiar with semihosting.

the common definition of semihosting is a technique that allows a target device, usually an embedded MCU, to use some of the resources available on a host connected via a debugger link (like JTAG).

the industry de-facto standard is ARM semihosting (https://static.docs.arm.com/100863/0200/semihosting.pdf)

there are two main usages of semihosting:
- to write tests (mostly unit tests), that receive a command line, possibly some input files, do some processing and return an exit code, possibly some output files
- to define a completely separated trace channel, that requires no resources, monitors, etc or special configurations on the target

if you want to abuse this term and extend it to gdb simulators, emulators, rom monitors, etc, sure, you are free to do it, but please be aware of the confusion this may create.

the libgloss distributed with the risc-v toolchain is anything but a semihosting library.

regards,

Liviu

Liviu Ionescu

unread,
Nov 17, 2018, 9:35:22 AM11/17/18
to Vibhor Rajvanshi, RISC-V SW Dev


> On 16 Nov 2018, at 09:10, Vibhor Rajvanshi <vibhor...@gmail.com> wrote:
>
Vibhor, coming back to your question, there are two different paths.

if all you need is to route the printf from the risc-v elf to your simulator console, you can use the current libgloss and implement the ECALL in the simulator to process the write system call in order to identify the stdout and forward the stream to wherever you want.

if you need to also run your elf on a physical target (even synthesised on an FPGA), connected to a debugger (like OpenOCD) via a JTAG connection, the current libgloss won't do it, since the ECALL will fail on a bare-metal device.

the solution is to use a semihosting protocol, which, instead of ECALL uses BRK, to break to the debugger.

of course you can invent your own protocol, but once you do it, you need to implement it in all the debuggers you plan to use.

the industry de-facto protocol is ARM semihosting, which is already implemented by most debuggers (for sure in OpenOCD, since I contributed the implementation), and it is perfectly possible to use the same protocol with risc-v devices.

to be noted that the semihosting solution is more general, you can run the same binary image both on a physical target via a debugger and on a simulator, since the semihosting protocol can be easily implemented on a simulator, while the ECALL solution normally cannot be used with a debugger, (since ECALL does not break to the debugger, only BRK can do it).


regards,

Liviu

Vibhor Rajvanshi

unread,
Nov 20, 2018, 6:13:58 AM11/20/18
to RISC-V SW Dev

We checked that riscv-tests package contains benchmark/common/syscalls.c file, this is linked in all the benchmark test codes.
All system calls ends up calling syscall() function in this file. 
eg. call flow to syscall is:    "printf() -> vprtintfmt()->putchar->syscall()" 

Is this an entry point to implement semi-hosting?

code snippet of syscall:

static uintptr_t syscall(uintptr_t which, uint64_t arg0, uint64_t arg1, uint64_t arg2)
{
  volatile uint64_t magic_mem[8] __attribute__((aligned(64)));
  magic_mem[0] = which;
  magic_mem[1] = arg0;
  magic_mem[2] = arg1;
  magic_mem[3] = arg2;
  __sync_synchronize();

  tohost = (uintptr_t)magic_mem;
  while (fromhost == 0)
    ;
  fromhost = 0;

  __sync_synchronize();
  return magic_mem[0];
}



Liviu Ionescu

unread,
Nov 20, 2018, 7:06:56 AM11/20/18
to Vibhor Rajvanshi, RISC-V SW Dev


> On 20 Nov 2018, at 13:13, Vibhor Rajvanshi <vibhor...@gmail.com> wrote:
>
> Is this an entry point to implement semi-hosting?

please explain what exactly you understand by semi-hosting and what you want to achieve, since apparently you did not get the whole picture.


regards,

Liviu

Vibhor Rajvanshi

unread,
Nov 20, 2018, 7:29:02 AM11/20/18
to RISC-V SW Dev

Hi Liviu,

My goal is to route the printf from riscv gcc-elf to my simulator console.

For this I compiled the benchmark tests using -lgloss flag in Makefile.

While scrolling through the benchmark code , I found that something related to printf is already done(benchmark/common/syscalls.c).
Also I can see the functions calls to printf() -> vprtintfmt()->putchar->syscall() in my assembly code . 
So I just wanted to know what is the significance of this syscall() call. And is it possible if there is someway to route this to my simulator console in order to get the print work.

Tommy Murphy

unread,
Nov 20, 2018, 7:53:48 AM11/20/18
to RISC-V SW Dev
I don't know if this is relevant or not but the readme here

https://github.com/riscv/riscv-tests/blob/master/benchmarks/readme.txt

says

"You cannot use standard clib functions (like memcopy or strcat). You
cannot use system calls and thus cannot use printf."

Liviu Ionescu

unread,
Nov 20, 2018, 7:55:11 AM11/20/18
to Vibhor Rajvanshi, RISC-V SW Dev


> On 20 Nov 2018, at 14:29, Vibhor Rajvanshi <vibhor...@gmail.com> wrote:
>
>
> Hi Liviu,
>
> My goal is to route the printf from riscv gcc-elf to my simulator console.

then adjust the way your simulator implements ECALL.

> For this I compiled the benchmark tests using -lgloss flag in Makefile.

ok, last time I checked, the riscv*-unknown-elf toolchains linked this by default.

> While scrolling through the benchmark code , I found that something related to printf is already done(benchmark/common/syscalls.c).
> Also I can see the functions calls to printf() -> vprtintfmt()->putchar->syscall() in my assembly code .
> So I just wanted to know what is the significance of this syscall() call.

libgloss implements most of the standard posix calls with ECALLs, similarly to user land system calls on unix systems.

> And is it possible if there is someway to route this to my simulator console in order to get the print work.

yes, extend the ECALL implementation in your simulator.


regards,

Liviu

Liviu Ionescu

unread,
Nov 20, 2018, 8:32:26 AM11/20/18
to Tommy Murphy, RISC-V SW Dev
these are usual precautions, the benchmark code itself should not include library calls, otherwise the results are affected by library quality.

but if the printf() is used outside of the benchmarked code, it should be ok.


regards,

Liviu

Tommy Murphy

unread,
Nov 20, 2018, 9:27:01 AM11/20/18
to RISC-V SW Dev, tommy_...@hotmail.com
I understand that certain code should not be used from within benchmark code but the intro for that and other comments says:

There are a couple important points to make about the *toolchain*. 

So if whoever wrote that readme meant to say that system calls and printf etc. should not be called FROM the benchmark rather than not at all then they were not very clear.
Reply all
Reply to author
Forward
0 new messages