- 论坛徽章:
- 3
|
Linux kernel 2.6.28:
首先, 内核里面切换进程空间是通过switch_mm, 于是:
src/linux-2.6.28/arch/x86/include/asm# grep 'switch_mm' -nr .
得到:- ./mmu_context_32.h:13:static inline void switch_mm(struct mm_struct *prev,
- ./mmu_context_64.h:14:static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
复制代码 进去看, 发现switch_mm是通过load_cr3来切换页目录的, 于是:
src/linux-2.6.28/arch/x86/include/asm# grep 'load_cr3' -nr .
得到:- ./mmu_context_32.h:29: load_cr3(next->pgd);
- ./mmu_context_32.h:46: load_cr3(next->pgd);
- ./mmu_context_64.h:26: load_cr3(next->pgd);
- ./mmu_context_64.h:41: load_cr3(next->pgd);
- ./processor.h:184:static inline void load_cr3(pgd_t *pgdir)
复制代码 很显然load_cr3定义在processor.h 184行. 发现load_cr3调了write_cr3, 于是:
src/linux-2.6.28/arch/x86/include/asm# grep 'write_cr3' -nr .
得到:- ./pgtable-3level.h:120: write_cr3(pgd);
- ./tlbflush.h:20: write_cr3(read_cr3());
- ./system.h:220:static inline void native_write_cr3(unsigned long val)
- ./system.h:280:#define write_cr3(x) (native_write_cr3(x))
- ./processor.h:186: write_cr3(__pa(pgdir));
- ./paravirt.h:230: void (*write_cr3)(unsigned long);
- ./paravirt.h:676:static inline void write_cr3(unsigned long x)
- ./paravirt.h:678: PVOP_VCALL1(pv_mmu_ops.write_cr3, x);
复制代码 嗯, write_cr3调用了一个通用的宏, 就是PVOP_VCALL1:
cat paravirt.h | grep '#define .*PVOP_VCALL1' -n- 559:#define PVOP_VCALL1(op, arg1)
复制代码 于是:
vim paravirt.h +559:- #define PVOP_VCALL1(op, arg1) \
- __PVOP_VCALL(op, "", "", "0" ((unsigned long)(arg1)))
复制代码 这个宏是__PVOP_VCALL的包装, 好吧, 那么看__PVOP_VCALL:- #define __PVOP_VCALL(op, pre, post, ...) \
- ({ \
- PVOP_VCALL_ARGS; \
- PVOP_TEST_NULL(op); \
- asm volatile(pre \
- paravirt_alt(PARAVIRT_CALL) \
- post \
- : PVOP_VCALL_CLOBBERS \
- : paravirt_type(op), \
- paravirt_clobber(CLBR_ANY), \
- ##__VA_ARGS__ \
- : "memory", "cc" VEXTRA_CLOBBERS); \
- })
复制代码 =======================================================
很抱歉, 因为2.6.28内核需要处理32, 64位x86构架以及SMP的原因导致了上面的一系列抽象, 最终的宏是那么XX, 我已经不知道该如何吐槽.
=======================================================
那么在Linux kernel 2.4.0里面switch_mm是什么样子涅? 如下:- static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
- {
- ...
- asm volatile("movl %0, %%cr3": :"r"(__pa(next->pgd)));
- ...
- }
复制代码 =======================================================
那么LZ的语法似乎是对的. LZ的内嵌部分只有指令部和输出部, 这个no problem.
而gcc编译时应该不知道这代码是拿来干嘛的, 是内核涅还是应用程序代码的一部分? 而且cc1不负责汇编代码识别, 那是gas的事情.编译器cc1只要看嵌入汇编语法木有错, 那么就没有理由报错.
gas汇编器也木有理由报错, 因为gas也不知道这代码拿来干嘛用的.
那么可能的问题是, LZ的语法有错, 或者这用法不符合Intel的规定. 仔细检查吧LZ.
总之一句话, 如果语法和用法没错, 编译期是不可能报错的, 因为编译期根本不知道你拿这段代码干嘛.
=======================================================
顺便, 这样的代码即使编译通过, 在应用层是绝对不可能运行的. 因为毫无疑问访问cr3是特权级代码. 想看cr3究竟指向了哪个物理地址是吧? 也很easy, 写个内核模块驱动, insmod就木有问题了.
======================================================= |
|