summaryrefslogtreecommitdiffstats
path: root/stand/pc98/btx
diff options
context:
space:
mode:
authorkevans <kevans@FreeBSD.org>2018-02-12 01:08:44 +0000
committerkevans <kevans@FreeBSD.org>2018-02-12 01:08:44 +0000
commit7d97ee5b28b409c00bfaf12daf5ab497a6038b9d (patch)
tree245306b754606bcf49c0ff17b131b58609b6c7a6 /stand/pc98/btx
parent43b278e1b66cf4de337a17034087ea785031bd6f (diff)
downloadFreeBSD-src-7d97ee5b28b409c00bfaf12daf5ab497a6038b9d.zip
FreeBSD-src-7d97ee5b28b409c00bfaf12daf5ab497a6038b9d.tar.gz
MFC r325834,r325997,326502: Move sys/boot to stand/
This is effectively a direct commit to stable/11, due to differences between stable/11 and head. Changes to DTS in sys/boot/fdt/dts were often accompanied by kernel changes. Many of these were also risc-v updates that likely had many more dependencies to MFC. Because of this, sys/boot/fdt/dts remains as-is while everything else in sys/boot relocates to stand/. r325834: Move sys/boot to stand. Fix all references to new location r325997: Remove empty directories. r326502: Document the sys/boot -> stand move in hier.7 and the top-level README.
Diffstat (limited to 'stand/pc98/btx')
-rw-r--r--stand/pc98/btx/Makefile5
-rw-r--r--stand/pc98/btx/Makefile.inc3
-rw-r--r--stand/pc98/btx/btx/Makefile33
-rw-r--r--stand/pc98/btx/btx/btx.S1104
-rw-r--r--stand/pc98/btx/btxldr/Makefile21
-rw-r--r--stand/pc98/btx/btxldr/btxldr.S430
-rw-r--r--stand/pc98/btx/lib/Makefile10
-rw-r--r--stand/pc98/btx/lib/btxcsu.S49
-rw-r--r--stand/pc98/btx/lib/btxsys.s40
-rw-r--r--stand/pc98/btx/lib/btxv86.h67
-rw-r--r--stand/pc98/btx/lib/btxv86.s85
11 files changed, 1847 insertions, 0 deletions
diff --git a/stand/pc98/btx/Makefile b/stand/pc98/btx/Makefile
new file mode 100644
index 0000000..39f78ed
--- /dev/null
+++ b/stand/pc98/btx/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SUBDIR= btx btxldr lib
+
+.include <bsd.subdir.mk>
diff --git a/stand/pc98/btx/Makefile.inc b/stand/pc98/btx/Makefile.inc
new file mode 100644
index 0000000..265f86d
--- /dev/null
+++ b/stand/pc98/btx/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include "../Makefile.inc"
diff --git a/stand/pc98/btx/btx/Makefile b/stand/pc98/btx/btx/Makefile
new file mode 100644
index 0000000..2755460
--- /dev/null
+++ b/stand/pc98/btx/btx/Makefile
@@ -0,0 +1,33 @@
+# $FreeBSD$
+
+PROG= btx
+INTERNALPROG=
+MAN=
+SRCS= btx.S
+
+.if defined(BOOT_BTX_NOHANG)
+BOOT_BTX_FLAGS=0x1
+.else
+BOOT_BTX_FLAGS=0x0
+.endif
+
+CFLAGS+=-DBTX_FLAGS=${BOOT_BTX_FLAGS}
+CFLAGS+=-I${.CURDIR}/../../../i386/common
+
+.if defined(BTX_SERIAL)
+BOOT_COMCONSOLE_PORT?= 0x238
+BOOT_COMCONSOLE_SPEED?= 9600
+B2SIOFMT?= 0x3
+
+CFLAGS+=-DBTX_SERIAL -DSIOPRT=${BOOT_COMCONSOLE_PORT} \
+ -DSIOFMT=${B2SIOFMT} -DSIOSPD=${BOOT_COMCONSOLE_SPEED}
+.endif
+
+ORG= 0x9000
+
+LDFLAGS=${LDFLAGS_BIN}
+
+.include <bsd.prog.mk>
+
+# XXX: clang integrated-as doesn't grok .codeNN directives yet
+CFLAGS.btx.S= ${CLANG_NO_IAS}
diff --git a/stand/pc98/btx/btx/btx.S b/stand/pc98/btx/btx/btx.S
new file mode 100644
index 0000000..e8710d3
--- /dev/null
+++ b/stand/pc98/btx/btx/btx.S
@@ -0,0 +1,1104 @@
+/*
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ *
+ * $FreeBSD$
+ */
+
+#include <bootargs.h>
+
+/*
+ * Memory layout.
+ */
+ .set MEM_BTX,0x1000 # Start of BTX memory
+ .set MEM_ESP0,0x1800 # Supervisor stack
+ .set MEM_BUF,0x1800 # Scratch buffer
+ .set MEM_ESPR,0x5e00 # Real mode stack
+ .set MEM_IDT,0x5e00 # IDT
+ .set MEM_TSS,0x5f98 # TSS
+ .set MEM_MAP,0x6000 # I/O bit map
+ .set MEM_TSS_END,0x7fff # End of TSS
+ .set MEM_ORG,0x9000 # BTX code
+ .set MEM_USR,0xa000 # Start of user memory
+/*
+ * 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.
+ */
+ .set SEL_SCODE,0x8 # Supervisor code
+ .set SEL_SDATA,0x10 # Supervisor data
+ .set SEL_RCODE,0x18 # Real mode code
+ .set SEL_RDATA,0x20 # Real mode data
+ .set SEL_UCODE,0x28|3 # User code
+ .set SEL_UDATA,0x30|3 # User data
+ .set SEL_TSS,0x38 # TSS
+/*
+ * Task state segment fields.
+ */
+ .set TSS_ESP0,0x4 # PL 0 ESP
+ .set TSS_SS0,0x8 # PL 0 SS
+ .set TSS_MAP,0x66 # I/O bit map base
+/*
+ * System calls.
+ */
+ .set SYS_EXIT,0x0 # Exit
+ .set SYS_EXEC,0x1 # Exec
+/*
+ * 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.
+ */
+ .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.
+ */
+ .set SCR_MAT,0xe1 # Mode/attribute
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+/*
+ * BIOS Data Area locations.
+ */
+ .set BDA_MEM,0x501 # Free memory
+ .set BDA_POS,0x53e # Cursor position
+/*
+ * Derivations, for brevity.
+ */
+ .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0
+ .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base
+ .set _TSSLM,MEM_TSS_END-MEM_TSS # TSS limit
+ .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit
+/*
+ * Code segment.
+ */
+ .globl start
+ .code16
+start: # Start of code
+/*
+ * BTX header.
+ */
+btx_hdr: .byte 0xeb # Machine ID
+ .byte 0xe # Header size
+ .ascii "BTX" # Magic
+ .byte 0x1 # Major version
+ .byte 0x2 # Minor version
+ .byte BTX_FLAGS # Flags
+ .word PAG_CNT-MEM_ORG>>0xc # Paging control
+ .word break-start # Text size
+ .long 0x0 # Entry address
+/*
+ * Initialization routine.
+ */
+init: cli # Disable interrupts
+ xor %ax,%ax # Zero/segment
+ mov %ax,%ss # Set up
+ mov $MEM_ESP0,%sp # stack
+ mov %ax,%es # Address
+ mov %ax,%ds # data
+ pushl $0x2 # Clear
+ popfl # flags
+/*
+ * Initialize memory.
+ */
+ mov $MEM_IDT,%di # Memory to initialize
+ mov $(MEM_ORG-MEM_IDT)/2,%cx # Words to zero
+ rep # Zero-fill
+ stosw # memory
+/*
+ * 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_IDT,%di
+ mov $idtctl,%si # Control string
+init.1: lodsb # Get entry
+ cbw # count
+ xchg %ax,%cx # as word
+ jcxz init.4 # If done
+ lodsb # Get segment
+ xchg %ax,%dx # P:DPL:type
+ lodsw # Get control
+ xchg %ax,%bx # set
+ lodsw # Get handler offset
+ mov $SEL_SCODE,%dh # Segment selector
+init.2: shr %bx # Handle this int?
+ jnc init.3 # No
+ mov %ax,(%di) # Set handler offset
+ mov %dh,0x2(%di) # and selector
+ mov %dl,0x5(%di) # Set P:DPL:type
+ add $0x4,%ax # Next handler
+init.3: lea 0x8(%di),%di # Next entry
+ loop init.2 # Till set done
+ jmp init.1 # Continue
+/*
+ * Initialize TSS.
+ */
+init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0
+ movb $SEL_SDATA,TSS_SS0(%di) # Set SS0
+ movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base
+/*
+ * Bring up the system.
+ */
+ mov $0x2820,%bx # Set protected mode
+ callw setpic # IRQ offsets
+ lidt idtdesc # Set IDT
+ lgdt gdtdesc # Set GDT
+ mov %cr0,%eax # Switch to protected
+ inc %ax # mode
+ mov %eax,%cr0 #
+ ljmp $SEL_SCODE,$init.8 # To 32-bit code
+ .code32
+init.8: xorl %ecx,%ecx # Zero
+ movb $SEL_SDATA,%cl # To 32-bit
+ movw %cx,%ss # stack
+/*
+ * Launch user task.
+ */
+ movb $SEL_TSS,%cl # Set task
+ ltr %cx # register
+ movl $MEM_USR,%edx # User base address
+ movzwl %ss:BDA_MEM,%eax # Get free memory
+ andl $0x7,%eax
+ incl %eax
+ shll $0x11,%eax # To bytes
+ subl $ARGSPACE,%eax # Less arg space
+ subl %edx,%eax # Less base
+ movb $SEL_UDATA,%cl # User data selector
+ pushl %ecx # Set SS
+ pushl %eax # Set ESP
+ push $0x202 # Set flags (IF set)
+ push $SEL_UCODE # Set CS
+ pushl btx_hdr+0xc # Set EIP
+ pushl %ecx # Set GS
+ pushl %ecx # Set FS
+ pushl %ecx # Set DS
+ pushl %ecx # Set ES
+ pushl %edx # Set EAX
+ movb $0x7,%cl # Set remaining
+init.9: push $0x0 # general
+ loop init.9 # registers
+#ifdef BTX_SERIAL
+ call sio_init # setup the serial console
+#endif
+ popa # and initialize
+ popl %es # Initialize
+ popl %ds # user
+ popl %fs # segment
+ popl %gs # registers
+ iret # To user mode
+/*
+ * Exit routine.
+ */
+exit: cli # Disable interrupts
+ movl $MEM_ESP0,%esp # Clear stack
+/*
+ * 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.
+ */
+ lgdt %cs:gdtdesc # Set GDT
+/*
+ * To 16 bits.
+ */
+ ljmpw $SEL_RCODE,$exit.1 # Reload CS
+ .code16
+exit.1: mov $SEL_RDATA,%cl # 16-bit selector
+ mov %cx,%ss # Reload SS
+ mov %cx,%ds # Load
+ mov %cx,%es # remaining
+ mov %cx,%fs # segment
+ mov %cx,%gs # registers
+/*
+ * To real-address mode.
+ */
+ dec %ax # Switch to
+ mov %eax,%cr0 # real mode
+ ljmp $0x0,$exit.2 # Reload CS
+exit.2: xor %ax,%ax # Real mode segment
+ mov %ax,%ss # Reload SS
+ mov %ax,%ds # Address data
+ mov $0x1008,%bx # Set real mode
+ callw setpic # IRQ offsets
+ lidt ivtdesc # Set IVT
+/*
+ * Reboot or await reset.
+ */
+ sti # Enable interrupts
+ testb $0x1,btx_hdr+0x7 # Reboot?
+exit.3: jz exit.3 # No
+ movb $0xa0,%al
+ outb %al,$0x35
+ movb $0x00,%al
+ outb %al,$0xf0 # reboot the machine
+exit.4: jmp exit.4
+/*
+ * Set IRQ offsets by reprogramming 8259A PICs.
+ */
+setpic: in $0x02,%al # Save master
+ push %ax # IMR
+ in $0x0a,%al # Save slave
+ push %ax # IMR
+ movb $0x11,%al # ICW1 to
+ outb %al,$0x00 # master,
+ outb %al,$0x08 # slave
+ movb %bl,%al # ICW2 to
+ outb %al,$0x02 # master
+ movb %bh,%al # ICW2 to
+ outb %al,$0x0a # slave
+ movb $0x80,%al # ICW3 to
+ outb %al,$0x02 # master
+ movb $0x7,%al # ICW3 to
+ outb %al,$0x0a # slave
+ movb $0x1d,%al # ICW4 to
+ outb %al,$0x02 # master,
+ movb $0x9,%al # ICW4 to
+ outb %al,$0x0a # slave
+ pop %ax # Restore slave
+ outb %al,$0x0a # IMR
+ pop %ax # Restore master
+ outb %al,$0x02 # IMR
+ retw # To caller
+ .code32
+/*
+ * Exception jump table.
+ */
+intx00: push $0x0 # Int 0x0: #DE
+ jmp ex_noc # Divide error
+ push $0x1 # Int 0x1: #DB
+ jmp ex_noc # Debug
+ push $0x3 # Int 0x3: #BP
+ jmp ex_noc # Breakpoint
+ push $0x4 # Int 0x4: #OF
+ jmp ex_noc # Overflow
+ push $0x5 # Int 0x5: #BR
+ jmp ex_noc # BOUND range exceeded
+ push $0x6 # Int 0x6: #UD
+ jmp ex_noc # Invalid opcode
+ push $0x7 # Int 0x7: #NM
+ jmp ex_noc # Device not available
+ push $0x8 # Int 0x8: #DF
+ jmp except # Double fault
+ push $0xa # Int 0xa: #TS
+ jmp except # Invalid TSS
+ push $0xb # Int 0xb: #NP
+ jmp except # Segment not present
+ push $0xc # Int 0xc: #SS
+ jmp except # Stack segment fault
+ push $0xd # Int 0xd: #GP
+ 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
+/*
+ * Save a zero error code.
+ */
+ex_noc: pushl (%esp,1) # Duplicate int no
+ movb $0x0,0x4(%esp,1) # Fake error code
+/*
+ * Handle exception.
+ */
+except: cld # String ops inc
+ pushl %ds # Save
+ pushl %es # most
+ pusha # registers
+ pushl %gs # Set GS
+ pushl %fs # Set FS
+ pushl %ds # Set DS
+ pushl %es # Set ES
+ cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode?
+ jne except.1 # No
+ pushl %ss # Set SS
+ jmp except.2 # Join common code
+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
+ movl %esp,%ebx # Stack frame
+ movl $dmpfmt,%esi # Dump format string
+ movl $MEM_BUF,%edi # Buffer
+ pushl %eax
+ pushl %edx
+wait.1: inb $0x60,%al
+ testb $0x04,%al
+ jz wait.1
+ movb $0xe0,%al
+ outb %al,$0x62
+wait.2: inb $0x60,%al
+ testb $0x01,%al
+ jz wait.2
+ xorl %edx,%edx
+ inb $0x62,%al
+ movb %al,%dl
+ inb $0x62,%al
+ movb %al,%dh
+ inb $0x62,%al
+ inb $0x62,%al
+ inb $0x62,%al
+ movl %edx,%eax
+ shlw $1,%ax
+ movl $BDA_POS,%edx
+ movw %ax,(%edx)
+ popl %edx
+ popl %eax
+ pushl %edi # Dump to
+ call dump # buffer
+ popl %esi # and
+ call putstr # display
+ leal 0x18(%esp,1),%esp # Discard frame
+ popa # Restore
+ popl %es # registers
+ popl %ds # saved
+ cmpb $0x3,(%esp,1) # Breakpoint?
+ je except.3 # Yes
+ cmpb $0x1,(%esp,1) # Debug?
+ jne except.2a # No
+ 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
+
+/*
+ * 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
+
+/*
+ * Protected Mode Hardware interrupt jump table.
+ */
+intx20: push $0x8 # Int 0x20: IRQ0
+ jmp int_hw # V86 int 0x8
+ push $0x9 # Int 0x21: IRQ1
+ jmp int_hw # V86 int 0x9
+ push $0xa # Int 0x22: IRQ2
+ jmp int_hw # V86 int 0xa
+ push $0xb # Int 0x23: IRQ3
+ jmp int_hw # V86 int 0xb
+ push $0xc # Int 0x24: IRQ4
+ jmp int_hw # V86 int 0xc
+ push $0xd # Int 0x25: IRQ5
+ jmp int_hw # V86 int 0xd
+ push $0xe # Int 0x26: IRQ6
+ jmp int_hw # V86 int 0xe
+ push $0xf # Int 0x27: IRQ7
+ jmp int_hw # V86 int 0xf
+ push $0x10 # Int 0x28: IRQ8
+ jmp int_hw # V86 int 0x10
+ push $0x11 # Int 0x29: IRQ9
+ jmp int_hw # V86 int 0x11
+ push $0x12 # Int 0x2a: IRQ10
+ jmp int_hw # V86 int 0x12
+ push $0x13 # Int 0x2b: IRQ11
+ jmp int_hw # V86 int 0x13
+ push $0x14 # Int 0x2c: IRQ12
+ jmp int_hw # V86 int 0x14
+ push $0x15 # Int 0x2d: IRQ13
+ jmp int_hw # V86 int 0x15
+ push $0x16 # Int 0x2e: IRQ14
+ jmp int_hw # V86 int 0x16
+ push $0x17 # Int 0x2f: IRQ15
+ jmp int_hw # V86 int 0x17
+
+/*
+ * Invoke real mode interrupt/function call from user mode with arguments.
+ */
+intx31: pushl $-1 # Dummy int no for btx_v86
+/*
+ * 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_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
+ 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_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_USR,%ebx # User base
+ movl %ebx,%edx # address
+ addl -0x4(%esi),%ebx # User ESP
+ movl (%ebx),%ebp # btx_v86 pointer
+ addl %ebp,%edx # Flatten btx_v86 ptr
+ movl %edx,MEM_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_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
+ 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_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_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_ESPR-0x0c # mode return trampoline
+ movl $rret_tramp,%ebx # Set return trampoline
+ movl %ebx,MEM_ESPR-0x10 # CS:IP
+ movl %eax,MEM_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_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_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_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_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_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_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_ESPR-0x08,%ecx # Get btx_v86 ptr
+ leal V86_GS(%ecx),%edi # %edi => btx_v86 seg regs
+ leal MEM_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_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.
+ */
+intx30: cmpl $SYS_EXEC,%eax # Exec system call?
+ jne intx30.1 # No
+ pushl %ss # Set up
+ popl %es # all
+ pushl %es # segment
+ popl %ds # registers
+ pushl %ds # for the
+ popl %fs # program
+ pushl %fs # we're
+ popl %gs # invoking
+ movl $MEM_USR,%eax # User base address
+ addl 0xc(%esp,1),%eax # Change to user
+ leal 0x4(%eax),%esp # stack
+ 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.0: stosb # Save char
+dump: lodsb # Load char
+ testb %al,%al # End of string?
+ jz dump.10 # Yes
+ testb $0x80,%al # Control?
+ jz dump.0 # No
+ movb %al,%ch # Save control
+ movb $'=',%al # Append
+ stosb # '='
+ lodsb # Get offset
+ pushl %esi # Save
+ movsbl %al,%esi # To
+ addl %ebx,%esi # pointer
+ testb $DMP_X16,%ch # Dump word?
+ jz dump.1 # No
+ lodsw # Get and
+ call hex16 # dump it
+dump.1: testb $DMP_X32,%ch # Dump long?
+ jz dump.2 # No
+ lodsl # Get and
+ call hex32 # dump it
+dump.2: testb $DMP_MEM,%ch # Dump memory?
+ jz dump.8 # No
+ pushl %ds # Save
+ testl $PSL_VM,0x50(%ebx) # V86 mode?
+ jnz dump.3 # Yes
+ verr 0x4(%esi) # Readable selector?
+ jnz dump.3 # No
+ ldsl (%esi),%esi # Load pointer
+ jmp dump.4 # Join common code
+dump.3: lodsl # Set offset
+ xchgl %eax,%edx # Save
+ lodsl # Get segment
+ shll $0x4,%eax # * 0x10
+ addl %edx,%eax # + offset
+ xchgl %eax,%esi # Set pointer
+dump.4: movb $2,%dl # Num lines
+dump.4a: movb $0x10,%cl # Bytes to dump
+dump.5: lodsb # Get byte and
+ call hex8 # dump it
+ decb %cl # Keep count
+ jz dump.6a # If done
+ movb $'-',%al # Separator
+ cmpb $0x8,%cl # Half way?
+ je dump.6 # Yes
+ movb $' ',%al # Use space
+dump.6: stosb # Save separator
+ jmp dump.5 # Continue
+dump.6a: decb %dl # Keep count
+ jz dump.7 # If done
+ movb $0xa,%al # Line feed
+ stosb # Save one
+ movb $7,%cl # Leading
+ movb $' ',%al # spaces
+dump.6b: stosb # Dump
+ decb %cl # spaces
+ jnz dump.6b
+ jmp dump.4a # Next line
+dump.7: popl %ds # Restore
+dump.8: popl %esi # Restore
+ movb $0xa,%al # Line feed
+ testb $DMP_EOL,%ch # End of line?
+ jnz dump.9 # Yes
+ movb $' ',%al # Use spaces
+ stosb # Save one
+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].
+ */
+hex32: pushl %eax # Save
+ shrl $0x10,%eax # Do upper
+ call hex16 # 16
+ popl %eax # Restore
+hex16: call hex16.1 # Do upper 8
+hex16.1: xchgb %ah,%al # Save/restore
+hex8: pushl %eax # Save
+ shrb $0x4,%al # Do upper
+ call hex8.1 # 4
+ popl %eax # Restore
+hex8.1: andb $0xf,%al # Get lower 4
+ cmpb $0xa,%al # Convert
+ sbbb $0x69,%al # to hex
+ das # digit
+ orb $0x20,%al # To lower case
+ stosb # Save char
+ ret # (Recursive)
+/*
+ * Output zero-terminated string [ESI] to the console.
+ */
+putstr.0: call putchr # Output char
+putstr: lodsb # Load char
+ testb %al,%al # End of string?
+ jnz putstr.0 # No
+ ret # To caller
+#ifdef BTX_SERIAL
+ .set SIO_PRT,SIOPRT # Base port
+ .set SIO_FMT,SIOFMT # 8N1
+ .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD
+
+/*
+ * int 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
+ pushl %edx # Save
+ subb $0x3,%dl # Divisor latch reg
+ movw $SIO_DIV,%ax # Set
+ outw %ax,(%dx) # BPS
+ popl %edx # Restore
+ movb $SIO_FMT,%al # Clear
+ outb %al,(%dx) # DLAB
+ incl %edx # Modem control reg
+ movb $0x3,%al # Set RTS,
+ outb %al,(%dx) # DTR
+ incl %edx # Line status reg
+ call sio_getc.1 # Get character
+
+/*
+ * int sio_flush(void)
+ */
+sio_flush: xorl %eax,%eax # Return value
+ xorl %ecx,%ecx # Timeout
+ movb $0x80,%ch # counter
+sio_flush.1: call sio_ischar # Check for character
+ jz sio_flush.2 # Till none
+ loop sio_flush.1 # or counter is zero
+ movb $1, %al # Exhausted all tries
+sio_flush.2: ret # To caller
+
+/*
+ * void sio_putc(int c)
+ */
+sio_putc: movw $SIO_PRT+0x5,%dx # Line status reg
+ xor %ecx,%ecx # Timeout
+ movb $0x40,%ch # counter
+sio_putc.1: inb (%dx),%al # Transmitter
+ testb $0x20,%al # buffer empty?
+ loopz sio_putc.1 # No
+ jz sio_putc.2 # If timeout
+ movb 0x4(%esp,1),%al # Get character
+ subb $0x5,%dl # Transmitter hold reg
+ outb %al,(%dx) # Write character
+sio_putc.2: ret $0x4 # To caller
+
+/*
+ * 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)
+ */
+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.
+ */
+putchr: pusha # Save
+ cmpb $10, %al # is it a newline?
+ jne putchr.1 # no?, then leave
+ push $13 # output a carriage
+ call sio_putc # return first
+ movb $10, %al # restore %al
+putchr.1: pushl %eax # Push the character
+ # onto the stack
+ call sio_putc # Output the character
+ popa # Restore
+ ret # To caller
+#else
+/*
+ * Output character AL to the console.
+ */
+putchr: pusha # Save
+ xorl %ecx,%ecx # Zero for loops
+ movb $SCR_MAT,%ah # Mode/attribute
+ movl $BDA_POS,%ebx # BDA pointer
+ movw (%ebx),%dx # Cursor position
+ movl $0xa0000,%edi
+putchr.1: cmpb $0xa,%al # New line?
+ je putchr.2 # Yes
+ movw %dx,%cx
+ movb %al,(%edi,%ecx,1) # Write char
+ addl $0x2000,%ecx
+ movb %ah,(%edi,%ecx,1) # Write attr
+ addw $0x02,%dx
+ jmp putchr.3
+putchr.2: movw %dx,%ax
+ movb $SCR_COL*2,%dl
+ div %dl
+ incb %al
+ mul %dl
+ movw %ax,%dx
+putchr.3: cmpw $SCR_ROW*SCR_COL*2,%dx
+ jb putchr.4 # No
+ leal 2*SCR_COL(%edi),%esi # New top line
+ movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
+ rep # Scroll
+ movsl # screen
+ movb $0x20,%al # Space
+ xorb %ah,%ah
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+ movw $(SCR_ROW-1)*SCR_COL*2,%dx
+putchr.4: movw %dx,(%ebx) # Update position
+ popa # Restore
+ ret # To caller
+#endif
+
+ .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 $0x10 # Int 0x28: IRQ8
+ jmp int_hwr # V86 int 0x10
+ push $0x11 # Int 0x29: IRQ9
+ jmp int_hwr # V86 int 0x11
+ push $0x12 # Int 0x2a: IRQ10
+ jmp int_hwr # V86 int 0x12
+ push $0x13 # Int 0x2b: IRQ11
+ jmp int_hwr # V86 int 0x13
+ push $0x14 # Int 0x2c: IRQ12
+ jmp int_hwr # V86 int 0x14
+ push $0x15 # Int 0x2d: IRQ13
+ jmp int_hwr # V86 int 0x15
+ push $0x16 # Int 0x2e: IRQ14
+ jmp int_hwr # V86 int 0x16
+ push $0x17 # Int 0x2f: IRQ15
+ jmp int_hwr # V86 int 0x17
+/*
+ * 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
+
+ .p2align 4
+/*
+ * Global descriptor table.
+ */
+gdt: .word 0x0,0x0,0x0,0x0 # Null entry
+ .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
+ .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
+ .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
+ .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
+ .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
+ .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
+tss_desc: .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
+gdt.1:
+/*
+ * Pseudo-descriptors.
+ */
+gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT
+idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT
+ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT
+/*
+ * IDT construction control string.
+ */
+idtctl: .byte 0x10, 0x8e # Int 0x0-0xf
+ .word 0x7dfb,intx00 # (exceptions)
+ .byte 0x10, 0x8e # Int 0x10
+ .word 0x1, intx10 # (exception)
+ .byte 0x10, 0x8e # Int 0x20-0x2f
+ .word 0xffff,intx20 # (hardware)
+ .byte 0x1, 0xee # int 0x30
+ .word 0x1, intx30 # (system call)
+ .byte 0x2, 0xee # Int 0x31-0x32
+ .word 0x1, intx31 # (V86, null)
+ .byte 0x0 # End of string
+/*
+ * Dump format string.
+ */
+dmpfmt: .byte '\n' # "\n"
+ .ascii "int" # "int="
+ .byte 0x80|DMP_X32, 0x40 # "00000000 "
+ .ascii "err" # "err="
+ .byte 0x80|DMP_X32, 0x44 # "00000000 "
+ .ascii "efl" # "efl="
+ .byte 0x80|DMP_X32, 0x50 # "00000000 "
+ .ascii "eip" # "eip="
+ .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
+ .ascii "eax" # "eax="
+ .byte 0x80|DMP_X32, 0x34 # "00000000 "
+ .ascii "ebx" # "ebx="
+ .byte 0x80|DMP_X32, 0x28 # "00000000 "
+ .ascii "ecx" # "ecx="
+ .byte 0x80|DMP_X32, 0x30 # "00000000 "
+ .ascii "edx" # "edx="
+ .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
+ .ascii "esi" # "esi="
+ .byte 0x80|DMP_X32, 0x1c # "00000000 "
+ .ascii "edi" # "edi="
+ .byte 0x80|DMP_X32, 0x18 # "00000000 "
+ .ascii "ebp" # "ebp="
+ .byte 0x80|DMP_X32, 0x20 # "00000000 "
+ .ascii "esp" # "esp="
+ .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n"
+ .ascii "cs" # "cs="
+ .byte 0x80|DMP_X16, 0x4c # "0000 "
+ .ascii "ds" # "ds="
+ .byte 0x80|DMP_X16, 0xc # "0000 "
+ .ascii "es" # "es="
+ .byte 0x80|DMP_X16, 0x8 # "0000 "
+ .ascii " " # " "
+ .ascii "fs" # "fs="
+ .byte 0x80|DMP_X16, 0x10 # "0000 "
+ .ascii "gs" # "gs="
+ .byte 0x80|DMP_X16, 0x14 # "0000 "
+ .ascii "ss" # "ss="
+ .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n"
+ .ascii "cs:eip" # "cs:eip="
+ .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\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.
+ */
+ .p2align 4
+break:
diff --git a/stand/pc98/btx/btxldr/Makefile b/stand/pc98/btx/btxldr/Makefile
new file mode 100644
index 0000000..47e83a0
--- /dev/null
+++ b/stand/pc98/btx/btxldr/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+PROG= btxldr
+INTERNALPROG=
+MAN=
+SRCS= btxldr.S
+
+CFLAGS+=-DLOADER_ADDRESS=${LOADER_ADDRESS}
+CFLAGS+=-I${.CURDIR}/../../../i386/common
+
+.if defined(BTXLDR_VERBOSE)
+CFLAGS+=-DBTXLDR_VERBOSE
+.endif
+
+ORG=${LOADER_ADDRESS}
+LDFLAGS=${LDFLAGS_BIN}
+
+.include <bsd.prog.mk>
+
+# XXX: clang integrated-as doesn't grok .codeNN directives yet
+CFLAGS.btxldr.S= ${CLANG_NO_IAS}
diff --git a/stand/pc98/btx/btxldr/btxldr.S b/stand/pc98/btx/btxldr/btxldr.S
new file mode 100644
index 0000000..9a6483f
--- /dev/null
+++ b/stand/pc98/btx/btxldr/btxldr.S
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ *
+ * $FreeBSD$
+ */
+
+#include <bootargs.h>
+
+/*
+ * Prototype BTX loader program, written in a couple of hours. The
+ * real thing should probably be more flexible, and in C.
+ */
+
+/*
+ * Memory locations.
+ */
+ .set MEM_STUB,0x600 # Real mode stub
+ .set MEM_ESP,0x1000 # New stack pointer
+ .set MEM_TBL,0x5000 # BTX page tables
+ .set MEM_ENTRY,0x9010 # BTX entry point
+ .set MEM_DATA,start+0x1000 # Data segment
+/*
+ * Segment selectors.
+ */
+ .set SEL_SCODE,0x8 # 4GB code
+ .set SEL_SDATA,0x10 # 4GB data
+ .set SEL_RCODE,0x18 # 64K code
+ .set SEL_RDATA,0x20 # 64K data
+/*
+ * Paging constants.
+ */
+ .set PAG_SIZ,0x1000 # Page size
+ .set PAG_ENT,0x4 # Page entry size
+/*
+ * Screen constants.
+ */
+ .set SCR_MAT,0xe1 # Mode/attribute
+ .set SCR_COL,0x50 # Columns per row
+ .set SCR_ROW,0x19 # Rows per screen
+/*
+ * BIOS Data Area locations.
+ */
+ .set BDA_MEM,0xa1501 # Free memory
+ .set BDA_POS,0xa153e # Cursor position
+/*
+ * Required by aout gas inadequacy.
+ */
+ .set SIZ_STUB,0x1a # Size of stub
+/*
+ * We expect to be loaded by boot2 at the origin defined in ./Makefile.
+ */
+ .globl start
+/*
+ * BTX program loader for ELF clients.
+ */
+start: cld # String ops inc
+ cli
+gdcwait.1: inb $0x60,%al
+ testb $0x04,%al
+ jz gdcwait.1
+ movb $0xe0,%al
+ outb %al,$0x62
+ nop
+gdcwait.2: inb $0x60,%al
+ testb $0x01,%al
+ jz gdcwait.2
+ inb $0x62,%al
+ movb %al,%dl
+ inb $0x62,%al
+ movb %al,%dh
+ inb $0x62,%al
+ inb $0x62,%al
+ inb $0x62,%al
+ shlw $1,%dx
+ movl $BDA_POS,%ebx
+ movw %dx,(%ebx)
+ movl $m_logo,%esi # Identify
+ call putstr # ourselves
+ movzwl BDA_MEM,%eax # Get base memory
+ andl $0x7,%eax
+ incl %eax
+ shll $0x11,%eax # in bytes
+ movl %eax,%ebp # Base of user stack
+#ifdef BTXLDR_VERBOSE
+ movl $m_mem,%esi # Display
+ call hexout # amount of
+ call putstr # base memory
+#endif
+ lgdt gdtdesc # Load new GDT
+/*
+ * Relocate caller's arguments.
+ */
+#ifdef BTXLDR_VERBOSE
+ movl $m_esp,%esi # Display
+ movl %esp,%eax # caller
+ call hexout # stack
+ call putstr # pointer
+ movl $m_args,%esi # Format string
+ leal 0x4(%esp),%ebx # First argument
+ movl $0x6,%ecx # Count
+start.1: movl (%ebx),%eax # Get argument and
+ addl $0x4,%ebx # bump pointer
+ call hexout # Display it
+ loop start.1 # Till done
+ call putstr # End message
+#endif
+ movl BA_BOOTINFO+4(%esp),%esi # Source: bootinfo
+ cmpl $0x0, %esi # If the bootinfo pointer
+ je start_null_bi # is null, don't copy it
+ movl BI_SIZE(%esi),%ecx # Allocate space
+ subl %ecx,%ebp # for bootinfo
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # it
+ movl %ebp,BA_BOOTINFO+4(%esp) # Update pointer
+ movl %edi,%ebp # Restore base pointer
+#ifdef BTXLDR_VERBOSE
+ movl $m_rel_bi,%esi # Display
+ movl %ebp,%eax # bootinfo
+ call hexout # relocation
+ call putstr # message
+#endif
+start_null_bi: movl $BOOTARGS_SIZE,%ecx # Fixed size of arguments
+ testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data
+ jz start_fixed # Skip if the flag is not set
+ addl BOOTARGS_SIZE+4(%esp),%ecx # Add size of variable args
+start_fixed: subl $ARGOFF,%ebp # Place args at fixed offset
+ leal 0x4(%esp),%esi # Source
+ movl %ebp,%edi # Destination
+ rep # Copy
+ movsb # them
+#ifdef BTXLDR_VERBOSE
+ movl $m_rel_args,%esi # Display
+ movl %ebp,%eax # argument
+ call hexout # relocation
+ call putstr # message
+#endif
+/*
+ * Set up BTX kernel.
+ */
+ movl $MEM_ESP,%esp # Set up new stack
+ movl $MEM_DATA,%ebx # Data segment
+ movl $m_vers,%esi # Display BTX
+ call putstr # version message
+ movb 0x5(%ebx),%al # Get major version
+ addb $'0',%al # Display
+ call putchr # it
+ movb $'.',%al # And a
+ call putchr # dot
+ movb 0x6(%ebx),%al # Get minor
+ xorb %ah,%ah # version
+ movb $0xa,%dl # Divide
+ divb %dl,%al # by 10
+ addb $'0',%al # Display
+ call putchr # tens
+ movb %ah,%al # Get units
+ addb $'0',%al # Display
+ call putchr # units
+ call putstr # End message
+ movl %ebx,%esi # BTX image
+ movzwl 0x8(%ebx),%edi # Compute
+ orl $PAG_SIZ/PAG_ENT-1,%edi # the
+ incl %edi # BTX
+ shll $0x2,%edi # load
+ addl $MEM_TBL,%edi # address
+ pushl %edi # Save load address
+ movzwl 0xa(%ebx),%ecx # Image size
+#ifdef BTXLDR_VERBOSE
+ pushl %ecx # Save image size
+#endif
+ rep # Relocate
+ movsb # BTX
+ movl %esi,%ebx # Keep place
+#ifdef BTXLDR_VERBOSE
+ movl $m_rel_btx,%esi # Restore
+ popl %eax # parameters
+ call hexout # and
+#endif
+ popl %ebp # display
+#ifdef BTXLDR_VERBOSE
+ movl %ebp,%eax # the
+ call hexout # relocation
+ call putstr # message
+#endif
+ addl $PAG_SIZ,%ebp # Display
+#ifdef BTXLDR_VERBOSE
+ movl $m_base,%esi # the
+ movl %ebp,%eax # user
+ call hexout # base
+ call putstr # address
+#endif
+/*
+ * Set up ELF-format client program.
+ */
+ cmpl $0x464c457f,(%ebx) # ELF magic number?
+ je start.3 # Yes
+ movl $e_fmt,%esi # Display error
+ call putstr # message
+start.2: jmp start.2 # Hang
+start.3:
+#ifdef BTXLDR_VERBOSE
+ movl $m_elf,%esi # Display ELF
+ call putstr # message
+ movl $m_segs,%esi # Format string
+#endif
+ movl $0x2,%edi # Segment count
+ movl 0x1c(%ebx),%edx # Get e_phoff
+ addl %ebx,%edx # To pointer
+ movzwl 0x2c(%ebx),%ecx # Get e_phnum
+start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD?
+ jne start.6 # No
+#ifdef BTXLDR_VERBOSE
+ movl 0x4(%edx),%eax # Display
+ call hexout # p_offset
+ movl 0x8(%edx),%eax # Display
+ call hexout # p_vaddr
+ movl 0x10(%edx),%eax # Display
+ call hexout # p_filesz
+ movl 0x14(%edx),%eax # Display
+ call hexout # p_memsz
+ call putstr # End message
+#endif
+ pushl %esi # Save
+ pushl %edi # working
+ pushl %ecx # registers
+ movl 0x4(%edx),%esi # Get p_offset
+ addl %ebx,%esi # as pointer
+ movl 0x8(%edx),%edi # Get p_vaddr
+ addl %ebp,%edi # as pointer
+ movl 0x10(%edx),%ecx # Get p_filesz
+ rep # Set up
+ movsb # segment
+ movl 0x14(%edx),%ecx # Any bytes
+ subl 0x10(%edx),%ecx # to zero?
+ jz start.5 # No
+ xorb %al,%al # Then
+ rep # zero
+ stosb # them
+start.5: popl %ecx # Restore
+ popl %edi # working
+ popl %esi # registers
+ decl %edi # Segments to do
+ je start.7 # If none
+start.6: addl $0x20,%edx # To next entry
+ loop start.4 # Till done
+start.7:
+#ifdef BTXLDR_VERBOSE
+ movl $m_done,%esi # Display done
+ call putstr # message
+#endif
+ movl $start.8,%esi # Real mode stub
+ movl $MEM_STUB,%edi # Destination
+ movl $start.9-start.8,%ecx # Size
+ rep # Relocate
+ movsb # it
+ ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code
+ .code16
+start.8: xorw %ax,%ax # Data
+ movb $SEL_RDATA,%al # selector
+ movw %ax,%ss # Reload SS
+ movw %ax,%ds # Reset
+ movw %ax,%es # other
+ movw %ax,%fs # segment
+ movw %ax,%gs # limits
+ movl %cr0,%eax # Switch to
+ decw %ax # real
+ movl %eax,%cr0 # mode
+ ljmp $0,$MEM_ENTRY # Jump to BTX entry point
+start.9:
+ .code32
+/*
+ * Output message [ESI] followed by EAX in hex.
+ */
+hexout: pushl %eax # Save
+ call putstr # Display message
+ popl %eax # Restore
+ pushl %esi # Save
+ pushl %edi # caller's
+ movl $buf,%edi # Buffer
+ pushl %edi # Save
+ call hex32 # To hex
+ xorb %al,%al # Terminate
+ stosb # string
+ popl %esi # Restore
+hexout.1: lodsb # Get a char
+ cmpb $'0',%al # Leading zero?
+ je hexout.1 # Yes
+ testb %al,%al # End of string?
+ jne hexout.2 # No
+ decl %esi # Undo
+hexout.2: decl %esi # Adjust for inc
+ call putstr # Display hex
+ popl %edi # Restore
+ popl %esi # caller's
+ ret # To caller
+/*
+ * Output zero-terminated string [ESI] to the console.
+ */
+putstr.0: call putchr # Output char
+putstr: lodsb # Load char
+ testb %al,%al # End of string?
+ jne putstr.0 # No
+ ret # To caller
+/*
+ * Output character AL to the console.
+ */
+putchr: pusha # Save
+ xorl %ecx,%ecx # Zero for loops
+ movb $SCR_MAT,%ah # Mode/attribute
+ movl $BDA_POS,%ebx # BDA pointer
+ movw (%ebx),%dx # Cursor position
+ movl $0xa0000,%edi # Regen buffer (color)
+putchr.1: cmpb $0xa,%al # New line?
+ je putchr.2 # Yes
+ movw %dx,%cx
+ movb %al,(%edi,%ecx,1) # Write char
+ addl $0x2000,%ecx
+ movb %ah,(%edi,%ecx,1) # Write attr
+ addw $0x2,%dx
+ jmp putchr.3
+putchr.2: movw %dx,%ax
+ movb $SCR_COL*2,%dl
+ div %dl
+ incb %al
+ mul %dl
+ movw %ax,%dx
+putchr.3: cmpw $SCR_COL*SCR_ROW*2,%dx
+ jb putchr.4 # No
+ leal 2*SCR_COL(%edi),%esi # New top line
+ movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
+ rep # Scroll
+ movsl # screen
+ movb $' ',%al # Space
+ xorb %ah,%ah
+ movb $SCR_COL,%cl # Columns to clear
+ rep # Clear
+ stosw # line
+ movw $(SCR_ROW-1)*SCR_COL*2,%dx
+putchr.4: movw %dx,(%ebx) # Update position
+ shrw $1,%dx
+gdcwait.3: inb $0x60,%al
+ testb $0x04,%al
+ jz gdcwait.3
+ movb $0x49,%al
+ outb %al,$0x62
+ movb %dl,%al
+ outb %al,$0x60
+ movb %dh,%al
+ outb %al,$0x60
+ popa # Restore
+ ret # To caller
+/*
+ * Convert EAX, AX, or AL to hex, saving the result to [EDI].
+ */
+hex32: pushl %eax # Save
+ shrl $0x10,%eax # Do upper
+ call hex16 # 16
+ popl %eax # Restore
+hex16: call hex16.1 # Do upper 8
+hex16.1: xchgb %ah,%al # Save/restore
+hex8: pushl %eax # Save
+ shrb $0x4,%al # Do upper
+ call hex8.1 # 4
+ popl %eax # Restore
+hex8.1: andb $0xf,%al # Get lower 4
+ cmpb $0xa,%al # Convert
+ sbbb $0x69,%al # to hex
+ das # digit
+ orb $0x20,%al # To lower case
+ stosb # Save char
+ ret # (Recursive)
+
+ .data
+ .p2align 4
+/*
+ * Global descriptor table.
+ */
+gdt: .word 0x0,0x0,0x0,0x0 # Null entry
+ .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
+ .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
+ .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
+ .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
+gdt.1:
+gdtdesc: .word gdt.1-gdt-1 # Limit
+ .long gdt # Base
+/*
+ * Messages.
+ */
+m_logo: .asciz " \nBTX loader 1.00 "
+m_vers: .asciz "BTX version is \0\n"
+e_fmt: .asciz "Error: Client format not supported\n"
+#ifdef BTXLDR_VERBOSE
+m_mem: .asciz "Starting in protected mode (base mem=\0)\n"
+m_esp: .asciz "Arguments passed (esp=\0):\n"
+m_args: .asciz"<howto="
+ .asciz" bootdev="
+ .asciz" junk="
+ .asciz" "
+ .asciz" "
+ .asciz" bootinfo=\0>\n"
+m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n"
+m_rel_args: .asciz "Relocated arguments (size=18) to \0\n"
+m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n"
+m_base: .asciz "Client base address is \0\n"
+m_elf: .asciz "Client format is ELF\n"
+m_segs: .asciz "text segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+ .asciz "data segment: offset="
+ .asciz " vaddr="
+ .asciz " filesz="
+ .asciz " memsz=\0\n"
+m_done: .asciz "Loading complete\n"
+#endif
+/*
+ * Uninitialized data area.
+ */
+buf: # Scratch buffer
diff --git a/stand/pc98/btx/lib/Makefile b/stand/pc98/btx/lib/Makefile
new file mode 100644
index 0000000..e5876bc
--- /dev/null
+++ b/stand/pc98/btx/lib/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+PROG= crt0.o
+INTERNALPROG=
+MAN=
+SRCS= btxcsu.S btxsys.s btxv86.s
+CFLAGS+=-I${.CURDIR}/../../../i386/common
+LDFLAGS=-Wl,-r
+
+.include <bsd.prog.mk>
diff --git a/stand/pc98/btx/lib/btxcsu.S b/stand/pc98/btx/lib/btxcsu.S
new file mode 100644
index 0000000..c46f809
--- /dev/null
+++ b/stand/pc98/btx/lib/btxcsu.S
@@ -0,0 +1,49 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $FreeBSD$
+
+#include <bootargs.h>
+
+#
+# BTX C startup code (ELF).
+#
+
+#
+# Globals.
+#
+ .global _start
+#
+# Client entry point.
+#
+_start: cld
+ pushl %eax
+ movl $_edata,%edi
+ movl $_end,%ecx
+ subl %edi, %ecx
+ xorb %al, %al
+ rep
+ stosb
+ popl __base
+ movl %esp,%eax # Set
+ addl $ARGADJ,%eax # argument
+ movl %eax,__args # pointer
+ call main # Invoke client main()
+ call exit # Invoke client exit()
+#
+# Data.
+#
+ .comm __base,4 # Client base address
+ .comm __args,4 # Client arguments
diff --git a/stand/pc98/btx/lib/btxsys.s b/stand/pc98/btx/lib/btxsys.s
new file mode 100644
index 0000000..9c77b42
--- /dev/null
+++ b/stand/pc98/btx/lib/btxsys.s
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $FreeBSD$
+
+#
+# BTX system calls.
+#
+
+#
+# Globals.
+#
+ .global __exit
+ .global __exec
+#
+# Constants.
+#
+ .set INT_SYS,0x30 # Interrupt number
+#
+# System call: exit
+#
+__exit: xorl %eax,%eax # BTX system
+ int $INT_SYS # call 0x0
+#
+# System call: exec
+#
+__exec: movl $0x1,%eax # BTX system
+ int $INT_SYS # call 0x1
diff --git a/stand/pc98/btx/lib/btxv86.h b/stand/pc98/btx/lib/btxv86.h
new file mode 100644
index 0000000..27f6b34
--- /dev/null
+++ b/stand/pc98/btx/lib/btxv86.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+/*
+ * $FreeBSD$
+ */
+
+#ifndef _BTXV86_H_
+#define _BTXV86_H_
+
+#include <sys/types.h>
+#include <machine/psl.h>
+
+#define V86_ADDR 0x10000 /* Segment:offset address */
+#define V86_CALLF 0x20000 /* Emulate far call */
+#define V86_FLAGS 0x40000 /* Return flags */
+
+struct __v86 {
+ uint32_t ctl; /* Control flags */
+ uint32_t addr; /* Interrupt number or address */
+ uint32_t es; /* V86 ES register */
+ uint32_t ds; /* V86 DS register */
+ uint32_t fs; /* V86 FS register */
+ uint32_t gs; /* V86 GS register */
+ uint32_t eax; /* V86 EAX register */
+ uint32_t ecx; /* V86 ECX register */
+ uint32_t edx; /* V86 EDX register */
+ uint32_t ebx; /* V86 EBX register */
+ uint32_t efl; /* V86 eflags register */
+ uint32_t ebp; /* V86 EBP register */
+ uint32_t esi; /* V86 ESI register */
+ uint32_t edi; /* V86 EDI register */
+};
+
+extern struct __v86 __v86; /* V86 interface structure */
+void __v86int(void);
+
+#define v86 __v86
+#define v86int __v86int
+
+extern u_int32_t __base;
+extern u_int32_t __args;
+
+#define PTOV(pa) ((caddr_t)(pa) - __base)
+#define VTOP(va) ((vm_offset_t)(va) + __base)
+#define VTOPSEG(va) (u_int16_t)(VTOP((caddr_t)va) >> 4)
+#define VTOPOFF(va) (u_int16_t)(VTOP((caddr_t)va) & 0xf)
+
+#define V86_CY(x) ((x) & PSL_C)
+#define V86_ZR(x) ((x) & PSL_Z)
+
+void __exit(int) __attribute__((__noreturn__));
+void __exec(caddr_t, ...);
+
+#endif /* !_BTXV86_H_ */
diff --git a/stand/pc98/btx/lib/btxv86.s b/stand/pc98/btx/lib/btxv86.s
new file mode 100644
index 0000000..0d7d111
--- /dev/null
+++ b/stand/pc98/btx/lib/btxv86.s
@@ -0,0 +1,85 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $FreeBSD$
+
+#
+# BTX V86 interface.
+#
+
+#
+# Globals.
+#
+ .global __v86int
+#
+# 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
+ .set V86_EAX,0x18 # V86 EAX
+ .set V86_ECX,0x1c # V86 ECX
+ .set V86_EDX,0x20 # V86 EDX
+ .set V86_EBX,0x24 # V86 EBX
+ .set V86_EFL,0x28 # V86 eflags
+ .set V86_EBP,0x2c # V86 EBP
+ .set V86_ESI,0x30 # V86 ESI
+ .set V86_EDI,0x34 # V86 EDI
+#
+# Other constants.
+#
+ .set INT_V86,0x31 # Interrupt number
+ .set SIZ_V86,0x38 # Size of V86 structure
+#
+# V86 interface function.
+#
+__v86int: popl __v86ret # Save return address
+ pushl $__v86 # Push pointer
+ call __v86_swap # Load V86 registers
+ int $INT_V86 # To BTX
+ call __v86_swap # Load user registers
+ addl $0x4,%esp # Discard pointer
+ pushl __v86ret # Restore return address
+ ret # To user
+#
+# Swap V86 and user registers.
+#
+__v86_swap: xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP
+ xchgl %eax,V86_EAX(%ebp) # Swap EAX
+ xchgl %ecx,V86_ECX(%ebp) # Swap ECX
+ xchgl %edx,V86_EDX(%ebp) # Swap EDX
+ xchgl %ebx,V86_EBX(%ebp) # Swap EBX
+ pushl %eax # Save
+ pushf # Put eflags
+ popl %eax # in EAX
+ xchgl %eax,V86_EFL(%ebp) # Swap
+ pushl %eax # Put EAX
+ popf # in eflags
+ movl 0x8(%esp,1),%eax # Load EBP
+ xchgl %eax,V86_EBP(%ebp) # Swap
+ movl %eax,0x8(%esp,1) # Save EBP
+ popl %eax # Restore
+ xchgl %esi,V86_ESI(%ebp) # Swap ESI
+ xchgl %edi,V86_EDI(%ebp) # Swap EDI
+ xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP
+ ret # To caller
+#
+# V86 interface structure.
+#
+ .comm __v86,SIZ_V86
+ .comm __v86ret,4
OpenPOWER on IntegriCloud