Solucionadas regresiones

Tras los cambios realizados hace unos días, en los que se resolvió el fallo cuando se hacía uso de una única cpu, se produjeron algunas regresiones relacionadas con la configuración de la paginación:

  • Al desactivar la paginación (integración de los procesadores incluida), dejando únicamente la segmentación, los procesadores no arrancaban.

    Se ha arreglado, y el sistema consigue arrancar cualquier número de procesadores, sin integrarlos al sistema (tal como estaba previamente)

  • Al desactivar la integración de los procesadores, con la paginación activa, el primer AP finalizaba su hilo y lanzaba una excepción, provocando un dump que colgaba el sistema (https://github.com/AlmuHS/GNUMach_SMP/issues/7)

    Para solucionarlo, hemos añadido una instrucción `hlt` que detiene el procesador en caso de no integrarse al sistema.

Tras esto, quedan resueltos varios casos clave que, a pesar de no corresponder a situaciones habituales, podrían producir problemas en ciertos casos.

Quedan aún por solucionar los problemas con el arranque del sistema con mas de 2 procesadores (con paginación e integración al kernel de los mismos), y los problemas de concurrencia tras la integración de los procesadores al kernel; de los cuales nos encargaremos próximamente.

Si tenéis interés en el proyecto, podéis ver los issues abiertos en este enlace: https://github.com/AlmuHS/GNUMach_SMP/issues

 

Anuncios

Recuperado arranque con una sola cpu

Tras revisar el historial de versiones, hemos encontrado la causa del error que impedía el arranque con una sola cpu.

Una llamada a `interrupt_stack_alloc()` añadida en este commit, producía el cuelgue del sistema al poco de comenzar su arranque

https://github.com/AlmuHS/GNUMach_SMP/commit/57756f1a94f21a67047c0194d666c49851b646dc#diff-1d86b385eeadacaec9a03188638c9af1R514  

Tras eliminar dicha llamada, el sistema vuelve a arrancar con una sola cpu, completando el arranque de forma exitosa. Además, podemos comprobar como, el sistema recién arrancado, responde correctamente.

También hemos hecho algunas mejoras, consiguiendo que la Local APIC se mapee incluso cuando hay una sola cpu, y que la desactivación del mapeado temporal también se aplique en este caso.

Además, hemos corregido algunos errores en la asignación de las pilas de los AP, y quitado la función `dummyf()` que se invocaba durante el envío de las IPI a los procesadores.

Podemos ver los cambios en la siguiente release
https://github.com/AlmuHS/GNUMach_SMP/releases/tag/0.0.10

 

 

Probando Hurd SMP (y Hurd) en hardware real

Tras probar Hurd SMP en Qemu y VirtualBox, hemos decidido repetir la prueba en equipos reales, para asegurar su funcionamiento correcto.

  • Ordenador de sobremesa HP CompaqHace unos meses logramos realizar una prueba, instalando Debian GNU/Hurd sobre un ordenador de sobremesa basado en un procesador Intel Core2Duo E8300, con 4 GB de RAM, y ejecutando el microkernel SMP sobre él.hpEsta prueba se realizó sin paginación, y antes de integrar los procesadores al sistema, por lo que el funcionamiento no es exactamente igual al actual.El entorno de dicha prueba es el que se indica en esta otra entrada:
    https://hurdsmp.wordpress.com/2019/04/21/avances-en-la-integracion-de-las-cpus/

    El vídeo de esta prueba se puede ver aquí:

    La prueba con el microkernel modificado fue un éxito, aunque el funcionamiento general del sistema en ese equipo era muy inestable; por lo que decidimos descartar dicho equipo

  • Thinkpad T60

    Hace dos días, repetimos la prueba con un Thinkpad T60, con un Intel Core Duo T2300.Esta vez, la prueba la hicimos con la última versión (incluyendo algunas modificaciones de la rama wip), con paginación e integrando los procesadores al sistema.En esta versión, el microkernel logra iniciar el sistema sin tarjeta de red, pero la tty no recibe entrada de teclado, por lo que el sistema queda inaccesible.La prueba en el Thinkpad T60 va acorde a lo esperado: su tarjeta de red no dispone de driver dentro de Mach, por lo que el netdde falla y arranca sin servicios de red. Y, tal como ya se había comprobado en las pruebas sobre máquina virtual, el sistema logra arrancar, pero la tty no responde al teclado.El vídeo de la prueba se puede ver aquí:

    También hemos aprovechado para hacer algunas pruebas con el microkernel original, abriendo un entorno de escritorio LXDE

    Las pruebas han sido un éxito: el cursor se mueve con fluidez sobre el escritorio, y se puede navegar de forma relativamente cómoda usando el navegador web Midori.

  • Thinkpad R60e

    Seguidamente, hemos repetido la prueba con un Thinkpad R60e, de la misma generación que el anterior, de gama mas baja. Este cuenta con un procesador Intel Core Duo T2400. En este caso, la instalación de Debian GNU/Hurd ha sido mas problemática, teniendo que reinstalar en varias ocasiones. También se ha percibido una lentitud mucho mayor a la del Thinkpad T60.Probándolo con el microkernel SMP, el resultado ha sido muy similar al del Thinkpad T60, arrancando e integrando los procesadores, pero fallando la tty tras el arranque del sistema.El vídeo del arranque del Hurd SMP lo podéis ver aquí:

    En este también hemos realizado las pruebas con el escritorio LXDE con el microkernel por defecto: estas pruebas han sido mas problemáticas, requiriendo varios intentos para arrancar el entorno.Las imágenes de esta prueba son las siguientes:

    En este caso, las pruebas no han sido tan satisfactorias: el escritorio funciona con bastante lentitud, teniendo que esperar casi un minuto para la apertura de cada aplicación.  El navegador Midori se colgaba al arrancar, por lo que se ha tenido que recurrir al navegador Arora para realizar la prueba del acceso a una página web.Este modelo no contaba con touchpad, por lo que se ha utilizado el trackpad, que ha funcionado sin problemas.

Pequeños arreglos y refactorizaciones

Mientras intentamos localizar la causa del fallo con mas de 2 cpus, hemos realizado algunas pequeñas reparaciones y refactorizaciones en el código.

  • En primer lugar, hemos movido el código que activa la paginación a una función en C, recuperando las llamadas originales provenientes de model_dep.c

    El código resultante se ha añadido a una nueva función, llamada paging_setup(), que se invoca desde cpuboot.S justo antes de llamar a cpu_ap_main(), quien se encarga de iniciar el resto de configuraciones de la cpu.

  • En segundo lugar, hemos retirado una instrucción pushl innecesaria, que provocaba que todos los AP compartieran el mismo valor en EIP, la pila del procesador. Tras esta modificación, cada cpu tiene su propio EIP, asegurando así que cada cpu tenga su propia pila.

Estas modificaciones no han provocado ninguna variación significativa en el comportamiento del sistema, que sigue manteniendo los problemas anteriores de concurrencia y problemas al usar ncpus <> 2.

Próximamente iniciaremos la depuración exhaustiva del código, para intentar encontrar la causa que provoca el fallo del arranque con mas de 2 cpus.

Integradas cpus en el microkernel

Tras varios meses de trabajo, hemos logrado incorporar las cpus al microkernel, y que empiecen a trabajar junto a la cpu principal.

Para ello, hemos tenido que activar la paginación en los procesadores AP, para posibilitar que la cpu pueda acceder al puntero de la Local APIC, y así ejecutar la función cpu_number(), necesaria para que la función slave_main() añada el AP al microkernel.

Para activar la paginación, es necesario inicializar los registros CR0, CR3 y CR4; indicando la dirección del directorio de páginas (CR3), las opciones especiales utilizadas en Mach (CR4), y activando el uso de la paginación (CR0).

Este proceso se ha realizado utilizando como base el código indicado en model_dep.c, que realiza la configuración de la paginación en el procesador principal (BSP); y la rutina cpuboot.S, que se lanza justo después de la startup IPI, y ya estábamos usando para pasar la cpu de modo real a modo protegido.

El código resultante se ha incorporado cpuboot.S. Debido a problemas con la inicialización del registro CR0, hemos tenido que hardcodear sus valores.

Debido a que Mach usa segmentación con base en 0xC0000000, es necesario hacer uso de un mapeado temporal, que remapea las direcciones a partir de 0xC0000000 en las direcciones 0x00000000 en adelante. Para conseguirlo, hemos mantenido el mapeado temporal ya realizado en model_dep.c (para el procesador principal), desplazando su desactivación hasta el final del arranque de las cpus, en start_other_cpus().

Tras esto, la paginación ya se activa correctamente, y es capaz de acceder correctamente a las posiciones indicadas por los punteros.

Pero el procesador todavía conserva las GDT e IDT temporales, con lo cual no puede cargar las LDT necesarias para incorporarse al kernel. Para resolverlo, hemos añadido dos llamadas, a gdt_init() e idt_init(), en la función cpu_setup(), ejecutada por el AP justo después de la rutina cpuboot.S.

Tras completar estos pasos, ya hemos podido reactivar la llamada a la función slave_main(), dentro de la misma función cpu_setup(), esta vez de forma exitosa.

Finalmente, después de todo este trabajo, las cpus parecen haberse incorporado correctamente al kernel, y funcionar correctamente. Pero, debido a la falta de control de la concurrencia en varias cpus, varios servicios fallan durante el arranque.

Con una tarjeta de red incompatible con Mach, el netdde falla y nos permite arrancar, aunque la pantalla de bienvenida no responde a las ordenes del teclado.

Con una NIC compatible, el proceso DHCP se cuelga, bloqueando el arranque. Configurando IP fija para evitar el DHCP, el arranque avanza un poco mas, pero se termina bloqueando al cargar el ssh

Durante el desarrollo también se han generado dos nuevos problemas: el arranque se detiene al usar una única cpu, y al usar mas de 2 cpus.

Los siguientes pasos tratarán de controlar la concurrencia de los hilos, introduciendo exclusión mutua; hacer algunas mejoras y refactorizaciones en el código para mejorar su funcionamiento; y resolver los problemas en ncpu = 1 o ncpu > 2.

Mejorada reserva de memoria en las pilas de las CPUs

Hace unos días, tras una revisión atenta del código, nos dimos cuenta de que la técnica usada para la reserva de memoria de las cpus podría provocar que la pila de una cpu sobreescribiese a la de otra, así que decidimos mejorarla. Para ello, nos hemos basado en la técnica utilizada en las pilas de interrupción, en la función ​`​interrupt_stack_alloc()` basada en un array de punteros a pilas, con una posición por cpu.

Utilizando esta técnica, hemos vuelto a conseguir que Hurd SMP funcione en VirtualBox, arrancando las cpus de forma correcta.

Los próximos pasos se encargarán de mejorar la copia en memoria de la rutina ensamblador de la startup IPI, y de activar la paginación dentro de los AP.

 

Resueltas algunas erratas

Tras revisar el código de cpuboot.S añadido ayer, hemos corregido algunas erratas en el mismo, eliminando código innecesario y corrigiendo algunas situaciones anómalas.

  • En primer lugar, hemos eliminado el código referente al iplt, que ya estaba siendo inicializado en boothdr.S, y por tanto era innecesario.
  • También hemos eliminado la carga de la pila de interrupciones, dado que estaba sobreescribiendo la carga anterior de la pila principal de la cpu; aunque hemos dejado su declaración.
  • Y hemos corregido una pequeña errata en el cálculo del desplazamiento en la pila principal.

Con estos cambios, el código ya no funciona en VirtualBox (se puede solucionar temporalmente cambiado la carga de la pila principal stack_ptr, por la de la pila de interrupciones, _intstack, aunque no es una solución definitiva)

En lo que respecta al funcionamiento, estas correcciones no han alterado el funcionamiento actual del sistema, que sigue mostrando el número real de cpus existentes en la máquina, con el comando nproc

nproc_hurd2