瀏覽代碼

Use the VGA start address for fast VirtualConsole scrolling.

Instead of memcpy'ing the entire screen every time we press enter at the
bottom, use the VGA start address register to make a "view" onto the
underlying memory that moves downward as we scroll.

Eventually we run out of memory and have to reset to the start of the
buffer. That's when we memcpy everything. It would be cool if there was
some way to get the hardware to act like a ring buffer with automatic
wrapping here but I don't know how to do that.
Andreas Kling 6 年之前
父節點
當前提交
3e3de67f02
共有 6 個文件被更改,包括 76 次插入26 次删除
  1. 1 1
      Kernel/.bochsrc
  2. 1 1
      Kernel/Process.cpp
  3. 23 11
      Kernel/VGA.cpp
  4. 3 0
      Kernel/VGA.h
  5. 42 13
      Kernel/VirtualConsole.cpp
  6. 6 0
      Kernel/VirtualConsole.h

+ 1 - 1
Kernel/.bochsrc

@@ -26,7 +26,7 @@ optramimage2: file=none
 optramimage3: file=none
 optramimage3: file=none
 optramimage4: file=none
 optramimage4: file=none
 pci: enabled=1, chipset=i440fx
 pci: enabled=1, chipset=i440fx
-vga: extension=vbe, update_freq=5, realtime=1
+vga: extension=vbe, update_freq=25, realtime=1
 cpu: count=1, ips=4000000, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
 cpu: count=1, ips=4000000, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
 cpuid: level=6, stepping=3, model=3, family=6, vendor_string="GenuineIntel", brand_string="              Intel(R) Pentium(R) 4 CPU        "
 cpuid: level=6, stepping=3, model=3, family=6, vendor_string="GenuineIntel", brand_string="              Intel(R) Pentium(R) 4 CPU        "
 cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true
 cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true

+ 1 - 1
Kernel/Process.cpp

@@ -592,7 +592,7 @@ Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring
             if (!fork_parent->m_file_descriptors[i])
             if (!fork_parent->m_file_descriptors[i])
                 continue;
                 continue;
 #ifdef FORK_DEBUG
 #ifdef FORK_DEBUG
-            dbgprintf("fork: cloning fd %u... (%p) istty? %um\n", i, fork_parent->m_file_descriptors[i].ptr(), fork_parent->m_file_descriptors[i]->isTTY());
+            dbgprintf("fork: cloning fd %u... (%p) istty? %u\n", i, fork_parent->m_file_descriptors[i].ptr(), fork_parent->m_file_descriptors[i]->isTTY());
 #endif
 #endif
             m_file_descriptors[i] = fork_parent->m_file_descriptors[i]->clone();
             m_file_descriptors[i] = fork_parent->m_file_descriptors[i]->clone();
         }
         }

+ 23 - 11
Kernel/VGA.cpp

@@ -7,13 +7,6 @@
 
 
 static byte* vga_mem = nullptr;
 static byte* vga_mem = nullptr;
 
 
-void vga_scroll_up()
-{
-    InterruptDisabler disabler;
-    memcpy(vga_mem, vga_mem + 160, 160 * 24);
-    vga_clear_row(24);
-}
-
 void vga_clear_row(word line)
 void vga_clear_row(word line)
 {
 {
     InterruptDisabler disabler;
     InterruptDisabler disabler;
@@ -37,6 +30,24 @@ void vga_putch_at(byte row, byte column, byte ch, byte attr)
     vga_mem[cur + 1] = attr;
     vga_mem[cur + 1] = attr;
 }
 }
 
 
+word vga_get_start_address()
+{
+    word value;
+    IO::out8(0x3d4, 0x0d);
+    value = IO::in8(0x3d5) << 8;
+    IO::out8(0x3d4, 0x0c);
+    value |= IO::in8(0x3d5);
+    return value;
+}
+
+void vga_set_start_address(word value)
+{
+    IO::out8(0x3d4, 0x0c);
+    IO::out8(0x3d5, MSB(value));
+    IO::out8(0x3d4, 0x0d);
+    IO::out8(0x3d5, LSB(value));
+}
+
 void vga_init()
 void vga_init()
 {
 {
     vga_mem = (byte*)0xb8000;
     vga_mem = (byte*)0xb8000;
@@ -61,10 +72,6 @@ WORD vga_get_cursor()
 
 
 void vga_set_cursor(WORD value)
 void vga_set_cursor(WORD value)
 {
 {
-    if (value >= (80 * 25)) {
-        vga_set_cursor(0);
-        return;
-    }
     IO::out8(0x3d4, 0x0e);
     IO::out8(0x3d4, 0x0e);
     IO::out8(0x3d5, MSB(value));
     IO::out8(0x3d5, MSB(value));
     IO::out8(0x3d4, 0x0f);
     IO::out8(0x3d4, 0x0f);
@@ -75,3 +82,8 @@ void vga_set_cursor(BYTE row, BYTE column)
 {
 {
     vga_set_cursor(row * 80 + column);
     vga_set_cursor(row * 80 + column);
 }
 }
+
+void vga_set_cursor(byte row, byte column, word start_address)
+{
+    vga_set_cursor((start_address) + (row * 80 + column));
+}

+ 3 - 0
Kernel/VGA.h

@@ -4,9 +4,12 @@
 
 
 void vga_init();
 void vga_init();
 void vga_set_cursor(WORD);
 void vga_set_cursor(WORD);
+void vga_set_cursor(byte row, byte column, word start_address);
 void vga_set_cursor(BYTE row, BYTE column);
 void vga_set_cursor(BYTE row, BYTE column);
 WORD vga_get_cursor();
 WORD vga_get_cursor();
 void vga_putch_at(byte row, byte column, byte ch, byte attr);
 void vga_putch_at(byte row, byte column, byte ch, byte attr);
 void vga_scroll_up();
 void vga_scroll_up();
 void vga_clear();
 void vga_clear();
 void vga_clear_row(word);
 void vga_clear_row(word);
+word vga_get_start_address();
+void vga_set_start_address(word);

+ 42 - 13
Kernel/VirtualConsole.cpp

@@ -63,12 +63,13 @@ void VirtualConsole::set_active(bool b)
 
 
     m_active = b;
     m_active = b;
     if (!m_active) {
     if (!m_active) {
-        memcpy(m_buffer, s_vga_buffer, 80 * 25 * 2);
+        memcpy(m_buffer, m_current_vga_window, 80 * 25 * 2);
         return;
         return;
     }
     }
 
 
     memcpy(s_vga_buffer, m_buffer, 80 * 25 * 2);
     memcpy(s_vga_buffer, m_buffer, 80 * 25 * 2);
-    vga_set_cursor(m_cursor_row, m_cursor_column);
+    set_vga_start_row(0);
+    vga_set_cursor(m_cursor_row, m_cursor_column, m_current_vga_start_address);
 
 
     Keyboard::the().setClient(this);
     Keyboard::the().setClient(this);
 }
 }
@@ -282,15 +283,31 @@ void VirtualConsole::execute_escape_sequence(byte final)
     m_intermediates.clear();
     m_intermediates.clear();
 }
 }
 
 
