Consolidate most constant memory addresses in bootasm.h part1/2. Convert
[dragonfly.git] / sys / boot / i386 / 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/i386/boot2/Attic/boot1.S,v 1.5 2004/07/18 23:40:01 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 $MEM_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.  When
167 // we read it in, we conveniently use 0x8c00 as our transfer buffer.  Thus,
168 // boot1 ends up at 0x8c00, and boot2 starts at 0x8c00 + 0x200 = 0x8e00.
169 // The first part of boot2 is the disklabel, which is 0x200 bytes long.
170 // The second part is BTX, which is thus loaded into 0x9000, which is where
171 // it also runs from.  The boot2.bin binary starts right after the end of
172 // BTX, so we have to figure out where the start of it is and then move the
173 // binary to 0xc000.  Normally, BTX clients start at MEM_USR, or 0xa000, but
174 // when we use btxld to create boot2, we use an entry point of 0x2000.  That
175 // entry point is relative to MEM_USR; thus boot2.bin starts at 0xc000.
176 // 
177 main.5:         mov %dx,MEM_ARG                 // Save args
178                 movb $NSECT,%dh                 // Sector count
179                 callw nread                     // Read disk
180                 mov $MEM_BTX,%bx                // BTX
181                 mov 0xa(%bx),%si                // Get BTX length and set
182                 add %bx,%si                     //  %si to start of boot2.bin
183                 mov $MEM_USR+SIZ_PAG*2,%di      // Client page 2
184                 mov $MEM_BTX+(NSECT-1)*SIZ_SEC,%cx // Byte
185                 sub %si,%cx                     //  count
186                 rep                             // Relocate
187                 movsb                           //  client
188                 sub %di,%cx                     // Byte count
189                 xorb %al,%al                    // Zero assumed bss from
190                 rep                             //  the end of boot2.bin
191                 stosb                           //  up to 0x10000
192                 callw seta20                    // Enable A20
193                 jmp start+MEM_JMP-MEM_ORG       // Start BTX
194 // 
195 // Enable A20 so we can access memory above 1 meg.
196 // 
197 seta20:         cli                             // Disable interrupts
198 seta20.1:       inb $0x64,%al                   // Get status
199                 testb $0x2,%al                  // Busy?
200                 jnz seta20.1                    // Yes
201                 movb $0xd1,%al                  // Command: Write
202                 outb %al,$0x64                  //  output port
203 seta20.2:       inb $0x64,%al                   // Get status
204                 testb $0x2,%al                  // Busy?
205                 jnz seta20.2                    // Yes
206                 movb $0xdf,%al                  // Enable
207                 outb %al,$0x60                  //  A20
208                 sti                             // Enable interrupts
209                 retw                            // To caller
210 // 
211 // Trampoline used to call read from within boot1.
212 // 
213 nread:          mov $MEM_BUF,%bx                // Transfer buffer
214                 mov 0x8(%si),%ax                // Get
215                 mov 0xa(%si),%cx                //  LBA
216                 push %cs                        // Read from
217                 callw xread.1                   //  disk
218                 jnc return                      // If success, return
219                 mov $msg_read,%si               // Otherwise, set the error
220                                                 //  message and fall through to
221                                                 //  the error routine
222 // 
223 // Print out the error message pointed to by %ds:(%si) followed
224 // by a prompt, wait for a keypress, and then reboot the machine.
225 // 
226 error:          callw putstr                    // Display message
227                 mov $prompt,%si                 // Display
228                 callw putstr                    //  prompt
229                 xorb %ah,%ah                    // BIOS: Get
230                 int $0x16                       //  keypress
231                 movw $0x1234, BDA_BOOT          // Do a warm boot
232                 ljmp $0xffff,$0x0               // reboot the machine
233 // 
234 // Display a null-terminated string using the BIOS output.
235 // 
236 putstr.0:       mov $0x7,%bx                    // Page:attribute
237                 movb $0xe,%ah                   // BIOS: Display
238                 int $0x10                       //  character
239 putstr:         lodsb                           // Get char
240                 testb %al,%al                   // End of string?
241                 jne putstr.0                    // No
242
243 //
244 // Overused return code.  ereturn is used to return an error from the
245 // read function.  Since we assume putstr succeeds, we (ab)use the
246 // same code when we return from putstr. 
247 // 
248 ereturn:        movb $0x1,%ah                   // Invalid
249                 stc                             //  argument
250 return:         retw                            // To caller
251 // 
252 // Reads sectors from the disk.  If EDD is enabled, then check if it is
253 // installed and use it if it is.  If it is not installed or not enabled, then
254 // fall back to using CHS.  Since we use a LBA, if we are using CHS, we have to
255 // fetch the drive parameters from the BIOS and divide it out ourselves.
256 // Call with:
257 //
258 // %dl  - byte     - drive number
259 // stack - 10 bytes - EDD Packet
260 //
261 read:           push %dx                        // Save
262                 movb $0x8,%ah                   // BIOS: Get drive
263                 int $0x13                       //  parameters
264                 movb %dh,%ch                    // Max head number
265                 pop %dx                         // Restore
266                 jc return                       // If error
267                 andb $0x3f,%cl                  // Sectors per track
268                 jz ereturn                      // If zero
269                 cli                             // Disable interrupts
270                 mov 0x8(%bp),%eax               // Get LBA
271                 push %dx                        // Save
272                 movzbl %cl,%ebx                 // Divide by
273                 xor %edx,%edx                   //  sectors
274                 div %ebx                        //  per track
275                 movb %ch,%bl                    // Max head number
276                 movb %dl,%ch                    // Sector number
277                 inc %bx                         // Divide by
278                 xorb %dl,%dl                    //  number
279                 div %ebx                        //  of heads
280                 movb %dl,%bh                    // Head number
281                 pop %dx                         // Restore
282                 cmpl $0x3ff,%eax                // Cylinder number supportable?
283                 sti                             // Enable interrupts
284                 ja read.7                       // No, try EDD
285                 xchgb %al,%ah                   // Set up cylinder
286                 rorb $0x2,%al                   //  number
287                 orb %ch,%al                     // Merge
288                 inc %ax                         //  sector
289                 xchg %ax,%cx                    //  number
290                 movb %bh,%dh                    // Head number
291                 subb %ah,%al                    // Sectors this track
292                 mov 0x2(%bp),%ah                // Blocks to read
293                 cmpb %ah,%al                    // To read
294                 jb read.2                       //  this
295 #ifdef  TRACK_AT_A_TIME
296                 movb %ah,%al                    //  track
297 #else
298                 movb $1,%al                     //  one sector
299 #endif
300 read.2:         mov $0x5,%di                    // Try count
301 read.3:         les 0x4(%bp),%bx                // Transfer buffer
302                 push %ax                        // Save
303                 movb $0x2,%ah                   // BIOS: Read
304                 int $0x13                       //  from disk
305                 pop %bx                         // Restore
306                 jnc read.4                      // If success
307                 dec %di                         // Retry?
308                 jz read.6                       // No
309                 xorb %ah,%ah                    // BIOS: Reset
310                 int $0x13                       //  disk system
311                 xchg %bx,%ax                    // Block count
312                 jmp read.3                      // Continue
313 read.4:         movzbw %bl,%ax                  // Sectors read
314                 add %ax,0x8(%bp)                // Adjust
315                 jnc read.5                      //  LBA,
316                 incw 0xa(%bp)                   //  transfer
317 read.5:         shlb %bl                        //  buffer
318                 add %bl,0x5(%bp)                //  pointer,
319                 sub %al,0x2(%bp)                //  block count
320                 ja read                         // If not done
321 read.6:         retw                            // To caller
322 read.7:         testb $FL_PACKET,%cs:MEM_REL+flags-start // LBA support enabled?
323                 jz ereturn                      // No, so return an error
324                 mov $0x55aa,%bx                 // Magic
325                 push %dx                        // Save
326                 movb $0x41,%ah                  // BIOS: Check
327                 int $0x13                       //  extensions present
328                 pop %dx                         // Restore
329                 jc return                       // If error, return an error
330                 cmp $0xaa55,%bx                 // Magic?
331                 jne ereturn                     // No, so return an error
332                 testb $0x1,%cl                  // Packet interface?
333                 jz ereturn                      // No, so return an error
334                 mov %bp,%si                     // Disk packet
335                 movb $0x42,%ah                  // BIOS: Extended
336                 int $0x13                       //  read
337                 retw                            // To caller
338
339 // Messages
340
341 msg_read:       .asciz "Read"
342 msg_part:       .asciz "Boot"
343
344 prompt:         .asciz " error\r\n"
345
346 flags:          .byte FLAGS                     // Flags
347
348                 .org PRT_OFF,0x90
349
350 // Partition table
351
352                 .fill 0x30,0x1,0x0
353 part4:          .byte 0x80, 0x00, 0x01, 0x00
354                 .byte 0xa5, 0xfe, 0xff, 0xff
355                 .byte 0x00, 0x00, 0x00, 0x00
356                 .byte 0x50, 0xc3, 0x00, 0x00    // 50000 sectors long, bleh
357
358                 .word 0xaa55                    // Magic number