Memahami Manajemen Memori Fisik Di Windows 7

Pada artikel sebelumnya, Memahami Address Translation Di Windows, saya menunjukkan bahwa masing-masing proses di Windows mengakses virtual address yang dipetakan ke physical address. Pemetaan ini berlaku unik untuk setiap proses yang ada karena masing-masing proses memiliki page table-nya sendiri. Dengan demikian, walaupun Notepad.exe mengakses alamat virtual X dan Paint.exe mengakses alamat virtual X yang sama, lokasi physical address yang dituju bisa saja berbeda. Untuk melihat mapping dari physical address ke virtual address secara lebih mudah, saya dapat menggunakan tool RAMMap dari SysInternals Suite seperti yang terlihat pada gambar berikut ini:

Melihat pemetaan physical address ke virtual address dengan RAMMap

Melihat pemetaan physical address ke virtual address dengan RAMMap

Pada artikel ini, saya akan mencoba mempelajari bagaimana Windows mengelola main memory secara fisik (bukan berdasarkan apa yang dilihat oleh program). Windows membagi wilayah main memory (RAM) ke dalam bagian-bagian yang disebut sebagai page. Ukuran default untuk sebuah page adalah 4K (0x1000). Windows mencatat alokasi page untuk masing-masing proses kedalam lokasi yang disebut sebagai Page Frame Number (PFN) database. Saya dapat melihat isi PFN database dengan Windows Debugger seperti yang terlihat pada gambar berikut ini:

Melihat Isi PFN

Melihat Isi PFN

Pada eksekusi di atas, setelah memperoleh alamat PFN database, saya menampilkan isinya dimana setiap PFN terdiri atas 24 byte. Windows Debugger memiliki perintah !pfn yang bisa dipakai untuk menampilkan informasi PFN secara lebih mudah dimengerti. Karena setiap page berukuran 4K (0x1000), maka PFN 1 mulai dari physical address 0x1000, PFN 2 mulai dari physical address 0x2000, dan seterusnya.

PFN mengandung informasi state dari page di memori fisik yang bisa berupa salah dari active, transition, standby, modified, modified no-write, free, zeroed, rom, dan bad. Saya dapat menampilkan alokasi memori fisik berdasarkan statusnya dengan perintah !memusage seperti pada berikut ini:

kd> !memusage 8

loading PFN database
loading (100% complete)
Compiling memory usage data (99% Complete).
             Zeroed: 262475 (1049900 kb)
               Free:      5 (    20 kb)
            Standby:  25173 (100692 kb)
           Modified:   1632 (  6528 kb)
    ModifiedNoWrite:      0 (     0 kb)
       Active/Valid:  98211 (392844 kb)
         Transition:      2 (     8 kb)
                Bad:    484 (  1936 kb)
            Unknown:      0 (     0 kb)
              TOTAL: 387498 (1549992 kb)

Selain itu, saya juga dapat menampilkan informasi yang dalam bentuk grafis dengan tool RAMMap seperti yang terlihat pada gambar berikut ini:

Isi physical memory berdasarkan status page

Isi physical memory berdasarkan status page

Satu fakta menarik tentang Windows 7 versi 32-bit adalah walaupun saya memiliki RAM 4 GB, saya tidak akan pernah bisa mengakses seluruh memori fisik tersebut secara penuh. Mengapa demikian? Hal ini karena sistem operasi 32-bit hanya memungkinkan pengalamatan hingga maksimal 2^32 = 4 GB. Masalahnya, alamat tersebut tidak sepenuhnya dipakai untuk memori fisik (RAM), tetapi juga dibutuhkan untuk hardware lainnya seperti video card dan audio card.

Untuk membuktikannya, saya akan membuka Device Manager, lalu memilih menu View, Resource By Connection. Pada bagian Memory, saya menemukan hasil seperti berikut ini (khusus untuk hardware yang sedang saya pakai):

