Saat kita membangun sebuah sistem operasi dari titik nol, kita akan menemui sebuah tembok besar yang disebut Real Mode. Ini adalah mode “bayi” dari CPU x86 di mana komputer hanya bisa mengakses memori maksimal 1 MB dan tidak memiliki sistem keamanan sama sekali.
Untuk melompat ke dunia Protected Mode (32-bit) yang lebih luas dan aman, kita membutuhkan sebuah paspor teknis yang disebut Global Descriptor Table (GDT). Tanpanya, CPU tidak akan mengizinkan kita menyentuh memori di atas 1 MB atau menjalankan instruksi 32-bit yang modern.
Mengapa Kita Membutuhkan GDT?
Di dunia Real Mode (16-bit), CPU menghitung alamat memori dengan sangat sederhana. Namun, kesederhanaan ini berbahaya karena satu program bisa dengan mudah menghapus data milik program lain atau bahkan merusak sistem BIOS.
Protected Mode diciptakan untuk mencegah hal tersebut. Di mode ini, CPU tidak lagi mengakses alamat memori secara langsung. CPU akan selalu bertanya kepada sebuah tabel aturan: “Apakah saya boleh mengakses area memori ini? Apakah ini berisi kode atau data?”. Tabel aturan inilah yang kita sebut GDT.
Struktur Sebuah Descriptor (Entri GDT)
Setiap entri dalam GDT disebut Segment Descriptor. Panjangnya tepat 8 byte (64 bit). Intel mendesain struktur ini dengan cara yang cukup unik (dan sedikit rumit) karena alasan sejarah kompatibilitas. Sebuah descriptor menyimpan informasi:
- Base Address (32-bit): Titik awal memori.
- Segment Limit (20-bit): Ukuran memori tersebut.
- Access Byte: Siapa yang boleh mengakses (Privilege) dan tipenya (Kode/Data).
- Flags: Mengatur apakah memori dihitung dalam satuan Byte atau 4KB (Granularity).
Implementasi Kode Assembly (NASM)
Berikut adalah contoh bagaimana kita menyusun GDT di dalam bahasa Assembly. Perhatikan bagaimana satu entri dibagi-bagi menjadi beberapa bagian (db untuk 1 byte, dw untuk 2 byte).
; =============================================================
; DEFINISI GLOBAL DESCRIPTOR TABLE (GDT)
; =============================================================
gdt_start:
; 1. NULL DESCRIPTOR (Wajib ada)
; 8 byte angka nol sebagai pengaman jika terjadi error.
dd 0x0 ; 4 byte pertama
dd 0x0 ; 4 byte kedua
; 2. CODE SEGMENT DESCRIPTOR
; Memori tempat program (kode) kita berada.
dw 0xffff ; Limit (bit 0-15) = 64 KB
dw 0x0 ; Base (bit 0-15) = Alamat 0
db 0x0 ; Base (bit 16-23) = Alamat 0
db 10011010b ; Access Byte: Present, Ring 0, Code, Readable
db 11001111b ; Flags & Limit (bit 16-19)
db 0x0 ; Base (bit 24-31) = Alamat 0
; 3. DATA SEGMENT DESCRIPTOR
; Memori tempat variabel dan stack berada.
dw 0xffff ; Limit sama dengan Code Segment
dw 0x0 ; Base sama dengan Code Segment
db 0x0
db 10010010b ; Access Byte: Present, Ring 0, Data, Writable
db 11001111b ; Flags
db 0x0
gdt_end:
; --- GDT Descriptor (Pointer untuk CPU) ---
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; Ukuran GDT (16-bit)
dd gdt_start ; Alamat awal GDT (32-bit)
; --- Konstanta untuk mempermudah pemanggilan ---
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
Bedah Kode: Apa yang Terjadi di Sana?
Mungkin Anda bingung melihat angka-angka aneh seperti 10011010b. Mari kita bedah secara perlahan:
1. Kenapa Base Address Dipisah?
Jika Anda perhatikan, Base Address (alamat awal) dipisahkan menjadi tiga bagian (dw, db, db). Ini dilakukan agar struktur GDT tetap kompatibel dengan prosesor lama (80286). Namun jika digabungkan, mereka membentuk alamat 0x0. Artinya, segmen kita dimulai dari titik paling awal RAM.
2. Access Byte (Penjaga Gerbang)
Angka biner seperti 10011010b adalah kunci keamanan:
- Bit 7 (Present): Harus 1 agar segmen ini dianggap ada.
- Bit 5-6 (Privilege):
00berarti Ring 0 (Kernel/Pangkat tertinggi). - Bit 3 (Executable):
1untuk Kode Program,0untuk Data.
3. Flags (Granularity)
Angka 11001111b di bagian Flags memberi tahu CPU bahwa limit memori kita tidak dihitung dalam satuan byte, melainkan dikalikan dengan 4 KB. Dengan cara ini, meskipun Limit hanya 20-bit, kita bisa mencakup seluruh RAM sebesar 4 GB.
Bagaimana Cara Menggunakannya?
Setelah tabel GDT dibuat, kita harus memberi tahu CPU di mana lokasi tabel tersebut berada. Kita menggunakan label gdt_descriptor yang sudah kita buat tadi dengan instruksi:
lgdt [gdt_descriptor]
Perintah ini akan memuat alamat GDT kita ke dalam register khusus di dalam CPU yang bernama GDTR. Setelah perintah ini dieksekusi, kita sudah siap melakukan “lompatan jauh” (Far Jump) untuk mengaktifkan mode 32-bit sepenuhnya.
Kesimpulan
GDT adalah fondasi dari manajemen memori modern. Tanpa tabel ini, fitur-fitur canggih seperti perlindungan memori antar aplikasi (agar aplikasi tidak saling membuat crash) tidak akan pernah ada. Meskipun penulisan kodenya terlihat sangat teknis dan manual, memahami GDT adalah langkah pertama yang paling membanggakan dalam perjalanan Anda membuat Sistem Operasi sendiri.