From: Alan Cox Date: Sun, 15 Oct 2017 21:13:50 +0000 (+0100) Subject: ibmpc: further 8086 sketching out X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=ec41ab380a2028806c127e86a17ecee63b589338;p=FUZIX.git ibmpc: further 8086 sketching out --- diff --git a/Kernel/lowlevel-8086.S b/Kernel/lowlevel-8086.S index 4ea98e24..be2faf1d 100644 --- a/Kernel/lowlevel-8086.S +++ b/Kernel/lowlevel-8086.S @@ -10,6 +10,7 @@ .global __hard_di .global __hard_irqrestore .global __hard_ei + .global set_irq /* GCC glue */ .global __ashrsi3 @@ -18,81 +19,156 @@ #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: diff --git a/Kernel/platform-ibmpc/ibmpc.S b/Kernel/platform-ibmpc/ibmpc.S index 94c1add7..8d231e3c 100644 --- a/Kernel/platform-ibmpc/ibmpc.S +++ b/Kernel/platform-ibmpc/ibmpc.S @@ -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 + +