Это такой вопрос, где всегда однозначного, идеального, решения добиться трудно, потому что аппаратура в некоторых редких случаях ведет себя достаточно странно (см. статью "A20 - a pain from the past"). Про необходимость "вычищать" порт 60h из-за возможных посылок хосту от контроллера/клавиатуры много читал, видел это в различных исходниках и даже когда-то использовал сам, но со временем пришел к выводу, что в этом нет необходимости. Необходимость запрета прерываний связана с тем, что приходится посылать двухбайтовую команду, между посылками которой возможна активация клавиатурного обработчика, который, возможно, станет посылать другие команды, т.е. есть вероятность "разорвать" одну команду другими. Открывать шлюз нужно обязательно, потому что как раз-таки в подавляющем большинстве случаев по умолчанию он закрыт, причем и на самых современных компьютерах, только не следует забывать при тестировании, что шлюз перекрывает не вообще доступ к памяти за первым мегом, а лишь к четным мегам, т.е. 2-му, 4-му и т.д. Короче, я когда-то тоже долго "страдал" неидеальностью моего кода, но потом все-таки пришел к коду, который к сегодняшнему дню протестирован на огромном количестве самых разнообразных компьютеров и проблем не вызывал, причем не только при явном тестировании (здесь могут быть неявные проблемы из-за кэширования памяти), но и после тестирования при последующей интенсивной работе со всем объемом памяти. Кстати, если кто-то обнаружит неработоспособность представленного ниже кода на каком-либо компьютере при каких-либо неестественных обстоятельствах (ну к примеру вы лежали на клаве во время отработки данного кода), буду весьма благодарен, если вы мне об этом сообщите. Вот код:
открываем шлюз адресной линии A20: 1) устанавливаем флаг GateA20 (бит 1) порта вывода контроллера клавиатуры 2) устанавливаем флаг GateA20 (бит 1) порта A управления системой
cli call Startup.WaitForEmpty jnz @f mov al, 0D1h ; команда контроллера для записи в порт вывода out 64h, al call Startup.WaitForEmpty jnz @f mov al, 0DFh ; Reset=1, GateA20=1 out 60h, al call Startup.WaitForEmpty @@: sti
call Startup.TestGateA20 jnz @f
in al, 92h test al, 02h ; если флаг уже установлен, но шлюз не сработал, jnz Startup.Error_4 ; будем считать это ошибкой and al, 0FEh ; на всякий случай очищаем флаг Reset or al, 02h out 92h, al
call Startup.TestGateA20 jnz @f
.Error_4: call Startup.SystemError db "4"
@@:
Используемые подпрограммы -------------------------
.WaitForEmpty: xor cx, cx @@: in al, 64h and al, 02h loopnz @b ret
.TestGateA20: mov ax, [1000h] dec ax mov [es:1010h], ax ; es=0FFFFh... вроде бы :) sub ax, [1000h] ret
|