From 5e0f257b4560979e89beaca51e3761def38b1c15 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 18 Sep 2009 12:18:55 -0700 Subject: [PATCH] boot - Bring in real-mode fixes for BIOS calls * 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 --- sys/boot/pc32/boot2/boot2.c | 6 +- sys/boot/pc32/bootasm.h | 14 +- sys/boot/pc32/btx/btx/Makefile | 4 - sys/boot/pc32/btx/btx/btx.S | 1144 ++++++++++++++++++---------------------- sys/boot/pc32/loader/main.c | 6 + 5 files changed, 527 insertions(+), 647 deletions(-) diff --git a/sys/boot/pc32/boot2/boot2.c b/sys/boot/pc32/boot2/boot2.c index 34bddfbf0d..775c6bddc0 100644 --- a/sys/boot/pc32/boot2/boot2.c +++ b/sys/boot/pc32/boot2/boot2.c @@ -61,6 +61,7 @@ #include #include #include +#include #include @@ -110,8 +111,8 @@ #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; diff --git a/sys/boot/pc32/bootasm.h b/sys/boot/pc32/bootasm.h index 0db08f026a..d570717b7b 100644 --- a/sys/boot/pc32/bootasm.h +++ b/sys/boot/pc32/bootasm.h @@ -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 */ @@ -107,16 +108,15 @@ #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) **********/ diff --git a/sys/boot/pc32/btx/btx/Makefile b/sys/boot/pc32/btx/btx/Makefile index ab638ff58d..2fe3c286aa 100644 --- a/sys/boot/pc32/btx/btx/Makefile +++ b/sys/boot/pc32/btx/btx/Makefile @@ -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 diff --git a/sys/boot/pc32/btx/btx/btx.S b/sys/boot/pc32/btx/btx/btx.S index 633d73df0a..5adc7fd021 100644 --- a/sys/boot/pc32/btx/btx/btx.S +++ b/sys/boot/pc32/btx/btx/btx.S @@ -50,15 +50,23 @@ #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 @@ -67,75 +75,83 @@ .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: diff --git a/sys/boot/pc32/loader/main.c b/sys/boot/pc32/loader/main.c index a81090d144..414bb101c2 100644 --- a/sys/boot/pc32/loader/main.c +++ b/sys/boot/pc32/loader/main.c @@ -67,6 +67,7 @@ #include #include #include +#include #include #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. -- 2.11.4.GIT