最新 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)的更多相关文章

  1. springmvc工作原理以及源码分析(基于spring3.1.0)

    springmvc是一个基于spring的web框架.本篇文章对它的工作原理以及源码进行深入分析. 一.springmvc请求处理流程 二.springmvc的工作机制 三.springmvc核心源码 ...

  2. 开源GUI-Microwindows之程序入口分析

    **************************************************************************************************** ...

  3. Android 短信模块分析(三) MMS入口分析

    MMS入口分析:      在Mms中最重要的两个Activity,一个是conversationList(短信列表) ,另一个就是ComposeMessageActivity(单个对话或者短信).每 ...

  4. 分析Linux内核5.0系统调用处理过程

    学号: 363 本实验来源 https://github.com/mengning/linuxkernel/ 一.实验要求 1.编译内核5.02.qemu -kernel linux-5.0.1/ar ...

  5. Socket与系统调用深度分析

    学习一下对Socket与系统调用的分析分析 一.介绍 我们都知道高级语言的网络编程最终的实现都是调用了系统的Socket API编程接口,在操作系统提供的socket系统接口之上可以建立不同端口之间的 ...

  6. Spring IoC 源码分析 (基于注解) 之 包扫描

    在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...

  7. ceph-csi源码分析(3)-rbd driver-服务入口分析

    更多ceph-csi其他源码分析,请查看下面这篇博文:kubernetes ceph-csi分析目录导航 ceph-csi源码分析(3)-rbd driver-服务入口分析 当ceph-csi组件启动 ...

  8. Spring Ioc源码分析系列--Ioc源码入口分析

    Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...

  9. AtomicInteger源码分析——基于CAS的乐观锁实现

    AtomicInteger源码分析——基于CAS的乐观锁实现 1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时 ...

随机推荐

  1. MyISAM Static 和 MyISAM Dynamic 有什么区别?

    在 MyISAM Static 上的所有字段有固定宽度.动态 MyISAM 表将具有像 TEXT, BLOB 等字段,以适应不同长度的数据类型. MyISAM Static 在受损情况下更容易恢复.

  2. CyclicBarrier 和 CountDownLatch 的区别 ?

    1.CountDownLatch 简单的说就是一个线程等待,直到他所等待的其他线程都执 行完成并且调用 countDown()方法发出通知后,当前线程才可以继续执行. 2.cyclicBarrier ...

  3. redis 为什么是单线程的?

    一.Redis为什么是单线程的? 因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽.既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理 ...

  4. ArrayList 与 LinkedList 的不区别?

    最明显的区别是 ArrrayList 底层的数据结构是数组,支持随机访问,而 LinkedList 的底层数据结构书链表,不支持随机访问.使用下标访问一个元素, ArrayList 的时间复杂度是 O ...

  5. JS练习实例--编写经典小游戏俄罗斯方块

    最近在学习JavaScript,想编一些实例练练手,之前编了个贪吃蛇,但是实现时没有注意使用面向对象的思想,实现起来也比较简单所以就不总结了,今天就总结下俄罗斯方块小游戏的思路和实现吧(需要下载代码也 ...

  6. HTML 初学整理

    一.HTML简介 HTML的概念 HTML是HyperText Markup Language(超文本标记语言)的简写,超文本标记语言,标准通用标记语言下的一个应用."超文本"就是 ...

  7. java中线程有什么用?

    线程有什么用? 通过引入线程技术,在浏览器中你可以浏览网页的同时,播放动画和声音效果,同时在后台打印一个页面.例如老板可以同时处理工程师,秘书和清洁人员的事,这 就是多线程处理机制.Within th ...

  8. Java JDK 动态代理实现和代码分析

    JDK 动态代理 内容 一.动态代理解析 1. 代理模式 2. 为什么要使用动态代理 3. JDK 动态代理简单结构图 4. JDK 动态代理实现步骤 5. JDK 动态代理 API 5.1 java ...

  9. es5语法下,javascript如何判断函数是new还是()调用

    es5语法没有支持类class,但是可以通关函数来申明一个类,如下: function Person(name){ this.name=name; } var john=new Person('joh ...

  10. springboot静态资源无法访问

    前言 今天使用springboot+layui+shiro实现一个前后端分离的商城后台系统,一个小小静态资源(image)问题搞了一下午:还好坚持了下来,否者崩溃.吐血都是小事 这是引入的路径 这是图 ...