Обещанные подробности
Режим ядра
Режим пользователя
Видно, что при выполнении прикладного потока в TSS хранится вершина стека ядра, а реально используемый потоком стек в другом месте
Инициализация режима пользователя
Код:
/*-----------------------------------------------------------------------------
* Switch to user mode
*---------------------------------------------------------------------------*/
void init_user_mode(void* entry_point, size_t stack_size)
{
void* user_stack = kmalloc(stack_size);
user_mode_switch(entry_point, (u32int) user_stack + stack_size);
}
Переключение в режим пользователя
Код:
/*-----------------------------------------------------------------------------
/
/ Switch to ring 3
/ (c) maisvendoo, 21.08.2013
/
/----------------------------------------------------------------------------*/
.set USER_CS, 0x1B /* user mode code selector */
.set USER_SS, 0x23 /* user mode stack selector */
.set USER_DS, 0x23 /* user mode data selector */
.global user_mode_switch
user_mode_switch:
mov 4(%esp), %edx /* entry_point --> EDX */
/* Set user data selector */
mov $USER_DS, %ax
mov %ax, %ds
mov %ax, %es
/* Prepare to SS, CS and EIP register loading */
mov 8(%esp), %eax /* user_stack_top --> EAX */
pushl $USER_SS /* Push SS value into stack */
pushl %eax /* Push ESP value into stack */
pushf /* Push EFLAGS into stack */
push $USER_CS /* Push CS value into stack */
push %edx /* Push EIP unto stack */
/* (user mode thread entry point) */
iret /* Return from interrupt to ring 3! */
Тут не обошлось и без "дурости". В начале, вчера, пропихнул в стек указатель на стек используемый главным потоком ядра. Это привело к тому, что при попытке "обернуть" системный вызов функцией C при выходе из подпрограмм из стека начали выталкиваться значения типа 0x23 и 0x1B, то есть загруженные ранее в этот же стек селекторы. Полезли #PF и #GP в произвольном порядке. в итоге вспомнил что
phantom-84 писал(а):
Еще нужно сохранить в стеке указатель на прикладной стек
Сделал свой стек этому потоку, косяки сразу исчезли, всё пашет пока как часы.
Понял что при переходе в ring 3, после вызова iret, происходит загрузка всех селекторов из стека ядра, оттуда же берется и устанавливается в ESP указатель на прикладной стек, загружается EIP точкой входа на прикладной код.
Для реализации системных вызовов использую шлюз ловушки - запись в IDT с байтом доступа 0xEF и селектором 0x8. Номер программного прерывания int 50h.
P.S.: На скринах можно увидеть открытый мануал JM. Да, я "стырил" оттуда некоторые макросы, на время, уже думаю избавится, хотя может и не буду. Весь приведенный код - самописный, по руководству Intel на 80386 и советам phantom-84