Наткнулся на неопределенность. В процессе работы (Protect Mode, никаких серверов, ничего лишнего, все свое собственное) есть необходимость редактировать содержимое GDT, например, при запуске новой задачи. Как именно корректно это осуществить? У меня есть следущие мысли: При удалении дескриптора из таблицы, его номер занести в "список свободных дескрипторов", удаляемый при этом затереть нулями (сделать его пустым). При выделении нового дескриптора: если "список свободных дескрипторов" пустой, то добавить дескриптор в конец таблицы, заполнить его нужными значениями, увеличить размер GDT, перегрузить GDTR, иначе - взять номер дескриптора из списка и работать с ним. Я так понимаю, что на время редактирования GDT должны быть запрещены прерывания, т.е. типа критическая секция. И как лучше оформить данную процедуру? Как обычную, с запрещением/разрешением прерываний установкой флага IF или оформить как обработчик аппаратного прерывания и вызывать его как программное, по идее прерывания буду запрещаться/разрешаться автоматически??.... Кто как думает? бывали у кого нить подобные реализации?
эмм. скажи, зачем тебе надо менять gdt? только те, которые используют дескрипторы, которые ты меняешь (то есть возможно все). если через interrupt gate, то да, есле через trap, то нет ("5.12.1.2 Flag Usage..." vol. 3a 5-19)
Дело в том, что в будущем колличество запускаемый задач будет меняться и не хотелось бы редактировать много текста. Хотелось бы делать это в динамике, по моему, меньше головной боли будет. т.е. я выделяю в IDT какой нибудь дескриптор, описываю его как шлюз прерывания, а вызываю как int N и на время работы внутри процедуры прерывания будут запрещены, так получается? (просто уточнить хочу) а можно ссылочку?
Barbos лучше использовать LDT для каждой задачи тогда и искать, собственно, ничего не придется нет, но на SMP-системе нужно использовать атомарные операции для модификации дескрипторов (или их частей)
да, я придерживаюсь того же мнения, но, как мне кажется, дескрипторы, описывающие LDT должны находиться в GDT
но ведь управление будет передано на процеруду через шлюз прерывания, а не через шлюз ловушки %) что то я запутался %)
при переключении задач модифицируешь LDT-дескриптор в GDT и выполняешь LLDT если использовать шлюз прерывания, после сохранения EFLAGS в стеке IF сбрасывается IRETD восстанавливает сохраненное значение EFLAGS
Надо иметь двоичный мьютекс на GDT. Если система будет многопроцессорная, то мэджик с IF не поможет. Работать с GDT можно только если мьютекс свободен. Дескриптор сегмента TSS в LDT запихнуть нельзя. Можно только запихнуть дескрипторы сегмента кода и данных. Более-менее нормальное решение - это дать заявку планировщику на создание потока. Либо на время создания нити блокировать GDT-мьютекс.
с мьютексами согласен, но у меня многопроцессорных систем не будет. А вот по поводу запрета прерываний при передаче управления через шлюз прерывания - "Assembler для DOS, Windows и UNIX" Зубков С. В. второе издание, стр 499: "Единственное различие между шлюзом прерывания и ловушки состоит в том, что при передачи управления через шлюз прерывания автоматически запрещаются дальнейшие прерывания, пока обработчик не выполнит IRETD". Ну т.е. так оно и получается, после помещения EFLAGS в стек при вызове через шлюз прерывания, IF будет сброшен и процессор не будет реагировать на запросы от 8529. Вобщем, оформляется некий обработчик аппаратного прерывания, цепляется на свободный вектор и, при помощи команды int, управление передается обработчику через шлюз прерывания и автоматически сбрасывается IF. Вот и будет некое атомарное действие. Единственное, щас надо будет это прогнать на практике.
Всё же мьютексы более симпатичны, потому что не надо отключать прерывания. И реализуются просто (при помощи команды xchg).
возможно, но не все сразу я щас в плане работы с системными регистрами только тропинку протаптываю. До этого работал всегда через DPMI, а щас решил, что хватит сил обходится без него. Но все равно спрошу. Как реализуется работа с помощью мьютексов? хотя бы схематически? Их я тоже никогда не использовал, их механизма пока не знаю.
прежде чем модифицировать GDT, захватывается блокировка после модификации освобождается работу с блокировками можно реализовать так Код (Text): spin_lock: ; eax contains address of spin-lock variable push edx xor edx, edx inc edx __spin_lock: cmp dword [eax], 0 jz @F pause jmp __spin_lock @@: xchg edx, dword [eax] test edx, edx jnz __spin_lock pop edx ret Код (Text): spin_unlock: push edx xor edx, edx xchg edx, dword [eax] pop edx ret
Нормальная схема, хотя лично я бы выполнил оптимизацию так, чтобы не перегружать GDTR при каждом расширении GDT. "Затирать" весь дескриптор нулями нет необходимости, достаточно обнулить байт прав доступа. Запрещать прерывания нет необходимости, если ты сможешь организовать полное добавление/удаление группы дескрипторов для задачи, включая в том числе и работу со "списком свободных дескрипторов", так чтобы эта операция в многозадачном режиме работы не пересекалась с такой же операцией, выполняемой в другом потоке команд. Оформлять это процедуру как отдельный обработчик программного прерывания, вызываемый через шлюз прерывания, естественно, не нужно. Это внутрисистемная процедура, поэтому чем меньше "видимых концов" она имеет, тем лучше.
а какими проблемами и в каких ситуациях может обернуться перезагрузка GDTR? Если не использовать в работе расширение GDT, то тогда она изначально должна быть достаточного размера под максимально используемое кол-во дескрипторов? других идей мне в голову не лезет
Проблем не будет. Я говорил просто об оптимизации, хотя создание/уничтожение задачи является не на столько частой операцией, как, скажем, переключение задач. Не обязательно задавать лимит GDT сразу на максимальное число дескрипторов (но если не экономить память, это конечно наиболее предпочтительный вариант). Можно, например, менять лимит GDT постранично вместе с распределением/высвобождением очередной страницы памяти под GDT. Правда, в этом случае время на выполнение операции будет затрачиваться крайне неравномерно, т.к. помимо времени на распределение самой страницы нужно тратить время на обнуление всех неиспользуемых дескрипторов внутри нее. Хотя честно говоря я сам использую далеко не оптимальный способ работы с GDT, перезаписывая GDTR при каждом добавлении/удалении группы дескрипторов, правда, это происходит только при загрузке/выгрузке драйверов, а для представления всех прикладных задач используется одна и та же группа десрипторов с фиксированным местоположением.