Time to have assembler part of Inferno kernel to be implemented. Let’s start with routines that allows to make labels and later jump to them, they are used in kernel sources to have scheduler to switch control and do context switching between processes. The Label structure in dat.h:

1struct Label {
2	ulong   sp;
3	ulong   pc;
4};

Simple idea to remember the PC(program counter) and SP(stack pointer), to init the structure and use later, we should have two functions implemented:

 1TEXT setlabel(SB), $-4
 2    MOVW    R13, 0(R0)
 3    MOVW    R14, 4(R0)
 4    MOVW    $0, R0
 5    RET
 6
 7TEXT gotolabel(SB), $-4 
 8    MOVW    0(R0), R13
 9    MOVW    4(R0), R14
10    MOVW    $1, R0
11    RET

It works in simple way, setlabel() has pointer to Label as argument (R0 registry), so initialization 0(R0) puts value of R13/SP into Label.sp, and 4(R0) puts value of R14/PC into Label.pc; gotolabel() does opposite, taking pointer to Label and initialize SP and PC and as result pass control of execution.

getcallerpc() also is very simple, when the function is called, the PC is put in stack for return address, so we can extract it as 0(SP):

1TEXT getcallerpc(SB), $-4
2    MOVW    0(SP), R0
3    RET

splhi() is function that saves PC into Mach structure, disables all maskable interrupts and returns the previous interrupt enable state, see the http://www.vitanuova.com/inferno/man/10/splhi.html, so we modify Mach structure to have ulong splpc at very beginning so address is same as address of Mach.

1struct Mach {
2    ulong   splpc;      /* pc of last caller to splhi */
3    int     machno;     /* physical id of processor */
4    ulong   ticks;      /* of the clock since boot time */
5    Proc*   proc;       /* current process on this processor */
6    Label   sched;      /* scheduler wakeup */
7};

So the code of int splhi():

1TEXT splhi(SB), $-4
2	MOVW	$(MACHADDR), R6
3	MOVW	R14, (R6)   /* m->splpc */
4	MOVW	CPSR, R0
5	ORR		$(PsrDirq), R0, R1
6	MOVW	R1, CPSR
7	RET

int spllo() enables interrupts and returns a flag representing the previous interrupt enable state:

splx(int x) saves PC into m->splpc, restores the interrupt enable state state to x, which must be a value returned by a previous call to splhi or spllo

splxpc(int x) does same but without saving PC

1TEXT splx(SB), $-4
2	MOVW	$(MACHADDR), R6
3	MOVW	R14, (R6)   /* m->splpc */
4TEXT splxpc(SB), $-4
5	MOVW	R0, R1
6	MOVW	CPSR, R0
7	MOVW	R1, CPSR
8	RET

int islo() returns true (non-zero) if interrupts are currently enabled, and 0 otherwise:

1TEXT islo(SB), $-4
2	MOVW	CPSR, R0
3	AND		$(PsrDirq), R0
4	EOR		$(PsrDirq), R0
5	RET

FILES: