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