Pemetaan physical address

Pemetaan physical address

Pada gambar di atas, terlihat bahwa alamat 0xA0000 sampai 0xBFFFF telah dipetakan untuk keperluah chipset. Total dari wilayah ini adalah sebesar 0x20000 bytes (atau 131.072 bytes). Bukan hanya itu saja, juga ada alokasi alamat dari wilayah 0xD0000 sampai 0xDFFFF sebesar 0x10000 bytes (atau 65.536 bytes) dan alokasi dari wilayah 0xBDE00000 sampai 0xFFFFFFFF sebesar 0x42200000 bytes (atau 1 GB).

Dengan demikian, total wilayah yang telah dipakai untuk keperluan selain memori fisik mencapai lebih dari 1 GB. Hal ini menyebabkan sisa wilayah yang dapat dipakai untuk pengalamatan memori fisik menjadi sekitar 3 GB. Windows menampilkan informasi ini di System Properties seperti yang terlihat pada gambar berikut ini:

Windows 32-bit tidak dapat mengakses seluruh wilayah 4 GB memori

Windows 32-bit tidak dapat mengakses seluruh wilayah 4 GB memori

Masalah ini tidak terjadi pada sistem operasi 64-bit karena secara teoritis, pengalamatan dapat dilakukan hingga mencapai 2^64 = 16 EB (Exa Byte). Ini jauh lebih dari cukup untuk kebutuhan hardware saat ini. Pada kenyataannya, karena alasan efisiensi, prosesor modern saat ini hanya dapat mengakses hingga maksimal 4 PB. Dukungan ini akan terus ditingkatkan seiring waktu berjalan. Sistem operasi Windows 7 sendiri memiliki lisensi yang membatasi penggunaan memori. Sebagai contoh, lisensi Windows 7 Ultimate 64-bit hanya membolehkan penggunaan memori RAM hingga maksimal 192 GB.

Iklan

Memahami Address Translation Di Windows

Pada sebuah PC, pengguna menyimpan program secara permanen pada media seperti hard disk drive (HDD). Ukuran hard disk yang tersedia saat ini mulai dari 20 GB hingga 2 TB. Sudah bisa ditebak, pasti ada banyak program yang dapat disimpan di hard disk. Lalu, bagaimana dengan fakta bahwa untuk menjalankan sebuah program, ia harus di-load ke main memory (RAM) terlebih dahulu? Ukuran sebuah keping tunggal main memory saat ini tersedia mulai dari 1 GB hingga 64 GB. Sebuah motherboard PC biasanya menyediakan maksimal 8 slot kosong. Walaupun demikian, ukuran main memory (RAM) tidak akan pernah menyamai ukuran hard disk drive (HDD)!

Pertanyaannya: seandainya saya men-install sebuah program berukuran 4 GB ke harddisk, kenapa saya bisa menjalankan program tersebut pada RAM yang hanya sebesar 1 GB? Hal ini karena sistem operasi menggunakan teknik paging untuk menciptakan sebuah ilusi bahwa PC memiliki main memory yang tidak terbatas. Ketika memori menjadi penuh, sistem operasi menyimpan page lama yang jarang diakses ke hard disk. Ketika program perlu mengakses page yang tidak ada di main memory, akan terjadi page fault. Sistem operasi memberikan respon dengan membaca page yang sebelumnya telah disimpan ke hard disk dan mengisinya di main memory. Semakin kecil ukuran main memory, maka kemungkinan page fault terjadi akan semakin besar. Hal ini terlihat dari lampu indikator hard disk yang semakin sering berkedip dimana efeknya adalah program berjalan lebih lambat.

