Versi jawaban ini dengan TOC yang bagus dan lebih banyak konten .
Saya akan memperbaiki kesalahan yang dilaporkan. Jika Anda ingin membuat modifikasi besar atau menambahkan aspek yang hilang, buatlah sesuai dengan jawaban Anda sendiri untuk mendapatkan perwakilan yang layak. Pengeditan kecil dapat digabungkan langsung di.
Kode sampel
Contoh minimal: https://github.com/cirosantilli/x86-bare-metal-examples/blob/5c672f73884a487414b3e21bd9e579c67cd77621/paging.S
Seperti semua hal lain dalam pemrograman, satu-satunya cara untuk benar-benar memahami ini adalah bermain dengan sedikit contoh.
Yang menjadikan ini subjek yang "sulit" adalah contoh minimalnya besar karena Anda perlu membuat OS kecil Anda sendiri.
Manual Intel
Meskipun tidak mungkin untuk memahami tanpa contoh dalam pikiran, cobalah untuk memahami manual secepat mungkin.
Intel menjelaskan paging dalam Panduan Pemrograman Sistem Volume 3 Manual Intel - 325384-056US September 2015 Bab 4 "Paging".
Yang menarik adalah Gambar 4-4 "Format CR3 dan Paging-Structure Entries dengan 32-Bit Paging", yang memberikan struktur data kunci.
MMU
Paging dilakukan oleh bagian Memory Management Unit (MMU) dari CPU. Seperti banyak lainnya (misalnya x87 co-processor , APIC ), ini dulunya dengan chip terpisah pada masa-masa awal, yang kemudian diintegrasikan ke dalam CPU. Namun istilah tersebut masih digunakan.
Fakta umum
Alamat logis adalah alamat memori yang digunakan dalam kode lahan pengguna "biasa" (misalnya, isi rsi
dalam mov eax, [rsi]
).
Segmentasi pertama menerjemahkannya menjadi alamat linier, lalu paging kemudian menerjemahkan alamat linier menjadi alamat fisik.
(logical) ------------------> (linear) ------------> (physical)
segmentation paging
Seringkali, kita dapat menganggap alamat fisik sebagai pengindeksan sel memori perangkat keras RAM yang sebenarnya, tetapi ini tidak 100% benar karena:
Paging hanya tersedia dalam mode terlindungi. Penggunaan paging dalam mode terlindung adalah opsional. Paging aktif jika PG
bit cr0
register disetel.
Paging vs segmentasi
Satu perbedaan utama antara paging dan segmentasi adalah:
- paging membagi RAM menjadi potongan berukuran sama yang disebut halaman
- segmentasi membagi memori menjadi potongan-potongan dengan ukuran yang berubah-ubah
Ini adalah keuntungan utama paging, karena potongan berukuran sama membuat segalanya lebih mudah dikelola.
Paging menjadi jauh lebih populer sehingga dukungan untuk segmentasi dihilangkan di x86-64 dalam mode 64-bit, mode operasi utama untuk perangkat lunak baru, yang hanya ada dalam mode kompatibilitas, yang mengemulasi IA32.
Aplikasi
Paging digunakan untuk mengimplementasikan proses ruang alamat virtual pada OS modern. Dengan alamat virtual, OS dapat memuat dua atau lebih proses bersamaan pada satu RAM dengan cara yang:
- kedua program tidak perlu tahu apa-apa tentang yang lain
- memori dari kedua program dapat bertambah dan menyusut sesuai kebutuhan
- peralihan antar program sangat cepat
- satu program tidak pernah bisa mengakses memori dari proses lain
Paging secara historis muncul setelah segmentasi, dan sebagian besar menggantikannya untuk implementasi memori virtual di OS modern seperti Linux karena lebih mudah untuk mengelola potongan memori halaman berukuran tetap daripada segmen panjang variabel.
Implementasi perangkat keras
Seperti segmentasi dalam mode terlindungi (di mana memodifikasi register segmen memicu beban dari GDT atau LDT), perangkat keras paging menggunakan struktur data dalam memori untuk melakukan tugasnya (tabel halaman, direktori halaman, dll.).
Format struktur data tersebut ditetapkan oleh perangkat keras , tetapi terserah pada OS untuk menyiapkan dan mengelola struktur data tersebut pada RAM dengan benar, dan memberi tahu perangkat keras di mana menemukannya (melalui cr3
).
Beberapa arsitektur lain meninggalkan paging hampir sepenuhnya di tangan perangkat lunak, jadi kesalahan TLB menjalankan fungsi yang disediakan OS untuk berjalan di tabel halaman dan memasukkan pemetaan baru ke dalam TLB. Hal ini membuat format tabel halaman dipilih oleh OS, tetapi tidak memungkinkan perangkat keras untuk dapat tumpang tindih saat berjalan di halaman dengan eksekusi instruksi lain yang tidak teratur, seperti yang dapat dilakukan x86 .
Contoh: skema halaman satu tingkat yang disederhanakan
Ini adalah contoh bagaimana paging beroperasi pada versi arsitektur x86 yang disederhanakan untuk mengimplementasikan ruang memori virtual.
Tabel halaman
OS dapat memberi mereka tabel halaman berikut:
Tabel halaman diberikan untuk proses 1 oleh OS:
RAM location physical address present
----------------- ----------------- --------
PT1 + 0 * L 0x00001 1
PT1 + 1 * L 0x00000 1
PT1 + 2 * L 0x00003 1
PT1 + 3 * L 0
... ...
PT1 + 0xFFFFF * L 0x00005 1
Tabel halaman yang diberikan untuk proses 2 oleh OS:
RAM location physical address present
----------------- ----------------- --------
PT2 + 0 * L 0x0000A 1
PT2 + 1 * L 0x0000B 1
PT2 + 2 * L 0
PT2 + 3 * L 0x00003 1
... ... ...
PT2 + 0xFFFFF * L 0x00004 1
Dimana:
PT1
dan PT2
: posisi awal tabel 1 dan 2 pada RAM.
Nilai sampel: 0x00000000
, 0x12345678
, dll
Ini adalah OS yang menentukan nilai-nilai itu.
L
: panjang entri tabel halaman.
present
: menunjukkan bahwa halaman tersebut ada di memori.
Tabel halaman berada di RAM. Misalnya, mereka dapat ditempatkan sebagai:
--------------> 0xFFFFFFFF
--------------> PT1 + 0xFFFFF * L
Page Table 1
--------------> PT1
--------------> PT2 + 0xFFFFF * L
Page Table 2
--------------> PT2
--------------> 0x0
Lokasi awal pada RAM untuk kedua tabel halaman bersifat arbitrer dan dikontrol oleh OS. Terserah OS untuk memastikan bahwa mereka tidak tumpang tindih!
Setiap proses tidak dapat menyentuh tabel halaman apa pun secara langsung, meskipun dapat membuat permintaan ke OS yang menyebabkan tabel halaman dimodifikasi, misalnya meminta tumpukan yang lebih besar atau segmen heap.
Halaman adalah potongan 4KB (12 bit), dan karena alamat memiliki 32 bit, hanya 20 bit (20 + 12 = 32, sehingga 5 karakter dalam notasi heksadesimal) diperlukan untuk mengidentifikasi setiap halaman. Nilai ini ditetapkan oleh perangkat keras.
Entri tabel halaman
Tabel halaman adalah ... tabel entri tabel halaman!
Format yang tepat dari entri tabel diperbaiki oleh perangkat keras .
Pada contoh yang disederhanakan ini, entri tabel halaman hanya berisi dua bidang:
bits function
----- -----------------------------------------
20 physical address of the start of the page
1 present flag
jadi dalam contoh ini para perancang perangkat keras bisa memilih L = 21
.
Sebagian besar entri tabel halaman nyata memiliki bidang lain.
Ini akan menjadi tidak praktis untuk menyelaraskan sesuatu pada 21 bit karena memori dapat dialamatkan oleh byte dan bukan bit. Oleh karena itu, meskipun hanya dibutuhkan 21 bit dalam kasus ini, perancang perangkat keras mungkin akan memilih L = 32
untuk membuat akses lebih cepat, dan hanya menyimpan bit bit yang tersisa untuk penggunaan nanti. Nilai sebenarnya L
pada x86 adalah 32 bit.
Terjemahan alamat dalam skema satu tingkat
Setelah tabel halaman disiapkan oleh OS, terjemahan alamat antara alamat linier dan fisik dilakukan oleh perangkat keras .
Ketika OS ingin mengaktifkan proses 1, ia menetapkan cr3
ke PT1
, awal tabel untuk proses pertama.
Jika Proses 1 ingin mengakses alamat linier 0x00000001
, rangkaian perangkat keras paging secara otomatis melakukan hal berikut untuk OS:
pisahkan alamat linier menjadi dua bagian:
| page (20 bits) | offset (12 bits) |
Jadi dalam hal ini kami akan memiliki:
- halaman = 0x00000
- offset = 0x001
lihat ke tabel Halaman 1 karena cr3
menunjuk ke sana.
lihat entri 0x00000
karena itu adalah bagian halaman.
Perangkat keras mengetahui bahwa entri ini terletak di alamat RAM PT1 + 0 * L = PT1
.
karena ada, akses tersebut valid
dengan tabel halaman, lokasi nomor halaman 0x00000
berada di 0x00001 * 4K = 0x00001000
.
untuk menemukan alamat fisik akhir kita hanya perlu menambahkan offset:
00001 000
+ 00000 001
-----------
00001 001
karena 00001
alamat fisik halaman yang dicari di tabel dan 001
offset.
Seperti yang ditunjukkan oleh namanya, offset selalu ditambahkan dengan alamat fisik halaman.
perangkat keras kemudian mendapatkan memori di lokasi fisik tersebut.
Dengan cara yang sama, terjemahan berikut akan terjadi untuk proses 1:
linear physical
--------- ---------
00000 002 00001 002
00000 003 00001 003
00000 FFF 00001 FFF
00001 000 00000 000
00001 001 00000 001
00001 FFF 00000 FFF
00002 000 00002 000
FFFFF 000 00005 000
Misalnya, saat mengakses alamat 00001000
, bagian halaman adalah 00001
perangkat keras yang mengetahui bahwa entri tabel halamannya terletak di alamat RAM: PT1 + 1 * L
( 1
karena bagian halaman), dan di sanalah ia akan mencarinya.
Ketika OS ingin beralih ke proses 2, yang perlu dilakukan hanyalah cr3
menunjuk ke halaman 2. Sesederhana itu!
Sekarang terjemahan berikut akan terjadi untuk proses 2:
linear physical
--------- ---------
00000 002 00001 002
00000 003 00001 003
00000 FFF 00001 FFF
00001 000 00000 000
00001 001 00000 001
00001 FFF 00000 FFF
00003 000 00003 000
FFFFF 000 00004 000
Alamat linier yang sama diterjemahkan ke alamat fisik yang berbeda untuk proses yang berbeda , tergantung hanya pada nilai di dalamnya cr3
.
Dengan cara ini, setiap program dapat mengharapkan datanya dimulai 0
dan diakhiri FFFFFFFF
, tanpa mengkhawatirkan alamat fisik yang tepat.
Kesalahan halaman
Bagaimana jika Proses 1 mencoba mengakses alamat di dalam halaman yang tidak ada?
Perangkat keras memberi tahu perangkat lunak melalui Pengecualian Kesalahan Halaman.
Kemudian biasanya tergantung pada OS untuk mendaftarkan penangan pengecualian untuk memutuskan apa yang harus dilakukan.
Ada kemungkinan bahwa mengakses halaman yang tidak ada di tabel adalah kesalahan pemrograman:
int is[1];
is[2] = 1;
tetapi mungkin ada kasus di mana ini dapat diterima, misalnya di Linux ketika:
program ingin meningkatkan tumpukannya.
Ini hanya mencoba untuk mengakses byte tertentu dalam kisaran yang mungkin diberikan, dan jika OS senang itu menambahkan halaman itu ke ruang alamat proses.
halaman telah ditukar ke disk.
OS perlu melakukan beberapa pekerjaan di belakang proses untuk mengembalikan halaman ke RAM.
OS dapat menemukan bahwa hal ini terjadi berdasarkan konten dari sisa entri tabel halaman, karena jika bendera saat ini jelas, entri lain dari entri tabel halaman sepenuhnya diserahkan kepada OS untuk apa yang diinginkannya.
Di Linux misalnya, saat ada = 0:
jika semua bidang entri tabel halaman adalah 0, alamat tidak valid.
lain, halaman telah ditukar ke disk, dan nilai sebenarnya dari kolom tersebut menyandikan posisi halaman di disk.
Bagaimanapun, OS perlu mengetahui alamat mana yang menghasilkan Page Fault untuk dapat mengatasi masalah tersebut. Inilah sebabnya mengapa para pengembang IA32 yang baik menetapkan nilai cr2
ke alamat itu setiap kali Page Fault terjadi. Penangan pengecualian kemudian dapat melihat ke dalam cr2
untuk mendapatkan alamatnya.
Penyederhanaan
Penyederhanaan realitas yang membuat contoh ini lebih mudah dipahami:
semua sirkuit paging nyata menggunakan paging multi-level untuk menghemat ruang, tetapi ini menunjukkan skema satu level yang sederhana.
tabel halaman hanya berisi dua field: alamat 20 bit dan flag 1 bit present.
Tabel halaman riil berisi total 12 bidang, dan oleh karena itu fitur lain yang telah dihilangkan.
Contoh: skema halaman multi-level
Masalah dengan skema paging satu level adalah bahwa ini akan memakan terlalu banyak RAM: entri 4G / 4K = 1 juta per proses. Jika setiap entri panjangnya 4 byte, itu akan menghasilkan 4M per proses , yang terlalu banyak bahkan untuk komputer desktop: ps -A | wc -l
mengatakan bahwa saya sedang menjalankan 244 proses sekarang, jadi itu akan memakan sekitar 1GB RAM saya!
Karena alasan ini, pengembang x86 memutuskan untuk menggunakan skema multi level yang mengurangi penggunaan RAM.
Kelemahan dari sistem ini adalah waktu aksesnya sedikit lebih tinggi.
Dalam skema paging 3 level sederhana yang digunakan untuk prosesor 32 bit tanpa PAE, 32 bit alamat dibagi sebagai berikut:
| directory (10 bits) | table (10 bits) | offset (12 bits) |
Setiap proses harus memiliki satu dan hanya satu direktori halaman yang terkait dengannya, sehingga akan berisi setidaknya 2^10 = 1K
entri direktori halaman, jauh lebih baik daripada minimum 1M yang diperlukan pada skema level tunggal.
Tabel halaman hanya dialokasikan sesuai kebutuhan oleh OS. Setiap tabel 2^10 = 1K
halaman memiliki entri direktori halaman
Direktori halaman berisi ... entri direktori halaman! Entri direktori halaman sama dengan entri tabel halaman kecuali yang menunjuk ke alamat RAM tabel halaman, bukan alamat fisik tabel . Karena alamat tersebut hanya lebarnya 20 bit, tabel halaman harus di awal halaman 4KB.
cr3
sekarang menunjuk ke lokasi pada RAM dari direktori halaman dari proses saat ini, bukan tabel halaman.
Entri tabel halaman tidak berubah sama sekali dari skema tingkat tunggal.
Tabel halaman berubah dari skema tingkat tunggal karena:
- setiap proses dapat memiliki hingga 1K tabel halaman, satu per entri direktori halaman.
- setiap tabel halaman berisi persis 1K entri, bukan 1 juta entri.
Alasan untuk menggunakan 10 bit pada dua tingkat pertama (dan bukan, katakanlah, 12 | 8 | 12
) adalah karena setiap entri Tabel Halaman panjangnya 4 byte. Kemudian 2 ^ 10 entri direktori Halaman dan Tabel Halaman akan cocok dengan baik ke dalam halaman 4Kb. Ini berarti lebih cepat dan lebih mudah untuk mengalokasikan dan membatalkan alokasi halaman untuk tujuan itu.
Terjemahan alamat dalam skema multi-level
Direktori halaman diberikan untuk proses 1 oleh OS:
RAM location physical address present
--------------- ----------------- --------
PD1 + 0 * L 0x10000 1
PD1 + 1 * L 0
PD1 + 2 * L 0x80000 1
PD1 + 3 * L 0
... ...
PD1 + 0x3FF * L 0
Tabel halaman yang diberikan untuk proses 1 oleh OS pada PT1 = 0x10000000
( 0x10000
* 4K):
RAM location physical address present
--------------- ----------------- --------
PT1 + 0 * L 0x00001 1
PT1 + 1 * L 0
PT1 + 2 * L 0x0000D 1
... ...
PT1 + 0x3FF * L 0x00005 1
Tabel halaman yang diberikan untuk proses 1 oleh OS pada PT2 = 0x80000000
( 0x80000
* 4K):
RAM location physical address present
--------------- ----------------- --------
PT2 + 0 * L 0x0000A 1
PT2 + 1 * L 0x0000C 1
PT2 + 2 * L 0
... ...
PT2 + 0x3FF * L 0x00003 1
dimana:
PD1
: posisi awal direktori halaman proses 1 pada RAM.
PT1
dan PT2
: posisi awal tabel halaman 1 dan tabel halaman 2 untuk proses 1 pada RAM.
Jadi dalam contoh ini direktori halaman dan tabel halaman dapat disimpan dalam RAM seperti:
----------------> 0xFFFFFFFF
----------------> PT2 + 0x3FF * L
Page Table 1
----------------> PT2
----------------> PD1 + 0x3FF * L
Page Directory 1
----------------> PD1
----------------> PT1 + 0x3FF * L
Page Table 2
----------------> PT1
----------------> 0x0
Mari terjemahkan alamat linier 0x00801004
langkah demi langkah.
Kami berasumsi bahwa cr3 = PD1
, maksudnya, ini menunjuk ke direktori halaman yang baru saja dijelaskan.
Dalam biner alamat liniernya adalah:
0 0 8 0 1 0 0 4
0000 0000 1000 0000 0001 0000 0000 0100
Pengelompokan sebagai pemberian 10 | 10 | 12
:
0000000010 0000000001 000000000100
0x2 0x1 0x4
pemberian yang mana:
- entri direktori halaman = 0x2
- entri tabel halaman = 0x1
- offset = 0x4
Jadi perangkat keras mencari entri 2 dari direktori halaman.
Tabel direktori halaman mengatakan bahwa tabel halaman berada di 0x80000 * 4K = 0x80000000
. Ini adalah proses akses RAM pertama.
Karena entri tabel halaman adalah 0x1
, perangkat keras melihat entri 1 dari tabel halaman di 0x80000000
, yang memberi tahu bahwa halaman fisik terletak di alamat0x0000C * 4K = 0x0000C000
. Ini adalah proses akses RAM kedua.
Akhirnya, perangkat keras paging menambahkan offset, dan alamat akhirnya adalah 0x0000C004
.
Contoh lain dari alamat yang diterjemahkan adalah:
linear 10 10 12 split physical
-------- --------------- ----------
00000001 000 000 001 00001001
00001001 000 001 001 page fault
003FF001 000 3FF 001 00005001
00400000 001 000 000 page fault
00800001 002 000 001 0000A001
00801008 002 001 008 0000C008
00802008 002 002 008 page fault
00B00001 003 000 000 page fault
Kesalahan halaman terjadi jika entri direktori halaman atau entri tabel halaman tidak ada.
Jika OS ingin menjalankan proses lain secara bersamaan, itu akan memberikan proses kedua direktori halaman terpisah, dan menautkan direktori itu ke tabel halaman terpisah.
Arsitektur 64-bit
64 bit masih terlalu banyak alamat untuk ukuran RAM saat ini, jadi kebanyakan arsitektur akan menggunakan lebih sedikit bit.
x86_64 menggunakan 48 bit (256 TiB), dan PAE mode lama sudah mengizinkan alamat 52-bit (4 PiB).
12 dari 48 bit tersebut sudah disediakan untuk offset, yang menyisakan 36 bit.
Jika pendekatan 2 level diambil, pembagian terbaik adalah dua level 18 bit.
Tetapi itu berarti bahwa direktori halaman akan memiliki 2^18 = 256K
entri, yang akan memakan terlalu banyak RAM: mendekati paging level tunggal untuk arsitektur 32 bit!
Oleh karena itu, arsitektur 64 bit membuat level halaman lebih jauh, biasanya 3 atau 4.
x86_64 menggunakan 4 level dalam 9 | 9 | 9 | 12
skema, sehingga level atas hanya mengambil 2^9
entri level yang lebih tinggi.
PAE
Ekstensi alamat fisik.
Dengan 32 bit, hanya 4GB RAM yang bisa digunakan.
Ini mulai menjadi batasan untuk server besar, jadi Intel memperkenalkan mekanisme PAE ke Pentium Pro.
Untuk mengatasi masalah tersebut, Intel menambahkan 4 baris alamat baru, sehingga 64GB dapat ditangani.
Struktur tabel halaman juga diubah jika PAE aktif. Cara yang tepat untuk mengubahnya tergantung pada apakah PSE aktif atau nonaktif.
PAE dihidupkan dan dimatikan melalui PAE
bit cr4
.
Meskipun total memori yang dapat dialamatkan adalah 64 GB, proses individual masih hanya dapat menggunakan hingga 4 GB. Namun OS dapat menempatkan proses yang berbeda pada potongan 4GB yang berbeda.
PSE
Ekstensi ukuran halaman.
Mengizinkan halaman berukuran 4M (atau 2M jika PAE aktif), bukan 4K.
PSE dihidupkan dan dimatikan melalui PAE
bit cr4
.
Skema tabel halaman PAE dan PSE
Jika PAE dan PSE aktif, skema tingkat halaman yang berbeda digunakan:
tanpa PAE dan tanpa PSE: 10 | 10 | 12
PAE ada dan PSE: 10 | 22
.
22 adalah offset dalam halaman 4Mb, karena 22 bit alamat 4Mb.
PAE dan tanpa PSE: 2 | 9 | 9 | 12
Alasan desain mengapa 9 digunakan dua kali, bukan 10 adalah bahwa sekarang entri tidak dapat lagi masuk ke dalam 32 bit, yang semuanya diisi oleh 20 bit alamat dan 12 bit flag yang bermakna atau dicadangkan.
Alasannya adalah bahwa 20 bit tidak cukup lagi untuk mewakili alamat tabel halaman: 24 bit sekarang diperlukan karena 4 kabel tambahan ditambahkan ke prosesor.
Oleh karena itu, desainer memutuskan untuk meningkatkan ukuran entri menjadi 64 bit, dan untuk membuatnya sesuai dengan tabel halaman tunggal, perlu mengurangi jumlah entri menjadi 2 ^ 9 daripada 2 ^ 10.
Awal 2 adalah tingkat Halaman baru yang disebut Tabel Penunjuk Direktori Halaman (PDPT), karena menunjuk ke direktori halaman dan mengisi alamat linier 32 bit. PDPT juga memiliki lebar 64 bit.
cr3
sekarang menunjuk ke PDPT yang harus berada di atas empat memori 4GB dan diselaraskan pada kelipatan 32 bit untuk menangani efisiensi. Ini berarti bahwa sekarang cr3
memiliki 27 bit signifikan, bukan 20: 2 ^ 5 untuk 32 kelipatan * 2 ^ 27 untuk menyelesaikan 2 ^ 32 dari 4GB pertama.
PAE dan PSE: 2 | 9 | 21
Desainer memutuskan untuk menyimpan bidang lebar 9 bit agar sesuai dengan satu halaman.
Ini menyisakan 23 bit. Meninggalkan 2 untuk PDPT agar semuanya tetap seragam dengan case PAE tanpa PSE menyisakan 21 untuk offset, yang berarti bahwa halaman memiliki lebar 2M, bukan 4M.
TLB
The Translation Lookahead Buffer (TLB) adalah cache untuk alamat paging.
Karena ini adalah cache, ia berbagi banyak masalah desain dari cache CPU, seperti tingkat keterkaitan.
Bagian ini akan menjelaskan TLB asosiatif penuh yang disederhanakan dengan 4 entri alamat tunggal. Perhatikan bahwa seperti cache lainnya, TLB asli biasanya tidak sepenuhnya asosiatif.
Operasi dasar
Setelah terjadi terjemahan antara alamat linier dan fisik, itu disimpan di TLB. Misalnya, 4 entri TLB dimulai dalam kondisi berikut:
valid linear physical
------ ------- ---------
> 0 00000 00000
0 00000 00000
0 00000 00000
0 00000 00000
Itu >
menunjukkan entry ini harus diganti.
dan setelah alamat linier halaman 00003
diterjemahkan ke alamat fisik 00005
, TLB menjadi:
valid linear physical
------ ------- ---------
1 00003 00005
> 0 00000 00000
0 00000 00000
0 00000 00000
dan setelah terjemahan kedua 00007
untuk 00009
menjadi:
valid linear physical
------ ------- ---------
1 00003 00005
1 00007 00009
> 0 00000 00000
0 00000 00000
Sekarang jika 00003
perlu diterjemahkan lagi, perangkat keras pertama-tama mencari TLB dan menemukan alamatnya dengan satu akses RAM 00003 --> 00005
.
Tentu saja, 00000
tidak ada di TLB karena tidak ada entri valid yang berisi 00000
sebagai kunci.
Kebijakan penggantian
Saat TLB diisi, alamat lama ditimpa. Sama seperti untuk cache CPU, kebijakan penggantian adalah operasi yang berpotensi kompleks, tetapi heuristik yang sederhana dan masuk akal adalah dengan menghapus entri yang paling terakhir digunakan (LRU).
Dengan LRU, mulai dari negara bagian:
valid linear physical
------ ------- ---------
> 1 00003 00005
1 00007 00009
1 00009 00001
1 0000B 00003
menambahkan 0000D -> 0000A
akan memberi:
valid linear physical
------ ------- ---------
1 0000D 0000A
> 1 00007 00009
1 00009 00001
1 0000B 00003
CAM
Menggunakan TLB membuat terjemahan lebih cepat, karena terjemahan awal mengambil satu akses per tingkat TLB , yang berarti 2 pada skema 32 bit sederhana, tetapi 3 atau 4 pada arsitektur 64 bit.
TLB biasanya diimplementasikan sebagai jenis RAM mahal yang disebut memori beralamat konten (CAM). CAM mengimplementasikan peta asosiatif pada perangkat keras, yaitu struktur yang diberi kunci (alamat linier), mengambil nilai.
Pemetaan juga dapat diterapkan pada alamat RAM, tetapi pemetaan CAM mungkin memerlukan entri yang jauh lebih sedikit daripada pemetaan RAM.
Misalnya, peta di mana:
- kedua kunci dan nilai memiliki 20 bit (kasus skema halaman sederhana)
- paling banyak 4 nilai perlu disimpan setiap saat
dapat disimpan di TLB dengan 4 entri:
linear physical
------- ---------
00000 00001
00001 00010
00010 00011
FFFFF 00000
Namun, untuk mengimplementasikan ini dengan RAM, perlu memiliki 2 ^ 20 alamat :
linear physical
------- ---------
00000 00001
00001 00010
00010 00011
... (from 00011 to FFFFE)
FFFFF 00000
yang akan lebih mahal daripada menggunakan TLB.
Entri tidak valid
Saat cr3
berubah, semua entri TLB tidak valid, karena tabel halaman baru untuk proses baru akan digunakan, jadi sepertinya tidak ada entri lama yang memiliki arti.
X86 juga menawarkan invlpg
instruksi yang secara eksplisit membatalkan satu entri TLB. Arsitektur lain menawarkan lebih banyak instruksi untuk entri TLB yang tidak valid, seperti membatalkan semua entri pada rentang tertentu.
Beberapa CPU x86 melampaui persyaratan spesifikasi x86 dan memberikan lebih banyak koherensi daripada yang dijaminnya, antara memodifikasi entri tabel halaman dan menggunakannya, ketika belum di-cache di TLB . Rupanya Windows 9x mengandalkan itu untuk kebenaran, tetapi CPU AMD modern tidak menyediakan perjalanan halaman yang koheren. CPU Intel melakukannya, meskipun mereka harus mendeteksi spekulasi yang salah untuk melakukannya. Mengambil keuntungan dari ini mungkin merupakan ide yang buruk, karena mungkin tidak banyak keuntungan yang didapat, dan risiko besar menyebabkan masalah sensitif waktu yang tidak kentara yang akan sulit di-debug.
Penggunaan kernel Linux
Kernel Linux menggunakan fitur paging x86 secara ekstensif untuk memungkinkan proses switch yang cepat dengan fragmentasi data yang kecil.
Masuk v4.2
, lihat di bawah arch/x86/
:
include/asm/pgtable*
include/asm/page*
mm/pgtable*
mm/page*
Tampaknya tidak ada struct yang didefinisikan untuk mewakili halaman, hanya makro: include/asm/page_types.h
menarik secara khusus. Kutipan:
#define _PAGE_BIT_PRESENT 0 /* is present */
#define _PAGE_BIT_RW 1 /* writeable */
#define _PAGE_BIT_USER 2 /* userspace addressable */
#define _PAGE_BIT_PWT 3 /* page write through */
arch/x86/include/uapi/asm/processor-flags.h
mendefinisikan CR0
, dan khususnya PG
posisi bit:
#define X86_CR0_PG_BIT 31 /* Paging */
Bibliografi
Gratis:
Tidak gratis: