]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/boot/i386/zfsboot/zfsldr.S
Re-sync loader.mk and ficl.mk to where they should be
[FreeBSD/FreeBSD.git] / sys / boot / i386 / zfsboot / zfsldr.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 /* Memory Locations */
19                 .set MEM_ARG,0x900              # Arguments
20                 .set MEM_ORG,0x7c00             # Origin
21                 .set MEM_BUF,0x8000             # Load area
22                 .set MEM_BTX,0x9000             # BTX start
23                 .set MEM_JMP,0x9010             # BTX entry point
24                 .set MEM_USR,0xa000             # Client start
25                 .set BDA_BOOT,0x472             # Boot howto flag
26         
27 /* Partition Constants */
28                 .set PRT_OFF,0x1be              # Partition offset
29                 .set PRT_NUM,0x4                # Partitions
30                 .set PRT_BSD,0xa5               # Partition type
31
32 /* Misc. Constants */
33                 .set SIZ_PAG,0x1000             # Page size
34                 .set SIZ_SEC,0x200              # Sector size
35                 .set COPY_BLKS,0x8              # Number of blocks
36                                                 # to copy for boot2
37                 .set COPY_BLK_SZ,0x8000         # Copy in 32k blocks; must be
38                                                 # a multiple of 16 bytes
39                 .set NSECT,(COPY_BLK_SZ / SIZ_SEC * COPY_BLKS)
40                 .globl start
41                 .code16
42
43 /*
44  * Load the rest of zfsboot2 and BTX up, copy the parts to the right locations,
45  * and start it all up.
46  */
47
48 /*
49  * Setup the segment registers to flat addressing (segment 0) and setup the
50  * stack to end just below the start of our code.
51  */
52 start:          cld                             # String ops inc
53                 xor %cx,%cx                     # Zero
54                 mov %cx,%es                     # Address
55                 mov %cx,%ds                     #  data
56                 mov %cx,%ss                     # Set up
57                 mov $start,%sp                  #  stack
58 /*
59  * Load the MBR and look for the first FreeBSD slice.  We use the fake
60  * partition entry below that points to the MBR when we call read.
61  * The first pass looks for the first active FreeBSD slice.  The
62  * second pass looks for the first non-active FreeBSD slice if the
63  * first one fails.
64  */
65                 call check_edd                  # Make sure EDD works
66                 mov $part4,%si                  # Dummy partition
67                 xor %eax,%eax                   # Read MBR
68                 movl $MEM_BUF,%ebx              #  from first
69                 call read                       #  sector
70                 mov $0x1,%cx                    # Two passes
71 main.1:         mov $MEM_BUF+PRT_OFF,%si        # Partition table
72                 movb $0x1,%dh                   # Partition
73 main.2:         cmpb $PRT_BSD,0x4(%si)          # Our partition type?
74                 jne main.3                      # No
75                 jcxz main.5                     # If second pass
76                 testb $0x80,(%si)               # Active?
77                 jnz main.5                      # Yes
78 main.3:         add $0x10,%si                   # Next entry
79                 incb %dh                        # Partition
80                 cmpb $0x1+PRT_NUM,%dh           # In table?
81                 jb main.2                       # Yes
82                 dec %cx                         # Do two
83                 jcxz main.1                     #  passes
84 /*
85  * If we get here, we didn't find any FreeBSD slices at all, so print an
86  * error message and die.
87  */
88                 mov $msg_part,%si               # Message
89                 jmp error                       # Error
90
91 /*
92  * Ok, we have a slice and drive in %dx now, so use that to locate and
93  * load boot2.  %si references the start of the slice we are looking
94  * for, so go ahead and load up the COPY_BLKS*COPY_BLK_SZ/SIZ_SEC sectors
95  * starting at sector 1024 (i.e. after the two vdev labels).  We don't
96  * have do anything fancy here to allow for an extra copy of boot1 and
97  * a partition table (compare to this section of the UFS bootstrap) so we
98  * just load it all at 0x9000. The first part of boot2 is BTX, which wants
99  * to run at 0x9000. The boot2.bin binary starts right after the end of BTX,
100  * so we have to figure out where the start of it is and then move the
101  * binary to 0xc000.  Normally, BTX clients start at MEM_USR, or 0xa000,
102  * but when we use btxld to create zfsboot2, we use an entry point of
103  * 0x2000.  That entry point is relative to MEM_USR; thus boot2.bin
104  * starts at 0xc000.
105  *
106  * The load area and the target area for the client overlap so we have
107  * to use a decrementing string move. We also play segment register
108  * games with the destination address for the move so that the client
109  * can be larger than 16k (which would overflow the zero segment since
110  * the client starts at 0xc000).
111  */
112 main.5:         mov %dx,MEM_ARG                 # Save args
113                 mov $NSECT,%cx                  # Sector count
114                 movl $1024,%eax                 # Offset to boot2
115                 mov $MEM_BTX,%ebx               # Destination buffer
116 main.6:         pushal                          # Save params
117                 call read                       # Read disk
118                 popal                           # Restore
119                 incl %eax                       # Advance to
120                 add $SIZ_SEC,%ebx               #  next sector
121                 loop main.6                     # If not last, read another
122
123                 mov $MEM_BTX,%bx                # BTX
124                 mov 0xa(%bx),%si                # Get BTX length and set
125                 add %bx,%si                     #  %si to start of boot2
126                 dec %si                         # Set %ds:%si to point at the
127                 mov %si,%ax                     # last byte we want to copy
128                 shr $4,%ax                      # from boot2, with %si made as
129                 add $(COPY_BLKS*COPY_BLK_SZ/16),%ax     # small as possible.
130                 and $0xf,%si                    #
131                 mov %ax,%ds                     #
132                 mov $(MEM_USR+2*SIZ_PAG)/16,%ax # Set %es:(-1) to point at
133                 add $(COPY_BLKS*COPY_BLK_SZ/16),%ax     # the last byte we
134                 mov %ax,%es                     # want to copy boot2 into.
135                 mov $COPY_BLKS,%bx              # Copy COPY_BLKS 32k blocks
136 copyloop:
137                 add $COPY_BLK_SZ,%si            # Adjust %ds:%si to point at
138                 mov %ds,%ax                     # the end of the next 32k to
139                 sub $COPY_BLK_SZ/16,%ax         # copy from boot2
140                 mov %ax,%ds
141                 mov $COPY_BLK_SZ-1,%di          # Adjust %es:%di to point at
142                 mov %es,%ax                     # the end of the next 32k into
143                 sub $COPY_BLK_SZ/16,%ax         # which we want boot2 copied
144                 mov %ax,%es
145                 mov $COPY_BLK_SZ,%cx            # Copy 32k
146                 std
147                 rep movsb
148                 dec %bx
149                 jnz copyloop
150                 mov %cx,%ds                     # Reset %ds and %es
151                 mov %cx,%es
152                 cld                             # Back to increment
153
154 /*
155  * Enable A20 so we can access memory above 1 meg.
156  * Use the zero-valued %cx as a timeout for embedded hardware which do not
157  * have a keyboard controller.
158  */
159 seta20:         cli                             # Disable interrupts
160 seta20.1:       dec %cx                         # Timeout?
161                 jz seta20.3                     # Yes
162                 inb $0x64,%al                   # Get status
163                 testb $0x2,%al                  # Busy?
164                 jnz seta20.1                    # Yes
165                 movb $0xd1,%al                  # Command: Write
166                 outb %al,$0x64                  #  output port
167 seta20.2:       inb $0x64,%al                   # Get status
168                 testb $0x2,%al                  # Busy?
169                 jnz seta20.2                    # Yes
170                 movb $0xdf,%al                  # Enable
171                 outb %al,$0x60                  #  A20
172 seta20.3:       sti                             # Enable interrupts
173
174                 jmp start+MEM_JMP-MEM_ORG       # Start BTX
175
176
177 /*
178  * Read a sector from the disk.  Sets up an EDD packet on the stack
179  * and passes it to read.  We assume that the destination address is
180  * always segment-aligned.
181  *
182  * %eax         - int     - LBA to read in relative to partition start
183  * %ebx         - ptr     - destination address
184  * %dl          - byte    - drive to read from
185  * %si          - ptr     - MBR partition entry
186  */
187 read:           xor %ecx,%ecx                   # Get
188                 addl 0x8(%si),%eax              #  LBA
189                 adc $0,%ecx
190                 pushl %ecx                      # Starting absolute block
191                 pushl %eax                      #  block number
192                 shr $4,%ebx                     # Convert to segment
193                 push %bx                        # Address of
194                 push $0                         #  transfer buffer
195                 push $0x1                       # Read 1 sector
196                 push $0x10                      # Size of packet
197                 mov %sp,%si                     # Packet pointer
198                 mov $0x42,%ah                   # BIOS: Extended
199                 int $0x13                       #  read
200                 jc read.1                       # If error, fail
201                 lea 0x10(%si),%sp               # Clear stack
202                 ret                             # If success, return
203 read.1:         mov %ah,%al                     # Format
204                 mov $read_err,%di               #  error
205                 call hex8                       #  code
206                 mov $msg_read,%si               # Set the error message and
207                                                 #  fall through to the error
208                                                 #  routine
209 /*
210  * Print out the error message pointed to by %ds:(%si) followed
211  * by a prompt, wait for a keypress, and then reboot the machine.
212  */
213 error:          callw putstr                    # Display message
214                 mov $prompt,%si                 # Display
215                 callw putstr                    #  prompt
216                 xorb %ah,%ah                    # BIOS: Get
217                 int $0x16                       #  keypress
218                 movw $0x1234, BDA_BOOT          # Do a warm boot
219                 ljmp $0xffff,$0x0               # reboot the machine
220 /*
221  * Display a null-terminated string using the BIOS output.
222  */
223 putstr.0:       mov $0x7,%bx                    # Page:attribute
224                 movb $0xe,%ah                   # BIOS: Display
225                 int $0x10                       #  character
226 putstr:         lodsb                           # Get char
227                 testb %al,%al                   # End of string?
228                 jne putstr.0                    # No
229                 ret                             # To caller
230 /*
231  * Check to see if the disk supports EDD.  zfsboot requires EDD and does not
232  * support older C/H/S disk I/O.
233  */
234 check_edd:      cmpb $0x80,%dl                  # Hard drive?
235                 jb check_edd.1                  # No, fail to boot
236                 mov $0x55aa,%bx                 # Magic
237                 push %dx                        # Save
238                 movb $0x41,%ah                  # BIOS: Check
239                 int $0x13                       #  extensions present
240                 pop %dx                         # Restore
241                 jc check_edd.1                  # If error, fail
242                 cmp $0xaa55,%bx                 # Magic?
243                 jne check_edd.1                 # No, so fail
244                 testb $0x1,%cl                  # Packet interface?
245                 jz check_edd.1                  # No, so fail
246                 ret                             # EDD ok, keep booting
247 check_edd.1:    mov $msg_chs,%si                # Warn that CHS is
248                 jmp error                       #  unsupported and fail
249 /*
250  * AL to hex, saving the result to [EDI].
251  */
252 hex8:           push %ax                        # Save
253                 shrb $0x4,%al                   # Do upper
254                 call hex8.1                     #  4
255                 pop %ax                         # Restore
256 hex8.1:         andb $0xf,%al                   # Get lower 4
257                 cmpb $0xa,%al                   # Convert
258                 sbbb $0x69,%al                  #  to hex
259                 das                             #  digit
260                 orb $0x20,%al                   # To lower case
261                 stosb                           # Save char
262                 ret                             # (Recursive)
263
264 /* Messages */
265
266 msg_chs:        .asciz "CHS not supported"
267 msg_read:       .ascii "Read error: "
268 read_err:       .asciz "XX"
269 msg_part:       .asciz "Boot error"
270
271 prompt:         .asciz "\r\n"
272
273                 .org PRT_OFF,0x90
274
275 /* Partition table */
276
277                 .fill 0x30,0x1,0x0
278 part4:          .byte 0x80, 0x00, 0x01, 0x00
279                 .byte 0xa5, 0xfe, 0xff, 0xff
280                 .byte 0x00, 0x00, 0x00, 0x00
281                 .byte 0x50, 0xc3, 0x00, 0x00    # 50000 sectors long, bleh
282
283                 .word 0xaa55                    # Magic number