Форум программистов, компьютерный форум, киберфорум
ОС на Assembler
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
3 / 3 / 0
Регистрация: 15.07.2021
Сообщений: 15

Прерывания в Long Mode

01.03.2025, 21:06. Показов 1929. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Вот уже недельку так с x86_64 пытаюсь разобраться, параллельно AMD'шные доки читая, но всё никак не могу с памятью работать научиться.

Вроде пишут, что для IDT(Interrupt Descriptor Table) дескриптора нужен селектор сегмента кода, в котором лежит обработчик прерывания, но при этом также в той же инструкции АМДишной прописано, что базовые адреса и размеры сегментов игнорируются.
Да и если для IDT и не игнорируется базовый адрес, то какой писать в GDT дескриптор кода? Текущий адрес, куда у меня код загружается?

Если что, у меня загрузка осуществляется через UEFI загрузчик, который ядро определяет не по фиксированному адресу, а "хитровыделенному", который может отличаться от системы к системе. Также UEFI сразу в Long Mode проц суёт, так что нужно выполнять хоть что-то из тех действий, что нужны для перехода в Long Mode, или можно просто новые таблички в GDTR и IDTR пихать и всё будет работать сразу, без изменения Control-регистров?

Короче я сам себя похоже запутал) Кто знает - помогите разобраться, пожалуйста
Хотелось бы с примером(можно на любом ассемблере, но если будет на FASM, то вообще отлично)
Заранее спасибо
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
01.03.2025, 21:06
Ответы с готовыми решениями:

Работа в Long Mode
Посоветуйте кто-нибудь статейки/документации по "Длительному режиму", я бы хотел с устройством памяти подробно ознакомиться, как там IDT,...

IDT Ассемблер Long mode
Всем привет, заинтересовался я как-то разработкой ОС(да-да-да, я уже всё решил и нет, меня не контузило), решил, значит, под 64-бит писать,...

Переход в long mode из защищённого режима
Как перейти в long mode из защищённого режима?

4
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6213 / 2447 / 403
Регистрация: 29.07.2014
Сообщений: 3,178
Записей в блоге: 4
05.03.2025, 19:17
Лучший ответ Сообщение было отмечено Mikl___ как решение

Решение

Цитата Сообщение от Adm1n1strat0r Посмотреть сообщение
Кто знает - помогите разобраться, пожалуйста
Сложно там всё, и в двух словах не объяснишь.
Лучше взять отладчик WinDbg и посмотреть, как это дело реализует ядро Windows Ntoskrnl.exe.
Читать доки одно, а наглядная картина это совсем другое.

Из особенностей - таблица IDT может находиться хоть в секции-данных, т.к. в ней хранятся просто указатели на обработчики прерываний. А вот непосредственно процедуры обработки уже нужно положить в исполняемую секцию-кода.

Все системные таблицы должны быть выровнены в памяти границу 4096-байт (одна вирт.страница), а IDT должна быть заполнена полностью, т.е. все 256 векторов от нуля до FFh. Если прерывание не имеет обработчика, вектор должен указывать на процедуру-заглушку (общая для всех неиспользуемых int'ов), которая тупо возвращает iretq.

В режиме Long дескрипторы в GDT имеют чуть иной формат. В частности, если в атрибутах взведён бит(L), то база и лимит игнорируется, а вот тип и оставшиеся атрибуты по прежнему действительны, например привилегия DPL (селектор, кольцо защиты), а так-же тип сегмента "код или данные". Первые 2 дескриптора в GDT должны быть нулевыми, а дальше Code/Data Ring(0), и Code/Data Ring(3). Для начала остальные можно не указывать, а как добавишь в ядро планировщик потоков, может потребоваться и дескриптор сегмента TSS.

Адреса таблиц GDT/IDT должны быть прописаны в регистрах gdtr/idtr соответственно, иначе проц их не найдёт. IDT не имеет дескриптора в GDT - она может располагаться где угодно, лишь-бы указатель на неё был прописан в регистре IDTR (в таблице GDT лежит дескриптор только на локальную таблицу LDT).

Вот что думает отладчик WinDbg на этот счёт..
Каждая запись Entry в таблицах размером 8-байт (дескрипторы и векторы):

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
0: kd> r @gdtr, @gdtl; r @idtr, @idtl  ;//<----- запрашиваем адрес и размеры таблиц
 
   gdtr=fffff80004056000  gdtl=007f    ;// 0080h =  128/8 = всего 16 дескрипторов в GDT
   idtr=fffff80004054000  idtl=0fff    ;// 1000h = 4096/8 = резерв для 512 векторов, хотя реальных 256
 
---------------------------
Базу таблиц можно получить и из структуры PCR процессора (Processor Control Region):
---------------------------
 
0: kd> !pcr
   KPCR for Processor 0 at fffff80002c49000:  ;//<----- Адрес
 
0: kd> dt _KPCR fffff80002c49000  ;//<----------------- Запрашиваем структуру
ntdll!_KPCR
   +0x000 NtTib        : _NT_TIB
   +0x000 GdtBase      : 0xfffff800`04056000  _KGDTENTRY64
   +0x008 TssBase      : 0xfffff800`04055000  _KTSS64
   +0x010 UserRsp      : 0x23d8b8
   +0x018 Self         : 0xfffff800`02c49000  _KPCR
   +0x020 CurrentPrcb  : 0xfffff800`02c49180  _KPRCB
   +0x028 LockArray    : 0xfffff800`02c497f0  _KSPIN_LOCK_QUEUE
   +0x030 Used_Self    : 0x000007ff`fffde000  Void
   +0x038 IdtBase      : 0xfffff800`04054000  _KIDTENTRY64
   +0x040 Unused       : 0
   +0x050 Irql         : 0
....................
0: kd>
Как видим, базы таблиц GDT/IDT и сегмента TSS выровнены на 1000h, т.е. мл.слово 4000/5000/6000h.
Расширение отладчика !idt дампит содержимое всей IDT, а команда dg отображает в удобном виде таблицу GDT:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
0: kd> dg 0 80    ;// в предпоследнем столбце указан тип сегмента, Long или нет
                                                        P Si Gr Pr Lo
Sel         Base               Limit           Type     l ze an es ng  Flags
----  -----------------  -----------------  ----------  - -- -- -- --  --------
0000  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
0008  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
0010  00000000`00000000  00000000`00000000  Code RE Ac  0 Nb By P  Lo  0000029b
0018  00000000`00000000  00000000`ffffffff  Data RW Ac  0 Bg Pg P  Nl  00000c93
0020  00000000`00000000  00000000`ffffffff  Code RE Ac  3 Bg Pg P  Nl  00000cfb
0028  00000000`00000000  00000000`ffffffff  Data RW Ac  3 Bg Pg P  Nl  00000cf3
0030  00000000`00000000  00000000`00000000  Code RE Ac  3 Nb By P  Lo  000002fb
0038  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
0040  00000000`04055000  00000000`00000067  TSS32 Busy  0 Nb By P  Nl  0000008b
0048  00000000`0000ffff  00000000`0000f800  <Reserved>  0 Nb By Np Nl  00000000
0050  ffffffff`fffda000  00000000`00003c00  Data RW Ac  3 Bg By P  Nl  000004f3
0058  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
0060  00000000`00000000  00000000`ffffffff  Code RE     0 Bg Pg P  Nl  00000c9a
0068  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
0070  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
0078  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
0080  Unable to get descriptor
 
----------------------------------------
 
0: kd> !idt
Dumping IDT:
 
00:     fffff80002b01900 nt!KiDivideErrorFault
01:     fffff80002b01c00 nt!KiDebugTrapOrFault  Stack = 0xFFFFF8000406D000
 
02:     fffff80002b02080 nt!KiNmiInterrupt      Stack = 0xFFFFF80004069000
 
03:     fffff80002b02480 nt!KiBreakpointTrap
04:     fffff80002b02780 nt!KiOverflowTrap
05:     fffff80002b02a80 nt!KiBoundFault
06:     fffff80002b02d80 nt!KiInvalidOpcodeFault
07:     fffff80002b03380 nt!KiNpxNotAvailableFault
08:     fffff80002b03640 nt!KiDoubleFaultAbort  Stack = 0xFFFFF80004067000
 
09:     fffff80002b03900 nt!KiNpxSegmentOverrunAbort
0a:     fffff80002b03bc0 nt!KiInvalidTssFault
0b:     fffff80002b03e80 nt!KiSegmentNotPresentFault
0c:     fffff80002b041c0 nt!KiStackFault
0d:     fffff80002b04500 nt!KiGeneralProtectionFault
0e:     fffff80002b04800 nt!KiPageFault
10:     fffff80002b04f40 nt!KiFloatingErrorFault
11:     fffff80002b052c0 nt!KiAlignmentFault
12:     fffff80002b055c0 nt!KiMcheckAbort       Stack = 0xFFFFF8000406B000
 
13:     fffff80002b059c0 nt!KiXmmException
1f:     fffff80002afc540 nt!KiApcInterrupt
2c:     fffff80002b05d40 nt!KiRaiseAssertion
2d:     fffff80002b06040 nt!KiDebugServiceTrap
2f:     fffff80002afcbc0 nt!KiDpcInterrupt
e1:     fffff80002afd180 nt!KiIpiInterrupt
 
0: kd>
Теперь имеем указатели на обработчики прерываний,
и можем cдизассмить любой из них, например первый INT-00h "KiDivideErrorFault" (фрагмент):

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
0: kd> u fffff80002b01900
 
nt!KiDivideErrorFault:
fffff800`02b01900  4883ec08          sub    rsp,8
fffff800`02b01904  55                push   rbp
fffff800`02b01905  4881ec58010000    sub    rsp,158h
fffff800`02b0190c  488dac2480000000  lea    rbp,[rsp+80h]
fffff800`02b01914  c645ab01          mov    byte ptr [rbp-55h],1
fffff800`02b01918  488945b0          mov    qword ptr [rbp-50h],rax
fffff800`02b0191c  48894db8          mov    qword ptr [rbp-48h],rcx
fffff800`02b01920  488955c0          mov    qword ptr [rbp-40h],rdx
.............
0: kd>
База IDT будет указывать как-раз на вектор(0),
так-что можно просмотреть и на его структуру "KIDTENTRY64":

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0: kd> dt 0xfffff800`04054000 _KIDTENTRY64 -v
 
nt!_KIDTENTRY64
union _KIDTENTRY64, 11 elements, 0x10 bytes
   +0x000 OffsetLow        : 0x1900
   +0x002 Selector         : 0x10
   +0x004 IstIndex         : Bitfield  0y000
   +0x004 Reserved0        : Bitfield  0y00000 (0)
   +0x004 Type             : Bitfield  0y01110 (0xe)
   +0x004 Dpl              : Bitfield  0y00
   +0x004 Present          : Bitfield  0y1
   +0x006 OffsetMiddle     : 0x2b0
   +0x008 OffsetHigh       : 0xfffff800
   +0x00c Reserved1        : 0
   +0x000 Alignment        : 0x2b08e00`00101900
0: kd>
Адрес обработчика хранится в трёх полях записи Entry: "High + Middle + Low",
тогда получаем всё тот-же указатель: 0xfffff800'02b01900.
Так-же из записи видно, что Selector(10h) = Long CodeSeg, и привилегия DPL(0) = Ring(0).
5
3 / 3 / 0
Регистрация: 15.07.2021
Сообщений: 15
08.03.2025, 19:32  [ТС]
R71MT, да мне то всего нужно было пустой обработчик создать и к таймеру APIC привязать, чтобы потом на его основе менеджмент задач сделать.
Про GDT и IDT осведомлён, просто когда я код писал под BIOS и делал переход в защищённый режим у меня всё ок работало, а когда перешёл на UEFI, то пришлось в Long Mode окунаться и... короче, только через неделю, когда понял как логирование в QEMU включить, смог найти в чём проблема - я неправильно адрес для GDT вычислял(для IDT, соответственно, тоже).
В итоге проц исключение давал и эмулятор в перезарузку уходил, а я думал, что дело в самой IDT, потому и тему создал

Всё равно спасибо, думаю этот ответ ещё кому-то пригодиться)

Добавлено через 6 минут
Также если кому-то нужно будет: в batch-скрипте, который запускает эмулятор QEMU, я использовал аргумент:
Code
1
-d cpu_reset,int,in_asm,guest_errors -D qemu_log.txt
тут сразу и дизассемблированный код выполняемых инструкций отображается, и в случае исключений или вызова прерываний выводиться состояние регистров(в том числе GDTR, IDTR и CR-регистров).

Можно конечно и в консольку выводить, убрав -D qemu_log.txt - но так(во всяком случае, у меня) эмулятор работает медленнее.
2
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6213 / 2447 / 403
Регистрация: 29.07.2014
Сообщений: 3,178
Записей в блоге: 4
09.03.2025, 07:44
Лучший ответ Сообщение было отмечено Adm1n1strat0r как решение

Решение

Цитата Сообщение от Adm1n1strat0r Посмотреть сообщение
пустой обработчик создать и к таймеру APIC привязать, чтобы потом на его основе менеджмент задач сделать.
Планировщик/шедулер создаст много проблем, а потому нужно быть к ним готовым.
Если в GDT определены кольца защиты CPL/DPL (т.е. есть дескрипторы для Ring=0/3), то по таймеру с квантами на задачу, потребуется переходы Ring(0/3) и обратно. В режиме х32 это sysenter/sysexit, а в х64 syscall/sysret. При этом задействуются и регистры MSR для смены CS:RIP, а так-же MSR.KERNEL_GS_BASE для доступа к стеку ядра. Соответственно выходить из обработчика таймера LAPIC нужно будет уже парой инструкций swapgs + iretq (см.описание swapgs). Для обработчиков прерываний от аппаратных устройств типа диск, клава и прочие, swapgs уже не нужен.



Сейчас, чтобы не получить в обработчике шедулер-таймера крэш, вам нужно через rdmsr прочитать значения указанных на скрине выше MSR, т.к. непонятно, что именно напихал в них EFI при переходе в Long. В частности узнать номер вектора прерывания от таймера LAPIC (кстати в большинстве случаях он замаскирован), для чего от базы из MSR.1Bh нужно сместиться на 0x320 к регистру локальной таблицы LVT. Если в этом регистре установлен бит(16), значит указанный в битах(0:7) вектор не валидный. Сам вектор является номером в IDT, и активировав сбросом бита(16) можно его переназначить. Только после этого можно будет плясать дальше..

2
4 / 3 / 2
Регистрация: 12.02.2025
Сообщений: 11
17.04.2025, 13:41
Цитата Сообщение от R71MT Посмотреть сообщение
swapgs уже не нужен.
swapgs всегда нужен если ты получаешь прерывание из юзерспейса или если ты возвращаешься в юзерспейс, но достаточно при прерывании просто проверить cs из стека и свапнуть gs

Добавлено через 3 минуты
Цитата Сообщение от R71MT Посмотреть сообщение
MSR.1Bh нужно сместиться на 0x320 к регистру локальной таблицы LVT. Если в этом регистре установлен бит(16), значит указанный в битах(0:7) вектор не валидный. Сам вектор является номером в IDT, и активировав сбросом бита(16) можно его переназначить. Только после этого можно будет плясать дальше..
таймер также нужно откалибровать, самый простой метод это использовать hpet таймер (ну его реализация самая простая)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
17.04.2025, 13:41
Помогаю со студенческими работами здесь

Вход в v8086 mode (real mode) и обратно из protected mode
Я столкнулся с проблемой, я не знаю как реализовать v8086 mode (я пробовал виртуалка кидала меня в ошибку) для перехода в графический режим...

Вывод на экран числа long long double средствами printf
Необходима помощь. Как все же вывести через printf long long double (tbyte) конструкция виснет. времени особо нет разбираться ...

Вывести содержимое корневого каталога логического диска А, используя Handle-ориентирование и 13 прерывание
люди, вот у меня задание: вывести содержимое корневого каталога логического диска А, используя Heandle ориентирование и 13 прерывание: ...

Прерывание 20h
Здравствуйте, господа! Я случайно наткнулся на этот форум, и мне здесь понравилось, особенно по сравнению с остальными) Собственно, у...

Организовать аппаратное прерывание DOS
Вопрос заключается в следующем: как организовать аппаратное прерывание? Конкретно нужно вот что: на любом этапе работы программы при...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru