All pastes #984853 Raw Edit

Untitled

public text v1 · immutable
·published 2008-04-14 16:44 UTC
rendered paste body
[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