Такс... малость помедитировал (что-то много работы сегодня на работе оказалось).
Во-первых, пара замечаний, хотя на работоспособность это не влияет:
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.