Oppure

Loading
18/03/17 22:21
TheDarkJuster
Buona sera,
Mi sto dilettando a scrivere un so per x64 che USA uefi per farsi arrivare.

Fin qui tutto bene, ho anche scritto una funzione che mi stampa a video lo stato dei registri rax, rbx, cr0 e cr3.

Ora, sono consapevole che la modalità lunga (il funzionamento nativo delle CPU x64) prevede la paginazione sempre attiva, e infatti stampando cr0 vedo che i bit riguardanti la paginazione sono settati.

So che in modalità x64 la gdt è uguale alla x86, quindi non può descrivere tutta la memoria, quindi voglio:

Caricare la mia gdt, che rende "di libero accesso" tutta la memoria che può essere descritta con la gdt (perché voglio gestire solo la paginazione)

Ora... Non riesco a impostare la mia gdt.

A tal proposito mi sono informato: wiki.osdev.org/… e vedo che nel descrittore della gdt il riferimento all'inizio della gdt è espresso come indirizzo virtuale (logico, visto che in x64 disattivare la paginazione porta la CPU in uno stato di errore), quindi ho creato dello spazio all'interno del mio programma uefi e lo uso per contenere la gdt.

Il problema è che dopo aver fatto lgdt il sistema si riavvia, quindi sicuramente qualcosa sbaglio....

Suppongo che, per i motivi sopra elencati anche l'indirizzo del descrittore della gdt sia da intendere virtuale, ed è ciò che passo alla istruzione lgdt, eppure non funziona....

Qualcosa mi è sfuggito?
aaa
18/03/17 23:48
TheDarkJuster
Il codice che uso è:


typedef struct _gdt_entry
{
	uint16_t limit_low;
	uint16_t base_low;
	uint8_t base_middle;
	uint8_t access;
	uint8_t granularity;
	uint8_t base_high;
} __attribute__((packed)) gdt_entry_t;

typedef struct _gdt_desc {
  uint16_t size;
  uint32_t offset;
} __attribute__((packed)) gdt_desc_t;

static gdt_entry_t gdt[32];
static gdt_desc_t gdt_desc;
static uint16_t gdt_num_entry;

void load_gdt(uint64_t gdt_addr);

void gdt_setup()
{
  //setup the GDT descriptor
  gdt_desc.size = 0;
  gdt_desc.offset = &gdt;

  gdt_num_entry = 0;
}

void gdt_add_entry(uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity) {
        gdt[gdt_num_entry].base_low = (base & 0xFFFF);
	gdt[gdt_num_entry].base_middle = (base >> 16) & 0xFF;
	gdt[gdt_num_entry].base_high = (base >> 24) & 0xFF;
	gdt[gdt_num_entry].limit_low = (limit & 0xFFFF);
	gdt[gdt_num_entry].granularity = ((limit >> 16) & 0x0F) | (granularity & 0xF0);
	gdt[gdt_num_entry].access = access;

       gdt_num_entry++; // la prossima chiamata riempira il prossimo "segmento" di GDT
}

void gdt_apply() {
  gdt_desc.size = (sizeof(gdt_entry_t) * gdt_num_entry) -1;

  load_gdt(&gdt_desc);
}


load_gdt è scritta in assembly (nasm):

BITS 64

GLOBAL load_gdt

load_gdt:
  lgdt	[rax]        	; load new GDT pointer
  ret



e nell'entry point EFI:

  gdt_setup();
        gdt_add_entry(0, 0, 0, 0);                // null - questo ci va, punto e basta.
        gdt_add_entry(0, 0xFFFFFFFF, 0x9A, 0xCF); // ring0 code a tutta la memoria
	gdt_add_entry(0, 0xFFFFFFFF, 0x92, 0xCF); // ring0 data a tutta la memoria
	gdt_add_entry(0, 0xFFFFFFFF, 0xFA, 0xCF); // ring3 code a tutta la memoria
	gdt_add_entry(0, 0xFFFFFFFF, 0xF2, 0xCF); // ring3 data a tutta la memoria
  gdt_apply();

  Print(L"GPT loaded.");

for (;;) // un bel ciclo infinito


la scritta "GPT loaded." appare, ma invece di ciclare all'infinito la vm si riavvia, mentre se tolgo gdt_apply() tutto funziona come previsto.
Ultima modifica effettuata da TheDarkJuster 18/03/17 23:51
aaa
19/03/17 10:47
nessuno
Dopo la lgdt la ret non ritorna dove ti aspetti. Quello che è stato messo nello stack prima della lgdt NON vale dopo la lgdt.
Sicuramente una ret di una call fatta prima di cambiare modalità fa un disastro.

La lgdt non va chiamata in quel modo ma nel main (nel flusso principale programma) e va seguita da una

jmp GDT64.Code:Target64

che passi al segmento in long mode appena creato. E da lì parte l'inizializzazione di stack, registri e via verso il codice 64
Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti ( uno dei padri fondatori del moderno Calcolo delle probabilità ) chiamava il gioco del Lotto Tassa sulla stupidità.
19/03/17 12:43
TheDarkJuster
Volevo evitare di fare tutto nel main.

Ho visto questo: github.com/luksow/… e volevo riproporre la stessa cosa per un sistema x64, però alcune cose non mi sono chiare:
1) perchè fa [esp+4] per trovare l'indirizzo della gdt? La calling convention non dovrebbe specificare che è in eax?
2) perchè lui riesce a saltare indietro al main e io no?
aaa