Labs de xv6 del MIT: P3, P5 y bono

Tres proyectos del curso usan laboratorios del curso 6.1810 Operating System Engineering del MIT (otoño 2025). Corren sobre xv6-riscv, el mismo kernel de P2, y traen su propio código de partida y sus propias pruebas (make grade). Los enunciados del MIT están en inglés y son la referencia oficial; aquí van un resumen, la versión exacta que usamos y cómo entregar.

Proyecto Lab del MIT Enunciado Rama Commit fijado Semanas
P3 Tablas de páginas pgtbl pgtbl cff452f8f70f46e9b22f815fc879242ebe5eacd6 8 → 10
P5 Sistema de archivos fs fs a95dec46d4443c579f47e793e7d731cce2d34388 13 → 16
Bono Fork con copy-on-write cow cow cf0eb5bdaaa24f3a46a80d2702af3c9e260c2692 11 → 16

Antes de empezar cualquiera de los tres, lean la página de orientación del MIT (cómo depurar, qué hacer cuando el kernel entra en pánico) y repasen el calentamiento con gdb de P2.

Preparar el código

Todo se hace dentro del contenedor del curso. Desde la carpeta so/ (la que se monta en /work):

./curso/env/run.sh                 # abre una shell en el contenedor
git clone git://g.csail.mit.edu/xv6-labs-2025
cd xv6-labs-2025
git config user.name "Nombre Apellido"     # una sola vez por repositorio
git config user.email "correo@uni.pe"

Sin esas dos líneas, git commit falla dentro del contenedor: el contenedor se borra al salir y no guarda una configuración global de git.

Cada lab vive en su propia rama. Creen una rama local con el nombre del lab, a partir del commit fijado (así todos trabajan sobre el mismo código, aunque el MIT actualice la rama durante el semestre):

git checkout -b pgtbl cff452f8f70f46e9b22f815fc879242ebe5eacd6   # P3
git checkout -b fs    a95dec46d4443c579f47e793e7d731cce2d34388   # P5
git checkout -b cow   cf0eb5bdaaa24f3a46a80d2702af3c9e260c2692   # bono
make clean
make qemu                          # salir con Ctrl-a x

Si ya avanzaron en un lab y van a cambiar de rama, primero hagan commit de su trabajo. Si la red de la universidad bloquea el protocolo git:// (puerto 9418), el docente publicará una copia del repositorio por otro medio.

Correr las pruebas

make grade

make grade hace make clean, compila, arranca xv6 varias veces sin interfaz gráfica y compara la salida con lo esperado. Al final imprime Score: N/M. Sobre el código sin modificar casi todo falla; eso es lo normal. Para correr una sola prueba, pasen su nombre (tal como aparece en el archivo grade-lab-*):

make GRADEFLAGS=simple grade       # solo la prueba "simple" de cow
  • No corran make grade mientras tengan otro make qemu abierto en la misma carpeta.
  • Las tres rutinas de prueba piden un archivo time.txt con un solo número entero: las horas que les tomó el lab. pgtbl además pide answers-pgtbl.txt con sus respuestas a las preguntas del enunciado; pueden responder en español.
  • En los labs fs y cow, usertests -q es parte de make grade. Con el código terminado, las pruebas de fs tardan varios minutos (bigfile escribe un archivo de 64 MB).

P3 — Tablas de páginas (pgtbl)

Qué pide. Trabajar directamente con las tablas de páginas (page tables) de tres niveles de RISC-V (Sv39):

  1. Inspeccionar la tabla de páginas de un proceso de usuario con el programa pgtbltest y explicar, para cada entrada (PTE), qué contiene esa página y qué significan sus bits de permiso.
  2. Acelerar getpid(): al crear cada proceso, mapear en la dirección USYSCALL una página de solo lectura para el usuario que guarde su PID. Así ugetpid() obtiene el PID sin entrar al kernel. Hay que crear, mapear y liberar esa página en los mismos puntos del ciclo de vida del proceso que el trapframe (kernel/proc.c).
  3. Imprimir una tabla de páginas: implementar vmprint() en kernel/vm.c, que recorre el árbol de tres niveles y muestra cada PTE válida con su nivel de indentación, su dirección virtual y la física.
  4. Superpáginas (superpages): cuando un proceso pide 2 MB o más con sbrk(), usar páginas de 2 MB alineadas en lugar de cientos de páginas de 4 KB. Implica reservar bloques de 2 MB en kernel/kalloc.c, y manejarlos en fork (copia), exit (liberación) y al reducir la memoria (partir una superpágina en páginas normales).

Pruebas. pgtbltest (ugetpid, print_kpgtbl, superpg), answers-pgtbl.txt y time.txt.

