KIV Code (Text): KERNEL_CODE64_SELECTOR = 1 shl 3 Тут 1 shl 3 будет равно 8? Я всё равно не понял как оно это делает. Ведь shl это же сдвиг влево.
В данном контексте это не команда ассемблера, а команда компилятора всё равно что: mov eax, 1 * 8 очевидно, что получиться mov eax, 8 а тут mov eax, 1 shl 8
s3dworld Нужно внимательно читать справочники и вникать в то, что там написано И кстати, думать головой постоянно, поскольку в официальных руководствах тоже встречаются ошибки, противоречия и недосказанности. Ну и простой совет: не пытаться сразу охватить всё. Если хорошо разобрались с работой в реальном режиме (в частности, чётко понимаете, что представляют из себя тамошние сегменты и почему к одной и той же физической ячейке памяти можно из программы обращаться по разным адресам), тогда переходите к защищённому. Разберётесь с ним -- начинайте вникать в страничный механизм. И лишь после этого беритесь за 64-разрядный режим.
SII Хороший совет! Почему в R-MODE через разные линейные адреса можно попасть на одну и ту же ячейку памяти - я разобрался. СЕГМЕНТ - это значение умноженное на 16 (0x10); СМЕЩЕНИЕ - смещение. И получается что: уже умноженное значение сегмента на 16 (0x10) + смещение. Но я всё равно не понял что значит shl((
shl -- сдвиг влево. А Вы запутались из-за того, что не различаете операции, выполняемые транслятором во время трансляции программы, и операциями, выполняемыми непосредственно при выполнении программы. В примере, приведённом выше, было написано: Code (Text): KERNEL_CODE64_SELECTOR = 1 shl 3 Это абсолютно то же самое, что: Code (Text): KERNEL_CODE64_SELECTOR = 8 Лично я, кстати, записал бы именно вторым способом, но это уже вопрос стиля. Так вот, сама эта запись обрабатывается транслятором в то время, когда он транслирует программу. Он просто вычисляет значение выражения справа от знака равенства и присваивает результат имени, указанному слева. Но, ещё раз повторюсь, это происходит во время трансляции программы, а не при её выполнении. А вот когда записана ассемблерная команда: Code (Text): shl ax, 1 она не будет выполнена во время трансляции; вместо этого транслятор переведёт её в соответствующий машинный код. Она будет выполнена лишь во время выполнения программы и сделает то, что положено: сдвинет влево на 1 разряд содержимое регистра AX.
SII Спасибо! Теперь стало понятно. Будем считать что это макрос. А действительно ли, что в защищённом режиме (скорее всего и в длинном режиме) не будут доступны функции (прерывания) BIOS? А то я прочитал что в таких случаях нужно либо писать самому драйвера на устройства (ой, мама, помоги!), либо использовать виртуальный режим 8086 (опять к динозаврам). Так как же на самом деле можно и как делают на практике?
max7C4 Так оборудования специфические. Это ведь BIOS использует общий функционал (стандарт какой-нибудь). Скажем переключить режим работы видеоадаптера и вывести точку в указанную позицию...я даже не представляю как это делается (конечно догадываюсь что пересылкой данных в порта и чтение данных из портов, но в какие).
s3dworld Биос не использует каких-то строгих стандартов. Он заточен только под те железяки, где сам находится, не более и не менее. Драйвера делают тоже самое. Они используя системный универсальный интерфейс для своего устройства, будучи заточенными под взаимодействие только с ними (устройством и универсальным системным интерфейсом), осуществляют передачу информации из устройства в систему и наоборот. {ADD} Драйвера можно сравнить с переводчиками с языка системы на язык своего устройства и наоборот.
s3dworld А вот не надо считать, что это макрос. Вещи надо считать тем, что они есть, иначе неизбежно запутаетесь. Действительно. Поэтому загрузчики ОС без конца прыгают между реальным и защищённым или же используют V86. В общем, сплошные костыли.
Кстати, в длинном режиме отказались от V86. Нет. Эта конструкция аналогична: Code (Text): #define KERNEL_CODE64_SELECTOR 8 Или если вы пишите в Си a = 1 shl 3 копилятор сам вычислит 1 shl 3 и сделает уже команду a = 8, а не заставит программу каждый раз вычислять 1 shl 3.
Мне вот интересно, а в нестандартных компьютерах (экран 16:9 или же экран 16:10, да и вообще в ноутбуках) ведь размер видео-странички при включении компьютера не такой как у обычных компьютеров с 4:3? То есть если я напишу программу которая зальёт всю мою видео-страничку, то при запуске этой де программы на другом компьютере, она возможно зальёт не всю страничку?
Совместимость обеспечивается БИОСом и самим железом. А ёмкость видеостраницы зависит от видеорежима, а не от отношения сторон монитора.
s3dworld Столько сколько захочет биос. На моих материнках и ноутбуке, если включить графическую заставку bios, он может забыть переключить видюху в режим 80*25
Это уже ошибка в БИОСе -- правда, по нынешним временам безобидная (вряд ли кто-то там запускает ДОС, да и она сама вроде как устанавливает себе режим соответствующим вызовом). Но, поскольку ошибки возможны, лучше всегда включать нужный режим, а потом уже обращаться к видеопамяти.
Что-то я запутался. Пишу на FASM. Вот файл main.asm: Code (Text): use16 ; Используем 16-битный код org 0x7C00 ; Смещение ; -------------------------------------------------------------------------- ; Начало 16-битного кода ; -------------------------------------------------------------------------- code16: call InitScreen ; Инициализация экрана call ClearScreen ; Очищаем весь экран mov DL,4 mov DH,4 call SetCursorPos mov BL,00000100b call DrawText call LoopProcessor ; Подвешиваем процессор ; -------------------------------------------------------------------------- ; Подвешивание процессора LoopProcessor: jmp LoopProcessor ; Переходим на эту же инструкцию ret ; -------------------------------------------------------------------------- include "BIOS.asm" ; -------------------------------------------------------------------------- ; Начало 16-битных данных ; -------------------------------------------------------------------------- data16: text1 db "Hello my friend!",0x00 Никак не могу понять как реализовать передачу адреса где находится первый байт строки и вообще вывод этой строки через смещение. Вот тут я начал делать, но не смог (BIOS.asm): Code (Text): ; -------------------------------------------------------------------------- ; Инициализация экрана ; -------------------------------------------------------------------------- InitScreen: mov AH,0x00 ; Код функции mov AL,0x03 ; Код режима (80x25x16) int 0x10 ; Вызываем прерывание BIOS ret ; -------------------------------------------------------------------------- ; Очистка экрана ; -------------------------------------------------------------------------- ClearScreen: mov AH,0x09 ; Код функции mov AL,' ' ; Выводимый символ mov BH,0x00 ; Номер страницы mov BL,00010000b ; Атрибуты mov CX,2000 ; Количество повторений int 0x10 ; Вызываем прерывание BIOS ret ; -------------------------------------------------------------------------- ; Установка положения курсора ; DH - номер строки ; DL - номер столбца ; -------------------------------------------------------------------------- SetCursorPos: mov AH,0x02 ; Код функции mov BH,0x00 ; Номер страницы int 0x10 ; Вызываем прерывание BIOS ret ; -------------------------------------------------------------------------- ; Вывод текста ; BL - атрибуты текста ; -------------------------------------------------------------------------- DrawText: mov AH,0x09 ; Код функции mov BH,0x00 ; Номер страницы mov CX,1 ; Количество повторений DrawTextLoop: ;mov AL,[DS:0x0000+DI] cmp AL,0x00 jz DrawTextExit int 0x10 ; Вызываем прерывание BIOS inc DI jmp DrawTextLoop DrawTextExit: ret Подскажите, как это реализовать?
Я делаю это так: Code (Text): write_str: push ax si mov ah, 0x0E @@: lodsb test al, al jz @f int 0x10 jmp @b @@: pop si ax ret ... mov si, hello_msg call write_str ... hello_msg db "Hello world!",13,10,0 При этом не стоит забывать инициализировать DS и прочие сег. регистры, потому что при старте там вполне может быть не 0: Code (Text): org 0x7C00 jmp 0:@f @@: mov ax, cs mov ds, ax mov es, ax sti ; Прерывания изначально запрещены - их надо разрешить ... тут уже собственно код твоей программы ...
s3dworld Не совсем ясно, в чём у Вас проблема. Я, правда, не знаток синтаксиса ФАСМ (не пишу на нём, поскольку он мне не нравится), но вроде бы считывание памяти по заданному адресу (у Вас, судя по всему, он находится в DSI) в AL там будет выглядеть так: MOV AL, [DI] (сегмент данных подразумевается во всех обращениях к операндам, за несколькими исключениями: если один из компонентов адреса операнда находится в BP/EBP или ESP (но не к SP -- такого быть попросту не может), тогда идёт обращение к стеку; в строковых операциях операнд-источник находится в DSE)SI, а приёмник -- в ESE)DI; вроде ещё какое-то исключение было).