当前位置: 首页 > news >正文

专业做网站建设建站免费网站推广工具

专业做网站建设建站,免费网站推广工具,强的网站建设公,自己接单赚钱app说明 基于riscv64 soc linux_5.10.4平台,通过新增一个系统调用深入了解下系统调用实现原理。 简介 Linux 软件运行环境分为用户空间和内核空间,默认情况下,用户进程无法访问内核,既不能访问内核所在的内存空间,也不…

说明

  • 基于riscv64 soc + linux_5.10.4平台,通过新增一个系统调用深入了解下系统调用实现原理。

简介

  • Linux 软件运行环境分为用户空间和内核空间,默认情况下,用户进程无法访问内核,既不能访问内核所在的内存空间,也不能调用内核中的函数。
  • 为了给应用层提供系统支持,Linux提供了一组系统调用接口,用户可以通过调用它们访问linux内核的数据和函数。
  • Linux系统调用实现原理是固定,不同平台(arm64,riscv)只是切换至内核态的汇编指令不同,大致原理如下:
  1. 程序将系统调用参数填充到对应的平台通用寄存器。
  2. 调用平台特定的汇编指令,触发同步异常,切换至内核态运行。
  3. 内核初始化时已设置异常向量表,应用层触发同步异常后,CPU会跳到异常向量表对应的异常处理执行(通常是一段平台相关的汇编代码)。
  4. 异常处理代码会检查系统调用号是否超出,未超出,再根据定义的系统调用表(sys_call_table)找到相应的系统调用函数入口地址,执行后,再通过汇编指令返回应用层。
  • 新增系统调用,实现步骤,如下:
  1. 修改系统调用表(syscall_table),新增一项。
  2. 系统调用声明。
  3. 系统调用实现。

修改系统调用表

  • 系统调用表(syscall_table)定义如下:
// file: arch/riscv/kernel/syscall_table.c
#undef __SYSCALL
#define __SYSCALL(nr, call)     [nr] = (call),const void *sys_call_table[__NR_syscalls] = {[0 ... __NR_syscalls - 1] = sys_ni_syscall,
#include <asm/unistd.h> //通过unistd.h导入实际定义
};
  • asm/unistd.h最终定义,如下:
//file: include/uapi/asm-generic/unistd.h 
...
#define __NR_openat2 437     //系统调用openat2 编号
__SYSCALL(__NR_openat2, sys_openat2) //系统调用openat2 syscall_table项定义
#define __NR_pidfd_getfd 438
__SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)
#define __NR_faccessat2 439
__SYSCALL(__NR_faccessat2, sys_faccessat2)
#define __NR_process_madvise 440
__SYSCALL(__NR_process_madvise, sys_process_madvise)#undef __NR_syscalls
#define __NR_syscalls 441 //系统调用表 项个数
...
  • 新增一项系统调用(mytest)
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 15279e8d8..7df066dc5 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -860,8 +860,11 @@ __SYSCALL(__NR_faccessat2, sys_faccessat2)#define __NR_process_madvise 440__SYSCALL(__NR_process_madvise, sys_process_madvise)+#define __NR_mytest 441
+__SYSCALL(__NR_mytest, sys_mytest)
+#undef __NR_syscalls
-#define __NR_syscalls 441
+#define __NR_syscalls 442

系统调用声明

  • 新增系统调用需要先声明,否则内核编译时会报错(找不到新增系统调用声明)。
//file: include/linux/syscalls.h
....
asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior);
asmlinkage long sys_process_madvise(int pidfd, const struct iovec __user *vec,size_t vlen, int behavior, unsigned int flags);
....
+asmlinkage long sys_mytest(int id); //新增系统调用声明

系统调用实现

  • 实现系统调用时,不能像实现普通函数一样,需要使用SYSCALL_DEFINE宏,如:系统调用madvise,定义时使用SYSCALL_DEFINE3宏,宏展开后就是sys_madvise。
//file: mm/madvise.c
SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
{                       return do_madvise(current->mm, start, len_in, behavior);
}int do_madvise(struct mm_struct *mm, unsigned long start, size_t len_in, int behavior)
{        ....//实际功能实现....
}
  • SYSCALL_DEFINE 宏定义
//file: include/linux/syscalls.h
#ifndef SYSCALL_DEFINE0         
#define SYSCALL_DEFINE0(sname)                                  \SYSCALL_METADATA(_##sname, 0);                          \asmlinkage long sys_##sname(void);                      \ALLOW_ERROR_INJECTION(sys_##sname, ERRNO);              \asmlinkage long sys_##sname(void)
#endif /* SYSCALL_DEFINE0 */#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)#define SYSCALL_DEFINE_MAXARGS  6#define SYSCALL_DEFINEx(x, sname, ...)                          \SYSCALL_METADATA(sname, x, __VA_ARGS__)                 \__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
  1. 系统调用最多支持6个参数,1个参数使用SYSCALL_DEFINE1,2个参数使用SYSCALL_DEFINE2,以此类推。
  • 新系统调用
// file: mm/madvise.c ,随便找了一个文件保存代码
SYSCALL_DEFINE1(mytest, int, id)
{return id; //测试将id返回
}

应用层测试

  • 编译并运行新内核后,可运行应用层程序验证。
int main(void) 
{int id = 0;id = syscall(441, 100);printf("result : %d\n", id);return 0;
}~# ./mytest 
result : 100

标准C库

  • 程序中调用的syscall来自标准C库,根据源码可知:应用层系统调用接口是封装的syscall。
  • 当前使用的标准C库(musl)syscall源码如下:
