Qual è la differenza tra le modalità utente e kernel nei sistemi operativi?


104

Quali sono le differenze tra la modalità utente e la modalità kernel, perché e come si attivano entrambe e quali sono i casi d'uso?



1
@ CiroSantilli709 大 抓捕 六四 事件 法轮功 una domanda che è stata posta 7 anni fa non può essere chiusa come duplicato di una domanda posta 6 anni fa. Se sono davvero duplicati, la chiusura dovrebbe avvenire in un altro modo.
Salvador Dali

2
@SalvadorDali ciao, il consenso attuale è chiudere per "qualità": meta.stackexchange.com/questions/147643/… Poiché la "qualità" non è misurabile, vado solo per voti positivi. ;-) Probabilmente dipende da quale domanda ha colpito le migliori nuove parole chiave di Google nel titolo. Ti incoraggio a copiare semplicemente la tua risposta lì con un disclaimer aggiunto in fondo e un collegamento da questo, nel caso in cui si chiuda.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Risposte:


143
  1. Modalità kernel

    In modalità kernel, il codice in esecuzione ha accesso completo e illimitato all'hardware sottostante. Può eseguire qualsiasi istruzione della CPU e fare riferimento a qualsiasi indirizzo di memoria. La modalità kernel è generalmente riservata alle funzioni di livello più basso e più affidabili del sistema operativo. Gli arresti anomali in modalità kernel sono catastrofici; interromperanno l'intero PC.

  2. Modalità utente

    In modalità Utente, il codice in esecuzione non è in grado di accedere direttamente all'hardware o alla memoria di riferimento. Il codice in esecuzione in modalità utente deve delegare alle API di sistema per accedere all'hardware o alla memoria. A causa della protezione offerta da questo tipo di isolamento, i crash in modalità utente sono sempre recuperabili. La maggior parte del codice in esecuzione sul computer verrà eseguita in modalità utente.

Leggi di più

Comprensione della modalità utente e kernel


Mi chiedo quando la CPU esegue il codice del sistema operativo, in quale modalità si trova il processore?
JackieLam

2
@ JackieLam: dovrebbe essere in modalità kernel.
kadina

Quindi di per sé, per eseguire un processo dello spazio utente , deve essere mappato allo spazio del kernel ?
roottraveller

@rahul Dubito che la memoria di riferimento possa essere ottenuta in modalità utente o che la più semplice manipolazione dei dati comporterà un costoso cambio di modalità in un linguaggio come java.
maki XIE

48

Queste sono due diverse modalità in cui il computer può funzionare. Prima di questo, quando i computer erano come una grande stanza, se qualcosa va in crash, si ferma l'intero computer. Così gli architetti informatici decidono di cambiarlo. I microprocessori moderni implementano nell'hardware almeno 2 stati diversi.

Modalità utente:

  • modalità in cui vengono eseguiti tutti i programmi utente. Non ha accesso alla RAM e all'hardware. Il motivo è che se tutti i programmi fossero eseguiti in modalità kernel, sarebbero in grado di sovrascrivere la memoria a vicenda. Se deve accedere a una di queste funzionalità, effettua una chiamata all'API sottostante. Ogni processo avviato da Windows ad eccezione del processo di sistema viene eseguito in modalità utente.

Modalità kernel:

  • modalità in cui vengono eseguiti tutti i programmi del kernel (driver diversi). Ha accesso a ogni risorsa e hardware sottostante. È possibile eseguire qualsiasi istruzione della CPU ed è possibile accedere a ogni indirizzo di memoria. Questa modalità è riservata ai conducenti che operano al livello più basso

Come avviene il passaggio.

Il passaggio dalla modalità utente alla modalità kernel non viene eseguito automaticamente dalla CPU. La CPU è interrotta da interrupt (timer, tastiera, I / O). Quando si verifica l'interrupt, la CPU interrompe l'esecuzione del programma in esecuzione, passa alla modalità kernel, esegue il gestore degli interrupt. Questo gestore salva lo stato della CPU, esegue le sue operazioni, ripristina lo stato e torna in modalità utente.

