Advertisement
Guest User

Full Bootloader Source

a guest
Apr 4th, 2012
888
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. org 0
  2. bits 16
  3.  
  4. jmp _main
  5. nop                                                     ; We need to fill up 3 bytes as part of the BPB
  6.  
  7. _bpb:
  8.     _bpb.oem                        db "Scratch "       ; OEM name or version
  9.     _bpb.bytesPerSector             dw 0x0200           ; Bytes per Sector (512)
  10.     _bpb.sectorsPerCluster          db 0x01             ; Sectors per cluster (usually 1)
  11.     _bpb.reservedSectors            dw 0x0001           ; Reserved sectors
  12.     _bpb.totalFATs                  db 0x0002           ; FAT copies
  13.     _bpb.rootEntries                dw 0x00e0           ; Root directory entries
  14.     _bpb.fat12.totalSectors         dw 0x0000           ; Sectors in filesystem (0 for FAT16)
  15.     _bpb.mediaDescriptor            db 0xf0             ; Media descriptor type (f0 for floppy or f8 for HDD)
  16.     _bpb.sectorsPerFAT              dw 0x0009           ; Sectors per FAT
  17.     _bpb.sectorsPerTrack            dw 0x0012           ; Sectors per track
  18.     _bpb.headsPerCylinder           dw 0x0002           ; Heads per cylinder
  19.     _bpb.hiddenSectors              dd 0x00000000       ; Number of hidden sectors (0)
  20.     _bpb.totalSectors               dd 0x00000b40       ; Number of sectors in the filesystem
  21.     _bpb.driveNumber                db 0x00             ; Sectors per FAT
  22.     _bpb.currentHead                db 0x00             ; Reserved (used to be current head)
  23.     _bpb.signature                  db 0x29             ; Extended signature (indicates we have serial, label, and type)
  24.     _bpb.serial                     dd 0xb3771b01       ; Serial number of partition
  25.     _bpb.diskLabel                  db "OS Dev     "    ; Volume label
  26.     _bpb.fileSystem                 db "FAT16   "       ; Filesystem type
  27.  
  28. _data:
  29.     fs.dataSector dw 0                          ; Stores our data sector
  30.     fileCluster  dw 0                           ; Stores the cluster of the strap file
  31.     chs:
  32.         chs.track db 0                          ; Stores the track\cylinder for LBAToCHS
  33.         chs.head db 0                           ; Stores the head for LBAToCHS
  34.         chs.sector db 0                         ; Stores the sector for LBAToCHS
  35.     filename db 'BOOT       '
  36.  
  37. _main:
  38.     ; Set up our segment registers and stack
  39.     cli                                                 ; We don't want our interrupts ATM
  40.     mov ax, 0x07c0                                      ; We're at 0000:7c000, so set our segment registers to that
  41.     mov ds, ax
  42.     mov es, ax
  43.     mov fs, ax
  44.     mov gs, ax
  45.  
  46.     mov ax, 0                                           ; Set our stack to 0x0000 and create it
  47.     mov ss, ax
  48.     mov sp, 0xffff
  49.     sti                                                 ; We can haz interrupts again!
  50.    
  51.     .loadRootDir:
  52.         xor cx, cx
  53.         xor dx, dx
  54.         mov ax, 0x0020                                  ; Every directory\file entry is 32 bytes (or 0x20)
  55.         mul word[_bpb.rootEntries]                      ; Entry size * number of root entries = size of root (in clusters)
  56.         div word[_bpb.bytesPerSector]                   ; Clusters / sectors per cluster = sectors of root
  57.         xchg ax, cx
  58.        
  59.         ; Compute the location of the FAT
  60.         mov al, byte[_bpb.totalFATs]
  61.         mul word[_bpb.sectorsPerFAT]
  62.         add ax, word[_bpb.reservedSectors]
  63.         mov word[fs.dataSector], ax
  64.         add word[fs.dataSector], cx
  65.        
  66.         ; DEBUG
  67.         push ax
  68.         mov ah, 0eh
  69.         mov al, 'T'
  70.         int 10h
  71.         pop ax
  72.        
  73.         ; Read the FAT to [7C00:0200]
  74.         mov bx, 0x0200
  75.         call ReadSectors
  76.         push ax
  77.        
  78.         ; DEBUG
  79.         mov ah, 0eh
  80.         mov al, 'D'
  81.         int 10h
  82.         pop ax
  83.        
  84.         mov cx, word[_bpb.rootEntries]                  ; We want to iterate through each entry
  85.         mov di, 0x0200                                  ; The first entry will be here (at [7C00:0200])
  86.    
  87.     .findFile:
  88.         push cx
  89.         mov cx, 0x000b
  90.         mov si, filename
  91.         push di
  92.         rep cmpsb
  93.         pop di
  94.         je .loadFile
  95.         pop cx
  96.         add di, 0x0020
  97.         loop .findFile
  98.         jmp .fail
  99.    
  100.     ; DI + 0x001A now contains the file's first cluster
  101.     .loadFile:
  102.         ; DEBUG
  103.         push ax
  104.         mov ah, 0eh
  105.         mov al, 0x0d
  106.         int 10h
  107.         mov al, 0x0a
  108.         int 10h
  109.         mov al, '.'
  110.         int 10h
  111.         pop ax
  112.        
  113.         .load.fat:
  114.             mov dx, word[di+0x001a]
  115.             mov word[fileCluster], dx                   ; Save the file's first cluster to file
  116.            
  117.             ; Store FAT size in AX (FAT size = Number of FATs + Sectors per FAT)
  118.             xor ax, ax
  119.             mov al, byte[_bpb.totalFATs]
  120.             mul word[_bpb.sectorsPerFAT]
  121.             mov cx, ax
  122.            
  123.             mov ax, word[_bpb.reservedSectors]          ; Store number of reserved sectors in AX
  124.            
  125.             mov bx, 0x0200
  126.             call ReadSectors                            ; Copy the FAT to 0x0200
  127.            
  128.             ; DEBUG
  129.             push ax
  130.             mov ah, 0eh
  131.             mov al, 'F'
  132.             int 10h
  133.             pop ax
  134.            
  135.             ; Load the next stage to [0050:0000]
  136.             mov ax, 0x0050
  137.             mov es, ax
  138.             mov bx, 0x0000
  139.             push bx
  140.        
  141.         .load.file:
  142.             mov ax, word[fileCluster]
  143.             pop bx
  144.             call ClusterToLBA
  145.             xor cx, cx
  146.             mov cl, byte[_bpb.sectorsPerCluster]
  147.             call ReadSectors
  148.             push bx
  149.            
  150.             mov ax, word[fileCluster]
  151.             mov cx, ax
  152.             mov dx, ax
  153.             shr dx, 0x0001
  154.             add cx, dx
  155.             mov bx, 0x0200
  156.             add bx, cx
  157.             mov dx, word[bx]
  158.             ; test ax, 0x0001
  159.             ; jnz .load.file.odd
  160.             ; jmp .load.file.even
  161.             ;
  162.             ; .load.file.even:
  163.             ;   ; and dx, 0000111111111111b
  164.             ;   jmp .load.file.done
  165.             ;
  166.             ; .load.file.odd:
  167.             ;   ; shr dx, 0x0004
  168.             ;   jmp .load.file.done
  169.            
  170.             .load.file.done:
  171.                 ; DEBUG
  172.                 push ax
  173.                 mov ah, 0eh
  174.                 mov al, 'L'
  175.                 int 10h
  176.                 pop ax
  177.                
  178.                 mov word[fileCluster], dx
  179.                 cmp dx, 0xfff8
  180.                 jb .load.file
  181.                
  182.                 ; DEBUG
  183.                 push ax
  184.                 mov ah, 0eh
  185.                 mov al, 0x0d
  186.                 int 10h
  187.                 mov al, 0x0a
  188.                 int 10h
  189.                 pop ax
  190.                
  191.                 push word 0x0050
  192.                 push word 0x0000
  193.                 retf
  194.                                
  195.                 cli
  196.                 hlt
  197.            
  198.     .fail:
  199.         ; DEBUG
  200.         push ax
  201.         mov ah, 0eh
  202.         mov al, 'E'
  203.         int 10h
  204.         pop ax
  205.        
  206.         mov ah, 00h
  207.         int 16h
  208.         int 19h
  209.  
  210. Print:
  211.     pusha
  212.     Print.loop:
  213.         lodsb                                   ; Load the next character from SI
  214.        
  215.         cmp al, 0                               ; If the character is null,
  216.         je Print.end                            ; then we're done
  217.        
  218.         mov ah, 0eh                             ; Use the 'print character' function
  219.         int 10h                                 ; Call the 'video services' interrupt
  220.         jmp Print.loop                          ; Print the next character as well
  221.  
  222.     Print.end:
  223.         popa
  224.         ret
  225.  
  226. ; Cluster to LBA - Convert from a cluster- to LBA- addressing system
  227. ; Parameters:
  228. ;   AX - Cluster address to convert
  229. ; Returns:
  230. ;   AX - Start of LBA
  231. ;   CX - Length of LBA
  232. ClusterToLBA:   ; Based on the conversion equation LBA = ((Cluster - 2) * SectorsPerCluster)
  233.     sub ax, 2
  234.     xor cx, cx
  235.     mov cl, byte[_bpb.sectorsPerCluster]
  236.     mul cx
  237.     add ax, word[fs.dataSector]
  238.    
  239.     ret
  240.  
  241. ; LBA to CHS - Convert from an LBA- to CHS- addressing system'
  242. ; Parameters:
  243. ;   AX - LBA address to convert
  244. ; Returns:
  245. ;   [chs.track]
  246. ;   [chs.head]
  247. ;   [chs.sector]
  248. LBAToCHS:  
  249.     ; Based on the equation Sector = (LBA % Sectors per Track) + 1
  250.     xor dx, dx
  251.     div word[_bpb.sectorsPerTrack]              ; Calculate the modulo (in DL)
  252.     inc dl
  253.     mov byte[chs.sector], dl                    ; Store it
  254.    
  255.     ; Based on the equation Head = (LBA / Sectors per Track) % Heads per Cylinder
  256.     xor dx, dx
  257.     div WORD [_bpb.headsPerCylinder]                ; AX already contains LBA / Sectors per Track
  258.     mov byte[chs.head], dl
  259.    
  260.     ; Based on the equation Track = LBA / (Sectors per Track * Number of Heads)
  261.     mov byte[chs.track], al                     ; Very conveniently-placed AX; it already contains the output!
  262.    
  263.     ret
  264.  
  265. ; Read Sectors - Reads sectors from disk into memory
  266. ; Parameters:
  267. ;   CX - Number of sectors to read
  268. ;   AX - Starting sector to read
  269. ;   ES:BX - Address to read to
  270. ; Returns:
  271. ;   [ES:BX] - Data from disk
  272. ReadSectors:
  273.     mov di, 0x0005                              ; How many times should we retry the read?
  274.    
  275.     ReadSectors.loop:
  276.         ; DEBUG
  277.         push ax
  278.         mov ah, 0eh
  279.         mov al, '-'
  280.         int 10h
  281.         pop ax
  282.        
  283.         push ax
  284.         push bx
  285.         push cx
  286.        
  287.         call LBAToCHS
  288.        
  289.         mov ah, 02h                             ; Set the interrupt to the 'read sector' function
  290.         mov al, 1                               ; Only read one sector
  291.         mov ch, byte[chs.track]                 ; The track to read from
  292.         mov cl, byte[chs.sector]                ; The sector to read from
  293.         mov dh, byte[chs.head]                  ; The head to read from
  294.         mov dl, byte[_bpb.driveNumber]          ; The drive to read from
  295.         int 13h                                 ; Call our 'disk IO' interrupt
  296.         jnc ReadSectors.success                 ; If we successfully read the data, we don't have to try again
  297.         mov ah, 00h                             ; Set the interrupt to the 'reset disk' function
  298.         int 13h                                 ; Call our 'disk IO' interrupt
  299.         dec di                                  ; Decrement our error counter
  300.         pop cx
  301.         pop bx
  302.         pop ax
  303.         jnz ReadSectors.loop                    ; Try again if we've failed
  304.         jmp ReadSectors.fail                    ; RED ALERT
  305.    
  306.     ReadSectors.success:
  307.         ; DEBUG
  308.         push ax
  309.         mov ah, 0eh
  310.         mov al, '_'
  311.         int 10h
  312.         pop ax
  313.        
  314.         pop cx
  315.         pop bx
  316.         pop ax
  317.        
  318.         add bx, word[_bpb.bytesPerSector]       ; Go to the next memory location
  319.         inc ax                                  ; Read from the next sector
  320.         loop ReadSectors
  321.        
  322.         ; DEBUG
  323.         push ax
  324.         mov ah, 0eh
  325.         mov al, '!'
  326.         int 10h
  327.         pop ax
  328.        
  329.         ret
  330.     ReadSectors.fail:
  331.         ; DEBUG
  332.         push ax
  333.         mov ah, 0eh
  334.         mov al, 'R'
  335.         int 10h
  336.         pop ax
  337.        
  338.         pop cx
  339.         pop bx
  340.         pop ax
  341.        
  342.         int 18h                                 ; Call the interrupt indicating a boot failure
  343.         ret
  344.  
  345. times 510-($-$$) db 0
  346. dw 0xaa55
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement