1ca987d46SWarner Losh/* 2ca987d46SWarner Losh * Copyright (c) 1998 Robert Nordier 3ca987d46SWarner Losh * All rights reserved. 4ca987d46SWarner Losh * 5ca987d46SWarner Losh * Redistribution and use in source and binary forms are freely 6ca987d46SWarner Losh * permitted provided that the above copyright notice and this 7ca987d46SWarner Losh * paragraph and the following disclaimer are duplicated in all 8ca987d46SWarner Losh * such forms. 9ca987d46SWarner Losh * 10ca987d46SWarner Losh * This software is provided "AS IS" and without any express or 11ca987d46SWarner Losh * implied warranties, including, without limitation, the implied 12ca987d46SWarner Losh * warranties of merchantability and fitness for a particular 13ca987d46SWarner Losh * purpose. 14ca987d46SWarner Losh */ 15ca987d46SWarner Losh 16ca987d46SWarner Losh#include <bootargs.h> 17ca987d46SWarner Losh 18ca987d46SWarner Losh/* 19ca987d46SWarner Losh * Memory layout. 20ca987d46SWarner Losh */ 21ca987d46SWarner Losh .set MEM_BTX,0x1000 # Start of BTX memory 22ca987d46SWarner Losh .set MEM_ESP0,0x1800 # Supervisor stack 23ca987d46SWarner Losh .set MEM_BUF,0x1800 # Scratch buffer 24ca987d46SWarner Losh .set MEM_ESPR,0x5e00 # Real mode stack 25ca987d46SWarner Losh .set MEM_IDT,0x5e00 # IDT 26ca987d46SWarner Losh .set MEM_TSS,0x5f98 # TSS 27ca987d46SWarner Losh .set MEM_MAP,0x6000 # I/O bit map 28ca987d46SWarner Losh .set MEM_TSS_END,0x7fff # End of TSS 29ca987d46SWarner Losh .set MEM_ORG,0x9000 # BTX code 30ca987d46SWarner Losh .set MEM_USR,0xa000 # Start of user memory 31ca987d46SWarner Losh/* 32ca987d46SWarner Losh * Paging control. 33ca987d46SWarner Losh */ 34ca987d46SWarner Losh .set PAG_SIZ,0x1000 # Page size 35ca987d46SWarner Losh .set PAG_CNT,0x1000 # Pages to map 36ca987d46SWarner Losh/* 37ca987d46SWarner Losh * Fields in %eflags. 38ca987d46SWarner Losh */ 39ca987d46SWarner Losh .set PSL_RESERVED_DEFAULT,0x00000002 40ca987d46SWarner Losh .set PSL_T,0x00000100 # Trap flag 41ca987d46SWarner Losh .set PSL_I,0x00000200 # Interrupt enable flag 42ca987d46SWarner Losh .set PSL_D,0x00000400 # String instruction direction 43ca987d46SWarner Losh .set PSL_NT,0x00004000 # Nested task flag 44ca987d46SWarner Losh .set PSL_VM,0x00020000 # Virtual 8086 mode flag 45ca987d46SWarner Losh .set PSL_AC,0x00040000 # Alignment check flag 46ca987d46SWarner Losh/* 47ca987d46SWarner Losh * Segment selectors. 48ca987d46SWarner Losh */ 49ca987d46SWarner Losh .set SEL_SCODE,0x8 # Supervisor code 50ca987d46SWarner Losh .set SEL_SDATA,0x10 # Supervisor data 51ca987d46SWarner Losh .set SEL_RCODE,0x18 # Real mode code 52ca987d46SWarner Losh .set SEL_RDATA,0x20 # Real mode data 53ca987d46SWarner Losh .set SEL_UCODE,0x28|3 # User code 54ca987d46SWarner Losh .set SEL_UDATA,0x30|3 # User data 55ca987d46SWarner Losh .set SEL_TSS,0x38 # TSS 56ca987d46SWarner Losh/* 57ca987d46SWarner Losh * Task state segment fields. 58ca987d46SWarner Losh */ 59ca987d46SWarner Losh .set TSS_ESP0,0x4 # PL 0 ESP 60ca987d46SWarner Losh .set TSS_SS0,0x8 # PL 0 SS 61ca987d46SWarner Losh .set TSS_MAP,0x66 # I/O bit map base 62ca987d46SWarner Losh/* 63ca987d46SWarner Losh * System calls. 64ca987d46SWarner Losh */ 65ca987d46SWarner Losh .set SYS_EXIT,0x0 # Exit 66ca987d46SWarner Losh .set SYS_EXEC,0x1 # Exec 67ca987d46SWarner Losh/* 68ca987d46SWarner Losh * Fields in V86 interface structure. 69ca987d46SWarner Losh */ 70ca987d46SWarner Losh .set V86_CTL,0x0 # Control flags 71ca987d46SWarner Losh .set V86_ADDR,0x4 # Int number/address 72ca987d46SWarner Losh .set V86_ES,0x8 # V86 ES 73ca987d46SWarner Losh .set V86_DS,0xc # V86 DS 74ca987d46SWarner Losh .set V86_FS,0x10 # V86 FS 75ca987d46SWarner Losh .set V86_GS,0x14 # V86 GS 76ca987d46SWarner Losh/* 77ca987d46SWarner Losh * V86 control flags. 78ca987d46SWarner Losh */ 79ca987d46SWarner Losh .set V86F_ADDR,0x10000 # Segment:offset address 80ca987d46SWarner Losh .set V86F_CALLF,0x20000 # Emulate far call 81ca987d46SWarner Losh .set V86F_FLAGS,0x40000 # Return flags 82ca987d46SWarner Losh/* 83ca987d46SWarner Losh * Dump format control bytes. 84ca987d46SWarner Losh */ 85ca987d46SWarner Losh .set DMP_X16,0x1 # Word 86ca987d46SWarner Losh .set DMP_X32,0x2 # Long 87ca987d46SWarner Losh .set DMP_MEM,0x4 # Memory 88ca987d46SWarner Losh .set DMP_EOL,0x8 # End of line 89ca987d46SWarner Losh/* 90ca987d46SWarner Losh * Screen defaults and assumptions. 91ca987d46SWarner Losh */ 92ca987d46SWarner Losh .set SCR_MAT,0x7 # Mode/attribute 93ca987d46SWarner Losh .set SCR_COL,0x50 # Columns per row 94ca987d46SWarner Losh .set SCR_ROW,0x19 # Rows per screen 95ca987d46SWarner Losh/* 96ca987d46SWarner Losh * BIOS Data Area locations. 97ca987d46SWarner Losh */ 98ca987d46SWarner Losh .set BDA_MEM,0x413 # Free memory 99ca987d46SWarner Losh .set BDA_SCR,0x449 # Video mode 100ca987d46SWarner Losh .set BDA_POS,0x450 # Cursor position 101ca987d46SWarner Losh .set BDA_BOOT,0x472 # Boot howto flag 102ca987d46SWarner Losh/* 103ca987d46SWarner Losh * Derivations, for brevity. 104ca987d46SWarner Losh */ 105ca987d46SWarner Losh .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0 106ca987d46SWarner Losh .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base 107ca987d46SWarner Losh .set _TSSLM,MEM_TSS_END-MEM_TSS # TSS limit 108ca987d46SWarner Losh .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit 109ca987d46SWarner Losh/* 110ca987d46SWarner Losh * Code segment. 111ca987d46SWarner Losh */ 112ca987d46SWarner Losh .globl start 113ca987d46SWarner Losh .code16 114ca987d46SWarner Loshstart: # Start of code 115ca987d46SWarner Losh/* 116ca987d46SWarner Losh * BTX header. 117ca987d46SWarner Losh */ 118ca987d46SWarner Loshbtx_hdr: .byte 0xeb # Machine ID 119ca987d46SWarner Losh .byte 0xe # Header size 120ca987d46SWarner Losh .ascii "BTX" # Magic 121ca987d46SWarner Losh .byte 0x1 # Major version 122ca987d46SWarner Losh .byte 0x2 # Minor version 123ca987d46SWarner Losh .byte BTX_FLAGS # Flags 124ca987d46SWarner Losh .word PAG_CNT-MEM_ORG>>0xc # Paging control 125ca987d46SWarner Losh .word break-start # Text size 126ca987d46SWarner Losh .long 0x0 # Entry address 127ca987d46SWarner Losh/* 128ca987d46SWarner Losh * Initialization routine. 129ca987d46SWarner Losh */ 130ca987d46SWarner Loshinit: cli # Disable interrupts 131ca987d46SWarner Losh xor %ax,%ax # Zero/segment 132ca987d46SWarner Losh mov %ax,%ss # Set up 133ca987d46SWarner Losh mov $MEM_ESP0,%sp # stack 134ca987d46SWarner Losh mov %ax,%es # Address 135ca987d46SWarner Losh mov %ax,%ds # data 136ca987d46SWarner Losh pushl $0x2 # Clear 137ca987d46SWarner Losh popfl # flags 138ca987d46SWarner Losh/* 139ca987d46SWarner Losh * Initialize memory. 140ca987d46SWarner Losh */ 141ca987d46SWarner Losh mov $MEM_IDT,%di # Memory to initialize 142ca987d46SWarner Losh mov $(MEM_ORG-MEM_IDT)/2,%cx # Words to zero 143ca987d46SWarner Losh rep # Zero-fill 144ca987d46SWarner Losh stosw # memory 145ca987d46SWarner Losh/* 146ca987d46SWarner Losh * Update real mode IDT for reflecting hardware interrupts. 147ca987d46SWarner Losh */ 148ca987d46SWarner Losh mov $intr20,%bx # Address first handler 149ca987d46SWarner Losh mov $0x10,%cx # Number of handlers 150ca987d46SWarner Losh mov $0x20*4,%di # First real mode IDT entry 151ca987d46SWarner Loshinit.0: mov %bx,(%di) # Store IP 152ca987d46SWarner Losh inc %di # Address next 153ca987d46SWarner Losh inc %di # entry 154ca987d46SWarner Losh stosw # Store CS 155ca987d46SWarner Losh add $4,%bx # Next handler 156ca987d46SWarner Losh loop init.0 # Next IRQ 157ca987d46SWarner Losh/* 158ca987d46SWarner Losh * Create IDT. 159ca987d46SWarner Losh */ 160ca987d46SWarner Losh mov $MEM_IDT,%di 161ca987d46SWarner Losh mov $idtctl,%si # Control string 162ca987d46SWarner Loshinit.1: lodsb # Get entry 163ca987d46SWarner Losh cbw # count 164ca987d46SWarner Losh xchg %ax,%cx # as word 165ca987d46SWarner Losh jcxz init.4 # If done 166ca987d46SWarner Losh lodsb # Get segment 167ca987d46SWarner Losh xchg %ax,%dx # P:DPL:type 168ca987d46SWarner Losh lodsw # Get control 169ca987d46SWarner Losh xchg %ax,%bx # set 170ca987d46SWarner Losh lodsw # Get handler offset 171ca987d46SWarner Losh mov $SEL_SCODE,%dh # Segment selector 172ca987d46SWarner Loshinit.2: shr %bx # Handle this int? 173ca987d46SWarner Losh jnc init.3 # No 174ca987d46SWarner Losh mov %ax,(%di) # Set handler offset 175ca987d46SWarner Losh mov %dh,0x2(%di) # and selector 176ca987d46SWarner Losh mov %dl,0x5(%di) # Set P:DPL:type 177ca987d46SWarner Losh add $0x4,%ax # Next handler 178ca987d46SWarner Loshinit.3: lea 0x8(%di),%di # Next entry 179ca987d46SWarner Losh loop init.2 # Till set done 180ca987d46SWarner Losh jmp init.1 # Continue 181ca987d46SWarner Losh/* 182ca987d46SWarner Losh * Initialize TSS. 183ca987d46SWarner Losh */ 184ca987d46SWarner Loshinit.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0 185ca987d46SWarner Losh movb $SEL_SDATA,TSS_SS0(%di) # Set SS0 186ca987d46SWarner Losh movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base 187ca987d46SWarner Losh/* 188ca987d46SWarner Losh * Bring up the system. 189ca987d46SWarner Losh */ 190ca987d46SWarner Losh mov $0x2820,%bx # Set protected mode 191ca987d46SWarner Losh callw setpic # IRQ offsets 192ca987d46SWarner Losh lidt idtdesc # Set IDT 193ca987d46SWarner Losh lgdt gdtdesc # Set GDT 194ca987d46SWarner Losh mov %cr0,%eax # Switch to protected 195ca987d46SWarner Losh inc %ax # mode 196ca987d46SWarner Losh mov %eax,%cr0 # 197ca987d46SWarner Losh ljmp $SEL_SCODE,$init.8 # To 32-bit code 198ca987d46SWarner Losh .code32 199ca987d46SWarner Loshinit.8: xorl %ecx,%ecx # Zero 200ca987d46SWarner Losh movb $SEL_SDATA,%cl # To 32-bit 201ca987d46SWarner Losh movw %cx,%ss # stack 202ca987d46SWarner Losh/* 203ca987d46SWarner Losh * Launch user task. 204ca987d46SWarner Losh */ 205ca987d46SWarner Losh movb $SEL_TSS,%cl # Set task 206ca987d46SWarner Losh ltr %cx # register 207ca987d46SWarner Losh movl $MEM_USR,%edx # User base address 208ca987d46SWarner Losh movzwl %ss:BDA_MEM,%eax # Get free memory 209ca987d46SWarner Losh shll $0xa,%eax # To bytes 210ca987d46SWarner Losh subl $ARGSPACE,%eax # Less arg space 211ca987d46SWarner Losh subl %edx,%eax # Less base 212ca987d46SWarner Losh movb $SEL_UDATA,%cl # User data selector 213ca987d46SWarner Losh pushl %ecx # Set SS 214ca987d46SWarner Losh pushl %eax # Set ESP 215ca987d46SWarner Losh push $0x202 # Set flags (IF set) 216ca987d46SWarner Losh push $SEL_UCODE # Set CS 217ca987d46SWarner Losh pushl btx_hdr+0xc # Set EIP 218ca987d46SWarner Losh pushl %ecx # Set GS 219ca987d46SWarner Losh pushl %ecx # Set FS 220ca987d46SWarner Losh pushl %ecx # Set DS 221ca987d46SWarner Losh pushl %ecx # Set ES 222ca987d46SWarner Losh pushl %edx # Set EAX 223ca987d46SWarner Losh movb $0x7,%cl # Set remaining 224ca987d46SWarner Loshinit.9: push $0x0 # general 225ca987d46SWarner Losh loop init.9 # registers 226ca987d46SWarner Losh#ifdef BTX_SERIAL 227ca987d46SWarner Losh call sio_init # setup the serial console 228ca987d46SWarner Losh#endif 229ca987d46SWarner Losh popa # and initialize 230ca987d46SWarner Losh popl %es # Initialize 231ca987d46SWarner Losh popl %ds # user 232ca987d46SWarner Losh popl %fs # segment 233ca987d46SWarner Losh popl %gs # registers 234ca987d46SWarner Losh iret # To user mode 235ca987d46SWarner Losh/* 236ca987d46SWarner Losh * Exit routine. 237ca987d46SWarner Losh */ 238ca987d46SWarner Loshexit: cli # Disable interrupts 239ca987d46SWarner Losh movl $MEM_ESP0,%esp # Clear stack 240ca987d46SWarner Losh/* 241ca987d46SWarner Losh * Turn off paging. 242ca987d46SWarner Losh */ 243ca987d46SWarner Losh movl %cr0,%eax # Get CR0 244ca987d46SWarner Losh andl $~0x80000000,%eax # Disable 245ca987d46SWarner Losh movl %eax,%cr0 # paging 246ca987d46SWarner Losh xorl %ecx,%ecx # Zero 247ca987d46SWarner Losh movl %ecx,%cr3 # Flush TLB 248ca987d46SWarner Losh/* 249ca987d46SWarner Losh * Restore the GDT in case we caught a kernel trap. 250ca987d46SWarner Losh */ 251ca987d46SWarner Losh lgdt %cs:gdtdesc # Set GDT 252ca987d46SWarner Losh/* 253ca987d46SWarner Losh * To 16 bits. 254ca987d46SWarner Losh */ 255ca987d46SWarner Losh ljmpw $SEL_RCODE,$exit.1 # Reload CS 256ca987d46SWarner Losh .code16 257ca987d46SWarner Loshexit.1: mov $SEL_RDATA,%cl # 16-bit selector 258ca987d46SWarner Losh mov %cx,%ss # Reload SS 259ca987d46SWarner Losh mov %cx,%ds # Load 260ca987d46SWarner Losh mov %cx,%es # remaining 261ca987d46SWarner Losh mov %cx,%fs # segment 262ca987d46SWarner Losh mov %cx,%gs # registers 263ca987d46SWarner Losh/* 264ca987d46SWarner Losh * To real-address mode. 265ca987d46SWarner Losh */ 266ca987d46SWarner Losh dec %ax # Switch to 267ca987d46SWarner Losh mov %eax,%cr0 # real mode 268ca987d46SWarner Losh ljmp $0x0,$exit.2 # Reload CS 269ca987d46SWarner Loshexit.2: xor %ax,%ax # Real mode segment 270ca987d46SWarner Losh mov %ax,%ss # Reload SS 271ca987d46SWarner Losh mov %ax,%ds # Address data 272ca987d46SWarner Losh mov $0x7008,%bx # Set real mode 273ca987d46SWarner Losh callw setpic # IRQ offsets 274ca987d46SWarner Losh lidt ivtdesc # Set IVT 275ca987d46SWarner Losh/* 276ca987d46SWarner Losh * Reboot or await reset. 277ca987d46SWarner Losh */ 278ca987d46SWarner Losh sti # Enable interrupts 279ca987d46SWarner Losh testb $0x1,btx_hdr+0x7 # Reboot? 280ca987d46SWarner Loshexit.3: jz exit.3 # No 281ca987d46SWarner Losh movw $0x1234, BDA_BOOT # Do a warm boot 282ca987d46SWarner Losh ljmp $0xf000,$0xfff0 # reboot the machine 283ca987d46SWarner Losh/* 284ca987d46SWarner Losh * Set IRQ offsets by reprogramming 8259A PICs. 285ca987d46SWarner Losh */ 286ca987d46SWarner Loshsetpic: in $0x21,%al # Save master 287ca987d46SWarner Losh push %ax # IMR 288ca987d46SWarner Losh in $0xa1,%al # Save slave 289ca987d46SWarner Losh push %ax # IMR 290ca987d46SWarner Losh movb $0x11,%al # ICW1 to 291ca987d46SWarner Losh outb %al,$0x20 # master, 292ca987d46SWarner Losh outb %al,$0xa0 # slave 293ca987d46SWarner Losh movb %bl,%al # ICW2 to 294ca987d46SWarner Losh outb %al,$0x21 # master 295ca987d46SWarner Losh movb %bh,%al # ICW2 to 296ca987d46SWarner Losh outb %al,$0xa1 # slave 297ca987d46SWarner Losh movb $0x4,%al # ICW3 to 298ca987d46SWarner Losh outb %al,$0x21 # master 299ca987d46SWarner Losh movb $0x2,%al # ICW3 to 300ca987d46SWarner Losh outb %al,$0xa1 # slave 301ca987d46SWarner Losh movb $0x1,%al # ICW4 to 302ca987d46SWarner Losh outb %al,$0x21 # master, 303ca987d46SWarner Losh outb %al,$0xa1 # slave 304ca987d46SWarner Losh pop %ax # Restore slave 305ca987d46SWarner Losh outb %al,$0xa1 # IMR 306ca987d46SWarner Losh pop %ax # Restore master 307ca987d46SWarner Losh outb %al,$0x21 # IMR 308ca987d46SWarner Losh retw # To caller 309ca987d46SWarner Losh .code32 310ca987d46SWarner Losh/* 311ca987d46SWarner Losh * Exception jump table. 312ca987d46SWarner Losh */ 313ca987d46SWarner Loshintx00: push $0x0 # Int 0x0: #DE 314ca987d46SWarner Losh jmp ex_noc # Divide error 315ca987d46SWarner Losh push $0x1 # Int 0x1: #DB 316ca987d46SWarner Losh jmp ex_noc # Debug 317ca987d46SWarner Losh push $0x3 # Int 0x3: #BP 318ca987d46SWarner Losh jmp ex_noc # Breakpoint 319ca987d46SWarner Losh push $0x4 # Int 0x4: #OF 320ca987d46SWarner Losh jmp ex_noc # Overflow 321ca987d46SWarner Losh push $0x5 # Int 0x5: #BR 322ca987d46SWarner Losh jmp ex_noc # BOUND range exceeded 323ca987d46SWarner Losh push $0x6 # Int 0x6: #UD 324ca987d46SWarner Losh jmp ex_noc # Invalid opcode 325ca987d46SWarner Losh push $0x7 # Int 0x7: #NM 326ca987d46SWarner Losh jmp ex_noc # Device not available 327ca987d46SWarner Losh push $0x8 # Int 0x8: #DF 328ca987d46SWarner Losh jmp except # Double fault 329ca987d46SWarner Losh push $0xa # Int 0xa: #TS 330ca987d46SWarner Losh jmp except # Invalid TSS 331ca987d46SWarner Losh push $0xb # Int 0xb: #NP 332ca987d46SWarner Losh jmp except # Segment not present 333ca987d46SWarner Losh push $0xc # Int 0xc: #SS 334ca987d46SWarner Losh jmp except # Stack segment fault 335ca987d46SWarner Losh push $0xd # Int 0xd: #GP 336ca987d46SWarner Losh jmp except # General protection 337ca987d46SWarner Losh push $0xe # Int 0xe: #PF 338ca987d46SWarner Losh jmp except # Page fault 339ca987d46SWarner Loshintx10: push $0x10 # Int 0x10: #MF 340ca987d46SWarner Losh jmp ex_noc # Floating-point error 341ca987d46SWarner Losh/* 342ca987d46SWarner Losh * Save a zero error code. 343ca987d46SWarner Losh */ 344ca987d46SWarner Loshex_noc: pushl (%esp,1) # Duplicate int no 345ca987d46SWarner Losh movb $0x0,0x4(%esp,1) # Fake error code 346ca987d46SWarner Losh/* 347ca987d46SWarner Losh * Handle exception. 348ca987d46SWarner Losh */ 349ca987d46SWarner Loshexcept: cld # String ops inc 350ca987d46SWarner Losh pushl %ds # Save 351ca987d46SWarner Losh pushl %es # most 352ca987d46SWarner Losh pusha # registers 353ca987d46SWarner Losh pushl %gs # Set GS 354ca987d46SWarner Losh pushl %fs # Set FS 355ca987d46SWarner Losh pushl %ds # Set DS 356ca987d46SWarner Losh pushl %es # Set ES 357ca987d46SWarner Losh cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode? 358ca987d46SWarner Losh jne except.1 # No 359ca987d46SWarner Losh pushl %ss # Set SS 360ca987d46SWarner Losh jmp except.2 # Join common code 361ca987d46SWarner Loshexcept.1: pushl 0x50(%esp,1) # Set SS 362ca987d46SWarner Loshexcept.2: pushl 0x50(%esp,1) # Set ESP 363ca987d46SWarner Losh push $SEL_SDATA # Set up 364ca987d46SWarner Losh popl %ds # to 365ca987d46SWarner Losh pushl %ds # address 366ca987d46SWarner Losh popl %es # data 367ca987d46SWarner Losh movl %esp,%ebx # Stack frame 368ca987d46SWarner Losh movl $dmpfmt,%esi # Dump format string 369ca987d46SWarner Losh movl $MEM_BUF,%edi # Buffer 370ca987d46SWarner Losh pushl %edi # Dump to 371ca987d46SWarner Losh call dump # buffer 372ca987d46SWarner Losh popl %esi # and 373ca987d46SWarner Losh call putstr # display 374ca987d46SWarner Losh leal 0x18(%esp,1),%esp # Discard frame 375ca987d46SWarner Losh popa # Restore 376ca987d46SWarner Losh popl %es # registers 377ca987d46SWarner Losh popl %ds # saved 378ca987d46SWarner Losh cmpb $0x3,(%esp,1) # Breakpoint? 379ca987d46SWarner Losh je except.3 # Yes 380ca987d46SWarner Losh cmpb $0x1,(%esp,1) # Debug? 381ca987d46SWarner Losh jne except.2a # No 382ca987d46SWarner Losh testl $PSL_T,0x10(%esp,1) # Trap flag set? 383ca987d46SWarner Losh jnz except.3 # Yes 384ca987d46SWarner Loshexcept.2a: jmp exit # Exit 385ca987d46SWarner Loshexcept.3: leal 0x8(%esp,1),%esp # Discard err, int no 386ca987d46SWarner Losh iret # From interrupt 387ca987d46SWarner Losh 388ca987d46SWarner Losh/* 389ca987d46SWarner Losh * Reboot the machine by setting the reboot flag and exiting 390ca987d46SWarner Losh */ 391ca987d46SWarner Loshreboot: orb $0x1,btx_hdr+0x7 # Set the reboot flag 392ca987d46SWarner Losh jmp exit # Terminate BTX and reboot 393ca987d46SWarner Losh 394ca987d46SWarner Losh/* 395ca987d46SWarner Losh * Protected Mode Hardware interrupt jump table. 396ca987d46SWarner Losh */ 397ca987d46SWarner Loshintx20: push $0x8 # Int 0x20: IRQ0 398ca987d46SWarner Losh jmp int_hw # V86 int 0x8 399ca987d46SWarner Losh push $0x9 # Int 0x21: IRQ1 400ca987d46SWarner Losh jmp int_hw # V86 int 0x9 401ca987d46SWarner Losh push $0xa # Int 0x22: IRQ2 402ca987d46SWarner Losh jmp int_hw # V86 int 0xa 403ca987d46SWarner Losh push $0xb # Int 0x23: IRQ3 404ca987d46SWarner Losh jmp int_hw # V86 int 0xb 405ca987d46SWarner Losh push $0xc # Int 0x24: IRQ4 406ca987d46SWarner Losh jmp int_hw # V86 int 0xc 407ca987d46SWarner Losh push $0xd # Int 0x25: IRQ5 408ca987d46SWarner Losh jmp int_hw # V86 int 0xd 409ca987d46SWarner Losh push $0xe # Int 0x26: IRQ6 410ca987d46SWarner Losh jmp int_hw # V86 int 0xe 411ca987d46SWarner Losh push $0xf # Int 0x27: IRQ7 412ca987d46SWarner Losh jmp int_hw # V86 int 0xf 413ca987d46SWarner Losh push $0x70 # Int 0x28: IRQ8 414ca987d46SWarner Losh jmp int_hw # V86 int 0x70 415ca987d46SWarner Losh push $0x71 # Int 0x29: IRQ9 416ca987d46SWarner Losh jmp int_hw # V86 int 0x71 417ca987d46SWarner Losh push $0x72 # Int 0x2a: IRQ10 418ca987d46SWarner Losh jmp int_hw # V86 int 0x72 419ca987d46SWarner Losh push $0x73 # Int 0x2b: IRQ11 420ca987d46SWarner Losh jmp int_hw # V86 int 0x73 421ca987d46SWarner Losh push $0x74 # Int 0x2c: IRQ12 422ca987d46SWarner Losh jmp int_hw # V86 int 0x74 423ca987d46SWarner Losh push $0x75 # Int 0x2d: IRQ13 424ca987d46SWarner Losh jmp int_hw # V86 int 0x75 425ca987d46SWarner Losh push $0x76 # Int 0x2e: IRQ14 426ca987d46SWarner Losh jmp int_hw # V86 int 0x76 427ca987d46SWarner Losh push $0x77 # Int 0x2f: IRQ15 428ca987d46SWarner Losh jmp int_hw # V86 int 0x77 429ca987d46SWarner Losh 430ca987d46SWarner Losh/* 431ca987d46SWarner Losh * Invoke real mode interrupt/function call from user mode with arguments. 432ca987d46SWarner Losh */ 433ca987d46SWarner Loshintx31: pushl $-1 # Dummy int no for btx_v86 434ca987d46SWarner Losh/* 435ca987d46SWarner Losh * Invoke real mode interrupt/function call from protected mode. 436ca987d46SWarner Losh * 437ca987d46SWarner Losh * We place a trampoline on the user stack that will return to rret_tramp 438ca987d46SWarner Losh * which will reenter protected mode and then finally return to the user 439ca987d46SWarner Losh * client. 440ca987d46SWarner Losh * 441ca987d46SWarner Losh * Kernel frame %esi points to: Real mode stack frame at MEM_ESPR: 442ca987d46SWarner Losh * 443ca987d46SWarner Losh * -0x00 user %ss -0x04 kernel %esp (with full frame) 444ca987d46SWarner Losh * -0x04 user %esp -0x08 btx_v86 pointer 445ca987d46SWarner Losh * -0x08 user %eflags -0x0c flags (only used if interrupt) 446ca987d46SWarner Losh * -0x0c user %cs -0x10 real mode CS:IP return trampoline 447ca987d46SWarner Losh * -0x10 user %eip -0x12 real mode flags 448ca987d46SWarner Losh * -0x14 int no -0x16 real mode CS:IP (target) 449ca987d46SWarner Losh * -0x18 %eax 450ca987d46SWarner Losh * -0x1c %ecx 451ca987d46SWarner Losh * -0x20 %edx 452ca987d46SWarner Losh * -0x24 %ebx 453ca987d46SWarner Losh * -0x28 %esp 454ca987d46SWarner Losh * -0x2c %ebp 455ca987d46SWarner Losh * -0x30 %esi 456ca987d46SWarner Losh * -0x34 %edi 457ca987d46SWarner Losh * -0x38 %gs 458ca987d46SWarner Losh * -0x3c %fs 459ca987d46SWarner Losh * -0x40 %ds 460ca987d46SWarner Losh * -0x44 %es 461ca987d46SWarner Losh * -0x48 zero %eax (hardware int only) 462ca987d46SWarner Losh * -0x4c zero %ecx (hardware int only) 463ca987d46SWarner Losh * -0x50 zero %edx (hardware int only) 464ca987d46SWarner Losh * -0x54 zero %ebx (hardware int only) 465ca987d46SWarner Losh * -0x58 zero %esp (hardware int only) 466ca987d46SWarner Losh * -0x5c zero %ebp (hardware int only) 467ca987d46SWarner Losh * -0x60 zero %esi (hardware int only) 468ca987d46SWarner Losh * -0x64 zero %edi (hardware int only) 469ca987d46SWarner Losh * -0x68 zero %gs (hardware int only) 470ca987d46SWarner Losh * -0x6c zero %fs (hardware int only) 471ca987d46SWarner Losh * -0x70 zero %ds (hardware int only) 472ca987d46SWarner Losh * -0x74 zero %es (hardware int only) 473ca987d46SWarner Losh */ 474ca987d46SWarner Loshint_hw: cld # String ops inc 475ca987d46SWarner Losh pusha # Save gp regs 476ca987d46SWarner Losh pushl %gs # Save 477ca987d46SWarner Losh pushl %fs # seg 478ca987d46SWarner Losh pushl %ds # regs 479ca987d46SWarner Losh pushl %es 480ca987d46SWarner Losh push $SEL_SDATA # Set up 481ca987d46SWarner Losh popl %ds # to 482ca987d46SWarner Losh pushl %ds # address 483ca987d46SWarner Losh popl %es # data 484ca987d46SWarner Losh leal 0x44(%esp,1),%esi # Base of frame 485ca987d46SWarner Losh movl %esp,MEM_ESPR-0x04 # Save kernel stack pointer 486ca987d46SWarner Losh movl -0x14(%esi),%eax # Get Int no 487ca987d46SWarner Losh cmpl $-1,%eax # Hardware interrupt? 488ca987d46SWarner Losh jne intusr.1 # Yes 489ca987d46SWarner Losh/* 490ca987d46SWarner Losh * v86 calls save the btx_v86 pointer on the real mode stack and read 491ca987d46SWarner Losh * the address and flags from the btx_v86 structure. For interrupt 492ca987d46SWarner Losh * handler invocations (VM86 INTx requests), disable interrupts, 493ca987d46SWarner Losh * tracing, and alignment checking while the handler runs. 494ca987d46SWarner Losh */ 495ca987d46SWarner Losh movl $MEM_USR,%ebx # User base 496ca987d46SWarner Losh movl %ebx,%edx # address 497ca987d46SWarner Losh addl -0x4(%esi),%ebx # User ESP 498ca987d46SWarner Losh movl (%ebx),%ebp # btx_v86 pointer 499ca987d46SWarner Losh addl %ebp,%edx # Flatten btx_v86 ptr 500ca987d46SWarner Losh movl %edx,MEM_ESPR-0x08 # Save btx_v86 ptr 501ca987d46SWarner Losh movl V86_ADDR(%edx),%eax # Get int no/address 502ca987d46SWarner Losh movl V86_CTL(%edx),%edx # Get control flags 503ca987d46SWarner Losh movl -0x08(%esi),%ebx # Save user flags in %ebx 504ca987d46SWarner Losh testl $V86F_ADDR,%edx # Segment:offset? 505ca987d46SWarner Losh jnz intusr.4 # Yes 506ca987d46SWarner Losh andl $~(PSL_I|PSL_T|PSL_AC),%ebx # Disable interrupts, tracing, 507ca987d46SWarner Losh # and alignment checking for 508ca987d46SWarner Losh # interrupt handler 509ca987d46SWarner Losh jmp intusr.3 # Skip hardware interrupt 510ca987d46SWarner Losh/* 511ca987d46SWarner Losh * Hardware interrupts store a NULL btx_v86 pointer and use the 512ca987d46SWarner Losh * address (interrupt number) from the stack with empty flags. Also, 513ca987d46SWarner Losh * push a dummy frame of zeros onto the stack for all the general 514ca987d46SWarner Losh * purpose and segment registers and clear %eflags. This gives the 515ca987d46SWarner Losh * hardware interrupt handler a clean slate. 516ca987d46SWarner Losh */ 517ca987d46SWarner Loshintusr.1: xorl %edx,%edx # Control flags 518ca987d46SWarner Losh movl %edx,MEM_ESPR-0x08 # NULL btx_v86 ptr 519ca987d46SWarner Losh movl $12,%ecx # Frame is 12 dwords 520ca987d46SWarner Loshintusr.2: pushl $0x0 # Fill frame 521ca987d46SWarner Losh loop intusr.2 # with zeros 522ca987d46SWarner Losh movl $PSL_RESERVED_DEFAULT,%ebx # Set clean %eflags 523ca987d46SWarner Losh/* 524ca987d46SWarner Losh * Look up real mode IDT entry for hardware interrupts and VM86 INTx 525ca987d46SWarner Losh * requests. 526ca987d46SWarner Losh */ 527ca987d46SWarner Loshintusr.3: shll $0x2,%eax # Scale 528ca987d46SWarner Losh movl (%eax),%eax # Load int vector 529ca987d46SWarner Losh jmp intusr.5 # Skip CALLF test 530ca987d46SWarner Losh/* 531ca987d46SWarner Losh * Panic if V86F_CALLF isn't set with V86F_ADDR. 532ca987d46SWarner Losh */ 533ca987d46SWarner Loshintusr.4: testl $V86F_CALLF,%edx # Far call? 534ca987d46SWarner Losh jnz intusr.5 # Ok 535ca987d46SWarner Losh movl %edx,0x30(%esp,1) # Place VM86 flags in int no 536ca987d46SWarner Losh movl $badvm86,%esi # Display bad 537ca987d46SWarner Losh call putstr # VM86 call 538ca987d46SWarner Losh popl %es # Restore 539ca987d46SWarner Losh popl %ds # seg 540ca987d46SWarner Losh popl %fs # regs 541ca987d46SWarner Losh popl %gs 542ca987d46SWarner Losh popal # Restore gp regs 543ca987d46SWarner Losh jmp ex_noc # Panic 544ca987d46SWarner Losh/* 545ca987d46SWarner Losh * %eax now holds the segment:offset of the function. 546ca987d46SWarner Losh * %ebx now holds the %eflags to pass to real mode. 547ca987d46SWarner Losh * %edx now holds the V86F_* flags. 548ca987d46SWarner Losh */ 549ca987d46SWarner Loshintusr.5: movw %bx,MEM_ESPR-0x12 # Pass user flags to real mode 550ca987d46SWarner Losh # target 551ca987d46SWarner Losh/* 552ca987d46SWarner Losh * If this is a v86 call, copy the seg regs out of the btx_v86 structure. 553ca987d46SWarner Losh */ 554ca987d46SWarner Losh movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr 555ca987d46SWarner Losh jecxz intusr.6 # Skip for hardware ints 556ca987d46SWarner Losh leal -0x44(%esi),%edi # %edi => kernel stack seg regs 557ca987d46SWarner Losh pushl %esi # Save 558ca987d46SWarner Losh leal V86_ES(%ecx),%esi # %esi => btx_v86 seg regs 559ca987d46SWarner Losh movl $4,%ecx # Copy seg regs 560ca987d46SWarner Losh rep # from btx_v86 561ca987d46SWarner Losh movsl # to kernel stack 562ca987d46SWarner Losh popl %esi # Restore 563ca987d46SWarner Loshintusr.6: movl -0x08(%esi),%ebx # Copy user flags to real 564ca987d46SWarner Losh movl %ebx,MEM_ESPR-0x0c # mode return trampoline 565ca987d46SWarner Losh movl $rret_tramp,%ebx # Set return trampoline 566ca987d46SWarner Losh movl %ebx,MEM_ESPR-0x10 # CS:IP 567ca987d46SWarner Losh movl %eax,MEM_ESPR-0x16 # Real mode target CS:IP 568ca987d46SWarner Losh ljmpw $SEL_RCODE,$intusr.7 # Change to 16-bit segment 569ca987d46SWarner Losh .code16 570ca987d46SWarner Loshintusr.7: movl %cr0,%eax # Leave 571ca987d46SWarner Losh dec %al # protected 572ca987d46SWarner Losh movl %eax,%cr0 # mode 573ca987d46SWarner Losh ljmpw $0x0,$intusr.8 574ca987d46SWarner Loshintusr.8: xorw %ax,%ax # Reset %ds 575ca987d46SWarner Losh movw %ax,%ds # and 576ca987d46SWarner Losh movw %ax,%ss # %ss 577ca987d46SWarner Losh lidt ivtdesc # Set IVT 578ca987d46SWarner Losh popl %es # Restore 579ca987d46SWarner Losh popl %ds # seg 580ca987d46SWarner Losh popl %fs # regs 581ca987d46SWarner Losh popl %gs 582ca987d46SWarner Losh popal # Restore gp regs 583ca987d46SWarner Losh movw $MEM_ESPR-0x16,%sp # Switch to real mode stack 584ca987d46SWarner Losh iret # Call target routine 585ca987d46SWarner Losh/* 586ca987d46SWarner Losh * For the return to real mode we setup a stack frame like this on the real 587ca987d46SWarner Losh * mode stack. Note that callf calls won't pop off the flags, but we just 588ca987d46SWarner Losh * ignore that by repositioning %sp to be just above the btx_v86 pointer 589ca987d46SWarner Losh * so it is aligned. The stack is relative to MEM_ESPR. 590ca987d46SWarner Losh * 591ca987d46SWarner Losh * -0x04 kernel %esp 592ca987d46SWarner Losh * -0x08 btx_v86 593ca987d46SWarner Losh * -0x0c %eax 594ca987d46SWarner Losh * -0x10 %ecx 595ca987d46SWarner Losh * -0x14 %edx 596ca987d46SWarner Losh * -0x18 %ebx 597ca987d46SWarner Losh * -0x1c %esp 598ca987d46SWarner Losh * -0x20 %ebp 599ca987d46SWarner Losh * -0x24 %esi 600ca987d46SWarner Losh * -0x28 %edi 601ca987d46SWarner Losh * -0x2c %gs 602ca987d46SWarner Losh * -0x30 %fs 603ca987d46SWarner Losh * -0x34 %ds 604ca987d46SWarner Losh * -0x38 %es 605ca987d46SWarner Losh * -0x3c %eflags 606ca987d46SWarner Losh */ 607ca987d46SWarner Loshrret_tramp: movw $MEM_ESPR-0x08,%sp # Reset stack pointer 608ca987d46SWarner Losh pushal # Save gp regs 609ca987d46SWarner Losh pushl %gs # Save 610ca987d46SWarner Losh pushl %fs # seg 611ca987d46SWarner Losh pushl %ds # regs 612ca987d46SWarner Losh pushl %es 613ca987d46SWarner Losh pushfl # Save %eflags 614ca987d46SWarner Losh pushl $PSL_RESERVED_DEFAULT|PSL_D # Use clean %eflags with 615ca987d46SWarner Losh popfl # string ops dec 616ca987d46SWarner Losh xorw %ax,%ax # Reset seg 617ca987d46SWarner Losh movw %ax,%ds # regs 618ca987d46SWarner Losh movw %ax,%es # (%ss is already 0) 619ca987d46SWarner Losh lidt idtdesc # Set IDT 620ca987d46SWarner Losh lgdt gdtdesc # Set GDT 621ca987d46SWarner Losh mov %cr0,%eax # Switch to protected 622ca987d46SWarner Losh inc %ax # mode 623ca987d46SWarner Losh mov %eax,%cr0 # 624ca987d46SWarner Losh ljmp $SEL_SCODE,$rret_tramp.1 # To 32-bit code 625ca987d46SWarner Losh .code32 626ca987d46SWarner Loshrret_tramp.1: xorl %ecx,%ecx # Zero 627ca987d46SWarner Losh movb $SEL_SDATA,%cl # Setup 628ca987d46SWarner Losh movw %cx,%ss # 32-bit 629ca987d46SWarner Losh movw %cx,%ds # seg 630ca987d46SWarner Losh movw %cx,%es # regs 631ca987d46SWarner Losh movl MEM_ESPR-0x04,%esp # Switch to kernel stack 632ca987d46SWarner Losh leal 0x44(%esp,1),%esi # Base of frame 633ca987d46SWarner Losh andb $~0x2,tss_desc+0x5 # Clear TSS busy 634ca987d46SWarner Losh movb $SEL_TSS,%cl # Set task 635ca987d46SWarner Losh ltr %cx # register 636ca987d46SWarner Losh/* 637ca987d46SWarner Losh * Now we are back in protected mode. The kernel stack frame set up 638ca987d46SWarner Losh * before entering real mode is still intact. For hardware interrupts, 639ca987d46SWarner Losh * leave the frame unchanged. 640ca987d46SWarner Losh */ 641ca987d46SWarner Losh cmpl $0,MEM_ESPR-0x08 # Leave saved regs unchanged 642ca987d46SWarner Losh jz rret_tramp.3 # for hardware ints 643ca987d46SWarner Losh/* 644ca987d46SWarner Losh * For V86 calls, copy the registers off of the real mode stack onto 645ca987d46SWarner Losh * the kernel stack as we want their updated values. Also, initialize 646ca987d46SWarner Losh * the segment registers on the kernel stack. 647ca987d46SWarner Losh * 648ca987d46SWarner Losh * Note that the %esp in the kernel stack after this is garbage, but popa 649ca987d46SWarner Losh * ignores it, so we don't have to fix it up. 650ca987d46SWarner Losh */ 651ca987d46SWarner Losh leal -0x18(%esi),%edi # Kernel stack GP regs 652ca987d46SWarner Losh pushl %esi # Save 653ca987d46SWarner Losh movl $MEM_ESPR-0x0c,%esi # Real mode stack GP regs 654ca987d46SWarner Losh movl $8,%ecx # Copy GP regs from 655ca987d46SWarner Losh rep # real mode stack 656ca987d46SWarner Losh movsl # to kernel stack 657ca987d46SWarner Losh movl $SEL_UDATA,%eax # Selector for data seg regs 658ca987d46SWarner Losh movl $4,%ecx # Initialize %ds, 659ca987d46SWarner Losh rep # %es, %fs, and 660ca987d46SWarner Losh stosl # %gs 661ca987d46SWarner Losh/* 662ca987d46SWarner Losh * For V86 calls, copy the saved seg regs on the real mode stack back 663ca987d46SWarner Losh * over to the btx_v86 structure. Also, conditionally update the 664ca987d46SWarner Losh * saved eflags on the kernel stack based on the flags from the user. 665ca987d46SWarner Losh */ 666ca987d46SWarner Losh movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr 667ca987d46SWarner Losh leal V86_GS(%ecx),%edi # %edi => btx_v86 seg regs 668ca987d46SWarner Losh leal MEM_ESPR-0x2c,%esi # %esi => real mode seg regs 669ca987d46SWarner Losh xchgl %ecx,%edx # Save btx_v86 ptr 670ca987d46SWarner Losh movl $4,%ecx # Copy seg regs 671ca987d46SWarner Losh rep # from real mode stack 672ca987d46SWarner Losh movsl # to btx_v86 673ca987d46SWarner Losh popl %esi # Restore 674ca987d46SWarner Losh movl V86_CTL(%edx),%edx # Read V86 control flags 675ca987d46SWarner Losh testl $V86F_FLAGS,%edx # User wants flags? 676ca987d46SWarner Losh jz rret_tramp.3 # No 677ca987d46SWarner Losh movl MEM_ESPR-0x3c,%eax # Read real mode flags 678ca987d46SWarner Losh andl $~(PSL_T|PSL_NT),%eax # Clear unsafe flags 679ca987d46SWarner Losh movw %ax,-0x08(%esi) # Update user flags (low 16) 680ca987d46SWarner Losh/* 681ca987d46SWarner Losh * Return to the user task 682ca987d46SWarner Losh */ 683ca987d46SWarner Loshrret_tramp.3: popl %es # Restore 684ca987d46SWarner Losh popl %ds # seg 685ca987d46SWarner Losh popl %fs # regs 686ca987d46SWarner Losh popl %gs 687ca987d46SWarner Losh popal # Restore gp regs 688ca987d46SWarner Losh addl $4,%esp # Discard int no 689ca987d46SWarner Losh iret # Return to user mode 690ca987d46SWarner Losh 691ca987d46SWarner Losh/* 692ca987d46SWarner Losh * System Call. 693ca987d46SWarner Losh */ 694ca987d46SWarner Loshintx30: cmpl $SYS_EXEC,%eax # Exec system call? 695ca987d46SWarner Losh jne intx30.1 # No 696ca987d46SWarner Losh pushl %ss # Set up 697ca987d46SWarner Losh popl %es # all 698ca987d46SWarner Losh pushl %es # segment 699ca987d46SWarner Losh popl %ds # registers 700ca987d46SWarner Losh pushl %ds # for the 701ca987d46SWarner Losh popl %fs # program 702ca987d46SWarner Losh pushl %fs # we're 703ca987d46SWarner Losh popl %gs # invoking 704ca987d46SWarner Losh movl $MEM_USR,%eax # User base address 705ca987d46SWarner Losh addl 0xc(%esp,1),%eax # Change to user 706ca987d46SWarner Losh leal 0x4(%eax),%esp # stack 707ca987d46SWarner Losh popl %eax # Call 708ca987d46SWarner Losh call *%eax # program 709ca987d46SWarner Loshintx30.1: orb $0x1,%ss:btx_hdr+0x7 # Flag reboot 710ca987d46SWarner Losh jmp exit # Exit 711ca987d46SWarner Losh/* 712ca987d46SWarner Losh * Dump structure [EBX] to [EDI], using format string [ESI]. 713ca987d46SWarner Losh */ 714ca987d46SWarner Loshdump.0: stosb # Save char 715ca987d46SWarner Loshdump: lodsb # Load char 716ca987d46SWarner Losh testb %al,%al # End of string? 717ca987d46SWarner Losh jz dump.10 # Yes 718ca987d46SWarner Losh testb $0x80,%al # Control? 719ca987d46SWarner Losh jz dump.0 # No 720ca987d46SWarner Losh movb %al,%ch # Save control 721ca987d46SWarner Losh movb $'=',%al # Append 722ca987d46SWarner Losh stosb # '=' 723ca987d46SWarner Losh lodsb # Get offset 724ca987d46SWarner Losh pushl %esi # Save 725ca987d46SWarner Losh movsbl %al,%esi # To 726ca987d46SWarner Losh addl %ebx,%esi # pointer 727ca987d46SWarner Losh testb $DMP_X16,%ch # Dump word? 728ca987d46SWarner Losh jz dump.1 # No 729ca987d46SWarner Losh lodsw # Get and 730ca987d46SWarner Losh call hex16 # dump it 731ca987d46SWarner Loshdump.1: testb $DMP_X32,%ch # Dump long? 732ca987d46SWarner Losh jz dump.2 # No 733ca987d46SWarner Losh lodsl # Get and 734ca987d46SWarner Losh call hex32 # dump it 735ca987d46SWarner Loshdump.2: testb $DMP_MEM,%ch # Dump memory? 736ca987d46SWarner Losh jz dump.8 # No 737ca987d46SWarner Losh pushl %ds # Save 738ca987d46SWarner Losh testl $PSL_VM,0x50(%ebx) # V86 mode? 739ca987d46SWarner Losh jnz dump.3 # Yes 740ca987d46SWarner Losh verr 0x4(%esi) # Readable selector? 741ca987d46SWarner Losh jnz dump.3 # No 742ca987d46SWarner Losh ldsl (%esi),%esi # Load pointer 743ca987d46SWarner Losh jmp dump.4 # Join common code 744ca987d46SWarner Loshdump.3: lodsl # Set offset 745ca987d46SWarner Losh xchgl %eax,%edx # Save 746ca987d46SWarner Losh lodsl # Get segment 747ca987d46SWarner Losh shll $0x4,%eax # * 0x10 748ca987d46SWarner Losh addl %edx,%eax # + offset 749ca987d46SWarner Losh xchgl %eax,%esi # Set pointer 750ca987d46SWarner Loshdump.4: movb $2,%dl # Num lines 751ca987d46SWarner Loshdump.4a: movb $0x10,%cl # Bytes to dump 752ca987d46SWarner Loshdump.5: lodsb # Get byte and 753ca987d46SWarner Losh call hex8 # dump it 754ca987d46SWarner Losh decb %cl # Keep count 755ca987d46SWarner Losh jz dump.6a # If done 756ca987d46SWarner Losh movb $'-',%al # Separator 757ca987d46SWarner Losh cmpb $0x8,%cl # Half way? 758ca987d46SWarner Losh je dump.6 # Yes 759ca987d46SWarner Losh movb $' ',%al # Use space 760ca987d46SWarner Loshdump.6: stosb # Save separator 761ca987d46SWarner Losh jmp dump.5 # Continue 762ca987d46SWarner Loshdump.6a: decb %dl # Keep count 763ca987d46SWarner Losh jz dump.7 # If done 764ca987d46SWarner Losh movb $0xa,%al # Line feed 765ca987d46SWarner Losh stosb # Save one 766ca987d46SWarner Losh movb $7,%cl # Leading 767ca987d46SWarner Losh movb $' ',%al # spaces 768ca987d46SWarner Loshdump.6b: stosb # Dump 769ca987d46SWarner Losh decb %cl # spaces 770ca987d46SWarner Losh jnz dump.6b 771ca987d46SWarner Losh jmp dump.4a # Next line 772ca987d46SWarner Loshdump.7: popl %ds # Restore 773ca987d46SWarner Loshdump.8: popl %esi # Restore 774ca987d46SWarner Losh movb $0xa,%al # Line feed 775ca987d46SWarner Losh testb $DMP_EOL,%ch # End of line? 776ca987d46SWarner Losh jnz dump.9 # Yes 777ca987d46SWarner Losh movb $' ',%al # Use spaces 778ca987d46SWarner Losh stosb # Save one 779ca987d46SWarner Loshdump.9: jmp dump.0 # Continue 780ca987d46SWarner Loshdump.10: stosb # Terminate string 781ca987d46SWarner Losh ret # To caller 782ca987d46SWarner Losh/* 783ca987d46SWarner Losh * Convert EAX, AX, or AL to hex, saving the result to [EDI]. 784ca987d46SWarner Losh */ 785ca987d46SWarner Loshhex32: pushl %eax # Save 786ca987d46SWarner Losh shrl $0x10,%eax # Do upper 787ca987d46SWarner Losh call hex16 # 16 788ca987d46SWarner Losh popl %eax # Restore 789ca987d46SWarner Loshhex16: call hex16.1 # Do upper 8 790ca987d46SWarner Loshhex16.1: xchgb %ah,%al # Save/restore 791ca987d46SWarner Loshhex8: pushl %eax # Save 792ca987d46SWarner Losh shrb $0x4,%al # Do upper 793ca987d46SWarner Losh call hex8.1 # 4 794ca987d46SWarner Losh popl %eax # Restore 795ca987d46SWarner Loshhex8.1: andb $0xf,%al # Get lower 4 796ca987d46SWarner Losh cmpb $0xa,%al # Convert 797ca987d46SWarner Losh sbbb $0x69,%al # to hex 798ca987d46SWarner Losh das # digit 799ca987d46SWarner Losh orb $0x20,%al # To lower case 800ca987d46SWarner Losh stosb # Save char 801ca987d46SWarner Losh ret # (Recursive) 802ca987d46SWarner Losh/* 803ca987d46SWarner Losh * Output zero-terminated string [ESI] to the console. 804ca987d46SWarner Losh */ 805ca987d46SWarner Loshputstr.0: call putchr # Output char 806ca987d46SWarner Loshputstr: lodsb # Load char 807ca987d46SWarner Losh testb %al,%al # End of string? 808ca987d46SWarner Losh jnz putstr.0 # No 809ca987d46SWarner Losh ret # To caller 810ca987d46SWarner Losh#ifdef BTX_SERIAL 811ca987d46SWarner Losh .set SIO_PRT,SIOPRT # Base port 812ca987d46SWarner Losh .set SIO_FMT,SIOFMT # 8N1 813ca987d46SWarner Losh .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD 814ca987d46SWarner Losh 815ca987d46SWarner Losh/* 816ca987d46SWarner Losh * int sio_init(void) 817ca987d46SWarner Losh */ 818ca987d46SWarner Loshsio_init: movw $SIO_PRT+0x3,%dx # Data format reg 819ca987d46SWarner Losh movb $SIO_FMT|0x80,%al # Set format 820ca987d46SWarner Losh outb %al,(%dx) # and DLAB 821ca987d46SWarner Losh pushl %edx # Save 822ca987d46SWarner Losh subb $0x3,%dl # Divisor latch reg 823ca987d46SWarner Losh movw $SIO_DIV,%ax # Set 824ca987d46SWarner Losh outw %ax,(%dx) # BPS 825ca987d46SWarner Losh popl %edx # Restore 826ca987d46SWarner Losh movb $SIO_FMT,%al # Clear 827ca987d46SWarner Losh outb %al,(%dx) # DLAB 828ca987d46SWarner Losh incl %edx # Modem control reg 829ca987d46SWarner Losh movb $0x3,%al # Set RTS, 830ca987d46SWarner Losh outb %al,(%dx) # DTR 831ca987d46SWarner Losh incl %edx # Line status reg 832ca987d46SWarner Losh call sio_getc.1 # Get character 833ca987d46SWarner Losh 834ca987d46SWarner Losh/* 835ca987d46SWarner Losh * int sio_flush(void) 836ca987d46SWarner Losh */ 837ca987d46SWarner Loshsio_flush: xorl %eax,%eax # Return value 838ca987d46SWarner Losh xorl %ecx,%ecx # Timeout 839ca987d46SWarner Losh movb $0x80,%ch # counter 840ca987d46SWarner Loshsio_flush.1: call sio_ischar # Check for character 841ca987d46SWarner Losh jz sio_flush.2 # Till none 842ca987d46SWarner Losh loop sio_flush.1 # or counter is zero 843ca987d46SWarner Losh movb $1, %al # Exhausted all tries 844ca987d46SWarner Loshsio_flush.2: ret # To caller 845ca987d46SWarner Losh 846ca987d46SWarner Losh/* 847ca987d46SWarner Losh * void sio_putc(int c) 848ca987d46SWarner Losh */ 849ca987d46SWarner Loshsio_putc: movw $SIO_PRT+0x5,%dx # Line status reg 850ca987d46SWarner Losh xor %ecx,%ecx # Timeout 851ca987d46SWarner Losh movb $0x40,%ch # counter 852ca987d46SWarner Loshsio_putc.1: inb (%dx),%al # Transmitter 853ca987d46SWarner Losh testb $0x20,%al # buffer empty? 854ca987d46SWarner Losh loopz sio_putc.1 # No 855ca987d46SWarner Losh jz sio_putc.2 # If timeout 856ca987d46SWarner Losh movb 0x4(%esp,1),%al # Get character 857ca987d46SWarner Losh subb $0x5,%dl # Transmitter hold reg 858ca987d46SWarner Losh outb %al,(%dx) # Write character 859ca987d46SWarner Loshsio_putc.2: ret $0x4 # To caller 860ca987d46SWarner Losh 861ca987d46SWarner Losh/* 862ca987d46SWarner Losh * int sio_getc(void) 863ca987d46SWarner Losh */ 864ca987d46SWarner Loshsio_getc: call sio_ischar # Character available? 865ca987d46SWarner Losh jz sio_getc # No 866ca987d46SWarner Loshsio_getc.1: subb $0x5,%dl # Receiver buffer reg 867ca987d46SWarner Losh inb (%dx),%al # Read character 868ca987d46SWarner Losh ret # To caller 869ca987d46SWarner Losh 870ca987d46SWarner Losh/* 871ca987d46SWarner Losh * int sio_ischar(void) 872ca987d46SWarner Losh */ 873ca987d46SWarner Loshsio_ischar: movw $SIO_PRT+0x5,%dx # Line status register 874ca987d46SWarner Losh xorl %eax,%eax # Zero 875ca987d46SWarner Losh inb (%dx),%al # Received data 876ca987d46SWarner Losh andb $0x1,%al # ready? 877ca987d46SWarner Losh ret # To caller 878ca987d46SWarner Losh 879ca987d46SWarner Losh/* 880ca987d46SWarner Losh * Output character AL to the serial console. 881ca987d46SWarner Losh */ 882ca987d46SWarner Loshputchr: pusha # Save 883ca987d46SWarner Losh cmpb $10, %al # is it a newline? 884ca987d46SWarner Losh jne putchr.1 # no?, then leave 885ca987d46SWarner Losh push $13 # output a carriage 886ca987d46SWarner Losh call sio_putc # return first 887ca987d46SWarner Losh movb $10, %al # restore %al 888ca987d46SWarner Loshputchr.1: pushl %eax # Push the character 889ca987d46SWarner Losh # onto the stack 890ca987d46SWarner Losh call sio_putc # Output the character 891ca987d46SWarner Losh popa # Restore 892ca987d46SWarner Losh ret # To caller 893ca987d46SWarner Losh#else 894ca987d46SWarner Losh/* 895ca987d46SWarner Losh * Output character AL to the console. 896ca987d46SWarner Losh */ 897ca987d46SWarner Loshputchr: pusha # Save 898ca987d46SWarner Losh xorl %ecx,%ecx # Zero for loops 899ca987d46SWarner Losh movb $SCR_MAT,%ah # Mode/attribute 900ca987d46SWarner Losh movl $BDA_POS,%ebx # BDA pointer 901ca987d46SWarner Losh movw (%ebx),%dx # Cursor position 902ca987d46SWarner Losh movl $0xb8000,%edi # Regen buffer (color) 903ca987d46SWarner Losh cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? 904ca987d46SWarner Losh jne putchr.1 # No 905ca987d46SWarner Losh xorw %di,%di # Regen buffer (mono) 906ca987d46SWarner Loshputchr.1: cmpb $0xa,%al # New line? 907ca987d46SWarner Losh je putchr.2 # Yes 908ca987d46SWarner Losh xchgl %eax,%ecx # Save char 909ca987d46SWarner Losh movb $SCR_COL,%al # Columns per row 910ca987d46SWarner Losh mulb %dh # * row position 911ca987d46SWarner Losh addb %dl,%al # + column 912ca987d46SWarner Losh adcb $0x0,%ah # position 913ca987d46SWarner Losh shll %eax # * 2 914ca987d46SWarner Losh xchgl %eax,%ecx # Swap char, offset 915ca987d46SWarner Losh movw %ax,(%edi,%ecx,1) # Write attr:char 916ca987d46SWarner Losh incl %edx # Bump cursor 917ca987d46SWarner Losh cmpb $SCR_COL,%dl # Beyond row? 918ca987d46SWarner Losh jb putchr.3 # No 919ca987d46SWarner Loshputchr.2: xorb %dl,%dl # Zero column 920ca987d46SWarner Losh incb %dh # Bump row 921ca987d46SWarner Loshputchr.3: cmpb $SCR_ROW,%dh # Beyond screen? 922ca987d46SWarner Losh jb putchr.4 # No 923ca987d46SWarner Losh leal 2*SCR_COL(%edi),%esi # New top line 924ca987d46SWarner Losh movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move 925ca987d46SWarner Losh rep # Scroll 926ca987d46SWarner Losh movsl # screen 927ca987d46SWarner Losh movb $0x20,%al # Space 928ca987d46SWarner Losh movb $SCR_COL,%cl # Columns to clear 929ca987d46SWarner Losh rep # Clear 930ca987d46SWarner Losh stosw # line 931ca987d46SWarner Losh movb $SCR_ROW-1,%dh # Bottom line 932ca987d46SWarner Loshputchr.4: movw %dx,(%ebx) # Update position 933ca987d46SWarner Losh popa # Restore 934ca987d46SWarner Losh ret # To caller 935ca987d46SWarner Losh#endif 936ca987d46SWarner Losh 937ca987d46SWarner Losh .code16 938ca987d46SWarner Losh/* 939ca987d46SWarner Losh * Real Mode Hardware interrupt jump table. 940ca987d46SWarner Losh */ 941ca987d46SWarner Loshintr20: push $0x8 # Int 0x20: IRQ0 942ca987d46SWarner Losh jmp int_hwr # V86 int 0x8 943ca987d46SWarner Losh push $0x9 # Int 0x21: IRQ1 944ca987d46SWarner Losh jmp int_hwr # V86 int 0x9 945ca987d46SWarner Losh push $0xa # Int 0x22: IRQ2 946ca987d46SWarner Losh jmp int_hwr # V86 int 0xa 947ca987d46SWarner Losh push $0xb # Int 0x23: IRQ3 948ca987d46SWarner Losh jmp int_hwr # V86 int 0xb 949ca987d46SWarner Losh push $0xc # Int 0x24: IRQ4 950ca987d46SWarner Losh jmp int_hwr # V86 int 0xc 951ca987d46SWarner Losh push $0xd # Int 0x25: IRQ5 952ca987d46SWarner Losh jmp int_hwr # V86 int 0xd 953ca987d46SWarner Losh push $0xe # Int 0x26: IRQ6 954ca987d46SWarner Losh jmp int_hwr # V86 int 0xe 955ca987d46SWarner Losh push $0xf # Int 0x27: IRQ7 956ca987d46SWarner Losh jmp int_hwr # V86 int 0xf 957ca987d46SWarner Losh push $0x70 # Int 0x28: IRQ8 958ca987d46SWarner Losh jmp int_hwr # V86 int 0x70 959ca987d46SWarner Losh push $0x71 # Int 0x29: IRQ9 960ca987d46SWarner Losh jmp int_hwr # V86 int 0x71 961ca987d46SWarner Losh push $0x72 # Int 0x2a: IRQ10 962ca987d46SWarner Losh jmp int_hwr # V86 int 0x72 963ca987d46SWarner Losh push $0x73 # Int 0x2b: IRQ11 964ca987d46SWarner Losh jmp int_hwr # V86 int 0x73 965ca987d46SWarner Losh push $0x74 # Int 0x2c: IRQ12 966ca987d46SWarner Losh jmp int_hwr # V86 int 0x74 967ca987d46SWarner Losh push $0x75 # Int 0x2d: IRQ13 968ca987d46SWarner Losh jmp int_hwr # V86 int 0x75 969ca987d46SWarner Losh push $0x76 # Int 0x2e: IRQ14 970ca987d46SWarner Losh jmp int_hwr # V86 int 0x76 971ca987d46SWarner Losh push $0x77 # Int 0x2f: IRQ15 972ca987d46SWarner Losh jmp int_hwr # V86 int 0x77 973ca987d46SWarner Losh/* 974ca987d46SWarner Losh * Reflect hardware interrupts in real mode. 975ca987d46SWarner Losh */ 976ca987d46SWarner Loshint_hwr: push %ax # Save 977ca987d46SWarner Losh push %ds # Save 978ca987d46SWarner Losh push %bp # Save 979ca987d46SWarner Losh mov %sp,%bp # Address stack frame 980ca987d46SWarner Losh xchg %bx,6(%bp) # Swap BX, int no 981ca987d46SWarner Losh xor %ax,%ax # Set %ds:%bx to 982ca987d46SWarner Losh shl $2,%bx # point to 983ca987d46SWarner Losh mov %ax,%ds # IDT entry 984ca987d46SWarner Losh mov (%bx),%ax # Load IP 985ca987d46SWarner Losh mov 2(%bx),%bx # Load CS 986ca987d46SWarner Losh xchg %ax,4(%bp) # Swap saved %ax,%bx with 987ca987d46SWarner Losh xchg %bx,6(%bp) # CS:IP of handler 988ca987d46SWarner Losh pop %bp # Restore 989ca987d46SWarner Losh pop %ds # Restore 990ca987d46SWarner Losh lret # Jump to handler 991ca987d46SWarner Losh 992ca987d46SWarner Losh .p2align 4 993ca987d46SWarner Losh/* 994ca987d46SWarner Losh * Global descriptor table. 995ca987d46SWarner Losh */ 996ca987d46SWarner Loshgdt: .word 0x0,0x0,0x0,0x0 # Null entry 997ca987d46SWarner Losh .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE 998ca987d46SWarner Losh .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA 999ca987d46SWarner Losh .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE 1000ca987d46SWarner Losh .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA 1001ca987d46SWarner Losh .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE 1002ca987d46SWarner Losh .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA 1003ca987d46SWarner Loshtss_desc: .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS 1004ca987d46SWarner Loshgdt.1: 1005ca987d46SWarner Losh/* 1006ca987d46SWarner Losh * Pseudo-descriptors. 1007ca987d46SWarner Losh */ 1008ca987d46SWarner Loshgdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT 1009ca987d46SWarner Loshidtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT 1010ca987d46SWarner Loshivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT 1011ca987d46SWarner Losh/* 1012ca987d46SWarner Losh * IDT construction control string. 1013ca987d46SWarner Losh */ 1014ca987d46SWarner Loshidtctl: .byte 0x10, 0x8e # Int 0x0-0xf 1015ca987d46SWarner Losh .word 0x7dfb,intx00 # (exceptions) 1016ca987d46SWarner Losh .byte 0x10, 0x8e # Int 0x10 1017ca987d46SWarner Losh .word 0x1, intx10 # (exception) 1018ca987d46SWarner Losh .byte 0x10, 0x8e # Int 0x20-0x2f 1019ca987d46SWarner Losh .word 0xffff,intx20 # (hardware) 1020ca987d46SWarner Losh .byte 0x1, 0xee # int 0x30 1021ca987d46SWarner Losh .word 0x1, intx30 # (system call) 1022ca987d46SWarner Losh .byte 0x2, 0xee # Int 0x31-0x32 1023ca987d46SWarner Losh .word 0x1, intx31 # (V86, null) 1024ca987d46SWarner Losh .byte 0x0 # End of string 1025ca987d46SWarner Losh/* 1026ca987d46SWarner Losh * Dump format string. 1027ca987d46SWarner Losh */ 1028ca987d46SWarner Loshdmpfmt: .byte '\n' # "\n" 1029ca987d46SWarner Losh .ascii "int" # "int=" 1030ca987d46SWarner Losh .byte 0x80|DMP_X32, 0x40 # "00000000 " 1031ca987d46SWarner Losh .ascii "err" # "err=" 1032ca987d46SWarner Losh .byte 0x80|DMP_X32, 0x44 # "00000000 " 1033ca987d46SWarner Losh .ascii "efl" # "efl=" 1034ca987d46SWarner Losh .byte 0x80|DMP_X32, 0x50 # "00000000 " 1035ca987d46SWarner Losh .ascii "eip" # "eip=" 1036ca987d46SWarner Losh .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n" 1037ca987d46SWarner Losh .ascii "eax" # "eax=" 1038ca987d46SWarner Losh .byte 0x80|DMP_X32, 0x34 # "00000000 " 1039ca987d46SWarner Losh .ascii "ebx" # "ebx=" 1040ca987d46SWarner Losh .byte 0x80|DMP_X32, 0x28 # "00000000 " 1041ca987d46SWarner Losh .ascii "ecx" # "ecx=" 1042ca987d46SWarner Losh .byte 0x80|DMP_X32, 0x30 # "00000000 " 1043ca987d46SWarner Losh .ascii "edx" # "edx=" 1044ca987d46SWarner Losh .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n" 1045ca987d46SWarner Losh .ascii "esi" # "esi=" 1046ca987d46SWarner Losh .byte 0x80|DMP_X32, 0x1c # "00000000 " 1047ca987d46SWarner Losh .ascii "edi" # "edi=" 1048ca987d46SWarner Losh .byte 0x80|DMP_X32, 0x18 # "00000000 " 1049ca987d46SWarner Losh .ascii "ebp" # "ebp=" 1050ca987d46SWarner Losh .byte 0x80|DMP_X32, 0x20 # "00000000 " 1051ca987d46SWarner Losh .ascii "esp" # "esp=" 1052ca987d46SWarner Losh .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n" 1053ca987d46SWarner Losh .ascii "cs" # "cs=" 1054ca987d46SWarner Losh .byte 0x80|DMP_X16, 0x4c # "0000 " 1055ca987d46SWarner Losh .ascii "ds" # "ds=" 1056ca987d46SWarner Losh .byte 0x80|DMP_X16, 0xc # "0000 " 1057ca987d46SWarner Losh .ascii "es" # "es=" 1058ca987d46SWarner Losh .byte 0x80|DMP_X16, 0x8 # "0000 " 1059ca987d46SWarner Losh .ascii " " # " " 1060ca987d46SWarner Losh .ascii "fs" # "fs=" 1061ca987d46SWarner Losh .byte 0x80|DMP_X16, 0x10 # "0000 " 1062ca987d46SWarner Losh .ascii "gs" # "gs=" 1063ca987d46SWarner Losh .byte 0x80|DMP_X16, 0x14 # "0000 " 1064ca987d46SWarner Losh .ascii "ss" # "ss=" 1065ca987d46SWarner Losh .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n" 1066ca987d46SWarner Losh .ascii "cs:eip" # "cs:eip=" 1067ca987d46SWarner Losh .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n" 1068ca987d46SWarner Losh .ascii "ss:esp" # "ss:esp=" 1069ca987d46SWarner Losh .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n" 1070ca987d46SWarner Losh .asciz "BTX halted\n" # End 1071ca987d46SWarner Losh/* 1072ca987d46SWarner Losh * Bad VM86 call panic 1073ca987d46SWarner Losh */ 1074ca987d46SWarner Loshbadvm86: .asciz "Invalid VM86 Request\n" 1075ca987d46SWarner Losh 1076ca987d46SWarner Losh/* 1077ca987d46SWarner Losh * End of BTX memory. 1078ca987d46SWarner Losh */ 1079ca987d46SWarner Losh .p2align 4 1080ca987d46SWarner Loshbreak: 1081