http://en.wikibooks.org/wiki/Windows_Programming/User_Mode_vs_Kernel_Mode

http://tldp.org/HOWTO/KernelAnalysis-HOWTO-3.html

http://en.wikipedia.org/wiki/Direct_memory_access

http://en.wikipedia.org/wiki/Interrupt_request


Mi chiedo quando la CPU esegue il codice del sistema operativo, in quale modalità si trova il processore?
JackieLam

1
@JackieLam: modalità kernel
Apurv Nerlekar

10

Un processore in un computer che esegue Windows ha due diverse modalità: modalità utente e modalità kernel. Il processore passa da una modalità all'altra a seconda del tipo di codice in esecuzione sul processore. Le applicazioni vengono eseguite in modalità utente e i componenti principali del sistema operativo vengono eseguiti in modalità kernel. Sebbene molti driver vengano eseguiti in modalità kernel, alcuni driver potrebbero essere eseguiti in modalità utente.

Quando si avvia un'applicazione in modalità utente, Windows crea un processo per l'applicazione. Il processo fornisce all'applicazione uno spazio di indirizzi virtuali privati ​​e una tabella handle privata. Poiché lo spazio degli indirizzi virtuali di un'applicazione è privato, un'applicazione non può modificare i dati che appartengono a un'altra applicazione. Ogni applicazione viene eseguita in isolamento e, se un'applicazione si blocca, l'arresto è limitato a quell'unica applicazione. Altre applicazioni e il sistema operativo non sono interessati dal crash.

Oltre ad essere privato, lo spazio degli indirizzi virtuali di un'applicazione in modalità utente è limitato. Un processore in esecuzione in modalità utente non può accedere agli indirizzi virtuali riservati per il sistema operativo. La limitazione dello spazio degli indirizzi virtuali di un'applicazione in modalità utente impedisce all'applicazione di alterare e possibilmente danneggiare i dati critici del sistema operativo.

Tutto il codice eseguito in modalità kernel condivide un singolo spazio di indirizzi virtuali. Ciò significa che un driver in modalità kernel non è isolato dagli altri driver e dal sistema operativo stesso. Se un driver in modalità kernel scrive accidentalmente nell'indirizzo virtuale sbagliato, i dati che appartengono al sistema operativo o un altro driver potrebbero essere compromessi. Se un driver in modalità kernel si blocca, l'intero sistema operativo si blocca.

Se sei un utente Windows una volta passato questo link ne otterrai di più.

Comunicazione tra modalità utente e modalità kernel


6

Gli anelli della CPU sono la distinzione più chiara

In modalità protetta x86, la CPU è sempre in uno dei 4 anelli. Il kernel Linux usa solo 0 e 3:

  • 0 per il kernel
  • 3 per gli utenti

Questa è la definizione più difficile e veloce di kernel vs userland.

Perché Linux non usa gli anelli 1 e 2: CPU Privilege Rings: Perché gli anelli 1 e 2 non vengono usati?

Come viene determinato l'anello attuale?

L'anello corrente viene selezionato da una combinazione di:

  • tabella descrittore globale: una tabella in memoria delle voci GDT e ogni voce ha un campo Privlche codifica l'anello.

    L'istruzione LGDT imposta l'indirizzo sulla tabella descrittiva corrente.

    Vedi anche: http://wiki.osdev.org/Global_Descriptor_Table

  • il segmento registra CS, DS, ecc., che puntano all'indice di una voce nella GDT.

    Ad esempio, CS = 0significa che la prima voce del GDT è attualmente attiva per il codice in esecuzione.

Cosa può fare ogni anello?

Il chip della CPU è costruito fisicamente in modo che:

  • l'anello 0 può fare qualsiasi cosa

  • ring 3 non può eseguire diverse istruzioni e scrivere su diversi registri, in particolare:

    • non può cambiare il proprio anello! Altrimenti, potrebbe impostarsi sull'anello 0 e gli squilli sarebbero inutili.

      In altre parole, non è possibile modificare il descrittore di segmento corrente , che determina l'anello corrente.

    • non è possibile modificare le tabelle delle pagine: come funziona la paginazione x86?

      In altre parole, non è possibile modificare il registro CR3 e il paging stesso impedisce la modifica delle tabelle delle pagine.

      Ciò impedisce a un processo di vedere la memoria di altri processi per motivi di sicurezza / facilità di programmazione.

    • Impossibile registrare gestori di interrupt. Questi vengono configurati scrivendo nelle posizioni di memoria, che viene anche impedito dal paging.

      I gestori vengono eseguiti nell'anello 0 e violerebbero il modello di sicurezza.

      In altre parole, non è possibile utilizzare le istruzioni LGDT e LIDT.

    • non può eseguire istruzioni I / O come ine out, e quindi avere accessi hardware arbitrari.

      Altrimenti, ad esempio, i permessi sui file sarebbero inutili se qualsiasi programma potesse leggere direttamente dal disco.

      Più precisamente grazie a Michael Petch : è effettivamente possibile per il sistema operativo consentire istruzioni IO sull'anello 3, questo è effettivamente controllato dal segmento di stato del task .

      Ciò che non è possibile è che l'anello 3 si dia il permesso di farlo se non lo aveva in primo luogo.

      Linux lo disabilita sempre. Vedi anche: Perché Linux non usa il cambio di contesto hardware tramite TSS?

In che modo i programmi e i sistemi operativi passano tra gli anelli?

  • quando la CPU è accesa, inizia a eseguire il programma iniziale nell'anello 0 (beh, ma è una buona approssimazione). Puoi pensare che questo programma iniziale sia il kernel (ma normalmente è un bootloader che poi chiama il kernel ancora nell'anello 0 ).

  • quando un processo userland vuole che il kernel faccia qualcosa come scrivere su un file, usa un'istruzione che genera un interrupt come int 0x80osyscall per segnalare il kernel. x86-64 Linux syscall hello world esempio:

    .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
    

    compila ed esegui:

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

    GitHub a monte .

    Quando ciò accade, la CPU chiama un gestore di callback di interrupt che il kernel ha registrato al momento dell'avvio. Ecco un esempio di metallo nudo concreto che registra un gestore e lo utilizza .

    Questo gestore viene eseguito nell'anello 0, che decide se il kernel consentirà questa azione, eseguirà l'azione e riavvierà il programma userland nell'anello 3. x86_64

  • quando execviene utilizzata la chiamata di sistema (o quando il kernel verrà avviato/init ), il kernel prepara i registri e la memoria del nuovo processo userland, quindi salta al punto di ingresso e commuta la CPU sull'anello 3

  • Se il programma cerca di fare qualcosa di cattivo come scrivere su un registro proibito o un indirizzo di memoria (a causa del paging), la CPU chiama anche un gestore di callback del kernel nell'anello 0.

    Ma poiché la userland era cattiva, questa volta il kernel potrebbe interrompere il processo o dargli un avviso con un segnale.

  • Quando il kernel si avvia, imposta un orologio hardware con una frequenza fissa, che genera periodicamente interruzioni.

    Questo orologio hardware genera interrupt che eseguono l'anello 0 e gli consentono di programmare quali processi userland riattivare.

    In questo modo, la pianificazione può avvenire anche se i processi non stanno effettuando alcuna chiamata di sistema.

Qual è il punto di avere più squilli?

Ci sono due principali vantaggi nel separare kernel e userland:

  • è più facile creare programmi poiché sei più certo che uno non interferirà con l'altro. Ad esempio, un processo userland non deve preoccuparsi di sovrascrivere la memoria di un altro programma a causa del paging, né di mettere l'hardware in uno stato non valido per un altro processo.
  • è più sicuro. Ad esempio, i permessi dei file e la separazione della memoria potrebbero impedire a un'app di hacking di leggere i tuoi dati bancari. Ciò presuppone, ovviamente, che ti fidi del kernel.

Come giocarci?

Ho creato una configurazione bare metal che dovrebbe essere un buon modo per manipolare direttamente gli anelli: https://github.com/cirosantilli/x86-bare-metal-examples

Sfortunatamente non ho avuto la pazienza di fare un esempio di userland, ma sono arrivato fino alla configurazione del paging, quindi userland dovrebbe essere fattibile. Mi piacerebbe vedere una richiesta di pull.

In alternativa, i moduli del kernel Linux vengono eseguiti nell'anello 0, quindi puoi utilizzarli per provare operazioni privilegiate, ad esempio leggere i registri di controllo: Come accedere ai registri di controllo cr0, cr2, cr3 da un programma? Ottenere l'errore di segmentazione

Ecco una comoda configurazione QEMU + Buildroot per provarlo senza uccidere il tuo host.

Lo svantaggio dei moduli del kernel è che altri kthread sono in esecuzione e potrebbero interferire con i tuoi esperimenti. Ma in teoria puoi prendere il controllo di tutti i gestori di interrupt con il tuo modulo del kernel e possedere il sistema, in realtà sarebbe un progetto interessante.

Anelli negativi

Sebbene gli anelli negativi non siano effettivamente citati nel manuale Intel, in realtà ci sono modalità CPU che hanno ulteriori capacità rispetto allo stesso anello 0, e quindi si adattano bene al nome "anello negativo".

Un esempio è la modalità hypervisor utilizzata nella virtualizzazione.

Per ulteriori dettagli vedere:

BRACCIO

In ARM, gli anelli sono invece chiamati livelli di eccezione, ma le idee principali rimangono le stesse.

Esistono 4 livelli di eccezione in ARMv8, comunemente usati come:

  • EL0: userland

  • EL1: kernel ("supervisore" nella terminologia ARM).

    Inserito con l' svcistruzione (SuperVisor Call), precedentemente nota come swi prima dell'assemblaggio unificato , che è l'istruzione utilizzata per effettuare chiamate di sistema Linux. Hello world esempio ARMv8:

    hello.s

    .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 a monte .

    Provalo con QEMU su 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
    

    Ecco un esempio di metallo nudo concreto che registra un gestore SVC e fa una chiamata SVC .

  • EL2: hypervisor , ad esempio Xen .

    Inserito con l' hvcistruzione (HyperVisor Call).

    Un hypervisor sta a un sistema operativo, ciò che un sistema operativo sta a userland.

    Ad esempio, Xen consente di eseguire più sistemi operativi come Linux o Windows sullo stesso sistema contemporaneamente e isola i sistemi operativi l'uno dall'altro per sicurezza e facilità di debug, proprio come fa Linux per i programmi userland.

    Gli hypervisor sono una parte fondamentale dell'attuale infrastruttura cloud: consentono a più server di funzionare su un singolo hardware, mantenendo l'utilizzo dell'hardware sempre vicino al 100% e risparmiando un sacco di soldi.

    AWS, ad esempio, ha utilizzato Xen fino al 2017, quando il suo passaggio a KVM ha fatto notizia .

  • EL3: ancora un altro livello. TODO esempio.

    Entrato con l' smcistruzione (Secure Mode Call)

Il modello di riferimento dell'architettura ARMv8 DDI 0487C.a - Capitolo D1 - Il modello del programmatore a livello di sistema AArch64 - La Figura D1-1 lo illustra magnificamente:

inserisci qui la descrizione dell'immagine

La situazione ARM è leggermente cambiata con l'avvento di ARMv8.1 Virtualization Host Extensions (VHE) . Questa estensione consente al kernel di funzionare in EL2 in modo efficiente:

inserisci qui la descrizione dell'immagine

VHE è stato creato perché le soluzioni di virtualizzazione del kernel Linux come KVM hanno guadagnato terreno su Xen (vedi ad esempio il passaggio di AWS a KVM menzionato sopra), perché la maggior parte dei client necessita solo di VM Linux e, come puoi immaginare, è tutto in un unico progetto, KVM è più semplice e potenzialmente più efficiente di Xen. Quindi ora il kernel Linux host funge da hypervisor in quei casi.

Nota come ARM, forse per il vantaggio del senno di poi, ha una convenzione di denominazione migliore per i livelli di privilegio rispetto a x86, senza la necessità di livelli negativi: 0 è il più basso e 3 il più alto. I livelli più alti tendono ad essere creati più spesso di quelli inferiori.

L'attuale EL può essere interrogato con l' MRSistruzione: qual è l'attuale modalità di esecuzione / livello di eccezione, ecc.?

ARM non richiede la presenza di tutti i livelli di eccezione per consentire implementazioni che non richiedono la funzionalità per salvare l'area del chip. ARMv8 "Livelli di eccezione" dice:

Un'implementazione potrebbe non includere tutti i livelli di eccezione. Tutte le implementazioni devono includere EL0 e EL1. EL2 e EL3 sono opzionali.

QEMU, ad esempio, è predefinito su EL1, ma EL2 ed EL3 possono essere abilitati con le opzioni della riga di comando: qemu-system-aarch64 inserendo el1 durante l'emulazione di a53 all'accensione

Snippet di codice testati su Ubuntu 18.10.


1
Poiché questa domanda non è specifica per alcun sistema operativo ine outsono disponibili per squillare 3. Il TSS può puntare a una tabella dei permessi di I / O nell'attività corrente che concede l'accesso in lettura / scrittura a tutte o porte specifiche.
Michael Petch

Ovviamente si impostano i bit IOPL sul valore 3, quindi il programma ring 3 ha accesso completo alla porta e le autorizzazioni TSS IO non si applicano.
Michael Petch

@MichaelPetch grazie, non lo sapevo. Ho aggiornato la risposta.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

5

Prenderò una pugnalata al buio e immagino che tu stia parlando di Windows. In poche parole, la modalità kernel ha pieno accesso all'hardware, ma la modalità utente no. Ad esempio, molti se non la maggior parte dei driver di dispositivo sono scritti in modalità kernel perché hanno bisogno di controllare i dettagli più fini del loro hardware.

Vedi anche questo wikibook .


2
Questo è importante per te come programmatore perché i bug del kernel tendono a provocare danni molto peggiori di quelli a cui potresti essere abituato. Uno dei motivi per la distinzione kernel / utente è che il kernel può monitorare / controllare le risorse di sistema critiche e proteggere ogni utente dagli altri. È un po 'troppo semplificato, ma comunque utile, ricordare a te stesso che i bug degli utenti sono spesso fastidiosi, ma i bug del kernel tendono a far cadere l'intera macchina.
Adam Liss

3

Altre risposte hanno già spiegato la differenza tra modalità utente e modalità kernel. Se vuoi davvero entrare nei dettagli dovresti procurarti una copia di Windows Internals , un ottimo libro scritto da Mark Russinovich e David Solomon che descrive l'architettura ei dettagli interni dei vari sistemi operativi Windows.


2

Che cosa

Fondamentalmente la differenza tra le modalità kernel e utente non dipende dal sistema operativo e si ottiene solo limitando l'esecuzione di alcune istruzioni solo in modalità kernel tramite la progettazione hardware. Tutti gli altri scopi, come la protezione della memoria, possono essere eseguiti solo con tale restrizione.

Come

Significa che il processore vive in modalità kernel o in modalità utente. Utilizzando alcuni meccanismi, l'architettura può garantire che ogni volta che si passa alla modalità kernel il codice del sistema operativo viene recuperato per essere eseguito.

Perché

Avendo questa infrastruttura hardware, questi potrebbero essere raggiunti in sistemi operativi comuni:

  • Proteggere i programmi utente dall'accesso a tutta la memoria, per evitare che i programmi sovrascrivano il sistema operativo, ad esempio,
  • impedire ai programmi utente di eseguire istruzioni sensibili come quelle che modificano i limiti del puntatore di memoria della CPU, per non lasciare che i programmi interrompano i loro limiti di memoria, ad esempio.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.