.global __hard_di
.global __hard_irqrestore
.global __hard_ei
+ .global set_irq
/* GCC glue */
.global __ashrsi3
#include "kernel-8086.def"
-unix_syscall_entry:
- pushw %ds
- pushw %es
+/*
+ * Things to be careful of
+ *
+ * 1. We run the syscall on this tasks kernel stack
+ * 2. We can enter into here, schedule and pop out of someone else's
+ * stack so don't use globals without thought
+ * 3. The cs we trap from is not always the cs we return to, nor
+ * is ss/ds guaranteed to stay the same as the syscall might
+ * (eg brk) cause us to be moved phsically.
+ *
+ * Rules
+ *
+ * 1. We always make a syscall from user space
+ * 2. We never make a syscall with interrupts off
+ * 3. We treat the compiler scratch registers as fair game
+ */
- pushw %bp
- movw %sp, %bp
- movw %cs:kernel_ds,%bx /* Load our DS */
- movw %bx, %ds
- movw %bx, %es
+unix_syscall_entry:
+ pushw %bp /* Create a stack frame */
+ movw %sp, %bp
+ movw %cs:kernel_ds,%bx /* Load our DS */
+ movw %bx, %ds
+ movw %bx, %es
/*
* We are now referencing the kernel except for the stack
* and that has our arguments on it with 6 bytes of trap
- * return info before it and two segment registers we
- * added. bp will reference ss: so we can now stash away our
- * arguments in peace
+ * return info before it and the segment registers we
+ * added plus a return (*). bp will reference ss: so we can now stash
+ * away our arguments in peace
+ *
+ * (*) The extra return means read (A,B,C) can just do mov $foo,%ax
+ * and int, and we'll use the parent stack frame to avoid copies
*/
- movw %ax, udata+U_DATA__U_CALLNO
+ movw %ax, udata+U_DATA__U_CALLNO
- movw 10(%bp),%ax
- movw %ax,udata+U_DATA__U_ARGN
- movw 12(%bp),%ax
- movw %ax,udata+U_DATA__U_ARGN1
- movw 14(%bp),%ax
- movw %ax,udata+U_DATA__U_ARGN2
- movw 16(%bp),%ax
- movw %ax,udata+U_DATA__U_ARGN3
+ movw 10(%bp),%ax
+ movw %ax,udata+U_DATA__U_ARGN
+ movw 12(%bp),%ax
+ movw %ax,udata+U_DATA__U_ARGN1
+ movw 14(%bp),%ax
+ movw %ax,udata+U_DATA__U_ARGN2
+ movw 16(%bp),%ax
+ movw %ax,udata+U_DATA__U_ARGN3
/*
* Time to stack switch (we need SP for brk() even though the
* entry/exit code has no need of it and can use bp
*/
- movw %sp,%ax
- movw %ax,udata+U_DATA__U_SYSCALL_SP
-/* ; save SS anyway - will be useful if we ever do multi-segment
- ; binaries
- mov %ss,%ax
- mov %ax,udata+U_DATA__U_SYSCALL_SS(%bx) */
+ movw %sp,%ax
+ movw %ax,udata+U_DATA__U_SYSCALL_SP
/*
* Stack switch. Load sp the instruction after ss. Doesn't matter
* currently as IRQs are off, but may if this changes
*/
- movw %ds,%ax
- movw %ax,%ss
- movw kstack_top,%sp
+ movw %ds,%ax
+ movw %ax,%ss
+ movw kstack_top,%sp
- movb $1,kernel_flag
+ movb $1,kernel_flag
sti
- call unix_syscall
+ call unix_syscall
cli
- movb $0,kernel_flag
+ /* At this point the user cs,ds,ss may have moved */
+
+ movb $0,kernel_flag
/*
- * SIGNALS TODO
+ * We have a pending signal ?
*/
+ cmpb $0,udata+U_DATA__U_CURSIG
+ je no_signal
+
+ xorb %ah,%ah
+ movb udata+U_DATA__U_CURSIG,%al
+ movb $0, udata+U_DATA__U_CURSIG
+ movw udata+U_DATA__U_SIGVEC,%bx
+ addw %ax,%bx
+ addw %ax,%bx
+ movw %bx,%cx
+
/*
- * We effective return a 32bit ulong to gcc half of which is return
- * and error
+ * Build a suitable return frame
*/
- mov udata+U_DATA__U_ERROR,%dx
- mov udata+U_DATA__U_RETVAL,%ax
+ movw udata+U_DATA__U_PAGE+2,%bx
+ movw %bx,%es
+ /* ES:BP is now the user stack. We build a new frame below
+ the existing one that looks like this
+
+
+ retval
+ error code
+ $23 (signal_return) handler
+ signalnumber
+ flags
+ signalvector
+ cs
+
+ The handler pops the retval/error into ax/dx then
+ dumps the stale iret frame segment and does a ret
+ */
+
+ movw udata+U_DATA__U_RETVAL,%ax
+ movw %ax,-2(%bp)
+ movb udata+U_DATA__U_ERROR,%al
+ xorb %ah,%ah
+ movw %ax,-4(%bp)
+ movw $23,-6(%bp)
+ pushf
+ /* FIXME: enable interrupts in mask */
+ popw %ax
+ movw %ax,-10(%bp)
+ movw %cx,-12(%bp)
+ /* FIXME: need to fix MMU logic */
+ movw udata+U_DATA__U_PAGE,%ax
+ movw %ax,-14(%bp)
+ subw $-14,%bp
+ movw %es,%ax
+ movw %ax,%ds
+ movw %ax,%ss
+ movw %bp,%sp
+ /* To signal handler */
+ iret
+no_signal:
/*
- * Stack back
+ * We effective return a 32bit ulong to gcc half of which is return
+ * and error
*/
- mov udata+U_DATA__U_PAGE+3,%bx
- mov %bx, %ss
- mov %bp, %sp
- pop %es
- pop %ds
+ xorb %dh,%dh
+ movb udata+U_DATA__U_ERROR,%dl
+ movw udata+U_DATA__U_RETVAL,%ax
+
+ /* FIXME: need MMU code here to get new correct cs/ds/es */
+
+ movw udata+U_DATA__U_PAGE+2,%bx
+ movw udata+U_DATA__U_PAGE, %cx
+
+ /* We can't reference kernel objects from here */
+ movw %bx, %ss
+ movw %bx, %ds
+ movw %bp, %sp
+ movw %cx,4(%bp) /* Patch the cs for the iret - we might
+ have been relocated */
+ popw %bp /* Recover frame pointer */
iret
/*
sti
ret
+set_irq:
+ pushw %bp
+ movw %sp,%bp
+ movw 4(%bp),%bx
+ movw 6(%bp),%ax
+ addw %bx,%bx
+ addw %bx,%bx
+ pushw %es
+ xorw %cx,%cx
+ movw %cx,%es
+ movw %ax,%es:(%bx)
+ movw %bp,%sp
+ ret
+
+
+
+
/* FIXME: extract from C library or write nice ones */
__ashlsi3:
.global kstack_top
.global istack_top
+#include "../kernel-8086.def"
+
udata:
.bss 512
kstack_top:
trap_reboot:
jmp trap_monitor
+/*
+ * Interrupt and trap handlers. The 8086 doesn't have real protection
+ * but it does at least actually throw real traps for the things it
+ * does which makes it easier to handle
+ */
+
+int1:
+ pushw %ax
+ movb $1,%al
+ jmp do_irq
+int2:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int3:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int4:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int5:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int6:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int7:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int8:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int9:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int10:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int11:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int12:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int13:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int14:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int15:
+ pushw %ax
+ movb $2,%al
+ jmp do_irq
+int0:
+ pushw %ax
+ xorb %al,%al
+do_irq:
+ /* Save base registers on current stack */
+ pushw %ds
+ pushw %es
+ pushw %bx
+ pushw %cx
+ pushw %dx
+ pushw %bp
+
+
+ /* Reload segment registers */
+ movw %cs:kernel_ds,%bx
+ movw %bx,%ds
+ movw %bx,%es
+
+ /* At this point our ds/es/cs are all kernel but our SS could be
+ one of several stacks */
+ movw %ss,%dx
+ movw %sp,%bp
+
+ /* Switch to the IRQ stack and save the old stack */
+ movw %bx,%ss
+ movw $istack_top,%sp
+ pushw %dx
+ pushw %bp
+
+ movb $1,inint
+ movb $1,udata + U_DATA__U_ININTERRUPT
+ pushw %ax
+ call platform_interrupt
+ popw %bx
+ movb $0,inint
+ movb $0,udata + U_DATA__U_ININTERRUPT
+
+ cmpb $1,udata + U_DATA__U_INSYS
+ je ret_user
+
+ /* Pull the data off the stack and life continues */
+ popw %bp
+ popw %dx
+
+ movw %bp,%sp
+ movw %dx,%ss
+
+ popw %bp
+ popw %dx
+ popw %cx
+ popw %bx
+ popw %es
+ popw %ds
+ iret
+
+ /* The user path is more complicated. We might have been signalled
+ or need to task switch. At this point we are on the kernel stack */
+ret_user:
+ cmpb $0,need_resched
+ je no_resched
+
+ popw %bp
+ popw %dx
+
+ /*
+ * Save our data for the user stack where the registers are saved. This
+ * matters big time because the istack will get reused before
+ * we re-run. Instead we borrow our kstack (which is private and -
+ * as we are not in a syscall free for use
+ */
+ movw %cs:kernel_ds,%ss
+ movw $kstack_top,%sp
+
+ pushw %dx
+ pushw %bp
+
+ movw udata + U_DATA__U_PTAB,%bp
+ movb $P_READY,P_TAB__P_STATUS_OFFSET(%bp)
+
+ call switchout
+
+ /* Another task will start execution, time will pass and eventually
+ * we'll pop back out of here */
+
+no_resched:
+ popw %bp
+ popw %dx
+ movw %dx,%ss
+ movw %bp,%sp
+
+ /* Back on our user stack */
+
+ /* We are now on the user stack via ss
+ /* Dispatch signals if required */
+ movb udata + U_DATA__U_CURSIG,%al
+ cmpb $0,%al
+ je no_signal
+ /*
+ * We have a pending signal
+ */
+ movb $0,udata + U_DATA__U_CURSIG;
+ xorb %ah,%ah
+ movw udata + U_DATA__U_SIGVEC,%bp
+ addw %ax,%bp
+ addw %ax,%bp
+ movw (%bp),%bx
+ movw $0,(%bp)
+
+ /*
+ * Build a deeper return frame
+ */
+ movw $20,%ax /* __sigeturn in binary */
+ pushw %ax
+ pushf /* IRET frame */
+ pushw %bx
+ /* FIXME: we need to wire the MMU code in here and get the *new*
+ correct CS */
+ movw 4(%bp),%ax /* Get CS from original frame */
+ pushw %ax /* And push it */
+ /* Clean registers */
+ xorw %ax,%ax
+ xorw %bx,%bx
+ xorw %cx,%cx
+ xorw %dx,%dx
+ xorw %bp,%bp
+ iret
+
+ /* _sigreturn does
+ recover registers including flags
+ skip over spare cs: ret */
+
+ /* The usual path is uneventful */
+no_signal:
+ popw %bp
+ pop %dx
+ pop %cx
+ pop %bx
+ popw %es
+ popw %ds
+ popw %ax
+ iret
+
+
/* Returns the BIOS parameter data CX:DX as a long DX:AX to the C code or
FFFF if we don't get the right answer
.data
equipment_word:
.word 0
+
+