Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / boot / i386 / boot0 / boot0.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/boot0/boot0.s,v 1.14.2.6 2000/12/19 00:32:19 rnordier Exp $
17 # $DragonFly: src/sys/boot/i386/boot0/Attic/boot0.s,v 1.2 2003/06/17 04:28:18 dillon Exp $
18
19 # A 512-byte boot manager.
20
21                 .set NHRDRV,0x475               # Number of hard drives
22                 .set ORIGIN,0x600               # Execution address
23                 .set FAKE,0x800                 # Partition entry
24                 .set LOAD,0x7c00                # Load address
25
26                 .set PRT_OFF,0x1be              # Partition table
27
28                 .set TBL0SZ,0x3                 # Table 0 size
29                 .set TBL1SZ,0xc                 # Table 1 size
30
31                 .set MAGIC,0xaa55               # Magic: bootable
32                 .set B0MAGIC,0xbb66             # Identification
33
34                 .set KEY_ENTER,0x1c             # Enter key scan code
35                 .set KEY_F1,0x3b                # F1 key scan code
36
37 #
38 # Addresses in the sector of embedded data values.
39 # Accessed with negative offsets from the end of the relocated sector (%ebp).
40 #
41                 .set _NXTDRV,-0x48              # Next drive
42                 .set _OPT,-0x47                 # Default option
43                 .set _SETDRV,-0x46              # Drive to force
44                 .set _FLAGS,-0x45               # Flags
45                 .set _TICKS,-0x44               # Timeout ticks
46                 .set _FAKE,0x0                  # Fake partition entry
47                 .set _MNUOPT,0xc                # Menu options
48
49                 .globl start                    # Entry point
50                 .code16                         # This runs in real mode
51
52 #
53 # Initialise segments and registers to known values.
54 # segments start at 0.
55 # The stack is immediately below the address we were loaded to.
56 #
57 start:          cld                             # String ops inc
58                 xorw %ax,%ax                    # Zero
59                 movw %ax,%es                    # Address
60                 movw %ax,%ds                    #  data
61                 movw %ax,%ss                    # Set up
62                 movw $LOAD,%sp                  #  stack
63         
64 #
65 # Copy this code to the address it was linked for
66 #
67                 movw %sp,%si                    # Source
68                 movw $start,%di                 # Destination
69                 movw $0x100,%cx                 # Word count
70                 rep                             # Relocate
71                 movsw                           #  code
72 #
73 # Set address for variable space beyond code, and clear it.
74 # Notice that this is also used to point to the values embedded in the block,
75 # by using negative offsets.
76 #
77                 movw %di,%bp                    # Address variables
78                 movb $0x8,%cl                   # Words to clear
79                 rep                             # Zero
80                 stosw                           #  them
81 #
82 # Relocate to the new copy of the code.
83 #
84                 incb -0xe(%di)                  # Sector number
85                 jmp main-LOAD+ORIGIN            # To relocated code
86 #
87 # Check what flags were loaded with us, specifically, Use a predefined Drive.
88 # If what the bios gives us is bad, use the '0' in the block instead, as well.
89 #
90 main:           testb $0x20,_FLAGS(%bp)         # Set number drive?
91                 jnz main.1                      # Yes
92                 testb %dl,%dl                   # Drive number valid?
93                 js main.2                       # Possibly (0x80 set)
94 main.1:         movb _SETDRV(%bp),%dl           # Drive number to use
95 #
96 # Whatever we decided to use, now store it into the fake
97 # partition entry that lives in the data space above us.
98 #
99 main.2:         movb %dl,_FAKE(%bp)             # Save drive number
100                 callw putn                      # To new line
101                 pushw %dx                       # Save drive number
102 #
103 # Start out with a pointer to the 4th byte of the first table entry
104 # so that after 4 iterations it's beyond the end of the sector.
105 # and beyond a 256 byte boundary and has overflowed 8 bits (see next comment).
106 # (remember that the table starts 2 bytes earlier than you would expect
107 # as the bootable flag is after it in the block)
108 #
109                 movw $(partbl+0x4),%bx          # Partition table (+4)
110                 xorw %dx,%dx                    # Item number
111 #
112 # Loop around on the partition table, printing values until we
113 # pass a 256 byte boundary. The end of loop test is at main.5.
114 #
115 main.3:         movb %ch,-0x4(%bx)              # Zero active flag (ch == 0)
116                 btw %dx,_FLAGS(%bp)             # Entry enabled?
117                 jnc main.5                      # No
118 #
119 # If any of the entries in the table are
120 # the same as the 'type' in the slice table entry,
121 # then this is an empty or non bootable partition. Skip it.
122 #
123                 movb (%bx),%al                  # Load type
124                 movw $tables,%di                # Lookup tables
125                 movb $TBL0SZ,%cl                # Number of entries
126                 repne                           # Exclude
127                 scasb                           #  partition?
128                 je main.5                       # Yes
129 #
130 # Now scan the table of known types
131 #
132                 movb $TBL1SZ,%cl                # Number of entries
133                 repne                           # Known
134                 scasb                           #  type?
135                 jne main.4                      # No
136 #
137 # If it matches get the matching element in the
138 # next array. if it doesn't, we are already
139 # pointing at its first element which points to a "?".
140 #
141                 addw $TBL1SZ,%di                # Adjust
142 main.4:         movb (%di),%cl                  # Partition
143                 addw %cx,%di                    #  description
144                 callw putx                      # Display it
145 main.5:         incw %dx                        # Next item 
146                 addb $0x10,%bl                  # Next entry
147                 jnc main.3                      # Till done
148 #
149 # Passed a 256 byte boundary..
150 # table is finished.
151 # Add one to the drive number and check it is valid, 
152 #
153                 popw %ax                        # Drive number
154                 subb $0x80-0x1,%al              # Does next
155                 cmpb NHRDRV,%al                 #  drive exist? (from BIOS?)
156                 jb main.6                       # Yes
157 # If not then if there is only one drive,
158 # Don't display drive as an option.
159 #
160                 decw %ax                        # Already drive 0?
161                 jz main.7                       # Yes
162 # If it was illegal or we cycled through them,
163 # then go back to drive 0.
164 #
165                 xorb %al,%al                    # Drive 0
166 #
167 # Whatever drive we selected, make it an ascii digit and save it back
168 # to the "next drive" location in the loaded block in case we
169 # want to save it for next time.
170 # This also is part of the printed drive string so add 0x80 to indicate
171 # end of string.
172 #
173 main.6:         addb $'0'|0x80,%al              # Save next
174                 movb %al,_NXTDRV(%bp)           #  drive number
175                 movw $drive,%di                 # Display
176                 callw putx                      #  item
177 #
178 # Now that we've printed the drive (if we needed to), display a prompt.
179 # Get ready for the input byt noting the time.
180 #
181 main.7:         movw $prompt,%si                # Display
182                 callw putstr                    #  prompt
183                 movb _OPT(%bp),%dl              # Display
184                 decw %si                        #  default
185                 callw putkey                    #  key
186                 xorb %ah,%ah                    # BIOS: Get
187                 int $0x1a                       #  system time
188                 movw %dx,%di                    # Ticks when
189                 addw _TICKS(%bp),%di            #  timeout
190
191 # Busy loop, looking for keystrokes but
192 # keeping one eye on the time.
193 #
194 main.8:         movb $0x1,%ah                   # BIOS: Check
195                 int $0x16                       #  for keypress
196                 jnz main.11                     # Have one
197                 xorb %ah,%ah                    # BIOS: Get
198                 int $0x1a                       #  system time
199                 cmpw %di,%dx                    # Timeout?
200                 jb main.8                       # No
201 #
202 # If timed out or defaulting, come here.
203 #
204 main.9:         movb _OPT(%bp),%al              # Load default
205                 jmp main.12                     # Join common code
206 #
207 # User's last try was bad, beep in displeasure.
208 # Since nothing was printed, just continue on as if the user
209 # hadn't done anything. This gives the effect of the user getting a beep 
210 # for all bad keystrokes but no action until either the timeout
211 # occurs or the user hits a good key.
212 #
213 main.10:        movb $0x7,%al                   # Signal
214                 callw putchr                    #  error
215 #
216 # Get the keystroke.
217 #
218 main.11:        xorb %ah,%ah                    # BIOS: Get
219                 int $0x16                       #  keypress
220                 movb %ah,%al                    # Scan code
221 #
222 # If it's CR act as if timed out.
223 #
224                 cmpb $KEY_ENTER,%al             # Enter pressed?
225                 je main.9                       # Yes
226 #
227 # Otherwise check if legal
228 # If not ask again.
229 #
230                 subb $KEY_F1,%al                # Less F1 scan code
231                 cmpb $0x4,%al                   # F1..F5?
232                 ja main.10                      # No
233 #
234 # We have a selection.
235 # but if it's a bad selection go back to complain.
236 # The bits in MNUOPT were set when the options were printed.
237 # Anything not printed is not an option.
238 #
239 main.12:        cbtw                            # Option
240                 btw %ax,_MNUOPT(%bp)            #  enabled?
241                 jnc main.10                     # No
242 #
243 # Save the info in the original tables
244 # for rewriting to the disk.
245 #
246                 movb %al,_OPT(%bp)              # Save option
247                 movw $FAKE,%si                  # Partition for write
248                 movb (%si),%dl                  # Drive number
249                 movw %si,%bx                    # Partition for read
250                 cmpb $0x4,%al                   # F5 pressed?
251                 pushf                           # Save
252                 je main.13                      # Yes
253                 shlb $0x4,%al                   # Point to
254                 addw $partbl,%ax                #  selected
255                 xchgw %bx,%ax                   #  partition
256                 movb $0x80,(%bx)                # Flag active
257 #
258 # If not asked to do a write-back (flags 0x40) don't do one.
259 #
260 main.13:        pushw %bx                       # Save
261                 testb $0x40,_FLAGS(%bp)         # No updates?
262                 jnz main.14                     # Yes
263                 movw $start,%bx                 # Data to write
264                 movb $0x3,%ah                   # Write sector
265                 callw intx13                    #  to disk
266 main.14:        popw %si                        # Restore
267                 popf                            # Restore
268 #
269 # If going to next drive, replace drive with selected one.
270 # Remember to un-ascii it. Hey 0x80 is already set, cool!
271 #
272                 jne main.15                     # If not F5
273                 movb _NXTDRV(%bp),%dl           # Next drive
274                 subb $'0',%dl                   #  number
275
276 # load  selected bootsector to the LOAD location in RAM.
277 # If it fails to read or isn't marked bootable, treat it
278 # as a bad selection.
279 # XXX what does %si carry?
280 #
281 main.15:        movw $LOAD,%bx                  # Address for read
282                 movb $0x2,%ah                   # Read sector
283                 callw intx13                    #  from disk
284                 jc main.10                      # If error
285                 cmpw $MAGIC,0x1fe(%bx)          # Bootable?
286                 jne main.10                     # No
287                 pushw %si                       # Save
288                 movw $crlf,%si                  # Leave some
289                 callw puts                      #  space
290                 popw %si                        # Restore
291                 jmp *%bx                        # Invoke bootstrap
292 #
293 # Display routines
294 #
295
296 putkey:         movb $'F',%al                   # Display
297                 callw putchr                    #  'F'
298                 movb $'1',%al                   # Prepare
299                 addb %dl,%al                    #  digit
300                 jmp putstr.1                    # Display the rest
301
302 #
303 # Display the option and note that it is a valid option.
304 # That last point is a bit tricky..
305 #
306 putx:           btsw %dx,_MNUOPT(%bp)           # Enable menu option
307                 movw $item,%si                  # Display
308                 callw putkey                    #  key
309                 movw %di,%si                    # Display the rest
310
311 puts:           callw putstr                    # Display string
312
313 putn:           movw $crlf,%si                  # To next line
314
315 putstr:         lodsb                           # Get byte
316                 testb $0x80,%al                 # End of string?
317                 jnz putstr.2                    # Yes
318 putstr.1:       callw putchr                    # Display char
319                 jmp putstr                      # Continue
320 putstr.2:       andb $~0x80,%al                 # Clear MSB
321
322 putchr:         pushw %bx                       # Save
323                 movw $0x7,%bx                   # Page:attribute
324                 movb $0xe,%ah                   # BIOS: Display
325                 int $0x10                       #  character
326                 popw %bx                        # Restore
327                 retw                            # To caller
328
329 # One-sector disk I/O routine
330
331 intx13:         movb 0x1(%si),%dh               # Load head
332                 movw 0x2(%si),%cx               # Load cylinder:sector
333                 movb $0x1,%al                   # Sector count
334                 pushw %si                       # Save
335                 movw %sp,%di                    # Save
336                 testb $0x80,_FLAGS(%bp)         # Use packet interface?
337                 jz intx13.1                     # No
338                 pushl $0x0                      # Set the
339                 pushl 0x8(%si)                  # LBA address
340                 pushw %es                       # Set the transfer
341                 pushw %bx                       #  buffer address
342                 push  $0x1                      # Block count
343                 push  $0x10                     # Packet size
344                 movw %sp,%si                    # Packet pointer
345                 decw %ax                        # Verify off
346                 orb $0x40,%ah                   # Use disk packet
347 intx13.1:       int $0x13                       # BIOS: Disk I/O
348                 movw %di,%sp                    # Restore
349                 popw %si                        # Restore
350                 retw                            # To caller
351
352 # Menu strings
353
354 item:           .ascii "  ";         .byte ' '|0x80
355 prompt:         .ascii "\nDefault:"; .byte ' '|0x80
356 crlf:           .ascii "\r";         .byte '\n'|0x80
357
358 # Partition type tables
359
360 tables:
361 #
362 # These entries identify invalid or NON BOOT types and partitions.
363 #
364                 .byte 0x0, 0x5, 0xf
365 #
366 # These values indicate bootable types we know the names of
367 #
368                 .byte 0x1, 0x4, 0x6, 0xb, 0xc, 0xe, 0x63, 0x83
369                 .byte 0x9f, 0xa5, 0xa6, 0xa9
370 #
371 # These are offsets that match the known names above and point to the strings
372 # that will be printed.
373 #
374                 .byte os_misc-.                 # Unknown
375                 .byte os_dos-.                  # DOS
376                 .byte os_dos-.                  # DOS
377                 .byte os_dos-.                  # DOS
378                 .byte os_dos-.                  # Windows
379                 .byte os_dos-.                  # Windows
380                 .byte os_dos-.                  # Windows
381                 .byte os_unix-.                 # UNIX
382                 .byte os_linux-.                # Linux
383                 .byte os_bsd-.                  # BSD/OS
384                 .byte os_freebsd-.              # FreeBSD
385                 .byte os_bsd-.                  # OpenBSD
386                 .byte os_bsd-.                  # NetBSD
387 #
388 # And here are the strings themselves. 0x80 or'd into a byte indicates 
389 # the end of the string. (not so great for Russians but...)
390 #
391 os_misc:        .ascii "?";    .byte '?'|0x80
392 os_dos:         .ascii "DO";   .byte 'S'|0x80
393 os_unix:        .ascii "UNI";  .byte 'X'|0x80
394 os_linux:       .ascii "Linu"; .byte 'x'|0x80
395 os_freebsd:     .ascii "Free"
396 os_bsd:         .ascii "BS";   .byte 'D'|0x80
397
398                 .org PRT_OFF-0xe,0x90
399
400                 .word B0MAGIC                   # Magic number
401
402 #
403 # These values are sometimes changed before writing back to the drive
404 # Be especially careful that nxtdrv: must come after drive:, as it 
405 # is part of the same string.
406 #
407 drive:          .ascii "Drive "
408 nxtdrv:         .byte 0x0                       # Next drive number
409 opt:            .byte 0x0                       # Option
410 setdrv:         .byte 0x80                      # Drive to force
411 flags:          .byte FLAGS                     # Flags
412 ticks:          .word TICKS                     # Delay
413
414 #
415 # here is the 64 byte partition table that fdisk would fiddle with.
416 #
417 partbl:         .fill 0x40,0x1,0x0              # Partition table
418                 .word MAGIC                     # Magic number