Emulando a Linus Torvalds: crea tu propio sistema operativo desde 0 (VII)

Bienvenidos a otro post sobre cómo crear nuestro propio sistema operativo (artículos anteriores de la serie: 1, 2, 3, 4, 5 y 6). Ha pasado mucho tiempo desde el último post, debido principalmente a un bug que encontré en lo que nos toca hoy. Veremos cómo manejar el reloj en arquitecturas x86.

Anteriormente habíamos activado los IRQ de manera genérica, pero hubo un pequeño problema ya que no los activábamos correctamente y pasábamos datos extra. Finalmente lo solucionamos carlosorta y yo y os puedo seguir comentando cómo seguir.

Bien, el reloj es un IRQ, concretamente el primero. Para configurarlo usaremos la función que definimos anteriormente para instalar de manera genérica los IRQ, la ND_IRQ_InstallHandler.

int ND_TIMER_TICKS=0;

void ND::Timer::Phase(int hz)
{
int divisor=1193180/hz;
ND::Ports::OutputB(0x43,0x36);
ND::Ports::OutputB(0x40, divisor & 0xFF);
ND::Ports::OutputB(0x40, divisor >> 8);
}

void ND::Timer::Wait(int ticks)
{
unsigned long eticks;
eticks=ND_TIMER_TICKS+ticks;
while(ND_TIMER_TICKS < eticks)
{

void ND::Timer::Setup()
{
ND::Screen::SetColor(ND_SIDE_FOREGROUND, ND_COLOR_BLACK);
ND::Screen::PutString("\nSetup timer...");
ND_IRQ_InstallHandler(0,&ND_Timer_Handler);
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_GREEN);
ND::Screen::PutString("done");
}

extern "C"
void ND_Timer_Handler(struct regs* r)
{
ND_TIMER_TICKS++;
if(ND_TIMER_TICKS % 18 ==0)
{
//ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_BROWN);
//ND::Screen::PutString("\nOne more second"); WE SHOULD DO A REFRESH SCREEN
}
}

El código se ejecuta de la siguiente manera: el sistema de inicialización llama a ND::Timer::Setup, que llama a ND_IRQ_InstallHandler para insertar en la primera posición, el IRQ0, una función de callback cuando el evento se produzca, esa es ND_Timer_Handler que aumenta los ticks. Como hemos puesto la velocidad del reloj a 18 Hz, como veremos más adelante, si lo dividiésemos entre 18 y nos diese entero habría pasado un segundo.

La función ND::Timer::Phase nos sirve para ajustar la velocidad del timer, ese número tan extravagante es 1.19 MHz que es un valor común. Bien, esta función la deberemos llamar si quisiésemos cambiar la velocidad del timer, por defecto va a 18,22 Hz, un valor peculiar que debió de decidir alguien dentro de IBM y se ha quedado hasta nuestros días.

La función ND::Timer::Wait es bastante simple, solamente espera con un bucle while hasta que se hayan alcanzado los ticks necesarios para continuar.

En la imagen podemos comprobar que si descomentamos el código dentro del ND_Timer_Handler obtenemos esto:

En el siguiente capítulo veremos cómo leer la entrada del teclado y hacer un pequeño shell para interactuar con nuestro sistema. Como siempre, el código está disponible en GitHub bajo la licencia GNU GPL v2.

Comparte para difundir

Si te ha gustado nuestro contenido ahora puedes ayudar a difundirlo en las redes sociales de manera sencilla usando los siguientes botones:

Envía
Pinea
Print

14 comentarios

  1.   Noé dijo

    Muy interesante serie de tutoriales, en lo personal no había visto muchos sobre la creación de una distribución Linux desde cero, y aún menos en español y tan completos. Creo que se pueden aprender muchas cosas con esto y en cuanto tenga tiempo espero poder realizar estos tutoriales.
    Lo único que pido es que no te desanimes y termines el tutorial, ya que he encontrado muchos buenos tutoriales que nunca son terminados.
    Saludos y gracias :).

    1.    roader dijo

      No es una distribucion linux , es un kernel 😛 .

    2.    desikoder dijo

      Te equivocas. Crear una distro linux no implica programar nada, por ejemplo, en un linux from scratch tu no programas, lo que haces es ir instalando ( a base de compilar ), paquetes basicos que forman una distro. Esto es muy diferente. Es crear tu propio sistema operativo. No tiene nada que ver con linux. Es lo que torvalds hizo en su día inspirandose en minix, y con aquella acalorada y popular discusion entre torvalds y andrew s. tanenbaum sobre kernel monolitico vs microkernel.

      Saludos !

  2.   illukki dijo

    Gracias che. Hasta ahora no le habia prestado mucha atencion a tus post pero ando en un proyecto asi que les voy a echar un ojo.
    Saludos.

  3.   roader dijo

    Digno de mencionar que se pueden utilizar otros lenguajes , como Objective-C(++) , C++, D o Rust .

    1.    AdrianArroyoCalle dijo

      Este está en C++, no en C. Sin embargo es difícil ver las diferencias ya que muchos operadores de C++ requieren un respaldo de una librería, como el operador new y el delete. Sería muy interesante hacer un sistema operativo en Rust. De hecho hay un canal en IRC dedicado a los sistemas operativos en Rust (#rust-osdev en irc.mozilla.net). Realmente vale cualquiera que compile a código máquina, incluido Java si usamos GCJ.

      1.    roader dijo

        Si , en efecto , Rust es un lenguaje muy interesante para sistemas operativos , por que , no solo es mas facil de aprender que C o C++ (todavia sigue con cambios continuos , pero mas facil es) , sino que , es mucho mas seguro .

  4.   roader dijo

    En los 70 era bastante comun programar directamente sobre el hardware , sin SO .

  5.   Christopher dijo

    Excelente… ahora solo me hace falta entender :3…

  6.   mmm dijo

    Hola. Muchas gracias por estos artículos. Peero, si no tengo conocimientos en programación como que mejor no lo hago no? digo, sino sería un “bueno, y ahora qué copio y pego?”… qué lástima, siempre me dio tantas ganas de saber programar y nada, soy más burro!

    1.    desikoder dijo

      No te culpes, no eres ningún burro. Para empezar, no todos los programadores saben escribir un kernel, es una tarea muy poco sencilla, y que en la práctica es más grande. Por ejemplo aquí el autor crea unos drivers genericos para el teclado y la pantalla, manipulando el array de pantalla,lo cual es un método que a día de hoy no se usa en absoluto. Los tty en linux a dia de hoy son muy, pero que muy complejos, y no dependen de que en la arquitectura x86 haya un array de pantalla a su disposición. Además, mucho del código en C depende de la arquitectura, cuando lo ideal es hacer en ensamblador el código de la arquitectura y que el código C funcione en cualquier procesador. Sin embargo, no le quito mérito al autor, porque que un kernel adquira las características que hoy día consideramos normales en un kernel linux, por ejempo, no es una labor facil, y ten por seguro que una sola persona es absolutamente incapaz de realizarla. Por algo los grandes proyectos como linux, gcc, glibc, etc, no los hace una sola persona sino que hay muchos colaboradores.

      Además, si quieres empezar a programar tienes por la web bastantes guías, aunque hay que tener cuidado, y seleccionar las guías buenas. Yo empecé a programar en linux tirandome a la piscina de cabeza y sin agua ( es decir, con el querido lenguaje C ), aunque ahora tengo algunas nociones básicas de python ( que también es muy buen lenguaje ). Hay algunos libros de C en los cuales abandonas en la página 6 como mucho del dolor de cabeza que te entra, pero más que libros estas cosas se adquieren por experiencia. Pasa como con el modelo OSI de red. La documentación sobre el modelo osi es absolutamente imposible de entender para el que se inicia, pero si encuentras un sitio con una buena explicación de las capas de red pillas rápidamente los conceptos como para manejarte con documentos tecnicos como los RFC.

      En definitiva, que hay buenas webs y manuales por ahí, es cuestión de ponerse a ello y dar con buen material.

      Saludos

  7.   Free_DOM dijo

    Hola, depues de tanto intento de solucionar el “error : no multiboot header found.” y “error you need to load the kernel first”, ya que no encontraba por ninguna parte la solucion del problema del primer artículo, que algunos como yo tenian…aca le dejo la solución, si a alguien le sirve…

    No se si mi teoria de la causa del error sea la correcta pero en fin, la cuestion es que al compilar los archivos en un sistema operativo de 32bits, no me generaba el error, pero como yo tengo un sistema operativo de 64bits(Gnu/Linux Debian 7), y que al compilar y probar me tiraba el error de “no multiboot header found”, y de hay la duda, entonce a mi parecer el error se debe al entorno o arquitectura del sistema operativo en el cual estamos compilando nuestros archivos…y bueno lo que hice es compilar mis archivos, especificando el entorno o arquitectura de 32bits..
    * sudo as -o kernel.o -c kernel.asm -32
    * sudo gcc -o NextKernel_Main.o -c NextKernel_Main.c -nostdlib -fPIC -ffreestanding -m32
    * sudo gcc -m32 -o START.ELF kernel.o NextKernel_Main.o -Tlink.ld -nostdlib -fPIC -ffreestanding
    Lo raro es que me quedo algunas duda jajajja, entonce el sistema operativo que estamos creando paso a paso es para una arquitectura de x86 o me estoy equivocando ajajaj ….

    P.D: alguien que me ayude con la duda, y disculpen algunos errores ortografico o mi mala expresión, y bueno no soy perfecto asi que “La perfeccion tiene su precio”….Y lo mas importante, emulate un sistema operativo de 32bits, santa solucion….jajajaj

    1.    Martin Villalba dijo

      Genio ! Tenia muchas ganas de hacer este tuto y me bajonie al principio con ese error jaja

  8.   Oscar dijo

    Felicitaciones, es un excelente aporte. Desde ya te comparto que tu buen trabajo mediante mi persona y otros (as) se hará extendido;

    Saludos

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*

*

  1. Responsable de los datos: Miguel Ángel Gatón
  2. Finalidad de los datos: Controlar el SPAM, gestión de comentarios.
  3. Legitimación: Tu consentimiento
  4. Comunicación de los datos: No se comunicarán los datos a terceros salvo por obligación legal.
  5. Almacenamiento de los datos: Base de datos alojada en Occentus Networks (UE)
  6. Derechos: En cualquier momento puedes limitar, recuperar y borrar tu información.