Membuat bootstrap loader untuk UFD


Pada beberapa mata kuliah seperti sistem operasi dan sistem berkas, dosen mungkin harus mendemokan beberapa komponen low-level yang tidak tersedia pada sistem operasi modern.  Seperti yang diketahui, seluruh sistem operasi modern zaman sekarang beroperasi pada CPU protected mode.  Hal ini berarti hanya kode program saja yang berada di ring 0, sementara kode program yang dibuat user tidak akan mendapatkan akses ring 0 (kecuali bila diizinkan oleh sistem operasi).  Beberapa instruksi assembly seperti IN, OUT, dan beberapa INT umumnya dibatasi oleh sistem operasi.  Sebagai contoh, Windows akan menolak instruksi IN/OUT pada program user mode tetapi mengizinkannya pada driver.  Sementara di Linux, IN/OUT diperbolehkan bila sebelumnya terdapat pemanggilan ioperm() dan program di-akses dengan hak akses superuser.

Bagaimana bila seseorang ingin tetap menjalankan programnya di CPU real-mode?  Ia harus membuat sistem operasi sendiri!  Atau untuk sebuah eksperimen sederhana, ia dapat membuat sebuah bootstrap loader yang akan menjalankan sebuah program real mode begitu komputer dinyalakan!  Dan untuk eksperimen seperti ini, media UFD (USB Flash Drive) adalah pilihan yang tepat.  Kebanyakan BIOS di motherboard zaman sekarang sudah mendukung emulasi disk untuk UFD, sehingga mendukung proses boot dari UFD.

Ini adalah percobaan yang saya lakukan dengan menggunakan sebuah UFD berukuran 4 GB yang menggunakan file system FAT32.  UFD tersebut hanya mengandung sebuah partisi.  Saya menyalin boot sector dari partisi pertama.  Struktur boot sector untuk FAT32 dapat dilihat di http://en.wikipedia.org/wiki/FAT32.  Berikut ini kode program assembly (dalam NASM) yang membentuk boot sector di UFD saya beserta dengan bootstrap loader buatan sendiri:

[BITS 16]
[ORG 0x7C00]

	jmp	mulai
	nop

	; ------------------------------------------------------
	; Informasi Boot Sector
	; ------------------------------------------------------

	db 'SOS-JCH '					; OEM name
	db 00, 0x2					; Bytes per sector
	db 0x8						; Sector per cluster
	db 0x20, 00					; Reserved sector count
	db 0x2						; Number of FAT
	db 00, 00, 00,00
	db 0xF8						; Media descriptor (F8 = Fixed disk)
	db 00, 00
	db 0x3E, 00					; Sectors per track
	db 0x7C, 00					; Number of heads
	db 00, 00, 00, 00				; Count of hidden sectors
	db 0xA2, 0xA7, 0x77, 00				; Total sectors
	db 0xDB, 0x1D, 00, 00				; Sectors per FAT
	db 00, 00					; Mirroring flags
	db 00, 00					; Version
	db 0x02, 00, 00, 00				; Cluster number of root directory start
	db 0x01, 00					; Sector number of FS Information Sector
	db 0x06, 00					; First sector number of a copy of three FAT32 boot sectors
	db 00, 00, 00, 00
	db 00, 00, 00, 00
	db 00, 00, 00, 00
	db 00, 00
	db 0x29						; Extended boot signature
	db 0xA5, 0x82, 0x1D, 0x86			; Volume ID
	db 'Latihan    '				; Volume Label
	db 'FAT32   '					; File system type

	; ------------------------------------------------------
	; Starting point
	; ------------------------------------------------------
mulai:

	; ------------------------------------------------------
	; Inisialisasi
    	; ------------------------------------------------------
	cli
	xor ax, ax
	mov ss, ax
	mov sp, 0x7C00
	mov ds, ax
	mov es, ax
	sti

	; ------------------------------------------------------
	; Menyalin FAT dan menyimpannya ke lokasi offset 0x7E00
	; ------------------------------------------------------ 

	mov word [ds:dap_jumlah_sector], 1
	mov word [ds:dap_dest_segment], ds
 	mov word [ds:dap_dest_offset], 0x7E00
	mov dword [ds:dap_lba_lo], 94 

	call bacasector

	mov eax, [0x7E08]
	mov [fat_next_cluster], eax

	; ------------------------------------------------------
	; Menyalin RootDirectoryEntry ke lokasi offset 0x8000
	; ------------------------------------------------------
	mov word [ds:dap_jumlah_sector], 8
 	mov word [ds:dap_dest_offset], 0x8000
	mov dword [ds:dap_lba_lo], 0x3C14
	call bacasector

	; ------------------------------------------------------
	; Mencari File Dengan Nama KERNEL.BIN
	; ------------------------------------------------------
