Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 8 Mar 2008 16:11:54 -0500
From:      John Nielsen <lists@jnielsen.net>
To:        freebsd-stable@freebsd.org
Cc:        Torfinn Ingolfsen <torfinn.ingolfsen@broadpark.no>, John Baldwin <jhb@freebsd.org>
Subject:   Re: BTX on USB pen drive
Message-ID:  <200803081611.54820.lists@jnielsen.net>
In-Reply-To: <200803071418.43480.lists@jnielsen.net>
References:  <200803061742.34291.vincent@netaktiv.com> <200803070913.12978.jhb@freebsd.org> <200803071418.43480.lists@jnielsen.net>

next in thread | previous in thread | raw e-mail | index | archive | help
--Boundary-00=_aEw0HSXa2q4PZF3
Content-Type: text/plain;
  charset="iso-8859-15"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

On Friday 07 March 2008 02:18:42 pm John Nielsen wrote:
> On Friday 07 March 2008 09:13:12 am John Baldwin wrote:
> > On Thursday 06 March 2008 07:29:40 pm Daniel O'Connor wrote:
> > > On Fri, 7 Mar 2008, Vincent Mialon wrote:
> > > > I tested various options in boot0cfg with no sucess. I also
> > > > tested the howto from
> > > > http://typo.submonkey.net/articles/2006/04/13/installing-freebsd-
> > > >on -u sb-stick-episode-2 with a 6.3 FreeBSD release which boots on
> > > > my pc but doesn't boot on my supermicro server.
> > > >
> > > > Do you have any idea or pointer that may help me find the way to
> > > > boot this usb drive ? I may file a bug report if you want.
> > >
> > > I wanted to make a USB flash drive based installer for FreeBSD but
> > > unfortunately BTX seems to have issues that make it difficult to do
> > > reliably :(
> > >
> > > Here are 2 patches I tried..
> > > http://people.freebsd.org/~kib/realbtx
> > > http://people.freebsd.org/~jhb/patches/btx_crx.patch
> >
> > Try this instead:
> >
> > http://people.freebsd.org/~jhb/patches/btx_real.patch
> >
> > (btx_crx has been in the base system for a while FWIW).  This is
> > somewhat similar to kib's patch but fixes at least one bug I found in
> > kib's patch (and uses some slightly different approaches in a few
> > places).
>
> I have a laptop that does the BTX register-spin thing when booting from
> USB even if I use Grub, so I'll give your patch a try. The first hunk
> doesn't apply cleanly on today's 7-STABLE sources--the new page tables
> entry at line 29 throws it off. I applied that hunk manually and am
> rebuilding now.
>
> FWIW the laptop is an Intel-based Gateway M465-E, and it boots from
> (internal) CD just fine. I don't currently have space or a partition on
> the internal hard drive for a FreeBSD install, hence the USB stick.

