Merge branch 'master' into sata-ahci-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 void
11 lxconsole_init()
12 {
13     memset(&lx_console, 0, sizeof(lx_console));
14     lx_console.buffer.data = VGA_BUFFER_VADDR + 0x1000;
15     lx_console.buffer.size = 8192;
16     mutex_init(&lx_console.buffer.lock);
17
18     // 分配控制台缓存
19     for (size_t i = 0; i < PG_ALIGN(lx_console.buffer.size); i += PG_SIZE) {
20         uintptr_t pa = pmm_alloc_page(KERNEL_PID, 0);
21         vmm_set_mapping(PD_REFERENCED,
22                         (uintptr_t)lx_console.buffer.data + i,
23                         pa,
24                         PG_PREM_URW,
25                         0);
26     }
27
28     memset(lx_console.buffer.data, 0, lx_console.buffer.size);
29
30     lx_console.flush_timer = NULL;
31 }
32
33 void
34 console_schedule_flush()
35 {
36     // TODO make the flush on-demand rather than periodic
37 }
38
39 void
40 console_view_up()
41 {
42     struct fifo_buffer* buffer = &lx_console.buffer;
43     mutex_lock(&buffer->lock);
44     size_t p = lx_console.erd_pos - 2;
45     while (p < lx_console.erd_pos && p != buffer->wr_pos &&
46            ((char*)buffer->data)[p] != '\n') {
47         p--;
48     }
49     p++;
50
51     if (p > lx_console.erd_pos) {
52         p = 0;
53     }
54
55     buffer->flags |= FIFO_DIRTY;
56     lx_console.erd_pos = p;
57     mutex_unlock(&buffer->lock);
58 }
59
60 size_t
61 __find_next_line(size_t start)
62 {
63     size_t p = start;
64     while (p != lx_console.buffer.wr_pos &&
65            ((char*)lx_console.buffer.data)[p] != '\n') {
66         p = (p + 1) % lx_console.buffer.size;
67     }
68     return p + 1;
69 }
70
71 void
72 console_view_down()
73 {
74     struct fifo_buffer* buffer = &lx_console.buffer;
75     mutex_lock(&buffer->lock);
76
77     lx_console.erd_pos = __find_next_line(lx_console.erd_pos);
78     buffer->flags |= FIFO_DIRTY;
79     mutex_unlock(&buffer->lock);
80 }
81
82 void
83 console_flush()
84 {
85     if (mutex_on_hold(&lx_console.buffer.lock)) {
86         return;
87     }
88     if (!(lx_console.buffer.flags & FIFO_DIRTY)) {
89         return;
90     }
91
92     tty_flush_buffer(lx_console.buffer.data,
93                      lx_console.erd_pos,
94                      lx_console.buffer.wr_pos,
95                      lx_console.buffer.size);
96     lx_console.buffer.flags &= ~FIFO_DIRTY;
97 }
98
99 void
100 console_write(struct console* console, uint8_t* data, size_t size)
101 {
102     mutex_lock(&console->buffer.lock);
103     uint8_t* buffer = console->buffer.data;
104     uintptr_t ptr = console->buffer.wr_pos;
105     uintptr_t rd_ptr = console->buffer.rd_pos;
106
107     char c;
108     int lines = 0;
109     for (size_t i = 0; i < size; i++) {
110         c = data[i];
111         buffer[(ptr + i) % console->buffer.size] = c;
112         lines += (c == '\n');
113     }
114
115     uintptr_t new_ptr = (ptr + size) % console->buffer.size;
116     console->buffer.wr_pos = new_ptr;
117
118     if (console->lines > TTY_HEIGHT && lines > 0) {
119         console->buffer.rd_pos =
120           __find_next_line((size + rd_ptr) % console->buffer.size);
121     }
122
123     if (new_ptr < ptr + size && new_ptr > rd_ptr) {
124         console->buffer.rd_pos = new_ptr;
125     }
126
127     console->lines += lines;
128     console->erd_pos = console->buffer.rd_pos;
129     console->buffer.flags |= FIFO_DIRTY;
130     mutex_unlock(&console->buffer.lock);
131 }
132
133 void
134 console_write_str(char* str)
135 {
136     console_write(&lx_console, str, strlen(str));
137 }
138
139 void
140 console_write_char(char str)
141 {
142     console_write(&lx_console, &str, 1);
143 }
144
145 void
146 console_start_flushing()
147 {
148     struct lx_timer* timer =
149       timer_run_ms(20, console_flush, NULL, TIMER_MODE_PERIODIC);
150     lx_console.flush_timer = timer;
151 }