Apakah Linux tidak menggunakan segmentasi tetapi hanya paging?

24

Linux Programming Interface menunjukkan tata letak ruang alamat virtual dari suatu proses. Apakah setiap wilayah dalam diagram adalah segmen?

masukkan deskripsi gambar di sini

Dari Memahami Kernel Linux ,

apakah benar bahwa berikut ini berarti bahwa unit segmentasi dalam MMU memetakan segmen dan offset dalam segmen ke alamat memori virtual, dan unit paging kemudian memetakan alamat memori virtual ke alamat memori fisik?

Memory Management Unit (MMU) mengubah alamat logis menjadi alamat linier melalui sirkuit perangkat keras yang disebut unit segmentasi; selanjutnya, rangkaian perangkat keras kedua yang disebut unit paging mengubah alamat linier menjadi alamat fisik (lihat Gambar 2-1).

masukkan deskripsi gambar di sini

Lalu mengapa dikatakan bahwa Linux tidak menggunakan segmentasi tetapi hanya paging?

Segmentasi telah dimasukkan dalam mikroprosesor 80x86 untuk mendorong programmer untuk membagi aplikasi mereka menjadi entitas yang berhubungan secara logis, seperti subrutin atau area data global dan lokal. Namun, Linux menggunakan segmentasi dengan cara yang sangat terbatas. Bahkan, segmentasi dan paging agak berlebihan, karena keduanya dapat digunakan untuk memisahkan ruang alamat fisik proses: segmentasi dapat menetapkan ruang alamat linear yang berbeda untuk setiap proses, sementara paging dapat memetakan ruang alamat linear yang sama ke dalam ruang alamat fisik yang berbeda . Linux lebih suka paging untuk segmentasi karena alasan berikut:

• Manajemen memori lebih sederhana ketika semua proses menggunakan nilai register segmen yang sama — yaitu, ketika mereka berbagi set alamat linear yang sama.

• Salah satu tujuan desain Linux adalah portabilitas ke berbagai arsitektur; Arsitektur RISC, khususnya, memiliki dukungan terbatas untuk segmentasi.

Versi 2.6 Linux menggunakan segmentasi hanya jika diperlukan oleh arsitektur 80x86.

Tim
sumber
Bisakah Anda menentukan edisi. Mungkin juga bermanfaat untuk menentukan nama penulis. Saya tahu setidaknya yang pertama adalah dari tokoh yang menonjol. Namun, kedua nama judulnya agak generik, tidak jelas bagi saya pada awalnya bahwa Anda berbicara tentang buku :-).
sourcejedi
2
Re "Segmentasi telah dimasukkan dalam mikroprosesor 80x86 ...": Itu tidak benar. Ini adalah warisan dari prosesor 808x, yang memiliki pointer data 16-bit dan segmen memori 64 Kb. Pointer segmen memungkinkan Anda untuk beralih segmen untuk mengatasi lebih banyak memori. Arsitektur itu dibawa ke 80x86 (dengan ukuran pointer meningkat menjadi 33 bit). Saat ini dalam model x86_64, Anda memiliki pointer 64 bit yang dapat (secara teoritis - saya pikir hanya 48 bit yang benar-benar digunakan) alamat 16 exabytes, jadi segmen tidak diperlukan.
jamesqf
2
@ jamesqf, well, mode 32-bit protected di 386 mendukung segmen yang sangat berbeda dari 16-byte scaled pointer di 8086, jadi ini bukan sekadar warisan biasa. Itu tidak berarti apa-apa tentang kegunaan mereka, tentu saja.
ilkkachu
@ jamesqf 80186 memiliki model memori yang sama dengan 8086, tidak ada "33 bit"
Jasen
Tidak ada jawaban yang layak, karena itu hanya komentar: Segmen dan Halaman hanya sebanding dalam konteks swapping (mis. Swapping halaman vs swapping segmen) dan dalam konteks itu Swapping halaman hanya akan menghancurkan segmen swapping yang keluar dari air. Jika Anda menukar segmen masuk / keluar, Anda harus menukar seluruh segmen, yang mungkin 2-4GB. Ini tidak pernah menjadi hal yang nyata untuk digunakan pada x86. Dengan halaman Anda selalu dapat bekerja pada unit 4KB. Ketika datang untuk mengakses memori maka segmen dan halaman terkait melalui tabel halaman dan perbandingan akan menjadi apel dengan jeruk.
vhu

Jawaban:

20

Arsitektur x86-64 tidak menggunakan segmentasi dalam mode panjang (mode 64-bit).

Empat dari register segmen: CS, SS, DS, dan ES dipaksa ke 0, dan batas ke 2 ^ 64.

https://en.wikipedia.org/wiki/X86_memory_segmentation#Later_developments

Tidak mungkin lagi bagi OS untuk membatasi rentang "alamat linear" mana yang tersedia. Karena itu ia tidak dapat menggunakan segmentasi untuk perlindungan memori; itu harus bergantung sepenuhnya pada paging.

Jangan khawatir tentang detail CPU x86 yang hanya akan berlaku saat berjalan dalam mode 32-bit lama. Linux untuk mode 32-bit tidak banyak digunakan. Bahkan mungkin dianggap "dalam keadaan diabaikan jinak selama beberapa tahun". Lihat dukungan x86 32-Bit di Fedora [LWN.net, 2017].

(Kebetulan Linux 32-bit tidak menggunakan segmentasi juga. Tapi Anda tidak perlu mempercayai saya tentang itu, Anda bisa mengabaikannya :-).

sourcejedi
sumber
Itu sedikit berlebihan. base / limit ditetapkan pada 0 / -1 dalam mode long untuk segmen legacy original-8086 (CS / DS / ES / SS), tetapi FS dan GS masih memiliki basis segmen yang berubah-ubah. Dan deskriptor segmen dimuat ke CS menentukan apakah CPU dijalankan dalam mode 32 atau 64-bit. Dan User-space di x86-64 Linux menggunakan FS untuk penyimpanan thread-local ( mov eax, [fs:rdi + 16]). Kernel menggunakan GS (setelah swapgs) untuk menemukan tumpukan kernel proses saat ini di syscalltitik masuk. Tapi ya, segmentasi tidak digunakan sebagai bagian dari manajemen memori OS utama / mekanisme perlindungan memori.
Peter Cordes
Ini pada dasarnya adalah apa yang dimaksud dengan kutipan dalam pertanyaan dengan "Versi 2.6 Linux menggunakan segmentasi hanya bila diperlukan oleh arsitektur 80x86." Tapi paragraf ke-2 Anda pada dasarnya salah. Linux menggunakan segmentasi yang pada dasarnya identik dalam mode 32 dan 64-bit. yaitu basis = 0 / batas = 2 ^ 32 atau 2 ^ 64 untuk segmen klasik (CS / DS / ES / SS) yang digunakan secara implisit oleh instruksi normal. Tidak ada "tambahan" yang perlu dikhawatirkan dalam kode Linux 32-bit; fungsi HW ada di sana tetapi tidak digunakan.
Peter Cordes
@PeterCordes Anda pada dasarnya menafsirkan jawabannya salah :-). Jadi saya sudah mengeditnya untuk mencoba dan membuat argumen saya kurang ambigu.
sourcejedi
Perbaikan bagus, sekarang tidak menyesatkan. Saya sepenuhnya setuju dengan poin asli Anda, yaitu Anda dapat dan harus benar-benar mengabaikan segmentasi x86, karena itu hanya digunakan untuk hal-hal manajemen sistem osdev, dan untuk TLS. Jika Anda ingin akhirnya mempelajarinya, itu jauh lebih mudah untuk dipahami setelah Anda sudah memahami as86 x86 dengan model memori datar.
Peter Cordes
8

Karena x86 memiliki segmen, tidak mungkin untuk tidak menggunakannya. Tetapi alamat basis cs(segmen kode) dan ds(segmen data) diatur ke nol, sehingga segmentasi tidak benar-benar digunakan. Pengecualian adalah utas data lokal, salah satu segmen yang biasanya tidak digunakan mendaftarkan poin untuk utas data lokal. Tapi itu terutama untuk menghindari pemesanan salah satu register tujuan umum untuk tugas ini.

