Доступ к метке извне функции - PullRequest
7 голосов
/ 07 февраля 2010

код:

/* 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 ]

4 голосов
/ 07 февраля 2010

Переключите реализацию функции: сделайте так, чтобы она выглядела так:

  • Переключение контекста с пользователя на ядро;
  • вызов в подпрограммы ядра;
  • Переключение контекста с ядра на пользователя.

Тогда вы можете просто установить прерывание для запуска функции с самого начала. Для «текущего пользовательского процесса» должен быть глобальный указатель - для переключения между процессами код ядра, который запускается «Вызовом подпрограмм ядра», просто изменяет эту переменную, указывая на другой процесс.

Вам понадобится один особый случай - для первоначального переключения из режима ядра в пользовательский режим, для начального процесса, который выполняется после загрузки. Однако после этого вышеприведенная функция сможет с этим справиться.

3 голосов
/ 07 февраля 2010

Немного поиграв с 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);
}
1 голос
/ 17 февраля 2010

Помимо использования встроенной сборки для доступа к _entry_point, вы также можете определить ее как функцию, например:

asm volatile("_entry_point:");

void contextinit() {
  extern void _entry_point();
  set_evec(49, (long)&_entry_point);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...