Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 30 Jan 2024 13:16:59 -0400
From:      Mitchell Horne <mhorne@freebsd.org>
To:        Lin Lee <leelin2602@gmail.com>, freebsd-riscv@freebsd.org
Subject:   Re: A little bit wondering about how a syscall works
Message-ID:  <9bfbdbe2-ff30-4c2f-abf3-2763aa433107@freebsd.org>
In-Reply-To: <8f66f3ed-2a49-4ebc-89eb-66c53e6d22bb@Spark>
References:  <9204b5c5-63bc-4c29-af19-1f1bb85f74e8@Spark> <8f66f3ed-2a49-4ebc-89eb-66c53e6d22bb@Spark>

next in thread | previous in thread | raw e-mail | index | archive | help


On 1/30/24 10:00, Lin Lee wrote:
> I am wondering about the function 
> ecall_handler(https://github.com/freebsd/freebsd-src/blob/main/sys/riscv/riscv/trap.c#L195 <https://github.com/freebsd/freebsd-src/blob/main/sys/riscv/riscv/trap.c#L195>), which later executing syscallenter, where &td->td_sa
>   Is used. I have no idea where the value of td->td_sa is being set. It 
> is a little bit confusing.
> 

The td_sa member is a struct syscall_args embedded within the larger struct thread. Therefore, it does not need to be set/allocated.

The expression "&td->td_sa" obtains a pointer to the syscall_args structure belonging to the struct thread, pointed at by td.

> Someone asks me to read 
> cpu_fetch_syscall_args(https://github.com/freebsd/freebsd-src/blob/main/sys/riscv/riscv/trap.c#L99 <https://github.com/freebsd/freebsd-src/blob/main/sys/riscv/riscv/trap.c#L99>), and it indeed explains how td->td_sa is being set. But however, I still have no idea how it works.
> 

So in this function, we obtain the pointer to the syscall_args structure:

   struct syscall_args *sa;
   ...
   sa = &td->td_sa;

 From there, we update a few fields of "sa", most notably the "code" which is the actual syscall number we are trying to execute.

   sa->code = td->td_frame->tf_t[0];

This could be written identically as:

   td->td_sa.code = td->td_frame->tf_t[0];

Therefore we have updated the syscall information within the thread structure, pointed at by td. sa->code is then used as the index into the system call vector (sysvec), to decide which function we should call.

Now, td_frame is the "trapframe", containing the CPU register contents at the time of the exception, generated by the system call instruction "ecall". So, CPU register t0 contains the syscall number, but where is this set?

If we look in the libc sources, the part executed by userspace, we find the SYSCALL() macro.

https://github.com/freebsd/freebsd-src/blob/7aa4e4eb36171d349c7f3948e16c09ff7540c241/lib/libc/riscv/SYS.h#L39

This short bit of assembly will:
  1. Set the t0 register with the appropriate numeric constant (e.g. SYS_fork)
  2. Execute the ecall instruction (which will trap into the kernel, and jump to the cpu_exception_handler assembly function in sys/riscv/riscv/exception.S)

(How exactly this macro gets used within libc is a little magic, and outside the scope here.)

Hope this helps!
Mitchell

> It is called as a function member in 
> elf64_freebsd_sysvec(https://github.com/freebsd/freebsd-src/blob/7aa4e4eb36171d349c7f3948e16c09ff7540c241/sys/riscv/riscv/elf_machdep.c#L61C25-L61C45 <https://github.com/freebsd/freebsd-src/blob/7aa4e4eb36171d349c7f3948e16c09ff7540c241/sys/riscv/riscv/elf_machdep.c#L61C25-L61C45>), and I think there is nothing to do with syscall here.
> 
> Could somebody please figure it out?
> How does a system call works? Where the value of td->td_sa is being set.
> 
> 
> Thank you very much
> 
> Best Regards,
> Lin Lee



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?9bfbdbe2-ff30-4c2f-abf3-2763aa433107>