Itu tidak mengatakan bahwa Linux tidak menggunakan segmentasi pada x86, karena itu tidak mungkin. Anda telah menyoroti satu bagian, Linux menggunakan segmentasi dengan cara yang sangat terbatas . Bagian kedua adalah Linux menggunakan segmentasi hanya jika diperlukan oleh arsitektur 80x86

Anda sudah mengutip alasannya, paging lebih mudah dan lebih portabel.

RalfFriedl
sumber
7

Apakah setiap wilayah dalam diagram adalah segmen?

Tidak.

Sementara sistem segmentasi (dalam mode dilindungi 32-bit pada x86) dirancang untuk mendukung segmen kode, data, dan stack yang berbeda, dalam praktiknya semua segmen diatur ke area memori yang sama. Yaitu, mereka mulai dari 0 dan berakhir pada akhir memori (*) . Itu membuat alamat logis dan alamat linear sama.

Ini disebut model memori "datar", dan agak lebih sederhana daripada model di mana Anda memiliki segmen yang berbeda dan kemudian menunjuk di dalamnya. Khususnya, model yang tersegmentasi membutuhkan pointer yang lebih panjang, karena pemilih segmen harus dimasukkan sebagai tambahan dari pointer offset. (Pemilih segmen 16-bit + offset 32-bit untuk total pointer 48 bit; dibandingkan hanya pointer datar 32-bit.)

Mode 64-bit panjang bahkan tidak mendukung segmentasi selain model memori datar.

Jika Anda memprogram dalam mode terproteksi 16-bit pada 286, Anda akan membutuhkan lebih banyak untuk segmen, karena ruang alamat 24 bit tetapi pointer hanya 16 bit.

(* Perhatikan bahwa saya tidak dapat mengingat bagaimana Linux 32-bit menangani pemisahan kernel / userspace. Segmentasi akan memungkinkan melalui pengaturan batas-batas segmen userspace sehingga mereka tidak menyertakan ruang kernel. Paging memungkinkan untuk itu karena ia menyediakan tingkat perlindungan per halaman.)

Lalu mengapa dikatakan bahwa Linux tidak menggunakan segmentasi tetapi hanya paging?

X86 masih memiliki segmen dan Anda tidak dapat menonaktifkannya. Mereka hanya digunakan sesedikit mungkin. Dalam mode terproteksi 32-bit, segmen perlu diatur untuk model datar, dan bahkan dalam mode 64-bit mereka masih ada.

ilkkachu
sumber
Huh, saya kira kernel 32-bit mungkin bisa mengurangi Meltdown lebih murah daripada mengubah tabel halaman dengan menetapkan batas segmen pada CS / DS / ES / SS yang mencegah ruang pengguna mengakses di atas 2G atau 3G. (The Meltdown vuln adalah solusi untuk bit kernel / pengguna dalam entri halaman-tabel, yang memungkinkan ruang pengguna untuk membaca dari halaman yang dipetakan hanya kernel). Halaman VDSO mungkin dipetakan di bagian atas 4G, meskipun: / wrfsbaseilegal dalam mode protected / compat, hanya mode panjang, jadi pada ruang pengguna kernel 32-bit tidak dapat mengatur basis FS tinggi.
Peter Cordes
Pada kernel 64-bit, ruang pengguna 32-bit berpotensi jauh melompat ke segmen kode 64-bit, jadi Anda tidak bisa bergantung pada batas segmen untuk perlindungan Meltdown, hanya mungkin dalam kernel 32-bit murni. (Yang memiliki kerugian besar pada mesin dengan banyak RAM fisik, misalnya kehabisan memori rendah untuk tumpukan thread.) Bagaimanapun, ya Linux melindungi memori kernel dengan paging, meninggalkan basis / batas = 0 / -1 di ruang pengguna untuk normal segmen (bukan FS / GS yang digunakan untuk penyimpanan thread-lokal).
Peter Cordes
Sebelum NX bit didukung dalam tabel halaman perangkat keras (PAE), beberapa patch keamanan awal menggunakan segmentasi untuk membuat tumpukan yang tidak dapat dieksekusi untuk kode ruang pengguna. misalnya linux.com/news/exec-shield-new-linux-security-feature (posting Ingo Molnar menyebutkan "tambalan tumpukan non-eksekutif" yang sangat baik dari Solar Designer.)
Peter Cordes
3

Linux x86 / 32 tidak menggunakan segmentasi dalam arti bahwa ia menginisialisasi semua segmen ke alamat dan batas linier yang sama. arsitektur x86 membutuhkan program untuk memiliki segmen: kode hanya dapat dijalankan dari segmen kode, tumpukan hanya dapat ditemukan di segmen tumpukan, data hanya dapat dimanipulasi di salah satu segmen data. Linux memintas mekanisme ini dengan mengatur semua segmen dengan cara yang sama (dengan pengecualian yang tidak disebutkan oleh buku Anda), sehingga alamat logis yang sama berlaku di segmen mana pun. Ini sebenarnya setara dengan tidak memiliki segmen sama sekali.

Dmitry Grigoryev
sumber
2

Apakah setiap wilayah dalam diagram adalah segmen?

Ini adalah 2 penggunaan yang hampir sama sekali berbeda dari kata "segmen"

  • register segmentasi / segmentasi x86: OS x86 modern menggunakan model memori datar di mana semua segmen memiliki basis yang sama = 0 dan batas = maks dalam mode 32-bit, sama dengan perangkat keras yang menerapkannya dalam mode 64-bit , menjadikan segmentasi semacam peninggalan . (Kecuali untuk FS atau GS, digunakan untuk penyimpanan thread-lokal bahkan dalam mode 64-bit.)
  • Bagian / segmen tautan program / pemuat program. ( Apa perbedaan bagian dan segmen dalam format file ELF )

The penggunaan memiliki asal usul yang sama: jika Anda sedang menggunakan model memori tersegmentasi (terutama tanpa memori virtual paged), Anda mungkin memiliki data dan alamat BSS menjadi relatif terhadap DS dasar segmen, tumpukan relatif terhadap basis SS, dan kode relatif terhadap Alamat dasar CS.

Jadi banyak program yang berbeda dapat dimuat ke alamat linear yang berbeda, atau bahkan dipindahkan setelah memulai, tanpa mengubah offset 16 atau 32-bit relatif terhadap basis segmen.

Tetapi kemudian Anda harus tahu segmen mana yang relatif menjadi pointer, sehingga Anda memiliki "pointer jauh" dan seterusnya. (Sebenarnya program 16-bit x86 sering tidak perlu mengakses kode mereka sebagai data, sehingga dapat menggunakan segmen kode 64k di suatu tempat, dan mungkin blok 64k lainnya dengan DS = SS, dengan tumpukan yang tumbuh dari offset tinggi, dan data di bagian bawah atau model kode kecil dengan semua basis segmen sama).


Bagaimana segmentasi x86 berinteraksi dengan paging

Pemetaan alamat dalam mode 32/64-bit adalah:

  1. segment: offset (basis segmen tersirat oleh register yang memegang offset, atau diganti dengan awalan instruksi)
  2. Alamat virtual linear 32 atau 64-bit = base + offset. (Dalam model memori datar seperti yang digunakan Linux, pointer / offset = alamat linear juga. Kecuali ketika mengakses TLS relatif ke FS atau GS.)
  3. tabel halaman (di-cache oleh TLB) memetakan linear ke 32 (mode legacy), 36 (legacy PAE), atau alamat fisik 52-bit (x86-64). ( /programming/46509152/why-in-64bit-the-virtual-address-are-4-bits-short-48bit-long-compared-with-the ).

    Langkah ini opsional: paging harus diaktifkan selama bootup dengan mengatur sedikit dalam register kontrol. Tanpa paging, alamat linear adalah alamat fisik.

Perhatikan bahwa segmentasi tidak memungkinkan Anda menggunakan lebih dari 32 atau 64 bit ruang alamat virtual dalam satu proses (atau utas) , karena ruang alamat datar (linier) semuanya dipetakan ke dalam hanya memiliki jumlah bit yang sama seperti offset sendiri. (Ini tidak berlaku untuk 16-bit x86, di mana segmentasi sebenarnya berguna untuk menggunakan lebih dari 64k memori dengan sebagian besar register dan offset 16-bit.)


CPU cache cache segmen yang dimuat dari GDT (atau LDT), termasuk basis segmen. Saat Anda menentukan referensi sebuah pointer, tergantung pada register yang mana, itu default ke DS atau SS sebagai segmen. Nilai register (pointer) diperlakukan sebagai offset dari basis segmen.

Karena basis segmen biasanya nol, CPU melakukan hal khusus ini. Atau dari perspektif lain, jika Anda memang memiliki basis segmen yang tidak nol, beban memiliki latensi tambahan karena kasus "khusus" (normal) untuk memintas menambahkan penambahan alamat basis tidak berlaku.


Bagaimana Linux mengatur register segmen x86:

Basis dan batas CS / DS / ES / SS semuanya 0 / -1 dalam mode 32 dan 64-bit. Ini disebut model memori datar karena semua pointer menunjuk ke ruang alamat yang sama.

(Arsitek AMD CPU mensegmentasi segmentasi dengan memberlakukan model memori datar untuk mode 64-bit karena OS mainstream tidak menggunakannya, kecuali untuk perlindungan no-exec yang disediakan dengan cara yang jauh lebih baik dengan paging dengan PAE atau x86- Format 64 halaman-tabel.)

  • TLS (Thread Local Storage): FS dan GS tidak diperbaiki pada base = 0 dalam mode panjang. (Mereka baru dengan 386, dan tidak digunakan secara implisit oleh instruksi apa pun, bahkan repinstruksi -string yang menggunakan ES). x86-64 Linux menetapkan alamat dasar FS untuk setiap utas ke alamat blok TLS.

    misal mov eax, [fs: 16]memuat nilai 32-bit dari 16 byte ke blok TLS untuk utas ini.

  • deskriptor segmen CS memilih mode apa yang digunakan CPU (mode terproteksi 16/32/64-bit / mode panjang). Linux menggunakan entri GDT tunggal untuk semua proses ruang pengguna 64-bit, dan entri GDT lain untuk semua proses ruang pengguna 32-bit. (Agar CPU berfungsi dengan benar, DS / ES juga harus diatur ke entri yang valid, dan begitu juga SS). Ia juga memilih level privilege (kernel (ring 0) vs. user (ring 3)), sehingga bahkan ketika kembali ke ruang pengguna 64-bit, kernel masih harus mengatur agar CS berubah, menggunakan iretatau sysretbukannya normal. lompat atau ret instruksi.

  • Di x86-64, syscalltitik masuk digunakan swapgsuntuk membalikkan GS dari ruang pengguna GS ke kernel, yang digunakannya untuk menemukan tumpukan kernel untuk utas ini. (Kasus khusus penyimpanan thread-lokal). The syscallinstruksi tidak mengubah stack pointer ke titik di stack kernel; itu masih menunjuk ke tumpukan pengguna ketika kernel mencapai titik masuk 1 .

  • DS / ES / SS juga harus diatur ke deskriptor segmen yang valid agar CPU berfungsi dalam mode terproteksi / mode lama, meskipun basis / batas dari deskriptor tersebut diabaikan dalam mode panjang.

Jadi pada dasarnya segmentasi x86 digunakan untuk TLS, dan untuk hal-hal wajib x86 osdev yang diperlukan oleh perangkat keras untuk Anda lakukan.


Catatan Kaki 1: Riwayat menyenangkan: ada arsip milis pesan antara devs kernel dan arsitek AMD dari beberapa tahun sebelum silikon AMD64 dirilis, menghasilkan perubahan pada desain syscallsehingga dapat digunakan. Lihat tautan dalam jawaban ini untuk detailnya.

Peter Cordes
sumber