最新 x86_64 系统调用入口分析 (基于 5.7.0)
最新 x86_64 系统调用入口分析 (基于5.7.0)
整体概览
最近的工作涉及系统调用入口,但网上的一些分析都比较老了,这里把自己的分析过程记录一下,仅供参考。
x86_64位系统调用使用 SYSCALL 指令进入内核空间,使CPU切换到ring 0。SYSCALL 指令主要工作为从MSR寄存器加载CS/SS,以及系统调用入口(entry_SYSCALL_64),从而进入系统调用处理流程。
MSR寄存器相关这里不再介绍,需要相关知识的指路 寄存器总结 以及
Model-specific register。
SYSCALL 指令
IF (CS.L ≠ 1 ) or (IA32_EFER.LMA ≠ 1) or (IA32_EFER.SCE ≠ 1)
(* Not in 64-Bit Mode or SYSCALL/SYSRET not enabled in IA32_EFER *)
THEN #UD;
FI;
RCX ← RIP; (* Will contain address of next instruction *)
RIP ← IA32_LSTAR;
R11 ← RFLAGS;
RFLAGS ← RFLAGS AND NOT(IA32_FMASK);
CS.Selector ← IA32_STAR[47:32] AND FFFCH (* Operating system provides CS; RPL forced to 0 *)
(* Set rest of CS to a fixed value *)
CS.Base ← 0;
(* Flat segment *)
CS.Limit ← FFFFFH;
(* With 4-KByte granularity, implies a 4-GByte limit *)
CS.Type ← 11;
(* Execute/read code, accessed *)
CS.S ← 1;
CS.DPL ← 0;
CS.P ← 1;
CS.L ← 1;
(* Entry is to 64-bit mode *)
CS.D ← 0;
(* Required if CS.L = 1 *)
CS.G ← 1;
(* 4-KByte granularity *)
CPL ← 0;
SS.Selector ← IA32_STAR[47:32] + 8;
(* SS just above CS *)
(* Set rest of SS to a fixed value *)
SS.Base ← 0;
(* Flat segment *)
SS.Limit ← FFFFFH;
(* With 4-KByte granularity, implies a 4-GByte limit *)
SS.Type ← 3;
(* Read/write data, accessed *)
SS.S ← 1;
SS.DPL ← 0;
SS.P ← 1;
SS.B ← 1;
(* 32-bit stack segment *)
SS.G ← 1;
(* 4-KByte granularity *)
(代码引自 https://www.felixcloutier.com/x86/syscall)
这里主要做了三个工作:
- 将RIP保存到RCX寄存器,即将SYSCALL指令下一条指令地址保存到RCX,后续用到。
- 从 IA32_LSTAR MSR 寄存器加载系统调用入口地址。64 位寄存器名为MSR_LSTAR。
- 从 IA32_STAR MSR 寄存器47-32到加载CS/SS段。64 位寄存器名为 MSR_STAR,其在内核启动过程中初始化。
MSR寄存器初始化源码点这
核心为:
wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
入口地址
接下来就是进入 entry_SYSCALL_64处理流程,源码在这。
但是这里有一个问题:在较新版内核中,都已支持 PTI 机制,用户态与内核态使用不同页表,而这里 entry_SYSCALL_64 已经属于内核代码,而我们仔细观察entry_SYSCALL_64 实现,在第四行才切换内核页表。想要 entry_SYSCALL_64 能被执行,就需要 cpu_entry_area 的作用了。
SYM_CODE_START(entry_SYSCALL_64)
UNWIND_HINT_EMPTY
/* * Interrupts are off on entry. * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON, * it is too small to ever cause noticeable irq latency. */
swapgs
/* tss.sp2 is scratch space. */
movq %rsp, PER_CPU_VAR(cpu_tss_rw + TSS_sp2)
SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp
cpu_entry_area 包括了CPU进入内核需要的所有数据/代码,会被映射到用户态页表。了解点着,但是要注意较新版本cpu_entry_area已经不包含其中的 a set of trampolines;
,至于为什么看这。
那又是怎么实现?
翻来覆去,终于在 pti 初始化处找到了关键点,其实现为
/* * Clone the populated PMDs of the entry and irqentry text and force it RO. */
static void pti_clone_entry_text(void){
pti_clone_pgtable((unsigned long) __entry_text_start,
(unsigned long) __irqentry_text_end,
PTI_CLONE_PMD);}
其将 __entry_text_start
开头的地址复制,而这又与 entry_SYSCALL_64 有什么关系?我们继续往下找
#define ENTRY_TEXT \
ALIGN_FUNCTION(); \
__entry_text_start = .; \
*(.entry.text) \
__entry_text_end = .;
而再看 entry_SYSCALL_64 定义的文件头部
.code64
.section .entry.text, "ax"
所以这里就会把 entry_SYSCALL_64 等一众函数地址拷贝到用户页表,从而实现可访问。具体定义展开这里就不进行了。
继续执行
回到 entry_SYSCALL_64,我们跳过一系列处理,可以看到一个关键点:
call do_syscall_64
很显然了,接下来就是执行 do_syscall_64 了。后面就是常规操作了。
最新 x86_64 系统调用入口分析 (基于 5.7.0)的更多相关文章
- springmvc工作原理以及源码分析(基于spring3.1.0)
springmvc是一个基于spring的web框架.本篇文章对它的工作原理以及源码进行深入分析. 一.springmvc请求处理流程 二.springmvc的工作机制 三.springmvc核心源码 ...
- 开源GUI-Microwindows之程序入口分析
**************************************************************************************************** ...
- Android 短信模块分析(三) MMS入口分析
MMS入口分析: 在Mms中最重要的两个Activity,一个是conversationList(短信列表) ,另一个就是ComposeMessageActivity(单个对话或者短信).每 ...
- 分析Linux内核5.0系统调用处理过程
学号: 363 本实验来源 https://github.com/mengning/linuxkernel/ 一.实验要求 1.编译内核5.02.qemu -kernel linux-5.0.1/ar ...
- Socket与系统调用深度分析
学习一下对Socket与系统调用的分析分析 一.介绍 我们都知道高级语言的网络编程最终的实现都是调用了系统的Socket API编程接口,在操作系统提供的socket系统接口之上可以建立不同端口之间的 ...
- Spring IoC 源码分析 (基于注解) 之 包扫描
在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...
- ceph-csi源码分析(3)-rbd driver-服务入口分析
更多ceph-csi其他源码分析,请查看下面这篇博文:kubernetes ceph-csi分析目录导航 ceph-csi源码分析(3)-rbd driver-服务入口分析 当ceph-csi组件启动 ...
- Spring Ioc源码分析系列--Ioc源码入口分析
Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...
- AtomicInteger源码分析——基于CAS的乐观锁实现
AtomicInteger源码分析——基于CAS的乐观锁实现 1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时 ...
随机推荐
- MyISAM Static 和 MyISAM Dynamic 有什么区别?
在 MyISAM Static 上的所有字段有固定宽度.动态 MyISAM 表将具有像 TEXT, BLOB 等字段,以适应不同长度的数据类型. MyISAM Static 在受损情况下更容易恢复.
- CyclicBarrier 和 CountDownLatch 的区别 ?
1.CountDownLatch 简单的说就是一个线程等待,直到他所等待的其他线程都执 行完成并且调用 countDown()方法发出通知后,当前线程才可以继续执行. 2.cyclicBarrier ...
- redis 为什么是单线程的?
一.Redis为什么是单线程的? 因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽.既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理 ...
- ArrayList 与 LinkedList 的不区别?
最明显的区别是 ArrrayList 底层的数据结构是数组,支持随机访问,而 LinkedList 的底层数据结构书链表,不支持随机访问.使用下标访问一个元素, ArrayList 的时间复杂度是 O ...
- JS练习实例--编写经典小游戏俄罗斯方块
最近在学习JavaScript,想编一些实例练练手,之前编了个贪吃蛇,但是实现时没有注意使用面向对象的思想,实现起来也比较简单所以就不总结了,今天就总结下俄罗斯方块小游戏的思路和实现吧(需要下载代码也 ...
- HTML 初学整理
一.HTML简介 HTML的概念 HTML是HyperText Markup Language(超文本标记语言)的简写,超文本标记语言,标准通用标记语言下的一个应用."超文本"就是 ...
- java中线程有什么用?
线程有什么用? 通过引入线程技术,在浏览器中你可以浏览网页的同时,播放动画和声音效果,同时在后台打印一个页面.例如老板可以同时处理工程师,秘书和清洁人员的事,这 就是多线程处理机制.Within th ...
- Java JDK 动态代理实现和代码分析
JDK 动态代理 内容 一.动态代理解析 1. 代理模式 2. 为什么要使用动态代理 3. JDK 动态代理简单结构图 4. JDK 动态代理实现步骤 5. JDK 动态代理 API 5.1 java ...
- es5语法下,javascript如何判断函数是new还是()调用
es5语法没有支持类class,但是可以通关函数来申明一个类,如下: function Person(name){ this.name=name; } var john=new Person('joh ...
- springboot静态资源无法访问
前言 今天使用springboot+layui+shiro实现一个前后端分离的商城后台系统,一个小小静态资源(image)问题搞了一下午:还好坚持了下来,否者崩溃.吐血都是小事 这是引入的路径 这是图 ...