ibmpc: further 8086 sketching out
authorAlan Cox <alan@linux.intel.com>
Sun, 15 Oct 2017 21:13:50 +0000 (22:13 +0100)
committerAlan Cox <alan@linux.intel.com>
Sun, 15 Oct 2017 21:13:50 +0000 (22:13 +0100)
Kernel/lowlevel-8086.S
Kernel/platform-ibmpc/ibmpc.S

index 4ea98e2..be2faf1 100644 (file)
@@ -10,6 +10,7 @@
        .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
 
 /*
@@ -177,6 +253,23 @@ __hard_ei:
        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:
 
index 94c1add..8d231e3 100644 (file)
@@ -7,6 +7,8 @@
        .global kstack_top
        .global istack_top
 
+#include       "../kernel-8086.def"
+
 udata:
        .bss 512
 kstack_top:
@@ -45,6 +47,215 @@ trap_monitor:
 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
 
@@ -194,3 +405,5 @@ kernel_ds:
        .data
 equipment_word:
        .word 0
+
+