《Understanding the Linux kernel》学习笔记 Chapter 2: Memory Addressing

Memory Addresses

When dealing with 80x86 microprocessor, we have to distinguish three kinds of addresses: logical address, linear address (also known as virtual address) and physical address.


Segmentation in Hardware

Segment Selectors and Segmentation Registers

A logical address consists of two parts: a segment identifier and an offset that specifies the relative address within the segment. The segment identifier is a 16-bit field called the Segment Selector, while the offset is a 32-bit field.


Segment Descriptors

Each segment is represented by an 8-byte Segment Descriptor that describe the segment characteristics. Segment Descriptors are stored either in the Global Descriptor Table (GDT) or in the Local Descriptor Table (LDT).

The address and size of the GDT in main memory are contained in the gdtr control register, while the address and size of the currently used LDT are contained in the ldtr control register.

There are several types of segments, and thus several types of Segment Descriptors (Code Segment Descriptor, Data Segment Descriptor, Task State Segment Descriptor, and Local Descriptor Table Descriptor).


Fast Access to Segment Descriptors

Every time a Segment Selector is loaded in a segment register, the corresponding Segment Descriptor is loaded from memory into the matching nonprogrammable CPU register.


Segmentation Unit

The segmentation unit performs the following operations:

  • Examines the TI field of the Segment Selector to determine which Descriptor Table stores the Segment Descriptor.
  • Computes the address of the Segment Descriptor from the index field of the Segment Selector.
  • Adds the offset of the logical address to the Base field of the Segment Descriptor, thus obtaining the linear address.
Notice that, thanks to the nonprogrammable registers associated with the segmentation registers, the first two operation need to be performed only when a segmentation register has been changed.

Segmentation in Linux

Linux uses segmentation in a very limited way.

In fact, segmentation and paging are somewhat redundant, because both can be used to separate the physical address space of processes: segmentation can assign a different linear address space to each process, while paging can map the same linear address space into different physical address space.

All Linux processes running in User Mode use the same pair of segments to address instructions and data. These segments are called user code segment and user data segment, respectively. Similarly, all Linux processes running in Kernel Mode use the same pair of segments to address instructions and data: they are called kernel code segement and kernel data segment, respectively.


The Linux GDT

In uniprocessor systems there is only one GDT, while in multiprocessor systems there is one GDT for every CPU in the system.

Each GDT includes 18 segment descriptors and 14 null, unused, or reserved entries.

The 18 segment descriptors included in each GDT point to the following segments:

  • Four user and kernel code and data segments.
  • A Task State Segment (TSS), different for each processor in the system.
  • A segment including the default Local Descriptor Table (LDT), usually shared by all processes.
  • Three Thread-Local Storage (TLS) segments.
  • Three segments related to Advanced Power Management (APM).
  • Five segments related to Plug and Play (PnP) BIOS services.
  • A special TSS segment used by the kernel to handle "Double fault" exceptions.

The Linux LDTs

Most Linux User Mode applications do not make use of a Local Descriptor Table, thus the kernel defines a default LDT to be shared by most processes.

Call gates are a mechanism provided by 80x86 microprocessors to change the privilege level of the CPU while invoking a predefined function.


Paging in Hardware

The data structures that map linear to physical addresses are called page tables; they are stored in main memory and must be properly initialized by the kernel before enabling the paging uint.


Regular Paging

Starting with the 80386, the paging unit of Intel processors handles 4KB pages.

The 32 bits of a linear address are divided into three fields: Directory (the most significant 10 bits), Table (the intermediate 10 bits), Offset (the least significant 12 bits).

The translation of linear addresses is accomplished in two steps, each based on a type of translation table. The first translation table is called the Page Directory, and the second is called the Page Table.

The entries of Page Directories and Page Tables have the same structure. Each entry includes the following fields: Present flag, Field containing the 20 most significant bits of a page frame physical address, Accessed flag, Dirty flag, Read/Write flag, User/Supervisor flags, PCD and PWT flags, Page Size flag, Global flag.


Extended Paging

Starting with the Pentium model, 80x86 microprocessors introduce extended paging, which allows page frames to be 4 MB instead of 4 KB in size.


Hardware Protection Scheme

Only two privilege levels are associated with pages and Page Tables.

Only two types of access rights (Read and Write) are associated with pages.


The Physical Address Extension (PAE) Paging Mechanism

PAE is activated by setting the Physical Address Extension (PAE) flag in the cr4 control register. The Page Size (PS) flag in the page directory entry enables large page sizes (2 MB when PAE is enabled).


Paging for 64-bit Architectures

Two-level paging is not suitable for computers that adopt a 64-bit architecture.


Hardware Cache

Hardware cache memories were introduced to reduce the speed mismatch between CPU and RAM. They are based on the well-known locality principle, which holds both for programs and data structures.


Translation Lookaside Buffers (TLB)

Besides general-purpose hardware caches, 80x86 processors include another cache called Translation Lookaside Buffers (TLB) to speed up linear address translation.


Paging in Linux

Linux's handling of processes relies heavily on paging. In fact, the automatic translation of linear addresses into physical ones makes the following design objectives feasible:

  • Assign a different physical address space to each process, ensuring an efficient protection against addressing errors.
  • Distinguish pages (groups of data) from page frames (physical addresses in main memory).

The Linear Address Fields

PAGE_SHIFT Specifies the length in bits of the Offset field; when applied to 80x86 processors, it yields the value 12.

PMD_SHIFT The total length in bits of the Offset and Table fields of a linear address; in order words, the logarithm of the size of the area a Page Middle Directory entry can map.

PUD_SHIFT Determines the logarithm of the size of the area a Page Upper Directory entry can map.

PGDIR_SHIFT Determines the logarithm of the size of the area that a Page Global Directory entry can map.

PTRS_PER_PTE, PTRS_PER_PMD, PTRS_PER_PUD, and PTRS_PER_PGD Computer the number of entries in the Page Table, Page Middle Directory, Page Upper Directory, and Page Global Directory.


Page Table Handling

Physical Memory Layout

As a general rule, the Linux kernel is installed in RAM starting from the physical address 0x00100000 -- i.e., from the second megabyte.

A typical configuration yields a kernel that can be loaded in less than 3 MB of RAM.


Process Page Tables

The linear address space of a process is divided into two parts:

  • Linear addresses from 0x00000000 to 0xbfffffff can be addressed when the process runs in either User or Kernel Mode.
  • Linear addresses from 0xc0000000 to 0xffffffff can be addressed only when the process runs in Kernel Mode.

Kernel Page Tables

Provisional kernel Page Tables

A provisional Page Global Directory is initialized statically during kernel compilation, while the provisional Page Tables are initialized by the startup_32() assembly language function defined in arch/i386/kernel/head.S.


Final kernel Page Table when RAM size is less than 896 MB

Final kernel Page Table when RAM size is between 896 MB and 4096 MB

Final kernel Page Table when RAM size is more than 4096 MB

Fix-Mapped Linear Addresses

Basically, a fix-mapped linear address is a constant linear address like 0xffffc000 whose conrresponding physical address does not have to be the linear address minus 0xc0000000, but rather a physical address set in an arbitrary way.


Handling the Hardware Cache and the TLB

 前言   第一章绪论   Linux与其他类Unix内核的比较   硬件的依赖性   Linux版本   操作系统基本概念   Unix文件系统概述   Unix内核概述   第二章内存寻址   内存地址   硬件中的分段   Linux中的分段   硬件中的分页   Linux中的分页   第三章进程   进程、轻量级进程和线程   进程描述符   进程切换   创建进程   撤消进程   第四章中断和异常   中断信号的作用   中断和异常   中断和异常处理程序的嵌套执行   初始化中断描述符表   异常处理   中断处理   软中断及tasklet   工作队列   从中断和异常返回   第五章内核同步   内核如何为不同的请求提供服务   同步原语   对内核数据结构的同步访问   避免竞争条件的实例   第六章定时测量   时钟和定时器电路   Linux计时体系结构   更新时间和日期   更新系统统计数   软定时器和延迟函数   与定时测量相关的系统调用   第七章进程调度   调度策略   调度算法   调度程序所使用的数据结构   调度程序所使用的函数   多处理器系统中运行队列的平衡   与调度相关的系统调用   第八章内存管理   页框管理   内存区管理   非连续内存区管理   第九章进程地址空间   进程的地址空间   内存描述符   线性区   缺页异常处理程序   创建和删除进程的地址空间   堆的管理   第十章系统调用   POSIXAPI和系统调用   系统调用处理程序及服务例程   进入和退出系统调用   参数传递   内核封装例程   第十一章信号   信号的作用   产生信号   传递信号   与信号处理相关的系统调用   第十二章虚拟文件系统   虚拟文件系统(VFS)的作用   VFS的数据结构   文件系统类型   文件系统处理   路径名查找   VFS系统调用的实现   文件加锁   第十三章I/O体系结构和设备驱动程序   I/O体系结构   设备驱动程序模型   设备文件   设备驱动程序   字符设备驱动程序   第十四章块设备驱动程序   块设备的处理   通用块层   I/O调度程序   块设备驱动程序   打开块设备文件   第十五章页高速缓存   页高速缓存   把块存放在页高速缓存中   把脏页写入磁盘   sync()、fsync()和fdatasync()系统调用   第十六章访问文件   读写文件   内存映射   直接I/O传送   异步I/O   第十七章回收页框   页框回收算法   反向映射   PFRA实现   交换   第十八章Ext2和Ext3文件系统   Ext2的一般特征   Ext2磁盘数据结构   Ext2的内存数据结构   创建Ext2文件系统   Ext2的方法   管理Ext2磁盘空间   Ext3文件系统   第十九章进程通信   管道   FIFO   SystemVIPC   POSIX消息队列   第二十章程序的执行   可执行文件   可执行格式   执行域   exec函数   附录一系统启动   附录二模块   参考文献
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值