SO Screen

From Movaxes

Contents

Escribiendo en pantalla

Introducción

No tengo mucho tiempo ahora así que simplemente voy a poner el código acá y espero poder explicarlo en poco tiempo. El código está comentado, espero que sea suficiente por el momento.

Notas

Las funciones para escribir a pantalla serían mucho más rápidas y ocuparían mucho menos espacio si fueran escritas en ASM, eso se puede notar al revisar el archivo kernel.dbg que se crea luego de compilar usando build.sh.

NULL OS corriendo en Bochs

Image:NULL-OS-0-0-2.png

Código

Para compilar solo necesitas escribir en un terminal:

$sh build.sh

Para probarlo usando GRUB mira en el tutorial de: Usando GRUB como bootloader.

boot.asm

;--------------------------;
; NULL OS (boot.asm)       ;
; version: 0.0.2           ;
; autor: movaxes           ;
; fecha: 6/2/07            ;
;--------------------------;
[BITS 32]

global boot					;donde inicia nuestro kernel (para link.ld)
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

;----------------;
;STACK           ;
;----------------;
;nuestro stack (pila) de 16kb:

	KERNEL_STACK	equ	0x4000

;----------------;
;BOOT            ;
;----------------;
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	_main				;llamamos a _main en main.c
	hlt					;detiene el CPU
	;jmp	$				;loop infinito

SECTION .bss
ALIGN 32
;----------------;
;STACK           ;
;----------------;
stack:

	resb KERNEL_STACK

gdt.asm

;--------------------------;
; NULL OS (gdt.asm)        ;
; version: 0.0.2           ;
; autor: movaxes           ;
; fecha: 13/2/07           ;
;--------------------------;
[BITS 32]
;----------------;
;gdt_set         ;
;----------------;
global gdt_set				;llamamos desde _main
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
;----------------;

globals.h (en folder: /include)

/*-------------------------;
; NULL OS (globals.h)      ;
; version: 0.0.2           ;
; autor: movaxes           ;
; fecha: 14/2/07           ;
;-------------------------*/
#ifndef __ASM_GLOBALS
#define __ASM_GLOBALS

//colores de la consola
#define BLACK		0x00
#define BLUE		0x01
#define GREEN		0x02
#define CYAN		0x03
#define RED		0x04
#define MAGENTA	0x05
#define BROWN		0x06
#define WHITE		0x07
#define GRAY		0x08
#define LBLUE		0x09
#define LGREEN		0x0A
#define LCYAN		0x0B
#define LRED		0x0C
#define LMAGENTA	0x0D
#define YELLOW		0x0E
#define BWHITE		0x0F

//gdt.asm
extern void gdt_set();

//system.c
extern unsigned char inportb (unsigned short port);
extern void outportb (unsigned short port, unsigned char data);

//string.c
extern int strlen(const char *str);

//screen.c
extern void cls(void);
extern void puts(char *src);
extern void putch(unsigned char c);
extern void newline(void);
extern void cursor_chck(void);
extern void scroll_chck(void);
extern void set_attrib(int foreColor, int bgColor);
extern void update_crs(void);
extern void init_video(void);

#endif

system.c

/*-------------------------;
; NULL OS (system.c)       ;
; version: 0.0.1           ;
; autor: movaxes           ;
; fecha: 15/2/07           ;
;-------------------------*/

// --- inportb ----------------------------
// usaremos esto para leer de los I/O ports 
// para poder obtener datos byte
// ----------------------------------------
unsigned char inportb (unsigned short port)
{
    unsigned char return_v; // el valor que vamos a retornar
    __asm__ __volatile__ ("inb %1, %0" : "=a" (return_v) : "dN" (port));
    return return_v; 
}

// --- outportb ---------------------------
// usaremos esto para escribir a los I/O ports 
// para poder enviar datos byte
// ----------------------------------------
void outportb (unsigned short port, unsigned char data)
{
    __asm__ __volatile__ ("outb %1, %0" : : "dN" (port), "a" (data));
}

string.c

/*-------------------------;
; NULL OS (string.c)       ;
; version: 0.0.1           ;
; autor: movaxes           ;
; fecha: 15/2/07           ;
;-------------------------*/

// --- strlen -----------------------------
// hace un loop en el array de caracteres str (string)
// y regresa el largo en bytes de la cadena 
// ----------------------------------------
int strlen(const char *str)
{
    int len = 0; // retval = return value
    while (*str++ != '\\0') // mientras no encontremos '\\0'
    {                      // significa que la cadena continua
      ++len;               // y entonces seguimos contando
    }
    return len; // regresamos el largo de str
    
}

screen.c

/*-------------------------;
; NULL OS (screen.c)       ;
; version: 0.0.2           ;
; autor: movaxes           ;
; fecha: 14/2/07           ;
;-------------------------*/

#include "globals.h"

unsigned short *vidmem = (unsigned short *)0xB8000;
                            
int attrib; // atributos de fondo y color del texto
int carry = 0;
int cx = 0; // coordinada del cursor en x
int cy = 0; // coordenada del cursor en y

// --- cls --------------------------------
// limpia la pantalla (clear screen)
// ----------------------------------------
void cls()
{
    unsigned short *vidmemp; // puntero a la memoria de video
    int x, y; // para controlar la posicion

    for(y=0;y<25;y++) { // alto
	  for(x=0;x<80;x++) { // ancho
		vidmemp = vidmem+((y*80)+x); // apuntamos a la nueva posicion
		*vidmemp = 0x20 | (WHITE << 8); // borramos
	  }
    }
}

// --- puts -------------------------------
// pone una cadena usando putch
// ----------------------------------------
void puts(char *str)
{
    int len;
    int i;

    len = strlen(str); // cuantos caracteres tiene?

    for(i=0; i<len; i++) {
      putch(str[i]); // ponemos en pantalla
    }
}

// --- putch ------------------------------
// pone un caracter en pantalla
// ----------------------------------------
void putch(unsigned char c) {
	unsigned short *vidmemp;

	if(c == 0x08) { //regreso (backspace)
		if(cx!=0) { //si no estamos al principio de la linea
		cx--;
		vidmemp = vidmem + ((cy*80)+cx);
		*vidmemp = 0x20 | (attrib << 8);
		} else if (carry!=0 && cx==0) {
		cx=79;
		cy--;
		carry--;
		vidmemp = vidmem + ((cy*80)+cx);
		*vidmemp = 0x20 | (attrib << 8);
		}
	} else if(c == 0x09) { // tab
		cx = (cx + 8) & ~(8-1);
	} else if(c == '\\r') { //retorno de linea
		cx = 0;
	} else if(c == '\
') { //una nueva linea
		if(carry!=0)
			carry=0;
		newline();
	} else if(c >= ' ') { //si es cualquier otro caracter
		vidmemp = vidmem + ((cy*80)+cx);
		*vidmemp = c | (attrib << 8);
		cx++;
	}
	cursor_chck();
	update_crs();
	scroll_chck();
}

//make new line
void newline(void) {
	cx = 0;
	cy++;
	update_crs();
}

//check cursor if it has reached the limit
void cursor_chck(void) {
	if (cx >= 80) {
		cx = 0;
		carry++;
		cy++;
	}
}

// --- scroll -----------------------------
// revisa si es necesario y 
// mueve la pantalla hacia arriba (scroll)
// ----------------------------------------
void scroll_chck(void) {

	unsigned short *vidmemsrc = (unsigned short *)0xB8000; // fuente
	unsigned short *vidmemdest = (unsigned short *)0xB8000+80; // destino
	int x, y; // para llevar el control de la posicion

	if(cy>=24) { // si estamos al final de la pantalla
		for(y=0;y<24;y++) {
			for(x=0;x<80;x++) {
				*vidmemsrc++ = *vidmemdest++;
			}
		}
	cx = 0;
	cy--;
	update_crs(); // actualizamos el cursor
	}
}

// --- set_attrib -------------------------
// pone los atributos del fondo y color del texto
// ----------------------------------------
void set_attrib(int foreColor, int bgColor) {
    // los 4 bytes superiores son el fondo
    // los 4 bytes inferiores son el color del texto
    attrib = (bgColor << 4) | (foreColor);
}

// --- update_crs -------------------------
// actualiza la posicion del cursor
// ----------------------------------------
void update_crs(void) {

	unsigned int pos;

    // la ecuacion para encontrar el indice en un pedazo lineal
    // de memoria es:
    // index = [(y * width) + x]
    // Encontramos posicion del cursor:
	pos = (cy*80)+cx;

	outportb(0x3D4, 14); // enviamos al indice 14 en el CRT Control Register del
                          // controlador del VGA
                          
	outportb(0x3D5, pos >> 8); // TODO: comentar, explicar
	
	outportb(0x3D4, 15); // enviamos al indice 15 en el CRT Control Register del
                          // controlador del VGA
                          
	outportb(0x3D5, pos); // TODO: comentar, explicar
}

// --- init_video -------------------------
// inicia el driver de video
// ----------------------------------------
void init_video(void)
{
    cx = 0;
    cy = 0;
    set_attrib(BWHITE, BLACK);
    cls();
}

main.c

/*--------------------------;
; NULL OS (main.c)          ;
; version: 0.0.2            ;
; autor: movaxes            ;
; fecha: 6/2/07             ;
;--------------------------*/

#include "globals.h"

void _main(void* mm, unsigned int magic) 
{
	//iniciamos la pantalla
	init_video();
	
	//nombre del sistema
	set_attrib(LGREEN, BLACK);
	puts("NULL OS (version 0.0.2)\
");
	puts("-----------------------\
");
	puts("Implementado:\
");
	puts("	GDT\
");
	puts("	SCREEN\
");
	puts("-----------------------\
");
	
	//ponemos nuestro GDT
	gdt_set();
	set_attrib(BWHITE, BLACK);
	puts("GDT cargado\
");
	
	//todo...
	puts("...\
");
}

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 -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o string.o string.c
gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o system.o system.c
gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o screen.o screen.c

echo --- linking *.o
ld -T link.ld -o kernel.bin boot.o gdt.o string.o system.o screen.o main.o 

echo --- borrando *.o
rm *.o

echo --- desensamblando kernel.bin --- ver kernel.dbg
objdump -d -f kernel.bin -M intel > kernel.dbg

echo --- EXITO!!
Personal tools