head.S分析
1. kmalloc和vmalloc对比 以ARM64为例,不考虑高端内存。 1.1. 实现原理 kmalloc和vmalloc底层函数都是__alloc_pages。 kmalloc会根据申请大小是否大于KMALLOC_MAX_CACHE_SIZE来决定使用slab还是__alloc_pages,而slab最终也是调用__alloc_pages。 1.2. 初始化 默认情况下,kmalloc和vmalloc都不会对申请的内存做初始。 可以通过kzalloc或vzalloc申请内存并初始化为0。 1.3. 对齐 kmalloc按块分配,通常为2^n对齐,每次分配的大小也是2^n。根据实现,可能也支持96或者192字节。...
1. 内核栈 在每一个进程的生命周期中,必然会通过到系统调用陷入内核。在执行系统调用陷入内核之后,这些内核代码所使用的栈并不是原先进程用户空间中的栈,而是一个单独内核空间的栈,这个称作进程内核栈。 1.1. init_task init_task,也就是bootcpu的swapper进程对应的task_struct,其内核栈是静态初始化的。 1/// init/init_task.c 2/* 3 * Set up the first task table, touch at your own risk!. Base=0, 4 * limit=0x1fffff (=2MB) 5 */ 6struct task_struct...
1. 编译选项 -fomit-frame-pointer表示在函数调用时不需要存储堆栈帧指针。此选项可减小生成的代码镜像大小, 一般在启用-On优化后会自动打开,也有的平台是默认打开的。 -fno-omit-frame-pointer表示将堆栈帧指针存储在寄存器中,帧指针是用来指示当前函数的栈帧(stack frame)的指针,在调试时可以帮助跟踪函数调用的堆栈信息。 在 AArch32 架构中,堆栈帧指针存储在寄存器R11A32代码)或寄存器R7T32代码)中. 在AArch64架构中,堆栈帧指针存储在寄存器X29中。作为帧指针使用的寄存器不能用作通用寄存器,但如果使用 -fomit-frame-pointer选项编译,则可用作...
1. IRQ domain注册 中断控制器初始化的过程中,要向中断子系统注册irq domain。核心函数__irq_domain_add。 gic-v2使用irq_domain_create_linear,gic-v3则使用irq_domain_add_tree。 __irq_domain_add的实现在kernel/irq/irqdomain.c,逻辑并不复杂,主要就是申请struct irq_domain结构体和对各个成员进行赋值,细节可以自己分析。 1/// kernel/irq/irqdomain.c 2/** 3 * __irq_domain_add() - Allocate a new irq_domain data...
1. 设备中断注册 gic-v3的中断号划分在《IHI0069H_gic_architecture_specification.pdf》有所罗列: 前边介绍,在gic初始化时,已经使用了0-7号SGI来作为IPI。 对于设备中断,使用的是PPI和SPI。设备probe时调用irq_of_parse_and_map等函数,如timer_of_irq_init。会调用函数来向系统注册中断,常用函数有如下几个: 1/// include/linux/of_irq.h 2extern int of_irq_get(struct device_node *dev, int index); 3extern int...
1. 申请中断 __setup_irq是用于设置和注册中断的核心函数,它是request_threaded_irq等函数的内部实现。 1.1. irqaction handler和thread_fn是struct irqaction的两个重要成员,由程序员指定或在__setup_irq中自动设置, 在中断发生后的处理函数被调用。 1/// include/linux/interrupt.h 2/** 3 * struct irqaction - per interrupt action descriptor 4 * @handler: interrupt handler function 5 * @name: name of...
1. 中断入口 要处理中断,必须为handle_arch_irq赋值。 ARM64自己定义handle_arch_irq的实现。 1/// arch/arm64/kernel/irq.c 2void (*handle_arch_irq)(struct pt_regs *) __ro_after_init = default_handle_irq; 3void (*handle_arch_fiq)(struct pt_regs *) __ro_after_init = default_handle_fiq; 4 5int __init set_handle_irq(void (*handle_irq)(struct pt_regs...
1. 简介 early_irq_init完成中断子系统软件部分初始化。 irqchip_init初始化中断控制器,向系统注册struct irq_domain。 2. 中断软件子系统初始化 early_irq_init初始化数组或树,用于保存virq到struct irq_desc的转换关系。 irq_to_desc用于将virq转换为struct irq_desc指针。 2.1. 线性映射 未定义CONFIG_SPARSE_IRQ时使用线性映射,使用数组实现,静态分配,支持的最大virq由NR_IRQS决定。 1struct irq_desc irq_desc[NR_IRQS]...
1. Linux内核代码的编写和优化技巧 1.1. 代码编写 使用 __same_type和 typecheck编译时检查类型匹配。 __printf和 __scanf编译时检查代码。 对宏进行undef后重新定义,生成不同的代码,如 __SYSCALL配合 unistd.h生成系统调用,TRACE_EVENT生成ftrace相关的数据结构和各个函数。 使用模板宏,减少重复代码也降低出错率,如 STANDARD_PARAM_DEF生成 module_param用到的set和get函数。 使用内联汇编提升性能。 使用位图优化内存占用。 无锁队列kfifo。 1.2. 控制编译时行为 O2或 O3,编译时优化汇编代码。...