2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * Copyright (c) 1998 Robert Nordier
35 * All rights reserved.
37 * Redistribution and use in source and binary forms are freely
38 * permitted provided that the above copyright notice and this
39 * paragraph and the following disclaimer are duplicated in all
42 * This software is provided "AS IS" and without any express or
43 * implied warranties, including, without limitation, the implied
44 * warranties of merchantability and fitness for a particular
47 * $FreeBSD: src/sys/boot/i386/btx/btx/btx.s,v 1.32 2002/10/08 18:19:02 jhb Exp $
48 * $DragonFly: src/sys/boot/pc32/btx/btx/btx.S,v 1.8 2006/01/18 09:59:34 swildner Exp $
51 #include "../../bootasm.h"
56 .set PAG_SIZ,0x1000 # Page size
57 .set PAG_CNT,0x1000 # Pages to map
61 .set PSL_RESERVED_DEFAULT,0x00000002
62 .set PSL_T,0x00000100 # Trap flag
63 .set PSL_I,0x00000200 # Interrupt enable flag
64 .set PSL_VM,0x00020000 # Virtual 8086 mode flag
65 .set PSL_AC,0x00040000 # Alignment check flag
70 .set SEL_SCODE,0x8 # Supervisor code
71 .set SEL_SDATA,0x10 # Supervisor data
72 .set SEL_RCODE,0x18 # Real mode code
73 .set SEL_RDATA,0x20 # Real mode data
74 .set SEL_UCODE,0x28|3 # User code
75 .set SEL_UDATA,0x30|3 # User data
76 .set SEL_TSS,0x38 # TSS
79 * Task state segment fields.
81 .set TSS_ESP0,0x4 # PL 0 ESP
82 .set TSS_SS0,0x8 # PL 0 SS
83 .set TSS_MAP,0x66 # I/O bit map base
88 .set SYS_EXIT,0x0 # Exit
89 .set SYS_EXEC,0x1 # Exec
92 * Fields in V86 interface structure.
94 .set V86_CTL,0x0 # Control flags
95 .set V86_ADDR,0x4 # Int number/address
96 .set V86_ES,0x8 # V86 ES
97 .set V86_DS,0xc # V86 DS
98 .set V86_FS,0x10 # V86 FS
99 .set V86_GS,0x14 # V86 GS
103 .set V86F_ADDR,0x10000 # Segment:offset address
104 .set V86F_CALLF,0x20000 # Emulate far call
105 .set V86F_FLAGS,0x40000 # Return flags
108 * Dump format control bytes.
110 .set DMP_X16,0x1 # Word
111 .set DMP_X32,0x2 # Long
112 .set DMP_MEM,0x4 # Memory
113 .set DMP_EOL,0x8 # End of line
116 * Screen defaults and assumptions.
118 .set SCR_MAT,0x7 # Mode/attribute
119 .set SCR_COL,0x50 # Columns per row
120 .set SCR_ROW,0x19 # Rows per screen
123 * Derivations, for brevity.
125 .set _ESP0H,MEM_BTX_ESP0>>0x8 # Byte 1 of ESP0
126 .set _TSSIO,MEM_BTX_MAP-MEM_BTX_TSS # TSS I/O base
127 .set _TSSLM,MEM_BTX_TSS_END-MEM_BTX_TSS # TSS limit
128 .set _IDTLM,MEM_BTX_TSS-MEM_BTX_IDT-1 # IDT limit
137 start: # Start of code
142 btx_hdr: .byte 0xeb # Machine ID
143 .byte 0xe # Header size
145 .byte 0x1 # Major version
146 .byte 0x2 # Minor version
147 .byte BTX_FLAGS # Flags
148 .word PAG_CNT-MEM_BTX_ORG>>0xc # Paging control
149 .word break-start # Text size
150 .long 0x0 # Entry address
153 * Initialization routine.
155 init: cli # Disable interrupts
156 xor %ax,%ax # Zero/segment
158 mov $MEM_BTX_ESP0,%sp # stack
159 mov %ax,%es # Address
167 mov $MEM_BTX_IDT,%di # Memory to initialize
168 mov $(MEM_BTX_ZEND-MEM_BTX_IDT)/2,%cx # Words to zero
173 * Update real mode IDT for reflecting hardware interrupts.
175 mov $intr20,%bx # Address first handler
176 mov $0x10,%cx # Number of handlers
177 mov $0x20*4,%di # First real mode IDT entry
178 init.0: mov %bx,(%di) # Store IP
179 inc %di # Address next
182 add $4,%bx # Next handler
183 loop init.0 # Next IRQ
188 mov $idtctl,%si # Control string
189 init.1: lodsb # Get entry
191 xchg %ax,%cx # as word
192 jcxz init.4 # If done
194 xchg %ax,%dx # P:DPL:type
197 lodsw # Get handler offset
198 mov $SEL_SCODE,%dh # Segment selector
199 init.2: shr %bx # Handle this int?
201 mov %ax,(%di) # Set handler offset
202 mov %dh,0x2(%di) # and selector
203 mov %dl,0x5(%di) # Set P:DPL:type
204 add $0x4,%ax # Next handler
205 init.3: lea 0x8(%di),%di # Next entry
206 loop init.2 # Till set done
207 jmp init.1 # Continue
212 init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0
213 movb $SEL_SDATA,TSS_SS0(%di) # Set SS0
214 movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base
216 * Bring up the system.
218 mov $0x2820,%bx # Set protected mode
219 callw setpic # IRQ offsets
220 lidt idtdesc # Set IDT
221 lgdt gdtdesc # Set GDT
222 mov %cr0,%eax # Switch to protected
225 ljmp $SEL_SCODE,$init.8 # To 32-bit code
227 init.8: xorl %ecx,%ecx # Zero
228 movb $SEL_SDATA,%cl # To 32-bit
234 movb $SEL_TSS,%cl # Set task
238 * BTX user area base of VM, for converting physical stack
239 * addresses to btx-client virtual stack addresses.
241 movl $MEM_BTX_USR,%edx
242 #if !defined(MEM_BTX_USR_STK)
244 * XXX We should NOT use BDA_MEM here. Use a fixed location
245 * instead. (%eax is a physical stack addr)
247 movzwl %ss:BDA_MEM,%eax # Get free memory
248 shll $0xa,%eax # To bytes
251 * Use a fixed user stack instead of depending on BDA_MEM.
252 * %eax is a physical * stack address.
254 movl $MEM_BTX_USR_STK,%eax
256 subl $USR_ARGSPACE,%eax # Less arg space
257 subl %edx,%eax # Less base Phys->Virt
258 movb $SEL_UDATA,%cl # User data selector
260 pushl %eax # Set ESP (virtual address)
261 push $0x202 # Set flags (IF set)
262 push $SEL_UCODE # Set CS
263 pushl btx_hdr+0xc # Set EIP
268 pushl %edx # Set EAX (phys base addr of VM)
269 movb $0x7,%cl # Set remaining
270 init.9: push $0x0 # general
271 loop init.9 # registers
273 call sio_init # setup the serial console
275 popa # and initialize
276 popl %es # Initialize
285 exit: cli # Disable interrupts
286 movl $MEM_BTX_ESP0,%esp # Clear stack
291 movl %cr0,%eax # Get CR0
292 andl $~0x80000000,%eax # Disable
293 movl %eax,%cr0 # paging
294 xorl %ecx,%ecx # Zero
295 movl %ecx,%cr3 # Flush TLB
298 * Restore the GDT in case we caught a kernel trap.
300 lgdt gdtdesc # Set GDT
305 ljmpw $SEL_RCODE,$exit.1 # Reload CS
307 exit.1: mov $SEL_RDATA,%cl # 16-bit selector
308 mov %cx,%ss # Reload SS
310 mov %cx,%es # remaining
311 mov %cx,%fs # segment
312 mov %cx,%gs # registers
315 * To real-address mode.
318 mov %eax,%cr0 # real mode
319 ljmp $0x0,$exit.2 # Reload CS
320 exit.2: xor %ax,%ax # Real mode segment
321 mov %ax,%ss # Reload SS
322 mov %ax,%ds # Address data
323 mov $0x7008,%bx # Set real mode
324 callw setpic # IRQ offsets
325 lidt ivtdesc # Set IVT
328 * Reboot or await reset.
330 sti # Enable interrupts
331 testb $0x1,btx_hdr+0x7 # Reboot?
332 exit.3: jz exit.3 # No
333 movw $0x1234, BDA_BOOT # Do a warm boot
334 ljmp $0xf000,$0xfff0 # reboot the machine
337 * Set IRQ offsets by reprogramming 8259A PICs.
339 setpic: in $0x21,%al # Save master
341 in $0xa1,%al # Save slave
343 movb $0x11,%al # ICW1 to
344 outb %al,$0x20 # master,
345 outb %al,$0xa0 # slave
346 movb %bl,%al # ICW2 to
347 outb %al,$0x21 # master
348 movb %bh,%al # ICW2 to
349 outb %al,$0xa1 # slave
350 movb $0x4,%al # ICW3 to
351 outb %al,$0x21 # master
352 movb $0x2,%al # ICW3 to
353 outb %al,$0xa1 # slave
354 movb $0x1,%al # ICW4 to
355 outb %al,$0x21 # master,
356 outb %al,$0xa1 # slave
357 pop %ax # Restore slave
359 pop %ax # Restore master
365 * Exception jump table.
367 intx00: push $0x0 # Int 0x0: #DE
368 jmp ex_noc # Divide error
369 push $0x1 # Int 0x1: #DB
371 push $0x3 # Int 0x3: #BP
372 jmp ex_noc # Breakpoint
373 push $0x4 # Int 0x4: #OF
374 jmp ex_noc # Overflow
375 push $0x5 # Int 0x5: #BR
376 jmp ex_noc # BOUND range exceeded
377 push $0x6 # Int 0x6: #UD
378 jmp ex_noc # Invalid opcode
379 push $0x7 # Int 0x7: #NM
380 jmp ex_noc # Device not available
381 push $0x8 # Int 0x8: #DF
382 jmp except # Double fault
383 push $0xa # Int 0xa: #TS
384 jmp except # Invalid TSS
385 push $0xb # Int 0xb: #NP
386 jmp except # Segment not present
387 push $0xc # Int 0xc: #SS
388 jmp except # Stack segment fault
389 push $0xd # Int 0xd: #GP
390 jmp except # General protection
391 push $0xe # Int 0xe: #PF
392 jmp except # Page fault
393 intx10: push $0x10 # Int 0x10: #MF
394 jmp ex_noc # Floating-point error
397 * Save a zero error code.
399 ex_noc: pushl (%esp,1) # Duplicate int no
400 movb $0x0,0x4(%esp,1) # Fake error code
405 except: cld # String ops inc
413 cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode?
416 jmp except.2 # Join common code
417 except.1: pushl 0x50(%esp,1) # Set SS
418 except.2: pushl 0x50(%esp,1) # Set ESP
419 push $SEL_SDATA # Set up
423 movl %esp,%ebx # Stack frame
424 movl $dmpfmt,%esi # Dump format string
425 movl $MEM_BTX_BUF,%edi # Buffer
429 call putstr # display
430 leal 0x18(%esp,1),%esp # Discard frame
434 cmpb $0x3,(%esp,1) # Breakpoint?
436 cmpb $0x1,(%esp,1) # Debug?
438 testl $PSL_T,0x10(%esp,1) # Trap flag set?
440 except.2a: jmp exit # Exit
441 except.3: leal 0x8(%esp,1),%esp # Discard err, int no
442 iret # From interrupt
445 * Reboot the machine by setting the reboot flag and exiting
447 reboot: orb $0x1,btx_hdr+0x7 # Set the reboot flag
448 jmp exit # Terminate BTX and reboot
451 * Protected Mode Hardware interrupt jump table.
453 intx20: push $0x8 # Int 0x20: IRQ0
454 jmp int_hw # V86 int 0x8
455 push $0x9 # Int 0x21: IRQ1
456 jmp int_hw # V86 int 0x9
457 push $0xa # Int 0x22: IRQ2
458 jmp int_hw # V86 int 0xa
459 push $0xb # Int 0x23: IRQ3
460 jmp int_hw # V86 int 0xb
461 push $0xc # Int 0x24: IRQ4
462 jmp int_hw # V86 int 0xc
463 push $0xd # Int 0x25: IRQ5
464 jmp int_hw # V86 int 0xd
465 push $0xe # Int 0x26: IRQ6
466 jmp int_hw # V86 int 0xe
467 push $0xf # Int 0x27: IRQ7
468 jmp int_hw # V86 int 0xf
469 push $0x70 # Int 0x28: IRQ8
470 jmp int_hw # V86 int 0x70
471 push $0x71 # Int 0x29: IRQ9
472 jmp int_hw # V86 int 0x71
473 push $0x72 # Int 0x2a: IRQ10
474 jmp int_hw # V86 int 0x72
475 push $0x73 # Int 0x2b: IRQ11
476 jmp int_hw # V86 int 0x73
477 push $0x74 # Int 0x2c: IRQ12
478 jmp int_hw # V86 int 0x74
479 push $0x75 # Int 0x2d: IRQ13
480 jmp int_hw # V86 int 0x75
481 push $0x76 # Int 0x2e: IRQ14
482 jmp int_hw # V86 int 0x76
483 push $0x77 # Int 0x2f: IRQ15
484 jmp int_hw # V86 int 0x77
487 * Invoke real mode interrupt/function call from user mode with arguments.
489 intx31: pushl $-1 # Dummy int no for btx_v86
492 * Invoke real mode interrupt/function call from protected mode.
494 * We place a trampoline on the user stack that will return to rret_tramp
495 * which will reenter protected mode and then finally return to the user
498 * Kernel frame %esi points to: Real mode stack frame at MEM_BTX_ESPR:
500 * -0x00 user %ss -0x04 kernel %esp (with full frame)
501 * -0x04 user %esp -0x08 btx_v86 pointer
502 * -0x08 user %eflags -0x0c flags (only used if interrupt)
503 * -0x0c user %cs -0x10 real mode CS:IP return trampoline
504 * -0x10 user %eip -0x12 real mode flags
505 * -0x14 int no -0x16 real mode CS:IP (target)
518 * -0x48 zero %eax (hardware int only)
519 * -0x4c zero %ecx (hardware int only)
520 * -0x50 zero %edx (hardware int only)
521 * -0x54 zero %ebx (hardware int only)
522 * -0x58 zero %esp (hardware int only)
523 * -0x5c zero %ebp (hardware int only)
524 * -0x60 zero %esi (hardware int only)
525 * -0x64 zero %edi (hardware int only)
526 * -0x68 zero %gs (hardware int only)
527 * -0x6c zero %fs (hardware int only)
528 * -0x70 zero %ds (hardware int only)
529 * -0x74 zero %es (hardware int only)
531 int_hw: cld # String ops inc
537 push $SEL_SDATA # Set up
541 leal 0x44(%esp,1),%esi # Base of frame
542 movl %esp,MEM_BTX_ESPR-0x04 # Save kernel stack pointer
543 movl -0x14(%esi),%eax # Get Int no
544 cmpl $-1,%eax # Hardware interrupt?
547 * v86 calls save the btx_v86 pointer on the real mode stack and read
548 * the address and flags from the btx_v86 structure. For interrupt
549 * handler invocations (VM86 INTx requests), disable interrupts,
550 * tracing, and alignment checking while the handler runs.
552 movl $MEM_BTX_USR,%ebx # User base
553 movl %ebx,%edx # address
554 addl -0x4(%esi),%ebx # User ESP
555 movl (%ebx),%ebp # btx_v86 pointer
556 addl %ebp,%edx # Flatten btx_v86 ptr
557 movl %edx,MEM_BTX_ESPR-0x08 # Save btx_v86 ptr
558 movl V86_ADDR(%edx),%eax # Get int no/address
559 movl V86_CTL(%edx),%edx # Get control flags
560 movl -0x08(%esi),%ebx # Save user flags in %ebx
561 testl $V86F_ADDR,%edx # Segment:offset?
563 andl $~(PSL_I|PSL_T|PSL_AC),%ebx # Disable interrupts, tracing,
564 # and alignment checking for
566 jmp intusr.3 # Skip hardware interrupt
568 * Hardware interrupts store a NULL btx_v86 pointer and use the
569 * address (interrupt number) from the stack with empty flags. Also,
570 * push a dummy frame of zeros onto the stack for all the general
571 * purpose and segment registers and clear %eflags. This gives the
572 * hardware interrupt handler a clean slate.
574 intusr.1: xorl %edx,%edx # Control flags
575 movl %edx,MEM_BTX_ESPR-0x08 # NULL btx_v86 ptr
576 movl $12,%ecx # Frame is 12 dwords
577 intusr.2: pushl $0x0 # Fill frame
578 loop intusr.2 # with zeros
579 movl $PSL_RESERVED_DEFAULT,%ebx # Set clean %eflags
581 * Look up real mode IDT entry for hardware interrupts and VM86 INTx
584 intusr.3: shll $0x2,%eax # Scale
585 movl (%eax),%eax # Load int vector
586 jmp intusr.5 # Skip CALLF test
588 * Panic if V86F_CALLF isn't set with V86F_ADDR.
590 intusr.4: testl $V86F_CALLF,%edx # Far call?
592 movl %edx,0x30(%esp,1) # Place VM86 flags in int no
593 movl $badvm86,%esi # Display bad
594 call putstr # VM86 call
599 popal # Restore gp regs
602 * %eax now holds the segment:offset of the function.
603 * %ebx now holds the %eflags to pass to real mode.
604 * %edx now holds the V86F_* flags.
606 intusr.5: movw %bx,MEM_BTX_ESPR-0x12 # Pass user flags to real mode
609 * If this is a v86 call, copy the seg regs out of the btx_v86 structure.
611 movl MEM_BTX_ESPR-0x08,%ecx # Get btx_v86 ptr
612 jecxz intusr.6 # Skip for hardware ints
613 leal -0x44(%esi),%edi # %edi => kernel stack seg regs
615 leal V86_ES(%ecx),%esi # %esi => btx_v86 seg regs
616 movl $4,%ecx # Copy seg regs
618 movsl # to kernel stack
620 intusr.6: movl -0x08(%esi),%ebx # Copy user flags to real
621 movl %ebx,MEM_BTX_ESPR-0x0c # mode return trampoline
622 movl $rret_tramp,%ebx # Set return trampoline
623 movl %ebx,MEM_BTX_ESPR-0x10 # CS:IP
624 movl %eax,MEM_BTX_ESPR-0x16 # Real mode target CS:IP
625 ljmpw $SEL_RCODE,$intusr.7 # Change to 16-bit segment
627 intusr.7: movl %cr0,%eax # Leave
629 movl %eax,%cr0 # mode
631 intusr.8: xorw %ax,%ax # Reset %ds
634 lidt ivtdesc # Set IVT
639 popal # Restore gp regs
640 movw $MEM_BTX_ESPR-0x16,%sp # Switch to real mode stack
641 iret # Call target routine
643 * For the return to real mode we setup a stack frame like this on the real
644 * mode stack. Note that callf calls won't pop off the flags, but we just
645 * ignore that by repositioning %sp to be just above the btx_v86 pointer
646 * so it is aligned. The stack is relative to MEM_BTX_ESPR.
664 rret_tramp: movw $MEM_BTX_ESPR-0x08,%sp # Reset stack pointer
665 pushal # Save gp regs
670 pushfl # Save %eflags
671 cli # Disable interrupts
673 xorw %ax,%ax # Reset seg
675 movw %ax,%es # (%ss is already 0)
676 lidt idtdesc # Set IDT
677 lgdt gdtdesc # Set GDT
678 mov %cr0,%eax # Switch to protected
681 ljmp $SEL_SCODE,$rret_tramp.1 # To 32-bit code
683 rret_tramp.1: xorl %ecx,%ecx # Zero
684 movb $SEL_SDATA,%cl # Setup
685 movw %cx,%ss # 32-bit
688 movl MEM_BTX_ESPR-0x04,%esp # Switch to kernel stack
689 leal 0x44(%esp,1),%esi # Base of frame
690 andb $~0x2,tss_desc+0x5 # Clear TSS busy
691 movb $SEL_TSS,%cl # Set task
694 * Now we are back in protected mode. The kernel stack frame set up
695 * before entering real mode is still intact. For hardware interrupts,
696 * leave the frame unchanged.
698 cmpl $0,MEM_BTX_ESPR-0x08 # Leave saved regs unchanged
699 jz rret_tramp.3 # for hardware ints
701 * For V86 calls, copy the registers off of the real mode stack onto
702 * the kernel stack as we want their updated values. Also, initialize
703 * the segment registers on the kernel stack.
705 * Note that the %esp in the kernel stack after this is garbage, but popa
706 * ignores it, so we don't have to fix it up.
708 leal -0x18(%esi),%edi # Kernel stack GP regs
710 movl $MEM_BTX_ESPR-0x0c,%esi # Real mode stack GP regs
711 movl $8,%ecx # Copy GP regs from
712 rep # real mode stack
713 movsl # to kernel stack
714 movl $SEL_UDATA,%eax # Selector for data seg regs
715 movl $4,%ecx # Initialize %ds,
719 * For V86 calls, copy the saved seg regs on the real mode stack back
720 * over to the btx_v86 structure. Also, conditionally update the
721 * saved eflags on the kernel stack based on the flags from the user.
723 movl MEM_BTX_ESPR-0x08,%ecx # Get btx_v86 ptr
724 leal V86_GS(%ecx),%edi # %edi => btx_v86 seg regs
725 leal MEM_BTX_ESPR-0x2c,%esi # %esi => real mode seg regs
726 xchgl %ecx,%edx # Save btx_v86 ptr
727 movl $4,%ecx # Copy seg regs
728 rep # from real mode stack
731 movl V86_CTL(%edx),%edx # Read V86 control flags
732 testl $V86F_FLAGS,%edx # User wants flags?
734 movl MEM_BTX_ESPR-0x3c,%eax # Read real mode flags
735 movw %ax,-0x08(%esi) # Update user flags (low 16)
737 * Return to the user task
739 rret_tramp.3: popl %es # Restore
743 popal # Restore gp regs
744 addl $4,%esp # Discard int no
745 iret # Return to user mode
750 intx30: cmpl $SYS_EXEC,%eax # Exec system call?
760 movl $MEM_BTX_USR,%eax # User base address
761 addl 0xc(%esp,1),%eax # Change to user
762 leal 0x4(%eax),%esp # stack
765 intx30.1: orb $0x1,%ss:btx_hdr+0x7 # Flag reboot
769 * Dump structure [EBX] to [EDI], using format string [ESI].
771 dump.0: stosb # Save char
772 dump: lodsb # Load char
773 testb %al,%al # End of string?
775 testb $0x80,%al # Control?
777 movb %al,%ch # Save control
778 movb $'=',%al # Append
783 addl %ebx,%esi # pointer
784 testb $DMP_X16,%ch # Dump word?
788 dump.1: testb $DMP_X32,%ch # Dump long?
792 dump.2: testb $DMP_MEM,%ch # Dump memory?
795 testl $PSL_VM,0x50(%ebx) # V86 mode?
797 verr 0x4(%esi) # Readable selector?
799 ldsl (%esi),%esi # Load pointer
800 jmp dump.4 # Join common code
801 dump.3: lodsl # Set offset
802 xchgl %eax,%edx # Save
804 shll $0x4,%eax # * 0x10
805 addl %edx,%eax # + offset
806 xchgl %eax,%esi # Set pointer
807 dump.4: movb $2,%dl # Num lines
808 dump.4a: movb $0x10,%cl # Bytes to dump
809 dump.5: lodsb # Get byte and
811 decb %cl # Keep count
813 movb $'-',%al # Separator
814 cmpb $0x8,%cl # Half way?
816 movb $' ',%al # Use space
817 dump.6: stosb # Save separator
818 jmp dump.5 # Continue
819 dump.6a: decb %dl # Keep count
821 movb $0xa,%al # Line feed
823 movb $7,%cl # Leading
824 movb $' ',%al # spaces
825 dump.6b: stosb # Dump
828 jmp dump.4a # Next line
829 dump.7: popl %ds # Restore
830 dump.8: popl %esi # Restore
831 movb $0xa,%al # Line feed
832 testb $DMP_EOL,%ch # End of line?
834 movb $' ',%al # Use spaces
836 dump.9: jmp dump.0 # Continue
837 dump.10: stosb # Terminate string
841 * Convert EAX, AX, or AL to hex, saving the result to [EDI].
843 hex32: pushl %eax # Save
844 shrl $0x10,%eax # Do upper
847 hex16: call hex16.1 # Do upper 8
848 hex16.1: xchgb %ah,%al # Save/restore
849 hex8: pushl %eax # Save
850 shrb $0x4,%al # Do upper
853 hex8.1: andb $0xf,%al # Get lower 4
854 cmpb $0xa,%al # Convert
855 sbbb $0x69,%al # to hex
857 orb $0x20,%al # To lower case
862 * Output zero-terminated string [ESI] to the console.
864 putstr.0: call putchr # Output char
865 putstr: lodsb # Load char
866 testb %al,%al # End of string?
870 .set SIO_PRT,SIOPRT # Base port
871 .set SIO_FMT,SIOFMT # 8N1
872 .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD
875 * void sio_init(void)
877 sio_init: movw $SIO_PRT+0x3,%dx # Data format reg
878 movb $SIO_FMT|0x80,%al # Set format
879 outb %al,(%dx) # and DLAB
881 subb $0x3,%dl # Divisor latch reg
882 movw $SIO_DIV,%ax # Set
885 movb $SIO_FMT,%al # Clear
886 outb %al,(%dx) # DLAB
887 incl %edx # Modem control reg
888 movb $0x3,%al # Set RTS,
890 incl %edx # Line status reg
893 * void sio_flush(void)
895 sio_flush.0: call sio_getc.1 # Get character
896 sio_flush: call sio_ischar # Check for character
897 jnz sio_flush.0 # Till none
901 * void sio_putc(int c)
903 sio_putc: movw $SIO_PRT+0x5,%dx # Line status reg
904 xor %ecx,%ecx # Timeout
905 movb $0x40,%ch # counter
906 sio_putc.1: inb (%dx),%al # Transmitter
907 testb $0x20,%al # buffer empty?
908 loopz sio_putc.1 # No
909 jz sio_putc.2 # If timeout
910 movb 0x4(%esp,1),%al # Get character
911 subb $0x5,%dl # Transmitter hold reg
912 outb %al,(%dx) # Write character
913 sio_putc.2: ret $0x4 # To caller
918 sio_getc: call sio_ischar # Character available?
920 sio_getc.1: subb $0x5,%dl # Receiver buffer reg
921 inb (%dx),%al # Read character
925 * int sio_ischar(void)
927 sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register
928 xorl %eax,%eax # Zero
929 inb (%dx),%al # Received data
930 andb $0x1,%al # ready?
934 * Output character AL to the serial console.
937 cmpb $10, %al # is it a newline?
938 jne putchr.1 # no?, then leave
939 push $13 # output a carriage
940 call sio_putc # return first
941 movb $10, %al # restore %al
942 putchr.1: pushl %eax # Push the character
944 call sio_putc # Output the character
949 * Output character AL to the console.
952 xorl %ecx,%ecx # Zero for loops
953 movb $SCR_MAT,%ah # Mode/attribute
954 movl $BDA_POS,%ebx # BDA pointer
955 movw (%ebx),%dx # Cursor position
956 movl $0xb8000,%edi # Regen buffer (color)
957 cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode?
959 xorw %di,%di # Regen buffer (mono)
960 putchr.1: cmpb $0xa,%al # New line?
962 xchgl %eax,%ecx # Save char
963 movb $SCR_COL,%al # Columns per row
964 mulb %dh # * row position
965 addb %dl,%al # + column
966 adcb $0x0,%ah # position
968 xchgl %eax,%ecx # Swap char, offset
969 movw %ax,(%edi,%ecx,1) # Write attr:char
970 incl %edx # Bump cursor
971 cmpb $SCR_COL,%dl # Beyond row?
973 putchr.2: xorb %dl,%dl # Zero column
975 putchr.3: cmpb $SCR_ROW,%dh # Beyond screen?
977 leal 2*SCR_COL(%edi),%esi # New top line
978 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
981 movb $0x20,%al # Space
982 movb $SCR_COL,%cl # Columns to clear
985 movb $SCR_ROW-1,%dh # Bottom line
986 putchr.4: movw %dx,(%ebx) # Update position
993 * Real Mode Hardware interrupt jump table.
995 intr20: push $0x8 # Int 0x20: IRQ0
996 jmp int_hwr # V86 int 0x8
997 push $0x9 # Int 0x21: IRQ1
998 jmp int_hwr # V86 int 0x9
999 push $0xa # Int 0x22: IRQ2
1000 jmp int_hwr # V86 int 0xa
1001 push $0xb # Int 0x23: IRQ3
1002 jmp int_hwr # V86 int 0xb
1003 push $0xc # Int 0x24: IRQ4
1004 jmp int_hwr # V86 int 0xc
1005 push $0xd # Int 0x25: IRQ5
1006 jmp int_hwr # V86 int 0xd
1007 push $0xe # Int 0x26: IRQ6
1008 jmp int_hwr # V86 int 0xe
1009 push $0xf # Int 0x27: IRQ7
1010 jmp int_hwr # V86 int 0xf
1011 push $0x70 # Int 0x28: IRQ8
1012 jmp int_hwr # V86 int 0x70
1013 push $0x71 # Int 0x29: IRQ9
1014 jmp int_hwr # V86 int 0x71
1015 push $0x72 # Int 0x2a: IRQ10
1016 jmp int_hwr # V86 int 0x72
1017 push $0x73 # Int 0x2b: IRQ11
1018 jmp int_hwr # V86 int 0x73
1019 push $0x74 # Int 0x2c: IRQ12
1020 jmp int_hwr # V86 int 0x74
1021 push $0x75 # Int 0x2d: IRQ13
1022 jmp int_hwr # V86 int 0x75
1023 push $0x76 # Int 0x2e: IRQ14
1024 jmp int_hwr # V86 int 0x76
1025 push $0x77 # Int 0x2f: IRQ15
1026 jmp int_hwr # V86 int 0x77
1028 * Reflect hardware interrupts in real mode.
1030 int_hwr: push %ax # Save
1033 mov %sp,%bp # Address stack frame
1034 xchg %bx,6(%bp) # Swap BX, int no
1035 xor %ax,%ax # Set %ds:%bx to
1036 shl $2,%bx # point to
1037 mov %ax,%ds # IDT entry
1038 mov (%bx),%ax # Load IP
1039 mov 2(%bx),%bx # Load CS
1040 xchg %ax,4(%bp) # Swap saved %ax,%bx with
1041 xchg %bx,6(%bp) # CS:IP of handler
1044 lret # Jump to handler
1047 * Global descriptor table.
1049 * 16: segment extent lsb
1050 * 24: segment base lsb
1056 * 4: segment extent msb
1058 * 1: 32 bit, else 16 bit
1059 * 1: limit granularity byte/page units
1061 * 8: segment base msb
1065 gdt: .word 0x0,0x0,0x0,0x0 # Null entry
1066 .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
1067 .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
1068 .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
1069 .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
1070 .word 0xffff,MEM_BTX_USR,0xfa00,0xcf# SEL_UCODE
1071 .word 0xffff,MEM_BTX_USR,0xf200,0xcf# SEL_UDATA
1072 tss_desc: .word _TSSLM,MEM_BTX_TSS,0x8900,0x0 # SEL_TSS
1075 * Pseudo-descriptors.
1077 gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT
1078 idtdesc: .word _IDTLM,MEM_BTX_IDT,0x0 # IDT
1079 ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT
1082 * IDT construction control string.
1084 idtctl: .byte 0x10, 0x8e # Int 0x0-0xf
1085 .word 0x7dfb,intx00 # (exceptions)
1086 .byte 0x10, 0x8e # Int 0x10
1087 .word 0x1, intx10 # (exception)
1088 .byte 0x10, 0x8e # Int 0x20-0x2f
1089 .word 0xffff,intx20 # (hardware)
1090 .byte 0x1, 0xee # int 0x30
1091 .word 0x1, intx30 # (system call)
1092 .byte 0x2, 0xee # Int 0x31-0x32
1093 .word 0x1, intx31 # (V86, null)
1094 .byte 0x0 # End of string
1097 * Dump format string.
1099 dmpfmt: .byte '\n' # "\n"
1100 .ascii "int" # "int="
1101 .byte 0x80|DMP_X32, 0x40 # "00000000 "
1102 .ascii "err" # "err="
1103 .byte 0x80|DMP_X32, 0x44 # "00000000 "
1104 .ascii "efl" # "efl="
1105 .byte 0x80|DMP_X32, 0x50 # "00000000 "
1106 .ascii "eip" # "eip="
1107 .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
1108 .ascii "eax" # "eax="
1109 .byte 0x80|DMP_X32, 0x34 # "00000000 "
1110 .ascii "ebx" # "ebx="
1111 .byte 0x80|DMP_X32, 0x28 # "00000000 "
1112 .ascii "ecx" # "ecx="
1113 .byte 0x80|DMP_X32, 0x30 # "00000000 "
1114 .ascii "edx" # "edx="
1115 .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
1116 .ascii "esi" # "esi="
1117 .byte 0x80|DMP_X32, 0x1c # "00000000 "
1118 .ascii "edi" # "edi="
1119 .byte 0x80|DMP_X32, 0x18 # "00000000 "
1120 .ascii "ebp" # "ebp="
1121 .byte 0x80|DMP_X32, 0x20 # "00000000 "
1122 .ascii "esp" # "esp="
1123 .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n"
1125 .byte 0x80|DMP_X16, 0x4c # "0000 "
1127 .byte 0x80|DMP_X16, 0xc # "0000 "
1129 .byte 0x80|DMP_X16, 0x8 # "0000 "
1132 .byte 0x80|DMP_X16, 0x10 # "0000 "
1134 .byte 0x80|DMP_X16, 0x14 # "0000 "
1136 .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n"
1137 .ascii "cs:eip" # "cs:eip="
1138 .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
1139 .ascii "ss:esp" # "ss:esp="
1140 .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n"
1141 .asciz "BTX halted\n" # End
1143 * Bad VM86 call panic
1145 badvm86: .asciz "Invalid VM86 Request\n"
1149 * End of BTX memory.