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.
14 comentarios, deja el tuyo
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 :).
No es una distribucion linux , es un kernel 😛 .
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 !
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.
Digno de mencionar que se pueden utilizar otros lenguajes , como Objective-C(++) , C++, D o Rust .
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.
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 .
En los 70 era bastante comun programar directamente sobre el hardware , sin SO .
Excelente… ahora solo me hace falta entender :3…
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!
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
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
Genio ! Tenia muchas ganas de hacer este tuto y me bajonie al principio con ese error jaja
Felicitaciones, es un excelente aporte. Desde ya te comparto que tu buen trabajo mediante mi persona y otros (as) se hará extendido;
Saludos