Доступ к маркировке снаружи функции

Код:

/* 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 таким образом, я могу восстановить контекст ядра и возвратить значение syscall к dispatcher().

Как я могу получить доступ к адресу памяти _entry_point снаружи функции?

7
задан Mike Douglas 7 February 2010 в 01:37
поделиться

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);
}
3
ответ дан 7 December 2019 в 05:22
поделиться

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

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

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

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

4
ответ дан 7 December 2019 в 05:22
поделиться

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

asm volatile("_entry_point:");

void contextinit() {
  extern void _entry_point();
  set_evec(49, (long)&_entry_point);
}
1
ответ дан 7 December 2019 в 05:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: