557462f104050e1da12f075c9431686fd8454b80
[people/lynusvaz/gpxe.git] / src / arch / i386 / prefix / boot1a.s
1 # This code is no longer used in Etherboot.  It is not maintained and
2 # may not work.
3
4
5 #
6 # Copyright (c) 1998 Robert Nordier
7 # All rights reserved.
8 # Very small bootrom changes by Luigi Rizzo
9 # <comment author="Luigi Rizzo">
10 # I recently had the problem of downloading the etherboot code
11 # from a hard disk partition instead of a floppy, and noticed that
12 # floppyload.S does not do the job. With a bit of hacking to
13 # the FreeBSD's boot1.s code, I managed to obtain a boot sector
14 # which works both for floppies and hard disks -- basically you
15 # do something like
16
17 #       cat boot1a bin32/<yourcard>.lzrom > /dev/ad0s4
18
19 # (or whatever is the HD partition you are using, I am using slice
20 # 4 on FreeBSD) and you are up and running.
21 # Then with "fdisk" you have to mark your partition as having type "1"
22 # (which is listed as DOS-- but basically it must be something matching
23 # the variable PRT_BSD in the assembly source below).
24 # </comment>
25 #
26 # Redistribution and use in source and binary forms are freely
27 # permitted provided that the above copyright notice and this
28 # paragraph and the following disclaimer are duplicated in all
29 # such forms.
30 #
31 # This software is provided "AS IS" and without any express or
32 # implied warranties, including, without limitation, the implied
33 # warranties of merchantability and fitness for a particular
34 # purpose.
35 #
36 # Makefile:
37 #boot1a: boot1a.out
38 #       objcopy -S -O binary boot1a.out boot1a
39 #
40 #boot1a.out: boot1a.o
41 #       ld -nostdlib -static -N -e start -Ttext 0x7c00 -o boot1a.out boot1a.o
42 #
43 #boot1a.o: boot1a.s
44 #       as --defsym FLAGS=0x80 boot1a.s -o boot1a.o
45 #
46 #
47
48 # $FreeBSD: src/sys/boot/i386/boot2/boot1.s,v 1.10.2.2 2000/07/07 21:12:32 jhb Exp $
49
50 # Memory Locations
51                 .set MEM_REL,0x700              # Relocation address
52                 .set MEM_ARG,0x900              # Arguments
53                 .set MEM_ORG,0x7c00             # Origin
54                 .set MEM_BUF,0x8c00             # Load area
55                 .set MEM_BTX,0x9000             # BTX start
56                 .set MEM_JMP,0x9010             # BTX entry point
57                 .set MEM_USR,0xa000             # Client start
58                 .set BDA_BOOT,0x472             # Boot howto flag
59         
60 # Partition Constants 
61                 .set PRT_OFF,0x1be              # Partition offset
62                 .set PRT_NUM,0x4                # Partitions
63                 .set PRT_BSD,0x1                # Partition type
64
65 # Flag Bits
66                 .set FL_PACKET,0x80             # Packet mode
67
68 # Misc. Constants
69                 .set SIZ_PAG,0x1000             # Page size
70                 .set SIZ_SEC,0x200              # Sector size
71
72                 .globl start
73                 .globl xread
74                 .code16
75
76 start:          jmp main                        # Start recognizably
77
78                 .org 0x4,0x90
79
80 # Trampoline used by boot2 to call read to read data from the disk via
81 # the BIOS.  Call with:
82 #
83 # %cx:%ax       - long    - LBA to read in
84 # %es:(%bx)     - caddr_t - buffer to read data into
85 # %dl           - byte    - drive to read from
86 # %dh           - byte    - num sectors to read
87
88
89 xread:          push %ss                        # Address
90                 pop %ds                         #  data
91 #
92 # Setup an EDD disk packet and pass it to read
93
94 xread.1:                                        # Starting
95                 pushl $0x0                      #  absolute
96                 push %cx                        #  block
97                 push %ax                        #  number
98                 push %es                        # Address of
99                 push %bx                        #  transfer buffer
100                 xor %ax,%ax                     # Number of
101                 movb %dh,%al                    #  blocks to
102                 push %ax                        #  transfer
103                 push $0x10                      # Size of packet
104                 mov %sp,%bp                     # Packet pointer
105                 callw read                      # Read from disk
106                 lea 0x10(%bp),%sp               # Clear stack
107                 lret                            # To far caller
108
109 # Load the rest of boot2 and BTX up, copy the parts to the right locations,
110 # and start it all up.
111 #
112
113 #
114 # Setup the segment registers to flat addressing (segment 0) and setup the
115 # stack to end just below the start of our code.
116
117 main:           cld                             # String ops inc
118                 xor %cx,%cx                     # Zero
119                 mov %cx,%es                     # Address
120                 mov %cx,%ds                     #  data
121                 mov %cx,%ss                     # Set up
122                 mov $start,%sp                  #  stack
123 #
124 # Relocate ourself to MEM_REL.  Since %cx == 0, the inc %ch sets
125 # %cx == 0x100.
126
127                 mov %sp,%si                     # Source
128                 mov $MEM_REL,%di                # Destination
129                 incb %ch                        # Word count
130                 rep                             # Copy
131                 movsw                           #  code
132 #
133 # If we are on a hard drive, then load the MBR and look for the first
134 # FreeBSD slice.  We use the fake partition entry below that points to
135 # the MBR when we call nread.  The first pass looks for the first active
136 # FreeBSD slice.  The second pass looks for the first non-active FreeBSD
137 # slice if the first one fails.
138
139                 mov $part4,%si                  # Partition
140                 cmpb $0x80,%dl                  # Hard drive?
141                 jb main.4                       # No
142                 movb $0x1,%dh                   # Block count
143                 callw nread                     # Read MBR
144                 mov $0x1,%cx                    # Two passes
145 main.1:         mov $MEM_BUF+PRT_OFF,%si        # Partition table
146                 movb $0x1,%dh                   # Partition
147 main.2:         cmpb $PRT_BSD,0x4(%si)          # Our partition type?
148                 jne main.3                      # No
149                 jcxz main.5                     # If second pass
150                 testb $0x80,(%si)               # Active?
151                 jnz main.5                      # Yes
152 main.3:         add $0x10,%si                   # Next entry
153                 incb %dh                        # Partition
154                 cmpb $0x1+PRT_NUM,%dh           # In table?
155                 jb main.2                       # Yes
156                 dec %cx                         # Do two
157                 jcxz main.1                     #  passes
158 #
159 # If we get here, we didn't find any FreeBSD slices at all, so print an
160 # error message and die.
161
162 booterror:      mov $msg_part,%si               # Message
163                 jmp error                       # Error
164 #
165 # Floppies use partition 0 of drive 0.
166
167 main.4:         xor %dx,%dx                     # Partition:drive
168 #
169 # Ok, we have a slice and drive in %dx now, so use that to locate and load
170 # boot2.  %si references the start of the slice we are looking for, so go
171 # ahead and load up the first 16 sectors (boot1 + boot2) from that.  When
172 # we read it in, we conveniently use 0x8c00 as our transfer buffer.  Thus,
173 # boot1 ends up at 0x8c00, and boot2 starts at 0x8c00 + 0x200 = 0x8e00.
174 # The first part of boot2 is the disklabel, which is 0x200 bytes long.
175 # The second part is BTX, which is thus loaded into 0x9000, which is where
176 # it also runs from.  The boot2.bin binary starts right after the end of
177 # BTX, so we have to figure out where the start of it is and then move the
178 # binary to 0xb000.  Normally, BTX clients start at MEM_USR, or 0xa000, but
179 # when we use btxld create boot2, we use an entry point of 0x1000.  That
180 # entry point is relative to MEM_USR; thus boot2.bin starts at 0xb000.
181
182 main.5:         mov %dx,MEM_ARG                 # Save args
183                 movb $0x2,%dh                   # Sector count
184                 mov $0x7e00, %bx
185                 callw nreadbx                   # Read disk
186                 movb $0x40,%dh                  # Sector count
187                 movb %dh, %al
188                 callw puthex
189                 mov $0x7e00, %bx
190                 callw nreadbx                   # Read disk
191                 push %si
192                 mov $msg_r1,%si
193                 callw putstr
194                 pop %si
195                 lcall $0x800,$0                 # enter the rom code
196                 int $0x19
197
198 msg_r1:         .asciz " done\r\n"
199                 
200 .if 0
201                 mov $MEM_BTX,%bx                # BTX
202                 mov 0xa(%bx),%si                # Get BTX length and set
203                 add %bx,%si                     #  %si to start of boot2.bin
204                 mov $MEM_USR+SIZ_PAG,%di        # Client page 1
205                 mov $MEM_BTX+0xe*SIZ_SEC,%cx    # Byte
206                 sub %si,%cx                     #  count
207                 rep                             # Relocate
208                 movsb                           #  client
209                 sub %di,%cx                     # Byte count
210                 xorb %al,%al                    # Zero assumed bss from
211                 rep                             #  the end of boot2.bin
212                 stosb                           #  up to 0x10000
213                 callw seta20                    # Enable A20
214                 jmp start+MEM_JMP-MEM_ORG       # Start BTX
215
216 # Enable A20 so we can access memory above 1 meg.
217
218 seta20:         cli                             # Disable interrupts
219 seta20.1:       inb $0x64,%al                   # Get status
220                 testb $0x2,%al                  # Busy?
221                 jnz seta20.1                    # Yes
222                 movb $0xd1,%al                  # Command: Write
223                 outb %al,$0x64                  #  output port
224 seta20.2:       inb $0x64,%al                   # Get status
225                 testb $0x2,%al                  # Busy?
226                 jnz seta20.2                    # Yes
227                 movb $0xdf,%al                  # Enable
228                 outb %al,$0x60                  #  A20
229                 sti                             # Enable interrupts
230                 retw                            # To caller
231 .endif
232
233 # Trampoline used to call read from within boot1.
234
235 nread:          mov $MEM_BUF,%bx                # Transfer buffer
236 nreadbx:                                        # same but address is in bx
237                 mov 0x8(%si),%ax                # Get
238                 mov 0xa(%si),%cx                #  LBA
239                 push %bx
240                 push %ax
241                 callw putword
242                 pop %ax
243                 pop %bx
244                 push %cs                        # Read from
245                 callw xread.1                   #  disk
246                 jnc return                      # If success, return
247                 mov $msg_read,%si               # Otherwise, set the error
248                                                 #  message and fall through to
249                                                 #  the error routine
250
251 # Print out the error message pointed to by %ds:(%si) followed
252 # by a prompt, wait for a keypress, and then reboot the machine.
253
254 error:          callw putstr                    # Display message
255                 mov $prompt,%si                 # Display
256                 callw putstr                    #  prompt
257                 xorb %ah,%ah                    # BIOS: Get
258                 int $0x16                       #  keypress
259                 movw $0x1234, BDA_BOOT          # Do a warm boot
260                 ljmp $0xffff,$0x0               # reboot the machine
261
262 # Display a null-terminated string using the BIOS output.
263
264 putstr.0:       call putchar
265 putstr:         lodsb                           # Get char
266                 testb %al,%al                   # End of string?
267                 jne putstr.0                    # No
268                 retw
269
270 putword:        push %ax
271                 movb $'.', %al
272                 callw putchar
273                 movb %ah, %al
274                 callw puthex
275                 pop %ax
276 puthex:         push %ax
277                 shr $4, %al
278                 callw putdigit
279                 pop %ax
280 putdigit:
281                 andb $0xf, %al
282                 addb $0x30, %al
283                 cmpb $0x39, %al
284                 jbe putchar
285                 addb $7, %al
286 putchar:        push %ax
287                 mov $0x7,%bx
288                 movb $0xe,%ah
289                 int $0x10
290                 pop %ax
291                 retw
292
293 #
294 # Overused return code.  ereturn is used to return an error from the
295 # read function.  Since we assume putstr succeeds, we (ab)use the
296 # same code when we return from putstr. 
297
298 ereturn:        movb $0x1,%ah                   # Invalid
299                 stc                             #  argument
300 return:         retw                            # To caller
301
302 # Reads sectors from the disk.  If EDD is enabled, then check if it is
303 # installed and use it if it is.  If it is not installed or not enabled, then
304 # fall back to using CHS.  Since we use a LBA, if we are using CHS, we have to
305 # fetch the drive parameters from the BIOS and divide it out ourselves.
306 # Call with:
307 #
308 # %dl   - byte     - drive number
309 # stack - 10 bytes - EDD Packet
310 #
311 read:           push %dx                        # Save
312                 movb $0x8,%ah                   # BIOS: Get drive
313                 int $0x13                       #  parameters
314                 movb %dh,%ch                    # Max head number
315                 pop %dx                         # Restore
316                 jc return                       # If error
317                 andb $0x3f,%cl                  # Sectors per track
318                 jz ereturn                      # If zero
319                 cli                             # Disable interrupts
320                 mov 0x8(%bp),%eax               # Get LBA
321                 push %dx                        # Save
322                 movzbl %cl,%ebx                 # Divide by
323                 xor %edx,%edx                   #  sectors
324                 div %ebx                        #  per track
325                 movb %ch,%bl                    # Max head number
326                 movb %dl,%ch                    # Sector number
327                 inc %bx                         # Divide by
328                 xorb %dl,%dl                    #  number
329                 div %ebx                        #  of heads
330                 movb %dl,%bh                    # Head number
331                 pop %dx                         # Restore
332                 cmpl $0x3ff,%eax                # Cylinder number supportable?
333                 sti                             # Enable interrupts
334                 ja read.7                       # No, try EDD
335                 xchgb %al,%ah                   # Set up cylinder
336                 rorb $0x2,%al                   #  number
337                 orb %ch,%al                     # Merge
338                 inc %ax                         #  sector
339                 xchg %ax,%cx                    #  number
340                 movb %bh,%dh                    # Head number
341                 subb %ah,%al                    # Sectors this track
342                 mov 0x2(%bp),%ah                # Blocks to read
343                 cmpb %ah,%al                    # To read
344                 jb read.2                       #  this
345                 movb %ah,%al                    #  track
346 read.2:         mov $0x5,%di                    # Try count
347 read.3:         les 0x4(%bp),%bx                # Transfer buffer
348                 push %ax                        # Save
349                 movb $0x2,%ah                   # BIOS: Read
350                 int $0x13                       #  from disk
351                 pop %bx                         # Restore
352                 jnc read.4                      # If success
353                 dec %di                         # Retry?
354                 jz read.6                       # No
355                 xorb %ah,%ah                    # BIOS: Reset
356                 int $0x13                       #  disk system
357                 xchg %bx,%ax                    # Block count
358                 jmp read.3                      # Continue
359 read.4:         movzbw %bl,%ax                  # Sectors read
360                 add %ax,0x8(%bp)                # Adjust
361                 jnc read.5                      #  LBA,
362                 incw 0xa(%bp)                   #  transfer
363 read.5:         shlb %bl                        #  buffer
364                 add %bl,0x5(%bp)                #  pointer,
365                 sub %al,0x2(%bp)                #  block count
366                 ja read                         # If not done
367 read.6:         retw                            # To caller
368 read.7:         testb $FL_PACKET,%cs:MEM_REL+flags-start # LBA support enabled?
369                 jz ereturn                      # No, so return an error
370                 mov $0x55aa,%bx                 # Magic
371                 push %dx                        # Save
372                 movb $0x41,%ah                  # BIOS: Check
373                 int $0x13                       #  extensions present
374                 pop %dx                         # Restore
375                 jc return                       # If error, return an error
376                 cmp $0xaa55,%bx                 # Magic?
377                 jne ereturn                     # No, so return an error
378                 testb $0x1,%cl                  # Packet interface?
379                 jz ereturn                      # No, so return an error
380                 mov %bp,%si                     # Disk packet
381                 movb $0x42,%ah                  # BIOS: Extended
382                 int $0x13                       #  read
383                 retw                            # To caller
384
385 # Messages
386
387 msg_read:       .asciz "Rd"
388 msg_part:       .asciz "Boot"
389
390 prompt:         .asciz " err\r\n"
391
392 flags:          .byte FLAGS                     # Flags
393
394                 .org PRT_OFF,0x90
395
396 # Partition table
397
398                 .fill 0x30,0x1,0x0
399 part4:          .byte 0x80
400                 .byte 0x00      # start head
401                 .byte 0x01      # start sector (6 bits) + start cyl (2 bit)
402                 .byte 0x00      # start cyl (low 8 bits)
403                 .byte 0x1       # part.type
404                 .byte 0xff      # end head
405                 .byte 0xff      # end sect (6) + end_cyl(2)
406                 .byte 0xff      # end cyl
407                 .byte 0x00, 0x00, 0x00, 0x00    # explicit start
408                 .byte 0x50, 0xc3, 0x00, 0x00    # 50000 sectors long, bleh
409
410                 .word 0xaa55                    # Magic number