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
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!!

