El GDT
From Movaxes
(→'''gdt.asm''') |
(→'''gdt.asm''') |
||
Line 179: | Line 179: | ||
db 0 | db 0 | ||
;----------------; | ;----------------; | ||
- | U_CODE_SEG equ $-GDT_INIT | + | U_CODE_SEG equ $-GDT_INIT ;segmento de Codigo de usuario: |
dw 0FFFFh | dw 0FFFFh | ||
Line 188: | Line 188: | ||
db 0 | db 0 | ||
;----------------; | ;----------------; | ||
- | U_DATA_SEG equ $-GDT_INIT | + | U_DATA_SEG equ $-GDT_INIT ;segmento de Datos de usuario: |
dw 0xFFFF | dw 0xFFFF |
Revision as of 13:36, 15 February 2007
Contents |
EL GDT (Global Table Descriptor)
GDT
El GDT es una estructura de datos para definir los privilegios de diferentes áreas de la memoria.
La tabla de descriptores es un array de entradas de 8 bytes que contienen descriptores, puede contener cualquier cantidad de descritores hasta un máximo de 8192 descriptores. La primera entrada del GDT no es usada por el procesador (descriptor nulo).
GDTR
El GDT es apuntado por un registro especial de 48 bits llamado GDTR. El puntero al GDT debe contener esta información:
- LIMIT: Los primeros 16 bits indican el tamaño del segmento del GDT.
- BASE: Los siguientes 32 bits indican en dónde se encuentra el GDT en el espacio lineal de 4Gb de la memoria. Se puede calcular de esta forma (ASM):
puntero_gdt: dw final_gdt-inicio_gdt-1 ;LIMIT dd inicio_gdt ;BASE
Segmentos
El GDT contiene un número de entradas llamadas Segment Descriptors, estos descriptores de segmento indican en que parte de la memoria empieza, termina y los privilegios asociados con esta entrada. Cada descriptor del GDT indica si el área de la memoria es para uso del sistema (ring 0) o para el uso de las aplicaciones (ring 3). Los anillos (rings) indican al procesador si está permitido ejecutar instrucciones especiales (por ejemplo: cli).
La estructura de una entrada del descriptor es:
- Limite (segment limit) 2 bytes.
- Base (base adress) 2 bytes: La dirección lineal en donde empieza el segmento.
- Base (base) 1 byte:
- Acceso (access) 1 byte: contiene los siguiente bits:
- Presencia (1 bit) = debe estar puesto a 1 si el segmento es válido
- Privilegio (2 bit) = contiene el nivel de privilegios (ring 0 = kernel, ring 3 = aplicaciones).
- Ejecutable (1 bit) = 1 si es segmento de codigo, 0 si es segmento de datos.
- Dirección (1 bit) =
- Segmento de Código: relacionado con los privilegios
- Segmento de Datos: 1 indica que el segmento crece hacia abajo, 0 que crece hacia arriba.
- Lectura y Escritura (1 bit) =
- Segmento de Código: Si está permitida la lectura de este segmento. (en un segmento de datos nunca puede escribirse)
- Segmento de Datos: Si está permitida la escritura de este segmento. (en un segmento de datos siempre se puede leer)
- Accedido (1 bit) = el procesador lo pone a 1 cuando accede a el.
- Banderas 2 =
- Granularidad (1 bit) = 0 si el límite está bloques de 1 byte (granulación de bytes), 1 si el límite está en bloques de 4Kib (granulación de páginas).
- Tamaño (1 bit) = 0 si el segmento define un modo protegido de 16 bits, 1 si es modo protegido de 32 bits.
;--------------------------------------------------------------------------------------------------------; ; Limite Bajo (2b) ; Base Baja (2b) ; Base Media (1b) ; Acceso (1b) ; Granularidad (1b) ; Base Alta (1b) ; ;--------------------------------------------------------------------------------------------------------;
todo: información más detallada?
Implementación
Esta es la implementación de NULL-OS con el GDT:
boot.asm
;--------------------------; ; NULL OS (boot.asm) ; ; version: 0.0.1 ; ; autor: movaxes ; ; fecha: 6/2/07 ; ;--------------------------; [BITS 32] %include "gdt.asm" global boot ;donde inicia nuestro kernel extern _main ;esta funcion se encuentra en main.c ;Multiboot Header MULTIBOOT_PAGE_ALIGN equ 1<<0 MULTIBOOT_MEMORY_MAP equ 1<<1 MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_MAP MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) SECTION .text ALIGN 4 multiboot_header: dd MULTIBOOT_HEADER_MAGIC dd MULTIBOOT_HEADER_FLAGS dd MULTIBOOT_CHECKSUM ;nuestro stack (pila) de 16kb: KERNEL_STACK equ 0x4000 boot: mov esp,stack+KERNEL_STACK ;apuntamos a nuestra pila push eax ;ponemos en la pila MULTIBOOT_HEADER_MAGIC push ebx ;ponemos en la pila MULTIBOOT_MEMORY_MAP call gdt_set ;ponemos el GDT call _main ;llamamos a main en main.c cli hlt ;detiene el CPU jmp $ ;loop infinito SECTION .bss ALIGN 32 stack: resb KERNEL_STACK
gdt.asm
;--------------------------; ; NULL OS (gdt.asm) ; ; version: 0.0.2 ; ; autor: movaxes ; ; fecha: 13/2/07 ; ;--------------------------; [BITS 32] ;----------------; ;gdt_set ; ;----------------; gdt_set: lgdt [puntero_gdt] ;carga el GDTR mov ax, 0x10 ; mov ds, ax ;Apuntamos el segmento de datos a 0x10 mov es, ax ;... mov fs, ax mov gs, ax mov ss, ax jmp 0x08:gdt_set_end ;cargamos el CS gdt_set_end: ret ;fin de gdt_set ;----------------; puntero_gdt: ;nuestro puntero al GDT dw GDT_END-GDT_INIT-1 ;limite (fin del gdt - inicio del gdt - 1) dd GDT_INIT ;base ;----------------; ;GDT ; ;----------------; GDT_INIT: ;----------------; NULL_SEG equ $-GDT_INIT ;Descriptor nulo (NULL = 0x0): dw 0 ;Limite del Segmento dw 0 ;00..15 de la dirección base db 0 ;16..23 de la dirección base db 0 ;Permisos de acceso al segmento: ;(presencia,privilegio,ejecutable,direccion,r/w,accedido) db 0 ;Granularidad, Tamaño del los optcodes (16 o 32), limite de 16..19 db 0 ;24..31 de la dirección base ;----------------; K_CODE_SEG equ $-GDT_INIT ;segmento de Codigo del kernel: dw 0xFFFF dw 0 db 0 db 10011010b db 11001111b db 0 ;----------------; K_DATA_SEG equ $-GDT_INIT ;segmento de Datos del Kernel: dw 0FFFFh dw 0 db 0 db 10010010b db 11001111b db 0 ;----------------; U_CODE_SEG equ $-GDT_INIT ;segmento de Codigo de usuario: dw 0FFFFh dw 0 db 0 db 11111010b db 11001111b db 0 ;----------------; U_DATA_SEG equ $-GDT_INIT ;segmento de Datos de usuario: dw 0xFFFF dw 0 db 0 db 11110010b db 11001111b db 0 ;----------------; GDT_END: ;fin del GDT ;----------------;
main.c
/*--------------------------; ; NULL OS (main.c) ; ; version: 0.0.1 ; ; autor: movaxes ; ; fecha: 6/2/07 ; ;--------------------------*/ //esta es nuestra funcion _main llamada desde boot.asm //los argumentos que pasamos son: //MULTIBOOT_HEADER_MAGIC //MULTIBOOT_MEMORY_INFO //los cuales estan en la pila (stack) void _main(void* mm, unsigned int magic) { //todo:... }
link.ld
ENTRY (boot) SECTIONS{ . = 0x00100000; .text :{ *(.text) } .rodata ALIGN (0x1000) : { *(.rodata) } .data ALIGN (0x1000) : { *(.data) } .bss : { _sbss = .; *(COMMON) *(.bss) _ebss = .; } }
build.sh:
#!/bin/bash echo --- compilando *.asm nasm -f elf boot.asm -o boot.o nasm -f elf gdt.asm -o gdt.o echo --- compilando *.c #gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o main.o main.c gcc -o main.o -c main.c -Wall -Werror -nostdlib -nostartfiles -nodefaultlibs echo --- linking *.o ld -T link.ld -o kernel.bin boot.o main.o gdt.o echo --- borrando *.o rm *.o echo --- EXITO!!
Compilar y Probar el Kernel
Para compilar solo escribe en un terminal:
$sh build.sh
Para poder probar tu nuevo kernel puedes usar GRUB (mira: Usando GRUB para saber cómo puedes hacerlo)