/*- * Copyright (c) 2005, Kohsuke Ohtani * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /** * bootsect.s - Boot sector for FAT * * The boot sector is 512 byte code to load the OS image. It is loaded * to address 0:7c00 by POST BIOS. * The boot sector searches the target file within the root directory of * FAT file system, and loads it to predefined memory address. Then, it * jumps to the first byte of the loaded image. * * All disk access are done by using BIOS Int13h interface. The BIOS * parameter block (BPB) has the disk/FAT information, and it exists * in the first portion of the FAT boot sector. It must be filled by the * FAT format utility, or the prex kernel install utility (mkboot.com). * This program assumes that correct BPB is stored in the boot sector. * * Limitation: * - Support only FAT12/16. FAT32 is not supported. * * Memory usage: * > 5000 - 6FFF ... Disk work area * > 7000 - 7BFF ... Stack * > 7C00 - 7DFF ... This boot sector * >10000 - ... FAT cache * >20000 - ... Data cache * >30000 - ... Image load address */ .code16 .text .align 1 # Memory locations #define BOOT_STACK 0x7c00 #define LOAD_ADDR 0x30000 #define ENTRY_SEG 0x3000 #define ENTRY_OFF 0x0000 #define WORK_AREA 0x5000 #define FAT_SEG 0x1000 #define DATA_SEG 0x2000 #define LOAD_MAX 0xA0000 # FAT Directory entry #define F_NAME 0 #define F_ATTR 11 #define F_RESERVED 12 #define F_TIME 22 #define F_DATA 24 #define F_CLUSTER 26 #define F_SIZE 28 #define DIR_SIZE 32 #define DIRENT_PER_SECTOR 16 # BIOS parameter block (BPB) location (%bp points to 0x7c00) #define OEM_ID 0x03(%bp) #define BYTE_PER_SECTOR 0x0b(%bp) #define SECT_PER_CLUSTER 0x0d(%bp) #define RESERVED_SECTORS 0x0e(%bp) #define NUM_OF_FATS 0x10(%bp) #define ROOT_ENTRIES 0x11(%bp) #define TOTAL_SECTORS 0x13(%bp) #define MEDIA_DESCRIPTOR 0x15(%bp) #define SECTORS_PER_FAT 0x16(%bp) #define SECTORS_PER_TRACK 0x18(%bp) #define HEADS 0x1a(%bp) #define HIDDEN_SECTORS 0x1c(%bp) #define BIG_TOTAL_SECTORS 0x20(%bp) #define PHYSICAL_DRIVE 0x24(%bp) #define EXT_BOOT_SIGNATURE 0x26(%bp) #define SERIAL_NO 0x27(%bp) #define VOLUME_ID 0x2b(%bp) #define FILE_SYS_ID 0x36(%bp) #define FILE_SYS_ID_NUM 0x3a(%bp) # Local data area (Note: These data will overlap the existing code) #define FAT_START 0x40(%bp) #define DATA_START 0x44(%bp) .global _boot # # Boot the system # _boot: jmp start # Skip BPB nop # Nop is for DOS compatibility # # BPB # .ascii "PREX1.00" .fill 0x33, 1, 0 # Drive parameter must be # filled by intaller # # Setup stack and segment registers # start: cli cld # Clear direction flag xorl %eax, %eax # Set EAX to zero movw %ax, %ds movw %ax, %es movw %ax, %ss movw $(BOOT_STACK), %sp movw %sp, %bp # EBP = Bios Parameter Block sti # # Display boot message # movw $load_msg, %si movw $21, %cx call puts # # Store disk information # movl HIDDEN_SECTORS, %ebx # Get hidden sector movw RESERVED_SECTORS, %ax # Add reserved sector addl %eax, %ebx # High 16 bit of EAX is 0 movl %ebx, FAT_START # FAT start = hidden + reserved movzbw NUM_OF_FATS, %ax # Normally 2 mulw SECTORS_PER_FAT # AX = Num of sector of FATs addl %ebx, %eax # EAX = Start of root directory movw ROOT_ENTRIES, %bx shrw $4, %bx # / 16 = DIRENT_PER_SECTOR movw %bx, %cx # CX = Num of sectors for root directory addl %eax, %ebx # DATA start = FAT start + root movl %ebx, DATA_START # Start sector of data area # # Find the OS image in the root directory # # EAX = Start sector of root next_sector: pushw %cx movl $(WORK_AREA), %ebx pushw %bx call read_sector # Read 1 sector in root popw %di # DI = dir_entry movw $(DIRENT_PER_SECTOR), %cx # CX = directory count next_entry: cmpb $0, (%di) # End of dir entry ? je error # Not found testb $0x18, F_ATTR(%di) # Subdir or Volume ? jnz not_file # Skip it pusha movw $11, %cx # File name + ext = 11 byte movw $image_name, %si repe # Compare file name cmpsb popa je found_file not_file: addw $(DIR_SIZE), %di # Check next directory entry loop next_entry popw %cx loop next_sector # Fall through # # Error case # error: movw $err_msg, %si movw $5, %cx call puts hang: hlt jmp hang # Stop here # # Load image # found_file: movzwl F_CLUSTER(%di), %eax # EAX = 1st cluster of loader movl $(LOAD_ADDR), %ebx # EBX = 32bit load address load_next: call read_cluster # Read cluster of loader call next_cluster # Get next cluster# in EAX jb load_next # EOF ? # # Turn fdd motor off # movw $0x3f2, %dx xorb %al, %al outb %al, %dx # # Jump to loaded image # ljmp $0x3000, $0x0 # # Puts - Print string # # Entry: # SI - Pointer to message string # CX - Number of character # puts: lodsb movb $0x0e, %ah movw $0x0007, %bx int $0x10 loop puts ret # # next_cluster - Return next cluster # # Entry: # EAX - Current cluter# # # Exit: # AF - End of cluster # EAX - Next cluter# # # Modified: # Flags,CX,EDX,SI,DI # next_cluster: pushl %ebx movw %ax, %di # Save cluster# in DI movw $0xfff8, %si # Set default EOF to FAT16 movl %eax, %ecx shll $1, %eax # * 2 cmpb $0x36, FILE_SYS_ID_NUM # ID is 'FAT16' ? je fat_16 addl %ecx, %eax # * 3 shrl $1, %eax # / 2 movw $0xff8, %si # EOF for FAT12 fat_16: # EAX - Offset of FAT entry xorw %dx, %dx divw BYTE_PER_SECTOR addl FAT_START, %eax # EAX = Sector# for FAT # DX = Offset in sector movl $(WORK_AREA), %ebx pushw %bx call read_sector # Read 2 sector for border call read_sector # data popw %bx addw %dx, %bx movw (%bx), %ax cmpw $0xfff8, %si # FAT16 ? je chk_end shrw $1, %di jc odd_pos andb $0x0f, %ah jmp chk_end odd_pos: shrw $4, %ax chk_end: cmpw %si, %ax popl %ebx ret # # read_cluster - Read one cluster # # Entry: # EBX - 32-bit pointer to buffer # EAX - Cluster number # # Exit: # EBX - Point to next buffer # # Modified: # flags,ECX,ECX,EDX # read_cluster: pushl %eax decw %ax # Translate clust# to sec# decw %ax xorl %ecx, %ecx movb SECT_PER_CLUSTER, %cl mull %ecx addl DATA_START, %eax # EAX = Read sec# # CX = Read sector size read_loop: call read_sector cmpl $(LOAD_MAX), %ebx jae error loop read_loop popl %eax ret # # read_sector - Read one sector # # Entry: # EBX - 32-bit pointer to buffer # EAX - Logical sector# to read # # Exit: # EBX - Pointer to next buffer # EAX - Next sector # # Modified: # Flags # read_sector: pushal pushw %ds pushw %es movl %eax, %esi # ESI = buffer movzwl SECTORS_PER_TRACK, %ecx # Get sec/track xorl %edx, %edx divl %ecx # EAX = track# # DX = sec# movw $(DATA_SEG), %cx # Check in cache leaw last_data, %di cmpl DATA_START, %esi jae data_reqest movw $(FAT_SEG), %cx leaw last_fat, %di data_reqest: # CX = Cached segment pushal # [DI] = Cached track movw %cx, %es xorw %bx, %bx # ES:BX = Cache address cmpl (%di), %eax # Last track ? je hit_cache movl %eax, (%di) # Save current track# call read_track hit_cache: popal pushw %es popw %ds shlw $9, %dx # sec# * 512 movw %dx, %si # DS:SI = Offset in cache movw %bx, %di # [EBX] -> ES:[DI] andw $0xf, %di shrl $4, %ebx movw %bx, %es mov $512, %cx # Copy 1 sector rep movsb popw %es popw %ds popal addl $512, %ebx # Next buffer incl %eax # Next sector ret # # read_track - Read one track # # Entry: # ES:[BX] - Pointer to buffer # EAX - Track number to read # # Exit: # None # # Modified: # Flags,EAX,ECX,EDX # read_track: movzwl HEADS, %ecx # Get num of head xorl %edx, %edx divl %ecx # AX = cyl# # DL = head# movb %al, %ch # CH = cyl# (low 8 bits) andb $3, %ah shlb $6, %ah orb $1, %ah movb %ah, %cl # CL[7:6] = cyl# (high 2 bits) # CL[5:0] = sec# = 1 movb %dl, %dh # DH = Head# movw SECTORS_PER_TRACK, %ax # AL = Num of sectors to read movb $2, %ah # AH = 02h (Read Disk Sectors) movb PHYSICAL_DRIVE, %dl # DL = Drive# int $0x13 # Invoke Disk BIOS jc error ret # # Local Data # last_fat: .long 0xffffffff last_data: .long 0xffffffff load_msg: .ascii "Loading " image_name: .ascii "PREXOS " crlf: .byte 0x0a, 0x0d err_msg: .ascii "Error" .org 510 .word 0xaa55