内核源码下载:
https://mirrors.edge.kernel.org/pub/linux/kernel/
http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/
本书基于2.4.16版本
分段分页
分段。Linux在启动过程中设置了段寄存器的值和全局描述符表GDT的内容。
段选择子:
// FILE: include/asm-i386/segment.h
#define __KERNEL_CS 0x10 // 内核代码段, index=2 TI=0 RPL=0
#define __KERNEL_DS 0x18 // 内核数据段, index=3 TI=0 RPL=0
#define __USER_CS 0x23 // 用户代码段, index=4 TI=0 RPL=3
#define __USER_DS 0x2B // 用户数据段, index=5 TI=0 RPL=3
段描述符GDT:
1)段基址都为0x0000_0000;2)段界限都为0xffff; 3)粒度G都为1,即段长单位为4KB;
4)段的D位为1,即对这4个段的访问都为32位指令;5)段的P位为1,即4个段都在内存。
// FILE: arch/i386/kernel/head.S
ENTRY(gdt_table)
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0000000000000000 /* not used */
.quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */
.quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */
.quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */
.quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */
.quad 0x0000000000000000 /* not used */
.quad 0x0000000000000000 /* not used */
分页。
Linux没有把这几个类型直接定义长整数而是定义为一个结构,是为了让gcc在编译时进行更严格的类型检查。另外,还定义了几个宏来访问这些结构的成分。
// FILE: include/asm-i386/page.h
// These are used to make use of C type-checking..
typedef struct { unsigned long pte_low; } pte_t;
typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pgd; } pgd_t;
typedef struct { unsigned long pgprot; } pgprot_t;
#define pte_val(x) ((x).pte_low)
#define pmd_val(x) ((x).pmd)
#define pgd_val(x) ((x).pgd)
#define pgprot_val(x) ((x).pgprot)
页表项。把标志位定义为宏,而不是位段,更有利于编码。
// FILE: include/asm-i386/pgtable.h
#define _PAGE_PRESENT 0x001
#define _PAGE_RW 0x002
#define _PAGE_USER 0x004
#define _PAGE_PWT 0x008
#define _PAGE_PCD 0x010
#define _PAGE_ACCESSED 0x020
#define _PAGE_DIRTY 0x040
#define _PAGE_PSE 0x080 /* 4 MB (or 2MB) page, Pentium+, if present.. */
#define _PAGE_GLOBAL 0x100 /* Global TLB entry PPro+ */
extern pgd_t swapper_pg_dir[1024]; // 页目录表
/* page table for 0-4MB for everybody */
extern unsigned long pg0[1024]; // 一个临时页表
中断机制
Intel x86通过两片级联的中断控制器8259A来响应15个外中断源,每个8259A可管理8个中断源。
IRQ0 时钟;IRQ1 键盘
初始化中断控制器8259A
// FILE: arch/i386/kernel/i8259.c
void __init init_8259A(int auto_eoi)()
{
...
}
86