Desarrollo de un sistema operativo monolítico tipo Unix: primeros pasos (1)

En relación con las críticas negativas del artículo de prueba "Desarrollo de un programador OC de Microkernel tipo Unix", decidí reiniciar la serie de artículos, teniendo en cuenta algunos comentarios. Ahora, al darme cuenta de mi público objetivo, pude cambiar el enfoque de mi especie a aquellos que realmente lo necesitan.

Respuestas a comentarios al artículo anterior.


Observación 1. El planificador es demasiado simple.

Desde la publicación del artículo anterior, el código ha cambiado mucho. Se formó un núcleo completo, que dejó de ser micronuclear. Hay soporte para disco RAM inicial (sistema de archivos del núcleo), soporte para memoria virtual (MMU). Ha sido posible para el núcleo escribir programas personalizados. Hubo llamadas al sistema y la biblioteca clib (stdio, string). Entonces, el shell /initrd/sh.elf es un programa separado que es analizado por el gestor de arranque elf y se ejecuta como un proceso.

Lista de comandos de shell: exec <file.elf>, ps, kill, exit. En este caso, el shell se puede iniciar desde el mismo shell (demostrando multitarea).

Nota 2. Demasiada magia detrás de escena en los videos tutoriales.

Decidí resaltar el texto que estoy explicando actualmente. También se dirigió a principiantes que necesitan aclaraciones y las cosas más simples. Honestamente, me sorprendió que los recién llegados que no tienen experiencia en programación estén interesados ​​en un tema tan complejo, aunque es un pecado esconderlo, comencé desde eso. Cambié el sesgo de explicar mi sistema operativo a explicar cómo escribir su OC.

Observación 3. ¿Dónde está el enlace a github ?

Ahora ella es. En la descripción del video en YouTube (sí, quiero que no pases por alto mis lecciones en video, al menos mira un ojo).

Observación 4. Debemos comenzar con el ensamblaje primero.

Eso es lo que haremos.

Observación 5. No escribes nada, solo comentas.

Sí, fue un error hablar de algo grande de inmediato. Ahora nos moveremos paso a paso, gradualmente, comenzando con el kernel Hello world más simple. Los videos tutoriales le permitirán crear una imagen holística del mundo, y el código fuente en el github lo sumergirá en los detalles.

Tabla de contenidos.


1. Sistema de construcción (marca, gcc, gas). Arranque inicial (arranque múltiple). Lanzamiento (qemu). Biblioteca C (strcpy, memcpy, strext).
2. Biblioteca C (sprintf, strcpy, strcmp, strtok, va_list ...). Creación de la biblioteca en modo kernel y modo de aplicación de usuario.
3. El registro del sistema del núcleo. Memoria de video Salida a la terminal (kprintf, kpanic, kassert).
4. Memoria dinámica, un montón (kmalloc, kfree).
6. Organización de la memoria y manejo de interrupciones (GDT, IDT, PIC, syscall). Excepciones
5. Memoria virtual (directorio de páginas y tabla de páginas).
6. El proceso. Planificador Multitarea Sistema de llamadas (kill, exit, ps).
7. El sistema de archivos del kernel (initrd), elf y sus componentes internos. Sistema de llamadas (exec).
8. Controladores de dispositivos de caracteres. Llamadas del sistema (ioctl, fopen, fread, fwrite). Biblioteca C (fopen, fclose, fprintf, fscanf).
9. El shell como un programa completo para el kernel.
10. Modo de protección del usuario (anillo3). Segmento de estado de la tarea (tss).

Vamos Parte 1. Construir sistema y lanzar


En el artículo enumeraré solo los pasos clave . Para obtener una explicación detallada, consulte el video tutorial de este artículo.

Necesitas Linux Recopilaremos buenas marcas antiguas. Para compilar el archivo ejecutable del núcleo, se necesitan los siguientes indicadores:

CC_FLAGS=-g -m32 -isystem $(IDIR) -I include -DKERNEL=1 -fno-stack-protector -Wall -Werror -fno-pie AS_FLAGS=-g --32 LD_FLAGS=-m elf_i386 

Como emulador de hardware, instale el emulador qemu en Linux. Vamos a ejecutar nuestro núcleo de esta manera:

 qemu-system-i386 -kernel ./bin/kernel.elf 

También requerirá un pequeño script para el enlazador. Es necesario para cargar secciones en la dirección correcta y en el orden correcto. También en él indicaremos el punto de entrada:

 OUTPUT_FORMAT(elf32-i386) ENTRY(start) SECTIONS { . = 0x100000; .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } } 

Dado que el kernel se cargará de acuerdo con la especificación de arranque múltiple, el encabezado se requerirá al comienzo de la sección de código:

 .code32 .text # multiboot spec .align 4 multiboot: .long 0x1BADB002 # magic .long 0x00 # flags .long -(0x1BADB002 + 0x00) # checksum. m+f+c should be zero 

Se recomienda que cambie inmediatamente a su propia pila y configure una tabla de descriptores globales. Definir nuestra propia pila:

 .bss .fill 8192,1 # 8Kb stack: 

Escribe un punto de entrada. Es posible que la sintaxis del ensamblador gnu sea inusual. Una vez también preferí la sintaxis de Intel, luego de haberla probado, profundizando en el código fuente de Linux, preferí completamente la sintaxis de AT&T. Lo principal para recordar es que tienen los operandos opuestos. El resto será intuitivo.

 start: cli movl $stack,%esp push %esp push %ebx /* address of struct multiboot_t */ call kernel_start /* should never return */ hlt 

Esto completa el código repetitivo. La diversión comienza. Ahora podemos escribir el código en C. Y antes que nada, definiremos el mensaje de saludo.

 char *hello = "Hello world!"; int screen_size = 80 * 25; 

A continuación, escribimos el punto de entrada al que el código del ensamblador transferirá el control:

 /* * Api - Kernel entry point */ extern void kernel_start(struct multiboot_t* multiboot, void* kstack) { char *video = (char*)0xB8000; char buff[screen_size + 1]; video[screen_size] = '\0'; memset(buff, ' ', screen_size); strext(video, buff, 0x7); strext(video, hello, 0x7); } 

Aquí simplemente mostramos el mensaje en la pantalla. En principio, puede copiar completamente el código de la primera lección, ya que es una plantilla y nunca se cambiará. Para mostrar algo en la pantalla, solo necesita escribirlo directamente en la memoria de video, complementando cada carácter con un símbolo de atributo. Para hacer esto, necesitará su propia biblioteca C, que escribiremos nosotros mismos para nuestras necesidades. Por lo tanto, será más fácil controlar el proceso. Entonces, por ejemplo, hoy tenemos a nuestra disposición 2 funciones familiares (strcpy, memcpy) y una de nuestro propio strext para insertar el byte de atributo después de cada carácter.

Conclusión


Eso es todo por hoy. Mire el video tutorial e intente hacer lo mismo por su cuenta. Si no funciona, puede echar un vistazo a las fuentes de la lección en el github. Enlace a github en la descripción del video tutorial:

Literatura



1. James Molloy. Haga rodar su propio sistema operativo de clones UNIX.
2. Dientes. Ensamblador para DOS, Windows, Unix
3. Kalashnikov. ¡Ensamblador es fácil!
4. Tanenbaum. Sistemas operativos Implementación y desarrollo.
5. Robert Love. Kernel de Linux Descripción del proceso de desarrollo.

Source: https://habr.com/ru/post/466365/


All Articles