Files
brahman/renaser/kernel/src/gdt.rs
T
sergio e2272c0ed3 feat: integra renaser (kernel SASOS bare-metal) al monorepo
renaser —kernel asíncrono de espacio de direcciones único, no-POSIX,
`no_std` x86_64— entra al monorepo como su PROPIO workspace de Cargo,
no fusionado: usa toolchain nightly, target `x86_64-unknown-none` y
`panic = "abort"`, incompatibles con los perfiles globales de brahman.

- `renaser/` — copia del proyecto (sin su `.git`; el repo original
  conserva su historia standalone). Workspace propio con su
  `rust-toolchain.toml` y `.cargo/`.
- `exclude = ["renaser"]` en el workspace de brahman: Cargo lo trata
  como ajeno.
- El kernel de renaser path-depende `mirada-layout` cruzando la
  frontera de workspace — primer núcleo compartido. Semilla de la
  Fase 8 (compositor): geometría de teselado compartida, framebuffer
  nativo de renaser; smithay se queda en el lado Linux.

Verificado: `cargo build -p boot` compila kernel + imagen UEFI con
mirada-layout enlazado para bare-metal.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 14:37:14 +00:00

81 lines
4.0 KiB
Rust

// =============================================================================
// renaser :: kernel/src/gdt.rs — Fase 2 :: cimientos del manejo de fallos
// -----------------------------------------------------------------------------
// La GDT y el TSS no se ven jamas, pero sostienen todo lo demas. Su cometido
// esencial en renaser es reservar un stack de emergencia inquebrantable: si la
// pila del kernel se desborda, el manejador de doble fallo aterrizara sobre
// terreno firme en lugar de arrastrar al sistema hacia un fallo triple.
//
// Una sola verdad, instalada una sola vez, que PERSISTE bajo cada interrupcion.
// =============================================================================
use x86_64::instructions::segmentation::{Segment, CS, DS, ES, SS};
use x86_64::instructions::tables::load_tss;
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
use x86_64::structures::tss::TaskStateSegment;
use x86_64::VirtAddr;
use crate::CeldaSync;
/// Indice, dentro de la Interrupt Stack Table del TSS, del stack reservado
/// para el manejador de doble fallo.
pub const IST_DOBLE_FALLO: u16 = 0;
/// Tamaño del stack de emergencia: 20 KiB. Holgura suficiente para diagnosticar
/// el fallo y encender la baliza sin volver a tocar la pila comprometida.
const TAM_STACK_EMERGENCIA: usize = 4096 * 5;
/// Stack de emergencia del doble fallo. Vive en `.bss`; la IST apuntara a su
/// extremo superior, pues la pila de x86_64 crece hacia direcciones menores.
static STACK_EMERGENCIA: CeldaSync<[u8; TAM_STACK_EMERGENCIA]> =
CeldaSync::nueva([0; TAM_STACK_EMERGENCIA]);
/// El Task State Segment. En 64 bits ya no describe «tareas»: lo conservamos
/// unicamente por su Interrupt Stack Table.
static TSS: CeldaSync<TaskStateSegment> = CeldaSync::nueva(TaskStateSegment::new());
/// La Global Descriptor Table propia de renaser.
static GDT: CeldaSync<GlobalDescriptorTable> = CeldaSync::nueva(GlobalDescriptorTable::new());
/// Instala una GDT propia con su TSS y arma el stack de emergencia.
///
/// Debe invocarse una sola vez, durante el arranque, ANTES de cargar la IDT:
/// la IDT inscribe en cada entrada el selector de codigo vigente en ese momento.
pub fn init() {
// --- 1. Inscribir en el TSS la cima del stack de emergencia. ---
// La pila crece hacia abajo: la IST exige la direccion MAS ALTA del bloque.
let cima_stack = VirtAddr::from_ptr(STACK_EMERGENCIA.puntero()) + TAM_STACK_EMERGENCIA as u64;
// SEGURIDAD: `init` corre una sola vez, en arranque secuencial de un solo
// hilo; nada mas referencia el TSS todavia.
unsafe {
(*TSS.puntero()).interrupt_stack_table[IST_DOBLE_FALLO as usize] = cima_stack;
}
// --- 2. Construir la GDT: codigo de kernel, datos de kernel y el TSS. ---
// SEGURIDAD: mismo argumento de unicidad; la GDT aun no esta cargada y
// ningun otro flujo posee referencias a estas celdas.
let gdt: &'static mut GlobalDescriptorTable = unsafe { &mut *GDT.puntero() };
let tss: &'static TaskStateSegment = unsafe { &*TSS.puntero() };
let sel_codigo: SegmentSelector = gdt.append(Descriptor::kernel_code_segment());
let sel_datos: SegmentSelector = gdt.append(Descriptor::kernel_data_segment());
let sel_tss: SegmentSelector = gdt.append(Descriptor::tss_segment(tss));
// --- 3. Activar la GDT y recargar TODOS los registros de segmento. ---
let gdt_estatica: &'static GlobalDescriptorTable = gdt;
gdt_estatica.load();
// SEGURIDAD: los tres selectores apuntan a entradas validas de la GDT
// recien cargada. Recargar SS/DS/ES es IMPRESCINDIBLE, no opcional: el
// cargador nos deja esos registros con selectores de SU tabla; si SS
// conservara el valor heredado, el primer `iretq` de una rutina de
// excepcion intentaria recargar un selector que en nuestra GDT ya no
// describe un segmento de datos, y degeneraria en un #GP.
unsafe {
CS::set_reg(sel_codigo);
SS::set_reg(sel_datos);
DS::set_reg(sel_datos);
ES::set_reg(sel_datos);
load_tss(sel_tss);
}
}