inb и outb функциональные ошибки
Этот код для inb
неверен:
static inline unsigned char inb (unsigned short int port)
{
unsigned char value;
asm ("inb %0, %%al":"=rm"(value):"a"(port));
return value;
}
Несколько проблем с ним:
- Кажется, у вас параметры
inb
поменялись местами. См. справочник по набору инструкций для inb
. Помните, что в синтаксисе AT&T (который вы используете в своем коде на ассемблере GNU) операнды меняются местами. Справочник по набору инструкций показывает их в формате Intel.
- Номер порта либо указывается как непосредственное 8-битное значение, либо передается в регистре DX. Правильным ограничением для указания регистра
DX
или непосредственного 8-битного значения для inb/outb является Nd
. См. мой ответ Stackoverflow здесь для объяснения ограничения Nd
.
- Адресат, в который возвращается прочитанное значение, — это AL/AX/EAX, поэтому ограничение
=rm
на выходе, указывающее, что доступный регистр или адрес памяти неверны. В вашем случае должно быть =a
.
Ваш код должен быть примерно таким:
static inline unsigned char inb (unsigned short int port)
{
unsigned char value;
asm volatile ("inb %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
Ваш шаблон ассемблера для outb
неверен:
static inline void outb(unsigned char value, unsigned short int port)
{
asm volatile ("outb %%al, $0"::"rm"(value), "a"(port));
}
Пара проблем с ним:
- Номер порта либо указывается как непосредственное 8-битное значение, либо передается в регистре DX. Правильным ограничением для указания регистра
DX
или непосредственного 8-битного значения для inb/outb является Nd
. См. мой ответ Stackoverflow здесь для объяснения ограничения Nd
.
- Значение для вывода на порт должно быть указано в AL/AX/EAX, поэтому ограничение
rm
на значение, говорящее о доступном регистре или адресе памяти, неверно. В вашем случае должно быть a
. См. справочник по набору инструкций для outb
Код, вероятно, должен выглядеть примерно так:
static inline void outb(unsigned char value, unsigned short int port)
{
asm volatile ("outb %0, %1"::"a"(value), "Nd"(port));
}
Включение и отключение курсора
Мне пришлось просмотреть регистры VGA о курсоре и найти этот документ в начальном регистре курсора, в котором говорится:
Cursor Start Register (Index 0Ah)
-------------------------------------------------
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
-------------------------------------------------
| | | CD | Cursor Scan Line Start |
-------------------------------------------------
CD -- курсор отключен
Это поле управляет отображением курсора в текстовом режиме. Значения:
0 -- Курсор включен
1 -- Курсор отключен
Начало строки сканирования курсора
Важно то, что курсор отключен, когда бит 5 установлен. В вашей функции github setcursor
вы делаете следующее:
outb(curstart | 0x20, 0x3D5);
curstart | 0x20
устанавливает бит 5 (0x20 = 0b00100000). Если вы хотите очистить бит 5 и включить курсор, вы должны побитово ОТРИЦАТЬ(~) битовую маску и побитовое И (&), что с curstart
. Это должно выглядеть так:
outb(curstart & ~0x20, 0x3D5);
Функциональные ошибки VGA
После того, как вы правильно активировали курсор, он отобразит курсор в цвете переднего плана (атрибут) для конкретного местоположения видео, в котором он находится в данный момент. Одна вещь, которую я заметил, это то, что ваша подпрограмма clc
делает это:
vga_deref_80x24(VGAx,VGAy) = \
vga_encode_80x24(' ',BgColor,BgColor);
Обратите внимание, что вы устанавливаете атрибут для цветов переднего плана и фона на BgColor
. Если вы установите bgcolor
в черный цвет перед вызовом clc
, он будет мигать черным подчеркивающим курсором на черном фоне, делая его невидимым в любом месте экрана. Чтобы курсор был виден, он должен находиться на экране, где передний план и фон имеют разные цвета. Один из способов проверить, работает ли это, — изменить код на:
vga_deref_80x24(VGAx,VGAy) = \
vga_encode_80x24(' ',BgColor,ForeColor);
Я думаю, что это ошибка, которую вы очищаете с помощью кодировки vga_encode_80x24(' ',BgColor,BgColor);
. Я думаю, вы имеете в виду использовать vga_encode_80x24(' ',BgColor,ForeColor);
Теперь в вашей функции kmain
вам нужно установить ForeColor и BgColor перед вызовом clc
, и они оба должны быть разных цветов, чтобы курсор был виден. У вас есть этот код:
setbgcolor(BLACK);
clc();
setforecolor(BLUE);
Теперь должно быть:
setbgcolor(BLACK);
setforecolor(BLUE);
clc();
Теперь, если курсор отображается где-либо в незаписанном месте на экране, он будет мигать СИНИМ подчеркиванием на ЧЕРНОМ фоне.
Это должно решить вашу проблему с курсором. Однако я заметил, что вы также используете encode vga_encode_80x24(' ',BgColor,BgColor);
в своих функциях VGA scrolldown
и terminal_control
. Я думаю, что это тоже ошибка, и я думаю, что вместо этого вам следует использовать encode vga_encode_80x24(' ',BgColor,ForeColor);
. Кажется, вы правильно установили его в terminal_write
.
Если вы хотите изменить цвет курсора в любом месте, вы можете написать функцию, которая изменяет атрибут переднего плана в месте расположения курсора без изменения цвета фона. Убедитесь, что два атрибута (цвет переднего плана и цвет фона) различны, чтобы курсор был виден. Если вы хотите скрыть курсор, вы можете установить цвет переднего плана и фона того же цвета, что и место на экране, в котором в данный момент находится курсор.
person
Michael Petch
schedule
26.09.2015
outb
запуталась.asm volatile ("outb %%al, $0"::"rm"(value), "a"(port));
это неправильно (как и inb).inb
иoutb
не принимают произвольные регистры. См. справку по инструкциям . Единственными допустимыми регистрами являются номер порта, указанный как непосредственное 8-битное значение или переданный в DX. Вы можете использовать только выходные регистры al/ax/eax. - person Michael Petch   schedule 26.09.2015inb
, иoutb
неверны. См. этот вопрос для правильной функцииinb
; stackoverflow.com/questions/32791997/ - person Ross Ridge   schedule 26.09.2015outb((position<<8)>>8,0x03d5);
легче выполнить побитовымand
изposition
с0xff
. Это установит верхние биты в 0, а нижние биты останутся такими, какие они есть. Что-то вроде `outb(position&0xff,0x03d5); - person Michael Petch   schedule 27.09.2015