首页 > 其他分享 >dummy的系统调用

dummy的系统调用

时间:2024-11-13 22:08:22浏览次数:1  
标签:load dummy 调用 pt segments 系统 yield 加载

dummy的系统调用

os的异常处理

让Nanos-lite(后面统称为os)事件处理回调函数识别自陷事件EVENT_YIELD.

os初始化CTE的时候,注册的回调函数为do_event,所以修改其中的事件判断条件即可(在nanos-lite/src/irq.c中定义)

static Context* do_event(Event e, Context* c) {
  switch (e.event) {
		case EVENT_YIELD:   printf("EVENT_YIELD event!\n");   break;
		case EVENT_SYSCALL: do_syscall(c);                    break;
    default: panic("Unhandled event ID = %d", e.event);
  }

  return c;
}

void init_irq(void) {
  Log("Initializing interrupt/exception handler...");
  cte_init(do_event);
}

os可以正确触发自陷操作,为应用程序提供了执行流切换的入口。下一步就是将程序加载到os中。注意:在Nanos-lite中, Log()宏通过你在klib中编写的printf()输出, 最终会调用TRM的putch().

加载程序

在操作系统中, 加载用户程序是由loader(加载器)模块负责的。其功能是:

  • 从文件中获取要加载的信息get_pt_load_segments()
  • 加载获取到的信息到内存load_segments
  • 返回入口地址

做完了PA上面的操作后,可以得知可执行文件位于ramdisk偏移为0处, 访问它就可以得到用户程序的第一个字节.结合ELF文件的操作man 5 elf,可以写出从ELF文件中获取要加载的信息函数get_pt_load_segments()

// 获取 PT_LOAD 段的数组和数量,并返回控制转移的入口地址
uintptr_t get_pt_load_segments(const char *filename, Elf_Phdr *pt_load_segments, size_t *num_pt_load_segments) {

  Elf_Ehdr ehdr;
  
  // Step 1: 读取 ELF 头部
  ramdisk_read(&ehdr, 0, sizeof(Elf_Ehdr));
  
  // 检查 ELF 魔数
  if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
      panic("Not a valid ELF file.\n");
  }
  
  // Step 2: 读取所有 Program Headers
  Elf_Phdr phdrs[MAX_SEGMENTS];
  ramdisk_read(phdrs, ehdr.e_phoff, ehdr.e_phnum * sizeof(Elf_Phdr));
  
  // Step 3: 筛选出所有 PT_LOAD 段
  int count = 0;
  for (int i = 0; i < ehdr.e_phnum; i++) {
      if (phdrs[i].p_type == PT_LOAD) {
          pt_load_segments[count++] = phdrs[i];
      }
  }
  // 保存要加载程序段的条目
  *num_pt_load_segments = count;

  // Step 4: 返回控制转移的入口地址
  return ehdr.e_entry;
}

以及将程序段加载到内存中的函数load_segments()

// 段加载函数,输入参数为pt_load_segments和其数量
void load_segments(Elf_Phdr *pt_load_segments, int num_segments){
  for (int i = 0; i < num_segments; i++) {
    Elf_Phdr *seg = &pt_load_segments[i];

    // 获取段的偏移、虚拟地址、文件大小、内存大小
    size_t offset = seg->p_offset;
    uint32_t vaddr = seg->p_vaddr;
    size_t filesz = seg->p_filesz;
    size_t memsz = seg->p_memsz;

    // 从ramdisk中读取段数据到内存
    ramdisk_read((void *)(vaddr), offset, filesz);

    // 清零 [VirtAddr + FileSiz, VirtAddr + MemSiz) 的内存
    if (memsz > filesz) {
      memset((void *)(vaddr + filesz) , 0, memsz - filesz);
    }
  }
}

两个主要功能做好后,loader的功能就ok了。

#define MAX_SEGMENTS 16  // 假设 ELF 文件中 Program Headers 的最大数量
static uintptr_t loader(PCB *pcb, const char *filename) {
  size_t count;
  Elf_Phdr pt_load_segments[MAX_SEGMENTS];
  // 获取要加载的段信息
  uintptr_t entry = get_pt_load_segments(filename, pt_load_segments, &count);

  // 加载段到内存中
  load_segments(pt_load_segments, count);
  return entry;
}

系统调用

这里的系统调用包含两个操作:

  • 系统调用参数:通过通用寄存器保存
  • 系统调用指令:自陷指令ecall

dummy程序会执行系统调用方法_syscall_()

#define SYS_yield 1
_syscall_(SYS_yield, 0, 0, 0);

具体定义在navy-apps/libs/libos/src/syscall.c

intptr_t _syscall_(intptr_t type, intptr_t a0, intptr_t a1, intptr_t a2) {
  register intptr_t _gpr1 asm (GPR1) = type;
  register intptr_t _gpr2 asm (GPR2) = a0;
  register intptr_t _gpr3 asm (GPR3) = a1;
  register intptr_t _gpr4 asm (GPR4) = a2;
  register intptr_t ret asm (GPRx);
  asm volatile (SYSCALL : "=r" (ret) : "r"(_gpr1), "r"(_gpr2), "r"(_gpr3), "r"(_gpr4));
  return ret;
}

结合繁多的宏定义,解析_syscall_()的行为:

  • 通用寄存器 a7a0a1a2分别保存系统调用的参数
  • 调用自陷指令ecall
  • 执行完毕后,将寄存器a0值传递给变量ret作为返回值

联系之前CTE中yield()在调用自陷指令之前,用a7保存了一个-1

li a7, -1

其目的都是相同的。用a7来保存系统调用的类型,这样不同的事件(访问文件、IO操作等)调用相同的自陷指令进行执行流切换的时候,就可以区分出来了。

这样就要修改CTE中的异常事件处理函数__am_irq_handle()中,对于事件的判断条件。将之前的从CSR寄存器mcause判断改为从寄存器a7中判断

Context* __am_irq_handle(Context *c) {
  if (user_handler) {
    Event ev = {0};
    int type = (int) c->GPR1;
    if (type < 0) {
      ev.event = EVENT_YIELD;
    } else if (type >= 0 && type <= 16) {
      ev.event = EVENT_SYSCALL; 
    }else {
      printf("c->GPR1 = %d\n", c->GPR1);
      assert(0);
    }
    c = user_handler(ev, c);
    assert(c != NULL);
  }
  return c;
}

abstract-machine/am/include/arch/riscv.h中,根据RISCV32的ABI定义的寄存器名称,修改通用寄存器下标,实现正确的GPR?宏, 让它们从上下文c中获得正确的系统调用参数寄存器.

#define GPR1 gpr[17] // a7
#define GPR2 gpr[10] // a0
#define GPR3 gpr[11] // a1
#define GPR4 gpr[12] // a2
#define GPRx gpr[10] // a0

这样异常事件打包函数__am_irq_handle就可以将自陷指令对应的系统调用事件EVENT_SYSCALL打包起来,交付给os处理了。

os收到系统调用事件之后,将会调出系统调用处理函数do_syscall()进行处理.并且按照用户进程之前设置好的系统调用参数(a7保存的值),进行下一步的分发。这里dummy的系统调用参数为1,触发了一个SYS_yield的系统调用。实现SYS_yield系统调用宏:

  • 调用CTE的yield()
  • 返回值设置为0
void sys_yield(Context *c) {
  yield();
  c->GPRx = 0;
}
void sys_exit() {
  halt(SYS_exit);
}
void do_syscall(Context *c) {
  uintptr_t a[4];
  a[0] = c->GPR1;

  switch (a[0]) {
    case SYS_exit : sys_exit(c);  break;
    case SYS_yield: sys_yield(c); break;
    default: panic("Unhandled syscall ID = %d", a[0]);
  }
}

标签:load,dummy,调用,pt,segments,系统,yield,加载
From: https://www.cnblogs.com/shangshankandashu/p/18544939

相关文章

  • 基于nodejs+vue中小型酒店管理系统[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于酒店管理系统的研究,现有研究主要以大型酒店或连锁酒店为主,专门针对中小型酒店管理系统的研究较少。在国内外,大型酒店由于资源丰富、管理复杂,吸引了......
  • 操作系统复习2-wait、signal操作第二部分
    4.佩奇、米老鼠、汤姆一起玩放水果的游戏。佩奇不停的往空盘子中放苹果米老鼠不停的取苹果,汤姆不停的取橘子。假设这个盘子最多能放的水果且他们三个不能同时取用。完成如下两问请写出记录型信号量的wait和signal操作的定义(7分)。请用信号量机制和wait和signal操作实现这三......
  • 基于springboot月子护理中心管理系统设计与实现
    开发说明abo开发说明开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:Maven3.3.9浏览器:谷歌浏览器后台路径地址:localhost:8080/项目名称/admin/dist/index.html前......
  • 基于FPGA的1024QAM基带通信系统,包含testbench,高斯信道模块,误码率统计模块,可以设置
    1.算法仿真效果vivado2019.2仿真结果如下(完整代码运行后无水印): 设置SNR=40db   将数据导入matlab显示星座图:   设置SNR=35db   将数据导入matlab显示星座图:   仿真操作步骤可参考程序配套的操作视频。 2.算法涉及理论知识概要     ......
  • 基于nodejs+vue中小型企业工资管理系统[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于工资管理系统的研究,现有研究多以大型企业或通用型企业管理系统为主,专门针对中小型企业工资管理系统的研究较少。在国内外,大型企业的工资管理系统往......
  • 基于微信小程序的奶茶点单系统
    毕业设计——基于微信小程序的奶茶点单系统摘要        随着“移动互联网+”不断发展,人们对于生活的消费方式和理念发生了巨大转变,微信已然成为了必备的手机软件。而微信小程序的出现,更是给消费者和商家们带来了极大的便利,对于爱喝奶茶的朋友而言,奶茶店自助点单小......
  • 基于Java+SpringBoot+Mysql在线课程学习教育系统功能设计与实现七
    一、前言介绍:免费获取:猿来入此1.1项目摘要随着信息技术的飞速发展和互联网的普及,教育领域正经历着深刻的变革。传统的面对面教学模式逐渐受到挑战,而在线课程学习教育系统作为一种新兴的教育形式,正逐渐受到广泛关注和应用。在线课程学习教育系统的出现,不仅为学生提供了更加灵......
  • node.js毕设通达学院竞赛信息管理系统(程序+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于高校竞赛信息管理的研究,现有研究主要集中在竞赛活动的组织与管理、学生参与竞赛的效果评估等方面。专门针对高校竞赛信息管理系统的开发与应用的研......
  • node.js毕设校园图书借阅系统(程序+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景随着信息技术的快速发展,图书馆管理系统也在不断更新和升级。传统的图书借阅方式已经无法满足现代高校师生对图书资源的需求。近年来,国内外学者对图书借......
  • 【Unity 天气系统插件】Enviro 3 - Sky and Weather 高度可定制的云、雾和光照系统
    Enviro3-SkyandWeather是一款功能强大的Unity插件,专门用于模拟逼真的天空、天气和环境效果。它适用于需要动态天气和日夜循环的游戏或应用,如开放世界RPG、模拟类游戏等。Enviro3提供了大量的设置选项和自定义功能,帮助开发者在Unity中创建沉浸式的自然环境效果。......