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