Cincin CPU adalah perbedaan yang paling jelas
Dalam mode terproteksi x86, CPU selalu berada dalam salah satu dari 4 dering. Kernel Linux hanya menggunakan 0 dan 3:
- 0 untuk kernel
- 3 untuk pengguna
Ini adalah definisi kernel vs userland yang paling keras dan cepat.
Mengapa Linux tidak menggunakan dering 1 dan 2: https://stackoverflow.com/questions/6710040/cpu-privilege-rings-why-rings-1-and-2-arent-used
Bagaimana cincin saat ini ditentukan?
Cincin saat ini dipilih oleh kombinasi dari:
tabel deskriptor global: tabel in-memory dari entri GDT, dan setiap entri memiliki bidang Privl
yang menyandikan ring.
Instruksi LGDT mengatur alamat ke tabel deskriptor saat ini.
Lihat juga: http://wiki.osdev.org/Global_Descriptor_Table
segmen mendaftarkan CS, DS, dll., yang menunjuk ke indeks entri di GDT.
Misalnya, CS = 0
berarti entri pertama GDT saat ini aktif untuk kode pelaksana.
Apa yang bisa dilakukan oleh setiap dering?
Chip CPU dibangun secara fisik sehingga:
dering 0 dapat melakukan apa saja
dering 3 tidak dapat menjalankan beberapa instruksi dan menulis ke beberapa register, terutama:
tidak dapat mengubah cincinnya sendiri! Kalau tidak, itu bisa mengatur dirinya sendiri untuk berdering 0 dan berdering akan sia-sia.
Dengan kata lain, tidak dapat memodifikasi deskriptor segmen saat ini , yang menentukan dering saat ini.
tidak dapat mengubah tabel halaman: https://stackoverflow.com/questions/18431261/how-does-x86-paging-work
Dengan kata lain, tidak dapat memodifikasi register CR3, dan paging itu sendiri mencegah modifikasi tabel halaman.
Ini mencegah satu proses dari melihat memori proses lain untuk keamanan / kemudahan alasan pemrograman.
tidak dapat mendaftarkan penangan interupsi. Itu dikonfigurasikan dengan menulis ke lokasi memori, yang juga dicegah dengan paging.
Handler dijalankan di ring 0, dan akan merusak model keamanan.
Dengan kata lain, tidak dapat menggunakan instruksi LGDT dan LIDT.
tidak dapat melakukan instruksi IO seperti in
dan out
, dan karenanya memiliki akses perangkat keras yang sewenang-wenang.
Kalau tidak, misalnya, izin file tidak akan berguna jika program apa pun dapat langsung membaca dari disk.
Lebih tepatnya berkat Michael Petch : sebenarnya dimungkinkan bagi OS untuk mengizinkan instruksi IO pada cincin 3, ini sebenarnya dikendalikan oleh segmen status Tugas .
Yang tidak mungkin adalah cincin 3 memberi izin pada dirinya sendiri jika tidak memilikinya sejak awal.
Linux selalu melarangnya. Lihat juga: https://stackoverflow.com/questions/2711044/why-doesnt-linux-use-the-hardware-context-switch-via-the-tss
Bagaimana transisi program dan sistem operasi antar cincin?
ketika CPU dihidupkan, itu mulai menjalankan program awal di ring 0 (agak baik, tetapi itu adalah perkiraan yang baik). Anda dapat menganggap program awal ini sebagai kernel (tetapi biasanya bootloader yang kemudian memanggil kernel masih di ring 0).
ketika proses userland menginginkan kernel untuk melakukan sesuatu untuknya seperti menulis ke file, ia menggunakan instruksi yang menghasilkan interupsi seperti int 0x80
atausyscall
untuk memberi sinyal kernel. x86-64 Linux syscall hello world contoh:
.data
hello_world:
.ascii "hello world\n"
hello_world_len = . - hello_world
.text
.global _start
_start:
/* write */
mov $1, %rax
mov $1, %rdi
mov $hello_world, %rsi
mov $hello_world_len, %rdx
syscall
/* exit */
mov $60, %rax
mov $0, %rdi
syscall
kompilasi dan jalankan:
as -o hello_world.o hello_world.S
ld -o hello_world.out hello_world.o
./hello_world.out
GitHub hulu .
Ketika ini terjadi, CPU memanggil pengendali panggilan balik interupsi yang didaftarkan kernel saat boot. Berikut adalah contoh baremetal konkret yang mendaftarkan pawang dan menggunakannya .
Handler ini berjalan di ring 0, yang memutuskan apakah kernel akan mengizinkan tindakan ini, melakukan tindakan, dan memulai kembali program userland di cincin 3. x86_64
ketika exec
panggilan sistem digunakan (atau ketika kernel akan mulai/init
), kernel menyiapkan register dan memori dari proses userland baru, kemudian melompat ke titik masuk dan mengalihkan CPU ke dering 3
Jika program mencoba melakukan sesuatu yang nakal seperti menulis ke register terlarang atau alamat memori (karena paging), CPU juga memanggil beberapa handler callback kernel di ring 0.
Tetapi karena userland nakal, kernel mungkin membunuh proses kali ini, atau memberinya peringatan dengan sinyal.
Ketika kernel melakukan boot, ia akan mengatur jam perangkat keras dengan frekuensi tetap, yang menghasilkan interupsi secara berkala.
Jam perangkat keras ini menghasilkan interupsi yang menjalankan dering 0, dan memungkinkannya untuk menjadwalkan pengguna mana proses untuk bangun.
Dengan cara ini, penjadwalan dapat terjadi bahkan jika proses tidak membuat panggilan sistem apa pun.
Apa gunanya memiliki beberapa dering?
Ada dua keuntungan utama dari pemisahan kernel dan userland:
- lebih mudah untuk membuat program karena Anda lebih yakin tidak akan mengganggu yang lain. Misalnya, satu proses userland tidak perlu khawatir tentang menimpa memori program lain karena paging, atau tentang meletakkan perangkat keras dalam keadaan tidak valid untuk proses lain.
- ini lebih aman. Misalnya, izin file dan pemisahan memori dapat mencegah aplikasi peretasan membaca data bank Anda. Ini mengandaikan, tentu saja, bahwa Anda mempercayai kernel.
Bagaimana cara bermain-main dengannya?
Saya telah membuat pengaturan logam kosong yang seharusnya menjadi cara yang baik untuk memanipulasi cincin secara langsung: https://github.com/cirosantilli/x86-bare-metal-examples
Saya tidak memiliki kesabaran untuk membuat contoh userland sayangnya, tapi saya melakukan pengaturan paging, jadi userland harus layak. Saya ingin melihat permintaan tarik.
Sebagai alternatif, modul kernel Linux berjalan di ring 0, sehingga Anda dapat menggunakannya untuk mencoba operasi yang diistimewakan, mis. Baca register kontrol: https://stackoverflow.com/questions/7415515/how-to-access-the-control-registers -cr0-cr2-cr3-dari-program-mendapatkan-segmenta / 7419306 # 7419306
Berikut ini adalah pengaturan QEMU + Buildroot yang nyaman untuk mencobanya tanpa membunuh host Anda.
Kelemahan dari modul kernel adalah bahwa kthreads lain sedang berjalan dan dapat mengganggu percobaan Anda. Tetapi secara teori Anda dapat mengambil alih semua penangan interupsi dengan modul kernel Anda dan memiliki sistem, yang sebenarnya merupakan proyek yang menarik.
Dering negatif
Walaupun dering negatif tidak benar-benar dirujuk dalam manual Intel, sebenarnya ada mode CPU yang memiliki kemampuan lebih lanjut dari dering 0 itu sendiri, dan begitu juga cocok untuk nama "cincin negatif".
Salah satu contoh adalah mode hypervisor yang digunakan dalam virtualisasi.
Untuk perincian lebih lanjut, lihat: https://security.stackexchange.com/questions/129098/what-is-protection-ring-1
LENGAN
Dalam ARM, cincinnya disebut Tingkat Pengecualian, tetapi gagasan utamanya tetap sama.
Ada 4 level pengecualian dalam ARMv8, yang biasa digunakan sebagai:
EL0: userland
EL1: kernel ("supervisor" dalam terminologi ARM).
Dimasukkan dengan svc
instruksi (Panggilan SuperVisor), yang sebelumnya dikenal sebagai swi
unified assembly , yang merupakan instruksi yang digunakan untuk melakukan panggilan sistem Linux. Contoh Hello world ARMv8:
.text
.global _start
_start:
/* write */
mov x0, 1
ldr x1, =msg
ldr x2, =len
mov x8, 64
svc 0
/* exit */
mov x0, 0
mov x8, 93
svc 0
msg:
.ascii "hello syscall v8\n"
len = . - msg
GitHub hulu .
Uji dengan QEMU di Ubuntu 16.04:
sudo apt-get install qemu-user gcc-arm-linux-gnueabihf
arm-linux-gnueabihf-as -o hello.o hello.S
arm-linux-gnueabihf-ld -o hello hello.o
qemu-arm hello
Berikut ini adalah contoh nyata beton yang mendaftarkan penangan SVC dan melakukan panggilan SVC .
EL2: hypervisors , misalnya Xen .
Dimasukkan dengan hvc
instruksi (Panggilan HyperVisor).
Hypervisor adalah untuk OS, apa OS untuk userland.
Sebagai contoh, Xen memungkinkan Anda untuk menjalankan banyak OS seperti Linux atau Windows pada sistem yang sama secara bersamaan, dan itu mengisolasi OS satu sama lain untuk keamanan dan kemudahan debug, seperti halnya Linux untuk program userland.
Hypervisor adalah bagian penting dari infrastruktur cloud saat ini: mereka memungkinkan banyak server untuk berjalan pada satu perangkat keras, menjaga penggunaan perangkat keras selalu mendekati 100% dan menghemat banyak uang.
AWS misalnya menggunakan Xen hingga 2017 ketika kepindahannya ke KVM menjadi berita .
EL3: tingkat lain. Contoh TODO.
Dimasukkan dengan smc
instruksi (Panggilan Mode Aman)
The ARMv8 Arsitektur Model Referensi DDI 0487C.a - Bab D1 - The AArch64 Sistem Tingkat Programmer Model - Gambar D1-1 menggambarkan ini indah:
Perhatikan bagaimana ARM, mungkin karena manfaat dari belakang, memiliki konvensi penamaan yang lebih baik untuk tingkat hak istimewa daripada x86, tanpa perlu tingkat negatif: 0 menjadi yang lebih rendah dan 3 tertinggi. Level yang lebih tinggi cenderung dibuat lebih sering daripada level yang lebih rendah.
EL saat ini dapat ditanyakan dengan MRS
instruksi: https://stackoverflow.com/questions/31787617/what-is-the-current-execution-mode-exception-level-etc
ARM tidak memerlukan semua level pengecualian untuk hadir untuk memungkinkan implementasi yang tidak memerlukan fitur untuk menghemat area chip. ARMv8 "Level pengecualian" mengatakan:
Suatu implementasi mungkin tidak mencakup semua level Pengecualian. Semua implementasi harus menyertakan EL0 dan EL1. EL2 dan EL3 adalah opsional.
QEMU misalnya default ke EL1, tetapi EL2 dan EL3 dapat diaktifkan dengan opsi baris perintah: https://stackoverflow.com/questions/42824706/qemu-system-aarch64-entering-el1-when-emulating-a53-power-up
Cuplikan kode diuji di Ubuntu 18.10.