Merge branch 'console-dev'
[lunaix-os.git] / lunaix-os / kernel / lxconsole.c
1 #include <klibc/string.h>
2 #include <lunaix/lxconsole.h>
3 #include <lunaix/mm/pmm.h>
4 #include <lunaix/mm/vmm.h>
5 #include <lunaix/tty/console.h>
6 #include <lunaix/tty/tty.h>
7
8 static struct console lx_console;
9
10 volatile int can_flush = 0;
11
12 void
13 lxconsole_init()
14 {
15     memset(&lx_console, 0, sizeof(lx_console));
16     lx_console.buffer.data = VGA_BUFFER_VADDR + 0x1000;
17     lx_console.buffer.size = 8192;
18     mutex_init(&lx_console.buffer.lock);
19
20     // 分配控制台缓存
21     for (size_t i = 0; i < PG_ALIGN(lx_console.buffer.size); i += PG_SIZE) {
22         uintptr_t pa = pmm_alloc_page(KERNEL_PID, 0);
23         vmm_set_mapping(PD_REFERENCED,
24                         (uintptr_t)lx_console.buffer.data + i,
25                         pa,
26                         PG_PREM_URW,
27                         0);
28     }
29
30     memset(lx_console.buffer.data, 0, lx_console.buffer.size);
31
32     lx_console.flush_timer = NULL;
33 }
34
35 void
36 console_schedule_flush()
37 {
38     // TODO make the flush on-demand rather than periodic
39 }
40
41 void
42 console_view_up(struct fifo_buffer* buffer)
43 {
44     // mutex_lock(&buffer->lock);
45     size_t p = buffer->rd_pos - 2;
46     while (p < buffer->rd_pos && p != buffer->wr_pos &&
47            ((char*)buffer->data)[p] != '\n') {
48         p--;
49     }
50     p++;
51
52     if (p < buffer->rd_pos) {
53         p = 0;
54     }
55
56     buffer->rd_pos = p;
57     // mutex_unlock(&buffer->lock);
58 }
59
60 void
61 console_view_down(struct fifo_buffer* buffer)
62 {
63     // mutex_lock(&buffer->lock);
64     size_t p = buffer->rd_pos;
65     while (p != buffer->wr_pos && ((char*)buffer->data)[p] != '\n') {
66         p = (p + 1) % buffer->size;
67     }
68
69     buffer->rd_pos = p + 1;
70     // mutex_unlock(&buffer->lock);
71 }
72
73 void
74 __flush_cb(void* arg)
75 {
76     if (mutex_on_hold(&lx_console.buffer.lock)) {
77         return;
78     }
79     if (!(lx_console.buffer.flags & FIFO_DIRTY)) {
80         return;
81     }
82
83     size_t pos = tty_flush_buffer(lx_console.buffer.data,
84                                   lx_console.buffer.rd_pos,
85                                   lx_console.buffer.wr_pos,
86                                   lx_console.buffer.size);
87     lx_console.flush_timer = NULL;
88     if (pos < lx_console.buffer.wr_pos) {
89         console_view_down(&lx_console.buffer);
90     } else {
91         // clear the dirty bit only if we have flush all the data
92         //  that means: read pointer == write pointer
93         lx_console.buffer.flags &= ~FIFO_DIRTY;
94     }
95 }
96
97 void
98 console_write(struct console* console, uint8_t* data, size_t size)
99 {
100     mutex_lock(&console->buffer.lock);
101     uint8_t* buffer = console->buffer.data;
102     uintptr_t ptr = console->buffer.wr_pos;
103     uintptr_t rd_ptr = console->buffer.rd_pos;
104
105     for (size_t i = 0; i < size; i++) {
106         buffer[(ptr + i) % console->buffer.size] = data[i];
107     }
108
109     uintptr_t new_ptr = (ptr + size) % console->buffer.size;
110     console->buffer.wr_pos = new_ptr;
111     if (new_ptr < ptr + size && new_ptr > rd_ptr) {
112         console->buffer.rd_pos = new_ptr;
113     }
114     console->buffer.flags |= FIFO_DIRTY;
115     mutex_unlock(&console->buffer.lock);
116 }
117
118 void
119 console_write_str(char* str)
120 {
121     console_write(&lx_console, str, strlen(str));
122 }
123
124 void
125 console_write_char(char str)
126 {
127     console_write(&lx_console, &str, 1);
128 }
129
130 void
131 console_start_flushing()
132 {
133     struct lx_timer* timer =
134       timer_run_ms(20, __flush_cb, NULL, TIMER_MODE_PERIODIC);
135     lx_console.flush_timer = timer;
136 }