e43ebc5883e11b496a3826f1ade11af34ba3f485
[lunaix-os.git] / lunaix-os / kernel / lxconsole.c
1 #include <klibc/string.h>
2 #include <lunaix/device.h>
3 #include <lunaix/lxconsole.h>
4 #include <lunaix/mm/pmm.h>
5 #include <lunaix/mm/vmm.h>
6 #include <lunaix/tty/console.h>
7 #include <lunaix/tty/tty.h>
8
9 static struct console lx_console;
10
11 int
12 __tty_write(struct device* dev,
13             void* buf,
14             unsigned int offset,
15             unsigned int len);
16
17 void
18 lxconsole_init()
19 {
20     memset(&lx_console, 0, sizeof(lx_console));
21     lx_console.buffer.data = VGA_BUFFER_VADDR + 0x1000;
22     lx_console.buffer.size = 8192;
23     mutex_init(&lx_console.buffer.lock);
24
25     // 分配控制台缓存
26     for (size_t i = 0; i < PG_ALIGN(lx_console.buffer.size); i += PG_SIZE) {
27         uintptr_t pa = pmm_alloc_page(KERNEL_PID, 0);
28         vmm_set_mapping(PD_REFERENCED,
29                         (uintptr_t)lx_console.buffer.data + i,
30                         pa,
31                         PG_PREM_URW,
32                         0);
33     }
34
35     memset(lx_console.buffer.data, 0, lx_console.buffer.size);
36
37     lx_console.flush_timer = NULL;
38
39     struct device* tty_dev = device_addseq(NULL, &lx_console, "tty");
40     tty_dev->write = __tty_write;
41 }
42
43 int
44 __tty_write(struct device* dev,
45             void* buf,
46             unsigned int offset,
47             unsigned int len)
48 {
49     struct console* console = (struct console*)dev->underlay;
50     console_write(console, buf, len);
51 }
52
53 void
54 console_schedule_flush()
55 {
56     // TODO make the flush on-demand rather than periodic
57 }
58
59 void
60 console_view_up()
61 {
62     struct fifo_buffer* buffer = &lx_console.buffer;
63     mutex_lock(&buffer->lock);
64     size_t p = lx_console.erd_pos - 2;
65     while (p < lx_console.erd_pos && p != buffer->wr_pos &&
66            ((char*)buffer->data)[p] != '\n') {
67         p--;
68     }
69     p++;
70
71     if (p > lx_console.erd_pos) {
72         p = 0;
73     }
74
75     buffer->flags |= FIFO_DIRTY;
76     lx_console.erd_pos = p;
77     mutex_unlock(&buffer->lock);
78 }
79
80 size_t
81 __find_next_line(size_t start)
82 {
83     size_t p = start;
84     while (p != lx_console.buffer.wr_pos &&
85            ((char*)lx_console.buffer.data)[p] != '\n') {
86         p = (p + 1) % lx_console.buffer.size;
87     }
88     return p + 1;
89 }
90
91 void
92 console_view_down()
93 {
94     struct fifo_buffer* buffer = &lx_console.buffer;
95     mutex_lock(&buffer->lock);
96
97     lx_console.erd_pos = __find_next_line(lx_console.erd_pos);
98     buffer->flags |= FIFO_DIRTY;
99     mutex_unlock(&buffer->lock);
100 }
101
102 void
103 console_flush()
104 {
105     if (mutex_on_hold(&lx_console.buffer.lock)) {
106         return;
107     }
108     if (!(lx_console.buffer.flags & FIFO_DIRTY)) {
109         return;
110     }
111
112     tty_flush_buffer(lx_console.buffer.data,
113                      lx_console.erd_pos,
114                      lx_console.buffer.wr_pos,
115                      lx_console.buffer.size);
116     lx_console.buffer.flags &= ~FIFO_DIRTY;
117 }
118
119 void
120 console_write(struct console* console, uint8_t* data, size_t size)
121 {
122     mutex_lock(&console->buffer.lock);
123     uint8_t* buffer = console->buffer.data;
124     uintptr_t ptr = console->buffer.wr_pos;
125     uintptr_t rd_ptr = console->buffer.rd_pos;
126
127     char c;
128     int lines = 0;
129     int j = 0;
130     for (size_t i = 0; i < size; i++) {
131         c = data[i];
132         if (!c) {
133             continue;
134         }
135         buffer[(ptr + j) % console->buffer.size] = c;
136         lines += (c == '\n');
137         j++;
138     }
139
140     size = j;
141
142     uintptr_t new_ptr = (ptr + size) % console->buffer.size;
143     console->buffer.wr_pos = new_ptr;
144
145     if (console->lines > TTY_HEIGHT && lines > 0) {
146         console->buffer.rd_pos =
147           __find_next_line((size + rd_ptr) % console->buffer.size);
148     }
149
150     if (new_ptr < ptr + size && new_ptr > rd_ptr) {
151         console->buffer.rd_pos = new_ptr;
152     }
153
154     console->lines += lines;
155     console->erd_pos = console->buffer.rd_pos;
156     console->buffer.flags |= FIFO_DIRTY;
157     mutex_unlock(&console->buffer.lock);
158 }
159
160 void
161 console_write_str(char* str)
162 {
163     console_write(&lx_console, str, strlen(str));
164 }
165
166 void
167 console_write_char(char str)
168 {
169     console_write(&lx_console, &str, 1);
170 }
171
172 void
173 console_start_flushing()
174 {
175     struct lx_timer* timer =
176       timer_run_ms(20, console_flush, NULL, TIMER_MODE_PERIODIC);
177     lx_console.flush_timer = timer;
178 }