2 # Copyright (c) 1998 Robert Nordier
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
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
21 .set MEM_BTX,0x1000 # Start of BTX memory
22 .set MEM_ESP0,0x1800 # Supervisor stack
23 .set MEM_BUF,0x1800 # Scratch buffer
24 .set MEM_ESP1,0x1e00 # Link stack
25 .set MEM_IDT,0x1e00 # IDT
26 .set MEM_TSS,0x1f98 # TSS
27 .set MEM_MAP,0x2000 # I/O bit map
28 .set MEM_DIR,0x4000 # Page directory
29 .set MEM_TBL,0x5000 # Page tables
30 .set MEM_ORG,0x9000 # BTX code
31 .set MEM_USR,0xa000 # Start of user memory
35 .set PAG_SIZ,0x1000 # Page size
36 .set PAG_CNT,0x1000 # Pages to map
40 .set SEL_SCODE,0x8 # Supervisor code
41 .set SEL_SDATA,0x10 # Supervisor data
42 .set SEL_RCODE,0x18 # Real mode code
43 .set SEL_RDATA,0x20 # Real mode data
44 .set SEL_UCODE,0x28|3 # User code
45 .set SEL_UDATA,0x30|3 # User data
46 .set SEL_TSS,0x38 # TSS
48 # Task state segment fields.
50 .set TSS_ESP0,0x4 # PL 0 ESP
51 .set TSS_SS0,0x8 # PL 0 SS
52 .set TSS_ESP1,0xc # PL 1 ESP
53 .set TSS_MAP,0x66 # I/O bit map base
57 .set SYS_EXIT,0x0 # Exit
58 .set SYS_EXEC,0x1 # Exec
62 .set V86_FLG,0x208eff # V86 flag mask
63 .set V86_STK,0x400 # V86 stack allowance
65 # Dump format control bytes.
67 .set DMP_X16,0x1 # Word
68 .set DMP_X32,0x2 # Long
69 .set DMP_MEM,0x4 # Memory
70 .set DMP_EOL,0x8 # End of line
72 # Screen defaults and assumptions.
75 .set SCR_MAT,0xe1 # Mode/attribute
77 .set SCR_MAT,0x7 # Mode/attribute
79 .set SCR_COL,0x50 # Columns per row
80 .set SCR_ROW,0x19 # Rows per screen
82 # BIOS Data Area locations.
85 .set BDA_MEM,0xa1501 # Free memory
86 .set BDA_POS,0xa153e # Cursor position
88 .set BDA_MEM,0x413 # Free memory
89 .set BDA_SCR,0x449 # Video mode
90 .set BDA_POS,0x450 # Cursor position
93 # Derivations, for brevity.
95 .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0
96 .set _ESP1H,MEM_ESP1>>0x8 # Byte 1 of ESP1
97 .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base
98 .set _TSSLM,MEM_DIR-MEM_TSS-1 # TSS limit
99 .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit
104 start: # Start of code
108 btx_hdr: .byte 0xeb # Machine ID
109 .byte 0xe # Header size
111 .byte 0x1 # Major version
112 .byte 0x1 # Minor version
114 .word PAG_CNT-MEM_ORG>>0xc # Paging control
115 .word break-start # Text size
116 .long 0x0 # Entry address
118 # Initialization routine.
120 init: cli # Disable interrupts
121 xorl %eax,%eax # Zero/segment
122 movl %ax,%ss # Set up
123 movwir(MEM_ESP0,_sp) # stack
124 movl %ax,%es # Address
131 movwir(MEM_IDT,_di) # Memory to initialize
132 movwir((MEM_ORG-MEM_IDT)/2,_cx) # Words to zero
140 movwir(idtctl,_si) # Control string
141 init.1: lodsb # Get entry
143 xchgl %eax,%ecx # as word
144 jecxz init.4 # If done
146 xchgl %eax,%edx # P:DPL:type
148 xchgl %eax,%ebx # set
149 lodsl # Get handler offset
150 movb $SEL_SCODE,%dh # Segment selector
151 init.2: shrl %ebx # Handle this int?
153 movwr0(_ax,_di_) # Set handler offset
154 movbr1(_dh,0x2,_di_) # and selector
155 movbr1(_dl,0x5,_di_) # Set P:DPL:type
156 addwia(0x4) # Next handler
157 init.3: leaw1r(0x8,_di_,_di) # Next entry
158 loop init.2 # Till set done
159 jmp init.1 # Continue
163 init.4: movbi1(_ESP0H,TSS_ESP0+1,_di_) # Set ESP0
164 movbi1(SEL_SDATA,TSS_SS0,_di_) # Set SS0
165 movbi1(_ESP1H,TSS_ESP1+1,_di_) # Set ESP1
166 movbi1(_TSSIO,TSS_MAP,_di_) # Set I/O bit map base
168 # Create page directory.
171 movb $PAG_SIZ>>0x8,%dh # size
173 movwir(MEM_DIR,_di) # Page directory
174 movb $PAG_CNT>>0xa,%cl # Entries
175 movwir(MEM_TBL|0x7,_ax) # First entry
176 init.5: stosw # Write entry
177 addl %edx,%eax # To next
178 loop init.5 # Till done
180 # Create page tables.
182 movwir(MEM_TBL,_di) # Page table
183 movb $PAG_CNT>>0x8,%ch # Entries
184 xorl %eax,%eax # Start address
185 init.6: movb $0x7,%al # Set U:W:P flags
186 cmpwmr(btx_hdr+0x8,_cx) # Standard user page?
188 cmpwir(PAG_CNT-MEM_BTX>>0xc,_cx)# BTX memory?
189 jae init.7 # No or first page
190 andb $~0x2,%al # Clear W flag
191 cmpwir(PAG_CNT-MEM_USR>>0xc,_cx)# User page zero?
193 tstbim(0x80,btx_hdr+0x7) # Unmap it?
195 andb $~0x1,%al # Clear P flag
196 init.7: stosw # Set entry
197 addw %dx,%ax # Next address
198 loop init.6 # Till done
200 # Bring up the system.
202 movwir(0x2820,_bx) # Set protected mode
203 callwi(setpic) # IRQ offsets
204 lidtwm(idtdesc) # Set IDT
205 xorw %ax,%ax # Set base
206 movb $MEM_DIR>>0x8,%ah # of page
207 movl %eax,%cr3 # directory
208 lgdtwm(gdtdesc) # Set GDT
209 movl %cr0,%eax # Switch to
211 orl $0x80000001,%eax # and enable
212 movl %eax,%cr0 # paging
213 jmpfwi(SEL_SCODE,init.8) # To 32-bit code
214 init.8: xorl %ecx,%ecx # Zero
215 movb $SEL_SDATA,%cl # To 32-bit
220 movb $SEL_TSS,%cl # Set task
222 movl $MEM_USR,%edx # User base address
223 movzwl %ss:BDA_MEM,%eax # Get free memory
227 shll $0x11,%eax # To bytes
229 shll $0xa,%eax # To bytes
231 subl $0x1000,%eax # Less arg space
232 subl %edx,%eax # Less base
233 movb $SEL_UDATA,%cl # User data selector
236 pushl $0x202 # Set flags (IF set)
237 pushl $SEL_UCODE # Set CS
238 pushl btx_hdr+0xc # Set EIP
244 movb $0x7,%cl # Set remaining
245 init.9: pushb $0x0 # general
246 loop init.9 # registers
247 popa # and initialize
248 popl %es # Initialize
256 exit: cli # Disable interrupts
257 movl $MEM_ESP0,%esp # Clear stack
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
270 jmpfwi(SEL_RCODE,exit.1) # CS
271 exit.1: movb $SEL_RDATA,%cl # 16-bit selector
272 movl %cx,%ss # Reload SS
274 movl %cx,%es # remaining
275 movl %cx,%fs # segment
276 movl %cx,%gs # registers
278 # To real-address mode.
280 decl %eax # Switch to
281 movl %eax,%cr0 # real mode
282 jmpfwi(0x0,exit.2) # Reload CS
283 exit.2: xorl %eax,%eax # Real mode segment
284 movl %ax,%ss # Reload SS
285 movl %ax,%ds # Address data
287 movwir(0x1008,_bx) # Set real mode
289 movwir(0x7008,_bx) # Set real mode
291 callwi(setpic) # IRQ offsets
292 lidtwm(ivtdesc) # Set IVT
294 # Reboot or await reset.
296 sti # Enable interrupts
297 tstbim(0x1,btx_hdr+0x7) # Reboot?
298 exit.3: jz exit.3 # No
306 int $0x19 # BIOS: Reboot
309 # Set IRQ offsets by reprogramming 8259A PICs.
312 setpic: inb $0x02,%al # Save master
314 inb $0x0a,%al # Save slave
316 movb $0x11,%al # ICW1 to
317 outb %al,$0x00 # master,
318 outb %al,$0x08 # slave
319 movb %bl,%al # ICW2 to
320 outb %al,$0x02 # master
321 movb %bh,%al # ICW2 to
322 outb %al,$0x0a # slave
323 movb $0x80,%al # ICW3 to
324 outb %al,$0x02 # master
325 movb $0x7,%al # ICW3 to
326 outb %al,$0x0a # slave
327 movb $0x1d,%al # ICW4 to
328 outb %al,$0x02 # master,
329 movb $0x9,%al # ICW4 to
330 outb %al,$0x0a # slave
331 popl %eax # Restore slave
333 popl %eax # Restore master
336 setpic: inb $0x21,%al # Save master
338 inb $0xa1,%al # Save slave
340 movb $0x11,%al # ICW1 to
341 outb %al,$0x20 # master,
342 outb %al,$0xa0 # slave
343 movb %bl,%al # ICW2 to
344 outb %al,$0x21 # master
345 movb %bh,%al # ICW2 to
346 outb %al,$0xa1 # slave
347 movb $0x4,%al # ICW3 to
348 outb %al,$0x21 # master
349 movb $0x2,%al # ICW3 to
350 outb %al,$0xa1 # slave
351 movb $0x1,%al # ICW4 to
352 outb %al,$0x21 # master,
353 outb %al,$0xa1 # slave
354 popl %eax # Restore slave
356 popl %eax # Restore master
361 # Initiate return from V86 mode to user mode.
363 inthlt: hlt # To supervisor mode
365 # Exception jump table.
367 intx00: pushb $0x0 # Int 0x0: #DE
368 jmp ex_noc # Divide error
369 pushb $0x1 # Int 0x1: #DB
371 pushb $0x3 # Int 0x3: #BP
372 jmp ex_noc # Breakpoint
373 pushb $0x4 # Int 0x4: #OF
374 jmp ex_noc # Overflow
375 pushb $0x5 # Int 0x5: #BR
376 jmp ex_noc # BOUND range exceeded
377 pushb $0x6 # Int 0x6: #UD
378 jmp ex_noc # Invalid opcode
379 pushb $0x7 # Int 0x7: #NM
380 jmp ex_noc # Device not available
381 pushb $0x8 # Int 0x8: #DF
382 jmp except # Double fault
383 pushb $0xa # Int 0xa: #TS
384 jmp except # Invalid TSS
385 pushb $0xb # Int 0xb: #NP
386 jmp except # Segment not present
387 pushb $0xc # Int 0xc: #SS
388 jmp except # Stack segment fault
389 pushb $0xd # Int 0xd: #GP
390 jmp ex_v86 # General protection
391 pushb $0xe # Int 0xe: #PF
392 jmp except # Page fault
393 intx10: pushb $0x10 # Int 0x10: #MF
394 jmp ex_noc # Floating-point error
396 # Handle #GP exception.
398 ex_v86: testb $0x2,0x12(%esp,1) # V86 mode?
400 jmp v86mon # To monitor
402 # Save a zero error code.
404 ex_noc: pushl (%esp,1) # Duplicate int no
405 movb $0x0,0x4(%esp,1) # Fake error code
409 except: cld # String ops inc
413 movb $0x6,%al # Push loop count
414 testb $0x2,0x3a(%esp,1) # V86 mode?
420 movb $0x2,%al # Push loop count
421 cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode?
424 leal 0x50(%esp,1),%eax # Set
426 jmp except.2 # Join common code
427 except.1: pushl 0x50(%esp,1) # Set GS, FS, DS, ES
428 decb %al # (if V86 mode), and
429 jne except.1 # SS, ESP
430 except.2: pushl $SEL_SDATA # Set up
434 movl %esp,%ebx # Stack frame
435 movl $dmpfmt,%esi # Dump format string
436 movl $MEM_BUF,%edi # Buffer
468 call putstr # display
469 leal 0x18(%esp,1),%esp # Discard frame
473 cmpb $0x3,(%esp,1) # Breakpoint?
476 except.3: leal 0x8(%esp,1),%esp # Discard err, int no
477 iret # From interrupt
479 # Return to user mode from V86 mode.
481 intrtn: cld # String ops inc
484 leal 0x3c(%ebp),%edx # V86 Segment registers
485 movl MEM_TSS+TSS_ESP1,%esi # Link stack pointer
486 lodsl # INT_V86 args pointer
487 movl %esi,%ebx # Saved exception frame
488 testl %eax,%eax # INT_V86 args?
490 movl $MEM_USR,%edi # User base
491 movl 0x1c(%esi),%ebx # User ESP
492 movl %eax,(%edi,%ebx,1) # Restore to user stack
493 leal 0x8(%edi,%eax,1),%edi # Arg segment registers
494 testb $0x4,-0x6(%edi) # Return flags?
496 movl 0x30(%ebp),%eax # Get V86 flags
497 movw %ax,0x18(%esi) # Set user flags
498 intrtn.1: leal 0x10(%esi),%ebx # Saved exception frame
499 xchgl %edx,%esi # Segment registers
500 movb $0x4,%cl # Update seg regs
503 intrtn.2: movl %edx,%esi # Segment registers
504 leal 0x28(%ebp),%edi # Set up seg
505 movb $0x4,%cl # regs for
508 movl %ebx,%esi # Restore exception
509 movb $0x5,%cl # frame to
512 movl %esi,MEM_TSS+TSS_ESP1 # Link stack pointer
514 leal 0x8(%esp,1),%esp # Discard err, int no
523 v86mon: cld # String ops inc
524 pushl $SEL_SDATA # Set up for
525 popl %ds # flat addressing
526 pusha # Save registers
527 movl %esp,%ebp # Address stack frame
528 movzwl 0x2c(%ebp),%edi # Load V86 CS
529 shll $0x4,%edi # To linear
530 movl 0x28(%ebp),%esi # Load V86 IP
531 addl %edi,%esi # Code pointer
532 xorl %ecx,%ecx # Zero
533 movb $0x2,%cl # 16-bit operands
534 xorl %eax,%eax # Zero
535 v86mon.1: lodsb # Get opcode
536 cmpb $0x66,%al # Operand size prefix?
538 movb $0x4,%cl # 32-bit operands
539 jmp v86mon.1 # Continue
540 v86mon.2: cmpb $0xf4,%al # HLT?
542 cmpl $inthlt+0x1,%esi # Is inthlt?
543 jne v86mon.7 # No (ignore)
544 jmp intrtn # Return to user mode
545 v86mon.3: cmpb $0xf,%al # Is
547 cmpb $0x20,(%esi) # a
548 jne v86mon.4 # MOV EAX,CR0
549 cmpb $0xc0,0x1(%esi) # instruction?
551 v86mon.4: cmpb $0xfa,%al # CLI?
553 cmpb $0xfb,%al # STI?
555 movzwl 0x38(%ebp),%ebx # Load V86 SS
556 shll $0x4,%ebx # To offset
558 addl 0x34(%ebp),%ebx # Add V86 SP
559 movl 0x30(%ebp),%edx # Load V86 flags
560 cmpb $0x9c,%al # PUSHF/PUSHFD?
562 cmpb $0x9d,%al # POPF/POPFD?
564 cmpb $0xcd,%al # INT imm8?
566 cmpb $0xcf,%al # IRET/IRETD?
570 jmp except # Handle exception
571 v86mon.5: movl %edx,0x30(%ebp) # Save V86 flags
572 v86mon.6: popl %edx # V86 SS adjustment
573 subl %edx,%ebx # Save V86
574 movl %ebx,0x34(%ebp) # SP
575 v86mon.7: subl %edi,%esi # From linear
576 movl %esi,0x28(%ebp) # Save V86 IP
578 leal 0x8(%esp,1),%esp # Discard int no, error
581 # Emulate MOV EAX,CR0.
583 v86mov: movl %cr0,%eax # CR0 to
584 movl %eax,0x1c(%ebp) # saved EAX
587 jmp v86mon.7 # Finish up
591 v86cli: andb $~0x2,0x31(%ebp) # Clear IF
592 jmp v86mon.7 # Finish up
596 v86sti: orb $0x2,0x31(%ebp) # Set IF
597 jmp v86mon.7 # Finish up
599 # Emulate PUSHF/PUSHFD.
601 v86pushf: subl %ecx,%ebx # Adjust SP
602 cmpb $0x4,%cl # 32-bit
605 v86pushf.1: movl %edx,(%ebx) # Save flags
606 jmp v86mon.6 # Finish up
608 # Emulate IRET/IRETD.
610 v86iret: movzwl (%ebx),%esi # Load V86 IP
611 movzwl 0x2(%ebx),%edi # Load V86 CS
612 leal 0x4(%ebx),%ebx # Adjust SP
613 movl %edi,0x2c(%ebp) # Save V86 CS
614 xorl %edi,%edi # No ESI adjustment
616 # Emulate POPF/POPFD (and remainder of IRET/IRETD).
618 v86popf: cmpb $0x4,%cl # 32-bit?
620 movl %edx,%eax # Initialize
622 v86popf.1: movl (%ebx),%eax # Load flags
623 addl %ecx,%ebx # Adjust SP
624 andl $V86_FLG,%eax # Merge
625 andl $~V86_FLG,%edx # the
626 orl %eax,%edx # flags
627 jmp v86mon.5 # Finish up
631 v86intn: lodsb # Get int no
632 subl %edi,%esi # From
633 shrl $0x4,%edi # linear
634 movw %dx,-0x2(%ebx) # Save flags
635 movw %di,-0x4(%ebx) # Save CS
636 leal -0x6(%ebx),%ebx # Adjust SP
637 movw %si,(%ebx) # Save IP
638 shll $0x2,%eax # Scale
639 movzwl (%eax),%esi # Load IP
640 movzwl 0x2(%eax),%edi # Load CS
641 movl %edi,0x2c(%ebp) # Save CS
642 xorl %edi,%edi # No ESI adjustment
643 andb $~0x3,%dh # Clear IF and TF
644 jmp v86mon.5 # Finish up
646 # Hardware interrupt jump table.
648 intx20: pushb $0x8 # Int 0x20: IRQ0
649 jmp int_hw # V86 int 0x8
650 pushb $0x9 # Int 0x21: IRQ1
651 jmp int_hw # V86 int 0x9
652 pushb $0xa # Int 0x22: IRQ2
653 jmp int_hw # V86 int 0xa
654 pushb $0xb # Int 0x23: IRQ3
655 jmp int_hw # V86 int 0xb
656 pushb $0xc # Int 0x24: IRQ4
657 jmp int_hw # V86 int 0xc
658 pushb $0xd # Int 0x25: IRQ5
659 jmp int_hw # V86 int 0xd
660 pushb $0xe # Int 0x26: IRQ6
661 jmp int_hw # V86 int 0xe
662 pushb $0xf # Int 0x27: IRQ7
663 jmp int_hw # V86 int 0xf
665 pushb $0x10 # Int 0x28: IRQ8
666 jmp int_hw # V86 int 0x10
667 pushb $0x11 # Int 0x29: IRQ9
668 jmp int_hw # V86 int 0x11
669 pushb $0x12 # Int 0x2a: IRQ10
670 jmp int_hw # V86 int 0x12
671 pushb $0x13 # Int 0x2b: IRQ11
672 jmp int_hw # V86 int 0x13
673 pushb $0x14 # Int 0x2c: IRQ12
674 jmp int_hw # V86 int 0x14
675 pushb $0x15 # Int 0x2d: IRQ13
676 jmp int_hw # V86 int 0x15
677 pushb $0x16 # Int 0x2e: IRQ14
678 jmp int_hw # V86 int 0x16
679 pushb $0x17 # Int 0x2f: IRQ15
680 jmp int_hw # V86 int 0x17
682 pushb $0x70 # Int 0x28: IRQ8
683 jmp int_hw # V86 int 0x70
684 pushb $0x71 # Int 0x29: IRQ9
685 jmp int_hw # V86 int 0x71
686 pushb $0x72 # Int 0x2a: IRQ10
687 jmp int_hw # V86 int 0x72
688 pushb $0x73 # Int 0x2b: IRQ11
689 jmp int_hw # V86 int 0x73
690 pushb $0x74 # Int 0x2c: IRQ12
691 jmp int_hw # V86 int 0x74
692 pushb $0x75 # Int 0x2d: IRQ13
693 jmp int_hw # V86 int 0x75
694 pushb $0x76 # Int 0x2e: IRQ14
695 jmp int_hw # V86 int 0x76
696 pushb $0x77 # Int 0x2f: IRQ15
697 jmp int_hw # V86 int 0x77
700 # Reflect hardware interrupts.
702 int_hw: testb $0x2,0xe(%esp,1) # V86 mode?
704 pushl $SEL_SDATA # Address
706 xchgl %eax,(%esp,1) # Swap EAX, int no
708 movl %esp,%ebp # stack frame
710 shll $0x2,%eax # Get int
711 movl (%eax),%eax # vector
712 subl $0x6,0x14(%ebp) # Adjust V86 ESP
713 movzwl 0x18(%ebp),%ebx # V86 SS
714 shll $0x4,%ebx # * 0x10
715 addl 0x14(%ebp),%ebx # + V86 ESP
716 xchgw %ax,0x8(%ebp) # Swap V86 IP
717 rorl $0x10,%eax # Swap words
718 xchgw %ax,0xc(%ebp) # Swap V86 CS
719 roll $0x10,%eax # Swap words
720 movl %eax,(%ebx) # CS:IP for IRET
721 movl 0x10(%ebp),%eax # V86 flags
722 movw %ax,0x4(%ebx) # Flags for IRET
723 andb $~0x3,0x11(%ebp) # Clear IF, TF
726 popl %eax # registers
729 # Invoke V86 interrupt from user mode, with arguments.
731 intx31: stc # Have btx_v86
732 pushl %eax # Missing int no
734 # Invoke V86 interrupt from user mode.
736 intusr: std # String ops dec
742 movl %esp,%eax # seg regs
746 pushb $SEL_SDATA # Set up
750 movl $MEM_USR,%ebx # User base
751 movl %ebx,%edx # address
752 jc intusr.1 # If btx_v86
753 xorl %edx,%edx # Control flags
754 xorl %ebp,%ebp # btx_v86 pointer
755 intusr.1: leal 0x50(%esp,1),%esi # Base of frame
757 addl -0x4(%esi),%ebx # User ESP
758 movl MEM_TSS+TSS_ESP1,%edi # Link stack pointer
759 leal -0x4(%edi),%edi # Adjust for push
760 xorl %ecx,%ecx # Zero
761 movb $0x5,%cl # Push exception
764 xchgl %eax,%esi # Saved seg regs
765 movl 0x40(%esp,1),%eax # Get int no
766 testl %edx,%edx # Have btx_v86?
768 movl (%ebx),%ebp # btx_v86 pointer
769 movb $0x4,%cl # Count
770 addl %ecx,%ebx # Adjust for pop
771 rep # Push saved seg regs
772 movsl # on link stack
773 addl %ebp,%edx # Flatten btx_v86 ptr
774 leal 0x14(%edx),%esi # Seg regs pointer
775 movl 0x4(%edx),%eax # Get int no/address
776 movzwl 0x2(%edx),%edx # Get control flags
777 intusr.2: movl %ebp,(%edi) # Push btx_v86 and
778 movl %edi,MEM_TSS+TSS_ESP1 # save link stack ptr
779 popl %edi # Base of frame
780 xchgl %eax,%ebp # Save intno/address
781 movl 0x48(%esp,1),%eax # Get flags
782 testb $0x2,%dl # Simulate CALLF?
784 decl %ebx # Push flags
786 movw %ax,(%ebx) # stack
787 intusr.3: movb $0x4,%cl # Count
788 subl %ecx,%ebx # Push return address
789 movl $inthlt,(%ebx) # on V86 stack
790 rep # Copy seg regs to
791 movsl # exception frame
792 xchgl %eax,%ecx # Save flags
793 movl %ebx,%eax # User ESP
794 subl $V86_STK,%eax # Less bytes
796 xorl %eax,%eax # keep
797 intusr.4: shrl $0x4,%eax # Gives segment
799 shll $0x4,%eax # To bytes
800 xchgl %eax,%ebx # Swap
801 subl %ebx,%eax # Gives offset
803 xchgl %eax,%ecx # Get flags
804 btsl $0x11,%eax # Set VM
805 andb $~0x3,%ah # Clear IF and TF
807 xchgl %eax,%ebp # Get int no/address
808 testb $0x1,%dl # Address?
810 shll $0x2,%eax # Scale
811 movl (%eax),%eax # Load int vector
812 intusr.5: movl %eax,%ecx # Save
813 shrl $0x10,%eax # Gives segment
815 movw %cx,%ax # Restore
817 leal 0x10(%esp,1),%esp # Discard seg regs
823 intx30: cmpl $SYS_EXEC,%eax # Exec system call?
833 movl $MEM_USR,%eax # User base address
834 addl 0xc(%esp,1),%eax # Change to user
835 leal 0x4(%eax),%esp # stack
836 movl %cr0,%eax # Turn
837 andl $~0x80000000,%eax # off
838 movl %eax,%cr0 # paging
839 xorl %eax,%eax # Flush
843 intx30.1: incb %ss:btx_hdr+0x7 # Flag reboot
846 # Dump structure [EBX] to [EDI], using format string [ESI].
848 dump.0: stosb # Save char
849 dump: lodsb # Load char
850 testb %al,%al # End of string?
852 testb $0x80,%al # Control?
854 movb %al,%ch # Save control
855 movb $'=',%al # Append
860 addl %ebx,%esi # pointer
861 testb $DMP_X16,%ch # Dump word?
865 dump.1: testb $DMP_X32,%ch # Dump long?
869 dump.2: testb $DMP_MEM,%ch # Dump memory?
872 testb $0x2,0x52(%ebx) # V86 mode?
874 verrl 0x4(%esi) # Readable selector?
876 ldsl (%esi),%esi # Load pointer
877 jmp dump.4 # Join common code
878 dump.3: lodsl # Set offset
879 xchgl %eax,%edx # Save
881 shll $0x4,%eax # * 0x10
882 addl %edx,%eax # + offset
883 xchgl %eax,%esi # Set pointer
884 dump.4: movb $0x10,%cl # Bytes to dump
885 dump.5: lodsb # Get byte and
887 decb %cl # Keep count
889 movb $'-',%al # Separator
890 cmpb $0x8,%cl # Half way?
892 movb $' ',%al # Use space
893 dump.6: stosb # Save separator
894 jmp dump.5 # Continue
895 dump.7: popl %ds # Restore
896 dump.8: popl %esi # Restore
897 movb $0xa,%al # Line feed
898 testb $DMP_EOL,%ch # End of line?
900 movb $' ',%al # Use spaces
902 dump.9: jmp dump.0 # Continue
903 dump.10: stosb # Terminate string
906 # Convert EAX, AX, or AL to hex, saving the result to [EDI].
908 hex32: pushl %eax # Save
909 shrl $0x10,%eax # Do upper
912 hex16: call hex16.1 # Do upper 8
913 hex16.1: xchgb %ah,%al # Save/restore
914 hex8: pushl %eax # Save
915 shrb $0x4,%al # Do upper
918 hex8.1: andb $0xf,%al # Get lower 4
919 cmpb $0xa,%al # Convert
920 sbbb $0x69,%al # to hex
922 orb $0x20,%al # To lower case
926 # Output zero-terminated string [ESI] to the console.
928 putstr.0: call putchr # Output char
929 putstr: lodsb # Load char
930 testb %al,%al # End of string?
934 # Output character AL to the console.
937 xorl %ecx,%ecx # Zero for loops
938 movb $SCR_MAT,%ah # Mode/attribute
939 movl $BDA_POS,%ebx # BDA pointer
940 movw (%ebx),%dx # Cursor position
944 movl $0xb8000,%edi # Regen buffer (color)
945 cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode?
947 xorw %di,%di # Regen buffer (mono)
949 putchr.1: cmpb $0xa,%al # New line?
953 movb %al,(%edi,%ecx,1) # Write char
955 movb %ah,(%edi,%ecx,1) # Write attr
958 putchr.2: movw %dx,%ax
964 putchr.3: cmpw $SCR_ROW*SCR_COL*2,%dx
966 xchgl %eax,%ecx # Save char
967 movb $SCR_COL,%al # Columns per row
968 mulb %dh # * row position
969 addb %dl,%al # + column
970 adcb $0x0,%ah # position
972 xchgl %eax,%ecx # Swap char, offset
973 movw %ax,(%edi,%ecx,1) # Write attr:char
974 incl %edx # Bump cursor
975 cmpb $SCR_COL,%dl # Beyond row?
977 putchr.2: xorb %dl,%dl # Zero column
979 putchr.3: cmpb $SCR_ROW,%dh # Beyond screen?
982 leal 2*SCR_COL(%edi),%esi # New top line
983 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
986 movb $' ',%al # Space
990 movb $SCR_COL,%cl # Columns to clear
994 movw $(SCR_ROW-1)*SCR_COL*2,%dx
996 movb $SCR_ROW-1,%dh # Bottom line
998 putchr.4: movw %dx,(%ebx) # Update position
1004 # Global descriptor table.
1006 gdt: .word 0x0,0x0,0x0,0x0 # Null entry
1007 .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
1008 .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
1009 .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
1010 .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
1011 .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
1012 .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
1013 .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
1016 # Pseudo-descriptors.
1018 gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT
1019 idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT
1020 ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT
1022 # IDT construction control string.
1024 idtctl: .byte 0x10, 0x8e # Int 0x0-0xf
1025 .word 0x7dfb,intx00 # (exceptions)
1026 .byte 0x10, 0x8e # Int 0x10
1027 .word 0x1, intx10 # (exception)
1028 .byte 0x10, 0x8e # Int 0x20-0x2f
1029 .word 0xffff,intx20 # (hardware)
1030 .byte 0x1, 0xee # int 0x30
1031 .word 0x1, intx30 # (system call)
1032 .byte 0x2, 0xee # Int 0x31-0x32
1033 .word 0x1, intx31 # (V86, null)
1034 .byte 0x0 # End of string
1036 # Dump format string.
1038 dmpfmt: .byte '\n' # "\n"
1039 .ascii "int" # "int="
1040 .byte 0x80|DMP_X32, 0x40 # "00000000 "
1041 .ascii "err" # "err="
1042 .byte 0x80|DMP_X32, 0x44 # "00000000 "
1043 .ascii "efl" # "efl="
1044 .byte 0x80|DMP_X32, 0x50 # "00000000 "
1045 .ascii "eip" # "eip="
1046 .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
1047 .ascii "eax" # "eax="
1048 .byte 0x80|DMP_X32, 0x34 # "00000000 "
1049 .ascii "ebx" # "ebx="
1050 .byte 0x80|DMP_X32, 0x28 # "00000000 "
1051 .ascii "ecx" # "ecx="
1052 .byte 0x80|DMP_X32, 0x30 # "00000000 "
1053 .ascii "edx" # "edx="
1054 .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
1055 .ascii "esi" # "esi="
1056 .byte 0x80|DMP_X32, 0x1c # "00000000 "
1057 .ascii "edi" # "edi="
1058 .byte 0x80|DMP_X32, 0x18 # "00000000 "
1059 .ascii "ebp" # "ebp="
1060 .byte 0x80|DMP_X32, 0x20 # "00000000 "
1061 .ascii "esp" # "esp="
1062 .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n"
1064 .byte 0x80|DMP_X16, 0x4c # "0000 "
1066 .byte 0x80|DMP_X16, 0xc # "0000 "
1068 .byte 0x80|DMP_X16, 0x8 # "0000 "
1071 .byte 0x80|DMP_X16, 0x10 # "0000 "
1073 .byte 0x80|DMP_X16, 0x14 # "0000 "
1075 .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n"
1076 .ascii "cs:eip" # "cs:eip="
1077 .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
1078 .ascii "ss:esp" # "ss:esp="
1079 .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n"
1080 .asciz "System halted" # End
1082 # End of BTX memory.