proses_cluster_berikutnya:

	mov si, 0x8000

pencarian_file_kernel:

	push si
	lea di,	[nama_file_kernel]
	cld
	mov cx, 11
	repe cmpsb
	jz file_kernel_ditemukan

	;
	; File kernel tidak ditemukan pada entry ini.
  	; Lanjut ke entry direktori berikutnya.
	;

	pop si
	add si, 32
	cmp si, 0x9000
	jbe pencarian_file_kernel

	;
	; File kernel tidak ditemukan di cluster ini
	; Periksa apakah masih ada cluster berikutnya.
	;

	mov eax, [fat_next_cluster]
	and eax, 0x0ffffff0
	cmp eax, 0x0ffffff0
	jz hang

	mov di, 0x8000
	call bacacluster
	call bacafat32

	jmp proses_cluster_berikutnya

file_kernel_ditemukan:

	;------------------------------------------------------------
	; Baca File Kernel dan Salin Di Lokasi Memori 0x8000
	;------------------------------------------------------------
	pop si
	mov ax, word [si+0x14]
	shl eax, 16
	mov ax, [si+0x1A]
	mov [fat_next_cluster], eax
	mov di, 0x8000

baca_cluster_kernel_berikutnya:
	call bacacluster
	call bacafat32
	mov eax, [fat_next_cluster]
	and eax, 0x0ffffff0
	cmp eax, 0x0ffffff0
	jz start_kernel

	add di, 0x1000
	mov eax, [fat_next_cluster]
	jmp baca_cluster_kernel_berikutnya

	;------------------------------------------------------------
	; Mulai eksekusi kernel
	;------------------------------------------------------------
start_kernel:	
	jmp 0x8000

hang:
	jmp hang

bacafat32:
	;
	; Baca sebuah sektor FAT32 ke lokasi 0x7E00
	; Perhitungan berdasarkan nilai memori [fat_next_cluster]
	;

	; Mengisi fat_next_cluster dengan nilai
	; entry fat berikutnya
	; Rumus: sector = 62 + 32 + fat_next_cluster / 128
	;	 offset = (fat_next_cluster % 128 ) * 4

	xor eax, eax
	xor edx, edx
	mov ax, [fat_next_cluster]
	mov dx, [fat_next_cluster+2]
	mov cx, 128
	div cx 

	push dx  	; remainder, untuk offset nanti

	add eax, 94;
	mov word [ds:dap_jumlah_sector], 1
	mov word [ds:dap_dest_offset], 0x7E00
	mov dword [ds:dap_lba_hi], 0
	mov dword [ds:dap_lba_lo], eax
	call bacasector

	pop dx
	shl dx, 2
	add edx, 0x7E00
	mov ecx, [edx]
	mov [fat_next_cluster], ecx

	ret

bacacluster:
	;
	; Baca cluster data berikutnya.
	; eax = nomor cluster
	;  di = offset tujuan
	; Rumus menghitung sector dari cluster:
	;  s = 62 + 15318 + ((c-2)*8)
	;
	dec eax
	dec eax
	mov ecx, 8
	mul ecx
	xor ecx, ecx
	add eax, 15380
	adc edx, ecx
	mov dword [ds:dap_lba_hi], edx
	mov dword [ds:dap_lba_lo], eax
	mov word [ds:dap_jumlah_sector], 8
 	mov word [ds:dap_dest_offset], di
	call bacasector
	ret

bacasector:
	mov ah, 0x42
	mov dl, 0x80
	mov si, dap
	int 0x13
	ret

dap			db	0x10, 0x00
dap_jumlah_sector	dw	0x0001
dap_dest_offset		dw	0x0000
dap_dest_segment	dw	0x007C
dap_lba_lo		dd	0x00000000
dap_lba_hi		dd	0x00000000

