Initial import from FreeBSD RELENG_4:
[games.git] / sys / boot / pc98 / btx / btxldr / btxldr.s
1 #
2 # Copyright (c) 1998 Robert Nordier
3 # All rights reserved.
4 #
5 # Redistribution and use in source and binary forms are freely
6 # permitted provided that the above copyright notice and this
7 # paragraph and the following disclaimer are duplicated in all
8 # such forms.
9 #
10 # This software is provided "AS IS" and without any express or
11 # implied warranties, including, without limitation, the implied
12 # warranties of merchantability and fitness for a particular
13 # purpose.
14 #
15
16 # $FreeBSD: src/sys/boot/pc98/btx/btxldr/btxldr.s,v 1.3.2.2 2000/07/06 23:04:33 obrien Exp $
17
18 #
19 # Prototype BTX loader program, written in a couple of hours.  The
20 # real thing should probably be more flexible, and in C.
21 #
22
23 #
24 # Memory locations.
25 #
26                 .set MEM_STUB,0x600             # Real mode stub
27                 .set MEM_ESP,0x1000             # New stack pointer
28                 .set MEM_TBL,0x5000             # BTX page tables
29                 .set MEM_ENTRY,0x9010           # BTX entry point
30                 .set MEM_DATA,start+0x1000      # Data segment
31 #
32 # Segment selectors.
33 #
34                 .set SEL_SCODE,0x8              # 4GB code
35                 .set SEL_SDATA,0x10             # 4GB data
36                 .set SEL_RCODE,0x18             # 64K code
37                 .set SEL_RDATA,0x20             # 64K data
38 #
39 # Paging constants.
40 #
41                 .set PAG_SIZ,0x1000             # Page size
42                 .set PAG_ENT,0x4                # Page entry size
43 #
44 # Screen constants.
45 #
46 ifdef(`PC98',`
47                 .set SCR_MAT,0xe1               # Mode/attribute
48 ',`
49                 .set SCR_MAT,0x7                # Mode/attribute
50 ')
51                 .set SCR_COL,0x50               # Columns per row
52                 .set SCR_ROW,0x19               # Rows per screen
53 #
54 # BIOS Data Area locations.
55 #
56 ifdef(`PC98',`
57                 .set BDA_MEM,0xa1501            # Free memory
58                 .set BDA_POS,0xa153e            # Cursor position
59 ',`
60                 .set BDA_MEM,0x413              # Free memory
61                 .set BDA_SCR,0x449              # Video mode
62                 .set BDA_POS,0x450              # Cursor position
63 ')
64 #
65 # Required by aout gas inadequacy.
66 #
67                 .set SIZ_STUB,0x1a              # Size of stub
68 #
69 # We expect to be loaded by boot2 at the origin defined in ./Makefile.
70 #
71                 .globl start
72 #
73 # BTX program loader for ELF clients.
74 #
75 start:          cld                             # String ops inc
76 ifdef(`PC98',`
77                 cli
78 gdcwait.1:      inb $0x60,%al
79                 testb $0x04,%al
80                 jz gdcwait.1
81                 movb $0xe0,%al
82                 outb %al,$0x62
83                 nop
84 gdcwait.2:      inb $0x60,%al
85                 testb $0x01,%al
86                 jz gdcwait.2
87                 inb $0x62,%al
88                 movb %al,%dl
89                 inb $0x62,%al
90                 movb %al,%dh
91                 inb $0x62,%al
92                 inb $0x62,%al
93                 inb $0x62,%al
94                 shlw $1,%dx
95                 movl $BDA_POS,%ebx
96                 movw %dx,(%ebx)
97 ')
98                 movl $m_logo,%esi               # Identify
99                 call putstr                     #  ourselves
100                 movzwl BDA_MEM,%eax             # Get base memory
101 ifdef(`PC98',`
102                 andl $0x7,%eax
103                 incl %eax
104                 shll $0x11,%eax                 #  in bytes
105 ',`
106                 shll $0xa,%eax                  #  in bytes
107 ')
108                 movl %eax,%ebp                  # Base of user stack
109 ifdef(`BTXLDR_VERBOSE',`
110                 movl $m_mem,%esi                # Display
111                 call hexout                     #  amount of
112                 call putstr                     #  base memory
113 ')
114                 lgdt gdtdesc                    # Load new GDT
115 #
116 # Relocate caller's arguments.
117 #
118 ifdef('BTXLDR_VERBOSE',`
119                 movl $m_esp,%esi                # Display
120                 movl %esp,%eax                  #  caller
121                 call hexout                     #  stack
122                 call putstr                     #  pointer
123                 movl $m_args,%esi               # Format string
124                 leal 0x4(%esp,1),%ebx           # First argument
125                 movl $0x6,%ecx                  # Count
126 start.1:        movl (%ebx),%eax                # Get argument and
127                 addl $0x4,%ebx                  #  bump pointer
128                 call hexout                     # Display it
129                 loop start.1                    # Till done
130                 call putstr                     # End message
131 ')
132                 movl $0x48,%ecx                 # Allocate space
133                 subl %ecx,%ebp                  #  for bootinfo
134                 movl 0x18(%esp,1),%esi          # Source: bootinfo
135                 cmpl $0x0, %esi                 # If the bootinfo pointer
136                 je start_null_bi                #  is null, don't copy it
137                 movl %ebp,%edi                  # Destination
138                 rep                             # Copy
139                 movsb                           #  it
140                 movl %ebp,0x18(%esp,1)          # Update pointer
141 ifdef(`BTXLDR_VERBOSE',`
142                 movl $m_rel_bi,%esi             # Display
143                 movl %ebp,%eax                  #  bootinfo
144                 call hexout                     #  relocation
145                 call putstr                     #  message
146 ')
147 start_null_bi:  movl $0x18,%ecx                 # Allocate space
148                 subl %ecx,%ebp                  #  for arguments
149                 leal 0x4(%esp,1),%esi           # Source
150                 movl %ebp,%edi                  # Destination
151                 rep                             # Copy
152                 movsb                           #  them
153 ifdef(`BTXLDR_VERBOSE',`
154                 movl $m_rel_args,%esi           # Display
155                 movl %ebp,%eax                  #  argument
156                 call hexout                     #  relocation
157                 call putstr                     #  message
158 ')
159 #
160 # Set up BTX kernel.
161 #
162                 movl $MEM_ESP,%esp              # Set up new stack
163                 movl $MEM_DATA,%ebx             # Data segment
164                 movl $m_vers,%esi               # Display BTX
165                 call putstr                     #  version message
166                 movb 0x5(%ebx),%al              # Get major version
167                 addb $'0',%al                   # Display
168                 call putchr                     #  it
169                 movb $'.',%al                   # And a
170                 call putchr                     #  dot
171                 movb 0x6(%ebx),%al              # Get minor
172                 xorb %ah,%ah                    #  version
173                 movb $0xa,%dl                   # Divide
174                 divb %dl,%al                    #  by 10
175                 addb $'0',%al                   # Display
176                 call putchr                     #  tens
177                 movb %ah,%al                    # Get units
178                 addb $'0',%al                   # Display
179                 call putchr                     #  units
180                 call putstr                     # End message
181                 movl %ebx,%esi                  # BTX image
182                 movzwl 0x8(%ebx),%edi           # Compute
183                 orl $PAG_SIZ/PAG_ENT-1,%edi     #  the
184                 incl %edi                       #  BTX
185                 shll $0x2,%edi                  #  load
186                 addl $MEM_TBL,%edi              #  address
187                 pushl %edi                      # Save load address
188                 movzwl 0xa(%ebx),%ecx           # Image size
189 ifdef(`BTXLDR_VERBOSE',`
190                 pushl %ecx                      # Save image size
191 ')
192                 rep                             # Relocate
193                 movsb                           #  BTX
194                 movl %esi,%ebx                  # Keep place
195 ifdef(`BTXLDR_VERBOSE',`
196                 movl $m_rel_btx,%esi            # Restore
197                 popl %eax                       #  parameters
198                 call hexout                     #  and
199 ')
200                 popl %ebp                       #  display
201 ifdef(`BTXLDR_VERBOSE',`
202                 movl %ebp,%eax                  #  the
203                 call hexout                     #  relocation
204                 call putstr                     #  message
205 ')
206                 addl $PAG_SIZ,%ebp              # Display
207 ifdef(`BTXLDR_VERBOSE',`
208                 movl $m_base,%esi               #  the
209                 movl %ebp,%eax                  #  user
210                 call hexout                     #  base
211                 call putstr                     #  address
212 ')
213 #
214 # Set up ELF-format client program.
215 #
216                 cmpl $0x464c457f,(%ebx)         # ELF magic number?
217                 je start.3                      # Yes
218                 movl $e_fmt,%esi                # Display error
219                 call putstr                     #  message
220 start.2:        jmp start.2                     # Hang
221 start.3:
222 ifdef(`BTXLDR_VERBOSE',`
223                 movl $m_elf,%esi                # Display ELF
224                 call putstr                     #  message
225                 movl $m_segs,%esi               # Format string
226 ')
227                 movl $0x2,%edi                  # Segment count
228                 movl 0x1c(%ebx),%edx            # Get e_phoff
229                 addl %ebx,%edx                  # To pointer
230                 movzwl 0x2c(%ebx),%ecx          # Get e_phnum
231 start.4:        cmpl $0x1,(%edx)                # Is p_type PT_LOAD?
232                 jne start.6                     # No
233 ifdef(`BTXLDR_VERBOSE',`
234                 movl 0x4(%edx),%eax             # Display
235                 call hexout                     #  p_offset
236                 movl 0x8(%edx),%eax             # Display
237                 call hexout                     #  p_vaddr
238                 movl 0x10(%edx),%eax            # Display
239                 call hexout                     #  p_filesz
240                 movl 0x14(%edx),%eax            # Display
241                 call hexout                     #  p_memsz
242                 call putstr                     # End message
243 ')
244                 pushl %esi                      # Save
245                 pushl %edi                      #  working
246                 pushl %ecx                      #  registers
247                 movl 0x4(%edx),%esi             # Get p_offset
248                 addl %ebx,%esi                  #  as pointer
249                 movl 0x8(%edx),%edi             # Get p_vaddr
250                 addl %ebp,%edi                  #  as pointer
251                 movl 0x10(%edx),%ecx            # Get p_filesz
252                 rep                             # Set up
253                 movsb                           #  segment
254                 movl 0x14(%edx),%ecx            # Any bytes
255                 subl 0x10(%edx),%ecx            #  to zero?
256                 jz start.5                      # No
257                 xorb %al,%al                    # Then
258                 rep                             #  zero
259                 stosb                           #  them
260 start.5:        popl %ecx                       # Restore
261                 popl %edi                       #  working
262                 popl %esi                       #  registers
263                 decl %edi                       # Segments to do
264                 je start.7                      # If none
265 start.6:        addl $0x20,%edx                 # To next entry
266                 loop start.4                    # Till done
267 start.7:
268 ifdef(`BTXLDR_VERBOSE',`
269                 movl $m_done,%esi               # Display done
270                 call putstr                     #  message
271 ')
272                 movl $start.8,%esi              # Real mode stub
273                 movl $MEM_STUB,%edi             # Destination
274                 movl $start.9-start.8,%ecx      # Size
275                 rep                             # Relocate
276                 movsb                           #  it
277                 ljmp $SEL_RCODE,$MEM_STUB       # To 16-bit code
278                 .code16
279 start.8:        xorw %ax,%ax                    # Data
280                 movb $SEL_RDATA,%al             #  selector
281                 movw %ax,%ss                    # Reload SS
282                 movw %ax,%ds                    # Reset
283                 movw %ax,%es                    #  other
284                 movw %ax,%fs                    #  segment
285                 movw %ax,%gs                    #  limits
286                 movl %cr0,%eax                  # Switch to
287                 decw %ax                        #  real
288                 movl %eax,%cr0                  #  mode
289                 ljmp $0,$MEM_ENTRY              # Jump to BTX entry point
290 start.9:
291                 .code32
292 #
293 # Output message [ESI] followed by EAX in hex.
294 #
295 hexout:         pushl %eax                      # Save
296                 call putstr                     # Display message
297                 popl %eax                       # Restore
298                 pushl %esi                      # Save
299                 pushl %edi                      #  caller's
300                 movl $buf,%edi                  # Buffer
301                 pushl %edi                      # Save
302                 call hex32                      # To hex
303                 xorb %al,%al                    # Terminate
304                 stosb                           #  string
305                 popl %esi                       # Restore
306 hexout.1:       lodsb                           # Get a char
307                 cmpb $'0',%al                   # Leading zero?
308                 je hexout.1                     # Yes
309                 testb %al,%al                   # End of string?
310                 jne hexout.2                    # No
311                 decl %esi                       # Undo
312 hexout.2:       decl %esi                       # Adjust for inc
313                 call putstr                     # Display hex
314                 popl %edi                       # Restore
315                 popl %esi                       #  caller's
316                 ret                             # To caller
317 #
318 # Output zero-terminated string [ESI] to the console.
319 #
320 putstr.0:       call putchr                     # Output char
321 putstr:         lodsb                           # Load char
322                 testb %al,%al                   # End of string?
323                 jne putstr.0                    # No
324                 ret                             # To caller
325 #
326 # Output character AL to the console.
327 #
328 putchr:         pusha                           # Save
329                 xorl %ecx,%ecx                  # Zero for loops
330                 movb $SCR_MAT,%ah               # Mode/attribute
331                 movl $BDA_POS,%ebx              # BDA pointer
332                 movw (%ebx),%dx                 # Cursor position
333 ifdef(`PC98',`
334                 movl $0xa0000,%edi              # Regen buffer (color)
335 ',`
336                 movl $0xb8000,%edi              # Regen buffer (color)
337                 cmpb %ah,BDA_SCR-BDA_POS(%ebx)  # Mono mode?
338                 jne putchr.1                    # No
339                 xorw %di,%di                    # Regen buffer (mono)
340 ')
341 putchr.1:       cmpb $0xa,%al                   # New line?
342                 je putchr.2                     # Yes
343 ifdef(`PC98',`
344                 movw %dx,%cx
345                 movb %al,(%edi,%ecx,1)          # Write char
346                 addl $0x2000,%ecx
347                 movb %ah,(%edi,%ecx,1)          # Write attr
348                 addw $0x2,%dx
349                 jmp putchr.3
350 putchr.2:       movw %dx,%ax
351                 movb $SCR_COL*2,%dl
352                 div %dl
353                 incb %al
354                 mul %dl
355                 movw %ax,%dx
356 putchr.3:       cmpw $SCR_COL*SCR_ROW*2,%dx
357 ',`
358                 xchgl %eax,%ecx                 # Save char
359                 movb $SCR_COL,%al               # Columns per row
360                 mulb %dh                        #  * row position
361                 addb %dl,%al                    #  + column
362                 adcb $0x0,%ah                   #  position
363                 shll %eax                       #  * 2
364                 xchgl %eax,%ecx                 # Swap char, offset
365                 movw %ax,(%edi,%ecx,1)          # Write attr:char
366                 incl %edx                       # Bump cursor
367                 cmpb $SCR_COL,%dl               # Beyond row?
368                 jb putchr.3                     # No
369 putchr.2:       xorb %dl,%dl                    # Zero column
370                 incb %dh                        # Bump row
371 putchr.3:       cmpb $SCR_ROW,%dh               # Beyond screen?
372 ')
373                 jb putchr.4                     # No
374                 leal 2*SCR_COL(%edi),%esi       # New top line
375                 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
376                 rep                             # Scroll
377                 movsl                           #  screen
378                 movb $' ',%al                   # Space
379 ifdef(`PC98',`
380                 xorb %ah,%ah
381 ')
382                 movb $SCR_COL,%cl               # Columns to clear
383                 rep                             # Clear
384                 stosw                           #  line
385 ifdef(`PC98',`
386                 movw $(SCR_ROW-1)*SCR_COL*2,%dx
387 putchr.4:       movw %dx,(%ebx)                 # Update position
388                 shrw $1,%dx
389 gdcwait.3:      inb $0x60,%al
390                 testb $0x04,%al
391                 jz gdcwait.3
392                 movb $0x49,%al
393                 outb %al,$0x62
394                 movb %dl,%al
395                 outb %al,$0x60
396                 movb %dh,%al
397                 outb %al,$0x60
398 ',`
399                 movb $SCR_ROW-1,%dh             # Bottom line
400 putchr.4:       movw %dx,(%ebx)                 # Update position
401 ')
402                 popa                            # Restore
403                 ret                             # To caller
404 #
405 # Convert EAX, AX, or AL to hex, saving the result to [EDI].
406 #
407 hex32:          pushl %eax                      # Save
408                 shrl $0x10,%eax                 # Do upper
409                 call hex16                      #  16
410                 popl %eax                       # Restore
411 hex16:          call hex16.1                    # Do upper 8
412 hex16.1:        xchgb %ah,%al                   # Save/restore
413 hex8:           pushl %eax                      # Save
414                 shrb $0x4,%al                   # Do upper
415                 call hex8.1                     #  4
416                 popl %eax                       # Restore
417 hex8.1:         andb $0xf,%al                   # Get lower 4
418                 cmpb $0xa,%al                   # Convert
419                 sbbb $0x69,%al                  #  to hex
420                 das                             #  digit
421                 orb $0x20,%al                   # To lower case
422                 stosb                           # Save char
423                 ret                             # (Recursive)
424
425                 .data
426                 .p2align 4
427 #
428 # Global descriptor table.
429 #
430 gdt:            .word 0x0,0x0,0x0,0x0           # Null entry
431                 .word 0xffff,0x0,0x9a00,0xcf    # SEL_SCODE
432                 .word 0xffff,0x0,0x9200,0xcf    # SEL_SDATA
433                 .word 0xffff,0x0,0x9a00,0x0     # SEL_RCODE
434                 .word 0xffff,0x0,0x9200,0x0     # SEL_RDATA
435 gdt.1:
436 gdtdesc:        .word gdt.1-gdt-1               # Limit
437                 .long gdt                       # Base
438 #
439 # Messages.
440 #
441 m_logo:         .asciz " \nBTX loader 1.00  "
442 m_vers:         .asciz "BTX version is \0\n"
443 e_fmt:          .asciz "Error: Client format not supported\n"
444 ifdef(`BTXLDR_VERBOSE',`
445 m_mem:          .asciz "Starting in protected mode (base mem=\0)\n"
446 m_esp:          .asciz "Arguments passed (esp=\0):\n"
447 m_args:         .asciz"<howto="
448                 .asciz" bootdev="
449                 .asciz" junk="
450                 .asciz" "
451                 .asciz" "
452                 .asciz" bootinfo=\0>\n"
453 m_rel_bi:       .asciz "Relocated bootinfo (size=48) to \0\n"
454 m_rel_args:     .asciz "Relocated arguments (size=18) to \0\n"
455 m_rel_btx:      .asciz "Relocated kernel (size=\0) to \0\n"
456 m_base:         .asciz "Client base address is \0\n"
457 m_elf:          .asciz "Client format is ELF\n"
458 m_segs:         .asciz "text segment: offset="
459                 .asciz " vaddr="
460                 .asciz " filesz="
461                 .asciz " memsz=\0\n"
462                 .asciz "data segment: offset="
463                 .asciz " vaddr="
464                 .asciz " filesz="
465                 .asciz " memsz=\0\n"
466 m_done:         .asciz "Loading complete\n"
467 ')
468 #
469 # Uninitialized data area.
470 #
471 buf:                                            # Scratch buffer