Changeset View
Changeset View
Standalone View
Standalone View
head/sys/boot/pc98/btx/btx/btx.S
Property | Old Value | New Value |
---|---|---|
svn:keywords | null | FreeBSD=%H \ No newline at end of property |
/* | |||||
* 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: |