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