xref: /dragonfly/stand/boot/pc32/btx/btxldr/btxldr.S (revision 479ab7f0492f2a51b48e8537e4f1dc686fc6014b)
1/*
2 * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 *    contributors may be used to endorse or promote products derived
19 *    from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * Copyright (c) 1998 Robert Nordier
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms are freely
38 * permitted provided that the above copyright notice and this
39 * paragraph and the following disclaimer are duplicated in all
40 * such forms.
41 *
42 * This software is provided "AS IS" and without any express or
43 * implied warranties, including, without limitation, the implied
44 * warranties of merchantability and fitness for a particular
45 * purpose.
46 *
47 * $FreeBSD: src/sys/boot/i386/btx/btxldr/Makefile,v 1.17 2004/04/27 19:45:16 ru Exp $
48 * $DragonFly: src/sys/boot/pc32/btx/btxldr/btxldr.S,v 1.3 2004/07/19 23:30:34 dillon Exp $
49 */
50
51/*
52 * Prototype BTX loader program, written in a couple of hours.  The
53 * real thing should probably be more flexible, and in C.
54 */
55
56#include "../../bootasm.h"
57/*
58 * Memory locations.
59 */
60                    .set MEM_DATA,start+0x1000    # Data segment
61/*
62 * Segment selectors.
63 */
64                    .set SEL_SCODE,0x8            # 4GB code
65                    .set SEL_SDATA,0x10           # 4GB data
66                    .set SEL_RCODE,0x18           # 64K code
67                    .set SEL_RDATA,0x20           # 64K data
68/*
69 * Paging constants.
70 */
71                    .set PAG_SIZ,0x1000           # Page size
72                    .set PAG_ENT,0x4              # Page entry size
73/*
74 * Screen constants.
75 */
76                    .set SCR_MAT,0x7              # Mode/attribute
77                    .set SCR_COL,0x50             # Columns per row
78                    .set SCR_ROW,0x19             # Rows per screen
79/*
80 * Required by aout gas inadequacy.
81 */
82                    .set SIZ_STUB,0x1a            # Size of stub
83/*
84 * We expect to be loaded by boot2 at the origin defined in ./Makefile.
85 * This is typically 0x200000.
86 *
87 * I *THINK* (not sure) that execution begins with us in 'virtual mode',
88 * meaning everything is offset by MEM_BTX_USR.  We will load a gdt to
89 * set the base offsets back to 0.
90 */
91                    .globl start
92/*
93 * BTX program loader for ELF clients.
94 */
95start:              cld                                     # String ops inc
96                    movl $m_logo,%esi             # Identify
97                    call putstr                             #  ourselves
98#if !defined(MEM_BTX_USR_STK)
99                    movzwl BDA_MEM,%eax           # Get base memory
100                    decl %eax
101                    shll $0xa,%eax                          # Convert to bytes
102#else
103                    movl $MEM_BTX_USR_STK,%eax
104#endif
105                    movl %eax,%ebp                          # Base of user stack
106#ifdef BTXLDR_VERBOSE
107                    movl $m_mem,%esi              # Display
108                    call hexout                             #  amount of
109                    call putstr                             #  base memory
110#endif
111
112                    /*
113                     * Load a new GDT.  XXX what does this do to running code
114                     * segments?  What if an interrupt occurs?  What if the
115                     * segment registers are reloaded?
116                     */
117                    lgdt gdtdesc
118
119                    /*
120                     * Relocate caller's arguments.
121                     */
122#ifdef BTXLDR_VERBOSE
123                    movl $m_esp,%esi              # Display
124                    movl %esp,%eax                          #  caller
125                    call hexout                             #  stack
126                    call putstr                             #  pointer
127                    movl $m_args,%esi             # Format string
128                    leal 0x4(%esp,1),%ebx                   # First argument
129                    movl $0x6,%ecx                          # Count
130start.1:  movl (%ebx),%eax              # Get argument and
131                    addl $0x4,%ebx                          #  bump pointer
132                    call hexout                             # Display it
133                    loop start.1                            # Till done
134                    call putstr                             # End message
135#endif
136                    /*
137                     * Arguments: (entry, boothowto, bootdev, 0, 0, 0, bootinfo)
138                     *                  0x00,  0x04,      0x08,             0x18
139                     *
140                     * sizeof(bootinfo) == 0x48 (BOOTINFO_SIZE)
141                     * sizeof arguments == 0x18 (MEM_ARG_SIZE)
142                     * total arguments  == 0x60 bytes (USR_ARGOFFSET)
143                     */
144
145                    movl $BOOTINFO_SIZE,%ecx      # Allocate space
146                    subl %ecx,%ebp                          #  for bootinfo
147                    movl 0x18(%esp,1),%esi                  # Source: bootinfo
148                    cmpl $0x0, %esi                         # If the bootinfo pointer
149                    je start_null_bi              #  is null, do not copy it
150                    movl %ebp,%edi                          # Destination
151                    rep                                     # Copy
152                    movsb                                   #  it
153                    movl %ebp,0x18(%esp,1)                  # Update pointer
154#ifdef BTXLDR_VERBOSE
155                    movl $m_rel_bi,%esi           # Display
156                    movl %ebp,%eax                          #  bootinfo
157                    call hexout                             #  relocation
158                    call putstr                             #  message
159#endif
160start_null_bi:      movl $0x18,%ecx               # Allocate space
161                    subl %ecx,%ebp                          #  for arguments
162                    leal 0x4(%esp,1),%esi                   # Source
163                    movl %ebp,%edi                          # Destination
164                    rep                                     # Copy
165                    movsb                                   #  them
166#ifdef BTXLDR_VERBOSE
167                    movl $m_rel_args,%esi                   # Display
168                    movl %ebp,%eax                          #  argument
169                    call hexout                             #  relocation
170                    call putstr                             #  message
171#endif
172/*
173 * Set up BTX kernel.
174 */
175                    movl $MEM_BTX_ESP,%esp                  # Set up new stack
176                    movl $MEM_DATA,%ebx           # Data segment
177                    movl $m_vers,%esi             # Display BTX
178                    call putstr                             #  version message
179                    movb 0x5(%ebx),%al            # Get major version
180                    addb $'0',%al                           # Display
181                    call putchr                             #  it
182                    movb $'.',%al                           # And a
183                    call putchr                             #  dot
184                    movb 0x6(%ebx),%al            # Get minor
185                    xorb %ah,%ah                            #  version
186                    movb $0xa,%dl                           # Divide
187                    divb %dl,%al                            #  by 10
188                    addb $'0',%al                           # Display
189                    call putchr                             #  tens
190                    movb %ah,%al                            # Get units
191                    addb $'0',%al                           # Display
192                    call putchr                             #  units
193                    call putstr                             # End message
194
195                    # Relocate the BTX image from wherever it was loaded (%ebx),
196                    # which is typically offset 0x1000 in the load data, to
197                    # MEM_BTX_ORG (typically 0x9000).
198                    #
199                    # MEM_BTX_TBL + ((mappages | 0x3ff) + 1) * 4
200                    # mappages is typically 0x0ffn so we get 0x1000*4 = 0x4000
201                    # MEM_BTX_TBL is traditionally mapped at 0x5000 so the
202                    # whole calculation translated to MEM_BTX_ORG (0x9000).
203#if 0
204                    /* XXX what is all of this junk? */
205                    movzwl 0x8(%ebx),%edi                   # Compute the BTX load address
206                    orl $PAG_SIZ/PAG_ENT-1,%edi   # (by skipping the page table)
207                    incl %edi
208                    shll $0x2,%edi
209                    addl $MEM_BTX_TBL,%edi
210#else
211                    movl $MEM_BTX_ORG,%edi
212#endif
213                    movl %ebx,%esi                          # %esi = BTX image source
214                    pushl %edi                              # Save load address
215                    movzwl 0xa(%ebx),%ecx                   # Image size (bytes)
216#ifdef BTXLDR_VERBOSE
217                    pushl %ecx                              # Save image size
218#endif
219                    rep                                     # Relocate BTX
220                    movsb
221                    movl %esi,%ebx                          # Keep place
222#ifdef BTXLDR_VERBOSE
223                    movl $m_rel_btx,%esi                    # Restore
224                    popl %eax                     #  parameters
225                    call hexout                             #  and
226#endif
227                    popl %ebp                     #  display
228#ifdef BTXLDR_VERBOSE
229                    movl %ebp,%eax                          #  the
230                    call hexout                             #  relocation
231                    call putstr                             #  message
232#endif
233                    /*
234                     * ADJUST EBP FOR USER BASE ADDRESS
235                     *
236                     * XXX why not just move MEM_BTX_USR into %ebp ?
237                     */
238                    addl $MEM_BTX_USR-MEM_BTX_ORG,%ebp
239#ifdef BTXLDR_VERBOSE
240                    movl $m_base,%esi             #  the
241                    movl %ebp,%eax                          #  user
242                    call hexout                             #  base
243                    call putstr                             #  address
244#endif
245/*
246 * Set up ELF-format client program.
247 */
248                    cmpl $0x464c457f,(%ebx)       # ELF magic number?
249                    je start.3                              # Yes
250                    movl $e_fmt,%esi              # Display error
251                    call putstr                             #  message
252start.2:  jmp start.2                             # Hang
253start.3:
254#ifdef BTXLDR_VERBOSE
255                    movl $m_elf,%esi              # Display ELF
256                    call putstr                             #  message
257                    movl $m_segs,%esi             # Format string
258#endif
259                    movl $0x2,%edi                          # Segment count
260                    movl 0x1c(%ebx),%edx                    # Get e_phoff
261                    addl %ebx,%edx                          # To pointer
262                    movzwl 0x2c(%ebx),%ecx                  # Get e_phnum
263start.4:  cmpl $0x1,(%edx)              # Is p_type PT_LOAD?
264                    jne start.6                             # No
265#ifdef BTXLDR_VERBOSE
266                    movl 0x4(%edx),%eax           # Display
267                    call hexout                             #  p_offset
268                    movl 0x8(%edx),%eax           # Display
269                    call hexout                             #  p_vaddr
270                    movl 0x10(%edx),%eax                    # Display
271                    call hexout                             #  p_filesz
272                    movl 0x14(%edx),%eax                    # Display
273                    call hexout                             #  p_memsz
274                    call putstr                             # End message
275#endif
276                    pushl %esi                              # Save
277                    pushl %edi                              #  working
278                    pushl %ecx                              #  registers
279                    movl 0x4(%edx),%esi           # Get p_offset
280                    addl %ebx,%esi                          #  as pointer
281                    movl 0x8(%edx),%edi           # Get p_vaddr
282                    addl %ebp,%edi                          #  as pointer
283                    movl 0x10(%edx),%ecx                    # Get p_filesz
284                    rep                                     # Set up
285                    movsb                                   #  segment
286                    movl 0x14(%edx),%ecx                    # Any bytes
287                    subl 0x10(%edx),%ecx                    #  to zero?
288                    jz start.5                              # No
289                    xorb %al,%al                            # Then
290                    rep                                     #  zero
291                    stosb                                   #  them
292start.5:  popl %ecx                     # Restore
293                    popl %edi                     #  working
294                    popl %esi                     #  registers
295                    decl %edi                     # Segments to do
296                    je start.7                              # If none
297start.6:  addl $0x20,%edx               # To next entry
298                    loop start.4                            # Till done
299start.7:
300#ifdef BTXLDR_VERBOSE
301                    movl $m_done,%esi             # Display done
302                    call putstr                             #  message
303#endif
304                    movl $start.8,%esi            # Real mode stub
305                    movl $BOOT0_ORIGIN,%edi                 # Destination
306                    movl $start.9-start.8,%ecx    # Size
307                    rep                                     # Relocate
308                    movsb                                   #  it
309                    ljmp $SEL_RCODE,$BOOT0_ORIGIN # To 16-bit code
310                    .code16
311start.8:  xorw %ax,%ax                            # Data
312                    movb $SEL_RDATA,%al           #  selector
313                    movw %ax,%ss                            # Reload SS
314                    movw %ax,%ds                            # Reset
315                    movw %ax,%es                            #  other
316                    movw %ax,%fs                            #  segment
317                    movw %ax,%gs                            #  limits
318                    movl %cr0,%eax                          # Switch to
319                    decw %ax                      #  real
320                    movl %eax,%cr0                          #  mode
321                    ljmp $0,$MEM_BTX_ENTRY                  # Jump to BTX entry point
322start.9:
323                    .code32
324/*
325 * Output message [ESI] followed by EAX in hex.
326 */
327hexout:   pushl %eax                              # Save
328                    call putstr                             # Display message
329                    popl %eax                     # Restore
330                    pushl %esi                              # Save
331                    pushl %edi                              # callers
332                    movl $buf,%edi                          # Buffer
333                    pushl %edi                              # Save
334                    call hex32                              # To hex
335                    xorb %al,%al                            # Terminate
336                    stosb                                   #  string
337                    popl %esi                     # Restore
338hexout.1: lodsb                                   # Get a char
339                    cmpb $'0',%al                           # Leading zero?
340                    je hexout.1                             # Yes
341                    testb %al,%al                           # End of string?
342                    jne hexout.2                            # No
343                    decl %esi                     # Undo
344hexout.2: decl %esi                     # Adjust for inc
345                    call putstr                             # Display hex
346                    popl %edi                     # Restore
347                    popl %esi                     # callers
348                    ret                                     # To caller
349/*
350 * Output zero-terminated string [ESI] to the console.
351 */
352putstr.0: call putchr                             # Output char
353putstr:   lodsb                                   # Load char
354                    testb %al,%al                           # End of string?
355                    jne putstr.0                            # No
356                    ret                                     # To caller
357/*
358 * Output character AL to the console.
359 */
360putchr:   pusha                                   # Save
361                    xorl %ecx,%ecx                          # Zero for loops
362                    movb $SCR_MAT,%ah             # Mode/attribute
363                    movl $BDA_POS,%ebx            # BDA pointer
364                    movw (%ebx),%dx               # Cursor position
365                    movl $0xb8000,%edi            # Regen buffer (color)
366                    cmpb %ah,BDA_SCR-BDA_POS(%ebx)          # Mono mode?
367                    jne putchr.1                            # No
368                    xorw %di,%di                            # Regen buffer (mono)
369putchr.1: cmpb $0xa,%al                           # New line?
370                    je putchr.2                             # Yes
371                    xchgl %eax,%ecx               # Save char
372                    movb $SCR_COL,%al             # Columns per row
373                    mulb %dh                      #  * row position
374                    addb %dl,%al                            #  + column
375                    adcb $0x0,%ah                           #  position
376                    shll %eax                     #  * 2
377                    xchgl %eax,%ecx               # Swap char, offset
378                    movw %ax,(%edi,%ecx,1)                  # Write attr:char
379                    incl %edx                     # Bump cursor
380                    cmpb $SCR_COL,%dl             # Beyond row?
381                    jb putchr.3                             # No
382putchr.2: xorb %dl,%dl                            # Zero column
383                    incb %dh                      # Bump row
384putchr.3: cmpb $SCR_ROW,%dh             # Beyond screen?
385                    jb putchr.4                             # No
386                    leal 2*SCR_COL(%edi),%esi     # New top line
387                    movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
388                    rep                                     # Scroll
389                    movsl                                   #  screen
390                    movb $' ',%al                           # Space
391                    movb $SCR_COL,%cl             # Columns to clear
392                    rep                                     # Clear
393                    stosw                                   #  line
394                    movb $SCR_ROW-1,%dh           # Bottom line
395putchr.4: movw %dx,(%ebx)               # Update position
396                    popa                                    # Restore
397                    ret                                     # To caller
398/*
399 * Convert EAX, AX, or AL to hex, saving the result to [EDI].
400 */
401hex32:              pushl %eax                              # Save
402                    shrl $0x10,%eax               # Do upper
403                    call hex16                              #  16
404                    popl %eax                     # Restore
405hex16:              call hex16.1                            # Do upper 8
406hex16.1:  xchgb %ah,%al                           # Save/restore
407hex8:               pushl %eax                              # Save
408                    shrb $0x4,%al                           # Do upper
409                    call hex8.1                             #  4
410                    popl %eax                     # Restore
411hex8.1:   andb $0xf,%al                           # Get lower 4
412                    cmpb $0xa,%al                           # Convert
413                    sbbb $0x69,%al                          #  to hex
414                    das                                     #  digit
415                    orb $0x20,%al                           # To lower case
416                    stosb                                   # Save char
417                    ret                                     # (Recursive)
418
419                    .data
420                    .p2align 4
421/*
422 * Global descriptor table.
423 */
424gdt:                .word 0x0,0x0,0x0,0x0                   # Null entry
425                    .word 0xffff,0x0,0x9a00,0xcf  # SEL_SCODE
426                    .word 0xffff,0x0,0x9200,0xcf  # SEL_SDATA
427                    .word 0xffff,0x0,0x9a00,0x0   # SEL_RCODE
428                    .word 0xffff,0x0,0x9200,0x0   # SEL_RDATA
429gdt.1:
430gdtdesc:  .word gdt.1-gdt-1             # Limit
431                    .long gdt                     # Base
432/*
433 * Messages.
434 */
435m_logo:   .asciz " \nBTX loader 1.00  "
436m_vers:   .asciz "BTX version is \0\n"
437e_fmt:              .asciz "Error: Client format not supported\n"
438#ifdef BTXLDR_VERBOSE
439m_mem:              .asciz "Starting in protected mode (base mem=\0)\n"
440m_esp:              .asciz "Arguments passed (esp=\0):\n"
441m_args:   .asciz"<howto="
442                    .asciz" bootdev="
443                    .asciz" junk="
444                    .asciz" "
445                    .asciz" "
446                    .asciz" bootinfo=\0>\n"
447m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n"
448m_rel_args:         .asciz "Relocated arguments (size=18) to \0\n"
449m_rel_btx:          .asciz "Relocated kernel (size=\0) to \0\n"
450m_base:   .asciz "Client base address is \0\n"
451m_elf:              .asciz "Client format is ELF\n"
452m_segs:   .asciz "text segment: offset="
453                    .asciz " vaddr="
454                    .asciz " filesz="
455                    .asciz " memsz=\0\n"
456                    .asciz "data segment: offset="
457                    .asciz " vaddr="
458                    .asciz " filesz="
459                    .asciz " memsz=\0\n"
460m_done:   .asciz "Loading complete\n"
461#endif
462/*
463 * Uninitialized data area.
464 */
465buf:                                                        # Scratch buffer
466