Hal yang erat kaitannya dengan paging adalah virtual memory. Dengan virtual memory, program menganggap bahwa dirinya mengakses lokasi memori yang sama dan berurut. Padahal, lokasi memori ini adalah virtual address dan bukan lokasi memori yang sesungguhnya! Sistem operasi nantinya akan menerjemahkan dari virtual address ke lokasi memori fisik yang sesungguhnya. Dua program berbeda boleh saja merasa dirinya mengakses lokasi memori yang sama (secara kode program), tapi pada saat dijalankan, sistem operasi bisa saja memetakannya ke lokasi fisik yang berbeda di main memory. Dengan demikian, pembuat program tidak perlu khawatir dengan bentrokan alamat memori bila terdapat lebih dari satu program yang dijalankan secara bersamaan (multitasking).

Sebagai contoh, saya membuka Notepad dan mengetik “thesolidsnake”. Saya menemukan bahwa string tersebut disimpan di lokasi virtual address 0x0029E0F0. Bagaimana caranya Windows menerjemahkan virtual address ke physical address di main memory?

Eksperimen dengan Windows Debugger menunjukkan bahwa physical address untuk 0x0029E0F0 (pada proses notepad.exe) adalah 0x4b3140f0 seperti yang terlihat pada gambar berikut ini:

Mencari physical address dari virtual address

Mencari physical address dari virtual address

Pada gambar di atas, saya menggunakan perintah !vtop untuk melakukan translasi dari virtual address menjadi physical address. Kemudian, saya menggunakan perintah !dc yang menerima parameter berupa physical address untuk menampilkan isi memori pada alamat tertentu.

Bagaimana proses perhitungannya secara manual? Dengan anggapan bahwa sistem tidak mendukung PAE, saya akan mengubah nilai 0x0029E0F0 ke dalam bilangan binary dan membaginya menjadi seperti:

0000 0000 00 | 10 1001 1110  | 0000 1111 0000
|            |               |
|            |               |- Byte index
|            |
|            |- Page table index
|
|- Page directory index

Terlihat bahwa nilai dari page directory index adalah 0, nilai dari page table index adalah 0x29E, dan nilai dari byte index adalah 0xF0. Saya dapat memperoleh lokasi page table entry (PTE) dengan menggunakan rumus berikut ini:

PTE address = PTE_BASE + (page directory index) * PAGE_SIZE + (page table index) * sizeof(MMPTE)
            = 0xC0000000 + (0 * 0x1000) + (0x29E * 4)
            = 0xC0000000 + 0 + 0xA78
            = 0xC0000A78

Setelah menemukan lokasi PTE, saya dapat melihat isinya dengan perintah seperti pada gambar berikut ini:

Melihat PTE untuk proses Notepad.exe

Melihat PTE untuk proses Notepad.exe

Saya berpindah ke context untuk proses Notepad.exe agar perintah dd dapat menampilkan lokasi yang tepat. Hal ini karena setiap proses memiliki page table-nya masing-masing dan saya sedang mencari page table entry (PTE) untuk proses Notepad.exe.

Pada gambar di atas, terlihat bahwa saya menemukan nilai PTE berupa 0x4b314867. Nilai ini terdiri atas nilai page frame number berupa 0x4b314 dan status flag berupa 0x867. Dengan demikian, lokasi physical address adalah:

physical address = page frame number  * 0x1000 + byte index
                 = 0x4B314 * 0x1000 + 0xF0
                 = 0x4B3140F0

Terlihat bahwa hasil perhitungan manual ini sama seperti hasil perhitungan yang diperoleh oleh !vtop.

Melakukan Kernel Debugging Pada Sistem Operasi Windows Di Virtual Machine

Pada artikel Melakukan Local Kernel Debugging Di Windows 7, saya melakukan local kernel debugging.   Tapi kernel debugging lebih sering dilakukan dengan dua komputer terpisah, dimana sebuah komputer berperan sebagai host dan yang lain sebagai target.   Dengan demikian, komputer host dapat menghentikan Windows di komputer target, lalu menelusuri kesalahan baris per baris.   Kali ini saya akan mencoba melakukan kernel debugging dengan dua sistem operasi Windows terpisah, tetapi target-nya adalah Windows 7 di virtual machine yang dijalankan dari dalam komputer host.   Dengan demikian, saya tidak perlu mengeluarkan biaya untuk membeli USB debug cable, mencari notebook/komputer lain dengan port serial (COM) atau membeli adapter Firewire.

