Cosa contiene l'indirizzo fisico 0 in Linux x86?


12

Non sono sicuro se questa domanda dovrebbe andare qui o in reverseengineering.stackexchange.com

Citando da Wikipedia :

Nel processore 8086, la tabella di interrupt si chiama IVT (tabella di vettore di interrupt). L'IVT risiede sempre nella stessa posizione in memoria, compresa tra 0x0000 e 0x03ff, ed è costituito da 256 puntatori remoti in modalità reale a quattro byte (256 × 4 = 1024 byte di memoria).

Questo è ciò che trovo nel monitor qemu:

(qemu) xp/128xw 0
0000000000000000: 0xf000ff53 0xf000ff53 0xf000e2c3 0xf000ff53
0000000000000010: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000020: 0xf000fea5 0xf000e987 0xf000d62c 0xf000d62c
0000000000000030: 0xf000d62c 0xf000d62c 0xf000ef57 0xf000d62c
0000000000000040: 0xc0005526 0xf000f84d 0xf000f841 0xf000e3fe
0000000000000050: 0xf000e739 0xf000f859 0xf000e82e 0xf000efd2
0000000000000060: 0xf000d648 0xf000e6f2 0xf000fe6e 0xf000ff53
0000000000000070: 0xf000ff53 0xf000ff53 0xf0006aa4 0xc0008930
0000000000000080: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000090: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000c0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000d0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000e0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000100: 0xf000ec59 0xf000ff53 0xf000ff53 0xc0006730
0000000000000110: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000120: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000130: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000140: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000150: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000160: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000170: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000180: 0x00000000 0x00000000 0x00000000 0x00000000
0000000000000190: 0x00000000 0x00000000 0x00000000 0xf000ff53
00000000000001a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001c0: 0xf000d611 0xf000ec4e 0xf000ec4e 0xf000ec4e
00000000000001d0: 0xf000d61a 0xf000d623 0xf000d608 0xf000ec4e
00000000000001e0: 0xf000ff53 0x00000000 0xf000ff53 0xf000ff53
00000000000001f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53

Non sono sicuro di cosa fare di questi valori. Non sembra una tabella di descrittori di interrupt (la dereferenziazione di questi valori fornisce tutti i valori null). Quindi cosa sto guardando qui?

Risposte:


9

Qualunque cosa il tuo firmware lo abbia lasciato contenente.

Su un sistema moderno ideale, il processore non entra mai nella modalità reale, come ho spiegato in questo SU SU D&R intitolato: In quale modalità i moderni PC chip Intel a 64 bit eseguono il settore di avvio? , il primo KiB della memoria fisica è irrilevante come Johan Myréen ha scoperto di essere in un'altra risposta qui. Ma molti firmware moderni (ancora) hanno il supporto della compatibilità , nel senso che

  • possono tornare indietro (sì, indietro , dato che sono passati direttamente dalla modalità irreale alla modalità protetta) dalla modalità protetta alla modalità reale per eseguire software di sistema scritti per la modalità reale, come programmi di avvio PC / AT vecchio stile in MBR e VBR; e
  • forniscono le vecchie API del firmware in modalità reale e impostano tutte le strutture di dati per quelle API, su cui si basano i software di sistema di cui sopra.

Una di queste strutture di dati è la modalità reale IVT. Le vecchie API del firmware in modalità reale si basano su intistruzioni e l'IVT in modalità reale viene popolata dal firmware come parte della sua inizializzazione con puntatori alle varie routine di gestione del firmware per tali istruzioni.

I software di sistema in modalità protetta non necessitano delle vecchie API del firmware in modalità reale e non eseguono mai il processore in modalità reale, quindi la modalità reale IVT nei primi 1 KiB di memoria fisica non viene utilizzata. (la modalità protetta v8086 non indirizza l'indirizzo fisico 00000000 e versioni successive, ricorda. Si rivolge agli indirizzi logici 00000000 e versioni successive, tradotti dalle tabelle delle pagine). Nei moderni sistemi EFI, il firmware passa una mappa di memoria della memoria fisica al sistema operativo bootstrap, indicando quali parti sono riservate al firmware per i suoi scopi API in modalità protetta e quali parti il ​​sistema operativo è libero di andare avanti e utilizzare per il suo pool di memoria fisica. In teoria, la prima pagina della memoria fisica può appartenere a quest'ultima categoria.

In pratica, in primo luogo, i firmware spesso contrassegnano la prima pagina della memoria fisica come "codice dei servizi di avvio", il che significa che un sistema operativo può rivendicarlo e andare avanti e usarlo come parte del suo pool di memoria fisica, ma solo dopo l'avvio- i servizi a tempo del firmware EFI sono stati chiusi dal sistema operativo e il firmware è stato ridotto a fornire solo i suoi servizi di runtime. Un esempio di questo può essere visto nel log del kernel di Linux (con l' add_efi_memmapopzione) mostrato da Finnbarr P. Murphy:

