从函数外部访问标签

时间:2010-02-07 01:15:32

标签: c assembly kernel

代码:

/* ctsw.c : context switcher
 */

#include <kernel.h>

static void *kstack;
extern int set_evec(int, long);

/* contextswitch - saves kernel context, switches to proc */
enum proc_req contextswitch(struct proc_ctrl_blk *proc) {
  enum proc_req call;

  kprintf("switching to %d\n", getpid(proc));

  asm volatile("pushf\n"          // save kernel flags
               "pusha\n"          // save kernel regs
               "movl %%esp, %0\n" // save kernel %esp
               "movl %1, %%esp\n" // load proc %esp
               "popa\n"           // load proc regs (from proc stack)
               "iret"             // switch to proc
               : "=g" (kstack)
               : "g" (proc->esp)
               );

_entry_point:
  asm volatile("pusha\n"          // save proc regs
               "movl %%esp, %0\n" // save proc %esp
               "movl %2, %%esp\n" // restore kernel %esp
               "movl %%eax, %1\n" // grabs syscall from process
               "popa\n"           // restore kernel regs (from kstack)
               "popf"             // restore kernel flags
               : "=g" (proc->esp), "=g" (call)
               : "g" (kstack)
               );
  kprintf("back to the kernel!\n");

  return call;
}

void contextinit() {
  set_evec(49, (long)&&_entry_point);
}

这是一个小型,合作,非抢占式内核的上下文切换器。 contextswitch()使用要加载的进程的堆栈指针调用dispatcher()。加载%esp和其他通用寄存器后,将调用iret并开始运行用户进程。

我需要设置一个中断,以便在contextswitch()之后返回iret中的点,这样我就可以恢复内核上下文并将系统调用的值返回给dispatcher()

如何从函数外部访问_entry_point的内存地址?

3 个答案:

答案 0 :(得分:4)

切换函数的实现:使它看起来像这样:

  • 从用户到内核的上下文切换;
  • 调用内核例程;
  • 上下文从内核切换回用户。

然后你可以设置中断从一开始就运行该功能。需要有一个“当前用户进程”的全局指针 - 在进程之间切换,由“调用内核例程”运行的内核代码只是将该变量更改为指向不同的进程。

对于从内核到用户模式的初始切换,您将需要一个特殊情况,用于启动后运行的初始进程。在那之后,上面的函数应该能够处理它。

答案 1 :(得分:3)

在与GCC玩了一会儿之后,我得到了答案。

下降到装配静音GCC警告未使用的标签。

所以,

_entry_point:

替换为

asm volatile("_entry_point:");

void contextinit() {
  set_evec_(49, &&_entry_point);
}

替换为

void contextinit() {
  long x;
  asm("movl $_entry_point, %%eax\n"
      "movl %%eax, %0": "=g" (x) : : "%eax");
  set_evec(49, x);
}

答案 2 :(得分:1)

除了使用内联汇编访问_entry_point之外,您还可以将其定义为函数,如:

asm volatile("_entry_point:");

void contextinit() {
  extern void _entry_point();
  set_evec(49, (long)&_entry_point);
}