// // Created by rick on 8/18/19. // #include #include #include #include #include char *_vga_character_memory = (char *) VGA_CHARACTER_MEMORY_LOCATION; int get_offset(int col, int row); int get_cursor_offset(); void set_cursor_offset(int offset); int get_offset_row(int offset); int get_offset_col(int offset); int print_char(char character, int col, int row, char attributes); void vga_clear_screen() { int size = VGA_COL_MAX * VGA_ROW_MAX; for (int i = 0; i < size; ++i) { _vga_character_memory[i * 2] = ' '; _vga_character_memory[i * 2 + 1] = VGA_WHITE | (VGA_BLACK << VGA_SHIFT_BG); } set_cursor_offset(0); } void kprint_at(const char *message, int col, int row) { int offset; if (col > 0 && row > 0) { offset = get_offset(col, row); } else { offset = get_cursor_offset(); row = get_offset_row(offset); col = get_offset_col(offset); } int i = 0; while (message[i] != 0) { offset = print_char(message[i++], col, row, VGA_WHITE | (VGA_BLACK << VGA_SHIFT_BG)); row = get_offset_row(offset); col = get_offset_col(offset); } } void vga_kprint(const char *message) { kprint_at(message, -1, -1); } int print_char(char character, int col, int row, char attributes) { if (!attributes) attributes = VGA_WHITE | (VGA_BLACK < VGA_SHIFT_BG); if (col >= VGA_COL_MAX || row > +VGA_ROW_MAX) { _vga_character_memory[2 * (VGA_COL_MAX) * (VGA_ROW_MAX) - 2] = 'E'; _vga_character_memory[2 * (VGA_COL_MAX) * (VGA_ROW_MAX) - 1] = VGA_RED | (VGA_WHITE < VGA_SHIFT_BG); return get_offset(col, row); } int offset; if (col >= 0 && row >= 0) { offset = get_offset(col, row); } else { offset = get_cursor_offset(); } switch (character) { case '\n': row = get_offset_row(offset); offset = get_offset(0, row + 1); break; case '\t': col = (col + 4) & (~0b11); if (col > VGA_COL_MAX) { row = get_offset_row(offset); offset = get_offset(0, row + 1); } else { offset = get_offset(col, row); } break; case '\r': row = get_offset_row(offset); offset = get_offset(0, row); break; default: _vga_character_memory[offset] = character; _vga_character_memory[offset + 1] = attributes; offset += 2; break; } if (offset >= (VGA_COL_MAX * 2 * VGA_ROW_MAX)) { memcpy(_vga_character_memory, _vga_character_memory + (VGA_COL_MAX * 2), (2 * VGA_COL_MAX * VGA_ROW_MAX) - (2 * VGA_COL_MAX)); for (int i = 0; i < VGA_COL_MAX; ++i) { _vga_character_memory[get_offset(i, VGA_ROW_MAX - 1)] = ' '; } offset = get_offset(0, VGA_ROW_MAX - 1); } set_cursor_offset(offset); return offset; } int get_cursor_offset() { port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_H); int offset = ((int) port_byte_in(PORT_REG_SCREEN_DATA)) << 8; port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_L); offset += port_byte_in(PORT_REG_SCREEN_DATA); return offset * 2; } void set_cursor_offset(int offset) { offset /= 2; port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_L); port_byte_out(PORT_REG_SCREEN_DATA, (unsigned char) (offset & 0xFF)); port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_H); port_byte_out(PORT_REG_SCREEN_DATA, (unsigned char) (offset >> 8) & 0xFF); } int get_offset(int col, int row) { return (row * VGA_COL_MAX + col) * 2; } int get_offset_row(int offset) { return offset / (VGA_COL_MAX * 2); } int get_offset_col(int offset) { return (offset - (get_offset_row(offset) * 2 * VGA_COL_MAX)) / 2; } void vga_init() { vga_clear_screen(); kprint_register(vga_kprint); } INIT_FUNCTION(100) = { .name = "vga", .stage = INIT_STAGE_EARLY_BOOT_0, .init = vga_init, };