Consolidate most constant memory addresses in bootasm.h part2/2:
[dragonfly.git] / sys / boot / pc32 / boot2 / boot1.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: src/sys/boot/i386/boot2/boot1.s,v 1.23 2003/08/22 01:59:28 imp Exp $
16  * $DragonFly: src/sys/boot/pc32/boot2/boot1.S,v 1.6 2004/07/19 01:24:58 dillon Exp $
17  */
18
19 #include "../bootasm.h"
20         
21 // Partition Constants 
22                 .set PRT_OFF,0x1be              // Partition offset
23                 .set PRT_NUM,0x4                // Partitions
24                 .set PRT_BSD,0xa5               // Partition type
25
26 // Flag Bits
27                 .set FL_PACKET,0x80             // Packet mode
28
29 // Misc. Constants
30                 .set SIZ_PAG,0x1000             // Page size
31                 .set SIZ_SEC,0x200              // Sector size
32                 .set NSECT,0x10
33
34                 .globl start
35                 .globl xread
36                 .code16
37
38 start:          jmp main                        // Start recognizably
39
40 // This is the start of a standard BIOS Parameter Block (BPB). Most bootable
41 // FAT disks have this at the start of their MBR. While normal BIOS's will
42 // work fine without this section, IBM's El Torito emulation "fixes" up the
43 // BPB by writing into the memory copy of the MBR. Rather than have data
44 // written into our xread routine, we'll define a BPB to work around it.
45 // The data marked with (T) indicates a field required for a ThinkPad to
46 // recognize the disk and (W) indicates fields written from IBM BIOS code.
47 // The use of the BPB is based on what OpenBSD and NetBSD implemented in
48 // their boot code but the required fields were determined by trial and error.
49 //
50 // Note: If additional space is needed in boot1, one solution would be to
51 // move the "prompt" message data (below) to replace the OEM ID.
52
53                 .org 0x03, 0x00
54 oemid:          .space 0x08, 0x00       // OEM ID
55
56                 .org 0x0b, 0x00
57 bpb:            .word   512             // sector size (T)
58                 .byte   0               // sectors/clustor
59                 .word   0               // reserved sectors
60                 .byte   0               // number of FATs
61                 .word   0               // root entries
62                 .word   0               // small sectors
63                 .byte   0               // media type (W)
64                 .word   0               // sectors/fat
65                 .word   18              // sectors per track (T)
66                 .word   2               // number of heads (T)
67                 .long   0               // hidden sectors (W)
68                 .long   0               // large sectors
69
70                 .org 0x24, 0x00
71 ebpb:           .byte   0               // BIOS physical drive number (W)
72
73                 .org 0x25,0x90
74 // 
75 // Trampoline used by boot2 to call read to read data from the disk via
76 // the BIOS.  Call with:
77 //
78 // %cx:%ax      - long    - LBA to read in
79 // %es:(%bx)    - caddr_t - buffer to read data into
80 // %dl          - byte    - drive to read from
81 // %dh          - byte    - num sectors to read
82 // 
83
84 xread:          push %ss                        // Address
85                 pop %ds                         //  data
86 //
87 // Setup an EDD disk packet and pass it to read
88 // 
89 xread.1:                                        // Starting
90                 pushl $0x0                      //  absolute
91                 push %cx                        //  block
92                 push %ax                        //  number
93                 push %es                        // Address of
94                 push %bx                        //  transfer buffer
95                 xor %ax,%ax                     // Number of
96                 movb %dh,%al                    //  blocks to
97                 push %ax                        //  transfer
98                 push $0x10                      // Size of packet
99                 mov %sp,%bp                     // Packet pointer
100                 callw read                      // Read from disk
101                 lea 0x10(%bp),%sp               // Clear stack
102                 lret                            // To far caller
103 // 
104 // Load the rest of boot2 and BTX up, copy the parts to the right locations,
105 // and start it all up.
106 //
107
108 //
109 // Setup the segment registers to flat addressing (segment 0) and setup the
110 // stack to end just below the start of our code.
111 // 
112 main:           cld                             // String ops inc
113                 xor %cx,%cx                     // Zero
114                 mov %cx,%es                     // Address
115                 mov %cx,%ds                     //  data
116                 mov %cx,%ss                     // Set up
117                 mov $start,%sp                  //  stack
118 //
119 // Relocate ourself to MEM_REL.  Since %cx == 0, the inc %ch sets
120 // %cx == 0x100.
121 // 
122                 mov %sp,%si                     // Source
123                 mov $MEM_REL,%di                // Destination
124                 incb %ch                        // Word count
125                 rep                             // Copy
126                 movsw                           //  code
127 //
128 // If we are on a hard drive, then load the MBR and look for the first
129 // FreeBSD slice.  We use the fake partition entry below that points to
130 // the MBR when we call nread.  The first pass looks for the first active
131 // FreeBSD slice.  The second pass looks for the first non-active FreeBSD
132 // slice if the first one fails.
133 // 
134                 mov $part4,%si                  // Partition
135                 cmpb $0x80,%dl                  // Hard drive?
136                 jb main.4                       // No
137                 movb $0x1,%dh                   // Block count
138                 callw nread                     // Read MBR
139                 mov $0x1,%cx                    // Two passes
140 main.1:         mov $BOOT2_LOAD_BUF+PRT_OFF,%si // Partition table
141                 movb $0x1,%dh                   // Partition
142 main.2:         cmpb $PRT_BSD,0x4(%si)          // Our partition type?
143                 jne main.3                      // No
144                 jcxz main.5                     // If second pass
145                 testb $0x80,(%si)               // Active?
146                 jnz main.5                      // Yes
147 main.3:         add $0x10,%si                   // Next entry
148                 incb %dh                        // Partition
149                 cmpb $0x1+PRT_NUM,%dh           // In table?
150                 jb main.2                       // Yes
151                 dec %cx                         // Do two
152                 jcxz main.1                     //  passes
153 //
154 // If we get here, we didn't find any FreeBSD slices at all, so print an
155 // error message and die.
156 // 
157                 mov $msg_part,%si               // Message
158                 jmp error                       // Error
159 //
160 // Floppies use partition 0 of drive 0.
161 // 
162 main.4:         xor %dx,%dx                     // Partition:drive
163 //
164 // Ok, we have a slice and drive in %dx now, so use that to locate and load
165 // boot2.  %si references the start of the slice we are looking for, so go
166 // ahead and load up the first 16 sectors (boot1 + boot2) from that.  
167 //
168 // When we read it in, we conveniently use BOOT2_LOAD_BUF (0x8c00) as our
169 // transfer buffer.  Thus, boot1 ends up at 0x8c00, and boot2 starts at
170 // 0x8c00 + 0x200 = 0x8e00.
171 //
172 // The first part of boot2 is the disklabel, which is 0x200 bytes long.
173 // The second part is BTX, which is thus loaded into 0x9000, which is where
174 // it also runs from.  The boot2.bin binary starts right after the end of
175 // BTX, so we have to figure out where the start of it is and then move the
176 // binary to 0xc000.  Normally, BTX clients start at MEM_BTX_USR, or 0xa000,
177 // but when we use btxld to create boot2, we use an entry point of 0x2000. 
178 // That entry point is relative to MEM_BTX_USR; thus boot2.bin starts
179 // at 0xc000.
180 // 
181 main.5:         mov %dx,MEM_ARG                 // Save args
182                 movb $NSECT,%dh                 // Sector count
183                 callw nread                     // Read disk
184                 mov $MEM_BTX_ORG,%bx            // BTX
185                 mov 0xa(%bx),%si                // Get BTX length and set
186                 add %bx,%si                     //  %si to start of boot2.bin
187                 mov $MEM_BTX_USR+SIZ_PAG*2,%di  // Client page 2
188                 mov $MEM_BTX_ORG+(NSECT-1)*SIZ_SEC,%cx // Byte
189                 sub %si,%cx                     //  count
190                 rep                             // Relocate
191                 movsb                           //  client
192                 sub %di,%cx                     // Byte count
193                 xorb %al,%al                    // Zero assumed bss from
194                 rep                             //  the end of boot2.bin
195                 stosb                           //  up to 0x10000
196                 callw seta20                    // Enable A20
197                 jmp start+MEM_BTX_ENTRY-MEM_ORG // Start BTX
198 // 
199 // Enable A20 so we can access memory above 1 meg.
200 // 
201 seta20:         cli                             // Disable interrupts
202 seta20.1:       inb $0x64,%al                   // Get status
203                 testb $0x2,%al                  // Busy?
204                 jnz seta20.1                    // Yes
205                 movb $0xd1,%al                  // Command: Write
206                 outb %al,$0x64                  //  output port
207 seta20.2:       inb $0x64,%al                   // Get status
208                 testb $0x2,%al                  // Busy?
209                 jnz seta20.2                    // Yes
210                 movb $0xdf,%al                  // Enable
211                 outb %al,$0x60                  //  A20
212                 sti                             // Enable interrupts
213                 retw                            // To caller
214 // 
215 // Trampoline used to call read from within boot1.
216 // 
217 nread:          mov $BOOT2_LOAD_BUF,%bx         // Transfer buffer
218                 mov 0x8(%si),%ax                // Get
219                 mov 0xa(%si),%cx                //  LBA
220                 push %cs                        // Read from
221                 callw xread.1                   //  disk
222                 jnc return                      // If success, return
223                 mov $msg_read,%si               // Otherwise, set the error
224                                                 //  message and fall through to
225                                                 //  the error routine
226 // 
227 // Print out the error message pointed to by %ds:(%si) followed
228 // by a prompt, wait for a keypress, and then reboot the machine.
229 // 
230 error:          callw putstr                    // Display message
231                 mov $prompt,%si                 // Display
232                 callw putstr                    //  prompt
233                 xorb %ah,%ah                    // BIOS: Get
234                 int $0x16                       //  keypress
235                 movw $0x1234, BDA_BOOT          // Do a warm boot
236                 ljmp $0xffff,$0x0               // reboot the machine
237 // 
238 // Display a null-terminated string using the BIOS output.
239 // 
240 putstr.0:       mov $0x7,%bx                    // Page:attribute
241                 movb $0xe,%ah                   // BIOS: Display
242                 int $0x10                       //  character
243 putstr:         lodsb                           // Get char
244                 testb %al,%al                   // End of string?
245                 jne putstr.0                    // No
246
247 //
248 // Overused return code.  ereturn is used to return an error from the
249 // read function.  Since we assume putstr succeeds, we (ab)use the
250 // same code when we return from putstr. 
251 // 
252 ereturn:        movb $0x1,%ah                   // Invalid
253                 stc                             //  argument
254 return:         retw                            // To caller
255 // 
256 // Reads sectors from the disk.  If EDD is enabled, then check if it is
257 // installed and use it if it is.  If it is not installed or not enabled, then
258 // fall back to using CHS.  Since we use a LBA, if we are using CHS, we have to
259 // fetch the drive parameters from the BIOS and divide it out ourselves.
260 // Call with:
261 //
262 // %dl  - byte     - drive number
263 // stack - 10 bytes - EDD Packet
264 //
265 read:           push %dx                        // Save
266                 movb $0x8,%ah                   // BIOS: Get drive
267                 int $0x13                       //  parameters
268                 movb %dh,%ch                    // Max head number
269                 pop %dx                         // Restore
270                 jc return                       // If error
271                 andb $0x3f,%cl                  // Sectors per track
272                 jz ereturn                      // If zero
273                 cli                             // Disable interrupts
274                 mov 0x8(%bp),%eax               // Get LBA
275                 push %dx                        // Save
276                 movzbl %cl,%ebx                 // Divide by
277                 xor %edx,%edx                   //  sectors
278                 div %ebx                        //  per track
279                 movb %ch,%bl                    // Max head number
280                 movb %dl,%ch                    // Sector number
281                 inc %bx                         // Divide by
282                 xorb %dl,%dl                    //  number
283                 div %ebx                        //  of heads
284                 movb %dl,%bh                    // Head number
285                 pop %dx                         // Restore
286                 cmpl $0x3ff,%eax                // Cylinder number supportable?
287                 sti                             // Enable interrupts
288                 ja read.7                       // No, try EDD
289                 xchgb %al,%ah                   // Set up cylinder
290                 rorb $0x2,%al                   //  number
291                 orb %ch,%al                     // Merge
292                 inc %ax                         //  sector
293                 xchg %ax,%cx                    //  number
294                 movb %bh,%dh                    // Head number
295                 subb %ah,%al                    // Sectors this track
296                 mov 0x2(%bp),%ah                // Blocks to read
297                 cmpb %ah,%al                    // To read
298                 jb read.2                       //  this
299 #ifdef  TRACK_AT_A_TIME
300                 movb %ah,%al                    //  track
301 #else
302                 movb $1,%al                     //  one sector
303 #endif
304 read.2:         mov $0x5,%di                    // Try count
305 read.3:         les 0x4(%bp),%bx                // Transfer buffer
306                 push %ax                        // Save
307                 movb $0x2,%ah                   // BIOS: Read
308                 int $0x13                       //  from disk
309                 pop %bx                         // Restore
310                 jnc read.4                      // If success
311                 dec %di                         // Retry?
312                 jz read.6                       // No
313                 xorb %ah,%ah                    // BIOS: Reset
314                 int $0x13                       //  disk system
315                 xchg %bx,%ax                    // Block count
316                 jmp read.3                      // Continue
317 read.4:         movzbw %bl,%ax                  // Sectors read
318                 add %ax,0x8(%bp)                // Adjust
319                 jnc read.5                      //  LBA,
320                 incw 0xa(%bp)                   //  transfer
321 read.5:         shlb %bl                        //  buffer
322                 add %bl,0x5(%bp)                //  pointer,
323                 sub %al,0x2(%bp)                //  block count
324                 ja read                         // If not done
325 read.6:         retw                            // To caller
326 read.7:         testb $FL_PACKET,%cs:MEM_REL+flags-start // LBA support enabled?
327                 jz ereturn                      // No, so return an error
328                 mov $0x55aa,%bx                 // Magic
329                 push %dx                        // Save
330                 movb $0x41,%ah                  // BIOS: Check
331                 int $0x13                       //  extensions present
332                 pop %dx                         // Restore
333                 jc return                       // If error, return an error
334                 cmp $0xaa55,%bx                 // Magic?
335                 jne ereturn                     // No, so return an error
336                 testb $0x1,%cl                  // Packet interface?
337                 jz ereturn                      // No, so return an error
338                 mov %bp,%si                     // Disk packet
339                 movb $0x42,%ah                  // BIOS: Extended
340                 int $0x13                       //  read
341                 retw                            // To caller
342
343 // Messages
344
345 msg_read:       .asciz "Read"
346 msg_part:       .asciz "Boot"
347
348 prompt:         .asciz " error\r\n"
349
350 flags:          .byte FLAGS                     // Flags
351
352                 .org PRT_OFF,0x90
353
354 // Partition table
355
356                 .fill 0x30,0x1,0x0
357 part4:          .byte 0x80, 0x00, 0x01, 0x00
358                 .byte 0xa5, 0xfe, 0xff, 0xff
359                 .byte 0x00, 0x00, 0x00, 0x00
360                 .byte 0x50, 0xc3, 0x00, 0x00    // 50000 sectors long, bleh
361
362                 .word 0xaa55                    // Magic number