Я пишу собственное ядро и использовал этот код, чтобы переопределить глобальную таблицу дескрипторов, установленную загрузчиком. Это делается в 32-битном защищенном режиме.
flush_gdt:
lgdt [gdtr]
jmp 0x08:complete_flush
complete_flush:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
ret
Код работает нормально, но я не могу понять, почему следующая инструкция после lgdt выполняется правильно.
Насколько я понимаю, значения сегментных регистров (особенно CS) остаются неизменными. Поэтому ЦП будет использовать старый регистр и новую таблицу для разрешения адреса инструкции jmp 0x08:complete_flush
. Скорее всего, запись в моей таблице, на которую указывает значение старого CS, не является допустимым сегментом кода, и это приведет к сбою. Однако ничего подобного не происходит. Почему?
РЕДАКТИРОВАТЬ: спрашивая об этом, потому что я понимаю, что ЦП разрешает линейные адреса с использованием пары регистров CS: EIP. Теперь после lgdt
CS внезапно укажет на другую запись, так почему следующая выполняемая инструкция - это инструкция jmp
cs
сохранят предел, базу и так далее, пока вы не перезагрузитеcs
(с большим скачком). - person ecm   schedule 29.09.2020wrmsr
илиwrfsbase
). Я предпочитаю говорить о внутренних регистрах. Но да, ключевой момент в том, что они обновляются только при изменении регистра сегмента. то есть вы можете установить их только косвенно, но это настоящие регистры, а не кеш или что-то еще. То, из чего они были загружены, может измениться, не затрагивая их. - person Peter Cordes   schedule 29.09.2020