El GDT

From Movaxes

(Difference between revisions)
('''gdt.asm''')
('''gdt.asm''')
Line 179: Line 179:
     db 0
     db 0
;----------------;
;----------------;
-
U_CODE_SEG    equ    $-GDT_INIT ;segmento de Codigo de usuario:
+
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 ;segmento de Datos de usuario:
+
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)



Personal tools