Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / boot / i386 / 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/i386/btx/btxldr/btxldr.s,v 1.8.2.2 2000/07/06 23:04:29 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                 .set SCR_MAT,0x7                # Mode/attribute
47                 .set SCR_COL,0x50               # Columns per row
48                 .set SCR_ROW,0x19               # Rows per screen
49 #
50 # BIOS Data Area locations.
51 #
52                 .set BDA_MEM,0x413              # Free memory
53                 .set BDA_SCR,0x449              # Video mode
54                 .set BDA_POS,0x450              # Cursor position
55 #
56 # Required by aout gas inadequacy.
57 #
58                 .set SIZ_STUB,0x1a              # Size of stub
59 #
60 # We expect to be loaded by boot2 at the origin defined in ./Makefile.
61 #
62                 .globl start
63 #
64 # BTX program loader for ELF clients.
65 #
66 start:          cld                             # String ops inc
67                 movl $m_logo,%esi               # Identify
68                 call putstr                     #  ourselves
69                 movzwl BDA_MEM,%eax             # Get base memory
70                 shll $0xa,%eax                  #  in bytes
71                 movl %eax,%ebp                  # Base of user stack
72 ifdef(`BTXLDR_VERBOSE',`
73                 movl $m_mem,%esi                # Display
74                 call hexout                     #  amount of
75                 call putstr                     #  base memory
76 ')
77                 lgdt gdtdesc                    # Load new GDT
78 #
79 # Relocate caller's arguments.
80 #
81 ifdef('BTXLDR_VERBOSE',`
82                 movl $m_esp,%esi                # Display
83                 movl %esp,%eax                  #  caller
84                 call hexout                     #  stack
85                 call putstr                     #  pointer
86                 movl $m_args,%esi               # Format string
87                 leal 0x4(%esp,1),%ebx           # First argument
88                 movl $0x6,%ecx                  # Count
89 start.1:        movl (%ebx),%eax                # Get argument and
90                 addl $0x4,%ebx                  #  bump pointer
91                 call hexout                     # Display it
92                 loop start.1                    # Till done
93                 call putstr                     # End message
94 ')
95                 movl $0x48,%ecx                 # Allocate space
96                 subl %ecx,%ebp                  #  for bootinfo
97                 movl 0x18(%esp,1),%esi          # Source: bootinfo
98                 cmpl $0x0, %esi                 # If the bootinfo pointer
99                 je start_null_bi                #  is null, don't copy it
100                 movl %ebp,%edi                  # Destination
101                 rep                             # Copy
102                 movsb                           #  it
103                 movl %ebp,0x18(%esp,1)          # Update pointer
104 ifdef(`BTXLDR_VERBOSE',`
105                 movl $m_rel_bi,%esi             # Display
106                 movl %ebp,%eax                  #  bootinfo
107                 call hexout                     #  relocation
108                 call putstr                     #  message
109 ')
110 start_null_bi:  movl $0x18,%ecx                 # Allocate space
111                 subl %ecx,%ebp                  #  for arguments
112                 leal 0x4(%esp,1),%esi           # Source
113                 movl %ebp,%edi                  # Destination
114                 rep                             # Copy
115                 movsb                           #  them
116 ifdef(`BTXLDR_VERBOSE',`
117                 movl $m_rel_args,%esi           # Display
118                 movl %ebp,%eax                  #  argument
119                 call hexout                     #  relocation
120                 call putstr                     #  message
121 ')
122 #
123 # Set up BTX kernel.
124 #
125                 movl $MEM_ESP,%esp              # Set up new stack
126                 movl $MEM_DATA,%ebx             # Data segment
127                 movl $m_vers,%esi               # Display BTX
128                 call putstr                     #  version message
129                 movb 0x5(%ebx),%al              # Get major version
130                 addb $'0',%al                   # Display
131                 call putchr                     #  it
132                 movb $'.',%al                   # And a
133                 call putchr                     #  dot
134                 movb 0x6(%ebx),%al              # Get minor
135                 xorb %ah,%ah                    #  version
136                 movb $0xa,%dl                   # Divide
137                 divb %dl,%al                    #  by 10
138                 addb $'0',%al                   # Display
139                 call putchr                     #  tens
140                 movb %ah,%al                    # Get units
141                 addb $'0',%al                   # Display
142                 call putchr                     #  units
143                 call putstr                     # End message
144                 movl %ebx,%esi                  # BTX image
145                 movzwl 0x8(%ebx),%edi           # Compute
146                 orl $PAG_SIZ/PAG_ENT-1,%edi     #  the
147                 incl %edi                       #  BTX
148                 shll $0x2,%edi                  #  load
149                 addl $MEM_TBL,%edi              #  address
150                 pushl %edi                      # Save load address
151                 movzwl 0xa(%ebx),%ecx           # Image size
152 ifdef(`BTXLDR_VERBOSE',`
153                 pushl %ecx                      # Save image size
154 ')
155                 rep                             # Relocate
156                 movsb                           #  BTX
157                 movl %esi,%ebx                  # Keep place
158 ifdef(`BTXLDR_VERBOSE',`
159                 movl $m_rel_btx,%esi            # Restore
160                 popl %eax                       #  parameters
161                 call hexout                     #  and
162 ')
163                 popl %ebp                       #  display
164 ifdef(`BTXLDR_VERBOSE',`
165                 movl %ebp,%eax                  #  the
166                 call hexout                     #  relocation
167                 call putstr                     #  message
168 ')
169                 addl $PAG_SIZ,%ebp              # Display
170 ifdef(`BTXLDR_VERBOSE',`
171                 movl $m_base,%esi               #  the
172                 movl %ebp,%eax                  #  user
173                 call hexout                     #  base
174                 call putstr                     #  address
175 ')
176 #
177 # Set up ELF-format client program.
178 #
179                 cmpl $0x464c457f,(%ebx)         # ELF magic number?
180                 je start.3                      # Yes
181                 movl $e_fmt,%esi                # Display error
182                 call putstr                     #  message
183 start.2:        jmp start.2                     # Hang
184 start.3:
185 ifdef(`BTXLDR_VERBOSE',`
186                 movl $m_elf,%esi                # Display ELF
187                 call putstr                     #  message
188                 movl $m_segs,%esi               # Format string
189 ')
190                 movl $0x2,%edi                  # Segment count
191                 movl 0x1c(%ebx),%edx            # Get e_phoff
192                 addl %ebx,%edx                  # To pointer
193                 movzwl 0x2c(%ebx),%ecx          # Get e_phnum
194 start.4:        cmpl $0x1,(%edx)                # Is p_type PT_LOAD?
195                 jne start.6                     # No
196 ifdef(`BTXLDR_VERBOSE',`
197                 movl 0x4(%edx),%eax             # Display
198                 call hexout                     #  p_offset
199                 movl 0x8(%edx),%eax             # Display
200                 call hexout                     #  p_vaddr
201                 movl 0x10(%edx),%eax            # Display
202                 call hexout                     #  p_filesz
203                 movl 0x14(%edx),%eax            # Display
204                 call hexout                     #  p_memsz
205                 call putstr                     # End message
206 ')
207                 pushl %esi                      # Save
208                 pushl %edi                      #  working
209                 pushl %ecx                      #  registers
210                 movl 0x4(%edx),%esi             # Get p_offset
211                 addl %ebx,%esi                  #  as pointer
212                 movl 0x8(%edx),%edi             # Get p_vaddr
213                 addl %ebp,%edi                  #  as pointer
214                 movl 0x10(%edx),%ecx            # Get p_filesz
215                 rep                             # Set up
216                 movsb                           #  segment
217                 movl 0x14(%edx),%ecx            # Any bytes
218                 subl 0x10(%edx),%ecx            #  to zero?
219                 jz start.5                      # No
220                 xorb %al,%al                    # Then
221                 rep                             #  zero
222                 stosb                           #  them
223 start.5:        popl %ecx                       # Restore
224                 popl %edi                       #  working
225                 popl %esi                       #  registers
226                 decl %edi                       # Segments to do
227                 je start.7                      # If none
228 start.6:        addl $0x20,%edx                 # To next entry
229                 loop start.4                    # Till done
230 start.7:
231 ifdef(`BTXLDR_VERBOSE',`
232                 movl $m_done,%esi               # Display done
233                 call putstr                     #  message
234 ')
235                 movl $start.8,%esi              # Real mode stub
236                 movl $MEM_STUB,%edi             # Destination
237                 movl $start.9-start.8,%ecx      # Size
238                 rep                             # Relocate
239                 movsb                           #  it
240                 ljmp $SEL_RCODE,$MEM_STUB       # To 16-bit code
241                 .code16
242 start.8:        xorw %ax,%ax                    # Data
243                 movb $SEL_RDATA,%al             #  selector
244                 movw %ax,%ss                    # Reload SS
245                 movw %ax,%ds                    # Reset
246                 movw %ax,%es                    #  other
247                 movw %ax,%fs                    #  segment
248                 movw %ax,%gs                    #  limits
249                 movl %cr0,%eax                  # Switch to
250                 decw %ax                        #  real
251                 movl %eax,%cr0                  #  mode
252                 ljmp $0,$MEM_ENTRY              # Jump to BTX entry point
253 start.9:
254                 .code32
255 #
256 # Output message [ESI] followed by EAX in hex.
257 #
258 hexout:         pushl %eax                      # Save
259                 call putstr                     # Display message
260                 popl %eax                       # Restore
261                 pushl %esi                      # Save
262                 pushl %edi                      #  caller's
263                 movl $buf,%edi                  # Buffer
264                 pushl %edi                      # Save
265                 call hex32                      # To hex
266                 xorb %al,%al                    # Terminate
267                 stosb                           #  string
268                 popl %esi                       # Restore
269 hexout.1:       lodsb                           # Get a char
270                 cmpb $'0',%al                   # Leading zero?
271                 je hexout.1                     # Yes
272                 testb %al,%al                   # End of string?
273                 jne hexout.2                    # No
274                 decl %esi                       # Undo
275 hexout.2:       decl %esi                       # Adjust for inc
276                 call putstr                     # Display hex
277                 popl %edi                       # Restore
278                 popl %esi                       #  caller's
279                 ret                             # To caller
280 #
281 # Output zero-terminated string [ESI] to the console.
282 #
283 putstr.0:       call putchr                     # Output char
284 putstr:         lodsb                           # Load char
285                 testb %al,%al                   # End of string?
286                 jne putstr.0                    # No
287                 ret                             # To caller
288 #
289 # Output character AL to the console.
290 #
291 putchr:         pusha                           # Save
292                 xorl %ecx,%ecx                  # Zero for loops
293                 movb $SCR_MAT,%ah               # Mode/attribute
294                 movl $BDA_POS,%ebx              # BDA pointer
295                 movw (%ebx),%dx                 # Cursor position
296                 movl $0xb8000,%edi              # Regen buffer (color)
297                 cmpb %ah,BDA_SCR-BDA_POS(%ebx)  # Mono mode?
298                 jne putchr.1                    # No
299                 xorw %di,%di                    # Regen buffer (mono)
300 putchr.1:       cmpb $0xa,%al                   # New line?
301                 je putchr.2                     # Yes
302                 xchgl %eax,%ecx                 # Save char
303                 movb $SCR_COL,%al               # Columns per row
304                 mulb %dh                        #  * row position
305                 addb %dl,%al                    #  + column
306                 adcb $0x0,%ah                   #  position
307                 shll %eax                       #  * 2
308                 xchgl %eax,%ecx                 # Swap char, offset
309                 movw %ax,(%edi,%ecx,1)          # Write attr:char
310                 incl %edx                       # Bump cursor
311                 cmpb $SCR_COL,%dl               # Beyond row?
312                 jb putchr.3                     # No
313 putchr.2:       xorb %dl,%dl                    # Zero column
314                 incb %dh                        # Bump row
315 putchr.3:       cmpb $SCR_ROW,%dh               # Beyond screen?
316                 jb putchr.4                     # No
317                 leal 2*SCR_COL(%edi),%esi       # New top line
318                 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
319                 rep                             # Scroll
320                 movsl                           #  screen
321                 movb $' ',%al                   # Space
322                 movb $SCR_COL,%cl               # Columns to clear
323                 rep                             # Clear
324                 stosw                           #  line
325                 movb $SCR_ROW-1,%dh             # Bottom line
326 putchr.4:       movw %dx,(%ebx)                 # Update position
327                 popa                            # Restore
328                 ret                             # To caller
329 #
330 # Convert EAX, AX, or AL to hex, saving the result to [EDI].
331 #
332 hex32:          pushl %eax                      # Save
333                 shrl $0x10,%eax                 # Do upper
334                 call hex16                      #  16
335                 popl %eax                       # Restore
336 hex16:          call hex16.1                    # Do upper 8
337 hex16.1:        xchgb %ah,%al                   # Save/restore
338 hex8:           pushl %eax                      # Save
339                 shrb $0x4,%al                   # Do upper
340                 call hex8.1                     #  4
341                 popl %eax                       # Restore
342 hex8.1:         andb $0xf,%al                   # Get lower 4
343                 cmpb $0xa,%al                   # Convert
344                 sbbb $0x69,%al                  #  to hex
345                 das                             #  digit
346                 orb $0x20,%al                   # To lower case
347                 stosb                           # Save char
348                 ret                             # (Recursive)
349
350                 .data
351                 .p2align 4
352 #
353 # Global descriptor table.
354 #
355 gdt:            .word 0x0,0x0,0x0,0x0           # Null entry
356                 .word 0xffff,0x0,0x9a00,0xcf    # SEL_SCODE
357                 .word 0xffff,0x0,0x9200,0xcf    # SEL_SDATA
358                 .word 0xffff,0x0,0x9a00,0x0     # SEL_RCODE
359                 .word 0xffff,0x0,0x9200,0x0     # SEL_RDATA
360 gdt.1:
361 gdtdesc:        .word gdt.1-gdt-1               # Limit
362                 .long gdt                       # Base
363 #
364 # Messages.
365 #
366 m_logo:         .asciz " \nBTX loader 1.00  "
367 m_vers:         .asciz "BTX version is \0\n"
368 e_fmt:          .asciz "Error: Client format not supported\n"
369 ifdef(`BTXLDR_VERBOSE',`
370 m_mem:          .asciz "Starting in protected mode (base mem=\0)\n"
371 m_esp:          .asciz "Arguments passed (esp=\0):\n"
372 m_args:         .asciz"<howto="
373                 .asciz" bootdev="
374                 .asciz" junk="
375                 .asciz" "
376                 .asciz" "
377                 .asciz" bootinfo=\0>\n"
378 m_rel_bi:       .asciz "Relocated bootinfo (size=48) to \0\n"
379 m_rel_args:     .asciz "Relocated arguments (size=18) to \0\n"
380 m_rel_btx:      .asciz "Relocated kernel (size=\0) to \0\n"
381 m_base:         .asciz "Client base address is \0\n"
382 m_elf:          .asciz "Client format is ELF\n"
383 m_segs:         .asciz "text segment: offset="
384                 .asciz " vaddr="
385                 .asciz " filesz="
386                 .asciz " memsz=\0\n"
387                 .asciz "data segment: offset="
388                 .asciz " vaddr="
389                 .asciz " filesz="
390                 .asciz " memsz=\0\n"
391 m_done:         .asciz "Loading complete\n"
392 ')
393 #
394 # Uninitialized data area.
395 #
396 buf:                                            # Scratch buffer