//file: musl-1.2.1/arch/riscv64/syscall_arch.h
...
#define __asm_syscall(...) \__asm__ __volatile__ ("ecall\n\t" \: "=r"(a0) : __VA_ARGS__ : "memory"); \return a0; \static inline long __syscall0(long n)
{register long a7 __asm__("a7") = n;register long a0 __asm__("a0");__asm_syscall("r"(a7))
}
...
static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f)
{register long a7 __asm__("a7") = n;register long a0 __asm__("a0") = a;register long a1 __asm__("a1") = b;register long a2 __asm__("a2") = c;register long a3 __asm__("a3") = d;register long a4 __asm__("a4") = e;register long a5 __asm__("a5") = f;__asm_syscall("r"(a7), "0"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5))
}
  • 可知:
  1. riscv64最终使用汇编指令ecall,触发同步异常,切换至内核态执行。
  2. 使用通用寄存器a7 存储系统调用编号
  3. 和内核定义一致,syscall支持0 ~ 6个参数(__syscall0 ~ __syscall6 ),使用寄存器a0 ~ a5传递参数。
  • ARM64实现原理也是一样,不同的只是触发异常的指令(svc)以及通用寄存器的使用,如下:
#define __asm_syscall(...) do { \__asm__ __volatile__ ( "svc 0" \: "=r"(x0) : __VA_ARGS__ : "memory", "cc"); \return x0; \} while (0)static inline long __syscall0(long n)
{register long x8 __asm__("x8") = n;register long x0 __asm__("x0");__asm_syscall("r"(x8));
}
...
static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f)
{register long x8 __asm__("x8") = n;register long x0 __asm__("x0") = a;register long x1 __asm__("x1") = b;register long x2 __asm__("x2") = c;register long x3 __asm__("x3") = d;register long x4 __asm__("x4") = e;register long x5 __asm__("x5") = f;__asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5));
}

总结

  1. 系统调用是安全的,执行时,应用层没有访问内核空间。
  2. 系统调用执行时,应用层暂停,切换至内核空间执行。
  3. 系统调用执行时,是通过平台相关的特定汇编指令触发同步异常,riscv64是使用ecall,aarch64是使用svc 0,Intel CPU由中断0x80实现。
  • CPU会跳转到对应的异常处理,源码如下:
//file: arch/riscv/kernel/entry.S
....
ENTRY(handle_exception) //对应的异常处理....
check_syscall_nr:/* Check to make sure we don't jump to a bogus syscall number. */li t0, __NR_syscallsla s0, sys_ni_syscall/** Syscall number held in a7.* If syscall number is above allowed value, redirect to ni_syscall.*/bgeu a7, t0, 3f
#ifdef CONFIG_COMPATREG_L s0, PT_STATUS(sp)srli s0, s0, SR_UXL_SHIFTandi s0, s0, (SR_UXL >> SR_UXL_SHIFT)li t0, (SR_UXL_32 >> SR_UXL_SHIFT)sub t0, s0, t0bnez t0, 1f/* Call compat_syscall */la s0, compat_sys_call_tablej 2f
1:
#endif/* Call syscall */la s0, sys_call_table
2:slli t0, a7, RISCV_LGPTRadd s0, s0, t0REG_L s0, 0(s0)
3:jalr s0ret_from_syscall:
....
  1. 内核态调用对应的系统调用函数,执行完后,会退出内核态切换至用户态,如上 ret_from_syscall。
  • 此过程 aarch64平台是由eret汇编指令实现,和arm trustzone机制 bl31切换至非安全world(REE)以及切换至安全world(bl32)实现流程是一样的,riscv64 平台,具体指令暂不明。
http://www.hkea.cn/news/544351/

相关文章:

  • 网站设计与推广国际时事新闻2022最新
  • 柬埔寨网站开发营销技巧和营销方法
  • 网站建立价格长沙网站外包公司
  • 王建设医生个人网站免费google账号注册入口
  • 免费自建手机网站搜索引擎优化的方法包括
  • 甘肃省建设工程安全质量监督管理局网站官网拉新项目官方一手平台
  • 做电影网站赚钱武汉新闻最新消息
  • 做网站没有成本的方法上海百度分公司电话
  • 寺庙网站建设百度ai人工智能
  • 完成公司网站建设下载关键词推广软件
  • wordpress如何关闭网站下载app
  • WordPress小程序二次修改石家庄seo排名外包
  • 做百度关键词网站厦门seo外包
  • 泉州seo-泉州网站建设公司谷歌关键词搜索工具
  • 组织部网站建设方案行业关键词分类
  • 上海黄浦 网站制作中国搜索引擎排名2021
  • 手机网站建设 cms营销技巧和营销方法
  • 平顶山做网站优化微博搜索引擎优化
  • 网站如何做品牌宣传海报每日舆情信息报送
  • 做论坛网站需要多大空间seo推广招聘
  • 中国建设银行网站软件不限次数观看视频的app
  • 网站开发建设的步骤win11优化大师
  • 在线做数据图的网站樱桃bt磁力天堂
  • 网站建设费的税率东莞公司网上推广
  • 上海设计公司排名前十宁波seo搜索优化费用
  • 如皋做网站公司com域名
  • 织梦做企业网站教程网络营销推广方案论文
  • 微信如何添加小程序二十条优化措施全文
  • 网站制作费可以做业务宣传费河北百度推广电话
  • wordpress日主题破解网站排名优化软件有哪些