]> 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 r177568,
[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  * $FreeBSD$
16  */
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_ESPR,0x5e00            # Real mode stack
25                 .set MEM_IDT,0x5e00             # IDT
26                 .set MEM_TSS,0x5f98             # TSS
27                 .set MEM_MAP,0x6000             # I/O bit map
28                 .set MEM_TSS_END,0x7fff         # End of TSS
29                 .set MEM_ORG,0x9000             # BTX code
30                 .set MEM_USR,0xa000             # Start of user memory
31 /*
32  * Paging control.
33  */
34                 .set PAG_SIZ,0x1000             # Page size
35                 .set PAG_CNT,0x1000             # Pages to map
36 /*
37  * Segment selectors.
38  */
39                 .set SEL_SCODE,0x8              # Supervisor code
40                 .set SEL_SDATA,0x10             # Supervisor data
41                 .set SEL_RCODE,0x18             # Real mode code
42                 .set SEL_RDATA,0x20             # Real mode data
43                 .set SEL_UCODE,0x28|3           # User code
44                 .set SEL_UDATA,0x30|3           # User data
45                 .set SEL_TSS,0x38               # TSS
46 /*
47  * Task state segment fields.
48  */
49                 .set TSS_ESP0,0x4               # PL 0 ESP
50                 .set TSS_SS0,0x8                # PL 0 SS
51                 .set TSS_MAP,0x66               # I/O bit map base
52 /*
53  * System calls.
54  */
55                 .set SYS_EXIT,0x0               # Exit
56                 .set SYS_EXEC,0x1               # Exec
57 /*
58  * Fields in V86 interface structure.
59  */
60                 .set V86_CTL,0x0                # Control flags
61                 .set V86_ADDR,0x4               # Int number/address
62                 .set V86_ES,0x8                 # V86 ES
63                 .set V86_DS,0xc                 # V86 DS
64                 .set V86_FS,0x10                # V86 FS
65                 .set V86_GS,0x14                # V86 GS
66 /*
67  * V86 control flags.
68  */
69                 .set V86F_ADDR,0x10000          # Segment:offset address
70                 .set V86F_CALLF,0x20000         # Emulate far call
71                 .set V86F_FLAGS,0x40000         # Return flags
72 /*
73  * Dump format control bytes.
74  */
75                 .set DMP_X16,0x1                # Word
76                 .set DMP_X32,0x2                # Long
77                 .set DMP_MEM,0x4                # Memory
78                 .set DMP_EOL,0x8                # End of line
79 /*
80  * Screen defaults and assumptions.
81  */
82                 .set SCR_MAT,0x7                # Mode/attribute
83                 .set SCR_COL,0x50               # Columns per row
84                 .set SCR_ROW,0x19               # Rows per screen
85 /*
86  * BIOS Data Area locations.
87  */
88                 .set BDA_MEM,0x413              # Free memory
89                 .set BDA_SCR,0x449              # Video mode
90                 .set BDA_POS,0x450              # Cursor position
91                 .set BDA_BOOT,0x472             # Boot howto flag
92 /*
93  * Derivations, for brevity.
94  */
95                 .set _ESP0H,MEM_ESP0>>0x8       # Byte 1 of ESP0
96                 .set _TSSIO,MEM_MAP-MEM_TSS     # TSS I/O base
97                 .set _TSSLM,MEM_TSS_END-MEM_TSS # TSS limit
98                 .set _IDTLM,MEM_TSS-MEM_IDT-1   # IDT limit
99 /*
100  * Code segment.
101  */
102                 .globl start
103                 .code16
104 start:                                          # Start of code
105 /*
106  * BTX header.
107  */
108 btx_hdr:        .byte 0xeb                      # Machine ID
109                 .byte 0xe                       # Header size
110                 .ascii "BTX"                    # Magic
111                 .byte 0x1                       # Major version
112                 .byte 0x2                       # Minor version
113                 .byte BTX_FLAGS                 # Flags
114                 .word PAG_CNT-MEM_ORG>>0xc      # Paging control
115                 .word break-start               # Text size
116                 .long 0x0                       # Entry address
117 /*
118  * Initialization routine.
119  */
120 init:           cli                             # Disable interrupts
121                 xor %ax,%ax                     # Zero/segment
122                 mov %ax,%ss                     # Set up
123                 mov $MEM_ESP0,%sp               #  stack
124                 mov %ax,%es                     # Address
125                 mov %ax,%ds                     #  data
126                 pushl $0x2                      # Clear
127                 popfl                           #  flags
128 /*
129  * Initialize memory.
130  */
131                 mov $MEM_IDT,%di                # Memory to initialize
132                 mov $(MEM_ORG-MEM_IDT)/2,%cx    # Words to zero
133                 rep                             # Zero-fill
134                 stosw                           #  memory
135 /*
136  * Update real mode IDT for reflecting hardware interrupts.
137  */
138                 mov $intr20,%bx                 # Address first handler
139                 mov $0x10,%cx                   # Number of handlers
140                 mov $0x20*4,%di                 # First real mode IDT entry
141 init.0:         mov %bx,(%di)                   # Store IP
142                 inc %di                         # Address next
143                 inc %di                         #  entry
144                 stosw                           # Store CS
145                 add $4,%bx                      # Next handler
146                 loop init.0                     # Next IRQ
147 /*
148  * Create IDT.
149  */
150                 mov $MEM_IDT,%di
151                 mov $idtctl,%si                 # Control string
152 init.1:         lodsb                           # Get entry
153                 cbw                             #  count
154                 xchg %ax,%cx                    #  as word
155                 jcxz init.4                     # If done
156                 lodsb                           # Get segment
157                 xchg %ax,%dx                    #  P:DPL:type
158                 lodsw                           # Get control
159                 xchg %ax,%bx                    #  set
160                 lodsw                           # Get handler offset
161                 mov $SEL_SCODE,%dh              # Segment selector
162 init.2:         shr %bx                         # Handle this int?
163                 jnc init.3                      # No
164                 mov %ax,(%di)                   # Set handler offset
165                 mov %dh,0x2(%di)                #  and selector
166                 mov %dl,0x5(%di)                # Set P:DPL:type
167                 add $0x4,%ax                    # Next handler
168 init.3:         lea 0x8(%di),%di                # Next entry
169                 loop init.2                     # Till set done
170                 jmp init.1                      # Continue
171 /*
172  * Initialize TSS.
173  */
174 init.4:         movb $_ESP0H,TSS_ESP0+1(%di)    # Set ESP0
175                 movb $SEL_SDATA,TSS_SS0(%di)    # Set SS0
176                 movb $_TSSIO,TSS_MAP(%di)       # Set I/O bit map base
177 /*
178  * Bring up the system.
179  */
180                 mov $0x2820,%bx                 # Set protected mode
181                 callw setpic                    #  IRQ offsets
182                 lidt idtdesc                    # Set IDT
183                 lgdt gdtdesc                    # Set GDT
184                 mov %cr0,%eax                   # Switch to protected
185                 inc %ax                         #  mode
186                 mov %eax,%cr0                   #
187                 ljmp $SEL_SCODE,$init.8         # To 32-bit code
188                 .code32
189 init.8:         xorl %ecx,%ecx                  # Zero
190                 movb $SEL_SDATA,%cl             # To 32-bit
191                 movw %cx,%ss                    #  stack
192 /*
193  * Launch user task.
194  */
195                 movb $SEL_TSS,%cl               # Set task
196                 ltr %cx                         #  register
197                 movl $MEM_USR,%edx              # User base address
198                 movzwl %ss:BDA_MEM,%eax         # Get free memory
199                 shll $0xa,%eax                  # To bytes
200                 subl $0x1000,%eax               # Less arg space
201                 subl %edx,%eax                  # Less base
202                 movb $SEL_UDATA,%cl             # User data selector
203                 pushl %ecx                      # Set SS
204                 pushl %eax                      # Set ESP
205                 push $0x202                     # Set flags (IF set)
206                 push $SEL_UCODE                 # Set CS
207                 pushl btx_hdr+0xc               # Set EIP
208                 pushl %ecx                      # Set GS
209                 pushl %ecx                      # Set FS
210                 pushl %ecx                      # Set DS
211                 pushl %ecx                      # Set ES
212                 pushl %edx                      # Set EAX
213                 movb $0x7,%cl                   # Set remaining
214 init.9:         push $0x0                       #  general
215                 loop init.9                     #  registers
216 #ifdef BTX_SERIAL
217                 call sio_init                   # setup the serial console
218 #endif
219                 popa                            #  and initialize
220                 popl %es                        # Initialize
221                 popl %ds                        #  user
222                 popl %fs                        #  segment
223                 popl %gs                        #  registers
224                 iret                            # To user mode
225 /*
226  * Exit routine.
227  */
228 exit:           cli                             # Disable interrupts
229                 movl $MEM_ESP0,%esp             # Clear stack
230 /*
231  * Turn off paging.
232  */
233                 movl %cr0,%eax                  # Get CR0
234                 andl $~0x80000000,%eax          # Disable
235                 movl %eax,%cr0                  #  paging
236                 xorl %ecx,%ecx                  # Zero
237                 movl %ecx,%cr3                  # Flush TLB
238 /*
239  * Restore the GDT in case we caught a kernel trap.
240  */
241                 lgdt gdtdesc                    # Set GDT
242 /*
243  * To 16 bits.
244  */
245                 ljmpw $SEL_RCODE,$exit.1        # Reload CS
246                 .code16
247 exit.1:         mov $SEL_RDATA,%cl              # 16-bit selector
248                 mov %cx,%ss                     # Reload SS
249                 mov %cx,%ds                     # Load
250                 mov %cx,%es                     #  remaining
251                 mov %cx,%fs                     #  segment
252                 mov %cx,%gs                     #  registers
253 /*
254  * To real-address mode.
255  */
256                 dec %ax                         # Switch to
257                 mov %eax,%cr0                   #  real mode
258                 ljmp $0x0,$exit.2               # Reload CS
259 exit.2:         xor %ax,%ax                     # Real mode segment
260                 mov %ax,%ss                     # Reload SS
261                 mov %ax,%ds                     # Address data
262                 mov $0x7008,%bx                 # Set real mode
263                 callw setpic                    #  IRQ offsets
264                 lidt ivtdesc                    # Set IVT
265 /*
266  * Reboot or await reset.
267  */
268                 sti                             # Enable interrupts
269                 testb $0x1,btx_hdr+0x7          # Reboot?
270 exit.3:         jz exit.3                       # No
271                 movw $0x1234, BDA_BOOT          # Do a warm boot
272                 ljmp $0xf000,$0xfff0            # reboot the machine
273 /*
274  * Set IRQ offsets by reprogramming 8259A PICs.
275  */
276 setpic:         in $0x21,%al                    # Save master
277                 push %ax                        #  IMR
278                 in $0xa1,%al                    # Save slave
279                 push %ax                        #  IMR
280                 movb $0x11,%al                  # ICW1 to
281                 outb %al,$0x20                  #  master,
282                 outb %al,$0xa0                  #  slave
283                 movb %bl,%al                    # ICW2 to
284                 outb %al,$0x21                  #  master
285                 movb %bh,%al                    # ICW2 to
286                 outb %al,$0xa1                  #  slave
287                 movb $0x4,%al                   # ICW3 to
288                 outb %al,$0x21                  #  master
289                 movb $0x2,%al                   # ICW3 to
290                 outb %al,$0xa1                  #  slave
291                 movb $0x1,%al                   # ICW4 to
292                 outb %al,$0x21                  #  master,
293                 outb %al,$0xa1                  #  slave
294                 pop %ax                         # Restore slave
295                 outb %al,$0xa1                  #  IMR
296                 pop %ax                         # Restore master
297                 outb %al,$0x21                  #  IMR
298                 retw                            # To caller
299                 .code32
300 /*
301  * Exception jump table.
302  */
303 intx00:         push $0x0                       # Int 0x0: #DE
304                 jmp ex_noc                      # Divide error
305                 push $0x1                       # Int 0x1: #DB
306                 jmp ex_noc                      # Debug
307                 push $0x3                       # Int 0x3: #BP
308                 jmp ex_noc                      # Breakpoint
309                 push $0x4                       # Int 0x4: #OF
310                 jmp ex_noc                      # Overflow
311                 push $0x5                       # Int 0x5: #BR
312                 jmp ex_noc                      # BOUND range exceeded
313                 push $0x6                       # Int 0x6: #UD
314                 jmp ex_noc                      # Invalid opcode
315                 push $0x7                       # Int 0x7: #NM
316                 jmp ex_noc                      # Device not available
317                 push $0x8                       # Int 0x8: #DF
318                 jmp except                      # Double fault
319                 push $0xa                       # Int 0xa: #TS
320                 jmp except                      # Invalid TSS
321                 push $0xb                       # Int 0xb: #NP
322                 jmp except                      # Segment not present
323                 push $0xc                       # Int 0xc: #SS
324                 jmp except                      # Stack segment fault
325                 push $0xd                       # Int 0xd: #GP
326                 jmp except                      # General protection
327                 push $0xe                       # Int 0xe: #PF
328                 jmp except                      # Page fault
329 intx10:         push $0x10                      # Int 0x10: #MF
330                 jmp ex_noc                      # Floating-point error
331 /*
332  * Save a zero error code.
333  */
334 ex_noc:         pushl (%esp,1)                  # Duplicate int no
335                 movb $0x0,0x4(%esp,1)           # Fake error code
336 /*
337  * Handle exception.
338  */
339 except:         cld                             # String ops inc
340                 pushl %ds                       # Save
341                 pushl %es                       #  most
342                 pusha                           #  registers
343                 pushl %gs                       # Set GS
344                 pushl %fs                       # Set FS
345                 pushl %ds                       # Set DS
346                 pushl %es                       # Set ES
347                 cmpw $SEL_SCODE,0x44(%esp,1)    # Supervisor mode?
348                 jne except.1                    # No
349                 pushl %ss                       # Set SS
350                 jmp except.2                    # Join common code
351 except.1:       pushl 0x50(%esp,1)              # Set SS
352 except.2:       pushl 0x50(%esp,1)              # Set ESP
353                 push $SEL_SDATA                 # Set up
354                 popl %ds                        #  to
355                 pushl %ds                       #  address
356                 popl %es                        #  data
357                 movl %esp,%ebx                  # Stack frame
358                 movl $dmpfmt,%esi               # Dump format string
359                 movl $MEM_BUF,%edi              # Buffer
360                 pushl %edi                      # Dump to
361                 call dump                       #  buffer
362                 popl %esi                       #  and
363                 call putstr                     #  display
364                 leal 0x18(%esp,1),%esp          # Discard frame
365                 popa                            # Restore
366                 popl %es                        #  registers
367                 popl %ds                        #  saved
368                 cmpb $0x3,(%esp,1)              # Breakpoint?
369                 je except.3                     # Yes
370                 cmpb $0x1,(%esp,1)              # Debug?
371                 jne except.2a                   # No
372                 testl $0x100,0x10(%esp,1)       # Trap flag set?
373                 jnz except.3                    # Yes
374 except.2a:      jmp exit                        # Exit
375 except.3:       leal 0x8(%esp,1),%esp           # Discard err, int no
376                 iret                            # From interrupt
377
378 /*
379  * Reboot the machine by setting the reboot flag and exiting
380  */
381 reboot:         orb $0x1,btx_hdr+0x7            # Set the reboot flag
382                 jmp exit                        # Terminate BTX and reboot
383
384 /*
385  * Protected Mode Hardware interrupt jump table.
386  */
387 intx20:         push $0x8                       # Int 0x20: IRQ0
388                 jmp int_hw                      # V86 int 0x8
389                 push $0x9                       # Int 0x21: IRQ1
390                 jmp int_hw                      # V86 int 0x9
391                 push $0xa                       # Int 0x22: IRQ2
392                 jmp int_hw                      # V86 int 0xa
393                 push $0xb                       # Int 0x23: IRQ3
394                 jmp int_hw                      # V86 int 0xb
395                 push $0xc                       # Int 0x24: IRQ4
396                 jmp int_hw                      # V86 int 0xc
397                 push $0xd                       # Int 0x25: IRQ5
398                 jmp int_hw                      # V86 int 0xd
399                 push $0xe                       # Int 0x26: IRQ6
400                 jmp int_hw                      # V86 int 0xe
401                 push $0xf                       # Int 0x27: IRQ7
402                 jmp int_hw                      # V86 int 0xf
403                 push $0x70                      # Int 0x28: IRQ8
404                 jmp int_hw                      # V86 int 0x70
405                 push $0x71                      # Int 0x29: IRQ9
406                 jmp int_hw                      # V86 int 0x71
407                 push $0x72                      # Int 0x2a: IRQ10
408                 jmp int_hw                      # V86 int 0x72
409                 push $0x73                      # Int 0x2b: IRQ11
410                 jmp int_hw                      # V86 int 0x73
411                 push $0x74                      # Int 0x2c: IRQ12
412                 jmp int_hw                      # V86 int 0x74
413                 push $0x75                      # Int 0x2d: IRQ13
414                 jmp int_hw                      # V86 int 0x75
415                 push $0x76                      # Int 0x2e: IRQ14
416                 jmp int_hw                      # V86 int 0x76
417                 push $0x77                      # Int 0x2f: IRQ15
418                 jmp int_hw                      # V86 int 0x77
419
420 /*
421  * Invoke real mode interrupt/function call from user mode with arguments.
422  */
423 intx31:         pushl $-1                       # Dummy int no for btx_v86
424 /*
425  * Invoke real mode interrupt/function call from protected mode.
426  *
427  * We place a trampoline on the user stack that will return to rret_tramp
428  * which will reenter protected mode and then finally return to the user
429  * client.
430  *
431  * Kernel frame %esi points to:         Real mode stack frame at MEM_ESPR:
432  *
433  * -0x00 user %ss                       -0x04 kernel %esp (with full frame)
434  * -0x04 user %esp                      -0x08 btx_v86 pointer
435  * -0x08 user %eflags                   -0x0c flags (only used if interrupt)
436  * -0x0c user %cs                       -0x10 real mode CS:IP return trampoline
437  * -0x10 user %eip                      -0x12 real mode flags
438  * -0x14 int no                         -0x16 real mode CS:IP (target)
439  * -0x18 %eax
440  * -0x1c %ecx
441  * -0x20 %edx
442  * -0x24 %ebx
443  * -0x28 %esp
444  * -0x2c %ebp
445  * -0x30 %esi
446  * -0x34 %edi
447  * -0x38 %gs
448  * -0x3c %fs
449  * -0x40 %ds
450  * -0x44 %es
451  */
452 int_hw:         cld                             # String ops inc
453                 pusha                           # Save gp regs
454                 pushl %gs                       # Save
455                 pushl %fs                       #  seg
456                 pushl %ds                       #  regs
457                 pushl %es
458                 push $SEL_SDATA                 # Set up
459                 popl %ds                        #  to
460                 pushl %ds                       #  address
461                 popl %es                        #  data
462                 leal 0x44(%esp,1),%esi          # Base of frame
463                 movl -0x14(%esi),%eax           # Get Int no
464                 cmpl $-1,%eax                   # Hardware interrupt?
465                 jne intusr.2                    # Yes
466 /*
467  * v86 calls save the btx_v86 pointer on the real mode stack and read the
468  * address and flags from the btx_v86 structure.
469  */
470                 movl $MEM_USR,%ebx              # User base
471                 movl %ebx,%edx                  #  address
472                 addl -0x4(%esi),%ebx            # User ESP
473                 movl (%ebx),%ebp                # btx_v86 pointer
474                 addl %ebp,%edx                  # Flatten btx_v86 ptr
475                 movl %edx,MEM_ESPR-0x08         # Save btx_v86 ptr
476                 movl -0x08(%esi),%ebx           # Pass user flags to
477                 movw %bx,MEM_ESPR-0x12          #  real mode target
478                 movl V86_ADDR(%edx),%eax        # Get int no/address
479                 movl V86_CTL(%edx),%edx         # Get control flags
480                 jmp intusr.3                    # Skip hardware interrupt
481 /*
482  * Hardware interrupts store a NULL btx_v86 pointer and use the address
483  * (interrupt number) from the stack with empty flags.  Also, we clear
484  * the segment registers for the interrupt handler and ensure interrupts
485  * are disabled when the interrupt handler is invoked.
486  */
487 intusr.2:       xorl %edx,%edx                  # Control flags
488                 movl %edx,MEM_ESPR-0x08         # NULL btx_v86 ptr
489                 movl %edx,-0x38(%esi)           # Real mode %gs of 0
490                 movl %edx,-0x3c(%esi)           # Real mode %fs of 0
491                 movl %edx,-0x40(%esi)           # Real mode %ds of 0
492                 movl %edx,-0x44(%esi)           # Real mode %es of 0
493                 movl -0x08(%esi),%ebx           # Pass user flags with
494                 andl $~0x200,%ebx               #  interrupts disabled
495                 movw %bx,MEM_ESPR-0x12          #  to real mode target
496 /*
497  * %eax now holds either the interrupt number or segment:offset of function.
498  * %edx now holds the V86F_* flags.
499  */
500 intusr.3:       testl $V86F_ADDR,%edx           # Segment:offset?
501                 jnz intusr.4                    # Yes
502                 shll $0x2,%eax                  # Scale
503                 movl (%eax),%eax                # Load int vector
504                 jmp intusr.5                    # Skip CALLF test
505 intusr.4:       testl $V86F_CALLF,%edx          # Far call?
506                 jnz intusr.5                    # Ok
507                 movl %edx,0x30(%esp,1)          # Place VM86 flags in int no
508                 movl $badvm86,%esi              # Display bad
509                 call putstr                     #  VM86 call
510                 popl %es                        # Restore
511                 popl %ds                        #  seg
512                 popl %fs                        #  regs
513                 popl %gs
514                 popal                           # Restore gp regs
515                 jmp ex_noc                      # Panic
516 /*
517  * If this is a v86 call, copy the seg regs out of the btx_v86 structure.
518  */
519 intusr.5:       movl MEM_ESPR-0x08,%ecx         # Get btx_v86 ptr
520                 jecxz intusr.6                  # Skip for hardware ints
521                 leal -0x44(%esi),%edi           # %edi => kernel stack seg regs
522                 pushl %esi                      # Save
523                 leal V86_ES(%ecx),%esi          # %esi => btx_v86 seg regs
524                 movl $4,%ecx                    # Copy seg regs
525                 rep                             #  from btx_v86
526                 movsl                           #  to kernel stack
527                 popl %esi                       # Restore
528 intusr.6:       movl %esp,MEM_ESPR-0x04         # Save kernel stack pointer
529                 movl -0x08(%esi),%ebx           # Copy user flags to real
530                 movl %ebx,MEM_ESPR-0x0c         #  mode return trampoline
531                 movl $rret_tramp,%ebx           # Set return trampoline
532                 movl %ebx,MEM_ESPR-0x10         #  CS:IP
533                 movl %eax,MEM_ESPR-0x16         # Real mode target CS:IP
534                 ljmpw $SEL_RCODE,$intusr.7      # Change to 16-bit segment
535                 .code16
536 intusr.7:       movl %cr0,%eax                  # Leave
537                 dec %al                         #  protected
538                 movl %eax,%cr0                  #  mode
539                 ljmpw $0x0,$intusr.8
540 intusr.8:       xorw %ax,%ax                    # Reset %ds
541                 movw %ax,%ds                    #  and
542                 movw %ax,%ss                    #  %ss
543                 lidt ivtdesc                    # Set IVT
544                 popl %es                        # Restore
545                 popl %ds                        #  seg
546                 popl %fs                        #  regs
547                 popl %gs
548                 popal                           # Restore gp regs
549                 movw $MEM_ESPR-0x16,%sp         # Switch to real mode stack
550                 iret                            # Call target routine
551 /*
552  * For the return to real mode we setup a stack frame like this on the real
553  * mode stack.  Note that callf calls won't pop off the flags, but we just
554  * ignore that by repositioning %sp to be just above the btx_v86 pointer
555  * so it is aligned.  The stack is relative to MEM_ESPR.
556  *
557  * -0x04        kernel %esp
558  * -0x08        btx_v86
559  * -0x0c        %eax
560  * -0x10        %ecx
561  * -0x14        %edx
562  * -0x18        %ebx
563  * -0x1c        %esp
564  * -0x20        %ebp
565  * -0x24        %esi
566  * -0x28        %edi
567  * -0x2c        %gs
568  * -0x30        %fs
569  * -0x34        %ds
570  * -0x38        %es
571  * -0x3c        %eflags
572  */
573 rret_tramp:     movw $MEM_ESPR-0x08,%sp         # Reset stack pointer
574                 pushal                          # Save gp regs
575                 pushl %gs                       # Save
576                 pushl %fs                       #  seg
577                 pushl %ds                       #  regs
578                 pushl %es
579                 pushfl                          # Save %eflags
580                 cli                             # Disable interrupts
581                 std                             # String ops dec
582                 xorw %ax,%ax                    # Reset seg 
583                 movw %ax,%ds                    #  regs
584                 movw %ax,%es                    #  (%ss is already 0)
585                 lidt idtdesc                    # Set IDT
586                 lgdt gdtdesc                    # Set GDT
587                 mov %cr0,%eax                   # Switch to protected
588                 inc %ax                         #  mode
589                 mov %eax,%cr0                   #
590                 ljmp $SEL_SCODE,$rret_tramp.1   # To 32-bit code
591                 .code32
592 rret_tramp.1:   xorl %ecx,%ecx                  # Zero
593                 movb $SEL_SDATA,%cl             # Setup
594                 movw %cx,%ss                    #  32-bit
595                 movw %cx,%ds                    #  seg
596                 movw %cx,%es                    #  regs
597                 movl MEM_ESPR-0x04,%esp         # Switch to kernel stack
598                 leal 0x44(%esp,1),%esi          # Base of frame
599                 andb $~0x2,tss_desc+0x5         # Clear TSS busy
600                 movb $SEL_TSS,%cl               # Set task
601                 ltr %cx                         #  register
602 /*
603  * Now we are back in protected mode.  Copy the registers off of the real
604  * mode stack onto the kernel stack.  Also, initialize all the seg regs on
605  * the kernel stack.
606  *
607  * Note that the %esp in the kernel stack after this is garbage, but popa
608  * ignores it, so we don't have to fix it up.
609  */
610                 leal -0x18(%esi),%edi           # Kernel stack GP regs
611                 pushl %esi                      # Save
612                 movl $MEM_ESPR-0x0c,%esi        # Real mode stack GP regs
613                 movl $8,%ecx                    # Copy GP regs from
614                 rep                             #  real mode stack
615                 movsl                           #  to kernel stack
616                 popl %esi                       # Restore
617                 movl $SEL_UDATA,%eax            # Selector for data seg regs
618                 movl $4,%ecx                    # Initialize %ds,
619                 rep                             #  %es, %fs, and
620                 stosl                           #  %gs
621 /*
622  * If this was a V86 call, copy the saved seg regs on the real mode stack
623  * back over to the btx_v86 structure.  Also, conditionally update the saved
624  * eflags on the kernel stack based on the flags from the user.
625  */
626                 movl MEM_ESPR-0x08,%ecx         # Get btx_v86 ptr
627                 jecxz rret_tramp.3              # Skip for hardware ints
628                 leal V86_GS(%ecx),%edi          # %edi => btx_v86 seg regs
629                 pushl %esi                      # Save
630                 leal MEM_ESPR-0x2c,%esi         # %esi => real mode seg regs
631                 xchgl %ecx,%edx                 # Save btx_v86 ptr
632                 movl $4,%ecx                    # Copy seg regs
633                 rep                             #  from real mode stack
634                 movsl                           #  to btx_v86
635                 popl %esi                       # Restore
636                 movl V86_CTL(%edx),%edx         # Read V86 control flags
637                 testl $V86F_FLAGS,%edx          # User wants flags?
638                 jz rret_tramp.3                 # No
639                 movl MEM_ESPR-0x3c,%eax         # Read real mode flags
640                 movw %ax,-0x08(%esi)            # Update user flags (low 16)
641 /*
642  * Return to the user task
643  */
644 rret_tramp.3:   popl %es                        # Restore
645                 popl %ds                        #  seg
646                 popl %fs                        #  regs
647                 popl %gs
648                 popal                           # Restore gp regs
649                 addl $4,%esp                    # Discard int no
650                 iret                            # Return to user mode
651
652 /*
653  * System Call.
654  */
655 intx30:         cmpl $SYS_EXEC,%eax             # Exec system call?
656                 jne intx30.1                    # No
657                 pushl %ss                       # Set up
658                 popl %es                        #  all
659                 pushl %es                       #  segment
660                 popl %ds                        #  registers
661                 pushl %ds                       #  for the
662                 popl %fs                        #  program
663                 pushl %fs                       #  we're
664                 popl %gs                        #  invoking
665                 movl $MEM_USR,%eax              # User base address
666                 addl 0xc(%esp,1),%eax           # Change to user
667                 leal 0x4(%eax),%esp             #  stack
668                 popl %eax                       # Call
669                 call *%eax                      #  program
670 intx30.1:       orb $0x1,%ss:btx_hdr+0x7        # Flag reboot
671                 jmp exit                        # Exit
672 /*
673  * Dump structure [EBX] to [EDI], using format string [ESI].
674  */
675 dump.0:         stosb                           # Save char
676 dump:           lodsb                           # Load char
677                 testb %al,%al                   # End of string?
678                 jz dump.10                      # Yes
679                 testb $0x80,%al                 # Control?
680                 jz dump.0                       # No
681                 movb %al,%ch                    # Save control
682                 movb $'=',%al                   # Append
683                 stosb                           #  '='
684                 lodsb                           # Get offset
685                 pushl %esi                      # Save
686                 movsbl %al,%esi                 # To
687                 addl %ebx,%esi                  #  pointer
688                 testb $DMP_X16,%ch              # Dump word?
689                 jz dump.1                       # No
690                 lodsw                           # Get and
691                 call hex16                      #  dump it
692 dump.1:         testb $DMP_X32,%ch              # Dump long?
693                 jz dump.2                       # No
694                 lodsl                           # Get and
695                 call hex32                      #  dump it
696 dump.2:         testb $DMP_MEM,%ch              # Dump memory?
697                 jz dump.8                       # No
698                 pushl %ds                       # Save
699                 testb $0x2,0x52(%ebx)           # V86 mode?
700                 jnz dump.3                      # Yes
701                 verr 0x4(%esi)                  # Readable selector?
702                 jnz dump.3                      # No
703                 ldsl (%esi),%esi                # Load pointer
704                 jmp dump.4                      # Join common code
705 dump.3:         lodsl                           # Set offset
706                 xchgl %eax,%edx                 # Save
707                 lodsl                           # Get segment
708                 shll $0x4,%eax                  #  * 0x10
709                 addl %edx,%eax                  #  + offset
710                 xchgl %eax,%esi                 # Set pointer
711 dump.4:         movb $2,%dl                     # Num lines
712 dump.4a:        movb $0x10,%cl                  # Bytes to dump
713 dump.5:         lodsb                           # Get byte and
714                 call hex8                       #  dump it
715                 decb %cl                        # Keep count
716                 jz dump.6a                      # If done
717                 movb $'-',%al                   # Separator
718                 cmpb $0x8,%cl                   # Half way?
719                 je dump.6                       # Yes
720                 movb $' ',%al                   # Use space
721 dump.6:         stosb                           # Save separator
722                 jmp dump.5                      # Continue
723 dump.6a:        decb %dl                        # Keep count
724                 jz dump.7                       # If done
725                 movb $0xa,%al                   # Line feed
726                 stosb                           # Save one
727                 movb $7,%cl                     # Leading
728                 movb $' ',%al                   #  spaces
729 dump.6b:        stosb                           # Dump
730                 decb %cl                        #  spaces
731                 jnz dump.6b
732                 jmp dump.4a                     # Next line
733 dump.7:         popl %ds                        # Restore
734 dump.8:         popl %esi                       # Restore
735                 movb $0xa,%al                   # Line feed
736                 testb $DMP_EOL,%ch              # End of line?
737                 jnz dump.9                      # Yes
738                 movb $' ',%al                   # Use spaces
739                 stosb                           # Save one
740 dump.9:         jmp dump.0                      # Continue
741 dump.10:        stosb                           # Terminate string
742                 ret                             # To caller
743 /*
744  * Convert EAX, AX, or AL to hex, saving the result to [EDI].
745  */
746 hex32:          pushl %eax                      # Save
747                 shrl $0x10,%eax                 # Do upper
748                 call hex16                      #  16
749                 popl %eax                       # Restore
750 hex16:          call hex16.1                    # Do upper 8
751 hex16.1:        xchgb %ah,%al                   # Save/restore
752 hex8:           pushl %eax                      # Save
753                 shrb $0x4,%al                   # Do upper
754                 call hex8.1                     #  4
755                 popl %eax                       # Restore
756 hex8.1:         andb $0xf,%al                   # Get lower 4
757                 cmpb $0xa,%al                   # Convert
758                 sbbb $0x69,%al                  #  to hex
759                 das                             #  digit
760                 orb $0x20,%al                   # To lower case
761                 stosb                           # Save char
762                 ret                             # (Recursive)
763 /*
764  * Output zero-terminated string [ESI] to the console.
765  */
766 putstr.0:       call putchr                     # Output char
767 putstr:         lodsb                           # Load char
768                 testb %al,%al                   # End of string?
769                 jnz putstr.0                    # No
770                 ret                             # To caller
771 #ifdef BTX_SERIAL
772                 .set SIO_PRT,SIOPRT             # Base port
773                 .set SIO_FMT,SIOFMT             # 8N1
774                 .set SIO_DIV,(115200/SIOSPD)    # 115200 / SPD
775
776 /*
777  * void sio_init(void)
778  */
779 sio_init:       movw $SIO_PRT+0x3,%dx           # Data format reg
780                 movb $SIO_FMT|0x80,%al          # Set format
781                 outb %al,(%dx)                  #  and DLAB
782                 pushl %edx                      # Save
783                 subb $0x3,%dl                   # Divisor latch reg
784                 movw $SIO_DIV,%ax               # Set
785                 outw %ax,(%dx)                  #  BPS
786                 popl %edx                       # Restore
787                 movb $SIO_FMT,%al               # Clear
788                 outb %al,(%dx)                  #  DLAB
789                 incl %edx                       # Modem control reg
790                 movb $0x3,%al                   # Set RTS,
791                 outb %al,(%dx)                  #  DTR
792                 incl %edx                       # Line status reg
793
794 /*
795  * void sio_flush(void)
796  */
797 sio_flush.0:    call sio_getc.1                 # Get character
798 sio_flush:      call sio_ischar                 # Check for character
799                 jnz sio_flush.0                 # Till none
800                 ret                             # To caller
801
802 /*
803  * void sio_putc(int c)
804  */
805 sio_putc:       movw $SIO_PRT+0x5,%dx           # Line status reg
806                 xor %ecx,%ecx                   # Timeout
807                 movb $0x40,%ch                  #  counter
808 sio_putc.1:     inb (%dx),%al                   # Transmitter
809                 testb $0x20,%al                 #  buffer empty?
810                 loopz sio_putc.1                # No
811                 jz sio_putc.2                   # If timeout
812                 movb 0x4(%esp,1),%al            # Get character
813                 subb $0x5,%dl                   # Transmitter hold reg
814                 outb %al,(%dx)                  # Write character
815 sio_putc.2:     ret $0x4                        # To caller
816
817 /*
818  * int sio_getc(void)
819  */
820 sio_getc:       call sio_ischar                 # Character available?
821                 jz sio_getc                     # No
822 sio_getc.1:     subb $0x5,%dl                   # Receiver buffer reg
823                 inb (%dx),%al                   # Read character
824                 ret                             # To caller
825
826 /*
827  * int sio_ischar(void)
828  */
829 sio_ischar:     movw $SIO_PRT+0x5,%dx           # Line status register
830                 xorl %eax,%eax                  # Zero
831                 inb (%dx),%al                   # Received data
832                 andb $0x1,%al                   #  ready?
833                 ret                             # To caller
834
835 /*
836  * Output character AL to the serial console.
837  */
838 putchr:         pusha                           # Save
839                 cmpb $10, %al                   # is it a newline?
840                 jne putchr.1                    #  no?, then leave
841                 push $13                        # output a carriage
842                 call sio_putc                   #  return first
843                 movb $10, %al                   # restore %al
844 putchr.1:       pushl %eax                      # Push the character
845                                                 #  onto the stack
846                 call sio_putc                   # Output the character
847                 popa                            # Restore
848                 ret                             # To caller
849 #else
850 /*
851  * Output character AL to the console.
852  */
853 putchr:         pusha                           # Save
854                 xorl %ecx,%ecx                  # Zero for loops
855                 movb $SCR_MAT,%ah               # Mode/attribute
856                 movl $BDA_POS,%ebx              # BDA pointer
857                 movw (%ebx),%dx                 # Cursor position
858                 movl $0xb8000,%edi              # Regen buffer (color)
859                 cmpb %ah,BDA_SCR-BDA_POS(%ebx)  # Mono mode?
860                 jne putchr.1                    # No
861                 xorw %di,%di                    # Regen buffer (mono)
862 putchr.1:       cmpb $0xa,%al                   # New line?
863                 je putchr.2                     # Yes
864                 xchgl %eax,%ecx                 # Save char
865                 movb $SCR_COL,%al               # Columns per row
866                 mulb %dh                        #  * row position
867                 addb %dl,%al                    #  + column
868                 adcb $0x0,%ah                   #  position
869                 shll %eax                       #  * 2
870                 xchgl %eax,%ecx                 # Swap char, offset
871                 movw %ax,(%edi,%ecx,1)          # Write attr:char
872                 incl %edx                       # Bump cursor
873                 cmpb $SCR_COL,%dl               # Beyond row?
874                 jb putchr.3                     # No
875 putchr.2:       xorb %dl,%dl                    # Zero column
876                 incb %dh                        # Bump row
877 putchr.3:       cmpb $SCR_ROW,%dh               # Beyond screen?
878                 jb putchr.4                     # No
879                 leal 2*SCR_COL(%edi),%esi       # New top line
880                 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
881                 rep                             # Scroll
882                 movsl                           #  screen
883                 movb $0x20,%al                  # Space
884                 movb $SCR_COL,%cl               # Columns to clear
885                 rep                             # Clear
886                 stosw                           #  line
887                 movb $SCR_ROW-1,%dh             # Bottom line
888 putchr.4:       movw %dx,(%ebx)                 # Update position
889                 popa                            # Restore
890                 ret                             # To caller
891 #endif
892
893                 .code16
894 /*
895  * Real Mode Hardware interrupt jump table.
896  */
897 intr20:         push $0x8                       # Int 0x20: IRQ0
898                 jmp int_hwr                     # V86 int 0x8
899                 push $0x9                       # Int 0x21: IRQ1
900                 jmp int_hwr                     # V86 int 0x9
901                 push $0xa                       # Int 0x22: IRQ2
902                 jmp int_hwr                     # V86 int 0xa
903                 push $0xb                       # Int 0x23: IRQ3
904                 jmp int_hwr                     # V86 int 0xb
905                 push $0xc                       # Int 0x24: IRQ4
906                 jmp int_hwr                     # V86 int 0xc
907                 push $0xd                       # Int 0x25: IRQ5
908                 jmp int_hwr                     # V86 int 0xd
909                 push $0xe                       # Int 0x26: IRQ6
910                 jmp int_hwr                     # V86 int 0xe
911                 push $0xf                       # Int 0x27: IRQ7
912                 jmp int_hwr                     # V86 int 0xf
913                 push $0x70                      # Int 0x28: IRQ8
914                 jmp int_hwr                     # V86 int 0x70
915                 push $0x71                      # Int 0x29: IRQ9
916                 jmp int_hwr                     # V86 int 0x71
917                 push $0x72                      # Int 0x2a: IRQ10
918                 jmp int_hwr                     # V86 int 0x72
919                 push $0x73                      # Int 0x2b: IRQ11
920                 jmp int_hwr                     # V86 int 0x73
921                 push $0x74                      # Int 0x2c: IRQ12
922                 jmp int_hwr                     # V86 int 0x74
923                 push $0x75                      # Int 0x2d: IRQ13
924                 jmp int_hwr                     # V86 int 0x75
925                 push $0x76                      # Int 0x2e: IRQ14
926                 jmp int_hwr                     # V86 int 0x76
927                 push $0x77                      # Int 0x2f: IRQ15
928                 jmp int_hwr                     # V86 int 0x77
929 /*
930  * Reflect hardware interrupts in real mode.
931  */
932 int_hwr:        push %ax                        # Save
933                 push %ds                        # Save
934                 push %bp                        # Save
935                 mov %sp,%bp                     # Address stack frame 
936                 xchg %bx,6(%bp)                 # Swap BX, int no
937                 xor %ax,%ax                     # Set %ds:%bx to
938                 shl $2,%bx                      #  point to
939                 mov %ax,%ds                     #  IDT entry
940                 mov (%bx),%ax                   # Load IP
941                 mov 2(%bx),%bx                  # Load CS
942                 xchg %ax,4(%bp)                 # Swap saved %ax,%bx with
943                 xchg %bx,6(%bp)                 #  CS:IP of handler
944                 pop %bp                         # Restore
945                 pop %ds                         # Restore
946                 lret                            # Jump to handler
947
948                 .p2align 4
949 /*
950  * Global descriptor table.
951  */
952 gdt:            .word 0x0,0x0,0x0,0x0           # Null entry
953                 .word 0xffff,0x0,0x9a00,0xcf    # SEL_SCODE
954                 .word 0xffff,0x0,0x9200,0xcf    # SEL_SDATA
955                 .word 0xffff,0x0,0x9a00,0x0     # SEL_RCODE
956                 .word 0xffff,0x0,0x9200,0x0     # SEL_RDATA
957                 .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
958                 .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
959 tss_desc:       .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
960 gdt.1:
961 /*
962  * Pseudo-descriptors.
963  */
964 gdtdesc:        .word gdt.1-gdt-1,gdt,0x0       # GDT
965 idtdesc:        .word _IDTLM,MEM_IDT,0x0        # IDT
966 ivtdesc:        .word 0x400-0x0-1,0x0,0x0       # IVT
967 /*
968  * IDT construction control string.
969  */
970 idtctl:         .byte 0x10,  0x8e               # Int 0x0-0xf
971                 .word 0x7dfb,intx00             #  (exceptions)
972                 .byte 0x10,  0x8e               # Int 0x10
973                 .word 0x1,   intx10             #  (exception)
974                 .byte 0x10,  0x8e               # Int 0x20-0x2f
975                 .word 0xffff,intx20             #  (hardware)
976                 .byte 0x1,   0xee               # int 0x30
977                 .word 0x1,   intx30             #  (system call)
978                 .byte 0x2,   0xee               # Int 0x31-0x32
979                 .word 0x1,   intx31             #  (V86, null)
980                 .byte 0x0                       # End of string
981 /*
982  * Dump format string.
983  */
984 dmpfmt:         .byte '\n'                      # "\n"
985                 .ascii "int"                    # "int="
986                 .byte 0x80|DMP_X32,        0x40 # "00000000  "
987                 .ascii "err"                    # "err="
988                 .byte 0x80|DMP_X32,        0x44 # "00000000  "
989                 .ascii "efl"                    # "efl="
990                 .byte 0x80|DMP_X32,        0x50 # "00000000  "
991                 .ascii "eip"                    # "eip="
992                 .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
993                 .ascii "eax"                    # "eax="
994                 .byte 0x80|DMP_X32,        0x34 # "00000000  "
995                 .ascii "ebx"                    # "ebx="
996                 .byte 0x80|DMP_X32,        0x28 # "00000000  "
997                 .ascii "ecx"                    # "ecx="
998                 .byte 0x80|DMP_X32,        0x30 # "00000000  "
999                 .ascii "edx"                    # "edx="
1000                 .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
1001                 .ascii "esi"                    # "esi="
1002                 .byte 0x80|DMP_X32,        0x1c # "00000000  "
1003                 .ascii "edi"                    # "edi="
1004                 .byte 0x80|DMP_X32,        0x18 # "00000000  "
1005                 .ascii "ebp"                    # "ebp="
1006                 .byte 0x80|DMP_X32,        0x20 # "00000000  "
1007                 .ascii "esp"                    # "esp="
1008                 .byte 0x80|DMP_X32|DMP_EOL,0x0  # "00000000\n"
1009                 .ascii "cs"                     # "cs="
1010                 .byte 0x80|DMP_X16,        0x4c # "0000  "
1011                 .ascii "ds"                     # "ds="
1012                 .byte 0x80|DMP_X16,        0xc  # "0000  "
1013                 .ascii "es"                     # "es="
1014                 .byte 0x80|DMP_X16,        0x8  # "0000  "
1015                 .ascii "  "                     # "  "
1016                 .ascii "fs"                     # "fs="
1017                 .byte 0x80|DMP_X16,        0x10 # "0000  "
1018                 .ascii "gs"                     # "gs="
1019                 .byte 0x80|DMP_X16,        0x14 # "0000  "
1020                 .ascii "ss"                     # "ss="
1021                 .byte 0x80|DMP_X16|DMP_EOL,0x4  # "0000\n"
1022                 .ascii "cs:eip"                 # "cs:eip="
1023                 .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
1024                 .ascii "ss:esp"                 # "ss:esp="
1025                 .byte 0x80|DMP_MEM|DMP_EOL,0x0  # "00 00 ... 00 00\n"
1026                 .asciz "BTX halted\n"           # End
1027 /*
1028  * Bad VM86 call panic
1029  */
1030 badvm86:        .asciz "Invalid VM86 Request\n"
1031
1032 /*
1033  * End of BTX memory.
1034  */
1035                 .p2align 4
1036 break: