Kullanıcı alanı ve Çekirdek alanı arasındaki fark nedir?


72

Çekirdek kullanıcı programı yani Sistem Çağrısı adına yürütülürken Çekirdek alanı kullanılıyor mu? Yoksa tüm Çekirdek iş parçacıkları için adres alanı mı (örneğin, zamanlayıcı)?

İlki ise normal kullanıcı programının 3GB'tan fazla belleğe sahip olamayacağı anlamına mı geliyor (bölme 3GB + 1GB ise)? Ayrıca, bu durumda, çekirdek yüksek belleği nasıl kullanır, çünkü hangi sanal bellek adresinin yüksek bellekten gelen sayfaları eşleştirileceği, 1GB çekirdek alanı mantıksal olarak eşleneceği için?

Yanıtlar:


93

Çekirdek kullanıcı programı yani Sistem Çağrısı adına yürütülürken Çekirdek alanı kullanılıyor mu? Yoksa tüm Çekirdek iş parçacıkları için adres alanı mı (örneğin, zamanlayıcı)?

Evet ve evet.

Daha ileri gitmeden önce, bunu hafıza hakkında belirtmeliyiz.

Hafıza almak iki farklı alana bölünmüştür:

  • Normal kullanıcı işlemlerinin çalıştığı bir konum kümesi olan kullanıcı alanı (yani çekirdek dışındaki her şey). Çekirdeğin rolü, bu alanda çalışan uygulamaları birbirleriyle ve makineyle karıştırmaktan yönetmektir.
  • Çekirdek kodunun saklandığı konum olan çekirdek alanı ve altında yürütülür.

Kullanıcı alanı altında çalışan işlemler, belleğin yalnızca sınırlı bir bölümüne erişime sahipken, çekirdeğin tüm belleğe erişimi vardır. Kullanıcı uzayda çalışan süreçler de yok çekirdek alanı erişebilirler. Kullanıcı uzay süreçleri olabilir , çekirdeğin sadece küçük bir bölümünü erişmek çekirdek tarafından maruz bir arayüz üzerinden - Sistem çağrıları . Bir işlem bir sistem çağrısı gerçekleştirirse, çekirdeğe bir yazılım kesmesi gönderilir, ardından uygun kesme işleyicisini gönderir ve işleyici bittikten sonra çalışmalarına devam eder.

Çekirdek alanı kodu, "çekirdek modunda" çalıştırma özelliğine sahiptir, (tipik masaüstünüzde - x86 - bilgisayarınızda), 0 halkası altında çalıştırdığınız kod olarak adlandırırsınız . Genelde x86 mimarisinde, 4 koruma halkası vardır . Zil 0 (çekirdek modu), Zil 1 (sanal makine hipervizörleri veya sürücüler tarafından kullanılabilir), Zil 2 (sürücüler tarafından kullanılabilir, bunun hakkında pek emin değilim). Halka 3, tipik uygulamaların altında çalıştığı şeydir. En az ayrıcalıklı halkadır ve üzerinde çalışan uygulamalar işlemcinin talimatlarının bir alt kümesine erişebilir. Halka 0 (çekirdek alanı) en ayrıcalıklı halkadır ve makinenin tüm talimatlarına erişebilir. Örneğin, bir "düz" uygulama (bir tarayıcı gibi) x86 montaj talimatlarını kullanamazlgdtgenel tanımlayıcı tablosunu yüklemek veya hltbir işlemciyi durdurmak için.

İlki ise normal kullanıcı programının 3GB'tan fazla belleğe sahip olamayacağı anlamına mı geliyor (bölme 3GB + 1GB ise)? Ayrıca, bu durumda, çekirdek yüksek belleği nasıl kullanır, çünkü hangi sanal bellek adresinin yüksek bellekten gelen sayfaları eşleştirileceği, 1GB çekirdek alanı mantıksal olarak eşleneceği için?

Bu bir cevap için, tarafından mükemmel cevaba bakınız sallayamam burada


4
Bir yerde bir hata yaptıysam bana söylemekten çekinme. Çekirdek programlama konusunda yeniyim ve şimdiye kadar öğrendiklerimi, web'de bulduğum diğer bilgilerle birlikte bıraktım. Bu, metinde gösterilebilecek kavramları anlamada eksiklikler olabileceği anlamına gelir.
NlightNFotis,

Teşekkürler! Sanırım şimdi daha iyi anlıyorum. Doğru anladığımdan emin olmak için bir sorum daha var. Yine, ilk 3GB'nin kullanıcı alanı için kullanıldığı ve 128 MB'lık çekirdek alanı Yüksek bellek için kullanıldığı düşünülürse, kalan 896 MB (Düşük Bellek) açılışta statik olarak eşlenir mi?
Poojan

1
@NlightNFotis Neredeyse 15 kişinin söylediğin her şeyin doğru olduğuna inandığını söylüyorum (ya da bize düşündürmeni sağlıyorsun;))
Braiam

X86 yüzüğünün -1hipervizörler için olduğunu sanıyordum ? en.wikipedia.org/wiki/Protection_ring
Dori

1
Sanal bellek ve fiziksel bellek arasındaki farka dikkat edin. İstediğiniz şeylerin çoğu sanal bellekle ilgili. Bu fiziksel hafızaya eşlenir, fiziksel hafıza 3GB'ye yaklaştığında karmaşıklaşır ve PAE kullanılır. 64bit çekirdek kullanıldığında tekrar basitleşir, bu durumda negatif adresler çekirdeğe, pozitif adresler ise kullanıcı alanı için ayrılmıştır. 32bit işlemler şimdi 4GB sanal alan kullanabilir. 64bit işlemler çok daha fazlasını kullanabilir - genellikle 48 bit değerinde (şu anda x86-64'te).
ctrl-alt-delor

16

CPU halkaları en belirgin ayrımdır

X86 korumalı modda, CPU her zaman 4 zilden birindedir. Linux çekirdeği yalnızca 0 ve 3 kullanır:

  • Çekirdek için 0
  • Kullanıcılar için 3

Bu çekirdek vs userland en sert ve hızlı tanımıdır.

Linux neden 1. ve 2. halkaları kullanmıyor: https://stackoverflow.com/questions/6710040/cpu-privilege-rings-why-rings-1-and-2-arent-used

Mevcut halka nasıl belirlenir?

Geçerli halka aşağıdakilerden oluşan bir kombinasyonla seçilir:

  • genel tanımlayıcı tablosu: GDT girişlerinin bellekteki bir tablosu ve her girişin Privlhalkayı kodlayan bir alanı vardır.

    LGDT talimatı adresi geçerli tanımlayıcı tablosuna ayarlar.

    Ayrıca bakınız: http://wiki.osdev.org/Global_Descriptor_Table

  • segment, GDT’deki bir girişin dizinine işaret eden CS, DS, vb. kaydeder.

    Örneğin CS = 0, GDT'nin ilk girişinin yürütme kodu için şu anda aktif olduğu anlamına gelir.

Her halka ne yapabilir?

İşlemci yongası fiziksel olarak şöyle yapılır:

  • 0 halkası her şeyi yapabilir

  • 3. halka, çok sayıda komut çalıştıramaz ve en önemlisi birkaç kayıt listesine yazamaz:

    • kendi yüzüğünü değiştiremez! Aksi takdirde, 0 çalmaya ayarlanmış ve yüzükler işe yaramaz.

      Başka bir deyişle, geçerli halkayı belirleyen mevcut segment tanımlayıcısını değiştiremezsiniz .

    • sayfa tablolarını değiştiremiyorum: https://stackoverflow.com/questions/18431261/how-does-x86-paging-work

      Başka bir deyişle, CR3 kaydını değiştiremez ve sayfalamanın kendisi sayfa tablolarının değiştirilmesini önler.

      Bu, bir işlemin güvenlik / programlama kolaylığı açısından diğer işlemlerin belleğini görmesini önler.

    • kesme işleyicilerini kaydedemiyorum. Bunlar, disk belleği tarafından da engellenen bellek konumlarına yazılarak yapılandırılır.

      İşleyiciler 0 halkasında çalıştırılır ve güvenlik modelini bozar.

      Başka bir deyişle, LGDT ve LIDT talimatlarını kullanamazsınız.

    • inve benzeri IO komutlarını yapamaz outve bu nedenle isteğe bağlı donanım erişimine sahip olur.

      Aksi takdirde, örneğin, herhangi bir program doğrudan diskten okuyabiliyorsa, dosya izinleri kullanılamaz.

      Daha doğrusu Michael Petch sayesinde : OS'nin halka 3'teki IO talimatlarına izin vermesi aslında mümkün, bu aslında Görev durumu segmenti tarafından kontrol ediliyor .

      Mümkün değil, halka 3'ün ilk etapta olmasaydı, buna izin vermesidir.

      Linux her zaman buna izin vermez. Ayrıca bakınız: https://stackoverflow.com/questions/2711044/why-doesnt-linux-use-the-hardware-context-switch-via-the-ts

Programlar ve işletim sistemleri halkalar arasında nasıl geçiş yapar?

  • CPU açıldığında, ilk programı 0 halkasında çalıştırmaya başlar (iyi, ancak bu iyi bir yaklaşımdır). Bu başlangıç ​​programının çekirdek olduğunu düşünebilirsiniz (ancak normalde çekirdek hala 0 halkasında olan bir önyükleyicidir).

  • Bir kullanıcı alanı süreci, çekirdeğin bir dosyaya yazmak gibi bir şey yapmasını istediğinde, çekirdeği işaret etmek int 0x80veyasyscall kesmek gibi bir kesinti oluşturan bir komut kullanır . x86-64 Linux sistem çağrısı merhaba dünya örneği:

    .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
    

    derleyin ve çalıştırın:

    as -o hello_world.o hello_world.S
    ld -o hello_world.out hello_world.o
    ./hello_world.out
    

    GitHub yukarı akış .

    Bu olduğunda, CPU, çekirdeğin önyükleme sırasında kayıtlı olduğu bir kesme geri çağrı işleyicisini çağırır. İşte bir işleyiciyi kaydeden ve kullanan somut bir yardımcı örnek .

    Bu işleyici, 0 halkasında çalışır; bu, çekirdeğin bu eyleme izin verip vermeyeceğine, eylemi gerçekleştirip kullanıcı halkası programını 3. halkada yeniden başlatıp başlatmayacağına karar verir. X86_64

  • zaman execsistem çağrısı kullanılır (veya çekirdek zaman başlar/init ), çekirdek kaydeder ve hafıza hazırlar yeni kullanım alanı işleminin, o zaman giriş noktası atlar ve 3 halka CPU anahtarları

  • Program yasaklanmış bir sicile veya hafıza adresine (çağrı nedeniyle) yazmaya yaramaz bir şey yapmaya çalışırsa, CPU ayrıca 0 halkasında bazı çekirdek geri çağırma işleyicisini çağırır.

    Ancak kullanıcı yaramaz olduğu için, çekirdek bu kez süreci öldürebilir ya da bir işaret ile uyarı verebilir.

  • Çekirdek önyüklendiğinde, belirli aralıklarla kesilen bazı sabit frekanslı bir donanım saati ayarlar.

    Bu donanım saati, 0 halkasını çalıştıran kesintileri üretir ve hangi kullanıcı alanını uyandırmak için programlamasına izin verir.

    Bu yolla, süreçler herhangi bir sistem çağrısı yapmasa bile zamanlama gerçekleşebilir.

Çoklu halkalara sahip olmanın amacı nedir?

Çekirdeği ve kullanıcı alanını ayırmanın iki büyük avantajı vardır:

  • Birisinin diğerini etkilemeyeceğinden emin olduğunuz için programlar yapmak daha kolaydır. Örneğin, bir kullanıcı süreci, çağrı nedeniyle başka bir programın belleğinin üzerine yazmaktan veya başka bir işlem için donanımı geçersiz duruma getirmek konusunda endişelenmek zorunda değildir.
  • daha güvenli. Örneğin, dosya izinleri ve hafıza ayrımı, bilgisayar korsanlığı uygulamalarının banka verilerinizi okumasını engelleyebilir. Bu, elbette, çekirdeğe güvendiğinizi varsayar.

Bununla nasıl oynanır?

Doğrudan halkaları işlemek için iyi bir yol olması gereken çıplak bir metal kurulum oluşturdum: https://github.com/cirosantilli/x86-bare-metal-examples

Ne yazık ki bir kullanıcı örneği örneği verme sabrım yoktu, ancak çağrı kurulumuna kadar gittim, bu yüzden kullanıcı alanı uygulanabilir olmalıdır. Çekme isteği görmek isterim.

Alternatif olarak, Linux çekirdek modülleri 0 halkasında çalışır, bu nedenle ayrıcalıklı işlemleri denemek için kullanabilirsiniz, örneğin kontrol kayıtlarını oku: https://stackoverflow.com/questions/7415515/how-to-access-the-control-registers -cr0-CR2-cr3-dan-bir-program alma-segmenta / 7419306 # 7419306

İşte sunucunuzu öldürmeden denemek için uygun bir QEMU + Buildroot kurulumu .

Çekirdek modüllerinin dezavantajı, diğer taban çizgilerinin çalışıyor olması ve denemenizi engelleyebilmesidir. Fakat teoride, çekirdek modülünüzle tüm kesme işleyicilerini devralabilir ve sistemin sahibi olabilirsiniz, bu aslında ilginç bir proje olacaktır.

Negatif halkalar

Negatif zil sesleri aslında Intel el kitabında referans gösterilmese de, Zil halkasının 0'dan daha fazla özelliğe sahip CPU modları vardır ve bu nedenle "negatif zil" adı için iyi bir seçimdir.

Bir örnek sanallaştırmada kullanılan hiper yönetici modudur.

Daha fazla ayrıntı için bakınız: https://security.stackexchange.com/questions/129098/what-is-protection-ring-1

KOL

ARM'de, halkalara bunun yerine İstisna Seviyeleri denir, ancak ana fikirler aynı kalır.

ARMv8'de yaygın olarak kullanılan 4 istisna seviyesi vardır:

  • EL0: kullanıcı ülkesi

  • EL1: çekirdek (ARM terminolojisinde "denetleyici").

    Linux sistem çağrıları yapmak için kullanılan talimat olan svc, daha swi önce birleşik birleştirme olarak bilinen talimatla (SuperVisor Call) girildi . Merhaba dünya ARMv8 örneği:

    .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 yukarı akış .

    Ubuntu 16.04'teki QEMU ile test edin:

    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
    

    İşte bir SVC işleyicisini kaydeden ve bir SVC çağrısı yapan somut bir yardımcı örnek .

  • EL2: hipervizörler , örneğin Xen .

    hvcTalimatla girildi (HyperVisor Call).

    Bir hipervizör bir işletim sistemine, bir işletim sisteminin kullanıcı alanına göre ne olduğunu.

    Örneğin, Xen, aynı sistemde aynı anda Linux veya Windows gibi birden fazla işletim sistemi çalıştırmanıza izin verir ve işletim sistemlerini, Linux'un kullanıcı programları için yaptığı gibi güvenlik ve hata ayıklama kolaylığı için birbirinden ayırır.

    Hiper yöneticiler bugünün bulut altyapısının önemli bir parçasıdır: birden fazla sunucunun tek bir donanımda çalışmasına izin verir, donanım kullanımını her zaman% 100'e yakın tutar ve çok para tasarrufu sağlar.

    Örneğin AWS, KVM'ye taşınması haberi yaptığında 2017 yılına kadar Xen'i kullandı .

  • EL3: başka bir seviye. TODO örneği.

    smcTalimatla girildi (Güvenli Mod Araması)

ARMv8 Mimarlık Referans Modeli DDI 0487C.a - Bölüm D1 - AArch64 Sistemi Seviye Programcı Modeli - Şekil D1-1 güzelce bunu göstermektedir:

görüntü tanımını buraya girin

ARM, rüzgârın yararına bağlı olarak, ayrıcalık seviyeleri için x86'dan daha iyi bir adlandırma kuralına sahip olduğunu, negatif seviyelere ihtiyaç duyulmadığını unutmayın: 0 düşük ve 3 en yüksek. Yüksek seviyeler düşük seviyelerden daha sık yaratılma eğilimindedir.

Mevcut EL MRStalimatı ile sorgulanabilir : https://stackoverflow.com/questions/31787617/what-is-the-current-execution-mode-exception-level-etc

ARM, çip alanından tasarruf etme özelliğine ihtiyaç duymayan uygulamalara izin vermek için tüm istisna seviyelerinin bulunmasını gerektirmez. ARMv8 "İstisna seviyeleri" diyor:

Bir uygulama, İstisna seviyelerinin tümünü içermeyebilir. Tüm uygulamalar EL0 ve EL1'i içermelidir. EL2 ve EL3 isteğe bağlıdır.

Örneğin, QEMU EL1'e varsayılandır, ancak EL2 ve EL3 komut satırı seçenekleriyle etkinleştirilebilir: https://stackoverflow.com/questions/42824706/qemu-system-aarch64-entering-el1-wulating-emulating-a53-power-up

Ubuntu 18.10'da test edilen kod parçacıkları.


3

İlki ise normal kullanıcı programının 3GB'tan fazla belleğe sahip olamayacağı anlamına mı geliyor (bölme 3GB + 1GB ise)?

Evet, normal bir linux sistemde böyledir. Kullanıcının ve çekirdeğin adres alanlarını tamamen bağımsız yapan bir noktada dolaşan bir dizi "4G / 4G" yaması vardı (performans maliyetiyle çekirdeğin kullanıcı hafızasına erişmesini zorlaştırdığı için) şimdiye kadar yukarı akışta birleştirildiler ve ilgi, x86-64'ün yükselişiyle azaldı

Ayrıca, bu durumda, çekirdek yüksek belleği nasıl kullanır, çünkü hangi sanal bellek adresinin yüksek bellekten gelen sayfaları eşleştirileceği, 1GB çekirdek alanı mantıksal olarak eşleneceği için?

Linux'un çalışma şekli (ve hafızanın adres alanına göre daha küçük olduğu sistemlerde de geçerlidir) fiziksel belleğin tamamının kalıcı olarak adres alanının çekirdek kısmına eşleştirilmesiydi. Bu, çekirdeğin yeniden boyutlandırma olmadan tüm fiziksel belleğe erişmesine izin verdi, ancak açıkça çok fazla fiziksel belleğe sahip 32 bit makinelere ölçeklenemedi.

Böylece düşük ve yüksek hafıza kavramı doğdu. "Düşük" bellek sürekli olarak çekirdek adres alanına eşleştirilir. "yüksek" hafıza değil.

İşlemci bir sistem çağrısı çalıştırırken, çekirdek modunda çalışıyor ancak yine de geçerli işlem bağlamında çalışıyor. Böylece, hem çekirdek adres alanına hem de geçerli işlemin kullanıcı adres alanına doğrudan erişebilir (yukarıda belirtilen 4G / 4G yamaları kullanmıyorsunuzdur). Bu, "yüksek" belleğin bir kullanıcı işlemine tahsis edilmesinin sorun olmadığı anlamına gelir.

Çekirdek amacıyla "yüksek" bellek kullanılması daha fazla sorun yaratır. Geçerli işlemle eşlenmemiş yüksek belleğe erişmek için, geçici olarak çekirdeğin adres alanına eşlenmelidir. Bu ekstra kod ve performans cezası anlamına gelir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.