9front - general discussion about 9front
 help / color / mirror / Atom feed
* [9front] pc64/l.s
@ 2025-02-15  7:10 ron minnich
  2025-02-15 14:40 ` Dan Cross
  2025-02-15 16:22 ` [9front] pc64/l.s ron minnich
  0 siblings, 2 replies; 3+ messages in thread
From: ron minnich @ 2025-02-15  7:10 UTC (permalink / raw)
  To: 9front

[-- Attachment #1: Type: text/plain, Size: 409 bytes --]

in syscallentry, it does
swapgs
movq gs:0, ax /* m -> */
movq 16(AX), BX
..
movq BX, SP

This is familiar code but a bit different than what I'm used to.

I can't understand it from how Mach is defined: the pointer at offset 16 in
Mach is to Proc.

I've confirmed from qemu that this it is loading Proc, and as far as I'm
concerned that means I don't know what's going on :-)

what am I missing here?

Thanks

[-- Attachment #2: Type: text/html, Size: 648 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [9front] pc64/l.s
  2025-02-15  7:10 [9front] pc64/l.s ron minnich
@ 2025-02-15 14:40 ` Dan Cross
  2025-02-15 16:22 ` [9front] pc64/l.s ron minnich
  1 sibling, 0 replies; 3+ messages in thread
From: Dan Cross @ 2025-02-15 14:40 UTC (permalink / raw)
  To: 9front

On Sat, Feb 15, 2025 at 2:17 AM ron minnich <rminnich@gmail.com> wrote:
> in syscallentry, it does
> swapgs
> movq gs:0, ax /* m -> */
> movq 16(AX), BX
> ..
> movq BX, SP
>
> This is familiar code but a bit different than what I'm used to.
>
> I can't understand it from how Mach is defined: the pointer at offset 16 in Mach is to Proc.
>
> I've confirmed from qemu that this it is loading Proc, and as far as I'm concerned that means I don't know what's going on :-)
>
> what am I missing here?

This is a tad subtle, but the key bit of information is that the
kstack for a proc is right below the proc itself.

It may be useful to look at the entire sequence.

|TEXT syscallentry(SB), 1, $-4
|        SWAPGS

Load the kernels GSBASE into GS.

|        BYTE $0x65; MOVQ 0, AX                  /* m-> (MOVQ GS:0x0, AX) */

Move the 64-bit word at offset 0 relative to the GS segment into RAX.
One sees that was set in `mmuinit` in `mmu.c`, and is the address of
the Mach for this processor (`wrmsr(GSBASE,
(uvlong)&machp[m->machno]);`).

|        MOVQ    16(AX), BX

Load whatever value is at offset 16 relative to RAX into RBX.  The
previous instruction put the address of a `Mach` in RAX; `Mach` is
defined in `/sys/src/9/pc64/dat.h` and there are three data at the
beginning of that struct:

|        int machno;     // offset 0.
|        uintptr splpc;   // offset 8, because of alignment
|        Proc* proc;      // offset 16.

So this loads `proc` into RBX.

|        MOVQ    SP, R13

Ok, save the old SP that we trapped into the kernel on in a scratch register.

|        MOVQ    BX, SP

Load the stack pointer with the pointer to `proc` that we loaded
earlier.  At first glance, this seems wrong as RBX points to a Proc;
the explanation lies in /sys/src/9/port/proc.c; specifically in
`newproc`.  The answer to the mystery is that `Proc` is allocated in a
block that also contains the kstack for that process.  Here's the
relevant bit of code:

```
                b = malloc(KSTACK+sizeof(Proc));
                if(b == nil){
                        unlock(&procalloc);
                        return nil;
                }
                p = (Proc*)(b + KSTACK);
```

So while RBX does indeed point to a proc, right below that is that
proc's kstack, and recall that x86 stacks are full descending.  So
this instruction is really loading the stack top into the SP.

|        PUSHQ   $UDSEL                          /* old stack segment */
|        PUSHQ   R13                             /* old sp */
|        PUSHQ   R11                             /* old flags */
|        PUSHQ   $UESEL                          /* old code segment */
|        PUSHQ   CX                              /* old ip */
|        PUSHQ   $0                              /* error code */
|        PUSHQ   $64                             /* trap number
(VectorSYSCALL) */

Push a bunch of state onto the `Proc`'s stack. Note that the first
push (`PUSHQ $UDSEL`) will decrement the SP before storing $UDSEL;
thus, that word will appear just below the start of the `Proc` in
`up`.

|       SUBQ    $(8 + 23*8-7*8), SP             /* arg + sizeof(Ureg)-pushed */

Allocate some space for the `Ureg` that lives at the top of the proc's
kstack when in the kernel.

|        MOVQ    RMACH, (15*8)(SP)               /* old r15 */
|        MOVQ    RUSER, (14*8)(SP)               /* old r14 */

Save the old m/up.

|        MOVQ    RARG, (7*8)(SP)                 /* system call number */

Move the system call number into the "argument register" slot in the
Ureg allocated above.

|        MOVQ    AX, RMACH                       /* m */
|        MOVQ    BX, RUSER                       /* up */

Now we load `m` and `up` with the data we just loaded from the Mach;
RMACH is R15 and RUSER is R14. (The plan 9 compilers know to leave
these alone.)

|        LEAQ    8(SP), RARG                     /* Ureg* arg */

Load the address of the Ureg* we allocated into the argument register;
the plan 9 calling convention takes the first argument in a register
(R8) and the rest of the stack.

|        CALL    syscall(SB)

Finally, call into C code; `syscall` takes a `Ureg*`, allocated on the
top of the stack.  Note that on return from `syscall` the code
immediately proceeds into `forkret`, which resets the kstack state
(dealloc's the Ureg and so on) and goes back to userspace via
`sysret`.

Note that a potential point of confusion is that `Proc`, defined in
`/sys/src/9/port/portdat.h` has the scheduler `Label` as the first
element. `Label` is defined in `sys/src/9/pc64.dat.h` and has two
data, an `sp` and a `pc`.  The `sp` comes first in the structure
definition, so one may observe that loading `m->proc` into RBX above
_also_ means that RBX points to the sched stack pointer, but that's
not relevant here.

        - Dan C.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [9front] Re: pc64/l.s
  2025-02-15  7:10 [9front] pc64/l.s ron minnich
  2025-02-15 14:40 ` Dan Cross
@ 2025-02-15 16:22 ` ron minnich
  1 sibling, 0 replies; 3+ messages in thread
From: ron minnich @ 2025-02-15 16:22 UTC (permalink / raw)
  To: 9front

[-- Attachment #1: Type: text/plain, Size: 648 bytes --]

nvm I realized what you were doing as I was falling asleep, it's an
improvement over the original ...

On Fri, Feb 14, 2025 at 11:10 PM ron minnich <rminnich@gmail.com> wrote:

> in syscallentry, it does
> swapgs
> movq gs:0, ax /* m -> */
> movq 16(AX), BX
> ..
> movq BX, SP
>
> This is familiar code but a bit different than what I'm used to.
>
> I can't understand it from how Mach is defined: the pointer at offset 16
> in Mach is to Proc.
>
> I've confirmed from qemu that this it is loading Proc, and as far as I'm
> concerned that means I don't know what's going on :-)
>
> what am I missing here?
>
> Thanks
>
>

[-- Attachment #2: Type: text/html, Size: 1173 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-02-15 16:24 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-02-15  7:10 [9front] pc64/l.s ron minnich
2025-02-15 14:40 ` Dan Cross
2025-02-15 16:22 ` [9front] pc64/l.s ron minnich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).