Created
April 3, 2011 17:33
-
-
Save daeken/900595 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [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