← Gestión de Memoria Bloque 5 · Paginación · Tema 20 de 52

Tema 20

Tablas de páginas y sus bits

Una entrada de la tabla de páginas no solo guarda el marco físico: también tiene bits que controlan la protección y el estado de la página. En este tema verás qué significa cada bit (presente, R/W, U/S, accessed, dirty, NX), cómo se usan para proteger y cómo la ausencia de una página (presente=0) es la base de la memoria virtual.

1. Qué es una entrada de tabla (PTE)

La tabla de páginas es un array de entradas (PTE, page table entry). Cada entrada corresponde a una página virtual y contiene:

En x86-64, cada PTE ocupa 8 bytes (64 bits). Con páginas de 4 KiB y un espacio virtual de 256 TiB, la tabla plana tendría 236 entradas (64 GiB), por eso se usan tablas multinivel (tema 22).

2. Los bits principales

Los bits más importantes de una PTE en x86 (y similares en otras arquitecturas) son:

BitNombreSignificado
P (presente)Present1 = la página está en la RAM. 0 = no está (fallo de página).
R/WRead/Write0 = solo lectura. 1 = lectura y escritura.
U/SUser/Supervisor0 = solo núcleo. 1 = accesible desde el espacio de usuario.
A (accessed)AccessedEl hardware lo pone a 1 cuando se accede a la página. El SO lo usa para LRU aproximado.
D (dirty)DirtyEl hardware lo pone a 1 cuando se escribe en la página. Indica que hay que escribirla al disco al reemplazarla.

Estos bits son la base de la protección y de la memoria virtual. El hardware los consulta y modifica en cada acceso; el SO los lee y modifica al gestionar las páginas.

3. Otros bits: NX, global, PAT

BitNombreSignificado
NX (no-execute)No-Execute1 = la página no se puede ejecutar (W^X). Evita ejecutar código en datos.
G (global)Global1 = la traducción se mantiene en la TLB tras cambio de proceso. Usado para páginas del núcleo.
PATPage Attribute TableControla el tipo de caché de la página (write-back, write-through, etc.).
PSPage Size1 = página grande (2 MiB o 1 GiB) en tablas de nivel superior.

4. Cómo se usa para proteger

La MMU comprueba los bits en cada acceso:

  1. Presente: si es 0, se lanza un fallo de página (no hay acceso a la RAM).
  2. R/W: si es 0 y el acceso es de escritura, se lanza una excepción de protección.
  3. U/S: si es 0 y el proceso es de usuario, se lanza una excepción.
  4. NX: si es 1 y el acceso es de ejecución, se lanza una excepción.

Esto permite, por ejemplo, que el código sea r-x (R/W=0, NX=0) y los datos rw- (R/W=1, NX=1). Un intento de escribir en el código o de ejecutar datos provoca SIGSEGV.

5. Cómo se usa para memoria virtual

El bit presente es la base de la paginación por demanda:

Los bits accessed y dirty ayudan al sistema a decidir qué página reemplazar (LRU aproximado) y si hay que escribirla al disco.

6. Ejemplo numérico

Una PTE de 8 bytes en x86-64 con los siguientes bits:

CampoValorSignificado
Marco (f)0x1A3F2La página está en el marco 0x1A3F2.
Presente (P)1La página está en la RAM.
R/W1Lectura y escritura permitidas.
U/S1Accesible desde el espacio de usuario.
Accessed (A)1Se ha accedido a la página.
Dirty (D)0No se ha escrito (no hay que escribirla al disco).
NX1No ejecutable (datos).

La PTE completa (simplificada) sería: 0x1A3F200000000007 (marco en los bits altos, bits de control en los bajos).

7. Experimento en C

El programa siguiente simula una PTE y muestra cómo se interpretan los bits:

pte.c
#include <stdio.h>
#include <stdint.h>

typedef struct {
    uint64_t marco : 40;
    uint64_t reservado : 11;
    uint64_t nx : 1;
    uint64_t g : 1;
    uint64_t ps : 1;
    uint64_t d : 1;
    uint64_t a : 1;
    uint64_t pcd : 1;
    uint64_t pwt : 1;
    uint64_t us : 1;
    uint64_t rw : 1;
    uint64_t p : 1;
} PTE;

int main(void)
{
    PTE e = { .marco = 0x1A3F2, .p = 1, .rw = 1, .us = 1, .a = 1, .d = 0, .nx = 1 };
    printf("Presente: %d\\n", e.p);
    printf("R/W: %d (%s)\\n", e.rw, e.rw ? "rw" : "r");
    printf("U/S: %d (%s)\\n", e.us, e.us ? "user" : "supervisor");
    printf("Accessed: %d\\n", e.a);
    printf("Dirty: %d\\n", e.d);
    printf("NX: %d (%s)\\n", e.nx, e.nx ? "no-exec" : "exec");
    printf("Marco: 0x%lX\\n", (unsigned long)e.marco);
    return 0;
}
terminal · bits de una PTE
$ gcc -std=c17 -Wall -Wextra -o pte pte.c
$ ./pte
Presente: 1
R/W: 1 (rw)
U/S: 1 (user)
Accessed: 1
Dirty: 0
NX: 1 (no-exec)
Marco: 0x1A3F2Marco: 0x1A3F2

8. Probar con un simulador

Este simulador muestra una PTE con sus bits y permite modificarlos para ver el efecto en la protección.

Simulador · bits de una PTE

CampoValor
Marco
Permisos
¿Lectura permitida?
¿Escritura permitida?
¿Ejecución permitida?
¿Acceso desde usuario?
¿Está en RAM?

9. En Linux y x86 hoy

En Linux sobre x86-64, los bits de la PTE se gestionan por el núcleo. Las herramientas para inspeccionarlos:

El bit NX se controla con la política W^X y se configura en las tablas de páginas por el núcleo. El bit accessed lo usa el algoritmo de reemplazo (aproximación a LRU).

10. Resumen

11. Preguntas de repaso

Intenta responder cada una antes de abrir la respuesta.

1. ¿Qué indica el bit presente (P)?

Si la página está en la RAM (1) o no (0). Si es 0, se lanza un fallo de página.

2. ¿Qué controla el bit R/W?

Si la página es de solo lectura (0) o de lectura/escritura (1).

3. ¿Qué controla el bit U/S?

Si la página es accesible solo desde el núcleo (0) o también desde el espacio de usuario (1).

4. ¿Quién pone a 1 el bit accessed?

El hardware, cuando se accede a la página. El SO lo lee para aproximaciones a LRU.

5. ¿Quién pone a 1 el bit dirty?

El hardware, cuando se escribe en la página. Indica que hay que escribirla al disco al reemplazarla.

6. ¿Qué es el bit NX?

No-Execute: si es 1, la página no se puede ejecutar (política W^X).

7. ¿Cómo se usa el bit presente para memoria virtual?

Las páginas se marcan como no presentes al crear el proceso; se cargan en la RAM solo cuando se accede a ellas.

8. ¿Qué herramienta muestra los permisos por página en Linux?

pmap -X PID y /proc/PID/smaps.

Para practicar

  1. Configura una PTE con P=1, R/W=0, U/S=1, NX=0. ¿Qué accesos son válidos?
  2. Configura una PTE con P=0. ¿Qué ocurre al acceder?
  3. Explica cómo el bit accessed ayuda al algoritmo de reemplazo LRU.
  4. Explica cómo el bit dirty evita escrituras innecesarias al disco.
  5. Investiga cómo Linux usa el bit NX para la política W^X.
  6. Compara los bits de la PTE en x86 con los de otra arquitectura (ARM).
  7. Dibuja una PTE con todos sus bits y explica cada uno.