Success! I was able to boot my laptop from my USB stick built with the 
btx_real patch (after I modified hunk 1 to work with the 7-STABLE 
sources). Using the same stick on a different (Acer) laptop I was able to 
get farther in the boot than previously--it won't even boot from a 
standard CD, but with the stick it got to the menu (and THEN did a btx 
register dump, but it didn't loop/scroll).

In case anyone (like Torfinn) is interested, I'm attaching my modified 
patch. If you already applied jhb's patch then you should be able to just 
cut out the first hunk from mine and apply it.

JN

--Boundary-00=_aEw0HSXa2q4PZF3
Content-Type: text/plain;
  charset="iso-8859-15";
  name="btx_real_jn.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="btx_real_jn.patch"

--- sys/boot/i386/btx/btx/btx.S.orig	2006-12-06 12:45:35.000000000 -0500
+++ sys/boot/i386/btx/btx/btx.S	2008-03-07 17:48:24.000000000 -0500
@@ -21,10 +21,11 @@
 		.set MEM_BTX,0x1000		# Start of BTX memory
 		.set MEM_ESP0,0x1800		# Supervisor stack
 		.set MEM_BUF,0x1800		# Scratch buffer
-		.set MEM_ESP1,0x1e00		# Link stack
-		.set MEM_IDT,0x1e00		# IDT
-		.set MEM_TSS,0x1f98		# TSS
-		.set MEM_MAP,0x2000		# I/O bit map
+		.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_DIR,0x4000		# Page directory
 		.set MEM_TBL,0x5000		# Page tables
 		.set MEM_ORG,0x9000		# BTX code
@@ -49,7 +50,6 @@
  */
 		.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.
@@ -57,10 +57,20 @@
 		.set SYS_EXIT,0x0		# Exit
 		.set SYS_EXEC,0x1		# Exec
 /*
- * V86 constants.
+ * Fields in V86 interface structure.
  */
-		.set V86_FLG,0x208eff		# V86 flag mask
-		.set V86_STK,0x400		# V86 stack allowance
+		.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.
  */
@@ -78,7 +88,6 @@
  * BIOS Data Area locations.
  */
 		.set BDA_MEM,0x413		# Free memory
-		.set BDA_KEYFLAGS,0x417		# Keyboard shift-state flags
 		.set BDA_SCR,0x449		# Video mode
 		.set BDA_POS,0x450		# Cursor position
 		.set BDA_BOOT,0x472		# Boot howto flag
@@ -86,7 +95,6 @@
  * Derivations, for brevity.
  */
 		.set _ESP0H,MEM_ESP0>>0x8	# Byte 1 of ESP0
-		.set _ESP1H,MEM_ESP1>>0x8	# Byte 1 of ESP1
 		.set _TSSIO,MEM_MAP-MEM_TSS	# TSS I/O base
 		.set _TSSLM,MEM_DIR-MEM_TSS-1	# TSS limit
 		.set _IDTLM,MEM_TSS-MEM_IDT-1	# IDT limit
@@ -103,7 +111,7 @@
 		.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_ORG>>0xc	# Paging control
 		.word break-start		# Text size
@@ -124,13 +132,24 @@
  */
 		mov $MEM_IDT,%di		# Memory to initialize
 		mov $(MEM_ORG-MEM_IDT)/2,%cx	# Words to zero
-		push %di			# Save
 		rep				# Zero-fill
 		stosw				#  memory
-		pop %di				# Restore
+/*
+ * 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
@@ -156,7 +175,6 @@
  */
 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
 /*
@@ -325,10 +343,6 @@
 		retw				# To caller
 		.code32
 /*
- * Initiate return from V86 mode to user mode.
- */
-inthlt: 	hlt				# To supervisor mode
-/*
  * Exception jump table.
  */
 intx00: 	push $0x0			# Int 0x0: #DE
@@ -354,18 +368,12 @@
 		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.
  */
 ex_noc: 	pushl (%esp,1)			# Duplicate int no
@@ -377,24 +385,17 @@
 		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
@@ -418,234 +419,6 @@
 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_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_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:	xchgl %edx,%esi			# Segment registers
-		leal 0x28(%ebp),%edi		# Set up seg
-		movb $0x4,%cl			#  regs for
-		rep				#  later
-		movsl				#  pop
-		xchgl %ebx,%esi			# Restore exception
-		movb $0x5,%cl			#  frame to
-		rep				#  supervisor
-		movsl				#  stack
-		movl %esi,MEM_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 MOV reg,CRx?
-		je v86mov			# Yes
-v86mon.4:	cmpb $0xfa,%al			# CLI?
-		je v86cli			# Yes
-		cmpb $0xfb,%al			# STI?
-		je v86sti			# Yes
-		cmpb $0xcc,%al			# INT3?
-		je v86mon.7			# Yes, ignore
-		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 reg,CRx.
- */
-v86mov: 	movb 0x1(%esi),%bl		# Fetch Mod R/M byte
-		testb $0x10,%bl			# Read CR2 or CR3?
-		jnz v86mov.1			# Yes
-		movl %cr0,%eax			# Read CR0
-		testb $0x20,%bl			# Read CR4 instead?
-		jz v86mov.2			# No
-		movl %cr4,%eax			# Read CR4
-		jmp v86mov.2
-v86mov.1:	movl %cr2,%eax			# Read CR2
-		testb $0x08,%bl			# Read CR3 instead?
-		jz v86mov.2			# No
-		movl %cr3,%eax			# Read CR3
-v86mov.2:	andl $0x7,%ebx			# Compute offset in
-		shl $2,%ebx			#  frame of destination
-		neg %ebx			#  register
-		movl %eax,0x1c(%ebp,%ebx,1)	# Store CR to reg
-		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 user's %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
-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
-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 %esi			# Save 
-		pushl %edi			#  registers
-		movl 0x3C(%ebp),%edi		# Load ES
-		movzwl 0x4(%ebp),%eax		# Load user's SI
-		shll $0x4,%edi			# EDI = (ES << 4) +
-		addl %eax,%edi			#   SI
-		movl 0x11(%edi),%eax		# Read base of
-		movb 0x17(%edi),%al		#  GDT entry
-		ror $8,%eax			#  for source
-		xchgl %eax,%esi			#  into %esi
-		movl 0x19(%edi),%eax		# Read base of
-		movb 0x1f(%edi),%al		#  GDT entry for
-		ror $8,%eax			#  destination
-		xchgl %eax,%edi			#  into %edi
-		pushl %ds			# Make:
-		popl %es			# es = ds
-		movzwl 0x18(%ebp),%ecx		# Get user's CX
-		shll $0x1,%ecx			# Convert count from words
-		rep				# repeat...
-		movsb				#  perform copy.
-		popl %edi			# Restore
-		popl %esi			#  registers
-		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
@@ -654,36 +427,7 @@
 		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.1			#  no, skip parse
-		cmpb $0x87,0x1d(%ebp)		# is it the memcpy subfunction?
-		je int15_87			#  yes
-		cmpw $0x4f53,0x1c(%ebp)		# is it the delete key callout?
-		jne v86intn.1			#  no, handle the int normally
-		movb BDA_KEYFLAGS,%ch		# get the shift key state
-		andb $0xc,%ch			# mask off just Ctrl and Alt
-		cmpb $0xc,%ch			# are both Ctrl and Alt down?
-		je reboot			# yes, reboot the machine
-v86intn.1:	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
@@ -717,127 +461,239 @@
 		jmp int_hw			# V86 int 0x76
 		push $0x77			# Int 0x2f: IRQ15
 		jmp int_hw			# V86 int 0x77
+
 /*
- * Reflect hardware interrupts.
+ * Invoke real mode interrupt/function call from user mode with arguments.
  */
-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 V86 interrupt from user mode.
- */
-intusr: 	std				# String ops dec
-		pushl %eax			# Expand
-		pushl %eax			#  stack
-		pushl %eax			#  frame
-		pusha				# Save
+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
+ */
+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 -0x14(%esi),%eax		# Get Int no
+		cmpl $-1,%eax			# Hardware interrupt?
+		jne intusr.2			# Yes
+/*
+ * v86 calls save the btx_v86 pointer on the real mode stack and read the
+ * address and flags from the btx_v86 structure.
+ */
 		movl $MEM_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_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_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
+		movl %edx,MEM_ESPR-0x08		# Save btx_v86 ptr
+		movl -0x08(%esi),%ebx		# Pass user flags to
+		movw %bx,MEM_ESPR-0x12		#  real mode target
+		movl V86_ADDR(%edx),%eax	# Get int no/address
+		movl V86_CTL(%edx),%edx		# Get control flags
+		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, we clear
+ * the segment registers for the interrupt handler and ensure interrupts
+ * are disabled when the interrupt handler is invoked.
+ */
+intusr.2:	xorl %edx,%edx			# Control flags
+		movl %edx,MEM_ESPR-0x08		# NULL btx_v86 ptr
+		movl %edx,-0x38(%esi)		# Real mode %gs of 0
+		movl %edx,-0x3c(%esi)		# Real mode %fs of 0
+		movl %edx,-0x40(%esi)		# Real mode %ds of 0
+		movl %edx,-0x44(%esi)		# Real mode %es of 0
+		movl -0x08(%esi),%ebx		# Pass user flags with
+		andl $~0x200,%ebx		#  interrupts disabled
+		movw %bx,MEM_ESPR-0x12		#  to real mode target
+/*
+ * %eax now holds either the interrupt number or segment:offset of function.
+ * %edx now holds the V86F_* flags.
+ */
+intusr.3:	testl $V86F_ADDR,%edx		# Segment:offset?
+		jnz intusr.4			# Yes
 		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
+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
+/*
+ * If this is a v86 call, copy the seg regs out of the btx_v86 structure.
+ */
+intusr.5:	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 %esp,MEM_ESPR-0x04		# Save kernel stack pointer
+		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.  Copy the registers off of the real
+ * mode stack onto the kernel stack.  Also, initialize all the seg regs 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
+		popl %esi			# Restore
+		movl $SEL_UDATA,%eax		# Selector for data seg regs
+		movl $4,%ecx			# Initialize %ds,
+		rep				#  %es, %fs, and
+		stosl				#  %gs
+/*
+ * If this was a V86 call, 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
+		jecxz rret_tramp.3		# Skip for hardware ints
+		leal V86_GS(%ecx),%edi		# %edi => btx_v86 seg regs
+		pushl %esi			# Save
+		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.
  */
@@ -1086,6 +942,61 @@
 		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 $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
+
 		.p2align 4
 /*
  * Global descriptor table.
@@ -1097,7 +1008,7 @@
 		.word 0xffff,0x0,0x9200,0x0	# SEL_RDATA
 		.word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
 		.word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
-		.word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
+tss_desc:	.word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
 gdt.1:
 /*
  * Pseudo-descriptors.
@@ -1166,6 +1077,11 @@
 		.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

--Boundary-00=_aEw0HSXa2q4PZF3--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200803081611.54820.lists>