pesan_salah_fat32	db	'Kernel tidak ditemukan.',0
nama_file_kernel	db	'KERNEL  BIN'
fat_next_cluster	dd	0x00000000

times 510-($-$$) db 0
dw 0xAA55

Directive [BITS 16] memberi tahu NASM bahwa output dari assembly ini adalah kode program real mode 16-bit.  Pada saat BIOS selesai menyalin boot sector, ia akan memindahkan IP pada 0x7C00 sehingga instruksi yang akan dikerjakan adalah 0x7C00.  Itu sebabnya terdapat directive [ORG 0x7C00].

Assembly di atas jauh dari sederhana, sehingga masih banyak perbaikan yang dapat dilakukan.  Salah satunya adalah saya menganggap 1 cluster terdiri atas 8 sector dan 1 sector terdiri atas 512 bytes.  Hal ini berlaku pada UFD saya, tetapi mungkin berbeda pada UFD yang di-format secara berbeda.  Selain itu, saya menganggap sector yang menampung informasi Root Directory dimulai dari lokasi sector ke 15.318.  Saya juga menganggap jarak dari MBR ke boot sector adalah 62 sector.  Kode assembly yang lebih baik akan menyertakan proses perhitungan (berdasarkan informasi field di boot sector) sehingga bootstrap loader menjadi fleksibel.

Kode assembly yang ada pada dasarnya akan memeriksa linked list di FAT32 dan membaca seluruh cluster yang berisi informasi Root Directory.  Bootstrap loader akan mencari file bernama KERNEL.BIN.  Bila file ini ketemu, isi dari file tersebut akan disalin ke lokasi memori 0x8000, dan eksekusi akan dilanjutkan pada lokasi memori tersebut.

Kode assembly di atas dapat diproses menjadi sebuah boot sector dengan menggunakan NASM:

nasm -o boot.bin boot.asm

Output dari perintah di atas adalah sebuah file berukuran 512 bytes dan diakhir dengan 0x55AA.  Semuanya memenuhi persyaratan sebuah boot sector.  Langkah berikutnya adalah men-copy file tersebut ke boot sector partisi pertama di UFD.  Hal ini dapat dilakukan dengan perintah dd di Linux:

$ sudo dd if=boot.bin of=/dev/sdb1 bs=512 count=1

Sebelum mulai restart komputer dan mengatur prioritas boot device di BIOS, pastikan terlebih dahulu bahwa boot flag pada partisi /dev/sdb1 telah di-set menjadi true.  Untuk mengatur flag tersebut, seseorang bisa menggunakan perintah fdisk di Linux.

Sekarang, pada saat ingin mencoba kode program real mode, seorang programmer assembly hanya perlu menyimpan program tersebut dengan nama KERNEL.BIN.  Setelah itu, copy file KERNEL.BIN ke root directory flash disk.  Kini, setiap kali komputer di-boot melalui flash disk, file KERNEL.BIN akan dikerjakan.

Perlu diingat bahwa program real-mode memiliki memori yang terbatas.  Akses memori hanya dibatasi pada range 1 MB (bila gate A20 aktif, menjadi 1.114.096 bytes).  Area memori ini sudah termasuk yang dipakai untuk Interrupt Descriptor Table (IDT), buffer I/O, dsb sehingga yang tersedia bagi program lebih sedikit lagi.   Untuk memakai memori lebih dari 1 MB, programmer harus beralih ke protected mode (itu sebabnya semua sistem operasi modern bekerja pada protected mode).

Perihal Solid Snake
I'm nothing...

3 Responses to Membuat bootstrap loader untuk UFD

  1. Ping-balik: Menjalankan File ISO Linux Dari Live USB Tanpa Instalasi | The Solid Snake

  2. Dana Saputra mengatakan:

    Akhirnya nemu caranya bikin bootloader dri anak Indonesia, tapi ane masih bingung caranya nge-load harddisk pake bhs Assembly.. Mohon penjelasannya gan

    • Solid Snake mengatakan:

      Seperti yang tertulis di artikel ini, saya membaca sector dari harddisk dengan int 0x13 pada bagian kode program berikut ini:

      mov ah, 0x42
      mov dl, 0x80
      mov si, dap
      int 0x13
      

      dap berisi informasi sector yang hendak dibaca.

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: