⎇ 07ab095d4202aa5ff30d9a109e610d517a434e74
renaser/kernel/src/gdt.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
feat: integra renaser (kernel SASOS bare-metal) al monorepo
1// =============================================================================
2// renaser :: kernel/src/gdt.rs — Fase 2 :: cimientos del manejo de fallos
3// -----------------------------------------------------------------------------
4// La GDT y el TSS no se ven jamas, pero sostienen todo lo demas. Su cometido
5// esencial en renaser es reservar un stack de emergencia inquebrantable: si la
6// pila del kernel se desborda, el manejador de doble fallo aterrizara sobre
7// terreno firme en lugar de arrastrar al sistema hacia un fallo triple.
8//
9// Una sola verdad, instalada una sola vez, que PERSISTE bajo cada interrupcion.
10// =============================================================================
11
12use x86_64::instructions::segmentation::{Segment, CS, DS, ES, SS};
13use x86_64::instructions::tables::load_tss;
14use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
15use x86_64::structures::tss::TaskStateSegment;
16use x86_64::VirtAddr;
17
18use crate::CeldaSync;
19
20/// Indice, dentro de la Interrupt Stack Table del TSS, del stack reservado
21/// para el manejador de doble fallo.
22pub const IST_DOBLE_FALLO: u16 = 0;
23
24/// Tamaño del stack de emergencia: 20 KiB. Holgura suficiente para diagnosticar
25/// el fallo y encender la baliza sin volver a tocar la pila comprometida.
26const TAM_STACK_EMERGENCIA: usize = 4096 * 5;
27
28/// Stack de emergencia del doble fallo. Vive en `.bss`; la IST apuntara a su
29/// extremo superior, pues la pila de x86_64 crece hacia direcciones menores.
30static STACK_EMERGENCIA: CeldaSync<[u8; TAM_STACK_EMERGENCIA]> =
31 CeldaSync::nueva([0; TAM_STACK_EMERGENCIA]);
32
33/// El Task State Segment. En 64 bits ya no describe «tareas»: lo conservamos
34/// unicamente por su Interrupt Stack Table.
35static TSS: CeldaSync<TaskStateSegment> = CeldaSync::nueva(TaskStateSegment::new());
36
37/// La Global Descriptor Table propia de renaser.
38static GDT: CeldaSync<GlobalDescriptorTable> = CeldaSync::nueva(GlobalDescriptorTable::new());
39
40/// Instala una GDT propia con su TSS y arma el stack de emergencia.
41///
42/// Debe invocarse una sola vez, durante el arranque, ANTES de cargar la IDT:
43/// la IDT inscribe en cada entrada el selector de codigo vigente en ese momento.
44pub fn init() {
45 // --- 1. Inscribir en el TSS la cima del stack de emergencia. ---
46 // La pila crece hacia abajo: la IST exige la direccion MAS ALTA del bloque.
47 let cima_stack = VirtAddr::from_ptr(STACK_EMERGENCIA.puntero()) + TAM_STACK_EMERGENCIA as u64;
48 // SEGURIDAD: `init` corre una sola vez, en arranque secuencial de un solo
49 // hilo; nada mas referencia el TSS todavia.
50 unsafe {
51 (*TSS.puntero()).interrupt_stack_table[IST_DOBLE_FALLO as usize] = cima_stack;
52 }
53
54 // --- 2. Construir la GDT: codigo de kernel, datos de kernel y el TSS. ---
55 // SEGURIDAD: mismo argumento de unicidad; la GDT aun no esta cargada y
56 // ningun otro flujo posee referencias a estas celdas.
57 let gdt: &'static mut GlobalDescriptorTable = unsafe { &mut *GDT.puntero() };
58 let tss: &'static TaskStateSegment = unsafe { &*TSS.puntero() };
59
60 let sel_codigo: SegmentSelector = gdt.append(Descriptor::kernel_code_segment());
61 let sel_datos: SegmentSelector = gdt.append(Descriptor::kernel_data_segment());
62 let sel_tss: SegmentSelector = gdt.append(Descriptor::tss_segment(tss));
63
64 // --- 3. Activar la GDT y recargar TODOS los registros de segmento. ---
65 let gdt_estatica: &'static GlobalDescriptorTable = gdt;
66 gdt_estatica.load();
67 // SEGURIDAD: los tres selectores apuntan a entradas validas de la GDT
68 // recien cargada. Recargar SS/DS/ES es IMPRESCINDIBLE, no opcional: el
69 // cargador nos deja esos registros con selectores de SU tabla; si SS
70 // conservara el valor heredado, el primer `iretq` de una rutina de
71 // excepcion intentaria recargar un selector que en nuestra GDT ya no
72 // describe un segmento de datos, y degeneraria en un #GP.
73 unsafe {
74 CS::set_reg(sel_codigo);
75 SS::set_reg(sel_datos);
76 DS::set_reg(sel_datos);
77 ES::set_reg(sel_datos);
78 load_tss(sel_tss);
79 }
80}