[0.000000] efi: mem00: tipo = 3, attr = 0xf, intervallo = [0x0000000000000000-0x0000000000001000) (0 MB)
che xe decodifica con un altro programma in una forma più leggibile dall'uomo come:

[# 00] Tipo: EfiBootServicesCode Attr: 0xF
      Phys: 0000000000000000-0000000000001000
      Virt: 0000000000000000-0000000000001000

In pratica, in secondo luogo, Linux ignora esplicitamente questo intervallo di memoria fisica anche se il firmware dice che può andare avanti e usarlo. Scoprirai che sia su firmware EFI che non EFI, una volta che Linux ha la mappa di memoria fisica, la patch ( in una funzione denominatatrim_bios_range ), risultando in messaggi di log del kernel come:

[0.000000] e820: aggiorna [mem 0x00000000-0x00000fff] utilizzabile ==> riservato

Questo non è tanto per far fronte ai moderni firmware EFI, dove la modalità reale IVT non fa parte dell'API del firmware, quanto per far fronte ai vecchi firmware PC98, dove fa parte dell'API del firmware ma i firmware lo segnalano (tramite quella stessa API) della memoria fisica disponibile per essere sovrascritta allegramente dal sistema operativo.

Quindi, mentre in teoria quell'intervallo di memoria fisica potrebbe contenere codice o dati arbitrari, a seconda delle esigenze momentanee degli allocatori di memoria del kernel e della memoria virtuale basata sulla domanda; in pratica Linux lo lascia intatto non appena il firmware lo ha originariamente impostato.

E sul tuo sistema il firmware lo aveva popolato con voci IVT in modalità reale. Le voci IVT in modalità reale sono solo puntatori lontani 16:16, ovviamente, e se guardi la tua memoria usando un hexdump a 2 byte puoi effettivamente vederlo abbastanza chiaramente. Qualche esempio:

  • La maggior parte delle voci IVT puntano a F000: FF53, un indirizzo nell'area ROM del firmware in modalità reale. È probabilmente una routine fittizia che non fa altro che un iret.
  • La voce IVT 1E indica F000: 6AA4, una tabella nella stessa area ROM.
  • La voce IVT 1F indica C000: 8930, una tabella nell'area del firmware della ROM video in modalità reale.
  • La voce IVT 43 indica C000: 6730, un'altra tabella nell'area del firmware della ROM video in modalità reale.

Ulteriori letture


No, intendo quello che ho scritto. Manuale per gli sviluppatori di software Intel Architecture volume 3 capitolo 20 § 2.
JdeBP

Bene, adesso, perché lo è; come spiega la prima frase di quella sezione. Sospetto da ciò che il non riconoscimento dell'abbreviazione comune "v8086" sia una sorta di shibboleth. (-:
JdeBP,

Devi imparare a leggere i sostantivi attribuiti. Oppure impara a vivere senza zuppa di funghi.
JdeBP,

7

L'architettura originale del processore 8086 (implementata come modalità reale nei processori 80286+) non ha rilevanza per Linux, che funziona in modalità protetta. Non esiste una tabella vettoriale di interrupt all'indirizzo fisico 0, ma viene utilizzata una tabella descrittore di interrupt contenente descrittori di interrupt. L'IDT può essere posizionato ovunque nella memoria.

Il kernel Linux ottiene una mappa di memoria fisica dal firmware (BIOS o EFI) che indica quali frame di pagine di memoria fisica sono utilizzabili e quali sono riservati o non presenti. La gamma di frame di pagina utilizzabili non è contigua, ma in genere presenta enormi buchi. Tradizionalmente, il kernel Linux x86 ha saltato l'inizio della memoria fisica, anche se è contrassegnato come utilizzabile. Pertanto, l'indirizzo fisico 0 non è utilizzato dal kernel Linux.


Questo ha senso. Hai idea di quale sia il contenuto rimasto in quella pagina inutilizzata?
Rhodeo,

Cercare su Google 53 ffrivela che questa è probabilmente una tabella vettoriale di interrupt in modalità reale 8086 impostata dal firmware o da un caricatore di avvio.
Johan Myréen,

4

Memoria di dumping

Ecco un modo alternativo per scaricare il contenuto della memoria all'interno del sistema anziché doverlo fare esternamente:

$ head /dev/mem | hexdump -C
00000000  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
00000010  53 ff 00 f0 53 ff 00 f0  cc e9 00 f0 53 ff 00 f0  |S...S.......S...|
00000020  a5 fe 00 f0 87 e9 00 f0  53 ff 00 f0 46 e7 00 f0  |........S...F...|
00000030  46 e7 00 f0 46 e7 00 f0  57 ef 00 f0 53 ff 00 f0  |F...F...W...S...|
00000040  22 00 00 c0 4d f8 00 f0  41 f8 00 f0 fe e3 00 f0  |"...M...A.......|
00000050  39 e7 00 f0 59 f8 00 f0  2e e8 00 f0 d4 ef 00 f0  |9...Y...........|
00000060  a4 f0 00 f0 f2 e6 00 f0  6e fe 00 f0 53 ff 00 f0  |........n...S...|
00000070  ed ef 00 f0 53 ff 00 f0  c7 ef 00 f0 ed 57 00 c0  |....S........W..|
00000080  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
...
...
000afea0  00 00 00 00 00 00 00 00  aa aa aa 00 aa aa aa 00  |................|
000afeb0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000b0000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
000c0000  55 aa 40 e9 62 0a 00 00  00 00 00 00 00 00 00 00  |U.@.b...........|
000c0010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 49 42  |..............IB|

Analisi

La parte superiore sopra 000c0000 potrebbe essere relativa al bootloader. Perché dovrei sospettare questo? Il codice 55aah in posizione 000c0000può in genere essere un segno in memoria per cose come un trigger per il BIOS per eseguire un bootloader secondario.

Riferimento: Boot Signature - BIOS

  ss # 1

Tuttavia, dato che 55aah si verifica nell'intervallo c0000h-effffh, è più probabile che questa porzione sia l'intestazione di espansione PNP:

Riferimento: specifica di avvio del BIOS

3.3 Dispositivi con intestazioni di espansione PnP

Tutti i dispositivi IPL con ROM opzionali devono contenere un'intestazione ROM opzionale valida che risiede tra gli indirizzi di memoria di sistema C0000h ed EFFFFh su un confine 2k e inizia con 55AAh. L'avvio di un dispositivo può essere controllato solo se ha un'intestazione di espansione PnP. L'intestazione di espansione, il cui indirizzo risiede nell'intestazione ROM dell'opzione standard a offset + 1Ah, contiene informazioni importanti utilizzate per configurare il dispositivo. Contiene inoltre i puntatori al codice nella ROM opzionale del dispositivo (BCV o BEV) che il BIOS chiamerà per l'avvio dal dispositivo. Vedere l'Appendice A per la struttura dell'intestazione di espansione PnP. Esistono due modi per avviare un dispositivo IPL con un'intestazione di espansione PnP. Deve contenere un BCV o un BEV.

53ff ...

Per quanto riguarda i dati 53ffh che è all'inizio. Non mi è chiaro cosa sia in realtà. Ulteriore ricerca è probabilmente qualcosa che il kernel Linux ha scritto lì dopo che il bootloading dell'MBR del BIOS è stato consegnato al kernel Linux per l'avvio.

Di solito, il bootloader carica il kernel in memoria, quindi passa al kernel. Il kernel sarà quindi in grado di recuperare la memoria utilizzata dal bootloader (perché ha già eseguito il suo lavoro). Tuttavia, è possibile includere il codice del sistema operativo nel settore di avvio e mantenerlo residente dopo l'avvio del sistema operativo

Scavando ulteriormente sono stato in grado di trovare questo paragrafo da un documento di ricerca intitolato: Iniezione di codice dannoso tramite / dev / mem :

1 Il dispositivo mem

/ dev / mem è l'interfaccia del driver per la memoria fisicamente indirizzabile. L'intento originale di mem e kmem era di fornire assistenza nel debug del kernel. Possiamo usare il dispositivo come un normale dispositivo a caratteri, usando lseek () per selezionare un offset di indirizzo. Il dispositivo kmem è simile ma fornisce un'immagine della memoria del kernel nel contesto dell'indirizzamento virtuale. Il server Xorg si avvale del dispositivo mem per accedere alla memoria video VESA e alla tabella ROM di interruzione vettoriale BIOS (IVT) situata all'indirizzo fisico 0x00000000 per manipolare le modalità video in modalità VM86. DOSEMU lo usa anche per accedere al BIOS IVT per essere in grado di eseguire BIOS Interrupt per varie attività (letture del disco, stampa sulla console, ecc.).

Riferimenti

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.