Se apoya en. Semanas 5–8: espacios de direcciones, traducción de direcciones, paginación (sem. 6), TLB y tablas de páginas multinivel (sem. 7) y memoria virtual completa (sem. 8). La experiencia con llamadas al sistema y con kernel/proc.c de P2. Lectura: capítulo 3 del libro de xv6 y los archivos kernel/memlayout.h, kernel/vm.c y kernel/kalloc.c.

P5 — Archivos grandes y enlaces simbólicos (fs)

Qué pide. Dos extensiones al sistema de archivos (file system) de xv6:

  1. Archivos grandes. Hoy un inodo (inode) tiene 12 bloques directos y uno indirecto simple, así que un archivo llega a 12 + 256 = 268 bloques. Hay que cambiar uno de los directos por un bloque doblemente indirecto (256 bloques indirectos de 256 entradas cada uno), sin cambiar el tamaño del inodo en disco. El máximo pasa a 11 + 256 + 256·256 = 65 803 bloques. El trabajo está en bmap() (traducir el número de bloque lógico del archivo a un bloque del disco, reservando bloques a medida que se necesitan) y en itrunc() (liberarlos todos), en kernel/fs.c, junto con las constantes de kernel/fs.h y kernel/file.h.
  2. Enlaces simbólicos (symbolic links). Agregar la llamada al sistema symlink(target, path), un tipo de archivo nuevo T_SYMLINK y una opción O_NOFOLLOW para open(). Al abrir un enlace, open() debe seguirlo (también si apunta a otro enlace), detectar ciclos con un límite de profundidad y fallar si el destino no existe. Con O_NOFOLLOW se abre el enlace mismo. link() y unlink() no siguen enlaces.

Pruebas. bigfile, symlinktest, usertests -q y time.txt. Hay que agregar symlinktest a UPROGS en el Makefile.

Se apoya en. Semana 13 (API de archivos y directorios, enlaces duros y simbólicos) y semana 14 (implementación de un sistema de archivos: inodos, bloques indirectos, bitmaps; y journaling, que en xv6 es el log de kernel/log.c con begin_op() y end_op()). En el laboratorio de la semana 14 ya dibujaron el formato del disco de xv6 y ubicaron bmap(). Lectura: capítulo 10 (“File system”) del libro de xv6.

Bono — Fork con copy-on-write (cow)

Qué pide. Que fork() no copie la memoria del padre. En lugar de eso:

  1. uvmcopy() (kernel/vm.c) mapea en el hijo las mismas páginas físicas del padre y quita el permiso de escritura en ambos. Conviene marcar esas PTE como copy-on-write, por ejemplo con uno de los bits RSW que RISC-V reserva para el software.
  2. Cuando alguno de los dos escribe, ocurre un fallo de página (page fault). El kernel reconoce que es una página copy-on-write, reserva una página nueva, copia el contenido y la mapea con escritura. Las páginas que eran de solo lectura desde el principio (el código) siguen compartidas, y escribir en ellas mata al proceso.
  3. Como una página física puede estar en varias tablas de páginas, se lleva un contador de referencias por página en kernel/kalloc.c: kfree() solo la devuelve a la lista libre cuando el contador llega a cero. El contador se modifica desde varias CPUs, así que necesita un lock.
  4. copyout() debe tratar las páginas copy-on-write igual que un fallo de página.
  5. Si no hay memoria para la copia, se mata al proceso (no se entra en pánico).

Pruebas. cowtest (simple, three, file y forkfork), usertests -q y time.txt. Sin modificar, cowtest falla de inmediato porque simple reserva más de la mitad de la memoria y luego hace fork().

Se apoya en. fork/exec (semana 2), paginación y fallos de página (semanas 6–8; copy-on-write aparece en la semana 8 con VAX/VMS) y locks (semana 10) para el contador de referencias. Es el lab que más integra: tiene lugar entre la semana 11 y la 16 y conviene empezarlo apenas termine P3. Lectura: capítulo 5 (“Page faults”) del libro de xv6, kernel/trap.c (usertrap()) y vmfault() en kernel/vm.c.

Cómo entregar

  1. Hagan commit de todo su trabajo en la rama del lab, incluidos time.txt, answers-pgtbl.txt (solo P3) y un README.md corto en la raíz con los integrantes, qué funciona y qué no, y sus decisiones de diseño.

  2. Verifiquen con make grade dentro del contenedor.

  3. Generen el archivo de entrega:

    make zipball

    Esto crea lab.zip con el último commit (git archive HEAD). Si les avisa de cambios sin commit o de archivos sin seguimiento (??), hagan git add y git commit de lo que su solución necesita y repitan.

  4. Entreguen lab.zip en la semana indicada en el calendario.

Las pruebas se corren con el make grade de la misma versión fijada. Además se revisa el código y puede haber una defensa oral breve, como en los demás proyectos (ver projects/README.md).

No publiquen sus soluciones en repositorios públicos: el MIT pide lo mismo a sus estudiantes y estos labs se reutilizan cada año.