Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/boot/x86/tools/bootsect/bootsect.S

/* [<][>][^][v][top][bottom][index][help] */
   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

/* [<][>][^][v][top][bottom][index][help] */