Курсор текстового режима не отображается в эмуляторе qemu vga

У меня проблема с функцией, которая обновляет позицию курсора в текстовом режиме, определение и объявление функции

#include <sys/io.h>
signed int VGAx = 0,VGAy=0;
void setcursor()
{
        uint16_t position = VGAx+VGAy*COLS;
        outb(0x0f, 0x03d4);
        outb((position<<8)>>8,0x03d5);
        outb(0x0e,0x03d4);
        outb(position>>8,0x03d5);
}

и файл sys/io.h

static inline unsigned char inb (unsigned short int port)
{
        unsigned char value;
        asm ("inb %0, %%al":"=rm"(value):"a"(port));
        return value;
}
static inline void outb(unsigned char value, unsigned short int port)
{
        asm volatile ("outb %%al, $0"::"rm"(value), "a"(port));
}

до использования функции курсор иногда мигал подчеркиванием, а иногда не появлялся, а после использования функции курсор не появлялся

вот основная функция, которая работает

#include <vga/vga.h>
int kmain(){
        setcursor()
        setbgcolor(BLACK);
        clc();
        setforecolor(BLUE);
        terminal_write('h');
        setcursor();
        return 0;
}

Я пытался использовать эту функцию

void enable_cursor() {
    outb(0x3D4, 0x0A);
    char curstart = inb(0x3D5) & 0x1F; // get cursor scanline start

    outb(0x3D4, 0x0A);
    outb(0x3D5, curstart | 0x20); // set enable bit
}

который предоставляется здесь, но я получил эту ошибку inline asm: operand type mismatch for 'in' любая помощь приветствуется

EDIT Я пытался исправить неправильные inb и outb:

static inline unsigned char inb (unsigned short int port)
{
        unsigned char value;
        asm volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
        return value;
}
static inline void outb(unsigned char value, unsigned short int port)
{
        asm volatile ("outb %%al, $0"::"Nd"(value), "a"(port));
}

Я думаю, это правильное определение, но курсор все еще не появился

EDIT 2 Я последовал данному ответу и определил файл io.h следующим образом

static inline unsigned char inb (unsigned short int port)
{
        unsigned char value;
        asm volatile ("inb %1, %0" : "=a"(value) : "Nd"(port));
        return value;
}
static inline void outb(unsigned char value, unsigned short int port)
{
        asm volatile ("outb %0, %1"::"a"(value), "Nd"(port));
}

Я хотел бы отметить, что я также добавил enable_cursor(); в начало kmain, теперь ошибка времени компиляции исправлена, но курсор не появлялся (что является основной проблемой)

EDIT 3 Я хотел бы отметить, что версия всего кода доступна на gihub. если кто-то хочет получить доступ к частям кода, которых нет в вопросе


person oddcoder    schedule 26.09.2015    source источник
comment
Проблема в том, что ваша функция outb запуталась. asm volatile ("outb %%al, $0"::"rm"(value), "a"(port)); это неправильно (как и inb). inb и outb не принимают произвольные регистры. См. справку по инструкциям . Единственными допустимыми регистрами являются номер порта, указанный как непосредственное 8-битное значение или переданный в DX. Вы можете использовать только выходные регистры al/ax/eax.   -  person Michael Petch    schedule 26.09.2015
comment
И inb, и outb неверны. См. этот вопрос для правильной функции inb; stackoverflow.com/questions/32791997/   -  person Ross Ridge    schedule 26.09.2015
comment
до сих пор ничего не изменилось   -  person oddcoder    schedule 26.09.2015
comment
извините, что не упомянул об этом #define COLS 80 #define ROWS 25 да, он установлен на 80   -  person oddcoder    schedule 27.09.2015
comment
Ваш код всегда устанавливает курсор в верхний левый угол экрана. Где вы обновляете VGAx и VGAy, чтобы переместить курсор в другое место, или вы намерены всегда ставить курсор на 0,0?   -  person Michael Petch    schedule 27.09.2015
comment
VGAx и VGAy обновляются до положения курсора в любой из функций terminal_write, clc или terminal_control. Эти функции, я уверен, работают отлично и тщательно отлажены.   -  person oddcoder    schedule 27.09.2015
comment
на самом деле я дал ссылку, где все (операционная система barebone существует в EDIT 3)   -  person oddcoder    schedule 27.09.2015
comment
Хотя это и не является частью вашей проблемы, ваш код outb((position<<8)>>8,0x03d5); легче выполнить побитовым and из position с 0xff. Это установит верхние биты в 0, а нижние биты останутся такими, какие они есть. Что-то вроде `outb(position&0xff,0x03d5);   -  person Michael Petch    schedule 27.09.2015
comment
На самом деле я только что заметил, что код в вашем репозитории github для enable_cursor() не соответствует тому, что вы разместили в Stackoverflow в своем вопросе. Вы вроде в одном месте починили, а в другом нет? Такие вещи делают это более трудным, чем нужно. И поскольку я не собираюсь собирать и тестировать ваше ядро, думаю, я потратил на это достаточно времени.   -  person Michael Petch    schedule 27.09.2015


Ответы (1)


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
comment
все еще не повезло, что курсор появился :( - person oddcoder; 26.09.2015
comment
да, но указатель все еще не появляется на экране, и цель состояла в том, чтобы заставить функцию работать правильно, и я попытался объяснить проблему, показав ошибку времени компиляции, однако ошибка устранена, цель не достигнута - person oddcoder; 26.09.2015
comment
Пожалуйста, помогите мне выяснить, почему курсор не появился, потому что это заняло у меня много времени, я хорошо разбираюсь в сборке, но проблема в том, что я впервые работаю с портами. - person oddcoder; 26.09.2015
comment
да на самом деле я напечатал это почти до того, как прочитал ваш ответ - person oddcoder; 26.09.2015
comment
затем я скопировал и вставил ваши функции как есть - person oddcoder; 26.09.2015
comment
это последняя версия, которую я использую static inline unsigned char inb (unsigned short int port) { unsigned char value; asm volatile ("inb %1, %0" : "=a"(value) : "Nd"(port)); return value; } static inline void outb(unsigned char value, unsigned short int port) { asm volatile ("outb %0, %1"::"a"(value), "Nd"(port)); } извините за неправильный формат - person oddcoder; 26.09.2015
comment
Клянусь, я исправил это в своем коде и отредактирую пост] - person oddcoder; 26.09.2015
comment
@AhmedAbdElMawgood Я изменил свой ответ, чтобы предоставить вам информацию об исправлении ошибки, из-за которой вы не смогли включить курсор. Код, который у вас есть, фактически отключает его (вопреки тому, что вы хотели). - person Michael Petch; 27.09.2015
comment
@AhmedAbdElMawgood: я дополнил свой ответ информацией о том, как отображается курсор, и о ряде проблем, которые у вас возникают с настройкой цвета переднего плана и фона, которые эффективно скрывают курсор. Теперь я представил решение для этого. - person Michael Petch; 27.09.2015
comment
большое спасибо, я действительно хочу поблагодарить вас, даже мои помощники не смогли помочь, я благодарен за вашу бесценную помощь. - person oddcoder; 27.09.2015
comment
Этот пост был очень полезен — спасибо. (Моя особая проблема заключалась в том, что когда я прокручивал дисплей, я обнулял последнюю строку, устанавливая цвет «черный на черном», то есть невидимый, и, следовательно, также курсор.) - person Thanatos; 28.07.2016