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_ESPR,0x5e00 # Real mode stack
25 .set MEM_IDT,0x5e00 # IDT
26 .set MEM_TSS,0x5f98 # TSS
27 .set MEM_MAP,0x6000 # I/O bit map
28 .set MEM_TSS_END,0x7fff # End of TSS
29 .set MEM_ORG,0x9000 # BTX code
30 .set MEM_USR,0xa000 # Start of user memory
34 .set PAG_SIZ,0x1000 # Page size
35 .set PAG_CNT,0x1000 # Pages to map
39 .set SEL_SCODE,0x8 # Supervisor code
40 .set SEL_SDATA,0x10 # Supervisor data
41 .set SEL_RCODE,0x18 # Real mode code
42 .set SEL_RDATA,0x20 # Real mode data
43 .set SEL_UCODE,0x28|3 # User code
44 .set SEL_UDATA,0x30|3 # User data
45 .set SEL_TSS,0x38 # TSS
47 * Task state segment fields.
49 .set TSS_ESP0,0x4 # PL 0 ESP
50 .set TSS_SS0,0x8 # PL 0 SS
51 .set TSS_MAP,0x66 # I/O bit map base
55 .set SYS_EXIT,0x0 # Exit
56 .set SYS_EXEC,0x1 # Exec
58 * Fields in V86 interface structure.
60 .set V86_CTL,0x0 # Control flags
61 .set V86_ADDR,0x4 # Int number/address
62 .set V86_ES,0x8 # V86 ES
63 .set V86_DS,0xc # V86 DS
64 .set V86_FS,0x10 # V86 FS
65 .set V86_GS,0x14 # V86 GS
69 .set V86F_ADDR,0x10000 # Segment:offset address
70 .set V86F_CALLF,0x20000 # Emulate far call
71 .set V86F_FLAGS,0x40000 # Return flags
73 * Dump format control bytes.
75 .set DMP_X16,0x1 # Word
76 .set DMP_X32,0x2 # Long
77 .set DMP_MEM,0x4 # Memory
78 .set DMP_EOL,0x8 # End of line
80 * Screen defaults and assumptions.
82 .set SCR_MAT,0x7 # Mode/attribute
83 .set SCR_COL,0x50 # Columns per row
84 .set SCR_ROW,0x19 # Rows per screen
86 * BIOS Data Area locations.
88 .set BDA_MEM,0x413 # Free memory
89 .set BDA_SCR,0x449 # Video mode
90 .set BDA_POS,0x450 # Cursor position
91 .set BDA_BOOT,0x472 # Boot howto flag
93 * Derivations, for brevity.
95 .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0
96 .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base
97 .set _TSSLM,MEM_TSS_END-MEM_TSS # TSS limit
98 .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 0x2 # Minor version
113 .byte BTX_FLAGS # Flags
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 xor %ax,%ax # Zero/segment
123 mov $MEM_ESP0,%sp # stack
124 mov %ax,%es # Address
131 mov $MEM_IDT,%di # Memory to initialize
132 mov $(MEM_ORG-MEM_IDT)/2,%cx # Words to zero
136 * Update real mode IDT for reflecting hardware interrupts.
138 mov $intr20,%bx # Address first handler
139 mov $0x10,%cx # Number of handlers
140 mov $0x20*4,%di # First real mode IDT entry
141 init.0: mov %bx,(%di) # Store IP
142 inc %di # Address next
145 add $4,%bx # Next handler
146 loop init.0 # Next IRQ
151 mov $idtctl,%si # Control string
152 init.1: lodsb # Get entry
154 xchg %ax,%cx # as word
155 jcxz init.4 # If done
157 xchg %ax,%dx # P:DPL:type
160 lodsw # Get handler offset
161 mov $SEL_SCODE,%dh # Segment selector
162 init.2: shr %bx # Handle this int?
164 mov %ax,(%di) # Set handler offset
165 mov %dh,0x2(%di) # and selector
166 mov %dl,0x5(%di) # Set P:DPL:type
167 add $0x4,%ax # Next handler
168 init.3: lea 0x8(%di),%di # Next entry
169 loop init.2 # Till set done
170 jmp init.1 # Continue
174 init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0
175 movb $SEL_SDATA,TSS_SS0(%di) # Set SS0
176 movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base
178 * Bring up the system.
180 mov $0x2820,%bx # Set protected mode
181 callw setpic # IRQ offsets
182 lidt idtdesc # Set IDT
183 lgdt gdtdesc # Set GDT
184 mov %cr0,%eax # Switch to protected
187 ljmp $SEL_SCODE,$init.8 # To 32-bit code
189 init.8: xorl %ecx,%ecx # Zero
190 movb $SEL_SDATA,%cl # To 32-bit
195 movb $SEL_TSS,%cl # Set task
197 movl $MEM_USR,%edx # User base address
198 movzwl %ss:BDA_MEM,%eax # Get free memory
199 shll $0xa,%eax # To bytes
200 subl $0x1000,%eax # Less arg space
201 subl %edx,%eax # Less base
202 movb $SEL_UDATA,%cl # User data selector
205 push $0x202 # Set flags (IF set)
206 push $SEL_UCODE # Set CS
207 pushl btx_hdr+0xc # Set EIP
213 movb $0x7,%cl # Set remaining
214 init.9: push $0x0 # general
215 loop init.9 # registers
217 call sio_init # setup the serial console
219 popa # and initialize
220 popl %es # Initialize
228 exit: cli # Disable interrupts
229 movl $MEM_ESP0,%esp # Clear stack
233 movl %cr0,%eax # Get CR0
234 andl $~0x80000000,%eax # Disable
235 movl %eax,%cr0 # paging
236 xorl %ecx,%ecx # Zero
237 movl %ecx,%cr3 # Flush TLB
239 * Restore the GDT in case we caught a kernel trap.
241 lgdt gdtdesc # Set GDT
245 ljmpw $SEL_RCODE,$exit.1 # Reload CS
247 exit.1: mov $SEL_RDATA,%cl # 16-bit selector
248 mov %cx,%ss # Reload SS
250 mov %cx,%es # remaining
251 mov %cx,%fs # segment
252 mov %cx,%gs # registers
254 * To real-address mode.
257 mov %eax,%cr0 # real mode
258 ljmp $0x0,$exit.2 # Reload CS
259 exit.2: xor %ax,%ax # Real mode segment
260 mov %ax,%ss # Reload SS
261 mov %ax,%ds # Address data
262 mov $0x7008,%bx # Set real mode
263 callw setpic # IRQ offsets
264 lidt ivtdesc # Set IVT
266 * Reboot or await reset.
268 sti # Enable interrupts
269 testb $0x1,btx_hdr+0x7 # Reboot?
270 exit.3: jz exit.3 # No
271 movw $0x1234, BDA_BOOT # Do a warm boot
272 ljmp $0xf000,$0xfff0 # reboot the machine
274 * Set IRQ offsets by reprogramming 8259A PICs.
276 setpic: in $0x21,%al # Save master
278 in $0xa1,%al # Save slave
280 movb $0x11,%al # ICW1 to
281 outb %al,$0x20 # master,
282 outb %al,$0xa0 # slave
283 movb %bl,%al # ICW2 to
284 outb %al,$0x21 # master
285 movb %bh,%al # ICW2 to
286 outb %al,$0xa1 # slave
287 movb $0x4,%al # ICW3 to
288 outb %al,$0x21 # master
289 movb $0x2,%al # ICW3 to
290 outb %al,$0xa1 # slave
291 movb $0x1,%al # ICW4 to
292 outb %al,$0x21 # master,
293 outb %al,$0xa1 # slave
294 pop %ax # Restore slave
296 pop %ax # Restore master
301 * Exception jump table.
303 intx00: push $0x0 # Int 0x0: #DE
304 jmp ex_noc # Divide error
305 push $0x1 # Int 0x1: #DB
307 push $0x3 # Int 0x3: #BP
308 jmp ex_noc # Breakpoint
309 push $0x4 # Int 0x4: #OF
310 jmp ex_noc # Overflow
311 push $0x5 # Int 0x5: #BR
312 jmp ex_noc # BOUND range exceeded
313 push $0x6 # Int 0x6: #UD
314 jmp ex_noc # Invalid opcode
315 push $0x7 # Int 0x7: #NM
316 jmp ex_noc # Device not available
317 push $0x8 # Int 0x8: #DF
318 jmp except # Double fault
319 push $0xa # Int 0xa: #TS
320 jmp except # Invalid TSS
321 push $0xb # Int 0xb: #NP
322 jmp except # Segment not present
323 push $0xc # Int 0xc: #SS
324 jmp except # Stack segment fault
325 push $0xd # Int 0xd: #GP
326 jmp except # General protection
327 push $0xe # Int 0xe: #PF
328 jmp except # Page fault
329 intx10: push $0x10 # Int 0x10: #MF
330 jmp ex_noc # Floating-point error
332 * Save a zero error code.
334 ex_noc: pushl (%esp,1) # Duplicate int no
335 movb $0x0,0x4(%esp,1) # Fake error code
339 except: cld # String ops inc
347 cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode?
350 jmp except.2 # Join common code
351 except.1: pushl 0x50(%esp,1) # Set SS
352 except.2: pushl 0x50(%esp,1) # Set ESP
353 push $SEL_SDATA # Set up
357 movl %esp,%ebx # Stack frame
358 movl $dmpfmt,%esi # Dump format string
359 movl $MEM_BUF,%edi # Buffer
363 call putstr # display
364 leal 0x18(%esp,1),%esp # Discard frame
368 cmpb $0x3,(%esp,1) # Breakpoint?
370 cmpb $0x1,(%esp,1) # Debug?
372 testl $0x100,0x10(%esp,1) # Trap flag set?
374 except.2a: jmp exit # Exit
375 except.3: leal 0x8(%esp,1),%esp # Discard err, int no
376 iret # From interrupt
379 * Reboot the machine by setting the reboot flag and exiting
381 reboot: orb $0x1,btx_hdr+0x7 # Set the reboot flag
382 jmp exit # Terminate BTX and reboot
385 * Protected Mode Hardware interrupt jump table.
387 intx20: push $0x8 # Int 0x20: IRQ0
388 jmp int_hw # V86 int 0x8
389 push $0x9 # Int 0x21: IRQ1
390 jmp int_hw # V86 int 0x9
391 push $0xa # Int 0x22: IRQ2
392 jmp int_hw # V86 int 0xa
393 push $0xb # Int 0x23: IRQ3
394 jmp int_hw # V86 int 0xb
395 push $0xc # Int 0x24: IRQ4
396 jmp int_hw # V86 int 0xc
397 push $0xd # Int 0x25: IRQ5
398 jmp int_hw # V86 int 0xd
399 push $0xe # Int 0x26: IRQ6
400 jmp int_hw # V86 int 0xe
401 push $0xf # Int 0x27: IRQ7
402 jmp int_hw # V86 int 0xf
403 push $0x70 # Int 0x28: IRQ8
404 jmp int_hw # V86 int 0x70
405 push $0x71 # Int 0x29: IRQ9
406 jmp int_hw # V86 int 0x71
407 push $0x72 # Int 0x2a: IRQ10
408 jmp int_hw # V86 int 0x72
409 push $0x73 # Int 0x2b: IRQ11
410 jmp int_hw # V86 int 0x73
411 push $0x74 # Int 0x2c: IRQ12
412 jmp int_hw # V86 int 0x74
413 push $0x75 # Int 0x2d: IRQ13
414 jmp int_hw # V86 int 0x75
415 push $0x76 # Int 0x2e: IRQ14
416 jmp int_hw # V86 int 0x76
417 push $0x77 # Int 0x2f: IRQ15
418 jmp int_hw # V86 int 0x77
421 * Invoke real mode interrupt/function call from user mode with arguments.
423 intx31: pushl $-1 # Dummy int no for btx_v86
425 * Invoke real mode interrupt/function call from protected mode.
427 * We place a trampoline on the user stack that will return to rret_tramp
428 * which will reenter protected mode and then finally return to the user
431 * Kernel frame %esi points to: Real mode stack frame at MEM_ESPR:
433 * -0x00 user %ss -0x04 kernel %esp (with full frame)
434 * -0x04 user %esp -0x08 btx_v86 pointer
435 * -0x08 user %eflags -0x0c flags (only used if interrupt)
436 * -0x0c user %cs -0x10 real mode CS:IP return trampoline
437 * -0x10 user %eip -0x12 real mode flags
438 * -0x14 int no -0x16 real mode CS:IP (target)
452 int_hw: cld # String ops inc
458 push $SEL_SDATA # Set up
462 leal 0x44(%esp,1),%esi # Base of frame
463 movl -0x14(%esi),%eax # Get Int no
464 cmpl $-1,%eax # Hardware interrupt?
467 * v86 calls save the btx_v86 pointer on the real mode stack and read the
468 * address and flags from the btx_v86 structure.
470 movl $MEM_USR,%ebx # User base
471 movl %ebx,%edx # address
472 addl -0x4(%esi),%ebx # User ESP
473 movl (%ebx),%ebp # btx_v86 pointer
474 addl %ebp,%edx # Flatten btx_v86 ptr
475 movl %edx,MEM_ESPR-0x08 # Save btx_v86 ptr
476 movl -0x08(%esi),%ebx # Pass user flags to
477 movw %bx,MEM_ESPR-0x12 # real mode target
478 movl V86_ADDR(%edx),%eax # Get int no/address
479 movl V86_CTL(%edx),%edx # Get control flags
480 jmp intusr.3 # Skip hardware interrupt
482 * Hardware interrupts store a NULL btx_v86 pointer and use the address
483 * (interrupt number) from the stack with empty flags. Also, we clear
484 * the segment registers for the interrupt handler and ensure interrupts
485 * are disabled when the interrupt handler is invoked.
487 intusr.2: xorl %edx,%edx # Control flags
488 movl %edx,MEM_ESPR-0x08 # NULL btx_v86 ptr
489 movl %edx,-0x38(%esi) # Real mode %gs of 0
490 movl %edx,-0x3c(%esi) # Real mode %fs of 0
491 movl %edx,-0x40(%esi) # Real mode %ds of 0
492 movl %edx,-0x44(%esi) # Real mode %es of 0
493 movl -0x08(%esi),%ebx # Pass user flags with
494 andl $~0x200,%ebx # interrupts disabled
495 movw %bx,MEM_ESPR-0x12 # to real mode target
497 * %eax now holds either the interrupt number or segment:offset of function.
498 * %edx now holds the V86F_* flags.
500 intusr.3: testl $V86F_ADDR,%edx # Segment:offset?
502 shll $0x2,%eax # Scale
503 movl (%eax),%eax # Load int vector
504 jmp intusr.5 # Skip CALLF test
505 intusr.4: testl $V86F_CALLF,%edx # Far call?
507 movl %edx,0x30(%esp,1) # Place VM86 flags in int no
508 movl $badvm86,%esi # Display bad
509 call putstr # VM86 call
514 popal # Restore gp regs
517 * If this is a v86 call, copy the seg regs out of the btx_v86 structure.
519 intusr.5: movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr
520 jecxz intusr.6 # Skip for hardware ints
521 leal -0x44(%esi),%edi # %edi => kernel stack seg regs
523 leal V86_ES(%ecx),%esi # %esi => btx_v86 seg regs
524 movl $4,%ecx # Copy seg regs
526 movsl # to kernel stack
528 intusr.6: movl %esp,MEM_ESPR-0x04 # Save kernel stack pointer
529 movl -0x08(%esi),%ebx # Copy user flags to real
530 movl %ebx,MEM_ESPR-0x0c # mode return trampoline
531 movl $rret_tramp,%ebx # Set return trampoline
532 movl %ebx,MEM_ESPR-0x10 # CS:IP
533 movl %eax,MEM_ESPR-0x16 # Real mode target CS:IP
534 ljmpw $SEL_RCODE,$intusr.7 # Change to 16-bit segment
536 intusr.7: movl %cr0,%eax # Leave
538 movl %eax,%cr0 # mode
540 intusr.8: xorw %ax,%ax # Reset %ds
543 lidt ivtdesc # Set IVT
548 popal # Restore gp regs
549 movw $MEM_ESPR-0x16,%sp # Switch to real mode stack
550 iret # Call target routine
552 * For the return to real mode we setup a stack frame like this on the real
553 * mode stack. Note that callf calls won't pop off the flags, but we just
554 * ignore that by repositioning %sp to be just above the btx_v86 pointer
555 * so it is aligned. The stack is relative to MEM_ESPR.
573 rret_tramp: movw $MEM_ESPR-0x08,%sp # Reset stack pointer
574 pushal # Save gp regs
579 pushfl # Save %eflags
580 cli # Disable interrupts
582 xorw %ax,%ax # Reset seg
584 movw %ax,%es # (%ss is already 0)
585 lidt idtdesc # Set IDT
586 lgdt gdtdesc # Set GDT
587 mov %cr0,%eax # Switch to protected
590 ljmp $SEL_SCODE,$rret_tramp.1 # To 32-bit code
592 rret_tramp.1: xorl %ecx,%ecx # Zero
593 movb $SEL_SDATA,%cl # Setup
594 movw %cx,%ss # 32-bit
597 movl MEM_ESPR-0x04,%esp # Switch to kernel stack
598 leal 0x44(%esp,1),%esi # Base of frame
599 andb $~0x2,tss_desc+0x5 # Clear TSS busy
600 movb $SEL_TSS,%cl # Set task
603 * Now we are back in protected mode. Copy the registers off of the real
604 * mode stack onto the kernel stack. Also, initialize all the seg regs on
607 * Note that the %esp in the kernel stack after this is garbage, but popa
608 * ignores it, so we don't have to fix it up.
610 leal -0x18(%esi),%edi # Kernel stack GP regs
612 movl $MEM_ESPR-0x0c,%esi # Real mode stack GP regs
613 movl $8,%ecx # Copy GP regs from
614 rep # real mode stack
615 movsl # to kernel stack
617 movl $SEL_UDATA,%eax # Selector for data seg regs
618 movl $4,%ecx # Initialize %ds,
622 * If this was a V86 call, copy the saved seg regs on the real mode stack
623 * back over to the btx_v86 structure. Also, conditionally update the saved
624 * eflags on the kernel stack based on the flags from the user.
626 movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr
627 jecxz rret_tramp.3 # Skip for hardware ints
628 leal V86_GS(%ecx),%edi # %edi => btx_v86 seg regs
630 leal MEM_ESPR-0x2c,%esi # %esi => real mode seg regs
631 xchgl %ecx,%edx # Save btx_v86 ptr
632 movl $4,%ecx # Copy seg regs
633 rep # from real mode stack
636 movl V86_CTL(%edx),%edx # Read V86 control flags
637 testl $V86F_FLAGS,%edx # User wants flags?
639 movl MEM_ESPR-0x3c,%eax # Read real mode flags
640 movw %ax,-0x08(%esi) # Update user flags (low 16)
642 * Return to the user task
644 rret_tramp.3: popl %es # Restore
648 popal # Restore gp regs
649 addl $4,%esp # Discard int no
650 iret # Return to user mode
655 intx30: cmpl $SYS_EXEC,%eax # Exec system call?
665 movl $MEM_USR,%eax # User base address
666 addl 0xc(%esp,1),%eax # Change to user
667 leal 0x4(%eax),%esp # stack
670 intx30.1: orb $0x1,%ss:btx_hdr+0x7 # Flag reboot
673 * Dump structure [EBX] to [EDI], using format string [ESI].
675 dump.0: stosb # Save char
676 dump: lodsb # Load char
677 testb %al,%al # End of string?
679 testb $0x80,%al # Control?
681 movb %al,%ch # Save control
682 movb $'=',%al # Append
687 addl %ebx,%esi # pointer
688 testb $DMP_X16,%ch # Dump word?
692 dump.1: testb $DMP_X32,%ch # Dump long?
696 dump.2: testb $DMP_MEM,%ch # Dump memory?
699 testb $0x2,0x52(%ebx) # V86 mode?
701 verr 0x4(%esi) # Readable selector?
703 ldsl (%esi),%esi # Load pointer
704 jmp dump.4 # Join common code
705 dump.3: lodsl # Set offset
706 xchgl %eax,%edx # Save
708 shll $0x4,%eax # * 0x10
709 addl %edx,%eax # + offset
710 xchgl %eax,%esi # Set pointer
711 dump.4: movb $2,%dl # Num lines
712 dump.4a: movb $0x10,%cl # Bytes to dump
713 dump.5: lodsb # Get byte and
715 decb %cl # Keep count
717 movb $'-',%al # Separator
718 cmpb $0x8,%cl # Half way?
720 movb $' ',%al # Use space
721 dump.6: stosb # Save separator
722 jmp dump.5 # Continue
723 dump.6a: decb %dl # Keep count
725 movb $0xa,%al # Line feed
727 movb $7,%cl # Leading
728 movb $' ',%al # spaces
729 dump.6b: stosb # Dump
732 jmp dump.4a # Next line
733 dump.7: popl %ds # Restore
734 dump.8: popl %esi # Restore
735 movb $0xa,%al # Line feed
736 testb $DMP_EOL,%ch # End of line?
738 movb $' ',%al # Use spaces
740 dump.9: jmp dump.0 # Continue
741 dump.10: stosb # Terminate string
744 * Convert EAX, AX, or AL to hex, saving the result to [EDI].
746 hex32: pushl %eax # Save
747 shrl $0x10,%eax # Do upper
750 hex16: call hex16.1 # Do upper 8
751 hex16.1: xchgb %ah,%al # Save/restore
752 hex8: pushl %eax # Save
753 shrb $0x4,%al # Do upper
756 hex8.1: andb $0xf,%al # Get lower 4
757 cmpb $0xa,%al # Convert
758 sbbb $0x69,%al # to hex
760 orb $0x20,%al # To lower case
764 * Output zero-terminated string [ESI] to the console.
766 putstr.0: call putchr # Output char
767 putstr: lodsb # Load char
768 testb %al,%al # End of string?
772 .set SIO_PRT,SIOPRT # Base port
773 .set SIO_FMT,SIOFMT # 8N1
774 .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD
777 * void sio_init(void)
779 sio_init: movw $SIO_PRT+0x3,%dx # Data format reg
780 movb $SIO_FMT|0x80,%al # Set format
781 outb %al,(%dx) # and DLAB
783 subb $0x3,%dl # Divisor latch reg
784 movw $SIO_DIV,%ax # Set
787 movb $SIO_FMT,%al # Clear
788 outb %al,(%dx) # DLAB
789 incl %edx # Modem control reg
790 movb $0x3,%al # Set RTS,
792 incl %edx # Line status reg
795 * void sio_flush(void)
797 sio_flush.0: call sio_getc.1 # Get character
798 sio_flush: call sio_ischar # Check for character
799 jnz sio_flush.0 # Till none
803 * void sio_putc(int c)
805 sio_putc: movw $SIO_PRT+0x5,%dx # Line status reg
806 xor %ecx,%ecx # Timeout
807 movb $0x40,%ch # counter
808 sio_putc.1: inb (%dx),%al # Transmitter
809 testb $0x20,%al # buffer empty?
810 loopz sio_putc.1 # No
811 jz sio_putc.2 # If timeout
812 movb 0x4(%esp,1),%al # Get character
813 subb $0x5,%dl # Transmitter hold reg
814 outb %al,(%dx) # Write character
815 sio_putc.2: ret $0x4 # To caller
820 sio_getc: call sio_ischar # Character available?
822 sio_getc.1: subb $0x5,%dl # Receiver buffer reg
823 inb (%dx),%al # Read character
827 * int sio_ischar(void)
829 sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register
830 xorl %eax,%eax # Zero
831 inb (%dx),%al # Received data
832 andb $0x1,%al # ready?
836 * Output character AL to the serial console.
839 cmpb $10, %al # is it a newline?
840 jne putchr.1 # no?, then leave
841 push $13 # output a carriage
842 call sio_putc # return first
843 movb $10, %al # restore %al
844 putchr.1: pushl %eax # Push the character
846 call sio_putc # Output the character
851 * Output character AL to the console.
854 xorl %ecx,%ecx # Zero for loops
855 movb $SCR_MAT,%ah # Mode/attribute
856 movl $BDA_POS,%ebx # BDA pointer
857 movw (%ebx),%dx # Cursor position
858 movl $0xb8000,%edi # Regen buffer (color)
859 cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode?
861 xorw %di,%di # Regen buffer (mono)
862 putchr.1: cmpb $0xa,%al # New line?
864 xchgl %eax,%ecx # Save char
865 movb $SCR_COL,%al # Columns per row
866 mulb %dh # * row position
867 addb %dl,%al # + column
868 adcb $0x0,%ah # position
870 xchgl %eax,%ecx # Swap char, offset
871 movw %ax,(%edi,%ecx,1) # Write attr:char
872 incl %edx # Bump cursor
873 cmpb $SCR_COL,%dl # Beyond row?
875 putchr.2: xorb %dl,%dl # Zero column
877 putchr.3: cmpb $SCR_ROW,%dh # Beyond screen?
879 leal 2*SCR_COL(%edi),%esi # New top line
880 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
883 movb $0x20,%al # Space
884 movb $SCR_COL,%cl # Columns to clear
887 movb $SCR_ROW-1,%dh # Bottom line
888 putchr.4: movw %dx,(%ebx) # Update position
895 * Real Mode Hardware interrupt jump table.
897 intr20: push $0x8 # Int 0x20: IRQ0
898 jmp int_hwr # V86 int 0x8
899 push $0x9 # Int 0x21: IRQ1
900 jmp int_hwr # V86 int 0x9
901 push $0xa # Int 0x22: IRQ2
902 jmp int_hwr # V86 int 0xa
903 push $0xb # Int 0x23: IRQ3
904 jmp int_hwr # V86 int 0xb
905 push $0xc # Int 0x24: IRQ4
906 jmp int_hwr # V86 int 0xc
907 push $0xd # Int 0x25: IRQ5
908 jmp int_hwr # V86 int 0xd
909 push $0xe # Int 0x26: IRQ6
910 jmp int_hwr # V86 int 0xe
911 push $0xf # Int 0x27: IRQ7
912 jmp int_hwr # V86 int 0xf
913 push $0x70 # Int 0x28: IRQ8
914 jmp int_hwr # V86 int 0x70
915 push $0x71 # Int 0x29: IRQ9
916 jmp int_hwr # V86 int 0x71
917 push $0x72 # Int 0x2a: IRQ10
918 jmp int_hwr # V86 int 0x72
919 push $0x73 # Int 0x2b: IRQ11
920 jmp int_hwr # V86 int 0x73
921 push $0x74 # Int 0x2c: IRQ12
922 jmp int_hwr # V86 int 0x74
923 push $0x75 # Int 0x2d: IRQ13
924 jmp int_hwr # V86 int 0x75
925 push $0x76 # Int 0x2e: IRQ14
926 jmp int_hwr # V86 int 0x76
927 push $0x77 # Int 0x2f: IRQ15
928 jmp int_hwr # V86 int 0x77
930 * Reflect hardware interrupts in real mode.
932 int_hwr: push %ax # Save
935 mov %sp,%bp # Address stack frame
936 xchg %bx,6(%bp) # Swap BX, int no
937 xor %ax,%ax # Set %ds:%bx to
938 shl $2,%bx # point to
939 mov %ax,%ds # IDT entry
940 mov (%bx),%ax # Load IP
941 mov 2(%bx),%bx # Load CS
942 xchg %ax,4(%bp) # Swap saved %ax,%bx with
943 xchg %bx,6(%bp) # CS:IP of handler
946 lret # Jump to handler
950 * Global descriptor table.
952 gdt: .word 0x0,0x0,0x0,0x0 # Null entry
953 .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
954 .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
955 .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
956 .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
957 .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
958 .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
959 tss_desc: .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
962 * Pseudo-descriptors.
964 gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT
965 idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT
966 ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT
968 * IDT construction control string.
970 idtctl: .byte 0x10, 0x8e # Int 0x0-0xf
971 .word 0x7dfb,intx00 # (exceptions)
972 .byte 0x10, 0x8e # Int 0x10
973 .word 0x1, intx10 # (exception)
974 .byte 0x10, 0x8e # Int 0x20-0x2f
975 .word 0xffff,intx20 # (hardware)
976 .byte 0x1, 0xee # int 0x30
977 .word 0x1, intx30 # (system call)
978 .byte 0x2, 0xee # Int 0x31-0x32
979 .word 0x1, intx31 # (V86, null)
980 .byte 0x0 # End of string
982 * Dump format string.
984 dmpfmt: .byte '\n' # "\n"
985 .ascii "int" # "int="
986 .byte 0x80|DMP_X32, 0x40 # "00000000 "
987 .ascii "err" # "err="
988 .byte 0x80|DMP_X32, 0x44 # "00000000 "
989 .ascii "efl" # "efl="
990 .byte 0x80|DMP_X32, 0x50 # "00000000 "
991 .ascii "eip" # "eip="
992 .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
993 .ascii "eax" # "eax="
994 .byte 0x80|DMP_X32, 0x34 # "00000000 "
995 .ascii "ebx" # "ebx="
996 .byte 0x80|DMP_X32, 0x28 # "00000000 "
997 .ascii "ecx" # "ecx="
998 .byte 0x80|DMP_X32, 0x30 # "00000000 "
999 .ascii "edx" # "edx="
1000 .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
1001 .ascii "esi" # "esi="
1002 .byte 0x80|DMP_X32, 0x1c # "00000000 "
1003 .ascii "edi" # "edi="
1004 .byte 0x80|DMP_X32, 0x18 # "00000000 "
1005 .ascii "ebp" # "ebp="
1006 .byte 0x80|DMP_X32, 0x20 # "00000000 "
1007 .ascii "esp" # "esp="
1008 .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n"
1010 .byte 0x80|DMP_X16, 0x4c # "0000 "
1012 .byte 0x80|DMP_X16, 0xc # "0000 "
1014 .byte 0x80|DMP_X16, 0x8 # "0000 "
1017 .byte 0x80|DMP_X16, 0x10 # "0000 "
1019 .byte 0x80|DMP_X16, 0x14 # "0000 "
1021 .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n"
1022 .ascii "cs:eip" # "cs:eip="
1023 .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
1024 .ascii "ss:esp" # "ss:esp="
1025 .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n"
1026 .asciz "BTX halted\n" # End
1028 * Bad VM86 call panic
1030 badvm86: .asciz "Invalid VM86 Request\n"
1033 * End of BTX memory.