tawasuyu

tawasuyu/brahman

Rust 506TOML 198Markdown 56JSON 197212 Sutichaykuna

⎇ 07ab095d4202aa5ff30d9a109e610d517a434e74 renaser/kernel/src/gdt.rs Rust · 80 siq'ikuna · 4.0 KB Ñawpa willay Pi imata llamkarqan ch'uya

feat: integra renaser (kernel SASOS bare-metal) al monorepo e2272c0ed · sergio ·

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}