Annotation of prex/boot/i386/utils/bootsect/bootsect.S, Revision 1.1
1.1 ! nbrk 1: /*-
! 2: * Copyright (c) 2005, Kohsuke Ohtani
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. Neither the name of the author nor the names of any co-contributors
! 14: * may be used to endorse or promote products derived from this software
! 15: * without specific prior written permission.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: */
! 29:
! 30: /**
! 31: * bootsect.s - Boot sector for FAT
! 32: *
! 33: * The boot sector is 512 byte code to load the OS image. It is loaded
! 34: * to address 0:7c00 by POST BIOS.
! 35: * The boot sector searches the target file within the root directory of
! 36: * FAT file system, and loads it to predefined memory address. Then, it
! 37: * jumps to the first byte of the loaded image.
! 38: *
! 39: * All disk access are done by using BIOS Int13h interface. The BIOS
! 40: * parameter block (BPB) has the disk/FAT information, and it exists
! 41: * in the first portion of the FAT boot sector. It must be filled by the
! 42: * FAT format utility, or the prex kernel install utility (mkboot.com).
! 43: * This program assumes that correct BPB is stored in the boot sector.
! 44: *
! 45: * Limitation:
! 46: * - Support only FAT12/16. FAT32 is not supported.
! 47: *
! 48: * Memory usage:
! 49: * > 5000 - 6FFF ... Disk work area
! 50: * > 7000 - 7BFF ... Stack
! 51: * > 7C00 - 7DFF ... This boot sector
! 52: * >10000 - ... FAT cache
! 53: * >20000 - ... Data cache
! 54: * >30000 - ... Image load address
! 55: */
! 56: .code16
! 57: .text
! 58: .align 1
! 59:
! 60: # Memory locations
! 61: #define BOOT_STACK 0x7c00
! 62:
! 63: #define LOAD_ADDR 0x30000
! 64: #define ENTRY_SEG 0x3000
! 65: #define ENTRY_OFF 0x0000
! 66:
! 67: #define WORK_AREA 0x5000
! 68: #define FAT_SEG 0x1000
! 69: #define DATA_SEG 0x2000
! 70:
! 71: #define LOAD_MAX 0xA0000
! 72:
! 73: # FAT Directory entry
! 74: #define F_NAME 0
! 75: #define F_ATTR 11
! 76: #define F_RESERVED 12
! 77: #define F_TIME 22
! 78: #define F_DATA 24
! 79: #define F_CLUSTER 26
! 80: #define F_SIZE 28
! 81:
! 82: #define DIR_SIZE 32
! 83: #define DIRENT_PER_SECTOR 16
! 84:
! 85: # BIOS parameter block (BPB) location (%bp points to 0x7c00)
! 86: #define OEM_ID 0x03(%bp)
! 87: #define BYTE_PER_SECTOR 0x0b(%bp)
! 88: #define SECT_PER_CLUSTER 0x0d(%bp)
! 89: #define RESERVED_SECTORS 0x0e(%bp)
! 90: #define NUM_OF_FATS 0x10(%bp)
! 91: #define ROOT_ENTRIES 0x11(%bp)
! 92: #define TOTAL_SECTORS 0x13(%bp)
! 93: #define MEDIA_DESCRIPTOR 0x15(%bp)
! 94: #define SECTORS_PER_FAT 0x16(%bp)
! 95: #define SECTORS_PER_TRACK 0x18(%bp)
! 96: #define HEADS 0x1a(%bp)
! 97: #define HIDDEN_SECTORS 0x1c(%bp)
! 98: #define BIG_TOTAL_SECTORS 0x20(%bp)
! 99: #define PHYSICAL_DRIVE 0x24(%bp)
! 100: #define EXT_BOOT_SIGNATURE 0x26(%bp)
! 101: #define SERIAL_NO 0x27(%bp)
! 102: #define VOLUME_ID 0x2b(%bp)
! 103: #define FILE_SYS_ID 0x36(%bp)
! 104:
! 105: #define FILE_SYS_ID_NUM 0x3a(%bp)
! 106:
! 107: # Local data area (Note: These data will overlap the existing code)
! 108: #define FAT_START 0x40(%bp)
! 109: #define DATA_START 0x44(%bp)
! 110:
! 111: .global _boot
! 112:
! 113: #
! 114: # Boot the system
! 115: #
! 116: _boot:
! 117: jmp start # Skip BPB
! 118: nop # Nop is for DOS compatibility
! 119:
! 120: #
! 121: # BPB
! 122: #
! 123: .ascii "PREX1.00"
! 124: .fill 0x33, 1, 0 # Drive parameter must be
! 125: # filled by intaller
! 126:
! 127: #
! 128: # Setup stack and segment registers
! 129: #
! 130: start:
! 131: cli
! 132: cld # Clear direction flag
! 133: xorl %eax, %eax # Set EAX to zero
! 134: movw %ax, %ds
! 135: movw %ax, %es
! 136: movw %ax, %ss
! 137: movw $(BOOT_STACK), %sp
! 138: movw %sp, %bp # EBP = Bios Parameter Block
! 139: sti
! 140:
! 141: #
! 142: # Display boot message
! 143: #
! 144: movw $load_msg, %si
! 145: movw $21, %cx
! 146: call puts
! 147:
! 148: #
! 149: # Store disk information
! 150: #
! 151: movl HIDDEN_SECTORS, %ebx # Get hidden sector
! 152: movw RESERVED_SECTORS, %ax # Add reserved sector
! 153: addl %eax, %ebx # High 16 bit of EAX is 0
! 154: movl %ebx, FAT_START # FAT start = hidden + reserved
! 155:
! 156: movzbw NUM_OF_FATS, %ax # Normally 2
! 157: mulw SECTORS_PER_FAT # AX = Num of sector of FATs
! 158: addl %ebx, %eax # EAX = Start of root directory
! 159:
! 160: movw ROOT_ENTRIES, %bx
! 161: shrw $4, %bx # / 16 = DIRENT_PER_SECTOR
! 162: movw %bx, %cx # CX = Num of sectors for root directory
! 163:
! 164: addl %eax, %ebx # DATA start = FAT start + root
! 165: movl %ebx, DATA_START # Start sector of data area
! 166:
! 167: #
! 168: # Find the OS image in the root directory
! 169: #
! 170: # EAX = Start sector of root
! 171: next_sector:
! 172: pushw %cx
! 173: movl $(WORK_AREA), %ebx
! 174: pushw %bx
! 175: call read_sector # Read 1 sector in root
! 176: popw %di # DI = dir_entry
! 177: movw $(DIRENT_PER_SECTOR), %cx # CX = directory count
! 178: next_entry:
! 179: cmpb $0, (%di) # End of dir entry ?
! 180: je error # Not found
! 181: testb $0x18, F_ATTR(%di) # Subdir or Volume ?
! 182: jnz not_file # Skip it
! 183: pusha
! 184: movw $11, %cx # File name + ext = 11 byte
! 185: movw $image_name, %si
! 186: repe # Compare file name
! 187: cmpsb
! 188: popa
! 189: je found_file
! 190: not_file:
! 191: addw $(DIR_SIZE), %di # Check next directory entry
! 192: loop next_entry
! 193: popw %cx
! 194: loop next_sector
! 195: # Fall through
! 196: #
! 197: # Error case
! 198: #
! 199: error:
! 200: movw $err_msg, %si
! 201: movw $5, %cx
! 202: call puts
! 203: hang:
! 204: hlt
! 205: jmp hang # Stop here
! 206:
! 207: #
! 208: # Load image
! 209: #
! 210: found_file:
! 211: movzwl F_CLUSTER(%di), %eax # EAX = 1st cluster of loader
! 212: movl $(LOAD_ADDR), %ebx # EBX = 32bit load address
! 213: load_next:
! 214: call read_cluster # Read cluster of loader
! 215: call next_cluster # Get next cluster# in EAX
! 216: jb load_next # EOF ?
! 217:
! 218: #
! 219: # Turn fdd motor off
! 220: #
! 221: movw $0x3f2, %dx
! 222: xorb %al, %al
! 223: outb %al, %dx
! 224:
! 225: #
! 226: # Jump to loaded image
! 227: #
! 228: ljmp $0x3000, $0x0
! 229:
! 230: #
! 231: # Puts - Print string
! 232: #
! 233: # Entry:
! 234: # SI - Pointer to message string
! 235: # CX - Number of character
! 236: #
! 237: puts:
! 238: lodsb
! 239: movb $0x0e, %ah
! 240: movw $0x0007, %bx
! 241: int $0x10
! 242: loop puts
! 243: ret
! 244:
! 245: #
! 246: # next_cluster - Return next cluster
! 247: #
! 248: # Entry:
! 249: # EAX - Current cluter#
! 250: #
! 251: # Exit:
! 252: # AF - End of cluster
! 253: # EAX - Next cluter#
! 254: #
! 255: # Modified:
! 256: # Flags,CX,EDX,SI,DI
! 257: #
! 258: next_cluster:
! 259: pushl %ebx
! 260: movw %ax, %di # Save cluster# in DI
! 261:
! 262: movw $0xfff8, %si # Set default EOF to FAT16
! 263:
! 264: movl %eax, %ecx
! 265: shll $1, %eax # * 2
! 266:
! 267: cmpb $0x36, FILE_SYS_ID_NUM # ID is 'FAT16' ?
! 268: je fat_16
! 269: addl %ecx, %eax # * 3
! 270: shrl $1, %eax # / 2
! 271: movw $0xff8, %si # EOF for FAT12
! 272: fat_16:
! 273: # EAX - Offset of FAT entry
! 274: xorw %dx, %dx
! 275: divw BYTE_PER_SECTOR
! 276: addl FAT_START, %eax # EAX = Sector# for FAT
! 277: # DX = Offset in sector
! 278: movl $(WORK_AREA), %ebx
! 279: pushw %bx
! 280: call read_sector # Read 2 sector for border
! 281: call read_sector # data
! 282: popw %bx
! 283: addw %dx, %bx
! 284: movw (%bx), %ax
! 285: cmpw $0xfff8, %si # FAT16 ?
! 286: je chk_end
! 287:
! 288: shrw $1, %di
! 289: jc odd_pos
! 290: andb $0x0f, %ah
! 291: jmp chk_end
! 292: odd_pos:
! 293: shrw $4, %ax
! 294: chk_end:
! 295: cmpw %si, %ax
! 296: popl %ebx
! 297: ret
! 298:
! 299: #
! 300: # read_cluster - Read one cluster
! 301: #
! 302: # Entry:
! 303: # EBX - 32-bit pointer to buffer
! 304: # EAX - Cluster number
! 305: #
! 306: # Exit:
! 307: # EBX - Point to next buffer
! 308: #
! 309: # Modified:
! 310: # flags,ECX,ECX,EDX
! 311: #
! 312: read_cluster:
! 313: pushl %eax
! 314: decw %ax # Translate clust# to sec#
! 315: decw %ax
! 316: xorl %ecx, %ecx
! 317: movb SECT_PER_CLUSTER, %cl
! 318: mull %ecx
! 319: addl DATA_START, %eax # EAX = Read sec#
! 320: # CX = Read sector size
! 321: read_loop:
! 322: call read_sector
! 323: cmpl $(LOAD_MAX), %ebx
! 324: jae error
! 325: loop read_loop
! 326: popl %eax
! 327: ret
! 328:
! 329: #
! 330: # read_sector - Read one sector
! 331: #
! 332: # Entry:
! 333: # EBX - 32-bit pointer to buffer
! 334: # EAX - Logical sector# to read
! 335: #
! 336: # Exit:
! 337: # EBX - Pointer to next buffer
! 338: # EAX - Next sector
! 339: #
! 340: # Modified:
! 341: # Flags
! 342: #
! 343: read_sector:
! 344: pushal
! 345: pushw %ds
! 346: pushw %es
! 347:
! 348: movl %eax, %esi # ESI = buffer
! 349:
! 350: movzwl SECTORS_PER_TRACK, %ecx # Get sec/track
! 351: xorl %edx, %edx
! 352: divl %ecx # EAX = track#
! 353: # DX = sec#
! 354: movw $(DATA_SEG), %cx # Check in cache
! 355: leaw last_data, %di
! 356: cmpl DATA_START, %esi
! 357: jae data_reqest
! 358: movw $(FAT_SEG), %cx
! 359: leaw last_fat, %di
! 360: data_reqest:
! 361: # CX = Cached segment
! 362: pushal # [DI] = Cached track
! 363: movw %cx, %es
! 364: xorw %bx, %bx # ES:BX = Cache address
! 365: cmpl (%di), %eax # Last track ?
! 366: je hit_cache
! 367: movl %eax, (%di) # Save current track#
! 368: call read_track
! 369: hit_cache:
! 370: popal
! 371:
! 372: pushw %es
! 373: popw %ds
! 374:
! 375: shlw $9, %dx # sec# * 512
! 376: movw %dx, %si # DS:SI = Offset in cache
! 377:
! 378: movw %bx, %di # [EBX] -> ES:[DI]
! 379: andw $0xf, %di
! 380: shrl $4, %ebx
! 381: movw %bx, %es
! 382:
! 383: mov $512, %cx # Copy 1 sector
! 384: rep
! 385: movsb
! 386:
! 387: popw %es
! 388: popw %ds
! 389: popal
! 390:
! 391: addl $512, %ebx # Next buffer
! 392: incl %eax # Next sector
! 393: ret
! 394:
! 395: #
! 396: # read_track - Read one track
! 397: #
! 398: # Entry:
! 399: # ES:[BX] - Pointer to buffer
! 400: # EAX - Track number to read
! 401: #
! 402: # Exit:
! 403: # None
! 404: #
! 405: # Modified:
! 406: # Flags,EAX,ECX,EDX
! 407: #
! 408: read_track:
! 409: movzwl HEADS, %ecx # Get num of head
! 410: xorl %edx, %edx
! 411: divl %ecx # AX = cyl#
! 412: # DL = head#
! 413:
! 414: movb %al, %ch # CH = cyl# (low 8 bits)
! 415: andb $3, %ah
! 416: shlb $6, %ah
! 417: orb $1, %ah
! 418: movb %ah, %cl # CL[7:6] = cyl# (high 2 bits)
! 419: # CL[5:0] = sec# = 1
! 420: movb %dl, %dh # DH = Head#
! 421: movw SECTORS_PER_TRACK, %ax # AL = Num of sectors to read
! 422: movb $2, %ah # AH = 02h (Read Disk Sectors)
! 423: movb PHYSICAL_DRIVE, %dl # DL = Drive#
! 424: int $0x13 # Invoke Disk BIOS
! 425: jc error
! 426: ret
! 427:
! 428: #
! 429: # Local Data
! 430: #
! 431: last_fat: .long 0xffffffff
! 432: last_data: .long 0xffffffff
! 433:
! 434: load_msg: .ascii "Loading "
! 435: image_name: .ascii "PREXOS "
! 436: crlf: .byte 0x0a, 0x0d
! 437: err_msg: .ascii "Error"
! 438:
! 439: .org 510
! 440: .word 0xaa55
CVSweb