libce
Libreria di Calcolatori Elettronici
Caricamento in corso...
Ricerca in corso...
Nessun risultato
Bootstrap da 32 a 64 bit
Diagramma di collaborazione per Bootstrap da 32 a 64 bit:

Topics

 Strutture dati hardware
 

Strutture dati

struct  boot64_segment
 Descrittore di segmento ELF. Continua...
 
struct  boot64_modinfo
 Descrittore di modulo. Continua...
 
struct  boot64_info
 Informazioni dal boot loader. Continua...
 

Definizioni

#define MAX_MODULES   3
 Numero massimo di moduli.
 
#define MAX_SEGMENTS   4
 Numero massimo di segmenti ELF.
 

Funzioni

bool controlla_collisione (boot64_info *info, natq beg, natq end)
 Controlla che un modulo non si sovrapponga a quelli già esistenti.
 
bool decodifica_modulo (multiboot_module_t *mod, boot64_modinfo *info, bool check_align)
 Estrae le informazioni sui moduli.
 
bool carica_modulo (boot64_info *info, paddr mem_tot)
 Carica il primo modulo secondo le indicazioni della sua tabella di programma.
 
static void parse_args (char *cmd)
 Interpreta gli argomenti passati al boot loader.
 
bool crea_finestra_FM (paddr root_tab, paddr mem_tot)
 Mappa la memoria fisica e l'area PCI in memoria virtuale.
 
void main (natl magic, multiboot_info_t *mbi)
 Entry point C++ del boot loader.
 

Variabili

static const int MAXARGS = 10
 Massimo numero di argomenti per il boot loader.
 
static int debug_mode = 0
 Flag settato se è richiesto il collegamento al debugger.
 
volatile int wait_for_gdb
 sincronizzazione con gdb
 
boot64_infoboot_info
 variabile globale in cui _start copia l'indirizzo del boot64_info ricevuto
 
natq tss_punt_nucleo
 variabile globale in cui _start copia l'indirizzo di punt_nucleo nel TSS
 

Descrizione dettagliata

Il boostrap avviene in due stadi.

STADIO 1 (realizzato dal bootloader incluso in QEMU)

Carica in memoria il secondo bootloader e eventuali moduli. Il secondo boot loader deve essere un file ELF e viene caricato agli indirizzi specificati nella sua tabella di programma (normalmente nel secondo MiB), mentre i moduli possono essere file generici e vengono semplicemente copiati in RAM (subito dopo il secondo boot loader). Il primo boot loader porta il processore da modo reale (16 bit) a modo protetto a 32 bit, quindi cede il controllo al secondo boot loader. Passa nel registro EAX una costante che permette al secondo boot loader di capire di essere stato avviato da un boot loader che rispetta lo standard "multiboot". Nel registro EBX passa l'indirizzo di una struttura multiboot_info_t che contiene varie informazioni (memoria RAM installata nel sistema, indirizzi in RAM delle copie dei moduli, ...). La struttura è definita in "mboot.h" in questa directory.

Stato della memoria alla fine dello stadio 1:

STADIO 2 (realizzato da questo programma)

Lo stadio 1 deve aver caricato almeno un modulo e questo modulo deve essere di tipo ELF. Il secondo bootloader interpreta questo modulo e copia i segmenti ELF al loro indirizzo di caricamento (che deve partire dal terzo MiB in poi per non sovrascrivere il boot loader stesso e i moduli). Porta poi la CPU nella modalità a 64 bit e cede il controllo al primo modulo. Passa in EDI il puntatore ad una struttura boot64_info che contiene varie informazioni (in particolare gli indirizzi dei moduli, che si trovano ancora in memoria dove erano stati caricati dal primo boot loader).

Stato della memoria alla fine dello stadio 2:

Documentazione delle funzioni

◆ carica_modulo()

bool carica_modulo ( boot64_info * info,
paddr mem_tot )

Carica il primo modulo secondo le indicazioni della sua tabella di programma.

Parametri
infopuntatore alla struttura che descrive i moduli
mem_totmemoria disponibile

Definizione alla linea 417 del file boot.cpp.

Questo è il grafo delle chiamate per questa funzione:
Questo è il grafo dei chiamanti di questa funzione:

◆ controlla_collisione()

bool controlla_collisione ( boot64_info * info,
natq beg,
natq end )

Controlla che un modulo non si sovrapponga a quelli già esistenti.

Parametri
infopuntatore alla struttura che descrive i moduli
begbase del modulo da controllare
endlimite del modulo da controllare

Definizione alla linea 320 del file boot.cpp.

Questo è il grafo delle chiamate per questa funzione:
Questo è il grafo dei chiamanti di questa funzione:

◆ crea_finestra_FM()

bool crea_finestra_FM ( paddr root_tab,
paddr mem_tot )

Mappa la memoria fisica e l'area PCI in memoria virtuale.

Parametri
root_tabindirizzo fisico della tabella radice
mem_totdimensione della memoria fisica

mappiamo tutta la memoria fisica:

  • a livello sistema (bit U/S non settato)
  • scrivibile (bit R/W settato)
  • con pagine di grandi dimensioni (bit PS) (usiamo pagine di livello 2 che sono sicuramente disponibili)
Nota
vogliamo saltare la prima pagina per intercettare *nullptr, e inoltre vogliamo settare il bit PWT per le pagine che contengono la memoria video. Per farlo dobbiamo rinunciare a settare PS per la prima regione

Mappiamo tutti gli altri indirizzi, fino a 4GiB, settando sia PWT che PCD. Questa zona di indirizzi è utilizzata in particolare dall'APIC per mappare i propri registri.

Definizione alla linea 494 del file boot.cpp.

Questo è il grafo delle chiamate per questa funzione:
Questo è il grafo dei chiamanti di questa funzione:

◆ decodifica_modulo()

bool decodifica_modulo ( multiboot_module_t * mod,
boot64_modinfo * info,
bool check_align )

Estrae le informazioni sui moduli.

Parametri
modpuntatore alla struttura passata dal primo boot loader
infopuntatore alla struttura da riempire
check_alignopzionalmente, controlla che l'allinamento richiesto non sia superiore alla pagina

Estrae le informazioni rilevanti dal modulo ELF e le copia nella struttura boot64_info. In questo modo il modulo successivo (il modulo sistema) non ha bisogno di dover interpretare il formato ELF.

Definizione alla linea 341 del file boot.cpp.

Questo è il grafo delle chiamate per questa funzione:
Questo è il grafo dei chiamanti di questa funzione:

◆ main()

void main ( natl magic,
multiboot_info_t * mbi )

Entry point C++ del boot loader.

Parametri
magiccodice che identifica lo standard multiboot
mbipuntatore alle informazioni passate dal primo bootstrap loader
Nota
L'entry point vero e proprio è _start in boot.s.

Il primo bootstrap loader (in QEMU) attiva il modo protetto (per poter accedere agli indirizzi di memoria principale superiori a 1MiB) e carica il secondo boostrap loader (questo programma) in memoria, quindi salta alla sua prima istruzione. Il primo bootstrap loader può anche passare delle informazioni al secondo (tramite i registri e la memoria).

Il primo loader, prima di saltare alla prima istruzione del secondo (l'entry point specificato nel file eseguibile), lascia nel registro eax un valore di riconoscimento e in ebx l'indirizzo di una struttura dati, contentente varie informazioni (in particolare, la quantità di memoria principale installata nel sistema, il dispositivo da cui è stato eseguito il bootstrap e l'indirizzo di memoria in cui sono stati caricati gli eventuali moduli)

Definizione alla linea 564 del file boot.cpp.

Questo è il grafo delle chiamate per questa funzione:

◆ parse_args()

static void parse_args ( char * cmd)
static

Interpreta gli argomenti passati al boot loader.

Parametri
cmdstringa degli argomenti

Scompone la stringa cmd in argomenti separati da spazi. Al momento comprendiamo un solo argomento: -s, che attiva la modalità debug.

Definizione alla linea 462 del file boot.cpp.

Questo è il grafo delle chiamate per questa funzione:
Questo è il grafo dei chiamanti di questa funzione:

Documentazione delle variabili

◆ wait_for_gdb

volatile int wait_for_gdb

sincronizzazione con gdb

Se è richiesta la connessione con il debugger, settiamo a 1 questo flag. Il codice in attiva_paginazione(), prima di saltare all'entry point del primo modulo, entra in un ciclo e ci resta fino a quando il flag vale 1. Lo script debug resetta questo flag alla partenza di gdb.

Definizione alla linea 544 del file boot.cpp.