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