feat: implement rmdir(2), unlink(2), unlinkat(2)
[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_add(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     for (size_t i = 0; i < size; i++) {
130         c = data[i];
131         buffer[(ptr + i) % console->buffer.size] = c;
132         lines += (c == '\n');
133     }
134
135     uintptr_t new_ptr = (ptr + size) % console->buffer.size;
136     console->buffer.wr_pos = new_ptr;
137
138     if (console->lines > TTY_HEIGHT && lines > 0) {
139         console->buffer.rd_pos =
140           __find_next_line((size + rd_ptr) % console->buffer.size);
141     }
142
143     if (new_ptr < ptr + size && new_ptr > rd_ptr) {
144         console->buffer.rd_pos = new_ptr;
145     }
146
147     console->lines += lines;
148     console->erd_pos = console->buffer.rd_pos;
149     console->buffer.flags |= FIFO_DIRTY;
150     mutex_unlock(&console->buffer.lock);
151 }
152
153 void
154 console_write_str(char* str)
155 {
156     console_write(&lx_console, str, strlen(str));
157 }
158
159 void
160 console_write_char(char str)
161 {
162     console_write(&lx_console, &str, 1);
163 }
164
165 void
166 console_start_flushing()
167 {
168     struct lx_timer* timer =
169       timer_run_ms(20, console_flush, NULL, TIMER_MODE_PERIODIC);
170     lx_console.flush_timer = timer;
171 }