Saya akan memakai Oracle VirtualBox untuk mensimulasikan sebuah komputer maya dengan sistem operasi Windows 7 SP 1.   Saya perlu menambahkan sebuah port serial pada komputer maya tersebut.   Caranya adalah men-klik tombol Settings, kemudian memilih Serial Ports pada dialog yang muncul.   Saya akan mengisinya dengan seperti yang terlihat pada gambar berikut ini:

Membuat port serial maya di VirtualBox

Membuat port serial maya di VirtualBox

Pada konfigurasi tersebut, sebuah port serial dengan nomor COM1 akan dipetakan pada sebuah named pipe di sistem operasi host dengan nama //./pipe/win7sp1.   Dengan demikian, komputer host dapat mengirim atau menerima pesan pada COM1 di komputer maya melalui named pipe tersebut.   Saya kemudian men-klik tombol OK untuk selesai.

Sebelum menyalakan komputer maya, saya terlebih dahulu memberikan sebuah perintah untuk meningkatkan kinerja baca tulis serial port di VirtualBox:

C:\Program Files\Oracle\VirtualBox>vboxmanage list vms
"Windows 7 For Kernel Debugging" {fdb66984-a4dd-41c3-8549-69e21ff554bc}

C:\Program Files\Oracle\VirtualBox>vboxmanage setextradata {fdb66984-a4dd-41c3-8549-69e21ff554bc} "VBoxInternal/Devices/serial/0/Config/YieldOnLSRRead" 1

C:\Program Files\Oracle\VirtualBox>VBoxmanage getextradata {fdb66984-a4dd-41c3-8549-69e21ff554bc} "VBoxInternal/Devices/serial/0/Config/YieldOnLSRRead"
Value: 1

Pada perintah di atas, saya perlu sebelumnya masuk ke direktori dimana saya men-install VirtualBox.   Selain itu, saya juga perlu menyesuaikan nama virtual machine yang akan diatur.

Setelah ini, saya menyalakan virtual machine tersebut yang mewakili target.   Saya kemudian membuka device manager di komputer maya dan memastikan bahwa sebuah serial port dengan nama COM1 telah terdaftar, seperti yang terlihat pada gambar berikut ini:

Memastikan COM1 telah terdaftar

Memastikan COM1 telah terdaftar

Selain itu, saya juga dapat memerika apakah named pipe sudah dibuat di komputer host dengan menggunakan tool pipelist.exe dari SysinternalsSuite.   Sebagai contoh, berikut ini adalah hasil yang saya peroleh saat mengerjakan pipelist.exe di komputer host:

C:\SysinternalsSuite>pipelist

PipeList v1.01
by Mark Russinovich
http://www.sysinternals.com

Pipe Name                                    Instances       Max Instances
---------                                    ---------       -------------
...
win7sp1                                           1                1

Langkah berikutnya adalah mengaktifkan modus debugging di sistem operasi target di komputer maya.   Saya me-restart komputer maya (virtual machine) dan menekan tombol F8 sesaat setelah layar BIOS, kemudian memilih debugging mode seperti yang terlihat pada gambar berikut ini:

Mengaktifkan debugging mode di target

Mengaktifkan debugging mode di target

Setelah itu, saya akan menjalankan windbg.exe di komputer host sebagai administrator.   Kemudian saya memilih menu File, Kernel Debug…. Saya mengisi dialog yang muncul seperti pada gambar berikut ini:

Memulai kernel debugging dari host

Memulai kernel debugging dari host

