MushOS  0.1
A UNIX-like OS prototype, written from scratch
Loading...
Searching...
No Matches
screen.c
1#include "screen.h"
2
3#include "../../lib/base/generic.h"
4#include "../../lib/base/memory.h"
5#include "../../lib/base/syscall.h"
6
7#include "../kernel/interruption_tables.h"
8
9#include "ports_io.h"
10
11
12#define REG_SCREEN_CTRL 0x3d4
13#define REG_SCREEN_DATA 0x3d5
14
15#define VIDEO_MEMORY 0xb8000
16
17#define BLACK 0u
18#define LIGHT_GRAY 7u
19
20#define ROWS_NUM 25
21#define COLS_NUM 80
22
23typedef struct {
24 word row;
25 word column;
27
28
29
30static u_dword get_cursor_offset() {
31 port_byte_out(REG_SCREEN_CTRL, 14);
32 u_dword offset = (u_dword) ((port_byte_in(REG_SCREEN_DATA) << 8) & 0xff00);
33 port_byte_out(REG_SCREEN_CTRL, 15);
34 offset += (u_dword) (port_byte_in(REG_SCREEN_DATA) & 0x00ff);
35 return offset;
36}
37
38static void set_cursor_offset(u_dword offset) {
39 //if (offset > COLS_NUM * ROWS_NUM) return; FIXME simple check not working.
40 port_byte_out(REG_SCREEN_CTRL, 14);
41 port_byte_out(REG_SCREEN_DATA, (byte) ((offset & 0xff00) >> 8));
42 port_byte_out(REG_SCREEN_CTRL, 15);
43 port_byte_out(REG_SCREEN_DATA, (byte) (offset & 0x00ff));
44}
45
46static screen_coords get_cursor() {
47 u_dword offset = get_cursor_offset();
48 return (screen_coords) {offset % COLS_NUM + 1, offset / COLS_NUM};
49}
50
51static void set_cursor(screen_coords coords) {
52 set_cursor_offset(coords.row * COLS_NUM + coords.column);
53}
54
55
56
57static u_dword scroll (u_dword cursor_offset) {
58 if (cursor_offset < COLS_NUM * ROWS_NUM * 2) return cursor_offset;
59
60 for (int i = 1; i < ROWS_NUM; ++i) {
61 byte* curr_row = (byte*) VIDEO_MEMORY + (i * COLS_NUM * 2);
62 byte* prev_row = (byte*) VIDEO_MEMORY + ((i - 1) * COLS_NUM * 2);
63 memory_copy(curr_row, prev_row, COLS_NUM * 2);
64 }
65
66 byte* last = (byte*) VIDEO_MEMORY + ((ROWS_NUM - 1) * COLS_NUM * 2);
67 u_word sample = (BLACK << 12u) + (LIGHT_GRAY << 8u) + ' ';
68 memory_fill(last, (byte *) &sample, 2, COLS_NUM);
69 cursor_offset -= COLS_NUM * 2;
70
71 return cursor_offset;
72}
73
74
75
76void print_char_color (char c, byte text_color, byte back_color) {
77 byte attributes = (back_color << 4u) + text_color;
78 byte* vm = (byte*) VIDEO_MEMORY;
79 u_dword mem_offset = get_cursor_offset() * 2;
80
81 if (c == '\n') {
82 u_dword rows = (mem_offset / 2) / COLS_NUM + 1;
83 mem_offset = 2 * COLS_NUM * rows - 2;
84 } else if (c == '\b') {
85 mem_offset -= 2;
86 vm[mem_offset] = ' ';
87 vm[mem_offset + 1] = attributes;
88 mem_offset -= 2;
89 } else if (c == '\t') {
90 for (int i = 0; i < 4; ++i) {
91 vm[mem_offset + (2 * i)] = ' ';
92 vm[mem_offset + (2 * i) + 1] = attributes;
93 }
94 mem_offset += 6;
95 } else {
96 vm[mem_offset] = c;
97 vm[mem_offset + 1] = attributes;
98 }
99
100 mem_offset += 2;
101 mem_offset = scroll(mem_offset);
102 set_cursor_offset(mem_offset / 2);
103}
104
105char get_char(screen_coords coords) {
106 byte* vm = (byte*) VIDEO_MEMORY;
107 return vm[coords.row * coords.column];
108}
109
110
111
112extern void print_string_color(string str, byte text_color, byte back_color, u_dword length) {
113 if (length == 0) for (int i = 0; str[i] != 0; ++i) print_char_color(str[i], text_color, back_color);
114 else for (int i = 0; i < length; ++i) print_char_color(str[i], text_color, back_color);
115}
116
117
118
119void clear_screen() {
120 u_word sample = (BLACK << 12) + (LIGHT_GRAY << 8) + ' ';
121 memory_fill((byte*) VIDEO_MEMORY, (byte *) &sample, 2, COLS_NUM * ROWS_NUM);
122 set_cursor((screen_coords) {0, 0});
123}
124
125
126
127typedef enum {
128 GET_CHAR = 0, SET_CHAR = 1, SET_CHARS = 2, GET_CURSOR = 3, SET_CURSOR = 4, CLEAR_SCREEN = 5
129} call_type;
130
131static void screen_callback(registers* regs) {
132 u_dword call_type, ret_value = 0;
133 system_get_arg(regs->ebp, 0, call_type)
134 switch (call_type) {
135 case GET_CHAR: {
136 ret_value = get_char((screen_coords) {0, 0});
137 break;
138 }
139 case SET_CHAR: {
140 u_dword character, front_color, back_color;
141 system_get_arg(regs->ebp, 1, character)
142 system_get_arg(regs->ebp, 2, front_color)
143 system_get_arg(regs->ebp, 3, back_color)
144 print_char_color(character, front_color, back_color);
145 break;
146 }
147 case SET_CHARS: {
148 u_dword str, front_color, back_color, length;
149 system_get_arg(regs->ebp, 1, str)
150 system_get_arg(regs->ebp, 2, front_color)
151 system_get_arg(regs->ebp, 3, back_color)
152 system_get_arg(regs->ebp, 4, length)
153 print_string_color((mod_string) str, front_color, back_color, length);
154 }
155 case GET_CURSOR: {
156 ret_value = get_cursor_offset();
157 break;
158 }
159 case SET_CURSOR: {
160 u_dword offset;
161 system_get_arg(regs->ebp, 1, offset)
162 set_cursor_offset(offset);
163 break;
164 }
165 case CLEAR_SCREEN:
166 clear_screen();
167 break;
168 default:
169 break;
170 }
171 system_push(regs->ebp, ret_value)
172}
173
174
175
176void init_screen_io() {
177 set_interrupt_handler(48, screen_callback);
178}