Transisi Arsitektur Sistem: Analisis Komparatif BIOS vs. UEFI – Bagian 2: Mekanisme Layanan Sistem (Interrupt Traps vs. ABI Calls)

Penulis: Reza Ervani bin Asmanu

1. Pendahuluan

Perbedaan paling radikal antara pengembangan Legacy Bootloader dan UEFI Application terletak pada mekanisme komunikasi antara perangkat lunak (Software) dan perangkat keras (Firmware).

Pada BIOS, komunikasi bersifat Imperatif dan Terpusat melalui Interrupt Vector Table (IVT). Pada UEFI, komunikasi bersifat Deklaratif dan Terdesentralisasi melalui Function Pointer Tables di Heap Memory. Artikel ini membedah implikasi register, stack, dan instruksi mesin dari kedua pendekatan tersebut.

2. BIOS: Arsitektur Berbasis Interupsi (Software Interrupt Architecture)

Dalam mode BIOS Real Mode, CPU menggunakan tabel di alamat fisik 0x0000 hingga 0x03FF (1 KB pertama RAM) yang berisi 256 alamat fungsi (ISR – Interrupt Service Routines).

2.1. Mekanisme Instruksi INT

Instruksi INT n (opcode CD imm8) bukan sekadar lompatan (JUMP). Ia adalah operasi kompleks yang melibatkan manipulasi stack otomatis oleh CPU:

  1. Push Flags: CPU menyimpan register FLAGS ke stack.
  2. Disable Interrupts: CPU mematikan Interrupt Flag (IF) (cli).
  3. Push CS:IP: CPU menyimpan alamat kembali (Return Address) ke stack.
  4. Vector Lookup: CPU membaca alamat handler dari IVT[n].
  5. Jump: CPU melompat ke kode BIOS.

2.2. Rigid Register Mapping (Kekakuan Register)

BIOS tidak memiliki standar ABI (Application Binary Interface) yang seragam antar vendor, namun memiliki konvensi de-facto IBM PC. Register memiliki peran semantik yang kaku:

  • AH (Accumulator High): Selalu berfungsi sebagai Function Selector (ID Perintah).
  • AL (Accumulator Low): Biasanya untuk sub-fungsi atau jumlah elemen.
  • DL (Data Low): De-facto standar untuk ID Drive (misal 0x80 untuk HDD).
  • Carry Flag (CF): Indikator status. Jika CF=1, operasi gagal.

2.3. Studi Kasus Forensik: Low-Level Disk Read (BIOS)

Operasi membaca sektor disk menuntut penggunaan register segmen yang rumit.

; --- BIOS DISK READ (INT 13h, AH=02h) ---
; Target: Baca 1 sektor ke alamat memori 0x07C0:0x0000

MOV  AX, 0x07C0
MOV  ES, AX       ; ES (Extra Segment) diisi segmen tujuan
XOR  BX, BX       ; BX (Offset) diisi 0. Alamat fisik = 0x07C00

MOV  AH, 0x02     ; FUNCTION ID: Read Sectors
MOV  AL, 0x01     ; Sektor count = 1
MOV  CH, 0x00     ; Cylinder = 0
MOV  CL, 0x02     ; Sector = 2 (Sector 1 is MBR)
MOV  DH, 0x00     ; Head = 0
MOV  DL, 0x80     ; Drive = First Hard Disk

INT  0x13         ; TRAP: Transfer kontrol ke BIOS ROM
JC   DiskError    ; Cek Carry Flag (CF). Jump if Carry Set.

Analisis Register: Register digunakan sebagai wadah nilai mentah. Tidak ada pointer ke struktur data yang kompleks. Semuanya hardcoded dalam register 16-bit.


3. UEFI: Arsitektur Berbasis Protokol (Interface Protocol Architecture)

UEFI membuang konsep Interupsi Software untuk layanan sistem. Sebagai gantinya, ia mengadopsi model C Object Oriented. Layanan tidak disimpan di lokasi memori tetap (seperti IVT 0x0000), melainkan dialokasikan secara dinamis saat boot.

3.1. Microsoft x64 Calling Convention (ABI)

UEFI secara ketat mengikuti standar ABI Microsoft x64. Ini mengubah total cara register digunakan. Register tidak lagi memiliki arti semantik (seperti “AH adalah ID Fungsi”), melainkan memiliki arti Posisional.

Aturan Volatile Register (Caller-Saved):

Register ini dianggap “rusak” setelah pemanggilan fungsi UEFI. Nilainya tidak dijamin sama saat kembali.

  • RAX, RCX, RDX, R8, R9, R10, R11, XMM0-XMM5.

Aturan Non-Volatile Register (Callee-Saved):

Fungsi UEFI wajib menjaga nilai register ini.

  • RBX, RBP, RDI, RSI, R12-R15.

3.2. Struktur Pemanggilan (Indirect Call)

Layanan UEFI dipanggil melalui Pointer to Function yang ada di dalam struktur data (biasanya SystemTable).

  • Pointer SystemTable biasanya diserahkan ke RCX (Argumen 1) atau disimpan di variabel global.

3.3. Studi Kasus Forensik: Low-Level Disk Read (UEFI)

Berbeda dengan BIOS yang pakai register CHS (Cylinder-Head-Sector), UEFI menggunakan protokol EFI_BLOCK_IO_PROTOCOL dan struktur data linear.

Mari kita lihat terjemahan Assembly murni dari pemanggilan fungsi BlockIo->ReadBlocks(...):

; --- UEFI DISK READ (BlockIo Protocol) ---
; C Prototype: ReadBlocks(BlockIo, MediaId, LBA, Size, Buffer)

; 1. Persiapan Stack Frame (Wajib untuk Shadow Space)
SUB  RSP, 32           ; Alokasi 32 bytes Shadow Space (Microsoft ABI Requirement)
AND  RSP, 0xFFFFFFF0   ; Stack Alignment 16-byte (Agar tidak crash di instruksi SSE)

; 2. Persiapan Argumen (Positional Register Mapping)
; Arg 5 (Buffer) - Masuk ke Stack (karena register habis)
MOV  RAX, [BufferPtr]  ; Ambil alamat buffer tujuan
MOV  [RSP + 32], RAX   ; Taruh di stack, tepat di atas shadow space

; Arg 4 (Size) -> Register R9
MOV  R9, 512           ; Ukuran 512 bytes

; Arg 3 (LBA/Offset) -> Register R8
MOV  R8, 1             ; Baca LBA 1 (Sektor ke-2)

; Arg 2 (Media ID) -> Register RDX
MOV  RDX, [MediaId]    ; ID Media dari struktur BlockIo

; Arg 1 (This Pointer) -> Register RCX
MOV  RCX, [BlockIo]    ; Pointer ke Object BlockIo itu sendiri (Context)

; 3. Eksekusi Call (Indirect Call)
; Kita harus mencari alamat fungsi ReadBlocks di dalam tabel vtable BlockIo
MOV  RAX, [RCX]        ; Dereference pointer BlockIo untuk dapat alamat VTable
CALL [RAX + 0x20]      ; Panggil fungsi di offset 0x20 (Offset fungsi ReadBlocks)

; 4. Cek Hasil
ADD  RSP, 32           ; Bersihkan stack
TEST RAX, RAX          ; Cek return value di RAX (EFI_STATUS)
JNZ  DiskError         ; Jika RAX != 0 (EFI_SUCCESS), maka Error.

4. Analisis Komparatif Mendalam

Berikut adalah tabel matriks perbedaan pada level instruksi mesin (opcode level):

Titik AnalisisBIOS (16-bit Assembly)UEFI (64-bit Assembly)
Metode DispatchINT 0x13 (Software Interrupt Trap)CALL [RAX+Offset] (Indirect Memory Call)
Penyimpanan ArgumenSemantic Registers (AH=Func, CX=Cyl). Register ditentukan oleh fungsi.Positional Registers (RCX=Arg1, RDX=Arg2). Register ditentukan oleh urutan.
Passing BufferSegmented Pointer (ES:BX). Terbatas 1MB. Harus hitung (ES<<4)+BX.Linear Pointer (64-bit Flat). Bisa alamat 0x0000000800000000 (RAM 32GB+).
Stack ManagementTidak wajib (kecuali push/pop data sendiri).Wajib. Harus alokasi Shadow Space (32 byte) dan Alignment (16 byte).
Error ReportingCarry Flag (Hardware Flag). 1 bit informasi.RAX (EFI_STATUS). 64-bit kode error (bisa membedakan DeviceError, NoMedia, dll).
KonteksStateless. BIOS tidak tahu siapa yang memanggil.Stateful. RCX (This Pointer) membawa konteks objek driver tertentu.

5. Implikasi bagi Pengembang OS (Relevansi Nyata)

  1. Debugging Complexity:
    • Di BIOS, jika disk gagal baca, Anda cukup lihat register AH.
    • Di UEFI, jika disk gagal baca, Anda harus memeriksa Stack Trace dan isi struktur EFI_SYSTEM_TABLE di memori. Debugging UEFI membutuhkan pemahaman tentang memory dump, bukan hanya register dump.
  2. Stack Safety:
    • Di BIOS, Anda bisa sembarangan memanipulasi SP (Stack Pointer).
    • Di UEFI, jika Anda lupa SUB RSP, 32 sebelum memanggil fungsi, firmware akan menimpa data stack Anda atau crash karena pelanggaran memori. Ini adalah sumber bug #1 bagi pemula UEFI Assembly.
  3. Portabilitas:
    • Kode Assembly BIOS hanya jalan di x86.
    • Kode C UEFI (yang dikompilasi ke pola register di atas) bisa di-recompile untuk ARM64 (Raspberry Pi) atau RISC-V dengan mudah, karena abstraksi protokolnya sama, hanya Calling Convention-nya yang berubah.

Bersambung ke Bagian 3: Akses Grafik (VGA Mode 0x13 vs GOP Linear Framebuffer).