Tidak lupa saya juga mengaktifkan verbose output dengan memilih menu View, Verbose Output.   Pada percobaan saya, koneksi tidak langsung dilakukan, sehingga saya perlu me-restart Windows di komputer maya (virtual machine) terlebih dahulu (tetap memilih debugging mode).   Setelah itu, pada WinDbg akan terlihat pesan seperti ‘Connected to Windows 7‘.   Untuk memulai proses debugging, saya perlu menghentikan eksekusi Windows di target dengan memilih menu Debug, Break di WinDbg dimana hasilnya akan terlihat seperti pada gambar berikut ini:

Memulai proses debugging

Memulai proses debugging

Setelah ini, Windows di komputer target akan berhenti dan terlihat tidak bekerja.  Tujuannya adalah agar saya dapat memeriksanya dari komputer host.   Saya dapat segera memberikan perintah di WinDbg untuk melakukan debugging, seperti yang terlihat pada gambar berikut ini:

Pekerjaan debugging dapat segera dimulai

Pekerjaan debugging dapat segera dimulai

Melakukan Local Kernel Debugging Di Windows 7

Kernel debugging adalah suatu proses dimana seseorang men-debug sistem operasi secara keseluruhan, bukan sebuah aplikasi tunggal.   Selain berguna untuk mencari tahu penyebab kesalahan sistem operasi, kernel debugging juga sering dimanfaatkan oleh programmer driver.   Debugging Tools for Windows yang dapat di-download secara gratis telah menyediakan dua debugger yang dapat dipakai: kd.exe yang berbasis command line dan windbg.exe yang berbasis GUI.   Pada kesempatan ini, saya akan memakai windbg.exe.   Walaupun tools ini berbasis GUI, penggunanya tetap perlu beradaptasi dengan sekian banyak perintah yang dimilikinya.   Visual Studio 2013 yang akan dirilis sebentar lagi memiliki peningkatan di bagian debugging, dimana penggunanya kini dapat melakukan kernel debugging langsung dari Visual Studio.   Sayangnya untuk saat ini saya masih belum memiliki kesempatan mencoba memakai Visual Studio 2013, sehingga saya harus betah dengan windbg.exe.

Sebelum saya dapat melakukan kernel debugging pada sebuah sistem operasi Windows, saya harus terlebih dahulu mengaktifkan debugging mode untuk sistem operasi tersebut.   Salah satu caranya adalah dengan menekan tombol F8 pada pertama kali komputer dinyalakan (setelah proses BIOS).    Akan muncul Windows Advanced Options Menu, dimana saya harus memilih Debugging Mode seperti yang terlihat pada gambar berikut ini:

Mengaktifkan modus debugging

Mengaktifkan modus debugging

Setelah itu, desktop Windows akan muncul seperti biasanya.    Saya perlu memastikan bahwa environment variable _NT_SYMBOL_PATH dengan lokasi yang berisi debugging symbols (baca di Menyiapkan dan Memakai Windows debugging symbols).   Cara membuat environment variable baru adalah dengan mengetik “edit system environment variable” di Start menu Windows 7, pilih item di Control Panel, kemudian pada dialog System Properties yang muncul, klik tombol Environment Variables….   Kemudian klik pada tombol New… di System variables untuk membuat environment variable baru bernama _NT_SYMBOL_PATH dengan nilai berupa lokasi yang berisi debugging symbols, misalnya srv*C:\symbols\*http://msdl.microsoft.com/download/symbols.

Kemudian saya mencari windbg.exe di lokasi instalasi Debugging Tools for Windows (secara default terletak di C:\Program Files\Debugging Tools for Windows).   Saya harus menjalankan program tersebut sebagai administrator dengan cara men-klik kanan icon file dan memilih Run as Administrator.   Saya kemudian memilih menu File, Kernel Debug….   Pada dialog yang muncul, saya memilih tab Local dan men-klik tombol OK seperti yang terlihat pada gambar berikut ini:

Memulai local kernel debugging

Memulai local kernel debugging

Setelah menjawab dialog Save information for workspace?, akan muncul sebuah window dimana saya dapat memberikan perintah debugging, seperti yang terlihat pada gambar berikut ini:

Tampilan setelah debugger terhubung dengan target

Tampilan setelah debugger terhubung dengan target

Ini adalah apa yang disebut sebagai local kernel debugging dimana saya men-debug sebuah sistem operasi yang sama (dari sistem operasi tersebut).   Beberapa perintah debugging tidak dapat bekerja pada modus ini.   Salah satu hal yang menarik yang dapat saya lakukan saat ini adalah melihat isi memori.   Saya senang meracik spesifikasi komputer sendiri, jadi ada baiknya saya mengetahui apa isi RAM (ini adalah komponen komputer yang bentuknya seperti kepingan panjang dengan kapasitas umum 2GB, 4GB atau 8GB) di komputer saya saat ini.   Untuk melihat isi 1 KiB pertama dari RAM (bila baca di buku arsitektur komputer, lokasi paling awal dari memori selalu di-isi dengan Interrupt Vector Table/IVT, tapi alangkah baiknya bila saya bisa melihat sendiri struktur tersebut), saya dapat menggunakan perintah !db 0x0 L 400 seperti yang terlihat pada gambar berikut ini:

Melihat isi memory 1 KiB pertama

Melihat isi memory 1 KiB pertama

Bila saya memberikan perintah yang tidak didukung, seperti melihat isi register, saya akan memperoleh pesan kesalahan seperti berikut ini:

lkd> r
     ^ Operation not supported in current debug session 'r'

Untuk mengatasi hal tersebut, saya dapat menggunakan tool LiveKD dari Sysinternals.   Setelah men-download paket program dari Sysinternals, saya dapat menjalankan LiveKD seperti pada perintah berikut ini (sesuaikan lokasi direktori yang dipakai):

C:\Sysinternals> livekd -w

LiveKD akan membuat sebuah crash dump untuk kondisi saat ini, lalu menjalankan WinDbg sehingga saya dapat bereksperimen dengan crash dump tersebut.   Sekarang, saya dapat melihat isi register seperti yang terlihat pada gambar berikut ini:

Isi Register Dapat Dilihat Setelah Memakai LiveKD

Isi Register Dapat Dilihat Setelah Memakai LiveKD

Untuk memperoleh status terbaru, saya perlu menutup WinDbg dimana LiveKD akan bertanya apakah saya ingin kembali menjalankan WinDbg dengan crash dump terbaru.   Cara ini agak repot dan tidak selalu dapat dipakai untuk segala jenis troubleshooting, tapi setidaknya lumayan berguna.

Skenario yang lebih umum adalah melakukan debugging dengan menggunakan dua komputer berbeda. Kedua komputer tersebut terhubung melalui null serial cable, kabel Firewire, atau kabel USB (kabel khusus debugging). Komputer yang akan di-debug disebut sebagai target; sementara itu komputer yang menjalankan debugger (men-debug) disebut sebagai host.   Mencari komputer atau notebook dengan serial cable sudah semakin sulit saat ini.   Perangkat usb-to-serial converter tidak dapat dipakai di sistem target karena serial port tersebut tidak akan terdeteksi sebelum driver USB disajikan.  Walaupun demikian, usb-to-serial boleh dipakai di sistem host (yang melakukan koneksi ke target).  Sementara itu, bila ingin memakai USB, dibutuhkan kabel USB khusus!!  Sangat ribet jadinya bukan?  Ingin memakai serial cable tapi tidak ada port-nya, ingin memakai port USB tapi tidak ada USB debug cable.   Kabar gembiranya, di Windows 8, kernel debugging dapat dilakukan dengan melalui koneksi jaringan (kabelnya murah dan port-nya sering tersedia).