I. Introducción
Desde el comienzo de este artículo, ingresamos a la parte de memoria del estudio. Primero, seguiré las tareas anteriores para task_struct
explicar la estructura de administración del espacio de tareas mm_struct
y presentaré brevemente el conocimiento relevante de la memoria física y la memoria virtual. Para obtener conocimientos y conceptos básicos detallados, consulte el libro CSAPP. No entraré en demasiados detalles aquí, pero el Aprendizaje basado en la comprensión de su relación cartográfica. En el siguiente artículo, continuaremos presentando la administración de la memoria física y el mapeo de memoria del modo de usuario y el modo de kernel.
2. Conceptos básicos de peinado
- La arquitectura de CPU, caché, memoria y memoria principal se deriva del hecho de que cuanto más rápido es el dispositivo, más caro, por lo que en aras de la economía (qiong), la arquitectura multicapa está diseñada y la CPU tiene MMU
- La memoria física es limitada y existen problemas de seguridad en el uso compartido de la memoria física de múltiples procesos, por lo que aparece el diseño de la memoria virtual
- La memoria virtual está diseñada de acuerdo con la estructura de ELF, y hay partes como montón, área de mapeo, pila, segmento de datos, etc.
- Teniendo en cuenta la estructura de la memoria virtual, existe una aplicación de pila que es memoria dinámica
- La memoria virtual asigna un espacio de direcciones separado para cada proceso y lo asigna a la memoria física para su ejecución, por lo que existe un método de asignación para la memoria física y la memoria virtual: página
- Para administrar la memoria virtual, aparecen tablas de páginas y tablas de páginas de varios niveles
- Para acelerar el mapeo, apareció el TLB en la CPU
- Para satisfacer las necesidades de compartir, apareció la memoria compartida en el mapa de memoria
- Debido a la existencia de fragmentación de la memoria, apareció un diseño de gestión de fragmentos y un recolector de basura
3. Gestión de la memoria de procesos
Para un proceso, es necesario considerar las diversas estructuras que deben almacenarse en el kernel en modo usuario y modo kernel.
El modo de usuario incluye
- Fragmento de código
- Variable global
- Cadena constante
- Pila de funciones, incluidas llamadas a funciones, variables locales, parámetros de funciones, etc.
- Montón: memoria asignada por malloc, etc.
- La asignación de memoria, como
glibc
elglibc
código de llamada , tiene la forma de archivo, por lo que también debe colocarse en la memoria.
El modo Kernel incluye
- Parte del kernel del código
- Variables globales en el kernel
- estructura_tarea
- Pila de kernel
- También hay memoria asignada dinámicamente en el kernel
- Tabla de asignación de dirección virtual a dirección física
El proceso se task_struct
gestiona en modo kernel y la task_struct
memoria tiene las siguientes variables miembro
struct mm_struct *mm;
struct mm_struct *active_mm;
/* Per-thread vma caching: */
struct vmacache vmacache;
La mm_struct
estructura también es más complicada, la presentaremos paso a paso. Primero, echemos un vistazo a la división de direcciones entre el modo kernel y el modo de usuario. Aquí se highest_vm_end
almacena la dirección máxima de la dirección de memoria virtual actual, pero task_size
el tamaño del modo de usuario.
struct mm_struct {
......
unsigned long task_size; /* size of task vm space */
unsigned long highest_vm_end; /* highest vma end address */
......
}
task_size
La definición es la siguiente. De los comentarios, se puede ver que el modo de usuario asigna espacio 3G en la memoria virtual 4G, y debido a que el espacio de 64 bits es enorme, se reserva un área libre entre el modo kernel y el modo de usuario para el aislamiento. El modo de usuario usa solo 47 bits, que es 128TB. El modo kernel también asigna 128TB, que es el bit más alto.
#ifdef CONFIG_X86_32
/*
* User space process size: 3GB (default).
*/
#define TASK_SIZE PAGE_OFFSET
#define TASK_SIZE_MAX TASK_SIZE
/*
config PAGE_OFFSET
hex
default 0xC0000000
depends on X86_32
*/
#else
/*
* User space process size. 47bits minus one guard page.
*/
#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)
#define TASK_SIZE (test_thread_flag(TIF_ADDR32) ? \
IA32_PAGE_OFFSET : TASK_SIZE_MAX)
......
3.1 Estructura de la memoria del modo de usuario
En el modo de usuario, mm_struct
existen las siguientes variables miembro
mmap_base
: La dirección de inicio del mapa de memoriammap_legacy_base
: Indica la dirección base del mapeo, que está fija en 32 bitsTASK_UNMAPPED_BASE
, y en 64 bits, hay un mecanismo de mapeo aleatorio de direcciones virtuales , por lo que esTASK_UNMAPPED_BASE + mmap_rnd()
hiwater_rss
: Alto uso de agua de RSShiwater_vm
: Uso de memoria virtual de alto niveltotal_vm
: Número total de páginas asignadaslocked_vm
: El número de páginas que están bloqueadas y no se pueden intercambiarpinned_vm
: El número de páginas que no se pueden intercambiar ni moverdata_vm
: El número de páginas que almacenan datosexec_vm
: El número de páginas que almacenan archivos ejecutablesstack_vm
: El número de páginas que almacenan la pilaarg_lock
: Introducidospin_lock
para proteger el acceso paralelo a las siguientes variables de áreastart_code 和 end_code
: Posición inicial y final del código ejecutablestart_data 和 end_data
: Posición inicial y posición final de los datos inicializadosstart_brk
: La posición inicial del montónbrk
: La posición final actual del montónstart_stack
: La posición inicial de la pila, la posición final de la pila está en el puntero superior del registro.arg_start 和 arg_end
: La posición de la lista de parámetros, ubicada en la dirección más alta de la pila.env_start 和 env_end
: La ubicación de la variable de entorno, ubicada en la dirección más alta de la pila.
struct mm_struct {
......
unsigned long mmap_base; /* base of mmap area */
unsigned long mmap_legacy_base; /* base of mmap area in bottom-up allocations */
......
unsigned long hiwater_rss; /* High-watermark of RSS usage */
unsigned long hiwater_vm; /* High-water virtual memory usage */
unsigned long total_vm; /* Total pages mapped */
unsigned long locked_vm; /* Pages that have PG_mlocked set */
atomic64_t pinned_vm; /* Refcount permanently increased */
unsigned long data_vm; /* VM_WRITE & ~VM_SHARED & ~VM_STACK */
unsigned long exec_vm; /* VM_EXEC & ~VM_WRITE & ~VM_STACK */
unsigned long stack_vm; /* VM_STACK */
spinlock_t arg_lock; /* protect the below fields */
unsigned long start_code, end_code, start_data, end_data;
unsigned long start_brk, brk, start_stack;
unsigned long arg_start, arg_end, env_start, env_end;
unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
......
}
De acuerdo con estas variables miembro, podemos planificar la posición de cada parte en el estado del usuario, pero también necesitamos una estructura para describir los atributos de estas áreas, a sabervm_area_struct
struct mm_struct {
......
struct vm_area_struct *mmap; /* list of VMAs */
struct rb_root mm_rb;
......
}
vm_area_struct
La definición de estructura específica de es la siguiente: en realidad es una lista doblemente enlazada combinada por vm_next
y vm_prev
, es decir, una serie de contenidos vm_area_struct
para expresar un proceso en cada área asignada en el modo usuario.
vm_start
Yvm_end
expresa el principio y el final del área del bloque.vm_rb
Correspondiente a un árbol rojo-negro, este árbol rojo-negro combina todovm_area_struct
para una fácil adición, eliminación y búsqueda.rb_subtree_gap
Almacene el intervalo entre el área actual y el área anterior para su posterior asignación.vm_mm
Señale la estructura a la que pertenece la estructuravm_struct
vm_page_prot
Gestionar la autoridad de acceso de esta página,vm_flags
como el bit de marcarb
Yrb_subtree_last
: estructura de árbol de intervalos con posiciones libresano_vma 和 ano_vma_chain
: Mapeo anónimo. El área de memoria virtual se puede asignar a la memoria física oa un archivo. Cuando se asigna a la memoria física, se denomina asignación anónima. Cuando se asigna a un archivo, debevm_file
especificar el archivo asignado yvm_pgoff
almacenar el desplazamiento.vm_opts
: Un puntero de función a la estructura, utilizado para procesar la estructuravm_private_data
: Almacenamiento de datos privados
/*
* This struct defines a memory VMM memory area. There is one of these
* per VM-area/task. A VM area is any part of the process virtual memory
* space that has a special rule for the page-fault handlers (ie a shared
* library, the executable area etc).
*/
struct vm_area_struct {
/* The first cache line has the info for VMA tree walking. */
unsigned long vm_start; /* Our start address within vm_mm. */
unsigned long vm_end; /* The first byte after our end address
within vm_mm. */
/* linked list of VM areas per task, sorted by address */
struct vm_area_struct *vm_next, *vm_prev;
struct rb_node vm_rb;
/*
* Largest free memory gap in bytes to the left of this VMA.
* Either between this VMA and vma->vm_prev, or between one of the
* VMAs below us in the VMA rbtree and its ->vm_prev. This helps
* get_unmapped_area find a free area of the right size.
*/
unsigned long rb_subtree_gap;
/* Second cache line starts here. */
struct mm_struct *vm_mm; /* The address space we belong to. */
pgprot_t vm_page_prot; /* Access permissions of this VMA. */
unsigned long vm_flags; /* Flags, see mm.h. */
/*
* For areas with an address space and backing store,
* linkage into the address_space->i_mmap interval tree.
*/
struct {
struct rb_node rb;
unsigned long rb_subtree_last;
} shared;
/*
* A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
* list, after a COW of one of the file pages. A MAP_SHARED vma
* can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack
* or brk vma (with NULL file) can only be in an anon_vma list.
*/
struct list_head anon_vma_chain; /* Serialized by mmap_sem & page_table_lock */
struct anon_vma *anon_vma; /* Serialized by page_table_lock */
/* Function pointers to deal with this struct. */
const struct vm_operations_struct *vm_ops;
/* Information about our backing store: */
unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE
units */
struct file * vm_file; /* File we map to (can be NULL). */
void * vm_private_data; /* was vm_pte (shared mem) */
atomic_long_t swap_readahead_info;
#ifndef CONFIG_MMU
struct vm_region *vm_region; /* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
struct mempolicy *vm_policy; /* NUMA policy for the VMA */
#endif
struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
} __randomize_layout;
Para a mm_struct
, vm_area_struct
se carga su archivo ELF de muchos , es decir, load_elf_binary()
cuando se carga el archivo build . Después de que la función analiza el formato de archivo ELF, establecerá el mapa de memoria, que incluye principalmente
- Llamar
setup_new_exec
, configurar el área del mapa de memoriammap_base
- Llamadas
setup_arg_pages
, configura la pilavm_area_struct
, se proporcionamm->arg_start
un punto de la parte inferior de la pila,current->mm->start_stack
es la parte inferior de la pila elf_map
Asignará parte del código en el archivo ELF a la memoriaset_brk
El montónvm_area_struct
está configuradocurrent->mm->start_brk = current->mm->brk
y el interior está configurado , es decir, el montón todavía está vacíoload_elf_interp
El dependienteso
mapeado en memoria área de memoria mapeada
static int load_elf_binary(struct linux_binprm *bprm)
{
......
setup_new_exec(bprm);
......
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
executable_stack);
......
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
elf_prot, elf_flags, total_size);
......
/* Calling set_brk effectively mmaps the pages that we need
* for the bss and break sections. We must do this before
* mapping in the interpreter, to make sure it doesn't wind
* up getting placed where the bss needs to go.
*/
retval = set_brk(elf_bss, elf_brk, bss_prot);
......
elf_entry = load_elf_interp(&loc->interp_elf_ex,
interpreter,
&interp_map_addr,
load_bias, interp_elf_phdata);
......
current->mm->end_code = end_code;
current->mm->start_code = start_code;
current->mm->start_data = start_data;
current->mm->end_data = end_data;
current->mm->start_stack = bprm->p;
......
}
3.2 estructura de estado del kernel
Debido a la gran brecha entre los sistemas de 32 y 64 bits, existen algunas diferencias en la estructura. Discutimos la estructura de los dos por separado aquí.
3.2.1 Estructura del modo kernel de 32 bits
El espacio virtual en el modo kernel es independiente del proceso, es decir, después de que todos los procesos ingresan al kernel a través de llamadas al sistema, el espacio de direcciones virtuales que ven es el mismo. La siguiente figura muestra el diagrama de distribución del espacio virtual del estado del kernel de 32 bits.
-
Área de mapeo directo
El primer 896M es un área de mapeo directo, que se utiliza para mapeo directo con memoria física. Reste 3G de la dirección de la memoria virtual para obtener la ubicación de la memoria física correspondiente. En el kernel, hay dos macros:
-
__pa(vaddr)
Devuelve la direcciónvaddr
física asociada a la dirección virtual ; -
__va(paddr)
Cálculo de la dirección física correspondiente a lapaddr
dirección virtual.
El acceso a esta parte de la dirección virtual también se realiza a modo de paginación, pero la dirección de la tabla de página es relativamente simple y la correspondencia uno a uno es suficiente.
Cuando se inicia el sistema, el primer 1M de la memoria física ya está ocupado. El segmento de código del kernel se carga desde 1M, y luego las variables globales del kernel, BSS, etc., también se cubren en ELF. De esta forma, los segmentos de código del núcleo, las variables globales y el BSS también se asignarán al espacio de direcciones virtuales después de 3G. Se puede ver el diseño específico de la memoria física /proc/iomem
, y el específico será diferente debido al sistema y la configuración de cada persona.
- alta_memoria
El nombre de memoria de alta gama proviene de la división del espacio de direcciones físicas en tres partes en la arquitectura x86: ZONE_DMA, ZONE_NORMAL y ZONE_HIGHMEM. ZONE_HIGHMEM tiene mucha memoria.
La memoria de gama alta es el nombre con el que el módulo de administración de memoria mira la memoria física, que se refiere al área por encima del área de mapeo directo del 896M. ** A excepción del módulo de administración de memoria en el kernel, el resto opera en direcciones virtuales. ** El módulo de gestión de memoria manipula directamente la dirección física y realiza la asignación y asignación de direcciones virtuales. El significado de su existencia es acceder al espacio de memoria física infinita desde el espacio limitado del kernel del sistema de 32 bits: pedir prestado este espacio de direcciones lógicas, crear una asignación a la memoria física a la que desea acceder (es decir, llenar la tabla de la página del kernel) y usarla temporalmente por un tiempo Y devuélvalo después de su uso.
- Espacio de mapeo dinámico del kernel (asignación de memoria no contigua)
En VMALLOC_START
y VMALLOC_END
llamar al mapeo dinámico del kernel entre la región del espacio, malloc
se vmalloc
puede aplicar un proceso correspondiente a la memoria de la aplicación en modo usuario como en el modo kernel . El modo kernel tiene una gestión de tabla de páginas separada, separada del modo de usuario.
- Área de mapeo de kernel permanente (mapeo de kernel permanente)
PKMAP_BASE
Al FIXADDR_START
espacio del kernel se le llama mapeo persistente entre el rango de direcciones de 4G-8M a 4G-4M. Usando la alloc_pages()
función cuando la memoria física en la struct page
estructura resultante de la memoria superior , se puede llamar kmap
a mapear a esta región. Debido a que el número de asignaciones permanentes permitidas es limitado, cuando la memoria de gama alta ya no es necesaria, la asignación debe desmapearse, lo que se puede realizar mediante kunmap()
funciones.
- Área de mapeo fija
FIXADDR_START
El FIXADDR_TOP(0xFFFF F000)
espacio, llamado área cartográfica fija, se utiliza principalmente para satisfacer necesidades especiales.
- Mapeo temporal del kernel
El mapeo temporal del kernel se pasa kmap_atomic
e kunmap_atomic
implementa, y se usa principalmente para operaciones cuando se requiere escribir en la memoria física o en la memoria principal, como cuando se escriben archivos.
3.2.2 Estructura del modo kernel de 64 bits
Debido al enorme espacio en el modo kernel de 64 bits, no es necesario planificar con cuidado como en el modo de 32 bits, y muchas áreas libres se dividen directamente para su protección. La estructura se muestra en la figura siguiente.
- Comenzar desde 0xffff800000000000 es parte del kernel, pero al principio hay un área de espacio de 8T.
- Desde el
__PAGE_OFFSET_BASE(0xffff880000000000)
espacio de direcciones virtuales que comienza 64T es un mapeo directo del área, que se restaPAGE_OFFSET
es la dirección física. En la mayoría de los casos, el mapeo entre direcciones virtuales y direcciones físicas aún se mapeará estableciendo una tabla de páginas. - Desde
VMALLOC_START(0xffffc90000000000)
el principio hasta elVMALLOC_END(0xffffe90000000000)
espacio de 32T es darvmalloc
el. - Desde el
VMEMMAP_START(0xffffea0000000000)
espacio 1T para almacenar la descripción física inicial de la estructurastruct page
de la página. - A partir de
__START_KERNEL_map(0xffffffff80000000)
512M, el segmento de código del kernel se utiliza para almacenar variables globales y, por lo tanto, el BSS. Esto corresponde a la posición inicial de la memoria física menos la__START_KERNEL_map
posibilidad de obtener la dirección de la memoria física. Esto es un poco similar al área de mapeo directo, pero no es contradictorio, porque hay un área vacía de 8T antes del área de mapeo directo, que ha pasado hace mucho tiempo la ubicación donde se carga el código del kernel en la memoria física.
para resumir
Este artículo analiza con más detalle la estructura del modo de usuario y el modo de kernel en la memoria, a partir de lo cual podemos comenzar a analizar la gestión y mapeo de la memoria posteriormente.
Información de código
[1] linux / include / linux / mm_types.h
Referencia
[1] wiki
[3] woboq
[4] Interior de Linux
[5] Conocimiento profundo del kernel de Linux
[6] El arte del diseño del kernel de Linux
[7] Geek Time habla sobre el sistema operativo Linux