Arm_Linux内核零碎笔记
字符设备 open->sys_open->(current->task_struct->fops = kobj_map->probes[主设备号]->ops)
module_init->是把所有驱动的初始化函数指针放到一个独立的段里,从那个段得起始地址依次调用.
ioremap 会重叠映射物理地址
include/linux/init.h -> #define module_init
内核启动时,会通过协处理指令(MCR P15,0,(Rd orr 0x2000),C1,C0,0)配置ARM内核的中断跳转地址为0xFFFF0000
----------------------------------
CP15 Register 1: Control registers
V (bit[13]) This bit is used to select the location of the exception vectors:
0 = Normal exception vectors selected (address range 0x00000000-0x0000001C)
1 = High exception vectors selected (address range 0xFFFF0000-0xFFFF001C).
An implementation can provide an input signal that determines the state of this bit after reset.
#define __initdata __section(.init.data)
实在计算不出他的地址了,就反汇编内核(arm-linux-gnu-objdump -D vmlinux > linux.dis).
系统调用->fs\*.c
vmlinux(带调试信息的ELF内核)->image(纯内核(D3 F0 21 E3 10 9F 10 EE))->zImage(加了压缩代码的内核)->uImage(加了64字节信息的内核)
ARM-ATPCS规则
----------------------------------------------------------------------------------------------------------
FP当前参数栈帧指针和当前函数体的局部变量
SP当前模式栈指针和当前函数调用传参参数的指针
第五个参数开始的压栈方向是从左到右
内核启动流程
----------------------------------------------------------------------------------------------------------
arch\arm\kernel\head.S->stext()->init\main.c->start_kernel()
原子操作
----------------------------------------------------------------------------------------------------------
自旋锁
static inline void atomic_add(int i, atomic_t *v)
{
unsigned long tmp;
int result;
__asm__ __volatile__("@ atomic_add\n"
"1:ldrex %0, [%3]\n"
"add %0, %0, %4\n"
"strex %1, %0, [%3]\n"
"teq %1, #0\n"
"bne 1b"
: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
: "r" (&v->counter), "Ir" (i)
: "cc");
}
static inline void atomic_sub(int i, atomic_t *v)
{
unsigned long tmp;
int result;
__asm__ __volatile__("@ atomic_sub\n"
"1:ldrex %0, [%3]\n"
"sub %0, %0, %4\n"
"strex %1, %0, [%3]\n"
"teq %1, #0\n"
"bne 1b"
: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
: "r" (&v->counter), "Ir" (i)
: "cc");
}
----------------------------------------------------------------------------------------------------------
信号量
void down(struct semaphore *sem)
{
unsigned long flags;
spin_lock_irqsave(&sem->lock, flags);
if (likely(sem->count > 0))
sem->count--;
else
__down(sem);//关中断,把自己放到等待队列里,然后把自己设置为不可中断睡眠,开中断,请求调度.
spin_unlock_irqrestore(&sem->lock, flags);
}
static noinline void __sched __up(struct semaphore *sem)
{
struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
struct semaphore_waiter, list);
list_del(&waiter->list);
waiter->up = 1;
wake_up_process(waiter->task);
}
可中断睡眠/不可中断睡眠
-----------------------
两种任务状态,区别在于时钟中断检查时间片时,如果是可中断睡眠,就会检查该任务的信号队列,如果是不可中断睡眠,则不会检查.
中断和系统调用
-----------------------
相关新闻>>
- 发表评论
-
- 最新评论 更多>>