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.
74 .set SCR_MAT,0x7 # Mode/attribute
75 .set SCR_COL,0x50 # Columns per row
76 .set SCR_ROW,0x19 # Rows per screen
78 # BIOS Data Area locations.
80 .set BDA_MEM,0x413 # Free memory
81 .set BDA_SCR,0x449 # Video mode
82 .set BDA_POS,0x450 # Cursor position
84 # Derivations, for brevity.
86 .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0
87 .set _ESP1H,MEM_ESP1>>0x8 # Byte 1 of ESP1
88 .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base
89 .set _TSSLM,MEM_DIR-MEM_TSS-1 # TSS limit
90 .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit
95 start: # Start of code
99 btx_hdr: .byte 0xeb # Machine ID
100 .byte 0xe # Header size
102 .byte 0x1 # Major version
103 .byte 0x1 # Minor version
105 .word PAG_CNT-MEM_ORG>>0xc # Paging control
106 .word break-start # Text size
107 .long 0x0 # Entry address
109 # Initialization routine.
111 init: cli # Disable interrupts
112 xorl %eax,%eax # Zero/segment
113 movl %ax,%ss # Set up
114 movwir(MEM_ESP0,_sp) # stack
115 movl %ax,%es # Address
122 movwir(MEM_IDT,_di) # Memory to initialize
123 movwir((MEM_ORG-MEM_IDT)/2,_cx) # Words to zero
131 movwir(idtctl,_si) # Control string
132 init.1: lodsb # Get entry
134 xchgl %eax,%ecx # as word
135 jecxz init.4 # If done
137 xchgl %eax,%edx # P:DPL:type
139 xchgl %eax,%ebx # set
140 lodsl # Get handler offset
141 movb $SEL_SCODE,%dh # Segment selector
142 init.2: shrl %ebx # Handle this int?
144 movwr0(_ax,_di_) # Set handler offset
145 movbr1(_dh,0x2,_di_) # and selector
146 movbr1(_dl,0x5,_di_) # Set P:DPL:type
147 addwia(0x4) # Next handler
148 init.3: leaw1r(0x8,_di_,_di) # Next entry
149 loop init.2 # Till set done
150 jmp init.1 # Continue
154 init.4: movbi1(_ESP0H,TSS_ESP0+1,_di_) # Set ESP0
155 movbi1(SEL_SDATA,TSS_SS0,_di_) # Set SS0
156 movbi1(_ESP1H,TSS_ESP1+1,_di_) # Set ESP1
157 movbi1(_TSSIO,TSS_MAP,_di_) # Set I/O bit map base
159 # Create page directory.
162 movb $PAG_SIZ>>0x8,%dh # size
164 movwir(MEM_DIR,_di) # Page directory
165 movb $PAG_CNT>>0xa,%cl # Entries
166 movwir(MEM_TBL|0x7,_ax) # First entry
167 init.5: stosw # Write entry
168 addl %edx,%eax # To next
169 loop init.5 # Till done
171 # Create page tables.
173 movwir(MEM_TBL,_di) # Page table
174 movb $PAG_CNT>>0x8,%ch # Entries
175 xorl %eax,%eax # Start address
176 init.6: movb $0x7,%al # Set U:W:P flags
177 cmpwmr(btx_hdr+0x8,_cx) # Standard user page?
179 cmpwir(PAG_CNT-MEM_BTX>>0xc,_cx)# BTX memory?
180 jae init.7 # No or first page
181 andb $~0x2,%al # Clear W flag
182 cmpwir(PAG_CNT-MEM_USR>>0xc,_cx)# User page zero?
184 tstbim(0x80,btx_hdr+0x7) # Unmap it?
186 andb $~0x1,%al # Clear P flag
187 init.7: stosw # Set entry
188 addw %dx,%ax # Next address
189 loop init.6 # Till done
191 # Bring up the system.
193 movwir(0x2820,_bx) # Set protected mode
194 callwi(setpic) # IRQ offsets
195 lidtwm(idtdesc) # Set IDT
196 xorw %ax,%ax # Set base
197 movb $MEM_DIR>>0x8,%ah # of page
198 movl %eax,%cr3 # directory
199 lgdtwm(gdtdesc) # Set GDT
200 movl %cr0,%eax # Switch to
202 orl $0x80000001,%eax # and enable
203 movl %eax,%cr0 # paging
204 jmpfwi(SEL_SCODE,init.8) # To 32-bit code
205 init.8: xorl %ecx,%ecx # Zero
206 movb $SEL_SDATA,%cl # To 32-bit
211 movb $SEL_TSS,%cl # Set task
213 movl $MEM_USR,%edx # User base address
214 movzwl %ss:BDA_MEM,%eax # Get free memory
215 shll $0xa,%eax # To bytes
216 subl $0x1000,%eax # Less arg space
217 subl %edx,%eax # Less base
218 movb $SEL_UDATA,%cl # User data selector
221 pushl $0x202 # Set flags (IF set)
222 pushl $SEL_UCODE # Set CS
223 pushl btx_hdr+0xc # Set EIP
229 movb $0x7,%cl # Set remaining
230 init.9: pushb $0x0 # general
231 loop init.9 # registers
232 popa # and initialize
233 popl %es # Initialize
241 exit: cli # Disable interrupts
242 movl $MEM_ESP0,%esp # Clear stack
246 movl %cr0,%eax # Get CR0
247 andl $~0x80000000,%eax # Disable
248 movl %eax,%cr0 # paging
249 xorl %ecx,%ecx # Zero
250 movl %ecx,%cr3 # Flush TLB
255 jmpfwi(SEL_RCODE,exit.1) # CS
256 exit.1: movb $SEL_RDATA,%cl # 16-bit selector
257 movl %cx,%ss # Reload SS
259 movl %cx,%es # remaining
260 movl %cx,%fs # segment
261 movl %cx,%gs # registers
263 # To real-address mode.
265 decl %eax # Switch to
266 movl %eax,%cr0 # real mode
267 jmpfwi(0x0,exit.2) # Reload CS
268 exit.2: xorl %eax,%eax # Real mode segment
269 movl %ax,%ss # Reload SS
270 movl %ax,%ds # Address data
271 movwir(0x7008,_bx) # Set real mode
272 callwi(setpic) # IRQ offsets
273 lidtwm(ivtdesc) # Set IVT
275 # Reboot or await reset.
277 sti # Enable interrupts
278 tstbim(0x1,btx_hdr+0x7) # Reboot?
279 exit.3: jz exit.3 # No
280 int $0x19 # BIOS: Reboot
282 # Set IRQ offsets by reprogramming 8259A PICs.
284 setpic: inb $0x21,%al # Save master
286 inb $0xa1,%al # Save slave
288 movb $0x11,%al # ICW1 to
289 outb %al,$0x20 # master,
290 outb %al,$0xa0 # slave
291 movb %bl,%al # ICW2 to
292 outb %al,$0x21 # master
293 movb %bh,%al # ICW2 to
294 outb %al,$0xa1 # slave
295 movb $0x4,%al # ICW3 to
296 outb %al,$0x21 # master
297 movb $0x2,%al # ICW3 to
298 outb %al,$0xa1 # slave
299 movb $0x1,%al # ICW4 to
300 outb %al,$0x21 # master,
301 outb %al,$0xa1 # slave
302 popl %eax # Restore slave
304 popl %eax # Restore master
308 # Initiate return from V86 mode to user mode.
310 inthlt: hlt # To supervisor mode
312 # Exception jump table.
314 intx00: pushb $0x0 # Int 0x0: #DE
315 jmp ex_noc # Divide error
316 pushb $0x1 # Int 0x1: #DB
318 pushb $0x3 # Int 0x3: #BP
319 jmp ex_noc # Breakpoint
320 pushb $0x4 # Int 0x4: #OF
321 jmp ex_noc # Overflow
322 pushb $0x5 # Int 0x5: #BR
323 jmp ex_noc # BOUND range exceeded
324 pushb $0x6 # Int 0x6: #UD
325 jmp ex_noc # Invalid opcode
326 pushb $0x7 # Int 0x7: #NM
327 jmp ex_noc # Device not available
328 pushb $0x8 # Int 0x8: #DF
329 jmp except # Double fault
330 pushb $0xa # Int 0xa: #TS
331 jmp except # Invalid TSS
332 pushb $0xb # Int 0xb: #NP
333 jmp except # Segment not present
334 pushb $0xc # Int 0xc: #SS
335 jmp except # Stack segment fault
336 pushb $0xd # Int 0xd: #GP
337 jmp ex_v86 # General protection
338 pushb $0xe # Int 0xe: #PF
339 jmp except # Page fault
340 intx10: pushb $0x10 # Int 0x10: #MF
341 jmp ex_noc # Floating-point error
343 # Handle #GP exception.
345 ex_v86: testb $0x2,0x12(%esp,1) # V86 mode?
347 jmp v86mon # To monitor
349 # Save a zero error code.
351 ex_noc: pushl (%esp,1) # Duplicate int no
352 movb $0x0,0x4(%esp,1) # Fake error code
356 except: cld # String ops inc
360 movb $0x6,%al # Push loop count
361 testb $0x2,0x3a(%esp,1) # V86 mode?
367 movb $0x2,%al # Push loop count
368 cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode?
371 leal 0x50(%esp,1),%eax # Set
373 jmp except.2 # Join common code
374 except.1: pushl 0x50(%esp,1) # Set GS, FS, DS, ES
375 decb %al # (if V86 mode), and
376 jne except.1 # SS, ESP
377 except.2: pushl $SEL_SDATA # Set up
381 movl %esp,%ebx # Stack frame
382 movl $dmpfmt,%esi # Dump format string
383 movl $MEM_BUF,%edi # Buffer
387 call putstr # display
388 leal 0x18(%esp,1),%esp # Discard frame
392 cmpb $0x3,(%esp,1) # Breakpoint?
395 except.3: leal 0x8(%esp,1),%esp # Discard err, int no
396 iret # From interrupt
398 # Return to user mode from V86 mode.
400 intrtn: cld # String ops inc
403 leal 0x3c(%ebp),%edx # V86 Segment registers
404 movl MEM_TSS+TSS_ESP1,%esi # Link stack pointer
405 lodsl # INT_V86 args pointer
406 movl %esi,%ebx # Saved exception frame
407 testl %eax,%eax # INT_V86 args?
409 movl $MEM_USR,%edi # User base
410 movl 0x1c(%esi),%ebx # User ESP
411 movl %eax,(%edi,%ebx,1) # Restore to user stack
412 leal 0x8(%edi,%eax,1),%edi # Arg segment registers
413 testb $0x4,-0x6(%edi) # Return flags?
415 movl 0x30(%ebp),%eax # Get V86 flags
416 movw %ax,0x18(%esi) # Set user flags
417 intrtn.1: leal 0x10(%esi),%ebx # Saved exception frame
418 xchgl %edx,%esi # Segment registers
419 movb $0x4,%cl # Update seg regs
422 intrtn.2: movl %edx,%esi # Segment registers
423 leal 0x28(%ebp),%edi # Set up seg
424 movb $0x4,%cl # regs for
427 movl %ebx,%esi # Restore exception
428 movb $0x5,%cl # frame to
431 movl %esi,MEM_TSS+TSS_ESP1 # Link stack pointer
433 leal 0x8(%esp,1),%esp # Discard err, int no
442 v86mon: cld # String ops inc
443 pushl $SEL_SDATA # Set up for
444 popl %ds # flat addressing
445 pusha # Save registers
446 movl %esp,%ebp # Address stack frame
447 movzwl 0x2c(%ebp),%edi # Load V86 CS
448 shll $0x4,%edi # To linear
449 movl 0x28(%ebp),%esi # Load V86 IP
450 addl %edi,%esi # Code pointer
451 xorl %ecx,%ecx # Zero
452 movb $0x2,%cl # 16-bit operands
453 xorl %eax,%eax # Zero
454 v86mon.1: lodsb # Get opcode
455 cmpb $0x66,%al # Operand size prefix?
457 movb $0x4,%cl # 32-bit operands
458 jmp v86mon.1 # Continue
459 v86mon.2: cmpb $0xf4,%al # HLT?
461 cmpl $inthlt+0x1,%esi # Is inthlt?
462 jne v86mon.7 # No (ignore)
463 jmp intrtn # Return to user mode
464 v86mon.3: cmpb $0xf,%al # Is
466 cmpb $0x20,(%esi) # a
467 jne v86mon.4 # MOV EAX,CR0
468 cmpb $0xc0,0x1(%esi) # instruction?
470 v86mon.4: cmpb $0xfa,%al # CLI?
472 cmpb $0xfb,%al # STI?
474 movzwl 0x38(%ebp),%ebx # Load V86 SS
475 shll $0x4,%ebx # To offset
477 addl 0x34(%ebp),%ebx # Add V86 SP
478 movl 0x30(%ebp),%edx # Load V86 flags
479 cmpb $0x9c,%al # PUSHF/PUSHFD?
481 cmpb $0x9d,%al # POPF/POPFD?
483 cmpb $0xcd,%al # INT imm8?
485 cmpb $0xcf,%al # IRET/IRETD?
489 jmp except # Handle exception
490 v86mon.5: movl %edx,0x30(%ebp) # Save V86 flags
491 v86mon.6: popl %edx # V86 SS adjustment
492 subl %edx,%ebx # Save V86
493 movl %ebx,0x34(%ebp) # SP
494 v86mon.7: subl %edi,%esi # From linear
495 movl %esi,0x28(%ebp) # Save V86 IP
497 leal 0x8(%esp,1),%esp # Discard int no, error
500 # Emulate MOV EAX,CR0.
502 v86mov: movl %cr0,%eax # CR0 to
503 movl %eax,0x1c(%ebp) # saved EAX
506 jmp v86mon.7 # Finish up
510 v86cli: andb $~0x2,0x31(%ebp) # Clear IF
511 jmp v86mon.7 # Finish up
515 v86sti: orb $0x2,0x31(%ebp) # Set IF
516 jmp v86mon.7 # Finish up
518 # Emulate PUSHF/PUSHFD.
520 v86pushf: subl %ecx,%ebx # Adjust SP
521 cmpb $0x4,%cl # 32-bit
524 v86pushf.1: movl %edx,(%ebx) # Save flags
525 jmp v86mon.6 # Finish up
527 # Emulate IRET/IRETD.
529 v86iret: movzwl (%ebx),%esi # Load V86 IP
530 movzwl 0x2(%ebx),%edi # Load V86 CS
531 leal 0x4(%ebx),%ebx # Adjust SP
532 movl %edi,0x2c(%ebp) # Save V86 CS
533 xorl %edi,%edi # No ESI adjustment
535 # Emulate POPF/POPFD (and remainder of IRET/IRETD).
537 v86popf: cmpb $0x4,%cl # 32-bit?
539 movl %edx,%eax # Initialize
541 v86popf.1: movl (%ebx),%eax # Load flags
542 addl %ecx,%ebx # Adjust SP
543 andl $V86_FLG,%eax # Merge
544 andl $~V86_FLG,%edx # the
545 orl %eax,%edx # flags
546 jmp v86mon.5 # Finish up
550 v86intn: lodsb # Get int no
551 subl %edi,%esi # From
552 shrl $0x4,%edi # linear
553 movw %dx,-0x2(%ebx) # Save flags
554 movw %di,-0x4(%ebx) # Save CS
555 leal -0x6(%ebx),%ebx # Adjust SP
556 movw %si,(%ebx) # Save IP
557 shll $0x2,%eax # Scale
558 movzwl (%eax),%esi # Load IP
559 movzwl 0x2(%eax),%edi # Load CS
560 movl %edi,0x2c(%ebp) # Save CS
561 xorl %edi,%edi # No ESI adjustment
562 andb $~0x3,%dh # Clear IF and TF
563 jmp v86mon.5 # Finish up
565 # Hardware interrupt jump table.
567 intx20: pushb $0x8 # Int 0x20: IRQ0
568 jmp int_hw # V86 int 0x8
569 pushb $0x9 # Int 0x21: IRQ1
570 jmp int_hw # V86 int 0x9
571 pushb $0xa # Int 0x22: IRQ2
572 jmp int_hw # V86 int 0xa
573 pushb $0xb # Int 0x23: IRQ3
574 jmp int_hw # V86 int 0xb
575 pushb $0xc # Int 0x24: IRQ4
576 jmp int_hw # V86 int 0xc
577 pushb $0xd # Int 0x25: IRQ5
578 jmp int_hw # V86 int 0xd
579 pushb $0xe # Int 0x26: IRQ6
580 jmp int_hw # V86 int 0xe
581 pushb $0xf # Int 0x27: IRQ7
582 jmp int_hw # V86 int 0xf
583 pushb $0x70 # Int 0x28: IRQ8
584 jmp int_hw # V86 int 0x70
585 pushb $0x71 # Int 0x29: IRQ9
586 jmp int_hw # V86 int 0x71
587 pushb $0x72 # Int 0x2a: IRQ10
588 jmp int_hw # V86 int 0x72
589 pushb $0x73 # Int 0x2b: IRQ11
590 jmp int_hw # V86 int 0x73
591 pushb $0x74 # Int 0x2c: IRQ12
592 jmp int_hw # V86 int 0x74
593 pushb $0x75 # Int 0x2d: IRQ13
594 jmp int_hw # V86 int 0x75
595 pushb $0x76 # Int 0x2e: IRQ14
596 jmp int_hw # V86 int 0x76
597 pushb $0x77 # Int 0x2f: IRQ15
598 jmp int_hw # V86 int 0x77
600 # Reflect hardware interrupts.
602 int_hw: testb $0x2,0xe(%esp,1) # V86 mode?
604 pushl $SEL_SDATA # Address
606 xchgl %eax,(%esp,1) # Swap EAX, int no
608 movl %esp,%ebp # stack frame
610 shll $0x2,%eax # Get int
611 movl (%eax),%eax # vector
612 subl $0x6,0x14(%ebp) # Adjust V86 ESP
613 movzwl 0x18(%ebp),%ebx # V86 SS
614 shll $0x4,%ebx # * 0x10
615 addl 0x14(%ebp),%ebx # + V86 ESP
616 xchgw %ax,0x8(%ebp) # Swap V86 IP
617 rorl $0x10,%eax # Swap words
618 xchgw %ax,0xc(%ebp) # Swap V86 CS
619 roll $0x10,%eax # Swap words
620 movl %eax,(%ebx) # CS:IP for IRET
621 movl 0x10(%ebp),%eax # V86 flags
622 movw %ax,0x4(%ebx) # Flags for IRET
623 andb $~0x3,0x11(%ebp) # Clear IF, TF
626 popl %eax # registers
629 # Invoke V86 interrupt from user mode, with arguments.
631 intx31: stc # Have btx_v86
632 pushl %eax # Missing int no
634 # Invoke V86 interrupt from user mode.
636 intusr: std # String ops dec
642 movl %esp,%eax # seg regs
646 pushb $SEL_SDATA # Set up
650 movl $MEM_USR,%ebx # User base
651 movl %ebx,%edx # address
652 jc intusr.1 # If btx_v86
653 xorl %edx,%edx # Control flags
654 xorl %ebp,%ebp # btx_v86 pointer
655 intusr.1: leal 0x50(%esp,1),%esi # Base of frame
657 addl -0x4(%esi),%ebx # User ESP
658 movl MEM_TSS+TSS_ESP1,%edi # Link stack pointer
659 leal -0x4(%edi),%edi # Adjust for push
660 xorl %ecx,%ecx # Zero
661 movb $0x5,%cl # Push exception
664 xchgl %eax,%esi # Saved seg regs
665 movl 0x40(%esp,1),%eax # Get int no
666 testl %edx,%edx # Have btx_v86?
668 movl (%ebx),%ebp # btx_v86 pointer
669 movb $0x4,%cl # Count
670 addl %ecx,%ebx # Adjust for pop
671 rep # Push saved seg regs
672 movsl # on link stack
673 addl %ebp,%edx # Flatten btx_v86 ptr
674 leal 0x14(%edx),%esi # Seg regs pointer
675 movl 0x4(%edx),%eax # Get int no/address
676 movzwl 0x2(%edx),%edx # Get control flags
677 intusr.2: movl %ebp,(%edi) # Push btx_v86 and
678 movl %edi,MEM_TSS+TSS_ESP1 # save link stack ptr
679 popl %edi # Base of frame
680 xchgl %eax,%ebp # Save intno/address
681 movl 0x48(%esp,1),%eax # Get flags
682 testb $0x2,%dl # Simulate CALLF?
684 decl %ebx # Push flags
686 movw %ax,(%ebx) # stack
687 intusr.3: movb $0x4,%cl # Count
688 subl %ecx,%ebx # Push return address
689 movl $inthlt,(%ebx) # on V86 stack
690 rep # Copy seg regs to
691 movsl # exception frame
692 xchgl %eax,%ecx # Save flags
693 movl %ebx,%eax # User ESP
694 subl $V86_STK,%eax # Less bytes
696 xorl %eax,%eax # keep
697 intusr.4: shrl $0x4,%eax # Gives segment
699 shll $0x4,%eax # To bytes
700 xchgl %eax,%ebx # Swap
701 subl %ebx,%eax # Gives offset
703 xchgl %eax,%ecx # Get flags
704 btsl $0x11,%eax # Set VM
705 andb $~0x3,%ah # Clear IF and TF
707 xchgl %eax,%ebp # Get int no/address
708 testb $0x1,%dl # Address?
710 shll $0x2,%eax # Scale
711 movl (%eax),%eax # Load int vector
712 intusr.5: movl %eax,%ecx # Save
713 shrl $0x10,%eax # Gives segment
715 movw %cx,%ax # Restore
717 leal 0x10(%esp,1),%esp # Discard seg regs
723 intx30: cmpl $SYS_EXEC,%eax # Exec system call?
733 movl $MEM_USR,%eax # User base address
734 addl 0xc(%esp,1),%eax # Change to user
735 leal 0x4(%eax),%esp # stack
736 movl %cr0,%eax # Turn
737 andl $~0x80000000,%eax # off
738 movl %eax,%cr0 # paging
739 xorl %eax,%eax # Flush
743 intx30.1: incb %ss:btx_hdr+0x7 # Flag reboot
746 # Dump structure [EBX] to [EDI], using format string [ESI].
748 dump.0: stosb # Save char
749 dump: lodsb # Load char
750 testb %al,%al # End of string?
752 testb $0x80,%al # Control?
754 movb %al,%ch # Save control
755 movb $'=',%al # Append
760 addl %ebx,%esi # pointer
761 testb $DMP_X16,%ch # Dump word?
765 dump.1: testb $DMP_X32,%ch # Dump long?
769 dump.2: testb $DMP_MEM,%ch # Dump memory?
772 testb $0x2,0x52(%ebx) # V86 mode?
774 verrl 0x4(%esi) # Readable selector?
776 ldsl (%esi),%esi # Load pointer
777 jmp dump.4 # Join common code
778 dump.3: lodsl # Set offset
779 xchgl %eax,%edx # Save
781 shll $0x4,%eax # * 0x10
782 addl %edx,%eax # + offset
783 xchgl %eax,%esi # Set pointer
784 dump.4: movb $0x10,%cl # Bytes to dump
785 dump.5: lodsb # Get byte and
787 decb %cl # Keep count
789 movb $'-',%al # Separator
790 cmpb $0x8,%cl # Half way?
792 movb $' ',%al # Use space
793 dump.6: stosb # Save separator
794 jmp dump.5 # Continue
795 dump.7: popl %ds # Restore
796 dump.8: popl %esi # Restore
797 movb $0xa,%al # Line feed
798 testb $DMP_EOL,%ch # End of line?
800 movb $' ',%al # Use spaces
802 dump.9: jmp dump.0 # Continue
803 dump.10: stosb # Terminate string
806 # Convert EAX, AX, or AL to hex, saving the result to [EDI].
808 hex32: pushl %eax # Save
809 shrl $0x10,%eax # Do upper
812 hex16: call hex16.1 # Do upper 8
813 hex16.1: xchgb %ah,%al # Save/restore
814 hex8: pushl %eax # Save
815 shrb $0x4,%al # Do upper
818 hex8.1: andb $0xf,%al # Get lower 4
819 cmpb $0xa,%al # Convert
820 sbbb $0x69,%al # to hex
822 orb $0x20,%al # To lower case
826 # Output zero-terminated string [ESI] to the console.
828 putstr.0: call putchr # Output char
829 putstr: lodsb # Load char
830 testb %al,%al # End of string?
834 # Output character AL to the console.
837 xorl %ecx,%ecx # Zero for loops
838 movb $SCR_MAT,%ah # Mode/attribute
839 movl $BDA_POS,%ebx # BDA pointer
840 movw (%ebx),%dx # Cursor position
841 movl $0xb8000,%edi # Regen buffer (color)
842 cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode?
844 xorw %di,%di # Regen buffer (mono)
845 putchr.1: cmpb $0xa,%al # New line?
847 xchgl %eax,%ecx # Save char
848 movb $SCR_COL,%al # Columns per row
849 mulb %dh # * row position
850 addb %dl,%al # + column
851 adcb $0x0,%ah # position
853 xchgl %eax,%ecx # Swap char, offset
854 movw %ax,(%edi,%ecx,1) # Write attr:char
855 incl %edx # Bump cursor
856 cmpb $SCR_COL,%dl # Beyond row?
858 putchr.2: xorb %dl,%dl # Zero column
860 putchr.3: cmpb $SCR_ROW,%dh # Beyond screen?
862 leal 2*SCR_COL(%edi),%esi # New top line
863 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
866 movb $' ',%al # Space
867 movb $SCR_COL,%cl # Columns to clear
870 movb $SCR_ROW-1,%dh # Bottom line
871 putchr.4: movw %dx,(%ebx) # Update position
877 # Global descriptor table.
879 gdt: .word 0x0,0x0,0x0,0x0 # Null entry
880 .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
881 .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
882 .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
883 .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
884 .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
885 .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
886 .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
889 # Pseudo-descriptors.
891 gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT
892 idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT
893 ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT
895 # IDT construction control string.
897 idtctl: .byte 0x10, 0x8e # Int 0x0-0xf
898 .word 0x7dfb,intx00 # (exceptions)
899 .byte 0x10, 0x8e # Int 0x10
900 .word 0x1, intx10 # (exception)
901 .byte 0x10, 0x8e # Int 0x20-0x2f
902 .word 0xffff,intx20 # (hardware)
903 .byte 0x1, 0xee # int 0x30
904 .word 0x1, intx30 # (system call)
905 .byte 0x2, 0xee # Int 0x31-0x32
906 .word 0x1, intx31 # (V86, null)
907 .byte 0x0 # End of string
909 # Dump format string.
911 dmpfmt: .byte '\n' # "\n"
912 .ascii "int" # "int="
913 .byte 0x80|DMP_X32, 0x40 # "00000000 "
914 .ascii "err" # "err="
915 .byte 0x80|DMP_X32, 0x44 # "00000000 "
916 .ascii "efl" # "efl="
917 .byte 0x80|DMP_X32, 0x50 # "00000000 "
918 .ascii "eip" # "eip="
919 .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
920 .ascii "eax" # "eax="
921 .byte 0x80|DMP_X32, 0x34 # "00000000 "
922 .ascii "ebx" # "ebx="
923 .byte 0x80|DMP_X32, 0x28 # "00000000 "
924 .ascii "ecx" # "ecx="
925 .byte 0x80|DMP_X32, 0x30 # "00000000 "
926 .ascii "edx" # "edx="
927 .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
928 .ascii "esi" # "esi="
929 .byte 0x80|DMP_X32, 0x1c # "00000000 "
930 .ascii "edi" # "edi="
931 .byte 0x80|DMP_X32, 0x18 # "00000000 "
932 .ascii "ebp" # "ebp="
933 .byte 0x80|DMP_X32, 0x20 # "00000000 "
934 .ascii "esp" # "esp="
935 .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n"
937 .byte 0x80|DMP_X16, 0x4c # "0000 "
939 .byte 0x80|DMP_X16, 0xc # "0000 "
941 .byte 0x80|DMP_X16, 0x8 # "0000 "
944 .byte 0x80|DMP_X16, 0x10 # "0000 "
946 .byte 0x80|DMP_X16, 0x14 # "0000 "
948 .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n"
949 .ascii "cs:eip" # "cs:eip="
950 .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
951 .ascii "ss:esp" # "ss:esp="
952 .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n"
953 .asciz "System halted" # End