]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/boot/i386/btx/btx/btx.s
This commit was generated by cvs2svn to compensate for changes in r50894,
[FreeBSD/FreeBSD.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$
17
18 #
19 # Memory layout.
20 #
21                 .set MEM_BTX,0x1000             # Start of BTX memory
22                 .set MEM_ESP0,0x1800            # Supervisor stack
23                 .set MEM_BUF,0x1800             # Scratch buffer
24                 .set MEM_ESP1,0x1e00            # Link stack
25                 .set MEM_IDT,0x1e00             # IDT
26                 .set MEM_TSS,0x1f98             # TSS
27                 .set MEM_MAP,0x2000             # I/O bit map
28                 .set MEM_DIR,0x4000             # Page directory
29                 .set MEM_TBL,0x5000             # Page tables
30                 .set MEM_ORG,0x9000             # BTX code
31                 .set MEM_USR,0xa000             # Start of user memory
32 #
33 # Paging control.
34 #
35                 .set PAG_SIZ,0x1000             # Page size
36                 .set PAG_CNT,0x1000             # Pages to map
37 #
38 # Segment selectors.
39 #
40                 .set SEL_SCODE,0x8              # Supervisor code
41                 .set SEL_SDATA,0x10             # Supervisor data
42                 .set SEL_RCODE,0x18             # Real mode code
43                 .set SEL_RDATA,0x20             # Real mode data
44                 .set SEL_UCODE,0x28|3           # User code
45                 .set SEL_UDATA,0x30|3           # User data
46                 .set SEL_TSS,0x38               # TSS
47 #
48 # Task state segment fields.
49 #
50                 .set TSS_ESP0,0x4               # PL 0 ESP
51                 .set TSS_SS0,0x8                # PL 0 SS
52                 .set TSS_ESP1,0xc               # PL 1 ESP
53                 .set TSS_MAP,0x66               # I/O bit map base
54 #
55 # System calls.
56 #
57                 .set SYS_EXIT,0x0               # Exit
58                 .set SYS_EXEC,0x1               # Exec
59 #
60 # V86 constants.
61 #
62                 .set V86_FLG,0x208eff           # V86 flag mask
63                 .set V86_STK,0x400              # V86 stack allowance
64 #
65 # Dump format control bytes.
66 #
67                 .set DMP_X16,0x1                # Word
68                 .set DMP_X32,0x2                # Long
69                 .set DMP_MEM,0x4                # Memory
70                 .set DMP_EOL,0x8                # End of line
71 #
72 # Screen defaults and assumptions.
73 #
74                 .set SCR_MAT,0x7                # Mode/attribute
75                 .set SCR_COL,0x50               # Columns per row
76                 .set SCR_ROW,0x19               # Rows per screen
77 #
78 # BIOS Data Area locations.
79 #
80                 .set BDA_MEM,0x413              # Free memory
81                 .set BDA_SCR,0x449              # Video mode
82                 .set BDA_POS,0x450              # Cursor position
83 #
84 # Derivations, for brevity.
85 #
86                 .set _ESP0H,MEM_ESP0>>0x8       # Byte 1 of ESP0
87                 .set _ESP1H,MEM_ESP1>>0x8       # Byte 1 of ESP1
88                 .set _TSSIO,MEM_MAP-MEM_TSS     # TSS I/O base
89                 .set _TSSLM,MEM_DIR-MEM_TSS-1   # TSS limit
90                 .set _IDTLM,MEM_TSS-MEM_IDT-1   # IDT limit
91 #
92 # Code segment.
93 #
94                 .globl start
95 start:                                          # Start of code
96 #
97 # BTX header.
98 #
99 btx_hdr:        .byte 0xeb                      # Machine ID
100                 .byte 0xe                       # Header size
101                 .ascii "BTX"                    # Magic
102                 .byte 0x1                       # Major version
103                 .byte 0x1                       # Minor version
104                 .byte 0x0                       # Flags
105                 .word PAG_CNT-MEM_ORG>>0xc      # Paging control
106                 .word break-start               # Text size
107                 .long 0x0                       # Entry address
108 #
109 # Initialization routine.
110 #
111 init:           cli                             # Disable interrupts
112                 xorl %eax,%eax                  # Zero/segment
113                 movl %ax,%ss                    # Set up
114                 movwir(MEM_ESP0,_sp)            #  stack
115                 movl %ax,%es                    # Address
116                 movl %ax,%ds                    #  data
117                 pushw $0x2                      # Clear
118                 popfw                           #  flags
119 #
120 # Initialize memory.
121 #
122                 movwir(MEM_IDT,_di)             # Memory to initialize
123                 movwir((MEM_ORG-MEM_IDT)/2,_cx) # Words to zero
124                 pushl %edi                      # Save
125                 rep                             # Zero-fill
126                 stosl                           #  memory
127                 popl %edi                       # Restore
128 #
129 # Create IDT.
130 #
131                 movwir(idtctl,_si)              # Control string
132 init.1:         lodsb                           # Get entry
133                 cwde                            #  count
134                 xchgl %eax,%ecx                 #  as word
135                 jecxz init.4                    # If done
136                 lodsb                           # Get segment
137                 xchgl %eax,%edx                 #  P:DPL:type
138                 lodsl                           # Get control
139                 xchgl %eax,%ebx                 #  set
140                 lodsl                           # Get handler offset
141                 movb $SEL_SCODE,%dh             # Segment selector
142 init.2:         shrl %ebx                       # Handle this int?
143                 jnc init.3                      # No
144                 movwr0(_ax,_di_)                # Set handler offset
145                 movbr1(_dh,0x2,_di_)            #  and selector
146                 movbr1(_dl,0x5,_di_)            # Set P:DPL:type
147                 addwia(0x4)                     # Next handler
148 init.3:         leaw1r(0x8,_di_,_di)            # Next entry
149                 loop init.2                     # Till set done
150                 jmp init.1                      # Continue
151 #
152 # Initialize TSS.
153 #
154 init.4:         movbi1(_ESP0H,TSS_ESP0+1,_di_)  # Set ESP0
155                 movbi1(SEL_SDATA,TSS_SS0,_di_)  # Set SS0
156                 movbi1(_ESP1H,TSS_ESP1+1,_di_)  # Set ESP1
157                 movbi1(_TSSIO,TSS_MAP,_di_)     # Set I/O bit map base
158 #
159 # Create page directory.
160 #
161                 xorw %dx,%dx                    # Page
162                 movb $PAG_SIZ>>0x8,%dh          #  size
163                 xorw %ax,%ax                    # Zero
164                 movwir(MEM_DIR,_di)             # Page directory
165                 movb $PAG_CNT>>0xa,%cl          # Entries
166                 movwir(MEM_TBL|0x7,_ax)         # First entry
167 init.5:         stosw                           # Write entry
168                 addl %edx,%eax                  # To next
169                 loop init.5                     # Till done
170 #
171 # Create page tables.
172 #
173                 movwir(MEM_TBL,_di)             # Page table
174                 movb $PAG_CNT>>0x8,%ch          # Entries
175                 xorl %eax,%eax                  # Start address
176 init.6:         movb $0x7,%al                   # Set U:W:P flags
177                 cmpwmr(btx_hdr+0x8,_cx)         # Standard user page?
178                 jb init.7                       # Yes
179                 cmpwir(PAG_CNT-MEM_BTX>>0xc,_cx)# BTX memory?
180                 jae init.7                      # No or first page
181                 andb $~0x2,%al                  # Clear W flag
182                 cmpwir(PAG_CNT-MEM_USR>>0xc,_cx)# User page zero?
183                 jne init.7                      # No
184                 tstbim(0x80,btx_hdr+0x7)        # Unmap it?
185                 jz init.7                       # No
186                 andb $~0x1,%al                  # Clear P flag
187 init.7:         stosw                           # Set entry
188                 addw %dx,%ax                    # Next address
189                 loop init.6                     # Till done
190 #
191 # Bring up the system.
192 #
193                 movwir(0x2820,_bx)              # Set protected mode
194                 callwi(setpic)                  #  IRQ offsets
195                 lidtwm(idtdesc)                 # Set IDT
196                 xorw %ax,%ax                    # Set base
197                 movb $MEM_DIR>>0x8,%ah          #  of page
198                 movl %eax,%cr3                  #  directory
199                 lgdtwm(gdtdesc)                 # Set GDT
200                 movl %cr0,%eax                  # Switch to
201                 o16                             #  protected mode
202                 orl $0x80000001,%eax            #  and enable
203                 movl %eax,%cr0                  #  paging
204                 jmpfwi(SEL_SCODE,init.8)        # To 32-bit code
205 init.8:         xorl %ecx,%ecx                  # Zero
206                 movb $SEL_SDATA,%cl             # To 32-bit
207                 movl %cx,%ss                    #  stack
208 #
209 # Launch user task.
210 #
211                 movb $SEL_TSS,%cl               # Set task
212                 ltrl %ecx                       #  register
213                 movl $MEM_USR,%edx              # User base address
214                 movzwl %ss:BDA_MEM,%eax         # Get free memory
215                 shll $0xa,%eax                  # To bytes
216                 subl $0x1000,%eax               # Less arg space
217                 subl %edx,%eax                  # Less base
218                 movb $SEL_UDATA,%cl             # User data selector
219                 pushl %ecx                      # Set SS
220                 pushl %eax                      # Set ESP
221                 pushl $0x202                    # Set flags (IF set)
222                 pushl $SEL_UCODE                # Set CS
223                 pushl btx_hdr+0xc               # Set EIP
224                 pushl %ecx                      # Set GS
225                 pushl %ecx                      # Set FS
226                 pushl %ecx                      # Set DS
227                 pushl %ecx                      # Set ES
228                 pushl %edx                      # Set EAX
229                 movb $0x7,%cl                   # Set remaining
230 init.9:         pushb $0x0                      #  general
231                 loop init.9                     #  registers
232                 popa                            #  and initialize
233                 popl %es                        # Initialize
234                 popl %ds                        #  user
235                 popl %fs                        #  segment
236                 popl %gs                        #  registers
237                 iret                            # To user mode
238 #
239 # Exit routine.
240 #
241 exit:           cli                             # Disable interrupts
242                 movl $MEM_ESP0,%esp             # Clear stack
243 #
244 # Turn off paging.
245 #
246                 movl %cr0,%eax                  # Get CR0
247                 andl $~0x80000000,%eax          # Disable
248                 movl %eax,%cr0                  #  paging
249                 xorl %ecx,%ecx                  # Zero
250                 movl %ecx,%cr3                  # Flush TLB
251 #
252 # To 16 bits.
253 #
254                 o16                             # Reload
255                 jmpfwi(SEL_RCODE,exit.1)        #  CS
256 exit.1:         movb $SEL_RDATA,%cl             # 16-bit selector
257                 movl %cx,%ss                    # Reload SS
258                 movl %cx,%ds                    # Load
259                 movl %cx,%es                    #  remaining
260                 movl %cx,%fs                    #  segment
261                 movl %cx,%gs                    #  registers
262 #
263 # To real-address mode.
264 #
265                 decl %eax                       # Switch to
266                 movl %eax,%cr0                  #  real mode
267                 jmpfwi(0x0,exit.2)              # Reload CS
268 exit.2:         xorl %eax,%eax                  # Real mode segment
269                 movl %ax,%ss                    # Reload SS
270                 movl %ax,%ds                    # Address data
271                 movwir(0x7008,_bx)              # Set real mode
272                 callwi(setpic)                  #  IRQ offsets
273                 lidtwm(ivtdesc)                 # Set IVT
274 #
275 # Reboot or await reset.
276 #
277                 sti                             # Enable interrupts
278                 tstbim(0x1,btx_hdr+0x7)         # Reboot?
279 exit.3:         jz exit.3                       # No
280                 int $0x19                       # BIOS: Reboot
281 #
282 # Set IRQ offsets by reprogramming 8259A PICs.
283 #
284 setpic:         inb $0x21,%al                   # Save master
285                 pushl %eax                      #  IMR
286                 inb $0xa1,%al                   # Save slave
287                 pushl %eax                      #  IMR
288                 movb $0x11,%al                  # ICW1 to
289                 outb %al,$0x20                  #  master,
290                 outb %al,$0xa0                  #  slave
291                 movb %bl,%al                    # ICW2 to
292                 outb %al,$0x21                  #  master
293                 movb %bh,%al                    # ICW2 to
294                 outb %al,$0xa1                  #  slave
295                 movb $0x4,%al                   # ICW3 to
296                 outb %al,$0x21                  #  master
297                 movb $0x2,%al                   # ICW3 to
298                 outb %al,$0xa1                  #  slave
299                 movb $0x1,%al                   # ICW4 to
300                 outb %al,$0x21                  #  master,
301                 outb %al,$0xa1                  #  slave
302                 popl %eax                       # Restore slave
303                 outb %al,$0xa1                  #  IMR
304                 popl %eax                       # Restore master
305                 outb %al,$0x21                  #  IMR
306                 ret                             # To caller
307 #
308 # Initiate return from V86 mode to user mode.
309 #
310 inthlt:         hlt                             # To supervisor mode
311 #
312 # Exception jump table.
313 #
314 intx00:         pushb $0x0                      # Int 0x0: #DE
315                 jmp ex_noc                      # Divide error
316                 pushb $0x1                      # Int 0x1: #DB
317                 jmp ex_noc                      # Debug
318                 pushb $0x3                      # Int 0x3: #BP
319                 jmp ex_noc                      # Breakpoint
320                 pushb $0x4                      # Int 0x4: #OF
321                 jmp ex_noc                      # Overflow
322                 pushb $0x5                      # Int 0x5: #BR
323                 jmp ex_noc                      # BOUND range exceeded
324                 pushb $0x6                      # Int 0x6: #UD
325                 jmp ex_noc                      # Invalid opcode
326                 pushb $0x7                      # Int 0x7: #NM
327                 jmp ex_noc                      # Device not available
328                 pushb $0x8                      # Int 0x8: #DF
329                 jmp except                      # Double fault
330                 pushb $0xa                      # Int 0xa: #TS
331                 jmp except                      # Invalid TSS
332                 pushb $0xb                      # Int 0xb: #NP
333                 jmp except                      # Segment not present
334                 pushb $0xc                      # Int 0xc: #SS
335                 jmp except                      # Stack segment fault
336                 pushb $0xd                      # Int 0xd: #GP
337                 jmp ex_v86                      # General protection
338                 pushb $0xe                      # Int 0xe: #PF
339                 jmp except                      # Page fault
340 intx10:         pushb $0x10                     # Int 0x10: #MF
341                 jmp ex_noc                      # Floating-point error
342 #
343 # Handle #GP exception.
344 #
345 ex_v86:         testb $0x2,0x12(%esp,1)         # V86 mode?
346                 jz except                       # No
347                 jmp v86mon                      # To monitor
348 #
349 # Save a zero error code.
350 #
351 ex_noc:         pushl (%esp,1)                  # Duplicate int no
352                 movb $0x0,0x4(%esp,1)           # Fake error code
353 #
354 # Handle exception.
355 #
356 except:         cld                             # String ops inc
357                 pushl %ds                       # Save
358                 pushl %es                       #  most
359                 pusha                           #  registers
360                 movb $0x6,%al                   # Push loop count
361                 testb $0x2,0x3a(%esp,1)         # V86 mode?
362                 jnz except.1                    # Yes
363                 pushl %gs                       # Set GS
364                 pushl %fs                       # Set FS
365                 pushl %ds                       # Set DS
366                 pushl %es                       # Set ES
367                 movb $0x2,%al                   # Push loop count
368                 cmpw $SEL_SCODE,0x44(%esp,1)    # Supervisor mode?
369                 jne except.1                    # No
370                 pushl %ss                       # Set SS
371                 leal 0x50(%esp,1),%eax          # Set
372                 pushl %eax                      #  ESP
373                 jmp except.2                    # Join common code
374 except.1:       pushl 0x50(%esp,1)              # Set GS, FS, DS, ES
375                 decb %al                        #  (if V86 mode), and
376                 jne except.1                    #  SS, ESP
377 except.2:       pushl $SEL_SDATA                # Set up
378                 popl %ds                        #  to
379                 pushl %ds                       #  address
380                 popl %es                        #  data
381                 movl %esp,%ebx                  # Stack frame
382                 movl $dmpfmt,%esi               # Dump format string
383                 movl $MEM_BUF,%edi              # Buffer
384                 pushl %edi                      # Dump to
385                 call dump                       #  buffer
386                 popl %esi                       #  and
387                 call putstr                     #  display
388                 leal 0x18(%esp,1),%esp          # Discard frame
389                 popa                            # Restore
390                 popl %es                        #  registers
391                 popl %ds                        #  saved
392                 cmpb $0x3,(%esp,1)              # Breakpoint?
393                 je except.3                     # Yes
394                 jmp exit                        # Exit
395 except.3:       leal 0x8(%esp,1),%esp           # Discard err, int no
396                 iret                            # From interrupt
397 #
398 # Return to user mode from V86 mode.
399 #
400 intrtn:         cld                             # String ops inc
401                 pushl %ds                       # Address
402                 popl %es                        #  data
403                 leal 0x3c(%ebp),%edx            # V86 Segment registers
404                 movl MEM_TSS+TSS_ESP1,%esi      # Link stack pointer
405                 lodsl                           # INT_V86 args pointer
406                 movl %esi,%ebx                  # Saved exception frame
407                 testl %eax,%eax                 # INT_V86 args?
408                 jz intrtn.2                     # No
409                 movl $MEM_USR,%edi              # User base
410                 movl 0x1c(%esi),%ebx            # User ESP
411                 movl %eax,(%edi,%ebx,1)         # Restore to user stack
412                 leal 0x8(%edi,%eax,1),%edi      # Arg segment registers
413                 testb $0x4,-0x6(%edi)           # Return flags?
414                 jz intrtn.1                     # No
415                 movl 0x30(%ebp),%eax            # Get V86 flags
416                 movw %ax,0x18(%esi)             # Set user flags
417 intrtn.1:       leal 0x10(%esi),%ebx            # Saved exception frame
418                 xchgl %edx,%esi                 # Segment registers
419                 movb $0x4,%cl                   # Update seg regs
420                 rep                             #  in INT_V86
421                 movsl                           #  args
422 intrtn.2:       movl %edx,%esi                  # Segment registers
423                 leal 0x28(%ebp),%edi            # Set up seg
424                 movb $0x4,%cl                   #  regs for
425                 rep                             #  later
426                 movsl                           #  pop
427                 movl %ebx,%esi                  # Restore exception
428                 movb $0x5,%cl                   #  frame to
429                 rep                             #  supervisor
430                 movsl                           #  stack
431                 movl %esi,MEM_TSS+TSS_ESP1      # Link stack pointer
432                 popa                            # Restore
433                 leal 0x8(%esp,1),%esp           # Discard err, int no
434                 popl %es                        # Restore
435                 popl %ds                        #  user
436                 popl %fs                        #  segment
437                 popl %gs                        #  registers
438                 iret                            # To user mode
439 #
440 # V86 monitor.
441 #
442 v86mon:         cld                             # String ops inc
443                 pushl $SEL_SDATA                # Set up for
444                 popl %ds                        #  flat addressing
445                 pusha                           # Save registers
446                 movl %esp,%ebp                  # Address stack frame
447                 movzwl 0x2c(%ebp),%edi          # Load V86 CS
448                 shll $0x4,%edi                  # To linear
449                 movl 0x28(%ebp),%esi            # Load V86 IP
450                 addl %edi,%esi                  # Code pointer
451                 xorl %ecx,%ecx                  # Zero
452                 movb $0x2,%cl                   # 16-bit operands
453                 xorl %eax,%eax                  # Zero
454 v86mon.1:       lodsb                           # Get opcode
455                 cmpb $0x66,%al                  # Operand size prefix?
456                 jne v86mon.2                    # No
457                 movb $0x4,%cl                   # 32-bit operands
458                 jmp v86mon.1                    # Continue
459 v86mon.2:       cmpb $0xf4,%al                  # HLT?
460                 jne v86mon.3                    # No
461                 cmpl $inthlt+0x1,%esi           # Is inthlt?
462                 jne v86mon.7                    # No (ignore)
463                 jmp intrtn                      # Return to user mode
464 v86mon.3:       cmpb $0xf,%al                   # Is
465                 jne v86mon.4                    #  this
466                 cmpb $0x20,(%esi)               #  a
467                 jne v86mon.4                    #  MOV EAX,CR0
468                 cmpb $0xc0,0x1(%esi)            #  instruction?
469                 je v86mov                       # Yes
470 v86mon.4:       cmpb $0xfa,%al                  # CLI?
471                 je v86cli                       # Yes
472                 cmpb $0xfb,%al                  # STI?
473                 je v86sti                       # Yes
474                 movzwl 0x38(%ebp),%ebx          # Load V86 SS
475                 shll $0x4,%ebx                  # To offset
476                 pushl %ebx                      # Save
477                 addl 0x34(%ebp),%ebx            # Add V86 SP
478                 movl 0x30(%ebp),%edx            # Load V86 flags
479                 cmpb $0x9c,%al                  # PUSHF/PUSHFD?
480                 je v86pushf                     # Yes
481                 cmpb $0x9d,%al                  # POPF/POPFD?
482                 je v86popf                      # Yes
483                 cmpb $0xcd,%al                  # INT imm8?
484                 je v86intn                      # Yes
485                 cmpb $0xcf,%al                  # IRET/IRETD?
486                 je v86iret                      # Yes
487                 popl %ebx                       # Restore
488                 popa                            # Restore
489                 jmp except                      # Handle exception
490 v86mon.5:       movl %edx,0x30(%ebp)            # Save V86 flags
491 v86mon.6:       popl %edx                       # V86 SS adjustment
492                 subl %edx,%ebx                  # Save V86
493                 movl %ebx,0x34(%ebp)            #  SP
494 v86mon.7:       subl %edi,%esi                  # From linear
495                 movl %esi,0x28(%ebp)            # Save V86 IP
496                 popa                            # Restore
497                 leal 0x8(%esp,1),%esp           # Discard int no, error
498                 iret                            # To V86 mode
499 #
500 # Emulate MOV EAX,CR0.
501 #
502 v86mov:         movl %cr0,%eax                  # CR0 to
503                 movl %eax,0x1c(%ebp)            #  saved EAX
504                 incl %esi                       # Adjust
505                 incl %esi                       #  IP
506                 jmp v86mon.7                    # Finish up
507 #
508 # Emulate CLI.
509 #
510 v86cli:         andb $~0x2,0x31(%ebp)           # Clear IF
511                 jmp v86mon.7                    # Finish up
512 #
513 # Emulate STI.
514 #
515 v86sti:         orb $0x2,0x31(%ebp)             # Set IF
516                 jmp v86mon.7                    # Finish up
517 #
518 # Emulate PUSHF/PUSHFD.
519 #
520 v86pushf:       subl %ecx,%ebx                  # Adjust SP
521                 cmpb $0x4,%cl                   # 32-bit
522                 je v86pushf.1                   # Yes
523                 o16                             # 16-bit
524 v86pushf.1:     movl %edx,(%ebx)                # Save flags
525                 jmp v86mon.6                    # Finish up
526 #
527 # Emulate IRET/IRETD.
528 #
529 v86iret:        movzwl (%ebx),%esi              # Load V86 IP
530                 movzwl 0x2(%ebx),%edi           # Load V86 CS
531                 leal 0x4(%ebx),%ebx             # Adjust SP
532                 movl %edi,0x2c(%ebp)            # Save V86 CS
533                 xorl %edi,%edi                  # No ESI adjustment
534 #
535 # Emulate POPF/POPFD (and remainder of IRET/IRETD).
536 #
537 v86popf:        cmpb $0x4,%cl                   # 32-bit?
538                 je v86popf.1                    # Yes
539                 movl %edx,%eax                  # Initialize
540                 o16                             # 16-bit
541 v86popf.1:      movl (%ebx),%eax                # Load flags
542                 addl %ecx,%ebx                  # Adjust SP
543                 andl $V86_FLG,%eax              # Merge
544                 andl $~V86_FLG,%edx             #  the
545                 orl %eax,%edx                   #  flags
546                 jmp v86mon.5                    # Finish up
547 #
548 # Emulate INT imm8.
549 #
550 v86intn:        lodsb                           # Get int no
551                 subl %edi,%esi                  # From
552                 shrl $0x4,%edi                  #  linear
553                 movw %dx,-0x2(%ebx)             # Save flags
554                 movw %di,-0x4(%ebx)             # Save CS
555                 leal -0x6(%ebx),%ebx            # Adjust SP
556                 movw %si,(%ebx)                 # Save IP
557                 shll $0x2,%eax                  # Scale
558                 movzwl (%eax),%esi              # Load IP
559                 movzwl 0x2(%eax),%edi           # Load CS
560                 movl %edi,0x2c(%ebp)            # Save CS
561                 xorl %edi,%edi                  # No ESI adjustment
562                 andb $~0x3,%dh                  # Clear IF and TF
563                 jmp v86mon.5                    # Finish up
564 #
565 # Hardware interrupt jump table.
566 #
567 intx20:         pushb $0x8                      # Int 0x20: IRQ0
568                 jmp int_hw                      # V86 int 0x8
569                 pushb $0x9                      # Int 0x21: IRQ1
570                 jmp int_hw                      # V86 int 0x9
571                 pushb $0xa                      # Int 0x22: IRQ2
572                 jmp int_hw                      # V86 int 0xa
573                 pushb $0xb                      # Int 0x23: IRQ3
574                 jmp int_hw                      # V86 int 0xb
575                 pushb $0xc                      # Int 0x24: IRQ4
576                 jmp int_hw                      # V86 int 0xc
577                 pushb $0xd                      # Int 0x25: IRQ5
578                 jmp int_hw                      # V86 int 0xd
579                 pushb $0xe                      # Int 0x26: IRQ6
580                 jmp int_hw                      # V86 int 0xe
581                 pushb $0xf                      # Int 0x27: IRQ7
582                 jmp int_hw                      # V86 int 0xf
583                 pushb $0x70                     # Int 0x28: IRQ8
584                 jmp int_hw                      # V86 int 0x70
585                 pushb $0x71                     # Int 0x29: IRQ9
586                 jmp int_hw                      # V86 int 0x71
587                 pushb $0x72                     # Int 0x2a: IRQ10
588                 jmp int_hw                      # V86 int 0x72
589                 pushb $0x73                     # Int 0x2b: IRQ11
590                 jmp int_hw                      # V86 int 0x73
591                 pushb $0x74                     # Int 0x2c: IRQ12
592                 jmp int_hw                      # V86 int 0x74
593                 pushb $0x75                     # Int 0x2d: IRQ13
594                 jmp int_hw                      # V86 int 0x75
595                 pushb $0x76                     # Int 0x2e: IRQ14
596                 jmp int_hw                      # V86 int 0x76
597                 pushb $0x77                     # Int 0x2f: IRQ15
598                 jmp int_hw                      # V86 int 0x77
599 #
600 # Reflect hardware interrupts.
601 #
602 int_hw:         testb $0x2,0xe(%esp,1)          # V86 mode?
603                 jz intusr                       # No
604                 pushl $SEL_SDATA                # Address
605                 popl %ds                        #  data
606                 xchgl %eax,(%esp,1)             # Swap EAX, int no
607                 pushl %ebp                      # Address
608                 movl %esp,%ebp                  #  stack frame
609                 pushl %ebx                      # Save
610                 shll $0x2,%eax                  # Get int
611                 movl (%eax),%eax                #  vector
612                 subl $0x6,0x14(%ebp)            # Adjust V86 ESP
613                 movzwl 0x18(%ebp),%ebx          # V86 SS
614                 shll $0x4,%ebx                  #  * 0x10
615                 addl 0x14(%ebp),%ebx            #  + V86 ESP
616                 xchgw %ax,0x8(%ebp)             # Swap V86 IP
617                 rorl $0x10,%eax                 # Swap words
618                 xchgw %ax,0xc(%ebp)             # Swap V86 CS
619                 roll $0x10,%eax                 # Swap words
620                 movl %eax,(%ebx)                # CS:IP for IRET
621                 movl 0x10(%ebp),%eax            # V86 flags
622                 movw %ax,0x4(%ebx)              # Flags for IRET
623                 andb $~0x3,0x11(%ebp)           # Clear IF, TF
624                 popl %ebx                       # Restore
625                 popl %ebp                       #  saved
626                 popl %eax                       #  registers
627                 iret                            # To V86 mode
628 #
629 # Invoke V86 interrupt from user mode, with arguments.
630 #
631 intx31:         stc                             # Have btx_v86
632                 pushl %eax                      # Missing int no
633 #
634 # Invoke V86 interrupt from user mode.
635 #
636 intusr:         std                             # String ops dec
637                 pushl %eax                      # Expand
638                 pushl %eax                      #  stack
639                 pushl %eax                      #  frame
640                 pusha                           # Save
641                 pushl %gs                       # Save
642                 movl %esp,%eax                  #  seg regs
643                 pushl %fs                       #  and
644                 pushl %ds                       #  point
645                 pushl %es                       #  to them
646                 pushb $SEL_SDATA                # Set up
647                 popl %ds                        #  to
648                 pushl %ds                       #  address
649                 popl %es                        #  data
650                 movl $MEM_USR,%ebx              # User base
651                 movl %ebx,%edx                  #  address
652                 jc intusr.1                     # If btx_v86
653                 xorl %edx,%edx                  # Control flags
654                 xorl %ebp,%ebp                  # btx_v86 pointer
655 intusr.1:       leal 0x50(%esp,1),%esi          # Base of frame
656                 pushl %esi                      # Save
657                 addl -0x4(%esi),%ebx            # User ESP
658                 movl MEM_TSS+TSS_ESP1,%edi      # Link stack pointer
659                 leal -0x4(%edi),%edi            # Adjust for push
660                 xorl %ecx,%ecx                  # Zero
661                 movb $0x5,%cl                   # Push exception
662                 rep                             #  frame on
663                 movsl                           #  link stack
664                 xchgl %eax,%esi                 # Saved seg regs
665                 movl 0x40(%esp,1),%eax          # Get int no
666                 testl %edx,%edx                 # Have btx_v86?
667                 jz intusr.2                     # No
668                 movl (%ebx),%ebp                # btx_v86 pointer
669                 movb $0x4,%cl                   # Count
670                 addl %ecx,%ebx                  # Adjust for pop
671                 rep                             # Push saved seg regs
672                 movsl                           #  on link stack
673                 addl %ebp,%edx                  # Flatten btx_v86 ptr
674                 leal 0x14(%edx),%esi            # Seg regs pointer
675                 movl 0x4(%edx),%eax             # Get int no/address
676                 movzwl 0x2(%edx),%edx           # Get control flags
677 intusr.2:       movl %ebp,(%edi)                # Push btx_v86 and
678                 movl %edi,MEM_TSS+TSS_ESP1      #  save link stack ptr
679                 popl %edi                       # Base of frame
680                 xchgl %eax,%ebp                 # Save intno/address
681                 movl 0x48(%esp,1),%eax          # Get flags
682                 testb $0x2,%dl                  # Simulate CALLF?
683                 jnz intusr.3                    # Yes
684                 decl %ebx                       # Push flags
685                 decl %ebx                       #  on V86
686                 movw %ax,(%ebx)                 #  stack
687 intusr.3:       movb $0x4,%cl                   # Count
688                 subl %ecx,%ebx                  # Push return address
689                 movl $inthlt,(%ebx)             #  on V86 stack
690                 rep                             # Copy seg regs to
691                 movsl                           #  exception frame
692                 xchgl %eax,%ecx                 # Save flags
693                 movl %ebx,%eax                  # User ESP
694                 subl $V86_STK,%eax              # Less bytes
695                 ja intusr.4                     #  to
696                 xorl %eax,%eax                  #  keep
697 intusr.4:       shrl $0x4,%eax                  # Gives segment
698                 stosl                           # Set SS
699                 shll $0x4,%eax                  # To bytes
700                 xchgl %eax,%ebx                 # Swap
701                 subl %ebx,%eax                  # Gives offset
702                 stosl                           # Set ESP
703                 xchgl %eax,%ecx                 # Get flags
704                 btsl $0x11,%eax                 # Set VM
705                 andb $~0x3,%ah                  # Clear IF and TF
706                 stosl                           # Set EFL
707                 xchgl %eax,%ebp                 # Get int no/address
708                 testb $0x1,%dl                  # Address?
709                 jnz intusr.5                    # Yes
710                 shll $0x2,%eax                  # Scale
711                 movl (%eax),%eax                # Load int vector
712 intusr.5:       movl %eax,%ecx                  # Save
713                 shrl $0x10,%eax                 # Gives segment
714                 stosl                           # Set CS
715                 movw %cx,%ax                    # Restore
716                 stosl                           # Set EIP
717                 leal 0x10(%esp,1),%esp          # Discard seg regs
718                 popa                            # Restore
719                 iret                            # To V86 mode
720 #
721 # System Call.
722 #
723 intx30:         cmpl $SYS_EXEC,%eax             # Exec system call?
724                 jne intx30.1                    # No
725                 pushl %ss                       # Set up
726                 popl %es                        #  all
727                 pushl %es                       #  segment
728                 popl %ds                        #  registers
729                 pushl %ds                       #  for the
730                 popl %fs                        #  program
731                 pushl %fs                       #  we're
732                 popl %gs                        #  invoking
733                 movl $MEM_USR,%eax              # User base address
734                 addl 0xc(%esp,1),%eax           # Change to user
735                 leal 0x4(%eax),%esp             #  stack
736                 movl %cr0,%eax                  # Turn
737                 andl $~0x80000000,%eax          #  off
738                 movl %eax,%cr0                  #  paging
739                 xorl %eax,%eax                  # Flush
740                 movl %eax,%cr3                  #  TLB
741                 popl %eax                       # Call
742                 call *%eax                      #  program
743 intx30.1:       incb %ss:btx_hdr+0x7            # Flag reboot
744                 jmp exit                        # Exit
745 #
746 # Dump structure [EBX] to [EDI], using format string [ESI].
747 #
748 dump.0:         stosb                           # Save char
749 dump:           lodsb                           # Load char
750                 testb %al,%al                   # End of string?
751                 jz dump.10                      # Yes
752                 testb $0x80,%al                 # Control?
753                 jz dump.0                       # No
754                 movb %al,%ch                    # Save control
755                 movb $'=',%al                   # Append
756                 stosb                           #  '='
757                 lodsb                           # Get offset
758                 pushl %esi                      # Save
759                 movsbl %al,%esi                 # To
760                 addl %ebx,%esi                  #  pointer
761                 testb $DMP_X16,%ch              # Dump word?
762                 jz dump.1                       # No
763                 lodsw                           # Get and
764                 call hex16                      #  dump it
765 dump.1:         testb $DMP_X32,%ch              # Dump long?
766                 jz dump.2                       # No
767                 lodsl                           # Get and
768                 call hex32                      #  dump it
769 dump.2:         testb $DMP_MEM,%ch              # Dump memory?
770                 jz dump.8                       # No
771                 pushl %ds                       # Save
772                 testb $0x2,0x52(%ebx)           # V86 mode?
773                 jnz dump.3                      # Yes
774                 verrl 0x4(%esi)                 # Readable selector?
775                 jnz dump.3                      # No
776                 ldsl (%esi),%esi                # Load pointer
777                 jmp dump.4                      # Join common code
778 dump.3:         lodsl                           # Set offset
779                 xchgl %eax,%edx                 # Save
780                 lodsl                           # Get segment
781                 shll $0x4,%eax                  #  * 0x10
782                 addl %edx,%eax                  #  + offset
783                 xchgl %eax,%esi                 # Set pointer
784 dump.4:         movb $0x10,%cl                  # Bytes to dump
785 dump.5:         lodsb                           # Get byte and
786                 call hex8                       #  dump it
787                 decb %cl                        # Keep count
788                 jz dump.7                       # If done
789                 movb $'-',%al                   # Separator
790                 cmpb $0x8,%cl                   # Half way?
791                 je dump.6                       # Yes
792                 movb $' ',%al                   # Use space
793 dump.6:         stosb                           # Save separator
794                 jmp dump.5                      # Continue
795 dump.7:         popl %ds                        # Restore
796 dump.8:         popl %esi                       # Restore
797                 movb $0xa,%al                   # Line feed
798                 testb $DMP_EOL,%ch              # End of line?
799                 jnz dump.9                      # Yes
800                 movb $' ',%al                   # Use spaces
801                 stosb                           # Save one
802 dump.9:         jmp dump.0                      # Continue
803 dump.10:        stosb                           # Terminate string
804                 ret                             # To caller
805 #
806 # Convert EAX, AX, or AL to hex, saving the result to [EDI].
807 #
808 hex32:          pushl %eax                      # Save
809                 shrl $0x10,%eax                 # Do upper
810                 call hex16                      #  16
811                 popl %eax                       # Restore
812 hex16:          call hex16.1                    # Do upper 8
813 hex16.1:        xchgb %ah,%al                   # Save/restore
814 hex8:           pushl %eax                      # Save
815                 shrb $0x4,%al                   # Do upper
816                 call hex8.1                     #  4
817                 popl %eax                       # Restore
818 hex8.1:         andb $0xf,%al                   # Get lower 4
819                 cmpb $0xa,%al                   # Convert
820                 sbbb $0x69,%al                  #  to hex
821                 das                             #  digit
822                 orb $0x20,%al                   # To lower case
823                 stosb                           # Save char
824                 ret                             # (Recursive)
825 #
826 # Output zero-terminated string [ESI] to the console.
827 #
828 putstr.0:       call putchr                     # Output char
829 putstr:         lodsb                           # Load char
830                 testb %al,%al                   # End of string?
831                 jnz putstr.0                    # No
832                 ret                             # To caller
833 #
834 # Output character AL to the console.
835 #
836 putchr:         pusha                           # Save
837                 xorl %ecx,%ecx                  # Zero for loops
838                 movb $SCR_MAT,%ah               # Mode/attribute
839                 movl $BDA_POS,%ebx              # BDA pointer
840                 movw (%ebx),%dx                 # Cursor position
841                 movl $0xb8000,%edi              # Regen buffer (color)
842                 cmpb %ah,BDA_SCR-BDA_POS(%ebx)  # Mono mode?
843                 jne putchr.1                    # No
844                 xorw %di,%di                    # Regen buffer (mono)
845 putchr.1:       cmpb $0xa,%al                   # New line?
846                 je putchr.2                     # Yes
847                 xchgl %eax,%ecx                 # Save char
848                 movb $SCR_COL,%al               # Columns per row
849                 mulb %dh                        #  * row position
850                 addb %dl,%al                    #  + column
851                 adcb $0x0,%ah                   #  position
852                 shll %eax                       #  * 2
853                 xchgl %eax,%ecx                 # Swap char, offset
854                 movw %ax,(%edi,%ecx,1)          # Write attr:char
855                 incl %edx                       # Bump cursor
856                 cmpb $SCR_COL,%dl               # Beyond row?
857                 jb putchr.3                     # No
858 putchr.2:       xorb %dl,%dl                    # Zero column
859                 incb %dh                        # Bump row
860 putchr.3:       cmpb $SCR_ROW,%dh               # Beyond screen?
861                 jb putchr.4                     # No
862                 leal 2*SCR_COL(%edi),%esi       # New top line
863                 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
864                 rep                             # Scroll
865                 movsl                           #  screen
866                 movb $' ',%al                   # Space
867                 movb $SCR_COL,%cl               # Columns to clear
868                 rep                             # Clear
869                 stosw                           #  line
870                 movb $SCR_ROW-1,%dh             # Bottom line
871 putchr.4:       movw %dx,(%ebx)                 # Update position
872                 popa                            # Restore
873                 ret                             # To caller
874
875                 .p2align 4
876 #
877 # Global descriptor table.
878 #
879 gdt:            .word 0x0,0x0,0x0,0x0           # Null entry
880                 .word 0xffff,0x0,0x9a00,0xcf    # SEL_SCODE
881                 .word 0xffff,0x0,0x9200,0xcf    # SEL_SDATA
882                 .word 0xffff,0x0,0x9a00,0x0     # SEL_RCODE
883                 .word 0xffff,0x0,0x9200,0x0     # SEL_RDATA
884                 .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
885                 .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
886                 .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
887 gdt.1:
888 #
889 # Pseudo-descriptors.
890 #
891 gdtdesc:        .word gdt.1-gdt-1,gdt,0x0       # GDT
892 idtdesc:        .word _IDTLM,MEM_IDT,0x0        # IDT
893 ivtdesc:        .word 0x400-0x0-1,0x0,0x0       # IVT
894 #
895 # IDT construction control string.
896 #
897 idtctl:         .byte 0x10,  0x8e               # Int 0x0-0xf
898                 .word 0x7dfb,intx00             #  (exceptions)
899                 .byte 0x10,  0x8e               # Int 0x10
900                 .word 0x1,   intx10             #  (exception)
901                 .byte 0x10,  0x8e               # Int 0x20-0x2f
902                 .word 0xffff,intx20             #  (hardware)
903                 .byte 0x1,   0xee               # int 0x30
904                 .word 0x1,   intx30             #  (system call)
905                 .byte 0x2,   0xee               # Int 0x31-0x32
906                 .word 0x1,   intx31             #  (V86, null)
907                 .byte 0x0                       # End of string
908 #
909 # Dump format string.
910 #
911 dmpfmt:         .byte '\n'                      # "\n"
912                 .ascii "int"                    # "int="
913                 .byte 0x80|DMP_X32,        0x40 # "00000000  "
914                 .ascii "err"                    # "err="
915                 .byte 0x80|DMP_X32,        0x44 # "00000000  "
916                 .ascii "efl"                    # "efl="
917                 .byte 0x80|DMP_X32,        0x50 # "00000000  "
918                 .ascii "eip"                    # "eip="
919                 .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
920                 .ascii "eax"                    # "eax="
921                 .byte 0x80|DMP_X32,        0x34 # "00000000  "
922                 .ascii "ebx"                    # "ebx="
923                 .byte 0x80|DMP_X32,        0x28 # "00000000  "
924                 .ascii "ecx"                    # "ecx="
925                 .byte 0x80|DMP_X32,        0x30 # "00000000  "
926                 .ascii "edx"                    # "edx="
927                 .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
928                 .ascii "esi"                    # "esi="
929                 .byte 0x80|DMP_X32,        0x1c # "00000000  "
930                 .ascii "edi"                    # "edi="
931                 .byte 0x80|DMP_X32,        0x18 # "00000000  "
932                 .ascii "ebp"                    # "ebp="
933                 .byte 0x80|DMP_X32,        0x20 # "00000000  "
934                 .ascii "esp"                    # "esp="
935                 .byte 0x80|DMP_X32|DMP_EOL,0x0  # "00000000\n"
936                 .ascii "cs"                     # "cs="
937                 .byte 0x80|DMP_X16,        0x4c # "0000  "
938                 .ascii "ds"                     # "ds="
939                 .byte 0x80|DMP_X16,        0xc  # "0000  "
940                 .ascii "es"                     # "es="
941                 .byte 0x80|DMP_X16,        0x8  # "0000  "
942                 .ascii "  "                     # "  "
943                 .ascii "fs"                     # "fs="
944                 .byte 0x80|DMP_X16,        0x10 # "0000  "
945                 .ascii "gs"                     # "gs="
946                 .byte 0x80|DMP_X16,        0x14 # "0000  "
947                 .ascii "ss"                     # "ss="
948                 .byte 0x80|DMP_X16|DMP_EOL,0x4  # "0000\n"
949                 .ascii "cs:eip"                 # "cs:eip="
950                 .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
951                 .ascii "ss:esp"                 # "ss:esp="
952                 .byte 0x80|DMP_MEM|DMP_EOL,0x0  # "00 00 ... 00 00\n"
953                 .asciz "System halted"          # End
954 #
955 # End of BTX memory.
956 #
957                 .p2align 4
958 break: