Come avviene il bootstrap di un PC

PC bootstrap

Nella terminologia informatica, e più precisamente nell’ambito dei sistemi operativi, il termine bootstrap identifica l’operazione a seguito della quale almeno una parte del sistema operativo viene trasferita in memoria, per poi essere eseguita dal microprocessore.

Quest’operazione include anche l’inizializzazione delle strutture dati del kernel, la creazione di alcuni processi utente, ed il trasferimento del controllo ad uno di essi. Il bootstrap è un’attività lunga e relativamente complessa, dal momento che coinvolge buona parte dell’hardware (inclusa la memoria RAM) che inizialmente si trova in uno stato non definito. Proprio per questo motivo il bootstrap è fortemente dipendente dal tipo di architettura hardware, e nel corso dell’articolo si farà riferimento ad una delle architetture più diffuse, e ancor oggi utilizzate, vale a dire l’architettura dei tradizionali PC IBM.

Ma cosa avviene esattamente, a livello di microprocessore, quando premiamo il tasto di accensione di un PC? Vediamo di scoprirlo insieme. Anzitutto occorre dire che i PC con architettura IBM si sono largamente evoluti nel corso degli anni, mantenendo però una sorta di compatibilità all’indietro (backward compatibility), vale a dire che i processori di ultima generazione sono in realtà in grado di eseguire il codice come i suoi più vecchi predecessori, ed in particolare il famoso Intel 8086, che ha dato origine all’architettura Intel x86 tuttora in voga. Questa compatibilità si concretizza proprio nella fase di bootstrap, cioè quando il sistema viene fatto (ri)partire.

Qualcuno potrebbe obiettare che i processori attuali si basano su un’architettura multi-core, mentre l’architettura originale IBM era necessariamente single-core. Per quanto concerne la fase di bootstrap, comunque, non esiste alcuna differenza: nel caso di processore multi-core, infatti, una sola CPU viene prescelta, dinamicamente, e soltanto questa eseguirà il bootstrap (viene perciò indicata con il termine BootStrap Processor, o semplicemente BSP), quindi il codice del BIOS ed il codice di inizializzazione del kernel.

I rimanenti processori (denominati Application Processor, o AP), rimangono sospesi fino a quando il kernel li attiverà esplicitamente. Che cos’è il BIOS? Il Basic Input Output System è un insieme di istruzioni (ora vengono allocate su un’unità dedicata di memoria flash, ma in passato risiedevano addirittura su una eprom!) che hanno il compito di identificare ed inizializzare i dispositivi hardware, come la scheda video, tastiera e mouse, hard disk, CD/DVD, ed altri dispositivi, e consentire il caricamento del sistema operativo.

In origine (ai tempi del sistema operativo MS-DOS, per intenderci) il BIOS aveva un’importanza maggiore, in quanto conteneva delle librerie di funzioni per accedere direttamente all’hardware e richiamabili sia dal sistema operativo che dal software applicativo (le famose BIOS-call). Col tempo questa funzione è venuta meno, ed oggi l’accesso all’hardware viene eseguito direttamente dai drivers inclusi nel sistema operativo. Durante questa fase di avvio, il processore lavora in real mode, con la paginazione della memoria disabilitata. Ciò significa che lo spazio di indirizzamento visto dal processore è perfettamente lineare ed è rappresentato su 20 bit, per un totale quindi di 1Mb di memoria disponibile la quale può includere memoria RAM, ROM, memoria video, periferiche di I/O, ecc.

Per tradizione di progetto, i processori Intel dopo il reset puntano sempre all’indirizzo 0xFFFFFFF0, al di fuori quindi del primo Mb visibile dal BIOS; sarà perciò cura di chi ha fabbricato l’hardware su cui gira il processore (scheda madre o scheda embedded custom) far sì che a questo indirizzo venga "cablata" un’istruzione di salto (jump) all’entry point nel BIOS. Semplice, no? Ricordiamo che in real-mode l’indirizzo è composto da una parte segmento (seg) e una parte offset (off), che assieme formano l’indirizzo fisico secondo la formula:

indirizzo fisico = 16 x seg + off

Si faccia riferimento all’immagine seguente nella quale vengono evidenziate le aree di memoria interessate dal BIOS. Una volta avviato, il BIOS comincia ad eseguire una prima inizializzazione dei componenti hardware essenziali, dopodichè avvia un apposito programma diagnostico, denominato POST (Power On Self Test) che esegue il test di vari componenti hardware. In sostanza il POST rileva la presenza dei componenti hardware di base e si accerta del loro funzionamento.

Eseguito il POST, il BIOS ha il compito successivo di caricare il sistema operativo, che a priori può essere su uno qualunque dei dispositivi di memoria di massa disponibili. Questi ultimi vengono quindi scanditi sequenzialmente (secondo un ordine configurabile tramite l’apposita interfaccia grafica del BIOS) fino a trovare il primo dispositivo in grado di eseguire il boot (in caso ciò non avvenga viene segnalato il tipico errore "Non-System Disk or Disk Error". A questo punto il BIOS comincia a leggere il settore 0 (il primo settore) del disco o unità di memoria di massa (un settore corrisponde a 512 byte), chiamato anche Master Boot Record (MBR).

Il contenuto dell’MBR viene quindi copiato in memoria all’indirizzo fisso 0x00007c00 ed il controllo di programma viene trasferito a questo indirizzo (attraverso un’istruzione di jump) per eseguire il codice contenuto nell’MBR stesso. L’MBR comprende al suo interno anche un’area con una partition table di 64 byte, con 4 entry da 16 byte ciascuna. E’ così possibile mettere in esecuzione uno tra più sistemi operativi: nel caso ciò avvenga, il codice dell’MBR trasferisce il controllo al boot sector associato alla partizione selezionata, cioè il primo settore della partizione stessa.

I due bootloader più diffusi di Linux (Lilo e GRUB) possono vantare molte funzionalità, consentendo non solo di eseguire più sistmei operativi, ma gestiscono anche diversi filesystem e configurazioni di boot. A questo punto il bootloader può startare il kernel, cioè leggere dalla partizione di boot l’immagine del kernel (ad esempio "vmlinuz-2.6.22-14-server" in Linux, oppure "NTLDR" su molte versioni di windows) caricarla in memoria ed eseguirla. A questo proposito c’è un aspetto curioso: l’immagine del kernel (anche se compressa come avviene in Linux) va ben al di là dei 640 Kb di memoria RAM disponibile in real-mode, per cui come è possibile caricarla?

A questo proposito si sfrutta una tecnica messa a disposizione dai progettisti Intel e largamente utilizzata nei videogiochi dei primi anni ’90: la modalità "unreal mode". Con questa modalità il processore può ancora eseguire il codice del BIOS (tra cui le importantissime funzioni di disk I/O) ma può anche accedere ad una quantità di memoria superiore. In pratica la formula precedente per la determinazione dell’indirizzo è ancoa valida, con la differenza che l’offset può essere caicato anche con dei valori a 32 bit.

Il processore, in pratica, continua a commutare tra le modalità real e protected in modo tale da poter accedere alla memoria sopra 1 MB continuando nel contempo ad eseguire il BIOS. Ora il kernel è stato caricato in memoria, con il processore ancora in real mode. A questo punto il lavoro del boot loader è completato, ed il kernel, che opera invece in protected mode, prende il controllo delle operazioni.

STAMPA     Tags:, , ,

4 Comments

  1. electropower 11 maggio 2011
  2. Giovanni Giomini Figliozzi 11 maggio 2011
  3. Nicolò 11 maggio 2011
  4. FlyTeo 11 maggio 2011

Leave a Reply