TASK_threadsp的实现及asm-offsets.h

      在学习极客时间刘超《趣谈Linux操作系统》 16 节时,讲到了主动调度, 通过__schedule() 函数让出cpu三个步骤: 

       1. 取出任务队列;

       2. 从队列取下一个任务;

       3. 进行上下文切换;

       其中第三步中上下文切换中  调用switch_to函数,  通过调用switch_to_asm函数完成栈顶执政寄存器的交换。 代码如下:

/arch/x86/include/asm/switch_to.h
#define switch_to(prev, next, last)					\
do {									\
	prepare_switch_to(next);					\
									\
	((last) = __switch_to_asm((prev), (next)));			\
} while (0)

/arch/x86/entry/entry_64.S

ENTRY(__switch_to_asm)
	UNWIND_HINT_FUNC
。。。
	/* switch stack */
	movq	%rsp, TASK_threadsp(%rdi)
	movq	TASK_threadsp(%rsi), %rsp
。。。。
END(__switch_to_asm)

其中 %rdi代表第一个参数,  %rsi代表第二个参数, 分别代表 prev task, next task
将当前栈顶指针放入prev task_struct 结构 thread_struct的 sp0 中。 将next_task栈顶 指做为当前栈顶指针,完成切换。

        关于 TASK_threadsp,涉及以下几个文件:(当然一开始的时候正是因为找不到才有了有序寻找答案的过程)

  •  编译相关
1 /Kbuild
...
#####
# Generate asm-offsets.h

offsets-file := include/generated/asm-offsets.h

always  += $(offsets-file)
targets += arch/$(SRCARCH)/kernel/asm-offsets.s

arch/$(SRCARCH)/kernel/asm-offsets.s: $(timeconst-file) $(bounds-file)

$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s FORCE
	$(call filechk,offsets,__ASM_OFFSETS_H__)
...


2. /scripts/Makefile.lib
...
# ASM offsets
# ---------------------------------------------------------------------------

# Default sed regexp - multiline due to syntax constraints
#
# Use [:space:] because LLVM's integrated assembler inserts <tab> around
# the .ascii directive whereas GCC keeps the <space> as-is.
define sed-offsets
	's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:; \
	/^->/{s:->#\(.*\):/* \1 */:; \
	s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
	s:->::; p;}'
endef

# Use filechk to avoid rebuilds when a header changes, but the resulting file
# does not
define filechk_offsets
	 echo "#ifndef $2"; \
	 echo "#define $2"; \
	 echo "/*"; \
	 echo " * DO NOT MODIFY."; \
	 echo " *"; \
	 echo " * This file was generated by Kbuild"; \
	 echo " */"; \
	 echo ""; \
	 sed -ne $(sed-offsets) < $<; \
	 echo ""; \
	 echo "#endif"
endef
...
  • 代码相关

/include/linux/kbuild.h

#define DEFINE(sym, val) \
	asm volatile("\n.ascii \"->" #sym " %0 " #val "\"" : : "i" (val))
#define OFFSET(sym, str, mem) \
	DEFINE(sym, offsetof(struct str, mem))
...


/arch/x86/kernel/asm-offsets.c

static void __used common(void)
{
...
	OFFSET(TASK_threadsp, task_struct, thread.sp);
...

//生成的头文件
/include/generated/asm-offsets.h
#ifndef __ASM_OFFSETS_H__
#define __ASM_OFFSETS_H__
/*
 * DO NOT MODIFY.
 *
 * This file was generated by Kbuild
 */
#define TASK_threadsp 4824 /* offsetof(struct task_struct, thread.sp) */

  • 整体处理流程:

        asm-offsets.c 转化为asm-offsets.s通过Makefile.lib 的filechk_offsets ,sed-offsets 将其生成宏定义, 这样汇编语言也可以方便的获得相关结构结构体的偏移了。 

         下面写个demo验证一下

  • Makefile:

offsets-file := asm-offsets.h

define sed-yo
        "/^->/{s:->#\(.*\):/* \1 */:; \
        s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
        s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
        s:->::; p;}"

endef
define sed-y
        's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:; \
        /^->/{s:->#\(.*\):/* \1 */:; \
        s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
        s:->::; p;}'
endef


define cmd_offsets
    (set -e; \
     echo "#ifndef __ASM_OFFSETS_H__"; \
     echo "#define __ASM_OFFSETS_H__"; \
     echo "/*"; \
     echo " * DO NOT MODIFY."; \
     echo " *"; \
     echo " * This file was generated by Kbuild"; \
     echo " *"; \
     echo " */"; \
     echo ""; \
     sed -ne $(sed-y) $<; \
     echo ""; \
     echo "#endif" ) > $@
endef


asm-offsets.s: asm-offsets.c
        gcc -S $<

$(offsets-file): asm-offsets.s
        @$(cmd_offsets)
  • asm-offsets.c
#include "kbuild.h"
#include <stddef.h>


struct thread_struct1 {
    int sp;
};
struct task_struct1 {
   struct thread_struct1 thread;
};


#define __used  __attribute__((__used__))
static void __used common(void){
   BLANK();
   COMMENT("TASK_threadsp1");
   OFFSET(TASK_threadsp1, task_struct1, thread.sp);
   BLANK();
}
  • asm-offsets.h 
[root@centosgpt generate]# cat asm-offsets.h
#ifndef __ASM_OFFSETS_H__
#define __ASM_OFFSETS_H__
/*
 * DO NOT MODIFY.
 *
 * This file was generated by Kbuild
 *
 */

/* TASK_threadsp1 */
#define TASK_threadsp1 0 /* offsetof(struct task_struct1, thread.sp) */

#endif

 asm-offsets.h 文件生成了。 

 

参考:

What’s purpose of “arm64/kernel/asm-offsets.c”?

lib/asm-offsets.c的作用

linux中的asm-offsets.h和bounds.h

Be First to Comment

发表回复