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