Почему работает загрузка GDT следующим образом

Я пишу собственное ядро ​​и использовал этот код, чтобы переопределить глобальную таблицу дескрипторов, установленную загрузчиком. Это делается в 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


person jason    schedule 29.09.2020    source источник
comment
Сегментные регистры имеют теневые поля для базы, ограничения, прав доступа, привилегий и т. Д. Все или некоторые из них записываются, когда вы перезагружаете регистр. В защищенном режиме перезагрузка сегментного регистра разыменовывает селектор в LDT или GDT, затем считывает дескриптор, а затем обновляет теневые поля из содержимого дескриптора. В реальном и виртуальном режимах 86 база теневого сегмента обновляется на основе значения загружаемого сегмента. Если вы переключитесь из режима Real 86 в защищенный режим, поля тени cs сохранят предел, базу и так далее, пока вы не перезагрузите cs (с большим скачком).   -  person ecm    schedule 29.09.2020
comment
Значение / значение CS не меняется при изменении GDT. База, предел, тип и т. Д. Хранятся в процессоре. Они меняются только тогда, когда CS перезагружается дальней инструкцией jmp.   -  person prl    schedule 29.09.2020
comment
@ecm: Я бы не сказал, что они затенены, это означает, что они затенены чем-то. Но база / предел сегмента, текущий режим и т. Д. Просто недоступны напрямую в любом режиме (за исключением базы данных FS / GS через wrmsr или wrfsbase ). Я предпочитаю говорить о внутренних регистрах. Но да, ключевой момент в том, что они обновляются только при изменении регистра сегмента. то есть вы можете установить их только косвенно, но это настоящие регистры, а не кеш или что-то еще. То, из чего они были загружены, может измениться, не затрагивая их.   -  person Peter Cordes    schedule 29.09.2020
comment
@Peter Cordes: Технически мы могли бы называть их кешами, просто с такой особой семантикой перезагрузки, что они кэшируют дескрипторы с момента последней перезагрузки сегрега. Как бы то ни было, это волосы ссадины.   -  person ecm    schedule 29.09.2020
comment
@ecm: мне не нравится термин кеш для чего-то, что нельзя исключить и перезагрузить / пересчитать из других данных в любое время. Это приведет к гораздо меньшей путанице, если мы зарезервируем термин для реальных кешей. (например, у людей есть всевозможные неправильные представления о (отсутствии) согласованности кэша ЦП из-за неряшливых описаний компиляторов C ++, кэширующих неатомарные значения в регистрах.) Полезный выбор терминологии - огромная часть ясного объяснения сложных вещей. В данном случае меня устраивает такая терминология, как скрытая часть архитектурного состояния, внутренние регистры или что-то подобное.   -  person Peter Cordes    schedule 29.09.2020
comment
@ecm Спасибо за ваш комментарий. Теперь это имеет большой смысл. У меня было заблуждение, что в регистрах хранится только селектор сегмента. Если база, лимит, права доступа и т. Д. Сохранены, это совсем другая история. Это кажется разумным, поскольку ЦП не будет обращаться к GDT каждый раз, когда он захочет получить данные о сегменте кода. Большое спасибо.   -  person jason    schedule 29.09.2020
comment
@ecm Подумав, я все еще не понял. Сегментные регистры 16-битные, как они могут содержать базу, лимит, права доступа и привилегии? Также согласно ответу с наибольшим количеством голосов здесь stackoverflow.com/questions/ 9113310 / segment-selector-in-ia-32 Я понимаю, что в регистрах хранятся только тип таблицы, индекс в таблице и предварительные значения. Вы можете объяснить, как это работает?   -  person jason    schedule 29.09.2020
comment
Только видимая часть является 16-битной, остальные поля хранятся в скрытой части соответствующего размера.   -  person Jester    schedule 29.09.2020
comment
@ Шестер Ааа, понятно. Спасибо. Не могли бы вы поделиться источником для получения такой информации? Я потратил некоторое время на поиски этого и не смог найти ничего надежного.   -  person jason    schedule 29.09.2020
comment
Руководство разработчика программного обеспечения для архитектур Intel® 64 и IA-32 Том 3: Руководство по системному программированию, раздел 3.4.3 Сегментные регистры.   -  person Jester    schedule 29.09.2020
comment
@Jester Я боялся, что это так :). Что ж, похоже, мне не сойдет с рук это прочтение. Спасибо.   -  person jason    schedule 29.09.2020