Ir al contenido

MMU y segmentación

🎯 Al terminar podrás

  1. Distinguir dirección lógica y física, y decir cuándo coinciden según el momento del binding.
  2. Traducir con base y límite: física = base + offset, solo si offset < límite.
  3. Partir una dirección en (segmento, offset) según los bits de cada parte, y detectar el segmentation fault (offset ≥ límite o s ≥ STLR).
  4. Comparar segmentación y paginación: quién divide el programa, qué fragmentación tiene cada una y si la traducción suma o concatena.

Antes necesitas: Binario y hexadecimal (agrupar de a 4 bits)

  • Visual mira el diagrama o la tabla y explica qué cambia en cada paso
  • Laboratorio sube la escalera: resuelto → completa → solo → variante
  • Simulador predice el estado antes de pulsar el paso siguiente
  • Lógica (virtual): la genera la CPU; es lo que ve el programa.
  • Física: la que ve la unidad de memoria.
  • Son iguales con binding en tiempo de compilación o carga, y distintas con binding en tiempo de ejecución.

Cada proceso (y el kernel) tiene su propio espacio de direcciones. La MMU traduce de la vista de la CPU a la vista de la memoria. Con traducción, la protección es fácil: si A ni siquiera puede nombrar los datos de B, no puede dañarlos. Además, todos los programas pueden enlazarse en la misma región virtual.

El esquema más simple es un registro base (llamado registro de relocalización), que se suma a cada dirección, más un registro límite para la protección:

fıˊsica=base+loˊgica,si loˊgica<lıˊmite\text{física} = \text{base} + \text{lógica}, \qquad \text{si } \text{lógica} < \text{límite}

Si no se cumple, se genera una trampa al SO. MS-DOS en 8086 usaba 4 registros de este tipo (CS, DS, SS y ES). En un cambio de contexto, el SO carga la base y el límite del nuevo proceso, que forman parte del PCB.

El programa se ve como un conjunto de segmentos lógicos de tamaño variable (código, datos, stack, compartido…). Cada dirección es un par (segmento, offset) y hay una tabla de segmentos con (base, límite, permisos) por entrada.

  • ✔ Refleja la estructura modular del programa, así que protección y compartición salen por segmento.
  • ✘ Los segmentos son de tamaño variable, así que hay fragmentación externa, como en las particiones dinámicas.

Arquitectura de la segmentación (diapositivas)

Sección titulada «Arquitectura de la segmentación (diapositivas)»
dirección lógica = (s, d)CPUs = 1d = 50STLR = 3cuántos segmentos haySTBRdónde está la tabla¿s < STLR?1 < 3 ✓notrap: s inválidosíSTBR + stabla de segmentos (en RAM)sVpermisoslímitebase01R-X500100011RW-200300020no válido——¿d < límite?50 < 200 ✓ · W ✓nosegmentation faultsí+base + dfísica3050

Se usa el ejemplo de arriba, (1, 50). El hardware hace dos controles antes de sumar. Primero mira si el segmento existe (s < STLR). Luego, en la entrada de la tabla, mira si es válida y si el permiso alcanza, y si el offset cabe (d < límite). Si algo falla, hay trampa al SO. Si todo pasa, física = base + d.

  • La dirección lógica es el par ⟨número de segmento s, offset d⟩.
  • STLR (Segment-Table Length Register) dice cuántos segmentos hay. STBR (Segment-Table Base Register) dice dónde está la tabla en la RAM. La entrada de s se encuentra en STBR + s.
  • Cada entrada guarda la base (dónde empieza el segmento en la RAM), el límite (cuánto mide), un bit de validez V (0 = segmento ilegal) y permisos R/W/X.

2. Lo que ve el programa vs dónde queda en la RAM

Sección titulada «2. Lo que ve el programa vs dónde queda en la RAM»
lo que ve el programa (lógica)memoria físicasegmento 0 · códigooffsets 0 … 499segmento 1 · datosoffsets 0 … 199segmento 2 · pilaoffsets 0 … 399cada segmento empieza en su offset 0y tiene su propio tamañoSOseg. 0huecoseg. 2huecoseg. 1hueco01000150020002400300032004000base 1000base 2000base 3000Los huecos entre segmentos son fragmentación externa.

Para el programa, cada segmento empieza en 0. En la RAM, los segmentos quedan donde haya espacio, en cualquier orden y sin estar juntos. Como miden distinto, ubicarlos es un problema de asignación dinámica (first-fit, best-fit…), igual que en las particiones dinámicas, y entre ellos quedan huecos.

tablas de segmentosmemoria físicaP1spermisosbaselím.0R-X40009001RW-6000300P2spermisosbaselím.0R-X40009001RW-7000250editor (código)4000 · compartidodatos de P1 · 6000datos de P2 · 7000Si P1 intenta escribir en su segmento 0 (no tiene W), la MMU da una violación de protección.

Dos procesos que usan el mismo editor apuntan su segmento de código a la misma base (4000). El código se carga una sola vez. Cada uno tiene sus datos propios. Como el permiso va por segmento, el código queda R-X (nadie lo puede modificar) y los datos RW-.

mov [es:bx], axla instrucción nombra el segmentoregistros de segmentoCS · códigoDS · datosSS · pilaES · extraFS, GSselector (16 bits)índiceTIRPLTI: 0 = GDT · 1 = LDTen CS, el RPL es el privilegio actual (CPL)GDT / LDT (en RAM)descriptorbase · límite · DPL· tipo · presente+base + bxoffset = bxdirección lineal→ luego, paginación

En x86, el segmento no sale de los bits de la dirección: lo nombra la instrucción, mediante un registro de segmento. El registro guarda un selector, que elige un descriptor de la GDT (global) o de la LDT (local del proceso). El descriptor aporta la base y el límite, y base + offset da la dirección lineal, que después pasa por la paginación.

  • En las diapositivas, el mapa de segmentos vive en el procesador. El segmento sale de los bits altos de la dirección, o de la propia instrucción (mov [es:bx], ax).
  • Las entradas marcadas N (no válidas) en el mapa disparan un error de acceso, como la fila V = 0 del diagrama 1.
  • En CS, el campo RPL del selector es el nivel de privilegio actual (CPL: 0 = kernel, 3 = usuario).

Ventajas para el programador (Stallings §8.1):

  1. Maneja estructuras que crecen: el SO agranda el segmento (o lo mueve o hace swap).
  2. Permite recompilar y enlazar módulos por separado.
  3. Facilita compartir (una utilidad o una tabla en su propio segmento).
  4. Facilita proteger (permisos por segmento).

La segmentación elimina la fragmentación interna y conserva la externa, aunque menor que en las particiones, porque los segmentos son más chicos que un proceso entero. Sí es visible para el programador o el compilador, que conocen el tamaño máximo de segmento.

Ejemplo de Stallings (fig. 7.11b): direcciones de 16 bits, con 4 bits de segmento y 12 de offset (segmentos de hasta 4096 B). 0001 001011110000 es el segmento 1, offset 752. Si la base del segmento 1 es 0010000000100000 (8224), la dirección física es 8224 + 752 = 8976 = 0010001100010000. Aquí sí hay una suma (en paginación basta concatenar) y se compara offset < largo.

El mapa del ejemplo de clase: el código queda en 0x4000–0x47FF, los datos en 0x4800–0x5BFF, el segmento compartido en 0xF000–0xFFFF (compartido con otras aplicaciones) y el stack en 0x0000–0x2FFF. El resto de la memoria física queda para otras aplicaciones.

Traducción con segmentación (dirección de 16 bits)

Los 2 bits altos eligen el segmento y los 14 bajos son el offset. La MMU comprueba offset < limit y calcula física = base + offset. Es la tabla de la diapositiva 37.

0
1
0
0
0
0
0
0
0
1
0
1
0
0
0
0
segmento = 01₂ = 1offset = 0x0050
SegNombreBaseLímite
0code0x40000x0800
1data0x48000x1400
2shared0xF0000x1000
3stack0x00000x3000
offset 0x0050 < límite 0x1400 ✔ → física = 0x4800 + 0x0050 = 0x4850

Tabla de la diapositiva 37 (direcciones de 16 bits: 2 bits de segmento | 14 bits de offset):

Seg.UsoBaseLímite
0código0x40000x0800
1datos0x48000x1400
2compartido0xF0000x1000
3stack0x00000x3000

Peldaño 1 · Resueltolee cada paso y su porqué

Resuelto: 0x8010

  1. Partir: 0x8010 = 10 | 00 0000 0001 0000. Segmento 2, offset 0x0010.
  2. Validar: ¿2 < STLR = 4? Sí. ¿0x10 < límite 0x1000? Sí.
  3. Sumar: 0xF000 + 0x10 = 0xF010.

Peldaño 2 · Complétalofaltan pasos clave: llénalos tú

Complétalo: 0x5000

El paso 1 ya está: 0x5000 = 01 | 01 0000 0000 0000, así que es el segmento 1. Completa: ¿cuál es el offset? ¿Pasa la validación? ¿Qué dirección física da?

Comparar

Offset = 01 0000 0000 0000 = 0x1000. Como 0x1000 < 0x1400, es válido. Física = 0x4800 + 0x1000 = 0x5800.

Peldaño 3 · Solosin ayuda; luego compara

Solo: 0xC100, 0x9200 y 0x47FF

Comparar (verificado con un script)
VirtualSeg.Offset¿Válido?Física
0xC10030x01000x100 < 0x30000x0100
0x920020x12000x1200 ≥ 0x1000segmentation fault
0x47FF10x07FF0x7FF < 0x14000x4FFF

0x47FF es la trampa: «parece» una dirección de código porque cae cerca de 0x4000, pero los 2 bits altos son 01 y por eso pertenece a datos. Nunca confundas una dirección virtual con una física.

Peldaño 4 · Variantecambia una condición: ¿sigue valiendo lo anterior?

Variante: la misma 0x5000, con 4 bits de segmento y 12 de offset (como en Stallings) y STLR = 4

Comparar

0x5000 = 0101 | 0000 0000 0000, así que ahora es el segmento 5, con offset 0. Como 5 ≥ STLR = 4, el segmento no existe y hay segmentation fault antes de mirar el offset. Lección: la misma dirección significa otra cosa si cambia cómo se reparten los bits. El primer paso siempre es fijar cuántos bits tiene cada campo.

  1. Fetch 0x0240 (0000 0010 0100 0000): segmento 0, offset 0x240 → física 0x4000 + 0x240 = 0x4240 → la $a0, varx → $a0 = 0x4050.
  2. Fetch 0x0244 → 0x4244 → jal strlen → $ra = 0x0248 y PC = 0x0360.
  3. Fetch 0x0360 → 0x4360 → li $v0, 0.
  4. Fetch 0x0364 → 0x4364 → lb $t0, ($a0): carga desde 0x4050 (0100 0000 0101 0000), que es el segmento 1, offset 0x50 → física 0x4800 + 0x50 = 0x4850.

Observa que la misma dirección 0x4050 es un dato virtual y no la física 0x4050, que caería dentro del segmento de código.

  • Modo real (8086): direcciones segmento:offset, segmentación intensiva.
  • Modo protegido (x86 de 32 bits): descriptores de segmento en la GDT/LDT (código, datos, stack…).
  • Modo largo (x86-64): la segmentación está prácticamente deshabilitada; base y límite se ignoran para código y datos. Solo FS y GS conservan significado:
    • FS: thread-local storage en espacio de usuario (glibc).
    • GS: variables per-CPU del kernel.
  • Linux ignora la segmentación y usa paginación como mecanismo principal, porque da aislamiento, memoria virtual y demand paging, cosas que la segmentación sola no maneja bien.

Autoevaluación

0/5 correctas · 0 respondidas
1. Con la tabla de la diapositiva 37, ¿a qué física va la virtual 0x8010?
2. ¿Qué pasa con 0x0900 (segmento 0, límite 0x800)?
3. La segmentación sufre de…
4. En x86-64 con Linux, ¿para qué se usa FS?
5. Las direcciones lógica y física difieren cuando el binding es en tiempo de…

📈 ¿Qué tan bien lo dominas?

Elige pensando en lo que hiciste, no en lo que leíste. Para marcar 3 tienes que haber resuelto un ejercicio nuevo sin pistas y haberlo justificado. Si solo lo leíste y sientes que «ya entendí», todavía es un 1.

Fuente ·for_partial/pending_themes/Sem06_06-OST-Memory.pdf (diap. 8–10, 24–40) · Stallings cap. 7 · Love, Linux Kernel Development