OSDev

для всех
Текущее время: 10 май 2024, 00:01

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 12 ]  На страницу 1, 2  След.
Автор Сообщение
СообщениеДобавлено: 17 фев 2010, 22:30 

Зарегистрирован: 16 фев 2010, 22:03
Сообщения: 101
Пишу 64-битную операционку. В режиме супервизора загружаю в IDTR адрес таблицы прерываний, устанавливаю обработчики, разрешаю прерывания. Всё работает нормально. Стоит мне перейти на код в режиме пользователя всё рушится. Если запретить прерывания, то всё работает нормально. Дело не в обработчике прерывания - он даже не успевает вызваться. В чём может быть проблема?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 18 фев 2010, 08:12 

Зарегистрирован: 28 окт 2007, 18:33
Сообщения: 1418
Со стеками порядок? Они ж разные должны быть.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 18 фев 2010, 15:17 

Зарегистрирован: 16 фев 2010, 22:03
Сообщения: 101
Я RSP0 в TSS настроил. У ядра и пользовательского кода разные стеки. Код пользователя точно не при чём - обычный бесконечный цикл jmp $. Ошибка возникает только если обработчик и текущй код имеют разные уровни привелегий. Пробовал устанавливать обработчики из USER MODE и ошибка не возникает. Может ошибка в описании дексриптора TSS и там указан неправильный адрес?
Код:
0x0000E90000003001 + ((tss and 0xFFFFFF) shl 16) + ((tss and 0xFF000000) shl 32),tss shr 32 ; TSS

Селектор, который я загружаю в TR точно верный иначе бы ошибка возникала ещё раньше.
Или дело может быть в описании дескриптора прерывания я пробовал устанавливать атрибуты и 0x8E (нельзя вызвать из пользовательского кода) и 0xEF (можно вызвать из пользовательского кода).
Ошибка происходит и при программном прерывании(разумеется, в этом случае у вызываемого прерывания атрибут 0xEF), а не только IRQ.
Я тестирую на Bochs 2.4.2. Я, надеюсь, это не его баг, иначе мне придётся искать другую VM.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 19 фев 2010, 00:05 

Зарегистрирован: 28 окт 2007, 18:33
Сообщения: 1418
А нельзя полный код ТСС и дескрипторов прерываний? Помедитировал бы над ними завтра (точней, уже сегодня) на работе...


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 19 фев 2010, 08:05 

Зарегистрирован: 16 фев 2010, 22:03
Сообщения: 101
Вот описание TSS:
Код:
; TSS
struct TSS
   dd ?
   rsp0 dq ?
   rsp1 dq ?
   rsp2 dq ?
   dq ?
   ist1 dq ?
   ist2 dq ?
   ist3 dq ?
   ist4 dq ?
   ist5 dq ?
   ist6 dq ?
   ist7 dq ?
   dq ?
   dw ?
   io_map_offset dw ?
   io_map db 8192 dup (?)
ends
virtual at 0xFFFFFFFFFFFFA000
   tss TSS
end virtual

Заполнение TSS (помять под TSS точно выделена)
Код:
   ; Загрузим значение в TR
   mov ax, TSS_SELECTOR
   ltr ax
   ; Настроим TSS
   mov rax, rsp
   mov [tss.rsp0], rax
   mov [tss.rsp1], rax
   mov [tss.rsp2], rax
   mov [tss.ist1], rax
   mov [tss.ist2], rax
   mov [tss.ist3], rax
   mov [tss.ist4], rax
   mov [tss.ist5], rax
   mov [tss.ist6], rax
   mov [tss.ist7], rax
   mov [tss.io_map_offset], tss.io_map - tss
   xor rax, rax
   mov rdi, tss.io_map
   mov rcx, 8192 / 8
   rep stosq

Код:
; Установка обработчика DX:RAX на прерывание BL типа BH
set_int_handler:
   push rdi
   movzx rdi, bl
   shl rdi, 4
   lea rdi, [qword idt + rdi]
   stosw
   mov ax, dx
   stosw
   xor al, al
   mov ah, bh
   stosw
   shr rax, 16
   stosw
   shr rax, 16
   stosd
   xor rax, rax
   stosd
   pop rdi
   ret

Код:
   ; Выделим память под таблицу дескрипторов прерываний
   mov rcx, 1
   call alloc_phis_memory
   mov rbx, cr3
   mov rdx, idt
   mov rcx, 1
   or rax, 11b
   call map_pages
   xor rax, rax
   mov rdi, idt
   mov rcx, 512
   rep stosq
   ; Установим стантартные обработчики прерываний
   mov dx, KERNEL_CODE64_SELECTOR
   mov rcx, 256
   xor bl, bl
   mov bh, 0xEF
@@:
   mov rax, default_int_handler
   call set_int_handler
   inc bl
   loop @b
   ; Установим стандартные обработчики IRQ прерываний
   mov rcx, 16
   mov bl, 0x20
   mov bh, 0xEF
@@:
   mov rax, default_IRQ_handler
   call set_int_handler
   inc bl
   loop @b
   ; Перенастроим контроллер прерываний
   mov al, 0x11
   out 0x20, al
   out 0xA0, al
   mov al, 0x20
   out 0x21, al
   add al, 8
   out 0xA1, al
   mov al, 4
   out 0x21, al
   mov al, 2
   out 0xA1, al
   mov al, 1
   out 0x21, al
   out 0xA1, al
   ; Загрузим значение в IDTR
   lidt [idtr]
           ; Разрешим прерывания
           sti


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 19 фев 2010, 13:19 

Зарегистрирован: 28 окт 2007, 18:33
Сообщения: 1418
Такс... малость помедитировал (что-то много работы сегодня на работе оказалось).

Во-первых, пара замечаний, хотя на работоспособность это не влияет:

1. Вы грузите LTR, и лишь затем заполняете TSS. ИМХО, так поступать не следует, поскольку загрузка значения в LTR "логически" подразумевает, что TSS уже корректен, а это не так.

2. Подпрограмму формирования дескриптора IDT можно сократить минимум на 1 байт. Для этого в её последних строках:

Код:
   xor rax, rax
   stosd


надо xor rax, rax заменить на xor eax, eax. Суть в том, что обращение к новым регистрам, а также в 64-разрядным расширениям старых требует наличия префикса REX, ну а для доступа к старым 8/16/32-разрядным этот префикс не нужен, что и даёт экономию :)

Ну а из реального криминала пока что вызывает подозрение заполнение полей указателей стека в TSS, т.е. вот эта последовательность команд:

Код:
   mov rax, rsp
   mov [tss.rsp0], rax
   mov [tss.rsp1], rax
   mov [tss.rsp2], rax


Вопрос в том, на какую границу выровнен текущий RSP. Согласно интеловскому мануалу,

Цитата:
Although the RSP alignment is always performed when LMA = 1, it is only of consequence
for the kernel-mode case where there is no stack switch or IST used. For a
stack switch or IST, the OS would have presumably put suitably aligned RSP values in
the TSS.


Т.е. в случае, когда происходит переключение стека, в TSS должны лежать правильно выровненные значения RSP. А правильное выравнивание для него -- не 8, как можно подумать, а 16 байт:

Цитата:
In legacy mode, the stack pointer may be at any alignment when an interrupt or
exception causes a stack frame to be pushed. This causes the stack frame and
succeeding pushes done by an interrupt handler to be at arbitrary alignments. In
IA-32e mode, the RSP is aligned to a 16-byte boundary before pushing the stack
frame. The stack frame itself is aligned on a 16-byte boundary when the interrupt
handler is called. The processor can arbitrarily realign the new RSP on interrupts
because the previous (possibly unaligned) RSP is unconditionally saved on the newly
aligned stack. The previous RSP will be automatically restored by a subsequent IRET.


Сам я не экспериментировал (всё руки не доходят), но, насколько понял из мануала, если переключения стека не происходит, процессор автоматом выровняет стек на границу 16 байт (просто сбросит младшие биты RSP перед сохранением в стеке SS:RSP на момент прерывания), ну а если нужно переключение стека, он просто грузит новое значение из TSS, и поэтому требуется, чтоб оно было корректным -- на границе 16 байт. В Вашем случае нельзя сказать, корректно оно или нет, поскольку неясно, каков текущий RSP.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 19 фев 2010, 13:44 

Зарегистрирован: 16 фев 2010, 22:03
Сообщения: 101
Исправил код в соответствии с вашими замечаниями. Стек действительно был не выровнен на 16 байт. Однако это не помогло. Вот что пишет Bochs:
Код:
00074792787i[BIOS ] Booting from 0000:7c00
00075939076e[CPU0 ] interrupt(long mode): canonical address failure 001000000000
0000
00075939076e[CPU0 ] interrupt(long mode): canonical address failure 001000000000
0000
00075939076e[CPU0 ] interrupt(long mode): canonical address failure 001000000000
0000
00075939076i[CPU0 ] CPU is in long mode (active)
00075939076i[CPU0 ] CS.d_b = 16 bit
00075939076i[CPU0 ] SS.d_b = 16 bit
00075939076i[CPU0 ] EFER   = 0x00000501
00075939076i[CPU0 ] | RAX=ffffffffffe00000  RBX=0000000000001000
00075939076i[CPU0 ] | RCX=0000000000000001  RDX=ffffffffffff7000
00075939076i[CPU0 ] | RSP=ffffffffffff7000  RBP=ffffffffffff7000
00075939076i[CPU0 ] | RSI=0000000000009205  RDI=ffffffffffe01000
00075939076i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00075939076i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00075939076i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00075939076i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00075939076i[CPU0 ] | IOPL=3 ID vip vif ac vm RF NT of df IF tf sf ZF AF PF cf
00075939076i[CPU0 ] | SEG selector     base    limit G D
00075939076i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00075939076i[CPU0 ] |  CS:0023( 0004| 0|  3) 00000000 00000fff 1 0
00075939076i[CPU0 ] |  DS:0000( 0002| 0|  0) 00000000 00000fff 1 0
00075939076i[CPU0 ] |  SS:001b( 0003| 0|  3) 00000000 00000fff 1 0
00075939076i[CPU0 ] |  ES:0000( 0002| 0|  0) 00000000 00000fff 1 0
00075939076i[CPU0 ] |  FS:0000( 0002| 0|  0) 00000000 00000fff 1 0
00075939076i[CPU0 ] |  GS:0000( 0002| 0|  0) 00000000 00000fff 1 0
00075939076i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00075939076i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00075939076i[CPU0 ] | RIP=ffffffffffe00000 (ffffffffffe00000)
00075939076i[CPU0 ] | CR0=0xe0000011 CR2=0x0000000000000000
00075939076i[CPU0 ] | CR3=0x00001000 CR4=0x00000020
00075939076i[CPU0 ] 0xffffffffffe00000>> jmp .+0xfffffffffffffffe (0xffffffffffe
00000) : EBFE
00075939076e[CPU0 ] exception(): 3rd (12) exception with no resolution, shutdown
 status is 00h, resetting

Ошибка точно происходит при смене уровня привилегий во время прерывания.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 19 фев 2010, 13:54 

Зарегистрирован: 28 окт 2007, 18:33
Сообщения: 1418
А что это за канонический адрес, который ему не нравится? Откуда он вообще взялся-то?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 19 фев 2010, 14:11 

Зарегистрирован: 16 фев 2010, 22:03
Сообщения: 101
Не знаю. В моей программе он никак не фигурирует. Вот я и думаю - может что-то в TSS? хотя я вроде бы там всё заполняю правильно. Вот где в памяти присутствует значение 0x0010000000000000:
0xC8650
0xC8672
0x100004
0x103FA8
0x103FB3


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 19 фев 2010, 14:39 

Зарегистрирован: 16 фев 2010, 22:03
Сообщения: 101
Извините, за то что отвлёк ваше внимание. Дело было в очень глупой ошибке. Дело в том, что физический адрес для TSS я выделял статически и он был равен 0x100000. А потом я туда же записывал описатель свободного блока памяти (для менеджера памяти) и так совпало, что по смещению 0x100004 оказалось число 0x0010000000000000 (на самом деле там должно было быть 0x100000, но мы смотрели на число не "сначала"). А менеджер памяти я инициализировал после TSS и соответственно разрушал его.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 12 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 109


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB