boot - Bring in real-mode fixes for BIOS calls
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 18 Sep 2009 19:18:55 +0000 (12:18 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 18 Sep 2009 19:18:55 +0000 (12:18 -0700)
* Make BIOS calls in real mode now (I think), and no longer use the
  pmap hacks.

  Improves BIOS compatibility, particularly when booting from a USB
  mass storage device.

Taken-from: FreeBSD
Submitted-by: Jordan Gordeev <smtms@crater.dragonflybsd.org>
sys/boot/pc32/boot2/boot2.c
sys/boot/pc32/bootasm.h
sys/boot/pc32/btx/btx/Makefile
sys/boot/pc32/btx/btx/btx.S
sys/boot/pc32/loader/main.c

index 34bddfb..775c6bd 100644 (file)
@@ -61,6 +61,7 @@
 #include <sys/dirent.h>
 #include <machine/bootinfo.h>
 #include <machine/elf.h>
+#include <machine/psl.h>
 
 #include <stdarg.h>
 
 #define NDEV           3
 #define MEM_BASE       0x12
 #define MEM_EXT        0x15
-#define V86_CY(x)      ((x) & 1)
-#define V86_ZR(x)      ((x) & 0x40)
+#define V86_CY(x)      ((x) & PSL_C)
+#define V86_ZR(x)      ((x) & PSL_Z)
 
 #define DRV_HARD       0x80
 #define DRV_MASK       0x7f
@@ -290,6 +291,7 @@ main(void)
     boot2_dmadat =
                (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
     v86.ctl = V86_FLAGS;
+    v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
     dsk.drive = *(uint8_t *)PTOV(MEM_BTX_USR_ARG);
     dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
     dsk.unit = dsk.drive & DRV_MASK;
index 0db08f0..d570717 100644 (file)
@@ -42,6 +42,8 @@
  *        stack.
  *   2   - experimental move addresses abobe 0x2000 and hardwire the user
  *        stack.
+ *      NOTE: some changes to the standard bootloader address set and the
+ *            rest of the code are not reflected in the experimental sets
  */
 /* #define BOOT_NEWBOOTLOADER 2 */
 
@@ -50,7 +52,6 @@
  */
 
 #define BDA_MEM                0x413           /* Free memory          */
-#define BDA_KEYFLAGS   0x417           /* Keyboard shift-state flags   */
 #define BDA_SCR                0x449           /* Video mode           */
 #define BDA_POS                0x450           /* Cursor position      */
 #define BDA_BOOT       0x472           /* Boot howto flag      */
 #define MEM_BTX_START  0x1000          /* start of BTX memory */
 #define MEM_BTX_ESP0   0x1800          /* Supervisor stack */
 #define MEM_BTX_BUF    0x1800          /* Scratch buffer stack */
-#define MEM_BTX_ESP1   0x1e00          /* Link stack */
-#define MEM_BTX_IDT    0x1e00          /* IDT */
-#define MEM_BTX_TSS    0x1f98          /* TSS */
-#define MEM_BTX_MAP    0x2000          /* I/O bit map */
-#define MEM_BTX_DIR    0x4000          /* Page directory */
+#define MEM_BTX_ESPR   0x5e00          /* Real mode stack */
+#define MEM_BTX_IDT    0x5e00          /* IDT */
+#define MEM_BTX_TSS    0x5f98          /* TSS */
+#define MEM_BTX_MAP    0x6000          /* I/O bit map */
+#define MEM_BTX_TSS_END        0x7fff          /* Start of user memory */
 
 /*
  * NOTE: page table location is hardwired in /usr/src/usr.sbin/btxld/btx.h
  */
-#define MEM_BTX_TBL    0x5000          /* Page tables */
 #define MEM_BTX_ZEND   0x7000          /* Zero from IDT to here in btx.S */
 
 /********************   0x7c00 BIOS LOAD ADDRESS (512 bytes) **********/
index ab638ff..2fe3c28 100644 (file)
@@ -1,10 +1,6 @@
 # $FreeBSD: src/sys/boot/i386/btx/btx/Makefile,v 1.13 2002/09/17 01:48:54 peter Exp $
 # $DragonFly: src/sys/boot/pc32/btx/btx/Makefile,v 1.4 2004/07/18 23:40:04 dillon Exp $
 
-.if defined(PAGING)
-AFLAGS+=       -DPAGING
-.endif
-
 .if defined(BOOT_BTX_NOHANG)
 BOOT_BTX_FLAGS=0x1
 .else
index 633d73d..5adc7fd 100644 (file)
 
 #include "../../bootasm.h"
 
-               /*
               * Paging control.
               */
+/*
+ * Paging control.
+ */
                .set PAG_SIZ,0x1000             # Page size
                .set PAG_CNT,0x1000             # Pages to map
+/*
+ * Fields in %eflags.
+ */
+               .set PSL_RESERVED_DEFAULT,0x00000002
+               .set PSL_T,0x00000100           # Trap flag
+               .set PSL_I,0x00000200           # Interrupt enable flag
+               .set PSL_VM,0x00020000          # Virtual 8086 mode flag
+               .set PSL_AC,0x00040000          # Alignment check flag
 
-               /*
               * Segment selectors.
               */
+/*
+ * Segment selectors.
+ */
                .set SEL_SCODE,0x8              # Supervisor code
                .set SEL_SDATA,0x10             # Supervisor data
                .set SEL_RCODE,0x18             # Real mode code
                .set SEL_UDATA,0x30|3           # User data
                .set SEL_TSS,0x38               # TSS
 
-               /*
               * Task state segment fields.
               */
+/*
+ * Task state segment fields.
+ */
                .set TSS_ESP0,0x4               # PL 0 ESP
                .set TSS_SS0,0x8                # PL 0 SS
-               .set TSS_ESP1,0xc               # PL 1 ESP
                .set TSS_MAP,0x66               # I/O bit map base
 
-               /*
               * System calls.
               */
+/*
+ * System calls.
+ */
                .set SYS_EXIT,0x0               # Exit
                .set SYS_EXEC,0x1               # Exec
 
-               /*
-                * V86 constants.
-                */
-               .set V86_FLG,0x208eff           # V86 flag mask
-               .set V86_STK,0x400              # V86 stack allowance
+/*
+ * Fields in V86 interface structure.
+ */
+               .set V86_CTL,0x0                # Control flags
+               .set V86_ADDR,0x4               # Int number/address
+               .set V86_ES,0x8                 # V86 ES
+               .set V86_DS,0xc                 # V86 DS
+               .set V86_FS,0x10                # V86 FS
+               .set V86_GS,0x14                # V86 GS
+/*
+ * V86 control flags.
+ */
+               .set V86F_ADDR,0x10000          # Segment:offset address
+               .set V86F_CALLF,0x20000         # Emulate far call
+               .set V86F_FLAGS,0x40000         # Return flags
 
-               /*
               * Dump format control bytes.
               */
+/*
+ * Dump format control bytes.
+ */
                .set DMP_X16,0x1                # Word
                .set DMP_X32,0x2                # Long
                .set DMP_MEM,0x4                # Memory
                .set DMP_EOL,0x8                # End of line
 
-               /*
               * Screen defaults and assumptions.
               */
+/*
+ * Screen defaults and assumptions.
+ */
                .set SCR_MAT,0x7                # Mode/attribute
                .set SCR_COL,0x50               # Columns per row
                .set SCR_ROW,0x19               # Rows per screen
 
-               /*
               * Derivations, for brevity.
               */
+/*
+ * Derivations, for brevity.
+ */
                .set _ESP0H,MEM_BTX_ESP0>>0x8   # Byte 1 of ESP0
-               .set _ESP1H,MEM_BTX_ESP1>>0x8   # Byte 1 of ESP1
                .set _TSSIO,MEM_BTX_MAP-MEM_BTX_TSS     # TSS I/O base
-               .set _TSSLM,MEM_BTX_DIR-MEM_BTX_TSS-1   # TSS limit
+               .set _TSSLM,MEM_BTX_TSS_END-MEM_BTX_TSS # TSS limit
                .set _IDTLM,MEM_BTX_TSS-MEM_BTX_IDT-1   # IDT limit
 
-               /*
               * Code segment.
               *
               * BTX start.
               */
+/*
+ * Code segment.
+ *
+ * BTX start.
+ */
                .globl start
                .code16
 start:                                         # Start of code
 
-               /*
               * BTX header.
               */
+/*
+ * BTX header.
+ */
 btx_hdr:       .byte 0xeb                      # Machine ID
                .byte 0xe                       # Header size
                .ascii "BTX"                    # Magic
                .byte 0x1                       # Major version
-               .byte 0x1                       # Minor version
+               .byte 0x2                       # Minor version
                .byte BTX_FLAGS                 # Flags
                .word PAG_CNT-MEM_BTX_ORG>>0xc  # Paging control
                .word break-start               # Text size
                .long 0x0                       # Entry address
 
-               /*
               * Initialization routine.
               */
+/*
+ * Initialization routine.
+ */
 init:          cli                             # Disable interrupts
                xor %ax,%ax                     # Zero/segment
                mov %ax,%ss                     # Set up
@@ -145,19 +161,30 @@ init:             cli                             # Disable interrupts
                pushl $0x2                      # Clear
                popfl                           #  flags
 
-               /*
               * Initialize memory.
               */
+/*
+ * Initialize memory.
+ */
                mov $MEM_BTX_IDT,%di            # Memory to initialize
                mov $(MEM_BTX_ZEND-MEM_BTX_IDT)/2,%cx   # Words to zero
-               push %di                        # Save
                rep                             # Zero-fill
                stosw                           #  memory
-               pop %di                         # Restore
 
-               /*
-                * Create IDT.
-                */
+/*
+ * Update real mode IDT for reflecting hardware interrupts.
+ */
+               mov $intr20,%bx                 # Address first handler
+               mov $0x10,%cx                   # Number of handlers
+               mov $0x20*4,%di                 # First real mode IDT entry
+init.0:                mov %bx,(%di)                   # Store IP
+               inc %di                         # Address next
+               inc %di                         #  entry
+               stosw                           # Store CS
+               add $4,%bx                      # Next handler
+               loop init.0                     # Next IRQ
+/*
+ * Create IDT.
+ */
+               mov $MEM_BTX_IDT,%di
                mov $idtctl,%si                 # Control string
 init.1:        lodsb                           # Get entry
                cbw                             #  count
@@ -179,66 +206,21 @@ init.3:   lea 0x8(%di),%di                # Next entry
                loop init.2                     # Till set done
                jmp init.1                      # Continue
 
-               /*
               * Initialize TSS.
               */
+/*
+ * Initialize TSS.
+ */
 init.4:        movb $_ESP0H,TSS_ESP0+1(%di)    # Set ESP0
                movb $SEL_SDATA,TSS_SS0(%di)    # Set SS0
-               movb $_ESP1H,TSS_ESP1+1(%di)    # Set ESP1
                movb $_TSSIO,TSS_MAP(%di)       # Set I/O bit map base
-#ifdef PAGING
-               /*
-                * Create page directory.
-                */
-               xor %edx,%edx                   # Page
-               mov $PAG_SIZ>>0x8,%dh           #  size
-               xor %eax,%eax                   # Zero
-               mov $MEM_BTX_DIR,%di            # Page directory
-               mov $PAG_CNT>>0xa,%cl           # Entries
-               mov $MEM_BTX_TBL|0x7,%ax        # First entry
-init.5:        stosl                           # Write entry
-               add %dx,%ax                     # To next
-               loop init.5                     # Till done
-
-               /*
-                * Create page tables.
-                */
-               mov $MEM_BTX_TBL,%di            # Page table
-               mov $PAG_CNT>>0x8,%ch           # Entries
-               xor %ax,%ax                     # Start address
-init.6:        mov $0x7,%al                    # Set U:W:P flags
-               cmp btx_hdr+0x8,%cx             # Standard user page?
-               jb init.7                       # Yes
-               cmp $PAG_CNT-MEM_BTX_START>>0xc,%cx     # BTX memory?
-               jae init.7                      # No or first page
-               and $~0x2,%al                   # Clear W flag
-               cmp $PAG_CNT-MEM_BTX_USR>>0xc,%cx       # User page zero?
-               jne init.7                      # No
-               testb $0x80,btx_hdr+0x7         # Unmap it?
-               jz init.7                       # No
-               and $~0x1,%al                   # Clear P flag
-init.7:        stosl                           # Set entry
-               add %edx,%eax                   # Next address
-               loop init.6                     # Till done
-#endif
-               /*
-                * Bring up the system.
-                */
+/*
+ * Bring up the system.
+ */
                mov $0x2820,%bx                 # Set protected mode
                callw setpic                    #  IRQ offsets
                lidt idtdesc                    # Set IDT
-#ifdef PAGING
-               xor %eax,%eax                   # Set base
-               mov $MEM_BTX_DIR>>0x8,%ah       #  of page
-               mov %eax,%cr3                   #  directory
-#endif
                lgdt gdtdesc                    # Set GDT
                mov %cr0,%eax                   # Switch to protected
-#ifdef PAGING
-               or $0x80000001,%eax             #  mode and enable paging
-#else
                or $0x01,%eax                   #  mode
-#endif
                mov %eax,%cr0                   #  
                ljmp $SEL_SCODE,$init.8         # To 32-bit code
                .code32
@@ -246,29 +228,29 @@ init.8:   xorl %ecx,%ecx                  # Zero
                movb $SEL_SDATA,%cl             # To 32-bit
                movw %cx,%ss                    #  stack
 
-               /*
               * Launch user task.
               */
+/*
+ * Launch user task.
+ */
                movb $SEL_TSS,%cl               # Set task
                ltr %cx                         #  register
 
-               /*
               * BTX user area base of VM, for converting physical stack
               * addresses to btx-client virtual stack addresses.
               */
+/*
+ * BTX user area base of VM, for converting physical stack
+ * addresses to btx-client virtual stack addresses.
+ */
                movl $MEM_BTX_USR,%edx
 #if !defined(MEM_BTX_USR_STK)
-               /* 
               * XXX We should NOT use BDA_MEM here.  Use a fixed location
               * instead.  (%eax is a physical stack addr)
               */
+/*
+ * XXX We should NOT use BDA_MEM here.  Use a fixed location
+ * instead.  (%eax is a physical stack addr)
+ */
                movzwl %ss:BDA_MEM,%eax         # Get free memory
                shll $0xa,%eax                  # To bytes
 #else
-               /*
               * Use a fixed user stack instead of depending on BDA_MEM.
               * %eax is a physical * stack address.
               */
+/*
+ * Use a fixed user stack instead of depending on BDA_MEM.
+ * %eax is a physical * stack address.
+ */
                movl $MEM_BTX_USR_STK,%eax
 #endif
                subl $USR_ARGSPACE,%eax         # Less arg space
@@ -297,29 +279,29 @@ init.9:           push $0x0                       #  general
                popl %gs                        #  registers
                iret                            # To user mode
 
-               /*
               * Exit routine.
               */
+/*
+ * Exit routine.
+ */
 exit:          cli                             # Disable interrupts
                movl $MEM_BTX_ESP0,%esp         # Clear stack
 
-               /*
               * Turn off paging.
               */
+/*
+ * Turn off paging.
+ */
                movl %cr0,%eax                  # Get CR0
                andl $~0x80000000,%eax          # Disable
                movl %eax,%cr0                  #  paging
                xorl %ecx,%ecx                  # Zero
                movl %ecx,%cr3                  # Flush TLB
 
-               /*
               * Restore the GDT in case we caught a kernel trap.
               */
+/*
+ * Restore the GDT in case we caught a kernel trap.
+ */
                lgdt gdtdesc                    # Set GDT
 
-               /*
               * To 16 bits.
               */
+/*
+ * To 16 bits.
+ */
                ljmpw $SEL_RCODE,$exit.1        # Reload CS
                .code16
 exit.1:        mov $SEL_RDATA,%cl              # 16-bit selector
@@ -329,9 +311,9 @@ exit.1:     mov $SEL_RDATA,%cl              # 16-bit selector
                mov %cx,%fs                     #  segment
                mov %cx,%gs                     #  registers
 
-               /*
               * To real-address mode.
               */
+/*
+ * To real-address mode.
+ */
                dec %ax                         # Switch to
                mov %eax,%cr0                   #  real mode
                ljmp $0x0,$exit.2               # Reload CS
@@ -342,18 +324,18 @@ exit.2:   xor %ax,%ax                     # Real mode segment
                callw setpic                    #  IRQ offsets
                lidt ivtdesc                    # Set IVT
 
-               /*
               * Reboot or await reset.
               */
+/*
+ * Reboot or await reset.
+ */
                sti                             # Enable interrupts
                testb $0x1,btx_hdr+0x7          # Reboot?
 exit.3:                jz exit.3                       # No
                movw $0x1234, BDA_BOOT          # Do a warm boot
                ljmp $0xf000,$0xfff0            # reboot the machine
 
-               /*
               * Set IRQ offsets by reprogramming 8259A PICs.
               */
+/*
+ * Set IRQ offsets by reprogramming 8259A PICs.
+ */
 setpic:        in $0x21,%al                    # Save master
                push %ax                        #  IMR
                in $0xa1,%al                    # Save slave
@@ -379,14 +361,9 @@ setpic:    in $0x21,%al                    # Save master
                retw                            # To caller
                .code32
 
-               /*
-                * Initiate return from V86 mode to user mode.
-                */
-inthlt:        hlt                             # To supervisor mode
-
-               /*
-                * Exception jump table.
-                */
+/*
+ * Exception jump table.
+ */
 intx00:        push $0x0                       # Int 0x0: #DE
                jmp ex_noc                      # Divide error
                push $0x1                       # Int 0x1: #DB
@@ -410,50 +387,36 @@ intx00:   push $0x0                       # Int 0x0: #DE
                push $0xc                       # Int 0xc: #SS
                jmp except                      # Stack segment fault
                push $0xd                       # Int 0xd: #GP
-               jmp ex_v86                      # General protection
+               jmp except                      # General protection
                push $0xe                       # Int 0xe: #PF
                jmp except                      # Page fault
 intx10:        push $0x10                      # Int 0x10: #MF
                jmp ex_noc                      # Floating-point error
 
-               /*
-                * Handle #GP exception.
-                */
-ex_v86:        testb $0x2,0x12(%esp,1)         # V86 mode?
-               jz except                       # No
-               jmp v86mon                      # To monitor
-
-               /*
-                * Save a zero error code.
-                */
+/*
+ * Save a zero error code.
+ */
 ex_noc:        pushl (%esp,1)                  # Duplicate int no
                movb $0x0,0x4(%esp,1)           # Fake error code
 
-               /*
               * Handle exception.
               */
+/*
+ * Handle exception.
+ */
 except:        cld                             # String ops inc
                pushl %ds                       # Save
                pushl %es                       #  most
                pusha                           #  registers
-               movb $0x6,%al                   # Push loop count
-               testb $0x2,0x3a(%esp,1)         # V86 mode?
-               jnz except.1                    # Yes
                pushl %gs                       # Set GS
                pushl %fs                       # Set FS
                pushl %ds                       # Set DS
                pushl %es                       # Set ES
-               movb $0x2,%al                   # Push loop count
                cmpw $SEL_SCODE,0x44(%esp,1)    # Supervisor mode?
                jne except.1                    # No
                pushl %ss                       # Set SS
-               leal 0x50(%esp,1),%eax          # Set
-               pushl %eax                      #  ESP
                jmp except.2                    # Join common code
-except.1:      pushl 0x50(%esp,1)              # Set GS, FS, DS, ES
-               decb %al                        #  (if V86 mode), and
-               jne except.1                    #  SS, ESP
-except.2:      push $SEL_SDATA                 # Set up
+except.1:      pushl 0x50(%esp,1)              # Set SS
+except.2:      pushl 0x50(%esp,1)              # Set ESP
+               push $SEL_SDATA                 # Set up
                popl %ds                        #  to
                pushl %ds                       #  address
                popl %es                        #  data
@@ -472,298 +435,21 @@ except.2:        push $SEL_SDATA                 # Set up
                je except.3                     # Yes
                cmpb $0x1,(%esp,1)              # Debug?
                jne except.2a                   # No
-               testl $0x100,0x10(%esp,1)       # Trap flag set?
+               testl $PSL_T,0x10(%esp,1)       # Trap flag set?
                jnz except.3                    # Yes
 except.2a:     jmp exit                        # Exit
 except.3:      leal 0x8(%esp,1),%esp           # Discard err, int no
                iret                            # From interrupt
 
-               /*
-                * Return to user mode from V86 mode.
-                */
-intrtn:        cld                             # String ops inc
-               pushl %ds                       # Address
-               popl %es                        #  data
-               leal 0x3c(%ebp),%edx            # V86 Segment registers
-               movl MEM_BTX_TSS+TSS_ESP1,%esi  # Link stack pointer
-               lodsl                           # INT_V86 args pointer
-               movl %esi,%ebx                  # Saved exception frame
-               testl %eax,%eax                 # INT_V86 args?
-               jz intrtn.2                     # No
-               movl $MEM_BTX_USR,%edi          # User base
-               movl 0x1c(%esi),%ebx            # User ESP
-               movl %eax,(%edi,%ebx,1)         # Restore to user stack
-               leal 0x8(%edi,%eax,1),%edi      # Arg segment registers
-               testb $0x4,-0x6(%edi)           # Return flags?
-               jz intrtn.1                     # No
-               movl 0x30(%ebp),%eax            # Get V86 flags
-               movw %ax,0x18(%esi)             # Set user flags
-intrtn.1:      leal 0x10(%esi),%ebx            # Saved exception frame
-               xchgl %edx,%esi                 # Segment registers
-               movb $0x4,%cl                   # Update seg regs
-               rep                             #  in INT_V86
-               movsl                           #  args
-intrtn.2:      movl %edx,%esi                  # Segment registers
-               leal 0x28(%ebp),%edi            # Set up seg
-               movb $0x4,%cl                   #  regs for
-               rep                             #  later
-               movsl                           #  pop
-               movl %ebx,%esi                  # Restore exception
-               movb $0x5,%cl                   #  frame to
-               rep                             #  supervisor
-               movsl                           #  stack
-               movl %esi,MEM_BTX_TSS+TSS_ESP1  # Link stack pointer
-               popa                            # Restore
-               leal 0x8(%esp,1),%esp           # Discard err, int no
-               popl %es                        # Restore
-               popl %ds                        #  user
-               popl %fs                        #  segment
-               popl %gs                        #  registers
-               iret                            # To user mode
-
-               /*
-                * V86 monitor.
-                */
-v86mon:        cld                             # String ops inc
-               pushl $SEL_SDATA                # Set up for
-               popl %ds                        #  flat addressing
-               pusha                           # Save registers
-               movl %esp,%ebp                  # Address stack frame
-               movzwl 0x2c(%ebp),%edi          # Load V86 CS
-               shll $0x4,%edi                  # To linear
-               movl 0x28(%ebp),%esi            # Load V86 IP
-               addl %edi,%esi                  # Code pointer
-               xorl %ecx,%ecx                  # Zero
-               movb $0x2,%cl                   # 16-bit operands
-               xorl %eax,%eax                  # Zero
-v86mon.1:      lodsb                           # Get opcode
-               cmpb $0x66,%al                  # Operand size prefix?
-               jne v86mon.2                    # No
-               movb $0x4,%cl                   # 32-bit operands
-               jmp v86mon.1                    # Continue
-v86mon.2:      cmpb $0xf4,%al                  # HLT?
-               jne v86mon.3                    # No
-               cmpl $inthlt+0x1,%esi           # Is inthlt?
-               jne v86mon.7                    # No (ignore)
-               jmp intrtn                      # Return to user mode
-v86mon.3:      cmpb $0xf,%al                   # Prefixed instruction?
-               jne v86mon.4                    # No
-               cmpb $0x09,(%esi)               # Is it a WBINVD?
-               je v86wbinvd                    # Yes
-               cmpb $0x30,(%esi)               # Is it a WRMSR?
-               je v86wrmsr                     # Yes
-               cmpb $0x32,(%esi)               # Is it a RDMSR?
-               je v86rdmsr                     # Yes
-               cmpb $0x20,(%esi)               # Is this a
-               jne v86mon.4                    #  MOV EAX,CR0
-               cmpb $0xc0,0x1(%esi)            #  instruction?
-               je v86mov                       # Yes
-v86mon.4:      cmpb $0xfa,%al                  # CLI?
-               je v86cli                       # Yes
-               cmpb $0xfb,%al                  # STI?
-               je v86sti                       # Yes
-               movzwl 0x38(%ebp),%ebx          # Load V86 SS
-               shll $0x4,%ebx                  # To offset
-               pushl %ebx                      # Save
-               addl 0x34(%ebp),%ebx            # Add V86 SP
-               movl 0x30(%ebp),%edx            # Load V86 flags
-               cmpb $0x9c,%al                  # PUSHF/PUSHFD?
-               je v86pushf                     # Yes
-               cmpb $0x9d,%al                  # POPF/POPFD?
-               je v86popf                      # Yes
-               cmpb $0xcd,%al                  # INT imm8?
-               je v86intn                      # Yes
-               cmpb $0xcf,%al                  # IRET/IRETD?
-               je v86iret                      # Yes
-               popl %ebx                       # Restore
-               popa                            # Restore
-               jmp except                      # Handle exception
-v86mon.5:      movl %edx,0x30(%ebp)            # Save V86 flags
-v86mon.6:      popl %edx                       # V86 SS adjustment
-               subl %edx,%ebx                  # Save V86
-               movl %ebx,0x34(%ebp)            #  SP
-v86mon.7:      subl %edi,%esi                  # From linear
-               movl %esi,0x28(%ebp)            # Save V86 IP
-               popa                            # Restore
-               leal 0x8(%esp,1),%esp           # Discard int no, error
-               iret                            # To V86 mode
-
-               /*
-                * Emulate MOV EAX,CR0.
-                */
-v86mov:        movl %cr0,%eax                  # CR0 to
-               movl %eax,0x1c(%ebp)            #  saved EAX
-               incl %esi                       # Adjust IP
-
-               /*
-                * Return from emulating a 0x0f prefixed instruction
-                */
-v86preret:     incl %esi                       # Adjust IP
-               jmp v86mon.7                    # Finish up
-
-               /*
-                * Emulate WBINVD
-                */
-v86wbinvd:     wbinvd                          # Write back and invalidate
-                                               #  cache
-               jmp v86preret                   # Finish up
-               /*
-                * Emulate WRMSR
-                */
-v86wrmsr:      movl 0x18(%ebp),%ecx            # Get users %ecx (MSR to write)
-               movl 0x14(%ebp),%edx            # Load the value
-               movl 0x1c(%ebp),%eax            #  to write
-               wrmsr                           # Write MSR
-               jmp v86preret                   # Finish up
-
-               /*
-                * Emulate RDMSR
-                */
-v86rdmsr:      movl 0x18(%ebp),%ecx            # MSR to read
-               rdmsr                           # Read the MSR
-               movl %eax,0x1c(%ebp)            # Return the value of
-               movl %edx,0x14(%ebp)            #  the MSR to the user
-               jmp v86preret                   # Finish up
-
-               /*
-                * Emulate CLI.
-                */
-v86cli:        andb $~0x2,0x31(%ebp)           # Clear IF
-               jmp v86mon.7                    # Finish up
-
-               /*
-                * Emulate STI.
-                */
-v86sti:        orb $0x2,0x31(%ebp)             # Set IF
-               jmp v86mon.7                    # Finish up
-
-               /*
-                * Emulate PUSHF/PUSHFD.
-                */
-v86pushf:      subl %ecx,%ebx                  # Adjust SP
-               cmpb $0x4,%cl                   # 32-bit
-               je v86pushf.1                   # Yes
-               data16                          # 16-bit (STDALONE ON PURPOSE)
-v86pushf.1:    movl %edx,(%ebx)                # Save flags
-               jmp v86mon.6                    # Finish up
-
-               /*
-                * Emulate IRET/IRETD.
-                */
-v86iret:       movzwl (%ebx),%esi              # Load V86 IP
-               movzwl 0x2(%ebx),%edi           # Load V86 CS
-               leal 0x4(%ebx),%ebx             # Adjust SP
-               movl %edi,0x2c(%ebp)            # Save V86 CS
-               xorl %edi,%edi                  # No ESI adjustment
-
-               /*
-                * Emulate POPF/POPFD (and remainder of IRET/IRETD).
-                */
-v86popf:       cmpb $0x4,%cl                   # 32-bit?
-               je v86popf.1                    # Yes
-               movl %edx,%eax                  # Initialize
-               data16                          # 16-bit (STDALONE ON PURPOSE)
-v86popf.1:     movl (%ebx),%eax                # Load flags
-               addl %ecx,%ebx                  # Adjust SP
-               andl $V86_FLG,%eax              # Merge
-               andl $~V86_FLG,%edx             #  the
-               orl %eax,%edx                   #  flags
-               jmp v86mon.5                    # Finish up
-
-               /*
-                * trap int 15, function 87
-                * reads %es:%si from saved registers on stack to find a 
-                * GDT containing source and destination locations reads
-                * count of words from saved %cx returns success by
-                * setting %ah to 0
-                */
-int15_87:      pushl %eax                      # Save 
-               pushl %ebx                      #  some information 
-               pushl %esi                      #  onto the stack.
-               pushl %edi
-               xorl %eax,%eax                  # clean EAX 
-               xorl %ebx,%ebx                  # clean EBX 
-               movl 0x4(%ebp),%esi             # Get users ESI
-               movl 0x3C(%ebp),%ebx            # store ES
-               movw %si,%ax                    # store SI
-               shll $0x4,%ebx                  # Make it a seg.
-               addl %eax,%ebx                  # ebx=(es<<4)+si
-               movb 0x14(%ebx),%al             # Grab the
-               movb 0x17(%ebx),%ah             #  necessary
-               shll $0x10,%eax                 #  information
-               movw 0x12(%ebx),%ax             #  from
-               movl %eax,%esi                  #  the
-               movb 0x1c(%ebx),%al             #  GDT in order to
-               movb 0x1f(%ebx),%ah             #  have %esi offset
-               shll $0x10,%eax                 #  of source and %edi
-               movw 0x1a(%ebx),%ax             #  of destination.
-               movl %eax,%edi
-               pushl %ds                       # Make:
-               popl %es                        # es = ds
-               pushl %ecx                      # stash ECX
-               xorl %ecx,%ecx                  # highw of ECX is clear
-               movw 0x18(%ebp),%cx             # Get users ECX
-               shll $0x1,%ecx                  # Convert from num words to num
-                                               #  bytes
-               rep                             # repeat...
-               movsb                           #  perform copy.
-               popl %ecx                       # Restore
-               popl %edi
-               popl %esi                       #  previous
-               popl %ebx                       #  register
-               popl %eax                       #  values.
-               movb $0x0,0x1d(%ebp)            # set ah = 0 to indicate
-                                               #  success
-               andb $0xfe,%dl                  # clear CF
-               jmp v86mon.5                    # Finish up
-
-               /*
-                * Reboot the machine by setting the reboot flag and exiting
-                */
+/*
+ * Reboot the machine by setting the reboot flag and exiting
+ */
 reboot:                orb $0x1,btx_hdr+0x7            # Set the reboot flag
                jmp exit                        # Terminate BTX and reboot
 
-               /*
-                * Emulate INT imm8... also make sure to check if it's
-                * int 15/87
-                */
-v86intn:       lodsb                           # Get int no
-               cmpb $0x19,%al                  # is it int 19?
-               je reboot                       #  yes, reboot the machine
-               cmpb $0x15,%al                  # is it int 15?
-               jne v86intn.3                   #  no, skip parse
-               pushl %eax                      # stash EAX
-               movl 0x1c(%ebp),%eax            # users saved EAX
-               cmpb $0x87,%ah                  # is it the memcpy subfunction?
-               jne v86intn.1                   #  no, keep checking
-               popl %eax                       # get the stack straight
-               jmp int15_87                    # its our cue
-v86intn.1:     cmpw $0x4f53,%ax                # is it the delete key callout?
-               jne v86intn.2                   #  no, handle the int normally
-               movb BDA_KEYFLAGS,%al           # get the shift key state
-               andb $0xc,%al                   # mask off just Ctrl and Alt
-               cmpb $0xc,%al                   # are both Ctrl and Alt down?
-               jne v86intn.2                   #  no, handle the int normally
-               popl %eax                       # restore EAX
-               jmp reboot                      # reboot the machine
-v86intn.2:     popl %eax                       # restore EAX
-v86intn.3:     subl %edi,%esi                  # From
-               shrl $0x4,%edi                  #  linear
-               movw %dx,-0x2(%ebx)             # Save flags
-               movw %di,-0x4(%ebx)             # Save CS
-               leal -0x6(%ebx),%ebx            # Adjust SP
-               movw %si,(%ebx)                 # Save IP
-               shll $0x2,%eax                  # Scale
-               movzwl (%eax),%esi              # Load IP
-               movzwl 0x2(%eax),%edi           # Load CS
-               movl %edi,0x2c(%ebp)            # Save CS
-               xorl %edi,%edi                  # No ESI adjustment
-               andb $~0x1,%dh                  # Clear TF
-               jmp v86mon.5                    # Finish up
-
-               /*
-                * Hardware interrupt jump table.
-                */
+/*
+ * Protected Mode Hardware interrupt jump table.
+ */
 intx20:        push $0x8                       # Int 0x20: IRQ0
                jmp int_hw                      # V86 int 0x8
                push $0x9                       # Int 0x21: IRQ1
@@ -797,133 +483,270 @@ intx20:         push $0x8                       # Int 0x20: IRQ0
                push $0x77                      # Int 0x2f: IRQ15
                jmp int_hw                      # V86 int 0x77
 
-               /*
-                * Reflect hardware interrupts.
-                */
-int_hw:        testb $0x2,0xe(%esp,1)          # V86 mode?
-               jz intusr                       # No
-               pushl $SEL_SDATA                # Address
-               popl %ds                        #  data
-               xchgl %eax,(%esp,1)             # Swap EAX, int no
-               pushl %ebp                      # Address
-               movl %esp,%ebp                  #  stack frame
-               pushl %ebx                      # Save
-               shll $0x2,%eax                  # Get int
-               movl (%eax),%eax                #  vector
-               subl $0x6,0x14(%ebp)            # Adjust V86 ESP
-               movzwl 0x18(%ebp),%ebx          # V86 SS
-               shll $0x4,%ebx                  #  * 0x10
-               addl 0x14(%ebp),%ebx            #  + V86 ESP
-               xchgw %ax,0x8(%ebp)             # Swap V86 IP
-               rorl $0x10,%eax                 # Swap words
-               xchgw %ax,0xc(%ebp)             # Swap V86 CS
-               roll $0x10,%eax                 # Swap words
-               movl %eax,(%ebx)                # CS:IP for IRET
-               movl 0x10(%ebp),%eax            # V86 flags
-               movw %ax,0x4(%ebx)              # Flags for IRET
-               andb $~0x3,0x11(%ebp)           # Clear IF, TF
-               popl %ebx                       # Restore
-               popl %ebp                       #  saved
-               popl %eax                       #  registers
-               iret                            # To V86 mode
-
-               /*
-                * Invoke V86 interrupt from user mode, with arguments.
-                */
-intx31:        stc                             # Have btx_v86
-               pushl %eax                      # Missing int no
+/*
+ * Invoke real mode interrupt/function call from user mode with arguments.
+ */
+intx31:        pushl $-1                       # Dummy int no for btx_v86
 
-               /*
-                * Invoke V86 interrupt from user mode.
-                */
-intusr:        std                             # String ops dec
-               pushl %eax                      # Expand
-               pushl %eax                      #  stack
-               pushl %eax                      #  frame
-               pusha                           # Save
+/*
+ * Invoke real mode interrupt/function call from protected mode.
+ *
+ * We place a trampoline on the user stack that will return to rret_tramp
+ * which will reenter protected mode and then finally return to the user
+ * client.
+ *
+ * Kernel frame %esi points to:                Real mode stack frame at MEM_BTX_ESPR:
+ *
+ * -0x00 user %ss                      -0x04 kernel %esp (with full frame)
+ * -0x04 user %esp                     -0x08 btx_v86 pointer
+ * -0x08 user %eflags                  -0x0c flags (only used if interrupt)
+ * -0x0c user %cs                      -0x10 real mode CS:IP return trampoline
+ * -0x10 user %eip                     -0x12 real mode flags
+ * -0x14 int no                                -0x16 real mode CS:IP (target)
+ * -0x18 %eax
+ * -0x1c %ecx
+ * -0x20 %edx
+ * -0x24 %ebx
+ * -0x28 %esp
+ * -0x2c %ebp
+ * -0x30 %esi
+ * -0x34 %edi
+ * -0x38 %gs
+ * -0x3c %fs
+ * -0x40 %ds
+ * -0x44 %es
+ * -0x48 zero %eax (hardware int only)
+ * -0x4c zero %ecx (hardware int only)
+ * -0x50 zero %edx (hardware int only)
+ * -0x54 zero %ebx (hardware int only)
+ * -0x58 zero %esp (hardware int only)
+ * -0x5c zero %ebp (hardware int only)
+ * -0x60 zero %esi (hardware int only)
+ * -0x64 zero %edi (hardware int only)
+ * -0x68 zero %gs (hardware int only)
+ * -0x6c zero %fs (hardware int only)
+ * -0x70 zero %ds (hardware int only)
+ * -0x74 zero %es (hardware int only)
+ */
+int_hw:        cld                             # String ops inc
+               pusha                           # Save gp regs
                pushl %gs                       # Save
-               movl %esp,%eax                  #  seg regs
-               pushl %fs                       #  and
-               pushl %ds                       #  point
-               pushl %es                       #  to them
+               pushl %fs                       #  seg
+               pushl %ds                       #  regs
+               pushl %es
                push $SEL_SDATA                 # Set up
                popl %ds                        #  to
                pushl %ds                       #  address
                popl %es                        #  data
+               leal 0x44(%esp,1),%esi          # Base of frame
+               movl %esp,MEM_BTX_ESPR-0x04             # Save kernel stack pointer
+               movl -0x14(%esi),%eax           # Get Int no
+               cmpl $-1,%eax                   # Hardware interrupt?
+               jne intusr.1                    # Yes
+/*
+ * v86 calls save the btx_v86 pointer on the real mode stack and read
+ * the address and flags from the btx_v86 structure.  For interrupt
+ * handler invocations (VM86 INTx requests), disable interrupts,
+ * tracing, and alignment checking while the handler runs.
+ */
                movl $MEM_BTX_USR,%ebx          # User base
                movl %ebx,%edx                  #  address
-               jc intusr.1                     # If btx_v86
-               xorl %edx,%edx                  # Control flags
-               xorl %ebp,%ebp                  # btx_v86 pointer
-intusr.1:      leal 0x50(%esp,1),%esi          # Base of frame
-               pushl %esi                      # Save
                addl -0x4(%esi),%ebx            # User ESP
-               movl MEM_BTX_TSS+TSS_ESP1,%edi  # Link stack pointer
-               leal -0x4(%edi),%edi            # Adjust for push
-               xorl %ecx,%ecx                  # Zero
-               movb $0x5,%cl                   # Push exception
-               rep                             #  frame on
-               movsl                           #  link stack
-               xchgl %eax,%esi                 # Saved seg regs
-               movl 0x40(%esp,1),%eax          # Get int no
-               testl %edx,%edx                 # Have btx_v86?
-               jz intusr.2                     # No
                movl (%ebx),%ebp                # btx_v86 pointer
-               movb $0x4,%cl                   # Count
-               addl %ecx,%ebx                  # Adjust for pop
-               rep                             # Push saved seg regs
-               movsl                           #  on link stack
                addl %ebp,%edx                  # Flatten btx_v86 ptr
-               leal 0x14(%edx),%esi            # Seg regs pointer
-               movl 0x4(%edx),%eax             # Get int no/address
-               movzwl 0x2(%edx),%edx           # Get control flags
-intusr.2:      movl %ebp,(%edi)                # Push btx_v86 and
-               movl %edi,MEM_BTX_TSS+TSS_ESP1  #  save link stack ptr
-               popl %edi                       # Base of frame
-               xchgl %eax,%ebp                 # Save intno/address
-               movl 0x48(%esp,1),%eax          # Get flags
-               testb $0x2,%dl                  # Simulate CALLF?
-               jnz intusr.3                    # Yes
-               decl %ebx                       # Push flags
-               decl %ebx                       #  on V86
-               movw %ax,(%ebx)                 #  stack
-intusr.3:      movb $0x4,%cl                   # Count
-               subl %ecx,%ebx                  # Push return address
-               movl $inthlt,(%ebx)             #  on V86 stack
-               rep                             # Copy seg regs to
-               movsl                           #  exception frame
-               xchgl %eax,%ecx                 # Save flags
-               movl %ebx,%eax                  # User ESP
-               subl $V86_STK,%eax              # Less bytes
-               ja intusr.4                     #  to
-               xorl %eax,%eax                  #  keep
-intusr.4:      shrl $0x4,%eax                  # Gives segment
-               stosl                           # Set SS
-               shll $0x4,%eax                  # To bytes
-               xchgl %eax,%ebx                 # Swap
-               subl %ebx,%eax                  # Gives offset
-               stosl                           # Set ESP
-               xchgl %eax,%ecx                 # Get flags
-               btsl $0x11,%eax                 # Set VM
-               andb $~0x1,%ah                  # Clear TF
-               stosl                           # Set EFL
-               xchgl %eax,%ebp                 # Get int no/address
-               testb $0x1,%dl                  # Address?
-               jnz intusr.5                    # Yes
-               shll $0x2,%eax                  # Scale
+               movl %edx,MEM_BTX_ESPR-0x08             # Save btx_v86 ptr
+               movl V86_ADDR(%edx),%eax        # Get int no/address
+               movl V86_CTL(%edx),%edx         # Get control flags
+               movl -0x08(%esi),%ebx           # Save user flags in %ebx
+               testl $V86F_ADDR,%edx           # Segment:offset?
+               jnz intusr.4                    # Yes
+               andl $~(PSL_I|PSL_T|PSL_AC),%ebx # Disable interrupts, tracing,
+                                               #  and alignment checking for
+                                               #  interrupt handler
+               jmp intusr.3                    # Skip hardware interrupt
+/*
+ * Hardware interrupts store a NULL btx_v86 pointer and use the
+ * address (interrupt number) from the stack with empty flags.  Also,
+ * push a dummy frame of zeros onto the stack for all the general
+ * purpose and segment registers and clear %eflags.  This gives the
+ * hardware interrupt handler a clean slate.
+ */
+intusr.1:      xorl %edx,%edx                  # Control flags
+               movl %edx,MEM_BTX_ESPR-0x08             # NULL btx_v86 ptr
+               movl $12,%ecx                   # Frame is 12 dwords
+intusr.2:      pushl $0x0                      # Fill frame
+               loop intusr.2                   #  with zeros
+               movl $PSL_RESERVED_DEFAULT,%ebx # Set clean %eflags
+/*
+ * Look up real mode IDT entry for hardware interrupts and VM86 INTx
+ * requests.
+ */
+intusr.3:      shll $0x2,%eax                  # Scale
                movl (%eax),%eax                # Load int vector
-intusr.5:      movl %eax,%ecx                  # Save
-               shrl $0x10,%eax                 # Gives segment
-               stosl                           # Set CS
-               movw %cx,%ax                    # Restore
-               stosl                           # Set EIP
-               leal 0x10(%esp,1),%esp          # Discard seg regs
-               popa                            # Restore
-               iret                            # To V86 mode
+               jmp intusr.5                    # Skip CALLF test
+/*
+ * Panic if V86F_CALLF isn't set with V86F_ADDR.
+ */
+intusr.4:      testl $V86F_CALLF,%edx          # Far call?
+               jnz intusr.5                    # Ok
+               movl %edx,0x30(%esp,1)          # Place VM86 flags in int no
+               movl $badvm86,%esi              # Display bad
+               call putstr                     #  VM86 call
+               popl %es                        # Restore
+               popl %ds                        #  seg
+               popl %fs                        #  regs
+               popl %gs
+               popal                           # Restore gp regs
+               jmp ex_noc                      # Panic
+/*
+ * %eax now holds the segment:offset of the function.
+ * %ebx now holds the %eflags to pass to real mode.
+ * %edx now holds the V86F_* flags.
+ */
+intusr.5:      movw %bx,MEM_BTX_ESPR-0x12              # Pass user flags to real mode
+                                               #  target
+/*
+ * If this is a v86 call, copy the seg regs out of the btx_v86 structure.
+ */
+               movl MEM_BTX_ESPR-0x08,%ecx             # Get btx_v86 ptr
+               jecxz intusr.6                  # Skip for hardware ints
+               leal -0x44(%esi),%edi           # %edi => kernel stack seg regs
+               pushl %esi                      # Save
+               leal V86_ES(%ecx),%esi          # %esi => btx_v86 seg regs
+               movl $4,%ecx                    # Copy seg regs
+               rep                             #  from btx_v86
+               movsl                           #  to kernel stack
+               popl %esi                       # Restore
+intusr.6:      movl -0x08(%esi),%ebx           # Copy user flags to real
+               movl %ebx,MEM_BTX_ESPR-0x0c             #  mode return trampoline
+               movl $rret_tramp,%ebx           # Set return trampoline
+               movl %ebx,MEM_BTX_ESPR-0x10             #  CS:IP
+               movl %eax,MEM_BTX_ESPR-0x16             # Real mode target CS:IP
+               ljmpw $SEL_RCODE,$intusr.7      # Change to 16-bit segment
+               .code16
+intusr.7:      movl %cr0,%eax                  # Leave
+               dec %al                         #  protected
+               movl %eax,%cr0                  #  mode
+               ljmpw $0x0,$intusr.8
+intusr.8:      xorw %ax,%ax                    # Reset %ds
+               movw %ax,%ds                    #  and
+               movw %ax,%ss                    #  %ss
+               lidt ivtdesc                    # Set IVT
+               popl %es                        # Restore
+               popl %ds                        #  seg
+               popl %fs                        #  regs
+               popl %gs
+               popal                           # Restore gp regs
+               movw $MEM_BTX_ESPR-0x16,%sp             # Switch to real mode stack
+               iret                            # Call target routine
+/*
+ * For the return to real mode we setup a stack frame like this on the real
+ * mode stack.  Note that callf calls won't pop off the flags, but we just
+ * ignore that by repositioning %sp to be just above the btx_v86 pointer
+ * so it is aligned.  The stack is relative to MEM_BTX_ESPR.
+ *
+ * -0x04       kernel %esp
+ * -0x08       btx_v86
+ * -0x0c       %eax
+ * -0x10       %ecx
+ * -0x14       %edx
+ * -0x18       %ebx
+ * -0x1c       %esp
+ * -0x20       %ebp
+ * -0x24       %esi
+ * -0x28       %edi
+ * -0x2c       %gs
+ * -0x30       %fs
+ * -0x34       %ds
+ * -0x38       %es
+ * -0x3c       %eflags
+ */
+rret_tramp:    movw $MEM_BTX_ESPR-0x08,%sp             # Reset stack pointer
+               pushal                          # Save gp regs
+               pushl %gs                       # Save
+               pushl %fs                       #  seg
+               pushl %ds                       #  regs
+               pushl %es
+               pushfl                          # Save %eflags
+               cli                             # Disable interrupts
+               std                             # String ops dec
+               xorw %ax,%ax                    # Reset seg
+               movw %ax,%ds                    #  regs
+               movw %ax,%es                    #  (%ss is already 0)
+               lidt idtdesc                    # Set IDT
+               lgdt gdtdesc                    # Set GDT
+               mov %cr0,%eax                   # Switch to protected
+               inc %ax                         #  mode
+               mov %eax,%cr0                   #
+               ljmp $SEL_SCODE,$rret_tramp.1   # To 32-bit code
+               .code32
+rret_tramp.1:  xorl %ecx,%ecx                  # Zero
+               movb $SEL_SDATA,%cl             # Setup
+               movw %cx,%ss                    #  32-bit
+               movw %cx,%ds                    #  seg
+               movw %cx,%es                    #  regs
+               movl MEM_BTX_ESPR-0x04,%esp             # Switch to kernel stack
+               leal 0x44(%esp,1),%esi          # Base of frame
+               andb $~0x2,tss_desc+0x5         # Clear TSS busy
+               movb $SEL_TSS,%cl               # Set task
+               ltr %cx                         #  register
+/*
+ * Now we are back in protected mode.  The kernel stack frame set up
+ * before entering real mode is still intact. For hardware interrupts,
+ * leave the frame unchanged.
+ */
+               cmpl $0,MEM_BTX_ESPR-0x08               # Leave saved regs unchanged
+               jz rret_tramp.3                 #  for hardware ints
+/*
+ * For V86 calls, copy the registers off of the real mode stack onto
+ * the kernel stack as we want their updated values.  Also, initialize
+ * the segment registers on the kernel stack.
+ *
+ * Note that the %esp in the kernel stack after this is garbage, but popa
+ * ignores it, so we don't have to fix it up.
+ */
+               leal -0x18(%esi),%edi           # Kernel stack GP regs
+               pushl %esi                      # Save
+               movl $MEM_BTX_ESPR-0x0c,%esi    # Real mode stack GP regs
+               movl $8,%ecx                    # Copy GP regs from
+               rep                             #  real mode stack
+               movsl                           #  to kernel stack
+               movl $SEL_UDATA,%eax            # Selector for data seg regs
+               movl $4,%ecx                    # Initialize %ds,
+               rep                             #  %es, %fs, and
+               stosl                           #  %gs
+/*
+ * For V86 calls, copy the saved seg regs on the real mode stack back
+ * over to the btx_v86 structure.  Also, conditionally update the
+ * saved eflags on the kernel stack based on the flags from the user.
+ */
+               movl MEM_BTX_ESPR-0x08,%ecx             # Get btx_v86 ptr
+               leal V86_GS(%ecx),%edi          # %edi => btx_v86 seg regs
+               leal MEM_BTX_ESPR-0x2c,%esi             # %esi => real mode seg regs
+               xchgl %ecx,%edx                 # Save btx_v86 ptr
+               movl $4,%ecx                    # Copy seg regs
+               rep                             #  from real mode stack
+               movsl                           #  to btx_v86
+               popl %esi                       # Restore
+               movl V86_CTL(%edx),%edx         # Read V86 control flags
+               testl $V86F_FLAGS,%edx          # User wants flags?
+               jz rret_tramp.3                 # No
+               movl MEM_BTX_ESPR-0x3c,%eax             # Read real mode flags
+               movw %ax,-0x08(%esi)            # Update user flags (low 16)
+/*
+ * Return to the user task
+ */
+rret_tramp.3:  popl %es                        # Restore
+               popl %ds                        #  seg
+               popl %fs                        #  regs
+               popl %gs
+               popal                           # Restore gp regs
+               addl $4,%esp                    # Discard int no
+               iret                            # Return to user mode
 
-               /*
               * System Call.
               */
+/*
+ * System Call.
+ */
 intx30:        cmpl $SYS_EXEC,%eax             # Exec system call?
                jne intx30.1                    # No
                pushl %ss                       # Set up
@@ -937,21 +760,14 @@ intx30:   cmpl $SYS_EXEC,%eax             # Exec system call?
                movl $MEM_BTX_USR,%eax          # User base address
                addl 0xc(%esp,1),%eax           # Change to user
                leal 0x4(%eax),%esp             #  stack
-#ifdef PAGING
-               movl %cr0,%eax                  # Turn
-               andl $~0x80000000,%eax          #  off
-               movl %eax,%cr0                  #  paging
-               xorl %eax,%eax                  # Flush
-               movl %eax,%cr3                  #  TLB
-#endif
                popl %eax                       # Call
                call *%eax                      #  program
 intx30.1:      orb $0x1,%ss:btx_hdr+0x7        # Flag reboot
                jmp exit                        # Exit
 
-               /*
               * Dump structure [EBX] to [EDI], using format string [ESI].
               */
+/*
+ * Dump structure [EBX] to [EDI], using format string [ESI].
+ */
 dump.0:        stosb                           # Save char
 dump:          lodsb                           # Load char
                testb %al,%al                   # End of string?
@@ -976,7 +792,7 @@ dump.1:     testb $DMP_X32,%ch              # Dump long?
 dump.2:        testb $DMP_MEM,%ch              # Dump memory?
                jz dump.8                       # No
                pushl %ds                       # Save
-               testb $0x2,0x52(%ebx)           # V86 mode?
+               testl $PSL_VM,0x50(%ebx)        # V86 mode?
                jnz dump.3                      # Yes
                verr 0x4(%esi)                  # Readable selector?
                jnz dump.3                      # No
@@ -1021,9 +837,9 @@ dump.9:    jmp dump.0                      # Continue
 dump.10:       stosb                           # Terminate string
                ret                             # To caller
 
-               /*
               * Convert EAX, AX, or AL to hex, saving the result to [EDI].
               */
+/*
+ * Convert EAX, AX, or AL to hex, saving the result to [EDI].
+ */
 hex32:         pushl %eax                      # Save
                shrl $0x10,%eax                 # Do upper
                call hex16                      #  16
@@ -1042,9 +858,9 @@ hex8.1:    andb $0xf,%al                   # Get lower 4
                stosb                           # Save char
                ret                             # (Recursive)
 
-               /*
               * Output zero-terminated string [ESI] to the console.
               */
+/*
+ * Output zero-terminated string [ESI] to the console.
+ */
 putstr.0:      call putchr                     # Output char
 putstr:        lodsb                           # Load char
                testb %al,%al                   # End of string?
@@ -1055,9 +871,9 @@ putstr:    lodsb                           # Load char
                .set SIO_FMT,SIOFMT             # 8N1
                .set SIO_DIV,(115200/SIOSPD)    # 115200 / SPD
 
-               /* 
-                * void sio_init(void) 
               */
+/*
+ * void sio_init(void)
+ */
 sio_init:      movw $SIO_PRT+0x3,%dx           # Data format reg
                movb $SIO_FMT|0x80,%al          # Set format
                outb %al,(%dx)                  #  and DLAB
@@ -1073,17 +889,17 @@ sio_init:        movw $SIO_PRT+0x3,%dx           # Data format reg
                outb %al,(%dx)                  #  DTR
                incl %edx                       # Line status reg
 
-               /*
               * void sio_flush(void)
               */
+/*
+ * void sio_flush(void)
+ */
 sio_flush.0:   call sio_getc.1                 # Get character
 sio_flush:     call sio_ischar                 # Check for character
                jnz sio_flush.0                 # Till none
                ret                             # To caller
 
-               /*
               * void sio_putc(int c)
               */
+/*
+ * void sio_putc(int c)
+ */
 sio_putc:      movw $SIO_PRT+0x5,%dx           # Line status reg
                xor %ecx,%ecx                   # Timeout
                movb $0x40,%ch                  #  counter
@@ -1096,27 +912,27 @@ sio_putc.1:      inb (%dx),%al                   # Transmitter
                outb %al,(%dx)                  # Write character
 sio_putc.2:    ret $0x4                        # To caller
 
-               /*
               * int sio_getc(void)
               */
+/*
+ * int sio_getc(void)
+ */
 sio_getc:      call sio_ischar                 # Character available?
                jz sio_getc                     # No
 sio_getc.1:    subb $0x5,%dl                   # Receiver buffer reg
                inb (%dx),%al                   # Read character
                ret                             # To caller
 
-               /*
               * int sio_ischar(void)
               */
+/*
+ * int sio_ischar(void)
+ */
 sio_ischar:    movw $SIO_PRT+0x5,%dx           # Line status register
                xorl %eax,%eax                  # Zero
                inb (%dx),%al                   # Received data
                andb $0x1,%al                   #  ready?
                ret                             # To caller
 
-               /*
               * Output character AL to the serial console.
               */
+/*
+ * Output character AL to the serial console.
+ */
 putchr:        pusha                           # Save
                cmpb $10, %al                   # is it a newline?
                jne putchr.1                    #  no?, then leave
@@ -1129,9 +945,9 @@ putchr.1:  pushl %eax                      # Push the character
                popa                            # Restore
                ret                             # To caller
 #else
-               /*
               * Output character AL to the console.
               */
+/*
+ * Output character AL to the console.
+ */
 putchr:        pusha                           # Save
                xorl %ecx,%ecx                  # Zero for loops
                movb $SCR_MAT,%ah               # Mode/attribute
@@ -1172,24 +988,79 @@ putchr.4:        movw %dx,(%ebx)                 # Update position
                ret                             # To caller
 #endif
 
-               /*
-                * Global descriptor table.
-                *
-                * 16: segment extent lsb
-                * 24: segment base lsb
-                *
-                * 5:TYPE
-                * 2:DPL
-                * 1:PRESENT
-                *
-                * 4:  segment extent msb
-                * 2:  unused
-                * 1:  32 bit, else 16 bit
-                * 1:  limit granularity byte/page units
+               .code16
+/*
+ * Real Mode Hardware interrupt jump table.
+ */
+intr20:        push $0x8                       # Int 0x20: IRQ0
+               jmp int_hwr                     # V86 int 0x8
+               push $0x9                       # Int 0x21: IRQ1
+               jmp int_hwr                     # V86 int 0x9
+               push $0xa                       # Int 0x22: IRQ2
+               jmp int_hwr                     # V86 int 0xa
+               push $0xb                       # Int 0x23: IRQ3
+               jmp int_hwr                     # V86 int 0xb
+               push $0xc                       # Int 0x24: IRQ4
+               jmp int_hwr                     # V86 int 0xc
+               push $0xd                       # Int 0x25: IRQ5
+               jmp int_hwr                     # V86 int 0xd
+               push $0xe                       # Int 0x26: IRQ6
+               jmp int_hwr                     # V86 int 0xe
+               push $0xf                       # Int 0x27: IRQ7
+               jmp int_hwr                     # V86 int 0xf
+               push $0x70                      # Int 0x28: IRQ8
+               jmp int_hwr                     # V86 int 0x70
+               push $0x71                      # Int 0x29: IRQ9
+               jmp int_hwr                     # V86 int 0x71
+               push $0x72                      # Int 0x2a: IRQ10
+               jmp int_hwr                     # V86 int 0x72
+               push $0x73                      # Int 0x2b: IRQ11
+               jmp int_hwr                     # V86 int 0x73
+               push $0x74                      # Int 0x2c: IRQ12
+               jmp int_hwr                     # V86 int 0x74
+               push $0x75                      # Int 0x2d: IRQ13
+               jmp int_hwr                     # V86 int 0x75
+               push $0x76                      # Int 0x2e: IRQ14
+               jmp int_hwr                     # V86 int 0x76
+               push $0x77                      # Int 0x2f: IRQ15
+               jmp int_hwr                     # V86 int 0x77
+/*
+ * Reflect hardware interrupts in real mode.
+ */
+int_hwr:       push %ax                        # Save
+               push %ds                        # Save
+               push %bp                        # Save
+               mov %sp,%bp                     # Address stack frame
+               xchg %bx,6(%bp)                 # Swap BX, int no
+               xor %ax,%ax                     # Set %ds:%bx to
+               shl $2,%bx                      #  point to
+               mov %ax,%ds                     #  IDT entry
+               mov (%bx),%ax                   # Load IP
+               mov 2(%bx),%bx                  # Load CS
+               xchg %ax,4(%bp)                 # Swap saved %ax,%bx with
+               xchg %bx,6(%bp)                 #  CS:IP of handler
+               pop %bp                         # Restore
+               pop %ds                         # Restore
+               lret                            # Jump to handler
+
+/*
+ * Global descriptor table.
+ *
+ * 16: segment extent lsb
+ * 24: segment base lsb
+ *
+ * 5:TYPE
+ * 2:DPL
+ * 1:PRESENT
+ *
+ * 4:  segment extent msb
+ * 2:  unused
+ * 1:  32 bit, else 16 bit
+ * 1:  limit granularity byte/page units
 
               * 8:  segment base msb
               *
               */
+ * 8:  segment base msb
+ *
+ */
                .p2align 4
 gdt:           .word 0x0,0x0,0x0,0x0           # Null entry
                .word 0xffff,0x0,0x9a00,0xcf    # SEL_SCODE
@@ -1198,18 +1069,18 @@ gdt:            .word 0x0,0x0,0x0,0x0           # Null entry
                .word 0xffff,0x0,0x9200,0x0     # SEL_RDATA
                .word 0xffff,MEM_BTX_USR,0xfa00,0xcf# SEL_UCODE
                .word 0xffff,MEM_BTX_USR,0xf200,0xcf# SEL_UDATA
-               .word _TSSLM,MEM_BTX_TSS,0x8900,0x0 # SEL_TSS
+tss_desc:      .word _TSSLM,MEM_BTX_TSS,0x8900,0x0 # SEL_TSS
 gdt.1:
-               /*
               * Pseudo-descriptors.
               */
+/*
+ * Pseudo-descriptors.
+ */
 gdtdesc:       .word gdt.1-gdt-1,gdt,0x0       # GDT
 idtdesc:       .word _IDTLM,MEM_BTX_IDT,0x0    # IDT
 ivtdesc:       .word 0x400-0x0-1,0x0,0x0       # IVT
 
-               /*
               * IDT construction control string.
               */
+/*
+ * IDT construction control string.
+ */
 idtctl:        .byte 0x10,  0x8e               # Int 0x0-0xf
                .word 0x7dfb,intx00             #  (exceptions)
                .byte 0x10,  0x8e               # Int 0x10
@@ -1222,9 +1093,9 @@ idtctl:   .byte 0x10,  0x8e               # Int 0x0-0xf
                .word 0x1,   intx31             #  (V86, null)
                .byte 0x0                       # End of string
 
-               /*
               * Dump format string.
               */
+/*
+ * Dump format string.
+ */
 dmpfmt:        .byte '\n'                      # "\n"
                .ascii "int"                    # "int="
                .byte 0x80|DMP_X32,        0x40 # "00000000  "
@@ -1268,9 +1139,14 @@ dmpfmt:  .byte '\n'                      # "\n"
                .ascii "ss:esp"                 # "ss:esp="
                .byte 0x80|DMP_MEM|DMP_EOL,0x0  # "00 00 ... 00 00\n"
                .asciz "BTX halted\n"           # End
+/*
+ * Bad VM86 call panic
+ */
+badvm86:       .asciz "Invalid VM86 Request\n"
 
-               /*
-                * End of BTX memory.
-                */
+
+/*
+ * End of BTX memory.
+ */
                .p2align 4
 break:
index a81090d..414bb10 100644 (file)
@@ -67,6 +67,7 @@
 #include <stand.h>
 #include <string.h>
 #include <machine/bootinfo.h>
+#include <machine/psl.h>
 #include <sys/reboot.h>
 
 #include "bootstrap.h"
@@ -151,6 +152,11 @@ main(void)
        kargs, initial_howto, initial_bootdev, initial_bootinfo);
 #endif
 
+    /* Initialize the v86 register set to a known-good state. */
+    bzero(&v86, sizeof(v86));
+    v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
+
+
     /* 
      * Initialize the heap as early as possible.  Once this is done, 
      * malloc() is usable.