+void VirtualConsole::clear_vga_row(word row)
+{
+    word* linemem = (word*)&m_current_vga_window[row * 160];
+    for (word i = 0; i < 80; ++i)
+        linemem[i] = 0x0720;
+}
+
 void VirtualConsole::scroll_up()
 void VirtualConsole::scroll_up()
 {
 {
     if (m_cursor_row == (m_rows - 1)) {
     if (m_cursor_row == (m_rows - 1)) {
-        memcpy(m_buffer, m_buffer + 160, 160 * 24);
-        word* linemem = (word*)&m_buffer[24 * 160];
-        for (word i = 0; i < 80; ++i)
-            linemem[i] = 0x0720;
-        if (m_active)
-            vga_scroll_up();
+        if (m_active) {
+            if (m_vga_start_row >= 160) {
+                memcpy(s_vga_buffer, m_current_vga_window + 160, 80 * 24 * 2);
+                set_vga_start_row(0);
+                clear_vga_row(24);
+            } else {
+                set_vga_start_row(m_vga_start_row + 1);
+                clear_vga_row(24);
+            }
+        } else {
+            memcpy(m_buffer, m_buffer + 160, 160 * 24);
+            word* linemem = (word*)&m_buffer[24 * 160];
+            for (word i = 0; i < 80; ++i)
+                linemem[i] = 0x0720;
+        }
     } else {
     } else {
         ++m_cursor_row;
         ++m_cursor_row;
     }
     }
@@ -304,7 +321,7 @@ void VirtualConsole::set_cursor(unsigned row, unsigned column)
     m_cursor_row = row;
     m_cursor_row = row;
     m_cursor_column = column;
     m_cursor_column = column;
     if (m_active)
     if (m_active)
-        vga_set_cursor(m_cursor_row, m_cursor_column);
+        vga_set_cursor(m_cursor_row, m_cursor_column, m_current_vga_start_address);
 }
 }
 
 
 void VirtualConsole::put_character_at(unsigned row, unsigned column, byte ch)
 void VirtualConsole::put_character_at(unsigned row, unsigned column, byte ch)
@@ -312,10 +329,14 @@ void VirtualConsole::put_character_at(unsigned row, unsigned column, byte ch)
     ASSERT(row < m_rows);
     ASSERT(row < m_rows);
     ASSERT(column < m_columns);
     ASSERT(column < m_columns);
     word cur = (row * 160) + (column * 2);
     word cur = (row * 160) + (column * 2);
-    m_buffer[cur] = ch;
-    m_buffer[cur + 1] = m_current_attribute;
-    if (m_active)
-        vga_putch_at(row, column, ch, m_current_attribute);
+    if (m_active) {
+        word cur = (row * 160) + (column * 2);
+        m_current_vga_window[cur] = ch;
+        m_current_vga_window[cur + 1] = m_current_attribute;
+    } else {
+        m_buffer[cur] = ch;
+        m_buffer[cur + 1] = m_current_attribute;
+    }
 }
 }
 
 
 void VirtualConsole::on_char(byte ch, bool shouldEmit)
 void VirtualConsole::on_char(byte ch, bool shouldEmit)
@@ -416,3 +437,11 @@ String VirtualConsole::ttyName() const
     ksprintf(buf, "/dev/tty%u", m_index);
     ksprintf(buf, "/dev/tty%u", m_index);
     return String(buf);
     return String(buf);
 }
 }
+
+void VirtualConsole::set_vga_start_row(word row)
+{
+    m_vga_start_row = row;
+    m_current_vga_start_address = row * 80;
+    m_current_vga_window = s_vga_buffer + row * 160;
+    vga_set_start_address(m_current_vga_start_address);
+}

+ 6 - 0
Kernel/VirtualConsole.h

@@ -51,6 +51,12 @@ private:
     byte m_saved_cursor_column { 0 };
     byte m_saved_cursor_column { 0 };
     byte m_current_attribute { 0x07 };
     byte m_current_attribute { 0x07 };
 
 
+    void clear_vga_row(word row);
+    void set_vga_start_row(word row);
+    word m_vga_start_row { 0 };
+    word m_current_vga_start_address { 0 };
+    byte* m_current_vga_window { nullptr };
+
     void execute_escape_sequence(byte final);
     void execute_escape_sequence(byte final);
 
 
     enum EscapeState {
     enum EscapeState {