Skip to content

Instantly share code, notes, and snippets.

@daeken
Created April 3, 2011 17:33
Show Gist options
  • Select an option

  • Save daeken/900595 to your computer and use it in GitHub Desktop.

Select an option

Save daeken/900595 to your computer and use it in GitHub Desktop.
[BITS 16]
[ORG 0x7C00]
jmp main
; Reads sectors
; bx == Low 16 bits of addr
; cx == High 12 bits of addr
; dx == Output buffer
; di == Number of sectors
; Reference: http://www.osdever.net/tutorials/lba.php
readSectors:
.start:
; Save output buffer
push dx
; outb(0x1F1, 0)
; Setup
mov dx, 0x1F1
xor ax, ax
out dx, al
; outb(0x1F2, 1)
; Send sector count to port 1F2
inc dx
mov ax, di
out dx, al
.sendAddr:
; outb(0x1F3, addr&0xFF)
; Send low byte of the address
mov al, bl
inc dx
out dx, al
; outb(0x1F4, (addr>>8)&0xFF)
mov al, bh
inc dx
out dx, al
; outb(0x1F5, (addr>>16)&0xFF)
mov al, cl
inc dx
out dx, al
; outb(0x1F6, 0xE0 | (drive << 4) | ((addr >> 24) & 0x0F))
; Send high 4 bits, drive ID, and magic
fs mov ax, [driveID]
or ax, 0xE0
or al, ch
inc dx
out dx, al
.sendCmd:
; outb(0x1F7, 0x20)
mov al, 0x20
inc dx
out dx, al
.waitForCompletion:
; al = inb(0x1F7)
in al, dx
; while((al & 0x08) == 0)
and al, 0x08
test al, al
jz .waitForCompletion
.setupRead:
pop bx
mov ax, 0x200
mul di
mov cx, ax
add cx, bx
mov dx, 0x1F0
.readResp:
; ax = inw(0x1F0)
in ax, dx
mov word [bx], ax
inc bx
inc bx
cmp bx, cx
jl .readResp
.return:
ret
; Finds attribute by type
; si == FILE record offset
; cx == Low 16 bits of attr type
; Returns attribute offset or 0 (in si)
findAttrByType:
.getAttrList:
add si, [si+14h] ; Offset to sequence of attributes
.iterate:
mov ax, 0FFFFh
xor ax, [si] ; End of attr list?
jnz .checkType
mov ax, 0FFFFh
xor ax, [si+2] ; End of attr list?
jz .notFound
.checkType:
mov ax, cx
xor ax, [si] ; Low 16 bits of attr type
jz .return
.next:
add si, [si+4] ; Attr len
jmp .iterate
.return:
ret
.notFound:
xor si, si
ret
; Get MFT entry
; ax = File entry num
; bx = Output buffer
getMFTEntry:
.getEntry:
fs mul word [sectorsPerMFTRecord]
fs add ax, [mftBaseLow]
mov cx, dx
fs adc cx, [mftBaseHigh]
mov dx, bx
mov bx, ax
fs mov di, [sectorsPerMFTRecord]
jmp readSectors
; Check file
; ax = File entry num
checkFile:
.getEntry:
mov bx, 0400h
call getMFTEntry
mov si, 0400h
mov ax, [si]
xor ax, 0FFFFh
jz $ ; Not found
.getFilename:
mov cx, 30h
call findAttrByType
.checkParent:
cmp word [si+18h], 5 ; Is it in the root directory?
jne .wrong
.compare:
mov bp, secondStageName
add si, 5Ah
.iterate:
fs mov bl, [bp]
test bl, bl
jz .right
inc bp
mov cl, [si]
add si, 2
xor bl, cl
jz .iterate
.wrong:
xor bx, bx
ret
.right:
mov bx, 1
ret
; Loads second stage bootloader
; ax == File entry num
loadFile:
.getEntry:
xor bx, bx
call getMFTEntry
.getData:
xor si, si
mov cx, 80h
call findAttrByType
.nonResident:
mov bx, [si+18h] ; Last VCN
sub bx, [si+10h] ; First VCN
push bx
add si, [si+20h] ; Runlist offset
.readRun:
xor bx, bx
xor ax, ax
fs mov al, [sectorsPerCluster]
mov bl, [si+1] ; Length
push bx ; Length in clusters
mul bl
mov di, ax
xor cx, cx
mov cl, [si] ; Size byte
inc si
mov ax, cx
and al, 0Fh ; Length size (bleh)
add si, ax
shr cx, 4 ; Offset size
push cx ; Offset size in bytes
sal cx, 3
mov bx, [si]
mov ax, 0FFFFh
sal ax, cl
not ax
and bx, ax
fs add [partStartLow], bx
mov bp, [si+2]
sub cx, 16
mov ax, 0FFFFh
sal ax, cl
not ax
and bp, ax
fs add [partStartHigh], bp
pop bp ; Offset size in bytes
add si, bp
pop bp ; Length in clusters
pop ax ; VCN left
sub ax, bp
push ax ; VCN left
fs mov bx, [partStartLow]
fs mov cx, [partStartHigh]
mov dx, 1000h
push di ; Number of sectors
call readSectors
.copy:
pop bp ; WTF? Why does this actually work?!
pop ax ; Number of sectors
mov cx, 512
mul cx
mov cx, ax
push si
mov si, 1000h
fs mov di, [curOff]
fs add [curOff], cx
cld
rep movsb
pop si
pop ax
push ax
test ax, ax
jnz .readRun
.run:
jmp 6000h:0
main:
.setupStack:
mov ax, 4000h
mov ss, ax
mov sp, 0FFFCh
.setupTemp:
mov ax, ds
mov fs, ax
mov ax, 3000h
mov ds, ax
mov ax, 6000h
mov es, ax
.getPartTable:
xor bx, bx ; Low 16 bits of addr
xor cx, cx ; High 12 bits of addr
xor dx, dx ; Output buffer
mov di, 1 ; Number of sectors
call readSectors
.getFirstPart:
mov bx, [0x1C6] ; Load low 16 bits of partition start
mov cx, [0x1C8] ; Load high 12 bits of partition start
fs mov [partStartLow], bx
fs mov [partStartHigh], cx
.getBPB:
xor dx, dx ; Output buffer
mov di, 1 ; Number of sectors
call readSectors
xor bx, bx
mov bl, [0x0D] ; Sectors per cluster
fs mov [sectorsPerCluster], bl
mov al, [0x40] ; Clusters per MFT record
mul bl
fs mov [sectorsPerMFTRecord], ax
mov ax, [0x30] ; First word of $MFT cluster num
mul bx
mov cx, ax
mov di, dx
mov ax, [0x32] ; Second word of $MFS cluster num
mul bx
fs add cx, [partStartLow]
fs adc ax, [partStartHigh]
fs mov [mftBaseLow], cx
fs mov [mftBaseHigh], ax
.walkMFT:
xor ax, ax
.iterate:
push ax
call checkFile
pop ax
test bx, bx
jnz .found
inc ax
jmp .iterate
.found:
jmp loadFile
sectorsPerCluster db 1
sectorsPerMFTRecord dw 2
mftBaseLow dw 4FD5h
mftBaseHigh dw 0005h
partStartLow dw 003Fh
partStartHigh dw 0
curOff dw 0
driveID dw 1<<4
secondStageName db "CBLdr.boot", 0
times 510-($-$$) db 90h
dw 0xAA55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment