OSDev http://osdev.su/ |
|
Проблема с прерываниями в длинном режиме http://osdev.su/viewtopic.php?f=6&t=309 |
Страница 1 из 2 |
Автор: | KIV [ 17 фев 2010, 22:30 ] |
Заголовок сообщения: | Проблема с прерываниями в длинном режиме |
Пишу 64-битную операционку. В режиме супервизора загружаю в IDTR адрес таблицы прерываний, устанавливаю обработчики, разрешаю прерывания. Всё работает нормально. Стоит мне перейти на код в режиме пользователя всё рушится. Если запретить прерывания, то всё работает нормально. Дело не в обработчике прерывания - он даже не успевает вызваться. В чём может быть проблема? |
Автор: | SII [ 18 фев 2010, 08:12 ] |
Заголовок сообщения: | Re: Проблема с прерываниями в длинном режиме |
Со стеками порядок? Они ж разные должны быть. |
Автор: | KIV [ 18 фев 2010, 15:17 ] |
Заголовок сообщения: | Re: Проблема с прерываниями в длинном режиме |
Я 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. |
Автор: | SII [ 19 фев 2010, 00:05 ] |
Заголовок сообщения: | Re: Проблема с прерываниями в длинном режиме |
А нельзя полный код ТСС и дескрипторов прерываний? Помедитировал бы над ними завтра (точней, уже сегодня) на работе... |
Автор: | KIV [ 19 фев 2010, 08:05 ] |
Заголовок сообщения: | Re: Проблема с прерываниями в длинном режиме |
Вот описание 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 |
Автор: | SII [ 19 фев 2010, 13:19 ] |
Заголовок сообщения: | Re: Проблема с прерываниями в длинном режиме |
Такс... малость помедитировал (что-то много работы сегодня на работе оказалось). Во-первых, пара замечаний, хотя на работоспособность это не влияет: 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. |
Автор: | KIV [ 19 фев 2010, 13:44 ] |
Заголовок сообщения: | Re: Проблема с прерываниями в длинном режиме |
Исправил код в соответствии с вашими замечаниями. Стек действительно был не выровнен на 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 Ошибка точно происходит при смене уровня привилегий во время прерывания. |
Автор: | SII [ 19 фев 2010, 13:54 ] |
Заголовок сообщения: | Re: Проблема с прерываниями в длинном режиме |
А что это за канонический адрес, который ему не нравится? Откуда он вообще взялся-то? |
Автор: | KIV [ 19 фев 2010, 14:11 ] |
Заголовок сообщения: | Re: Проблема с прерываниями в длинном режиме |
Не знаю. В моей программе он никак не фигурирует. Вот я и думаю - может что-то в TSS? хотя я вроде бы там всё заполняю правильно. Вот где в памяти присутствует значение 0x0010000000000000: 0xC8650 0xC8672 0x100004 0x103FA8 0x103FB3 |
Автор: | KIV [ 19 фев 2010, 14:39 ] |
Заголовок сообщения: | Re: Проблема с прерываниями в длинном режиме |
Извините, за то что отвлёк ваше внимание. Дело было в очень глупой ошибке. Дело в том, что физический адрес для TSS я выделял статически и он был равен 0x100000. А потом я туда же записывал описатель свободного блока памяти (для менеджера памяти) и так совпало, что по смещению 0x100004 оказалось число 0x0010000000000000 (на самом деле там должно было быть 0x100000, но мы смотрели на число не "сначала"). А менеджер памяти я инициализировал после TSS и соответственно разрушал его. |
Страница 1 из 2 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |