Переключение в режим пользователя с помощью iret - PullRequest
12 голосов
/ 01 августа 2011

Я пишу небольшую ОС, которая будет выполнять некоторый код в пользовательском режиме (уровень привилегий 3).Из этого кода уровня пользователя я хочу вызвать прерывание обратно в ОС, которая печатает сообщение.Сейчас мне не важно, как мой обработчик прерываний принимает аргументы или что-то в этом роде, я просто хочу, чтобы обработчик прерываний информировал меня (пользователя) о выполнении кода.

Мой вопрос: какзапустить код в режиме пользователя?У меня есть функция, которая устанавливает таблицу локальных дескрипторов с сегментом кода и сегментом данных (оба с привилегиями пользовательского режима).Что я не понимаю, так это то, как я должен загружать эти сегменты в cs, ss и ds.Я успешно загрузил свой LDT, но я не знаю, как на самом деле его использовать.Я слышал, что должен использовать iret, но я не совсем понимаю, как.

Другой вопрос, который у меня возникает, - как должен работать мой обработчик прерываний.Допустим, я установил обработчик прерываний для вектора с номером 0x40, который я хочу напечатать «привет, пользовательский режим!».Я знаю, как настроить обработчик прерываний, но я не совсем понимаю, как будет переключаться контекст при входе в обработчик прерываний ядра из пользовательского режима.Я знаю, что регистр cs должен измениться, поскольку моя подпрограмма будет выполняться из сегмента кода, указанного в моей записи IDT.Я также понимаю, что селектор стека, вероятно, также изменяется, но я не могу быть уверен в этом.

Может кто-нибудь объяснить мне, какие изменения контекста производятся при вызове шлюза прерываний?

Ответы [ 2 ]

23 голосов
/ 01 августа 2011

Добраться до звонка 3 можно с помощью iret, потому что способ его работы был задокументирован. Когда вы получаете прерывание, процессор нажимает:

  1. Сегмент стека и указатель (ss: esp) в виде 4 слов
  2. EFLAGS
  3. Сегмент кода возврата и указатель инструкции (cs: eip) в виде 4 слов
  4. Код ошибки, если требуется.

iret работает путем отмены шагов 1-3 (ISR отвечает за отмену шага 4 при необходимости). Мы можем использовать этот факт, чтобы добраться до кольца 3, помещая необходимую информацию в стек и выполняя инструкцию iret. Убедитесь, что у вас есть правильный CPL в вашем коде и сегментах стека (младшие два бита должны быть установлены в каждом). Однако iret не изменяет ни один из сегментов данных, поэтому вам придется изменить их вручную. Для этого вы используете инструкцию mov, но вы не сможете читать данные вне стека между выполнением этого и переключением колец.

cli
mov   ax, Ring3_DS
mov   ds, eax
push  dword Ring3_SS
push  dword Ring3_ESP
pushfd
or    dword [esp], 0x200 // Set IF in EFLAGS so that interrupts will be reenabled in user mode
push  dword Ring3_CS
push  dword Ring3_EIP
iret

Если вы хотите получить полный рабочий пример, см. этот учебник .


Когда выдается прерывание, процессор считывает вашу IDT, чтобы получить правильный сегмент кода и указатель инструкций для ISR. Затем он смотрит на ваш TSS, чтобы найти новый сегмент стека и указатель. Он соответственно изменяет ss и esp, а затем помещает старые значения в новый стек. Он не изменяет любой из регистров сегмента данных. Вы должны сделать это вручную, если вам нужен доступ к памяти в вашем ISR.

1 голос
/ 24 марта 2015

Вы также можете сделать ретф.Дальний возврат к менее привилегированному сегменту кода приведет к тому, что новые ss и sp будут выталкиваться из привилегированного стека.

Просто убедитесь, что вы делаете дальний возврат для дальних вызовов и irets для прерываний.Единственная разница между ними заключается в наличии флагов в стеке, но не стоит смешивать их.

Кроме того, не забывайте, что исключения иногда помещают коды ошибок в стек.

...