#include "tty.h" #include "x86.h" #include "console.h" #include "const.h" #include "assert.h" #define INDEX(row, col) ((row)*SCR_WIDTH + (col)) #define NEXTLINE(row) NEXT(row, SCR_MAXLINE) #define LASTLINE(row) LAST(row, SCR_MAXLINE) #define ADDLINE(row, add_num) (((row) + add_num) % SCR_MAXLINE) void enable_blink() { disable_int(); inb(0x3DA); outb(0x3C0, 0x30); u8 temp = inb(0x3C1); outb(0x3C0, temp | 0x08); enable_int(); } void disable_blink() { disable_int(); inb(0x3DA); outb(0x3C0, 0x30); u8 temp = inb(0x3C1); outb(0x3C0, temp & 0xF7); enable_int(); } void set_underline(u32 addr) { disable_int(); inb(0x3DA); outb(0x3C0, 0x30); u8 temp = inb(0x3C1); outb(0x3C0, temp | 0x01); outb(CRTC_ADDR_REG, UNDERLINE_REG); outb(CRTC_DATA_REG, addr & 0xFF); enable_int(); } // called by csi void csi_scroll(vga_buf *vgabuf, i16 scroll_num) { while (scroll_num > 0) // down { scroll_num--; for (int i = SCR_HEIGHT - 1; i > 0; i--) { int line_dst = ADDLINE(vgabuf->scr_top_line, i); int line_src = ADDLINE(vgabuf->scr_top_line, i - 1); u32 *ptr_buf_dst = (u32 *)(vgabuf->buf + sizeof(u16) * line_dst * SCR_WIDTH); u32 *ptr_buf_src = (u32 *)(vgabuf->buf + sizeof(u16) * line_src * SCR_WIDTH); for (int p = 0; p < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++p) { *ptr_buf_dst++ = *ptr_buf_src++; } } u32 *ptr_buf_start = (u32 *)(vgabuf->buf + sizeof(u16) * (vgabuf->scr_top_line) * SCR_WIDTH); for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++i) { *ptr_buf_start++ = (BLANK << 16) | BLANK; } } while (scroll_num < 0) // up { scroll_num++; for (int i = 0; i < SCR_HEIGHT - 1; i++) { int line_dst = ADDLINE(vgabuf->scr_top_line, i); int line_src = ADDLINE(vgabuf->scr_top_line, i + 1); u32 *ptr_buf_dst = (u32 *)(vgabuf->buf + sizeof(u16) * line_dst * SCR_WIDTH); u32 *ptr_buf_src = (u32 *)(vgabuf->buf + sizeof(u16) * line_src * SCR_WIDTH); for (int p = 0; p < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++p) { *ptr_buf_dst++ = *ptr_buf_src++; } } int line_end = ADDLINE(vgabuf->scr_top_line, SCR_HEIGHT - 1); u32 *ptr_buf_end = (u32 *)(vgabuf->buf + sizeof(u16) * line_end * SCR_WIDTH); for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++i) { *ptr_buf_end++ = (BLANK << 16) | BLANK; // bg-black, fg-white, ascii-space } } } void cursor_locate(i16 row, i16 col, vga_buf *vgabuf) { vgabuf->scr_cur_line = vgabuf->scr_top_line; while (row > 0 && row < SCR_HEIGHT) { row--; vgabuf->scr_cur_line = NEXTLINE(vgabuf->scr_cur_line); if (vgabuf->scr_cur_line == vgabuf->scr_bot_line) break; } if (col >= 0 && col <= SCR_WIDTH - 1) { vgabuf->cur_col = col; } } void cursor_move(i16 move_row, i16 move_col, vga_buf *vgabuf) { // kprintf("%d,%d", move_row, move_col); while (move_row > 0) // down { move_row--; if (vgabuf->scr_cur_line == vgabuf->scr_bot_line) break; vgabuf->scr_cur_line = NEXTLINE(vgabuf->scr_cur_line); vgabuf->cur_row = CYCLE_SUB(vgabuf->scr_top_line, vgabuf->scr_cur_line, SCR_MAXLINE); if (vgabuf->cur_row == SCR_HEIGHT) { // auto scroll vgabuf->scr_top_line = NEXTLINE(vgabuf->scr_top_line); } } while (move_row < 0) // up { move_row++; if (vgabuf->scr_cur_line == vgabuf->scr_top_line) break; vgabuf->scr_cur_line = LASTLINE(vgabuf->scr_cur_line); // if (vgabuf->scr_cur_line == vgabuf->scr_top_line) // { // if (vgabuf->scr_top_line == vgabuf->head_line) // break; // // vgabuf->scr_cur_line = LASTLINE(vgabuf->scr_cur_line); // vgabuf->scr_top_line = LASTLINE(vgabuf->scr_top_line); // vgabuf->scr_bot_line = LASTLINE(vgabuf->scr_bot_line); // } } vgabuf->cur_row = CYCLE_SUB(vgabuf->scr_top_line, vgabuf->scr_cur_line, SCR_MAXLINE); vgabuf->cur_col += move_col; if (vgabuf->cur_col < 0) vgabuf->cur_col = 0; else if (vgabuf->cur_col >= SCR_WIDTH) vgabuf->cur_col = SCR_WIDTH - 1; } void clear_screen(vga_buf *vgabuf, i16 src_row, i16 src_col, i16 dst_row, i16 dst_col) { u16 *buf = vgabuf->buf; int src_index = INDEX(src_row, src_col); int dst_index = INDEX(dst_row, dst_col); if (src_index <= dst_index) for (int i = src_index; i <= dst_index; i++) { buf[i] = BLANK; } else // scr>dst { for (int i = 0; i <= dst_index; i++) buf[i] = BLANK; int index_end = INDEX(SCR_MAXLINE - 1, SCR_WIDTH - 1); for (int i = 0; i <= index_end; i++) buf[i] = BLANK; } } inline static void param12vga_color(i16 *param) { u8 tmp = *param & 1; *param &= 0b0110; *param |= *param >> 2; *param &= 0b0011; *param |= tmp << 2; } inline static void enable_reverse(vga_buf *vgabuf) { vgabuf->last_color = vgabuf->color; vgabuf->color = ((vgabuf->color & 0xf000) >> 4) | ((vgabuf->color & 0x0f00) << 4); vgabuf->IsColorReverse = true; } inline static void disable_reverse(vga_buf *vgabuf) { if (vgabuf->IsColorReverse == true) { vgabuf->color = vgabuf->last_color; vgabuf->IsColorReverse = false; } } inline static void enable_hide(vga_buf *vgabuf) { vgabuf->last_color = vgabuf->color; u16 back_clolor = ((vgabuf->color & 0xF000) >> 4); vgabuf->color &= 0xf000; vgabuf->color |= back_clolor; vgabuf->IsHide = true; } inline static void disable_hide(vga_buf *vgabuf) { if (vgabuf->IsHide == true) { vgabuf->color = vgabuf->last_color; vgabuf->IsHide = false; } } void set_color(vga_buf *vgabuf) { if (vgabuf->param1 == 0) { disable_reverse(vgabuf); disable_hide(vgabuf); vgabuf->color = DEFAULT_CHAR_COLOR; } else if (vgabuf->param1 == 7) { enable_reverse(vgabuf); } else if (vgabuf->param1 == 8) { enable_hide(vgabuf); } else if (vgabuf->param1 == 25) { disable_blink(); vgabuf->color &= (~FLASH_CHAR); } else if (vgabuf->param1 == 27) { disable_reverse(vgabuf); } else if (vgabuf->param1 == 28) { disable_hide(vgabuf); } else if (30 <= vgabuf->param1 && vgabuf->param1 <= 37) { vgabuf->param1 -= 30; param12vga_color(&(vgabuf->param1)); vgabuf->color = (vgabuf->color & 0xf8ff) | FOREGROUND(vgabuf->param1); } else if (vgabuf->param1 == 39) { u16 default_foreground = DEFAULT_CHAR_COLOR & 0x0f00; vgabuf->color = (vgabuf->color & 0xf0ff) | default_foreground; } else if (40 <= vgabuf->param1 && vgabuf->param1 <= 47) { vgabuf->param1 -= 40; param12vga_color(&(vgabuf->param1)); vgabuf->color = (vgabuf->color & 0x8fff) | BACKGROUND(vgabuf->param1); } else if (vgabuf->param1 == 49) { u16 default_background = DEFAULT_CHAR_COLOR & 0xf000; vgabuf->color = (vgabuf->color & 0x0fff) | default_background; } else if (90 <= vgabuf->param1 && vgabuf->param1 <= 97) { vgabuf->param1 -= 90; param12vga_color(&(vgabuf->param1)); vgabuf->param1 |= 0x8; vgabuf->color = (vgabuf->color & 0xf0ff) | FOREGROUND(vgabuf->param1); } else if (100 <= vgabuf->param1 && vgabuf->param1 <= 107) { vgabuf->param1 -= 100; param12vga_color(&(vgabuf->param1)); vgabuf->param1 |= 0x8; vgabuf->color = (vgabuf->color & 0x0fff) | BACKGROUND(vgabuf->param1); } else { warn("\x1b[47;93munsupport CSI: sgr param:%d\x1b[m\n", vgabuf->param1); } if (vgabuf->Is2param == true) { if (vgabuf->param2 == 0) { disable_reverse(vgabuf); disable_hide(vgabuf); vgabuf->color = DEFAULT_CHAR_COLOR; } // else if (vgabuf->param2 == 5 || vgabuf->param2 == 6) // { // enable_blink(); // vgabuf->color |= FLASH_CHAR; // } else if (vgabuf->param2 == 7) { enable_reverse(vgabuf); } else if (vgabuf->param2 == 8) { enable_hide(vgabuf); } else if (vgabuf->param2 == 25) { disable_blink(); vgabuf->color &= (~FLASH_CHAR); } else if (vgabuf->param2 == 27) { disable_reverse(vgabuf); } else if (vgabuf->param2 == 28) { disable_hide(vgabuf); } else if (30 <= vgabuf->param2 && vgabuf->param2 <= 37) { vgabuf->param2 -= 30; param12vga_color(&(vgabuf->param2)); vgabuf->color = (vgabuf->color & 0xf8ff) | FOREGROUND(vgabuf->param2); } else if (vgabuf->param2 == 39) { u16 default_foreground = DEFAULT_CHAR_COLOR & 0x0f00; vgabuf->color = (vgabuf->color & 0xf0ff) | default_foreground; } else if (40 <= vgabuf->param2 && vgabuf->param2 <= 47) { vgabuf->param2 -= 40; param12vga_color(&(vgabuf->param2)); vgabuf->color = (vgabuf->color & 0x8fff) | BACKGROUND(vgabuf->param2); } else if (vgabuf->param2 == 49) { u16 default_background = DEFAULT_CHAR_COLOR & 0xf000; vgabuf->color = (vgabuf->color & 0x0fff) | default_background; } else if (90 <= vgabuf->param2 && vgabuf->param2 <= 97) { vgabuf->param2 -= 90; param12vga_color(&(vgabuf->param2)); vgabuf->param2 |= 0x8; vgabuf->color = (vgabuf->color & 0xf0ff) | FOREGROUND(vgabuf->param2); } else if (100 <= vgabuf->param2 && vgabuf->param2 <= 107) { vgabuf->param2 -= 100; param12vga_color(&(vgabuf->param2)); vgabuf->param2 |= 0x8; vgabuf->color = (vgabuf->color & 0x0fff) | BACKGROUND(vgabuf->param2); } else { warn("\x1b[47;93unsupport CSI: sgr param:%d\n", vgabuf->param2); } } } void CSI_Erase_handler(vga_buf *vgabuf, int n) { if (n == 2) { vgabuf->scr_bot_line = ADDLINE(vgabuf->scr_top_line, SCR_HEIGHT - 1); for (int i = 0; i < SCR_HEIGHT; i++) { vgabuf->scr_cur_line = NEXTLINE(vgabuf->scr_cur_line); vgabuf->scr_bot_line = NEXTLINE(vgabuf->scr_bot_line); // kprintf("af %x\n", vgabuf->scr_cur_line); vgabuf->cur_row = CYCLE_SUB(vgabuf->scr_top_line, vgabuf->scr_bot_line, SCR_MAXLINE); if (vgabuf->cur_row == SCR_HEIGHT) { // auto scroll vgabuf->scr_top_line = NEXTLINE(vgabuf->scr_top_line); } if (vgabuf->scr_bot_line == vgabuf->head_line) { vgabuf->head_line = NEXTLINE(vgabuf->head_line); // remember to fill blank the old line u32 *ptr_buf = (u32 *)(vgabuf->buf + sizeof(u16) * vgabuf->scr_bot_line * SCR_WIDTH); for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++i) { *ptr_buf++ = (BLANK << 16) | BLANK; // bg-black, fg-white, ascii-space } } } } if (n == 3) { int line = vgabuf->head_line; while (line != vgabuf->scr_top_line) { u32 *ptr_buf = (u32 *)(vgabuf->buf + sizeof(u16) * line * SCR_WIDTH); for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++i) { *ptr_buf++ = (BLANK << 16) | BLANK; // bg-black, fg-white, ascii-space } line = NEXTLINE(line); } vgabuf->head_line = vgabuf->scr_top_line; } } void CSI_handler(u8 terminator, vga_buf *vgabuf) { vgabuf->CSI = CSI_ESC; switch (terminator) { case 'A': // Cursor Up if (vgabuf->param1 == 0) vgabuf->param1 = 1; cursor_move(-vgabuf->param1, 0, vgabuf); break; case 'B': // Cursor Down if (vgabuf->param1 == 0) vgabuf->param1 = 1; cursor_move(+vgabuf->param1, 0, vgabuf); break; case 'C': // Cursor Forward if (vgabuf->param1 == 0) vgabuf->param1 = 1; cursor_move(0, +vgabuf->param1, vgabuf); break; case 'D': // Cursor Back if (vgabuf->param1 == 0) vgabuf->param1 = 1; cursor_move(0, -vgabuf->param1, vgabuf); // nothing break; case 'E': // Cursor Next Line if (vgabuf->param1 == 0) vgabuf->param1 = 1; cursor_move(+vgabuf->param1, -vgabuf->cur_col, vgabuf); break; case 'F': // Cursor Previous Line if (vgabuf->param1 == 0) vgabuf->param1 = 1; cursor_move(-vgabuf->param1, -vgabuf->cur_col, vgabuf); break; case 'G': // Cursor Horizontal Absolute if (vgabuf->param1 == 0) vgabuf->param1 = 1; cursor_locate(CYCLE_SUB(vgabuf->scr_top_line, vgabuf->scr_cur_line, SCR_MAXLINE), vgabuf->param1 - 1, vgabuf); break; case 'H': // Cursor Position case 'f': if (vgabuf->param1 == 0) vgabuf->param1 = 1; if (vgabuf->param2 == 0) vgabuf->param2 = 1; cursor_locate(vgabuf->param1 - 1, vgabuf->param2 - 1, vgabuf); break; case 'J': // Erase in Display if (vgabuf->param1 == 0) // from Cursor Position to the end of the screen clear_screen(vgabuf, vgabuf->scr_cur_line, vgabuf->cur_col, ADDLINE(vgabuf->scr_top_line, SCR_HEIGHT - 1), SCR_WIDTH - 1); else if (vgabuf->param1 == 1) // from Cursor Position to the start of the screen clear_screen(vgabuf, vgabuf->scr_top_line, 0, vgabuf->scr_cur_line, vgabuf->cur_col); else if (vgabuf->param1 == 2) // The whole screen CSI_Erase_handler(vgabuf, 2); else if (vgabuf->param1 == 3) // The whole screen and the buffer CSI_Erase_handler(vgabuf, 3); break; case 'K': // Erase in Line if (vgabuf->param1 == 0) // from Cursor Position to the end of the line clear_screen(vgabuf, vgabuf->scr_cur_line, vgabuf->cur_col, vgabuf->scr_cur_line, SCR_WIDTH - 1); else if (vgabuf->param1 == 1) // from Cursor Position to the start of the line clear_screen(vgabuf, vgabuf->scr_cur_line, 0, vgabuf->scr_cur_line, vgabuf->cur_col); else if (vgabuf->param1 == 2) // The whole line clear_screen(vgabuf, vgabuf->scr_cur_line, 0, vgabuf->scr_cur_line, SCR_WIDTH - 1); break; case 'S': // Scroll Up if (vgabuf->param1 == 0) vgabuf->param1 = 1; csi_scroll(vgabuf, -vgabuf->param1); break; case 'T': // Scroll Down if (vgabuf->param1 == 0) vgabuf->param1 = 1; csi_scroll(vgabuf, +vgabuf->param1); break; case 'm': // Select Graphic Rendition set_color(vgabuf); break; } }