| 1 | # |
| 2 | # Copyright (c) 1998 Robert Nordier |
| 3 | # All rights reserved. |
| 4 | # |
| 5 | # Redistribution and use in source and binary forms are freely |
| 6 | # permitted provided that the above copyright notice and this |
| 7 | # paragraph and the following disclaimer are duplicated in all |
| 8 | # such forms. |
| 9 | # |
| 10 | # This software is provided "AS IS" and without any express or |
| 11 | # implied warranties, including, without limitation, the implied |
| 12 | # warranties of merchantability and fitness for a particular |
| 13 | # purpose. |
| 14 | # |
| 15 | |
| 16 | # $FreeBSD: src/sys/boot/i386/btx/btx/btx.s,v 1.32 2002/10/08 18:19:02 jhb Exp $ |
| 17 | # $DragonFly: src/sys/boot/i386/btx/btx/Attic/btx.s,v 1.4 2004/06/24 23:31:06 dillon Exp $ |
| 18 | |
| 19 | # |
| 20 | # Memory layout. |
| 21 | # |
| 22 | .set MEM_BTX,0x1000 # Start of BTX memory |
| 23 | .set MEM_ESP0,0x1800 # Supervisor stack |
| 24 | .set MEM_BUF,0x1800 # Scratch buffer |
| 25 | .set MEM_ESP1,0x1e00 # Link stack |
| 26 | .set MEM_IDT,0x1e00 # IDT |
| 27 | .set MEM_TSS,0x1f98 # TSS |
| 28 | .set MEM_MAP,0x2000 # I/O bit map |
| 29 | .set MEM_DIR,0x4000 # Page directory |
| 30 | .set MEM_TBL,0x5000 # Page tables |
| 31 | .set MEM_ORG,0x9000 # BTX code |
| 32 | .set MEM_USR,0xa000 # Start of user memory |
| 33 | # |
| 34 | # Paging control. |
| 35 | # |
| 36 | .set PAG_SIZ,0x1000 # Page size |
| 37 | .set PAG_CNT,0x1000 # Pages to map |
| 38 | # |
| 39 | # Segment selectors. |
| 40 | # |
| 41 | .set SEL_SCODE,0x8 # Supervisor code |
| 42 | .set SEL_SDATA,0x10 # Supervisor data |
| 43 | .set SEL_RCODE,0x18 # Real mode code |
| 44 | .set SEL_RDATA,0x20 # Real mode data |
| 45 | .set SEL_UCODE,0x28|3 # User code |
| 46 | .set SEL_UDATA,0x30|3 # User data |
| 47 | .set SEL_TSS,0x38 # TSS |
| 48 | # |
| 49 | # Task state segment fields. |
| 50 | # |
| 51 | .set TSS_ESP0,0x4 # PL 0 ESP |
| 52 | .set TSS_SS0,0x8 # PL 0 SS |
| 53 | .set TSS_ESP1,0xc # PL 1 ESP |
| 54 | .set TSS_MAP,0x66 # I/O bit map base |
| 55 | # |
| 56 | # System calls. |
| 57 | # |
| 58 | .set SYS_EXIT,0x0 # Exit |
| 59 | .set SYS_EXEC,0x1 # Exec |
| 60 | # |
| 61 | # V86 constants. |
| 62 | # |
| 63 | .set V86_FLG,0x208eff # V86 flag mask |
| 64 | .set V86_STK,0x400 # V86 stack allowance |
| 65 | # |
| 66 | # Dump format control bytes. |
| 67 | # |
| 68 | .set DMP_X16,0x1 # Word |
| 69 | .set DMP_X32,0x2 # Long |
| 70 | .set DMP_MEM,0x4 # Memory |
| 71 | .set DMP_EOL,0x8 # End of line |
| 72 | # |
| 73 | # Screen defaults and assumptions. |
| 74 | # |
| 75 | .set SCR_MAT,0x7 # Mode/attribute |
| 76 | .set SCR_COL,0x50 # Columns per row |
| 77 | .set SCR_ROW,0x19 # Rows per screen |
| 78 | # |
| 79 | # BIOS Data Area locations. |
| 80 | # |
| 81 | .set BDA_MEM,0x413 # Free memory |
| 82 | .set BDA_KEYFLAGS,0x417 # Keyboard shift-state flags |
| 83 | .set BDA_SCR,0x449 # Video mode |
| 84 | .set BDA_POS,0x450 # Cursor position |
| 85 | .set BDA_BOOT,0x472 # Boot howto flag |
| 86 | # |
| 87 | # Derivations, for brevity. |
| 88 | # |
| 89 | .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0 |
| 90 | .set _ESP1H,MEM_ESP1>>0x8 # Byte 1 of ESP1 |
| 91 | .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base |
| 92 | .set _TSSLM,MEM_DIR-MEM_TSS-1 # TSS limit |
| 93 | .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit |
| 94 | # |
| 95 | # Code segment. |
| 96 | # |
| 97 | .globl start |
| 98 | .code16 |
| 99 | start: # Start of code |
| 100 | # |
| 101 | # BTX header. |
| 102 | # |
| 103 | btx_hdr: .byte 0xeb # Machine ID |
| 104 | .byte 0xe # Header size |
| 105 | .ascii "BTX" # Magic |
| 106 | .byte 0x1 # Major version |
| 107 | .byte 0x1 # Minor version |
| 108 | .byte BTX_FLAGS # Flags |
| 109 | .word PAG_CNT-MEM_ORG>>0xc # Paging control |
| 110 | .word break-start # Text size |
| 111 | .long 0x0 # Entry address |
| 112 | # |
| 113 | # Initialization routine. |
| 114 | # |
| 115 | init: cli # Disable interrupts |
| 116 | xor %ax,%ax # Zero/segment |
| 117 | mov %ax,%ss # Set up |
| 118 | mov $MEM_ESP0,%sp # stack |
| 119 | mov %ax,%es # Address |
| 120 | mov %ax,%ds # data |
| 121 | pushl $0x2 # Clear |
| 122 | popfl # flags |
| 123 | # |
| 124 | # Initialize memory. |
| 125 | # |
| 126 | mov $MEM_IDT,%di # Memory to initialize |
| 127 | mov $(MEM_ORG-MEM_IDT)/2,%cx # Words to zero |
| 128 | push %di # Save |
| 129 | rep # Zero-fill |
| 130 | stosw # memory |
| 131 | pop %di # Restore |
| 132 | # |
| 133 | # Create IDT. |
| 134 | # |
| 135 | mov $idtctl,%si # Control string |
| 136 | init.1: lodsb # Get entry |
| 137 | cbw # count |
| 138 | xchg %ax,%cx # as word |
| 139 | jcxz init.4 # If done |
| 140 | lodsb # Get segment |
| 141 | xchg %ax,%dx # P:DPL:type |
| 142 | lodsw # Get control |
| 143 | xchg %ax,%bx # set |
| 144 | lodsw # Get handler offset |
| 145 | mov $SEL_SCODE,%dh # Segment selector |
| 146 | init.2: shr %bx # Handle this int? |
| 147 | jnc init.3 # No |
| 148 | mov %ax,(%di) # Set handler offset |
| 149 | mov %dh,0x2(%di) # and selector |
| 150 | mov %dl,0x5(%di) # Set P:DPL:type |
| 151 | add $0x4,%ax # Next handler |
| 152 | init.3: lea 0x8(%di),%di # Next entry |
| 153 | loop init.2 # Till set done |
| 154 | jmp init.1 # Continue |
| 155 | # |
| 156 | # Initialize TSS. |
| 157 | # |
| 158 | init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0 |
| 159 | movb $SEL_SDATA,TSS_SS0(%di) # Set SS0 |
| 160 | movb $_ESP1H,TSS_ESP1+1(%di) # Set ESP1 |
| 161 | movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base |
| 162 | ifdef(`PAGING',` |
| 163 | # |
| 164 | # Create page directory. |
| 165 | # |
| 166 | xor %edx,%edx # Page |
| 167 | mov $PAG_SIZ>>0x8,%dh # size |
| 168 | xor %eax,%eax # Zero |
| 169 | mov $MEM_DIR,%di # Page directory |
| 170 | mov $PAG_CNT>>0xa,%cl # Entries |
| 171 | mov $MEM_TBL|0x7,%ax # First entry |
| 172 | init.5: stosl # Write entry |
| 173 | add %dx,%ax # To next |
| 174 | loop init.5 # Till done |
| 175 | # |
| 176 | # Create page tables. |
| 177 | # |
| 178 | mov $MEM_TBL,%di # Page table |
| 179 | mov $PAG_CNT>>0x8,%ch # Entries |
| 180 | xor %ax,%ax # Start address |
| 181 | init.6: mov $0x7,%al # Set U:W:P flags |
| 182 | cmp btx_hdr+0x8,%cx # Standard user page? |
| 183 | jb init.7 # Yes |
| 184 | cmp $PAG_CNT-MEM_BTX>>0xc,%cx # BTX memory? |
| 185 | jae init.7 # No or first page |
| 186 | and $~0x2,%al # Clear W flag |
| 187 | cmp $PAG_CNT-MEM_USR>>0xc,%cx # User page zero? |
| 188 | jne init.7 # No |
| 189 | testb $0x80,btx_hdr+0x7 # Unmap it? |
| 190 | jz init.7 # No |
| 191 | and $~0x1,%al # Clear P flag |
| 192 | init.7: stosl # Set entry |
| 193 | add %edx,%eax # Next address |
| 194 | loop init.6 # Till done |
| 195 | ') |
| 196 | # |
| 197 | # Bring up the system. |
| 198 | # |
| 199 | mov $0x2820,%bx # Set protected mode |
| 200 | callw setpic # IRQ offsets |
| 201 | lidt idtdesc # Set IDT |
| 202 | ifdef(`PAGING',` |
| 203 | xor %eax,%eax # Set base |
| 204 | mov $MEM_DIR>>0x8,%ah # of page |
| 205 | mov %eax,%cr3 # directory |
| 206 | ') |
| 207 | lgdt gdtdesc # Set GDT |
| 208 | mov %cr0,%eax # Switch to protected |
| 209 | ifdef(`PAGING',` |
| 210 | or $0x80000001,%eax # mode and enable paging |
| 211 | ',` |
| 212 | or $0x01,%eax # mode |
| 213 | ') |
| 214 | mov %eax,%cr0 # |
| 215 | ljmp $SEL_SCODE,$init.8 # To 32-bit code |
| 216 | .code32 |
| 217 | init.8: xorl %ecx,%ecx # Zero |
| 218 | movb $SEL_SDATA,%cl # To 32-bit |
| 219 | movw %cx,%ss # stack |
| 220 | # |
| 221 | # Launch user task. |
| 222 | # |
| 223 | movb $SEL_TSS,%cl # Set task |
| 224 | ltr %cx # register |
| 225 | movl $MEM_USR,%edx # User base address |
| 226 | movzwl %ss:BDA_MEM,%eax # Get free memory |
| 227 | shll $0xa,%eax # To bytes |
| 228 | subl $0x1000,%eax # Less arg space |
| 229 | subl %edx,%eax # Less base |
| 230 | movb $SEL_UDATA,%cl # User data selector |
| 231 | pushl %ecx # Set SS |
| 232 | pushl %eax # Set ESP |
| 233 | push $0x202 # Set flags (IF set) |
| 234 | push $SEL_UCODE # Set CS |
| 235 | pushl btx_hdr+0xc # Set EIP |
| 236 | pushl %ecx # Set GS |
| 237 | pushl %ecx # Set FS |
| 238 | pushl %ecx # Set DS |
| 239 | pushl %ecx # Set ES |
| 240 | pushl %edx # Set EAX |
| 241 | movb $0x7,%cl # Set remaining |
| 242 | init.9: push $0x0 # general |
| 243 | loop init.9 # registers |
| 244 | ifdef(`BTX_SERIAL',` |
| 245 | call sio_init # setup the serial console |
| 246 | ') |
| 247 | popa # and initialize |
| 248 | popl %es # Initialize |
| 249 | popl %ds # user |
| 250 | popl %fs # segment |
| 251 | popl %gs # registers |
| 252 | iret # To user mode |
| 253 | # |
| 254 | # Exit routine. |
| 255 | # |
| 256 | exit: cli # Disable interrupts |
| 257 | movl $MEM_ESP0,%esp # Clear stack |
| 258 | # |
| 259 | # Turn off paging. |
| 260 | # |
| 261 | movl %cr0,%eax # Get CR0 |
| 262 | andl $~0x80000000,%eax # Disable |
| 263 | movl %eax,%cr0 # paging |
| 264 | xorl %ecx,%ecx # Zero |
| 265 | movl %ecx,%cr3 # Flush TLB |
| 266 | # |
| 267 | # Restore the GDT in case we caught a kernel trap. |
| 268 | # |
| 269 | lgdt gdtdesc # Set GDT |
| 270 | # |
| 271 | # To 16 bits. |
| 272 | # |
| 273 | ljmpw $SEL_RCODE,$exit.1 # Reload CS |
| 274 | .code16 |
| 275 | exit.1: mov $SEL_RDATA,%cl # 16-bit selector |
| 276 | mov %cx,%ss # Reload SS |
| 277 | mov %cx,%ds # Load |
| 278 | mov %cx,%es # remaining |
| 279 | mov %cx,%fs # segment |
| 280 | mov %cx,%gs # registers |
| 281 | # |
| 282 | # To real-address mode. |
| 283 | # |
| 284 | dec %ax # Switch to |
| 285 | mov %eax,%cr0 # real mode |
| 286 | ljmp $0x0,$exit.2 # Reload CS |
| 287 | exit.2: xor %ax,%ax # Real mode segment |
| 288 | mov %ax,%ss # Reload SS |
| 289 | mov %ax,%ds # Address data |
| 290 | mov $0x7008,%bx # Set real mode |
| 291 | callw setpic # IRQ offsets |
| 292 | lidt ivtdesc # Set IVT |
| 293 | # |
| 294 | # Reboot or await reset. |
| 295 | # |
| 296 | sti # Enable interrupts |
| 297 | testb $0x1,btx_hdr+0x7 # Reboot? |
| 298 | exit.3: jz exit.3 # No |
| 299 | movw $0x1234, BDA_BOOT # Do a warm boot |
| 300 | ljmp $0xf000,$0xfff0 # reboot the machine |
| 301 | # |
| 302 | # Set IRQ offsets by reprogramming 8259A PICs. |
| 303 | # |
| 304 | setpic: in $0x21,%al # Save master |
| 305 | push %ax # IMR |
| 306 | in $0xa1,%al # Save slave |
| 307 | push %ax # IMR |
| 308 | movb $0x11,%al # ICW1 to |
| 309 | outb %al,$0x20 # master, |
| 310 | outb %al,$0xa0 # slave |
| 311 | movb %bl,%al # ICW2 to |
| 312 | outb %al,$0x21 # master |
| 313 | movb %bh,%al # ICW2 to |
| 314 | outb %al,$0xa1 # slave |
| 315 | movb $0x4,%al # ICW3 to |
| 316 | outb %al,$0x21 # master |
| 317 | movb $0x2,%al # ICW3 to |
| 318 | outb %al,$0xa1 # slave |
| 319 | movb $0x1,%al # ICW4 to |
| 320 | outb %al,$0x21 # master, |
| 321 | outb %al,$0xa1 # slave |
| 322 | pop %ax # Restore slave |
| 323 | outb %al,$0xa1 # IMR |
| 324 | pop %ax # Restore master |
| 325 | outb %al,$0x21 # IMR |
| 326 | retw # To caller |
| 327 | .code32 |
| 328 | # |
| 329 | # Initiate return from V86 mode to user mode. |
| 330 | # |
| 331 | inthlt: hlt # To supervisor mode |
| 332 | # |
| 333 | # Exception jump table. |
| 334 | # |
| 335 | intx00: push $0x0 # Int 0x0: #DE |
| 336 | jmp ex_noc # Divide error |
| 337 | push $0x1 # Int 0x1: #DB |
| 338 | jmp ex_noc # Debug |
| 339 | push $0x3 # Int 0x3: #BP |
| 340 | jmp ex_noc # Breakpoint |
| 341 | push $0x4 # Int 0x4: #OF |
| 342 | jmp ex_noc # Overflow |
| 343 | push $0x5 # Int 0x5: #BR |
| 344 | jmp ex_noc # BOUND range exceeded |
| 345 | push $0x6 # Int 0x6: #UD |
| 346 | jmp ex_noc # Invalid opcode |
| 347 | push $0x7 # Int 0x7: #NM |
| 348 | jmp ex_noc # Device not available |
| 349 | push $0x8 # Int 0x8: #DF |
| 350 | jmp except # Double fault |
| 351 | push $0xa # Int 0xa: #TS |
| 352 | jmp except # Invalid TSS |
| 353 | push $0xb # Int 0xb: #NP |
| 354 | jmp except # Segment not present |
| 355 | push $0xc # Int 0xc: #SS |
| 356 | jmp except # Stack segment fault |
| 357 | push $0xd # Int 0xd: #GP |
| 358 | jmp ex_v86 # General protection |
| 359 | push $0xe # Int 0xe: #PF |
| 360 | jmp except # Page fault |
| 361 | intx10: push $0x10 # Int 0x10: #MF |
| 362 | jmp ex_noc # Floating-point error |
| 363 | # |
| 364 | # Handle #GP exception. |
| 365 | # |
| 366 | ex_v86: testb $0x2,0x12(%esp,1) # V86 mode? |
| 367 | jz except # No |
| 368 | jmp v86mon # To monitor |
| 369 | # |
| 370 | # Save a zero error code. |
| 371 | # |
| 372 | ex_noc: pushl (%esp,1) # Duplicate int no |
| 373 | movb $0x0,0x4(%esp,1) # Fake error code |
| 374 | # |
| 375 | # Handle exception. |
| 376 | # |
| 377 | except: cld # String ops inc |
| 378 | pushl %ds # Save |
| 379 | pushl %es # most |
| 380 | pusha # registers |
| 381 | movb $0x6,%al # Push loop count |
| 382 | testb $0x2,0x3a(%esp,1) # V86 mode? |
| 383 | jnz except.1 # Yes |
| 384 | pushl %gs # Set GS |
| 385 | pushl %fs # Set FS |
| 386 | pushl %ds # Set DS |
| 387 | pushl %es # Set ES |
| 388 | movb $0x2,%al # Push loop count |
| 389 | cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode? |
| 390 | jne except.1 # No |
| 391 | pushl %ss # Set SS |
| 392 | leal 0x50(%esp,1),%eax # Set |
| 393 | pushl %eax # ESP |
| 394 | jmp except.2 # Join common code |
| 395 | except.1: pushl 0x50(%esp,1) # Set GS, FS, DS, ES |
| 396 | decb %al # (if V86 mode), and |
| 397 | jne except.1 # SS, ESP |
| 398 | except.2: push $SEL_SDATA # Set up |
| 399 | popl %ds # to |
| 400 | pushl %ds # address |
| 401 | popl %es # data |
| 402 | movl %esp,%ebx # Stack frame |
| 403 | movl $dmpfmt,%esi # Dump format string |
| 404 | movl $MEM_BUF,%edi # Buffer |
| 405 | pushl %edi # Dump to |
| 406 | call dump # buffer |
| 407 | popl %esi # and |
| 408 | call putstr # display |
| 409 | leal 0x18(%esp,1),%esp # Discard frame |
| 410 | popa # Restore |
| 411 | popl %es # registers |
| 412 | popl %ds # saved |
| 413 | cmpb $0x3,(%esp,1) # Breakpoint? |
| 414 | je except.3 # Yes |
| 415 | cmpb $0x1,(%esp,1) # Debug? |
| 416 | jne except.2a # No |
| 417 | testl $0x100,0x10(%esp,1) # Trap flag set? |
| 418 | jnz except.3 # Yes |
| 419 | except.2a: jmp exit # Exit |
| 420 | except.3: leal 0x8(%esp,1),%esp # Discard err, int no |
| 421 | iret # From interrupt |
| 422 | # |
| 423 | # Return to user mode from V86 mode. |
| 424 | # |
| 425 | intrtn: cld # String ops inc |
| 426 | pushl %ds # Address |
| 427 | popl %es # data |
| 428 | leal 0x3c(%ebp),%edx # V86 Segment registers |
| 429 | movl MEM_TSS+TSS_ESP1,%esi # Link stack pointer |
| 430 | lodsl # INT_V86 args pointer |
| 431 | movl %esi,%ebx # Saved exception frame |
| 432 | testl %eax,%eax # INT_V86 args? |
| 433 | jz intrtn.2 # No |
| 434 | movl $MEM_USR,%edi # User base |
| 435 | movl 0x1c(%esi),%ebx # User ESP |
| 436 | movl %eax,(%edi,%ebx,1) # Restore to user stack |
| 437 | leal 0x8(%edi,%eax,1),%edi # Arg segment registers |
| 438 | testb $0x4,-0x6(%edi) # Return flags? |
| 439 | jz intrtn.1 # No |
| 440 | movl 0x30(%ebp),%eax # Get V86 flags |
| 441 | movw %ax,0x18(%esi) # Set user flags |
| 442 | intrtn.1: leal 0x10(%esi),%ebx # Saved exception frame |
| 443 | xchgl %edx,%esi # Segment registers |
| 444 | movb $0x4,%cl # Update seg regs |
| 445 | rep # in INT_V86 |
| 446 | movsl # args |
| 447 | intrtn.2: movl %edx,%esi # Segment registers |
| 448 | leal 0x28(%ebp),%edi # Set up seg |
| 449 | movb $0x4,%cl # regs for |
| 450 | rep # later |
| 451 | movsl # pop |
| 452 | movl %ebx,%esi # Restore exception |
| 453 | movb $0x5,%cl # frame to |
| 454 | rep # supervisor |
| 455 | movsl # stack |
| 456 | movl %esi,MEM_TSS+TSS_ESP1 # Link stack pointer |
| 457 | popa # Restore |
| 458 | leal 0x8(%esp,1),%esp # Discard err, int no |
| 459 | popl %es # Restore |
| 460 | popl %ds # user |
| 461 | popl %fs # segment |
| 462 | popl %gs # registers |
| 463 | iret # To user mode |
| 464 | # |
| 465 | # V86 monitor. |
| 466 | # |
| 467 | v86mon: cld # String ops inc |
| 468 | pushl $SEL_SDATA # Set up for |
| 469 | popl %ds # flat addressing |
| 470 | pusha # Save registers |
| 471 | movl %esp,%ebp # Address stack frame |
| 472 | movzwl 0x2c(%ebp),%edi # Load V86 CS |
| 473 | shll $0x4,%edi # To linear |
| 474 | movl 0x28(%ebp),%esi # Load V86 IP |
| 475 | addl %edi,%esi # Code pointer |
| 476 | xorl %ecx,%ecx # Zero |
| 477 | movb $0x2,%cl # 16-bit operands |
| 478 | xorl %eax,%eax # Zero |
| 479 | v86mon.1: lodsb # Get opcode |
| 480 | cmpb $0x66,%al # Operand size prefix? |
| 481 | jne v86mon.2 # No |
| 482 | movb $0x4,%cl # 32-bit operands |
| 483 | jmp v86mon.1 # Continue |
| 484 | v86mon.2: cmpb $0xf4,%al # HLT? |
| 485 | jne v86mon.3 # No |
| 486 | cmpl $inthlt+0x1,%esi # Is inthlt? |
| 487 | jne v86mon.7 # No (ignore) |
| 488 | jmp intrtn # Return to user mode |
| 489 | v86mon.3: cmpb $0xf,%al # Prefixed instruction? |
| 490 | jne v86mon.4 # No |
| 491 | cmpb $0x09,(%esi) # Is it a WBINVD? |
| 492 | je v86wbinvd # Yes |
| 493 | cmpb $0x30,(%esi) # Is it a WRMSR? |
| 494 | je v86wrmsr # Yes |
| 495 | cmpb $0x32,(%esi) # Is it a RDMSR? |
| 496 | je v86rdmsr # Yes |
| 497 | cmpb $0x20,(%esi) # Is this a |
| 498 | jne v86mon.4 # MOV EAX,CR0 |
| 499 | cmpb $0xc0,0x1(%esi) # instruction? |
| 500 | je v86mov # Yes |
| 501 | v86mon.4: cmpb $0xfa,%al # CLI? |
| 502 | je v86cli # Yes |
| 503 | cmpb $0xfb,%al # STI? |
| 504 | je v86sti # Yes |
| 505 | movzwl 0x38(%ebp),%ebx # Load V86 SS |
| 506 | shll $0x4,%ebx # To offset |
| 507 | pushl %ebx # Save |
| 508 | addl 0x34(%ebp),%ebx # Add V86 SP |
| 509 | movl 0x30(%ebp),%edx # Load V86 flags |
| 510 | cmpb $0x9c,%al # PUSHF/PUSHFD? |
| 511 | je v86pushf # Yes |
| 512 | cmpb $0x9d,%al # POPF/POPFD? |
| 513 | je v86popf # Yes |
| 514 | cmpb $0xcd,%al # INT imm8? |
| 515 | je v86intn # Yes |
| 516 | cmpb $0xcf,%al # IRET/IRETD? |
| 517 | je v86iret # Yes |
| 518 | popl %ebx # Restore |
| 519 | popa # Restore |
| 520 | jmp except # Handle exception |
| 521 | v86mon.5: movl %edx,0x30(%ebp) # Save V86 flags |
| 522 | v86mon.6: popl %edx # V86 SS adjustment |
| 523 | subl %edx,%ebx # Save V86 |
| 524 | movl %ebx,0x34(%ebp) # SP |
| 525 | v86mon.7: subl %edi,%esi # From linear |
| 526 | movl %esi,0x28(%ebp) # Save V86 IP |
| 527 | popa # Restore |
| 528 | leal 0x8(%esp,1),%esp # Discard int no, error |
| 529 | iret # To V86 mode |
| 530 | # |
| 531 | # Emulate MOV EAX,CR0. |
| 532 | # |
| 533 | v86mov: movl %cr0,%eax # CR0 to |
| 534 | movl %eax,0x1c(%ebp) # saved EAX |
| 535 | incl %esi # Adjust IP |
| 536 | # |
| 537 | # Return from emulating a 0x0f prefixed instruction |
| 538 | # |
| 539 | v86preret: incl %esi # Adjust IP |
| 540 | jmp v86mon.7 # Finish up |
| 541 | # |
| 542 | # Emulate WBINVD |
| 543 | # |
| 544 | v86wbinvd: wbinvd # Write back and invalidate |
| 545 | # cache |
| 546 | jmp v86preret # Finish up |
| 547 | # |
| 548 | # Emulate WRMSR |
| 549 | # |
| 550 | v86wrmsr: movl 0x18(%ebp),%ecx # Get user's %ecx (MSR to write) |
| 551 | movl 0x14(%ebp),%edx # Load the value |
| 552 | movl 0x1c(%ebp),%eax # to write |
| 553 | wrmsr # Write MSR |
| 554 | jmp v86preret # Finish up |
| 555 | # |
| 556 | # Emulate RDMSR |
| 557 | # |
| 558 | v86rdmsr: movl 0x18(%ebp),%ecx # MSR to read |
| 559 | rdmsr # Read the MSR |
| 560 | movl %eax,0x1c(%ebp) # Return the value of |
| 561 | movl %edx,0x14(%ebp) # the MSR to the user |
| 562 | jmp v86preret # Finish up |
| 563 | # |
| 564 | # Emulate CLI. |
| 565 | # |
| 566 | v86cli: andb $~0x2,0x31(%ebp) # Clear IF |
| 567 | jmp v86mon.7 # Finish up |
| 568 | # |
| 569 | # Emulate STI. |
| 570 | # |
| 571 | v86sti: orb $0x2,0x31(%ebp) # Set IF |
| 572 | jmp v86mon.7 # Finish up |
| 573 | # |
| 574 | # Emulate PUSHF/PUSHFD. |
| 575 | # |
| 576 | v86pushf: subl %ecx,%ebx # Adjust SP |
| 577 | cmpb $0x4,%cl # 32-bit |
| 578 | je v86pushf.1 # Yes |
| 579 | data16 # 16-bit |
| 580 | v86pushf.1: movl %edx,(%ebx) # Save flags |
| 581 | jmp v86mon.6 # Finish up |
| 582 | # |
| 583 | # Emulate IRET/IRETD. |
| 584 | # |
| 585 | v86iret: movzwl (%ebx),%esi # Load V86 IP |
| 586 | movzwl 0x2(%ebx),%edi # Load V86 CS |
| 587 | leal 0x4(%ebx),%ebx # Adjust SP |
| 588 | movl %edi,0x2c(%ebp) # Save V86 CS |
| 589 | xorl %edi,%edi # No ESI adjustment |
| 590 | # |
| 591 | # Emulate POPF/POPFD (and remainder of IRET/IRETD). |
| 592 | # |
| 593 | v86popf: cmpb $0x4,%cl # 32-bit? |
| 594 | je v86popf.1 # Yes |
| 595 | movl %edx,%eax # Initialize |
| 596 | data16 # 16-bit |
| 597 | v86popf.1: movl (%ebx),%eax # Load flags |
| 598 | addl %ecx,%ebx # Adjust SP |
| 599 | andl $V86_FLG,%eax # Merge |
| 600 | andl $~V86_FLG,%edx # the |
| 601 | orl %eax,%edx # flags |
| 602 | jmp v86mon.5 # Finish up |
| 603 | # |
| 604 | # trap int 15, function 87 |
| 605 | # reads %es:%si from saved registers on stack to find a GDT containing |
| 606 | # source and destination locations |
| 607 | # reads count of words from saved %cx |
| 608 | # returns success by setting %ah to 0 |
| 609 | # |
| 610 | int15_87: pushl %eax # Save |
| 611 | pushl %ebx # some information |
| 612 | pushl %esi # onto the stack. |
| 613 | pushl %edi |
| 614 | xorl %eax,%eax # clean EAX |
| 615 | xorl %ebx,%ebx # clean EBX |
| 616 | movl 0x4(%ebp),%esi # Get user's ESI |
| 617 | movl 0x3C(%ebp),%ebx # store ES |
| 618 | movw %si,%ax # store SI |
| 619 | shll $0x4,%ebx # Make it a seg. |
| 620 | addl %eax,%ebx # ebx=(es<<4)+si |
| 621 | movb 0x14(%ebx),%al # Grab the |
| 622 | movb 0x17(%ebx),%ah # necessary |
| 623 | shll $0x10,%eax # information |
| 624 | movw 0x12(%ebx),%ax # from |
| 625 | movl %eax,%esi # the |
| 626 | movb 0x1c(%ebx),%al # GDT in order to |
| 627 | movb 0x1f(%ebx),%ah # have %esi offset |
| 628 | shll $0x10,%eax # of source and %edi |
| 629 | movw 0x1a(%ebx),%ax # of destination. |
| 630 | movl %eax,%edi |
| 631 | pushl %ds # Make: |
| 632 | popl %es # es = ds |
| 633 | pushl %ecx # stash ECX |
| 634 | xorl %ecx,%ecx # highw of ECX is clear |
| 635 | movw 0x18(%ebp),%cx # Get user's ECX |
| 636 | shll $0x1,%ecx # Convert from num words to num |
| 637 | # bytes |
| 638 | rep # repeat... |
| 639 | movsb # perform copy. |
| 640 | popl %ecx # Restore |
| 641 | popl %edi |
| 642 | popl %esi # previous |
| 643 | popl %ebx # register |
| 644 | popl %eax # values. |
| 645 | movb $0x0,0x1d(%ebp) # set ah = 0 to indicate |
| 646 | # success |
| 647 | andb $0xfe,%dl # clear CF |
| 648 | jmp v86mon.5 # Finish up |
| 649 | |
| 650 | # |
| 651 | # Reboot the machine by setting the reboot flag and exiting |
| 652 | # |
| 653 | reboot: orb $0x1,btx_hdr+0x7 # Set the reboot flag |
| 654 | jmp exit # Terminate BTX and reboot |
| 655 | |
| 656 | # |
| 657 | # Emulate INT imm8... also make sure to check if it's int 15/87 |
| 658 | # |
| 659 | v86intn: lodsb # Get int no |
| 660 | cmpb $0x19,%al # is it int 19? |
| 661 | je reboot # yes, reboot the machine |
| 662 | cmpb $0x15,%al # is it int 15? |
| 663 | jne v86intn.3 # no, skip parse |
| 664 | pushl %eax # stash EAX |
| 665 | movl 0x1c(%ebp),%eax # user's saved EAX |
| 666 | cmpb $0x87,%ah # is it the memcpy subfunction? |
| 667 | jne v86intn.1 # no, keep checking |
| 668 | popl %eax # get the stack straight |
| 669 | jmp int15_87 # it's our cue |
| 670 | v86intn.1: cmpw $0x4f53,%ax # is it the delete key callout? |
| 671 | jne v86intn.2 # no, handle the int normally |
| 672 | movb BDA_KEYFLAGS,%al # get the shift key state |
| 673 | andb $0xc,%al # mask off just Ctrl and Alt |
| 674 | cmpb $0xc,%al # are both Ctrl and Alt down? |
| 675 | jne v86intn.2 # no, handle the int normally |
| 676 | popl %eax # restore EAX |
| 677 | jmp reboot # reboot the machine |
| 678 | v86intn.2: popl %eax # restore EAX |
| 679 | v86intn.3: subl %edi,%esi # From |
| 680 | shrl $0x4,%edi # linear |
| 681 | movw %dx,-0x2(%ebx) # Save flags |
| 682 | movw %di,-0x4(%ebx) # Save CS |
| 683 | leal -0x6(%ebx),%ebx # Adjust SP |
| 684 | movw %si,(%ebx) # Save IP |
| 685 | shll $0x2,%eax # Scale |
| 686 | movzwl (%eax),%esi # Load IP |
| 687 | movzwl 0x2(%eax),%edi # Load CS |
| 688 | movl %edi,0x2c(%ebp) # Save CS |
| 689 | xorl %edi,%edi # No ESI adjustment |
| 690 | andb $~0x1,%dh # Clear TF |
| 691 | jmp v86mon.5 # Finish up |
| 692 | # |
| 693 | # Hardware interrupt jump table. |
| 694 | # |
| 695 | intx20: push $0x8 # Int 0x20: IRQ0 |
| 696 | jmp int_hw # V86 int 0x8 |
| 697 | push $0x9 # Int 0x21: IRQ1 |
| 698 | jmp int_hw # V86 int 0x9 |
| 699 | push $0xa # Int 0x22: IRQ2 |
| 700 | jmp int_hw # V86 int 0xa |
| 701 | push $0xb # Int 0x23: IRQ3 |
| 702 | jmp int_hw # V86 int 0xb |
| 703 | push $0xc # Int 0x24: IRQ4 |
| 704 | jmp int_hw # V86 int 0xc |
| 705 | push $0xd # Int 0x25: IRQ5 |
| 706 | jmp int_hw # V86 int 0xd |
| 707 | push $0xe # Int 0x26: IRQ6 |
| 708 | jmp int_hw # V86 int 0xe |
| 709 | push $0xf # Int 0x27: IRQ7 |
| 710 | jmp int_hw # V86 int 0xf |
| 711 | push $0x70 # Int 0x28: IRQ8 |
| 712 | jmp int_hw # V86 int 0x70 |
| 713 | push $0x71 # Int 0x29: IRQ9 |
| 714 | jmp int_hw # V86 int 0x71 |
| 715 | push $0x72 # Int 0x2a: IRQ10 |
| 716 | jmp int_hw # V86 int 0x72 |
| 717 | push $0x73 # Int 0x2b: IRQ11 |
| 718 | jmp int_hw # V86 int 0x73 |
| 719 | push $0x74 # Int 0x2c: IRQ12 |
| 720 | jmp int_hw # V86 int 0x74 |
| 721 | push $0x75 # Int 0x2d: IRQ13 |
| 722 | jmp int_hw # V86 int 0x75 |
| 723 | push $0x76 # Int 0x2e: IRQ14 |
| 724 | jmp int_hw # V86 int 0x76 |
| 725 | push $0x77 # Int 0x2f: IRQ15 |
| 726 | jmp int_hw # V86 int 0x77 |
| 727 | # |
| 728 | # Reflect hardware interrupts. |
| 729 | # |
| 730 | int_hw: testb $0x2,0xe(%esp,1) # V86 mode? |
| 731 | jz intusr # No |
| 732 | pushl $SEL_SDATA # Address |
| 733 | popl %ds # data |
| 734 | xchgl %eax,(%esp,1) # Swap EAX, int no |
| 735 | pushl %ebp # Address |
| 736 | movl %esp,%ebp # stack frame |
| 737 | pushl %ebx # Save |
| 738 | shll $0x2,%eax # Get int |
| 739 | movl (%eax),%eax # vector |
| 740 | subl $0x6,0x14(%ebp) # Adjust V86 ESP |
| 741 | movzwl 0x18(%ebp),%ebx # V86 SS |
| 742 | shll $0x4,%ebx # * 0x10 |
| 743 | addl 0x14(%ebp),%ebx # + V86 ESP |
| 744 | xchgw %ax,0x8(%ebp) # Swap V86 IP |
| 745 | rorl $0x10,%eax # Swap words |
| 746 | xchgw %ax,0xc(%ebp) # Swap V86 CS |
| 747 | roll $0x10,%eax # Swap words |
| 748 | movl %eax,(%ebx) # CS:IP for IRET |
| 749 | movl 0x10(%ebp),%eax # V86 flags |
| 750 | movw %ax,0x4(%ebx) # Flags for IRET |
| 751 | andb $~0x3,0x11(%ebp) # Clear IF, TF |
| 752 | popl %ebx # Restore |
| 753 | popl %ebp # saved |
| 754 | popl %eax # registers |
| 755 | iret # To V86 mode |
| 756 | # |
| 757 | # Invoke V86 interrupt from user mode, with arguments. |
| 758 | # |
| 759 | intx31: stc # Have btx_v86 |
| 760 | pushl %eax # Missing int no |
| 761 | # |
| 762 | # Invoke V86 interrupt from user mode. |
| 763 | # |
| 764 | intusr: std # String ops dec |
| 765 | pushl %eax # Expand |
| 766 | pushl %eax # stack |
| 767 | pushl %eax # frame |
| 768 | pusha # Save |
| 769 | pushl %gs # Save |
| 770 | movl %esp,%eax # seg regs |
| 771 | pushl %fs # and |
| 772 | pushl %ds # point |
| 773 | pushl %es # to them |
| 774 | push $SEL_SDATA # Set up |
| 775 | popl %ds # to |
| 776 | pushl %ds # address |
| 777 | popl %es # data |
| 778 | movl $MEM_USR,%ebx # User base |
| 779 | movl %ebx,%edx # address |
| 780 | jc intusr.1 # If btx_v86 |
| 781 | xorl %edx,%edx # Control flags |
| 782 | xorl %ebp,%ebp # btx_v86 pointer |
| 783 | intusr.1: leal 0x50(%esp,1),%esi # Base of frame |
| 784 | pushl %esi # Save |
| 785 | addl -0x4(%esi),%ebx # User ESP |
| 786 | movl MEM_TSS+TSS_ESP1,%edi # Link stack pointer |
| 787 | leal -0x4(%edi),%edi # Adjust for push |
| 788 | xorl %ecx,%ecx # Zero |
| 789 | movb $0x5,%cl # Push exception |
| 790 | rep # frame on |
| 791 | movsl # link stack |
| 792 | xchgl %eax,%esi # Saved seg regs |
| 793 | movl 0x40(%esp,1),%eax # Get int no |
| 794 | testl %edx,%edx # Have btx_v86? |
| 795 | jz intusr.2 # No |
| 796 | movl (%ebx),%ebp # btx_v86 pointer |
| 797 | movb $0x4,%cl # Count |
| 798 | addl %ecx,%ebx # Adjust for pop |
| 799 | rep # Push saved seg regs |
| 800 | movsl # on link stack |
| 801 | addl %ebp,%edx # Flatten btx_v86 ptr |
| 802 | leal 0x14(%edx),%esi # Seg regs pointer |
| 803 | movl 0x4(%edx),%eax # Get int no/address |
| 804 | movzwl 0x2(%edx),%edx # Get control flags |
| 805 | intusr.2: movl %ebp,(%edi) # Push btx_v86 and |
| 806 | movl %edi,MEM_TSS+TSS_ESP1 # save link stack ptr |
| 807 | popl %edi # Base of frame |
| 808 | xchgl %eax,%ebp # Save intno/address |
| 809 | movl 0x48(%esp,1),%eax # Get flags |
| 810 | testb $0x2,%dl # Simulate CALLF? |
| 811 | jnz intusr.3 # Yes |
| 812 | decl %ebx # Push flags |
| 813 | decl %ebx # on V86 |
| 814 | movw %ax,(%ebx) # stack |
| 815 | intusr.3: movb $0x4,%cl # Count |
| 816 | subl %ecx,%ebx # Push return address |
| 817 | movl $inthlt,(%ebx) # on V86 stack |
| 818 | rep # Copy seg regs to |
| 819 | movsl # exception frame |
| 820 | xchgl %eax,%ecx # Save flags |
| 821 | movl %ebx,%eax # User ESP |
| 822 | subl $V86_STK,%eax # Less bytes |
| 823 | ja intusr.4 # to |
| 824 | xorl %eax,%eax # keep |
| 825 | intusr.4: shrl $0x4,%eax # Gives segment |
| 826 | stosl # Set SS |
| 827 | shll $0x4,%eax # To bytes |
| 828 | xchgl %eax,%ebx # Swap |
| 829 | subl %ebx,%eax # Gives offset |
| 830 | stosl # Set ESP |
| 831 | xchgl %eax,%ecx # Get flags |
| 832 | btsl $0x11,%eax # Set VM |
| 833 | andb $~0x1,%ah # Clear TF |
| 834 | stosl # Set EFL |
| 835 | xchgl %eax,%ebp # Get int no/address |
| 836 | testb $0x1,%dl # Address? |
| 837 | jnz intusr.5 # Yes |
| 838 | shll $0x2,%eax # Scale |
| 839 | movl (%eax),%eax # Load int vector |
| 840 | intusr.5: movl %eax,%ecx # Save |
| 841 | shrl $0x10,%eax # Gives segment |
| 842 | stosl # Set CS |
| 843 | movw %cx,%ax # Restore |
| 844 | stosl # Set EIP |
| 845 | leal 0x10(%esp,1),%esp # Discard seg regs |
| 846 | popa # Restore |
| 847 | iret # To V86 mode |
| 848 | # |
| 849 | # System Call. |
| 850 | # |
| 851 | intx30: cmpl $SYS_EXEC,%eax # Exec system call? |
| 852 | jne intx30.1 # No |
| 853 | pushl %ss # Set up |
| 854 | popl %es # all |
| 855 | pushl %es # segment |
| 856 | popl %ds # registers |
| 857 | pushl %ds # for the |
| 858 | popl %fs # program |
| 859 | pushl %fs # we're |
| 860 | popl %gs # invoking |
| 861 | movl $MEM_USR,%eax # User base address |
| 862 | addl 0xc(%esp,1),%eax # Change to user |
| 863 | leal 0x4(%eax),%esp # stack |
| 864 | ifdef(`PAGING',` |
| 865 | movl %cr0,%eax # Turn |
| 866 | andl $~0x80000000,%eax # off |
| 867 | movl %eax,%cr0 # paging |
| 868 | xorl %eax,%eax # Flush |
| 869 | movl %eax,%cr3 # TLB |
| 870 | ') |
| 871 | popl %eax # Call |
| 872 | call *%eax # program |
| 873 | intx30.1: orb $0x1,%ss:btx_hdr+0x7 # Flag reboot |
| 874 | jmp exit # Exit |
| 875 | # |
| 876 | # Dump structure [EBX] to [EDI], using format string [ESI]. |
| 877 | # |
| 878 | dump.0: stosb # Save char |
| 879 | dump: lodsb # Load char |
| 880 | testb %al,%al # End of string? |
| 881 | jz dump.10 # Yes |
| 882 | testb $0x80,%al # Control? |
| 883 | jz dump.0 # No |
| 884 | movb %al,%ch # Save control |
| 885 | movb $'=',%al # Append |
| 886 | stosb # '=' |
| 887 | lodsb # Get offset |
| 888 | pushl %esi # Save |
| 889 | movsbl %al,%esi # To |
| 890 | addl %ebx,%esi # pointer |
| 891 | testb $DMP_X16,%ch # Dump word? |
| 892 | jz dump.1 # No |
| 893 | lodsw # Get and |
| 894 | call hex16 # dump it |
| 895 | dump.1: testb $DMP_X32,%ch # Dump long? |
| 896 | jz dump.2 # No |
| 897 | lodsl # Get and |
| 898 | call hex32 # dump it |
| 899 | dump.2: testb $DMP_MEM,%ch # Dump memory? |
| 900 | jz dump.8 # No |
| 901 | pushl %ds # Save |
| 902 | testb $0x2,0x52(%ebx) # V86 mode? |
| 903 | jnz dump.3 # Yes |
| 904 | verr 0x4(%esi) # Readable selector? |
| 905 | jnz dump.3 # No |
| 906 | ldsl (%esi),%esi # Load pointer |
| 907 | jmp dump.4 # Join common code |
| 908 | dump.3: lodsl # Set offset |
| 909 | xchgl %eax,%edx # Save |
| 910 | lodsl # Get segment |
| 911 | shll $0x4,%eax # * 0x10 |
| 912 | addl %edx,%eax # + offset |
| 913 | xchgl %eax,%esi # Set pointer |
| 914 | dump.4: movb $2,%dl # Num lines |
| 915 | dump.4a: movb $0x10,%cl # Bytes to dump |
| 916 | dump.5: lodsb # Get byte and |
| 917 | call hex8 # dump it |
| 918 | decb %cl # Keep count |
| 919 | jz dump.6a # If done |
| 920 | movb $'-',%al # Separator |
| 921 | cmpb $0x8,%cl # Half way? |
| 922 | je dump.6 # Yes |
| 923 | movb $' ',%al # Use space |
| 924 | dump.6: stosb # Save separator |
| 925 | jmp dump.5 # Continue |
| 926 | dump.6a: decb %dl # Keep count |
| 927 | jz dump.7 # If done |
| 928 | movb $0xa,%al # Line feed |
| 929 | stosb # Save one |
| 930 | movb $7,%cl # Leading |
| 931 | movb $' ',%al # spaces |
| 932 | dump.6b: stosb # Dump |
| 933 | decb %cl # spaces |
| 934 | jnz dump.6b |
| 935 | jmp dump.4a # Next line |
| 936 | dump.7: popl %ds # Restore |
| 937 | dump.8: popl %esi # Restore |
| 938 | movb $0xa,%al # Line feed |
| 939 | testb $DMP_EOL,%ch # End of line? |
| 940 | jnz dump.9 # Yes |
| 941 | movb $' ',%al # Use spaces |
| 942 | stosb # Save one |
| 943 | dump.9: jmp dump.0 # Continue |
| 944 | dump.10: stosb # Terminate string |
| 945 | ret # To caller |
| 946 | # |
| 947 | # Convert EAX, AX, or AL to hex, saving the result to [EDI]. |
| 948 | # |
| 949 | hex32: pushl %eax # Save |
| 950 | shrl $0x10,%eax # Do upper |
| 951 | call hex16 # 16 |
| 952 | popl %eax # Restore |
| 953 | hex16: call hex16.1 # Do upper 8 |
| 954 | hex16.1: xchgb %ah,%al # Save/restore |
| 955 | hex8: pushl %eax # Save |
| 956 | shrb $0x4,%al # Do upper |
| 957 | call hex8.1 # 4 |
| 958 | popl %eax # Restore |
| 959 | hex8.1: andb $0xf,%al # Get lower 4 |
| 960 | cmpb $0xa,%al # Convert |
| 961 | sbbb $0x69,%al # to hex |
| 962 | das # digit |
| 963 | orb $0x20,%al # To lower case |
| 964 | stosb # Save char |
| 965 | ret # (Recursive) |
| 966 | # |
| 967 | # Output zero-terminated string [ESI] to the console. |
| 968 | # |
| 969 | putstr.0: call putchr # Output char |
| 970 | putstr: lodsb # Load char |
| 971 | testb %al,%al # End of string? |
| 972 | jnz putstr.0 # No |
| 973 | ret # To caller |
| 974 | ifdef(`BTX_SERIAL',` |
| 975 | .set SIO_PRT,SIOPRT # Base port |
| 976 | .set SIO_FMT,SIOFMT # 8N1 |
| 977 | .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD |
| 978 | |
| 979 | # void sio_init(void) |
| 980 | |
| 981 | sio_init: movw $SIO_PRT+0x3,%dx # Data format reg |
| 982 | movb $SIO_FMT|0x80,%al # Set format |
| 983 | outb %al,(%dx) # and DLAB |
| 984 | pushl %edx # Save |
| 985 | subb $0x3,%dl # Divisor latch reg |
| 986 | movw $SIO_DIV,%ax # Set |
| 987 | outw %ax,(%dx) # BPS |
| 988 | popl %edx # Restore |
| 989 | movb $SIO_FMT,%al # Clear |
| 990 | outb %al,(%dx) # DLAB |
| 991 | incl %edx # Modem control reg |
| 992 | movb $0x3,%al # Set RTS, |
| 993 | outb %al,(%dx) # DTR |
| 994 | incl %edx # Line status reg |
| 995 | |
| 996 | # void sio_flush(void) |
| 997 | |
| 998 | sio_flush.0: call sio_getc.1 # Get character |
| 999 | sio_flush: call sio_ischar # Check for character |
| 1000 | jnz sio_flush.0 # Till none |
| 1001 | ret # To caller |
| 1002 | |
| 1003 | # void sio_putc(int c) |
| 1004 | |
| 1005 | sio_putc: movw $SIO_PRT+0x5,%dx # Line status reg |
| 1006 | xor %ecx,%ecx # Timeout |
| 1007 | movb $0x40,%ch # counter |
| 1008 | sio_putc.1: inb (%dx),%al # Transmitter |
| 1009 | testb $0x20,%al # buffer empty? |
| 1010 | loopz sio_putc.1 # No |
| 1011 | jz sio_putc.2 # If timeout |
| 1012 | movb 0x4(%esp,1),%al # Get character |
| 1013 | subb $0x5,%dl # Transmitter hold reg |
| 1014 | outb %al,(%dx) # Write character |
| 1015 | sio_putc.2: ret $0x4 # To caller |
| 1016 | |
| 1017 | # int sio_getc(void) |
| 1018 | |
| 1019 | sio_getc: call sio_ischar # Character available? |
| 1020 | jz sio_getc # No |
| 1021 | sio_getc.1: subb $0x5,%dl # Receiver buffer reg |
| 1022 | inb (%dx),%al # Read character |
| 1023 | ret # To caller |
| 1024 | |
| 1025 | # int sio_ischar(void) |
| 1026 | |
| 1027 | sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register |
| 1028 | xorl %eax,%eax # Zero |
| 1029 | inb (%dx),%al # Received data |
| 1030 | andb $0x1,%al # ready? |
| 1031 | ret # To caller |
| 1032 | |
| 1033 | # |
| 1034 | # Output character AL to the serial console. |
| 1035 | # |
| 1036 | putchr: pusha # Save |
| 1037 | cmpb $10, %al # is it a newline? |
| 1038 | jne putchr.1 # no?, then leave |
| 1039 | push $13 # output a carriage |
| 1040 | call sio_putc # return first |
| 1041 | movb $10, %al # restore %al |
| 1042 | putchr.1: pushl %eax # Push the character |
| 1043 | # onto the stack |
| 1044 | call sio_putc # Output the character |
| 1045 | popa # Restore |
| 1046 | ret # To caller |
| 1047 | ',` |
| 1048 | # |
| 1049 | # Output character AL to the console. |
| 1050 | # |
| 1051 | putchr: pusha # Save |
| 1052 | xorl %ecx,%ecx # Zero for loops |
| 1053 | movb $SCR_MAT,%ah # Mode/attribute |
| 1054 | movl $BDA_POS,%ebx # BDA pointer |
| 1055 | movw (%ebx),%dx # Cursor position |
| 1056 | movl $0xb8000,%edi # Regen buffer (color) |
| 1057 | cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? |
| 1058 | jne putchr.1 # No |
| 1059 | xorw %di,%di # Regen buffer (mono) |
| 1060 | putchr.1: cmpb $0xa,%al # New line? |
| 1061 | je putchr.2 # Yes |
| 1062 | xchgl %eax,%ecx # Save char |
| 1063 | movb $SCR_COL,%al # Columns per row |
| 1064 | mulb %dh # * row position |
| 1065 | addb %dl,%al # + column |
| 1066 | adcb $0x0,%ah # position |
| 1067 | shll %eax # * 2 |
| 1068 | xchgl %eax,%ecx # Swap char, offset |
| 1069 | movw %ax,(%edi,%ecx,1) # Write attr:char |
| 1070 | incl %edx # Bump cursor |
| 1071 | cmpb $SCR_COL,%dl # Beyond row? |
| 1072 | jb putchr.3 # No |
| 1073 | putchr.2: xorb %dl,%dl # Zero column |
| 1074 | incb %dh # Bump row |
| 1075 | putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? |
| 1076 | jb putchr.4 # No |
| 1077 | leal 2*SCR_COL(%edi),%esi # New top line |
| 1078 | movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move |
| 1079 | rep # Scroll |
| 1080 | movsl # screen |
| 1081 | movb $0x20,%al # Space |
| 1082 | movb $SCR_COL,%cl # Columns to clear |
| 1083 | rep # Clear |
| 1084 | stosw # line |
| 1085 | movb $SCR_ROW-1,%dh # Bottom line |
| 1086 | putchr.4: movw %dx,(%ebx) # Update position |
| 1087 | popa # Restore |
| 1088 | ret # To caller |
| 1089 | ') |
| 1090 | |
| 1091 | .p2align 4 |
| 1092 | # |
| 1093 | # Global descriptor table. |
| 1094 | # |
| 1095 | gdt: .word 0x0,0x0,0x0,0x0 # Null entry |
| 1096 | .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE |
| 1097 | .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA |
| 1098 | .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE |
| 1099 | .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA |
| 1100 | .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE |
| 1101 | .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA |
| 1102 | .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS |
| 1103 | gdt.1: |
| 1104 | # |
| 1105 | # Pseudo-descriptors. |
| 1106 | # |
| 1107 | gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT |
| 1108 | idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT |
| 1109 | ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT |
| 1110 | # |
| 1111 | # IDT construction control string. |
| 1112 | # |
| 1113 | idtctl: .byte 0x10, 0x8e # Int 0x0-0xf |
| 1114 | .word 0x7dfb,intx00 # (exceptions) |
| 1115 | .byte 0x10, 0x8e # Int 0x10 |
| 1116 | .word 0x1, intx10 # (exception) |
| 1117 | .byte 0x10, 0x8e # Int 0x20-0x2f |
| 1118 | .word 0xffff,intx20 # (hardware) |
| 1119 | .byte 0x1, 0xee # int 0x30 |
| 1120 | .word 0x1, intx30 # (system call) |
| 1121 | .byte 0x2, 0xee # Int 0x31-0x32 |
| 1122 | .word 0x1, intx31 # (V86, null) |
| 1123 | .byte 0x0 # End of string |
| 1124 | # |
| 1125 | # Dump format string. |
| 1126 | # |
| 1127 | dmpfmt: .byte '\n' # "\n" |
| 1128 | .ascii "int" # "int=" |
| 1129 | .byte 0x80|DMP_X32, 0x40 # "00000000 " |
| 1130 | .ascii "err" # "err=" |
| 1131 | .byte 0x80|DMP_X32, 0x44 # "00000000 " |
| 1132 | .ascii "efl" # "efl=" |
| 1133 | .byte 0x80|DMP_X32, 0x50 # "00000000 " |
| 1134 | .ascii "eip" # "eip=" |
| 1135 | .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n" |
| 1136 | .ascii "eax" # "eax=" |
| 1137 | .byte 0x80|DMP_X32, 0x34 # "00000000 " |
| 1138 | .ascii "ebx" # "ebx=" |
| 1139 | .byte 0x80|DMP_X32, 0x28 # "00000000 " |
| 1140 | .ascii "ecx" # "ecx=" |
| 1141 | .byte 0x80|DMP_X32, 0x30 # "00000000 " |
| 1142 | .ascii "edx" # "edx=" |
| 1143 | .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n" |
| 1144 | .ascii "esi" # "esi=" |
| 1145 | .byte 0x80|DMP_X32, 0x1c # "00000000 " |
| 1146 | .ascii "edi" # "edi=" |
| 1147 | .byte 0x80|DMP_X32, 0x18 # "00000000 " |
| 1148 | .ascii "ebp" # "ebp=" |
| 1149 | .byte 0x80|DMP_X32, 0x20 # "00000000 " |
| 1150 | .ascii "esp" # "esp=" |
| 1151 | .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n" |
| 1152 | .ascii "cs" # "cs=" |
| 1153 | .byte 0x80|DMP_X16, 0x4c # "0000 " |
| 1154 | .ascii "ds" # "ds=" |
| 1155 | .byte 0x80|DMP_X16, 0xc # "0000 " |
| 1156 | .ascii "es" # "es=" |
| 1157 | .byte 0x80|DMP_X16, 0x8 # "0000 " |
| 1158 | .ascii " " # " " |
| 1159 | .ascii "fs" # "fs=" |
| 1160 | .byte 0x80|DMP_X16, 0x10 # "0000 " |
| 1161 | .ascii "gs" # "gs=" |
| 1162 | .byte 0x80|DMP_X16, 0x14 # "0000 " |
| 1163 | .ascii "ss" # "ss=" |
| 1164 | .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n" |
| 1165 | .ascii "cs:eip" # "cs:eip=" |
| 1166 | .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n" |
| 1167 | .ascii "ss:esp" # "ss:esp=" |
| 1168 | .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n" |
| 1169 | .asciz "BTX halted\n" # End |
| 1170 | # |
| 1171 | # End of BTX memory. |
| 1172 | # |
| 1173 | .p2align 4 |
| 1174 | break: |