:: limine / common / lib / term.c 9.5 KB raw

1
#include <stdint.h>
2
#include <stddef.h>
3
#include <stdbool.h>
4
#include <lib/term.h>
5
#include <lib/real.h>
6
#include <lib/misc.h>
7
#include <lib/fb.h>
8
#include <mm/pmm.h>
9
#include <mm/mtrr.h>
10
#include <mm/efi_pt.h>
11
#include <drivers/vga_textmode.h>
12
#include <flanterm_backends/fb.h>
13
14
#if defined (BIOS)
15
int current_video_mode = -1;
16
#endif
17
18
struct flanterm_context **terms = NULL;
19
size_t terms_i = 0;
20
21
int term_backend = _NOT_READY;
22
23
void term_notready(void) {
24
#if defined (__i386__) || defined (__x86_64__)
25
#if defined (__x86_64__) && defined (UEFI)
26
    efi_pt_restore();
27
#else
28
    mtrr_restore();
29
#endif
30
#endif
31
32
    for (size_t i = 0; i < terms_i; i++) {
33
        struct flanterm_context *term = terms[i];
34
35
        term->deinit(term, pmm_free_size_t);
36
    }
37
38
    pmm_free(terms, terms_i * sizeof(void *));
39
40
    terms_i = 0;
41
    terms = NULL;
42
43
    term_backend = _NOT_READY;
44
}
45
46
// --- fallback ---
47
48
#if defined (BIOS)
49
static void fallback_raw_putchar(struct flanterm_context *ctx, uint8_t c) {
50
    (void)ctx;
51
    struct rm_regs r = {0};
52
    r.eax = 0x0e00 | c;
53
    rm_int(0x10, &r, &r);
54
}
55
56
static void fallback_set_cursor_pos(struct flanterm_context *ctx, size_t x, size_t y);
57
static void fallback_get_cursor_pos(struct flanterm_context *ctx, size_t *x, size_t *y);
58
59
static void fallback_clear(struct flanterm_context *ctx, bool move) {
60
    (void)ctx;
61
    size_t x, y;
62
    fallback_get_cursor_pos(NULL, &x, &y);
63
    struct rm_regs r = {0};
64
    rm_int(0x11, &r, &r);
65
    switch ((r.eax >> 4) & 3) {
66
        case 0:
67
            r.eax = 3;
68
            break;
69
        case 1:
70
            r.eax = 1;
71
            break;
72
        case 2:
73
            r.eax = 3;
74
            break;
75
        case 3:
76
            r.eax = 7;
77
            break;
78
    }
79
    rm_int(0x10, &r, &r);
80
    if (move) {
81
        x = y = 0;
82
    }
83
    fallback_set_cursor_pos(NULL, x, y);
84
}
85
86
static void fallback_set_cursor_pos(struct flanterm_context *ctx, size_t x, size_t y) {
87
    (void)ctx;
88
    struct rm_regs r = {0};
89
    r.eax = 0x0200;
90
    r.ebx = 0;
91
    r.edx = (y << 8) + x;
92
    rm_int(0x10, &r, &r);
93
}
94
95
static void fallback_get_cursor_pos(struct flanterm_context *ctx, size_t *x, size_t *y) {
96
    (void)ctx;
97
    struct rm_regs r = {0};
98
    r.eax = 0x0300;
99
    r.ebx = 0;
100
    rm_int(0x10, &r, &r);
101
    *x = r.edx & 0xff;
102
    *y = r.edx >> 8;
103
}
104
105
static void fallback_scroll(struct flanterm_context *ctx) {
106
    (void)ctx;
107
    size_t x, y;
108
    fallback_get_cursor_pos(NULL, &x, &y);
109
    fallback_set_cursor_pos(NULL, ctx->cols - 1, ctx->rows - 1);
110
    fallback_raw_putchar(NULL, ' ');
111
    fallback_set_cursor_pos(NULL, x, y);
112
}
113
114
#elif defined (UEFI)
115
116
static size_t cursor_x = 0, cursor_y = 0;
117
118
static void fallback_scroll(struct flanterm_context *ctx) {
119
    (void)ctx;
120
    UINTN uefi_x_size, uefi_y_size;
121
    gST->ConOut->QueryMode(gST->ConOut, gST->ConOut->Mode->Mode, &uefi_x_size, &uefi_y_size);
122
    gST->ConOut->SetCursorPosition(gST->ConOut, uefi_x_size - 1, uefi_y_size - 1);
123
    CHAR16 string[2];
124
    string[0] = ' ';
125
    string[1] = 0;
126
    gST->ConOut->OutputString(gST->ConOut, string);
127
    gST->ConOut->SetCursorPosition(gST->ConOut, cursor_x, cursor_y);
128
}
129
130
static void fallback_raw_putchar(struct flanterm_context *ctx, uint8_t c) {
131
    if (!ctx->scroll_enabled && cursor_x == ctx->cols - 1 && cursor_y == ctx->rows - 1) {
132
        return;
133
    }
134
    gST->ConOut->EnableCursor(gST->ConOut, true);
135
    CHAR16 string[2];
136
    string[0] = c;
137
    string[1] = 0;
138
    gST->ConOut->OutputString(gST->ConOut, string);
139
    if (++cursor_x >= ctx->cols) {
140
        cursor_x = 0;
141
        if (++cursor_y >= ctx->rows) {
142
            cursor_y--;
143
        }
144
    }
145
    gST->ConOut->SetCursorPosition(gST->ConOut, cursor_x, cursor_y);
146
}
147
148
static void fallback_clear(struct flanterm_context *ctx, bool move) {
149
    (void)ctx;
150
    gST->ConOut->ClearScreen(gST->ConOut);
151
    if (move) {
152
        cursor_x = cursor_y = 0;
153
    }
154
    gST->ConOut->SetCursorPosition(gST->ConOut, cursor_x, cursor_y);
155
}
156
157
static void fallback_set_cursor_pos(struct flanterm_context *ctx, size_t x, size_t y) {
158
    (void)ctx;
159
    if (x >= ctx->cols || y >= ctx->rows) {
160
        return;
161
    }
162
    gST->ConOut->SetCursorPosition(gST->ConOut, x, y);
163
    cursor_x = x;
164
    cursor_y = y;
165
}
166
167
static void fallback_get_cursor_pos(struct flanterm_context *ctx, size_t *x, size_t *y) {
168
    (void)ctx;
169
    *x = cursor_x;
170
    *y = cursor_y;
171
}
172
173
static UINTN ansi_colours[] = {
174
    EFI_BLACK,
175
    EFI_RED,
176
    EFI_GREEN,
177
    EFI_YELLOW,
178
    EFI_BLUE,
179
    EFI_MAGENTA,
180
    EFI_CYAN,
181
    EFI_LIGHTGRAY
182
};
183
184
static UINTN conout_current_fg, conout_current_bg;
185
186
static void fallback_set_text_fg(struct flanterm_context *ctx, size_t fg) {
187
    (void)ctx;
188
    conout_current_fg = ansi_colours[fg];
189
    gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(conout_current_fg, conout_current_bg));
190
}
191
192
static void fallback_set_text_bg(struct flanterm_context *ctx, size_t bg) {
193
    (void)ctx;
194
    conout_current_bg = ansi_colours[bg];
195
    gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(conout_current_fg, conout_current_bg));
196
}
197
198
static void fallback_set_text_fg_bright(struct flanterm_context *ctx, size_t fg) {
199
    (void)ctx;
200
    conout_current_fg = ansi_colours[fg] | EFI_BRIGHT;
201
    gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(conout_current_fg, conout_current_bg));
202
}
203
204
static void fallback_set_text_bg_bright(struct flanterm_context *ctx, size_t bg) {
205
    (void)ctx;
206
    // bg does not support bright
207
    conout_current_bg = ansi_colours[bg];
208
    gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(conout_current_fg, conout_current_bg));
209
}
210
211
static void fallback_set_text_fg_default(struct flanterm_context *ctx) {
212
    (void)ctx;
213
    conout_current_fg = EFI_LIGHTGRAY;
214
    gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(conout_current_fg, conout_current_bg));
215
}
216
217
static void fallback_set_text_bg_default(struct flanterm_context *ctx) {
218
    (void)ctx;
219
    conout_current_bg = EFI_BLACK;
220
    gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(conout_current_fg, conout_current_bg));
221
}
222
223
static void fallback_swap_palette(struct flanterm_context *ctx) {
224
    (void)ctx;
225
    UINTN tmp = conout_current_bg;
226
    conout_current_bg = conout_current_fg;
227
    conout_current_fg = tmp;
228
    gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(conout_current_fg, conout_current_bg));
229
}
230
231
#endif
232
233
static bool dummy_handle(void) {
234
    return true;
235
}
236
237
void term_fallback(void) {
238
#if defined (UEFI)
239
    int prev_backend = term_backend;
240
#endif
241
242
    term_notready();
243
244
    terms = ext_mem_alloc(sizeof(void *));
245
    terms_i = 1;
246
247
    terms[0] = ext_mem_alloc(sizeof(struct flanterm_context));
248
249
    struct flanterm_context *term = terms[0];
250
251
#if defined (UEFI)
252
    if (!efi_boot_services_exited) {
253
        if (prev_backend != FALLBACK && prev_backend != _NOT_READY) {
254
            gST->ConOut->Reset(gST->ConOut, true);
255
        }
256
#endif
257
258
        // XXX: Ideally we clear the screen, but that gets rid of the BGRT boot logo
259
        // and is slow, so...
260
        //fallback_clear(NULL, true);
261
262
        term->set_text_fg = (void *)dummy_handle;
263
        term->set_text_bg = (void *)dummy_handle;
264
        term->set_text_fg_bright = (void *)dummy_handle;
265
        term->set_text_bg_bright = (void *)dummy_handle;
266
        term->set_text_fg_rgb = (void *)dummy_handle;
267
        term->set_text_bg_rgb = (void *)dummy_handle;
268
        term->set_text_fg_default = (void *)dummy_handle;
269
        term->set_text_bg_default = (void *)dummy_handle;
270
        term->move_character = (void *)dummy_handle;
271
        term->revscroll = (void *)dummy_handle;
272
        term->swap_palette = (void *)dummy_handle;
273
        term->save_state = (void *)dummy_handle;
274
        term->restore_state = (void *)dummy_handle;
275
        term->double_buffer_flush = (void *)dummy_handle;
276
        term->full_refresh = (void *)dummy_handle;
277
        term->deinit = (void *)dummy_handle;
278
279
        term->raw_putchar = fallback_raw_putchar;
280
        term->clear = fallback_clear;
281
        term->set_cursor_pos = fallback_set_cursor_pos;
282
        term->get_cursor_pos = fallback_get_cursor_pos;
283
        term->scroll = fallback_scroll;
284
        term->cols = 80;
285
        term->rows = 24;
286
        term_backend = FALLBACK;
287
        flanterm_context_reinit(term);
288
#if defined (UEFI)
289
290
        cursor_x = 0;
291
        cursor_y = 0;
292
        gST->ConOut->SetCursorPosition(gST->ConOut, 0, 0);
293
294
        term->set_text_fg = fallback_set_text_fg;
295
        term->set_text_bg = fallback_set_text_bg;
296
        term->set_text_fg_bright = fallback_set_text_fg_bright;
297
        term->set_text_bg_bright = fallback_set_text_bg_bright;
298
        term->set_text_fg_default = fallback_set_text_fg_default;
299
        term->set_text_bg_default = fallback_set_text_bg_default;
300
        term->swap_palette = fallback_swap_palette;
301
302
        term->set_text_fg_default(term);
303
        term->set_text_bg_default(term);
304
    } else {
305
        if (fb_fbs_count == 0) {
306
            goto fail;
307
        }
308
309
        terms[0] = flanterm_fb_init(ext_mem_alloc_size_t, pmm_free_size_t,
310
            (void *)(uintptr_t)fb_fbs[0].framebuffer_addr, fb_fbs[0].framebuffer_width,
311
            fb_fbs[0].framebuffer_height, fb_fbs[0].framebuffer_pitch,
312
            fb_fbs[0].red_mask_size, fb_fbs[0].red_mask_shift,
313
            fb_fbs[0].green_mask_size, fb_fbs[0].green_mask_shift,
314
            fb_fbs[0].blue_mask_size, fb_fbs[0].blue_mask_shift,
315
            NULL,
316
            NULL, NULL,
317
            NULL, NULL,
318
            NULL, NULL,
319
            NULL, 0, 0, 1,
320
            0, 0,
321
            0,
322
            FLANTERM_FB_ROTATE_0
323
        );
324
325
        flanterm_fb_set_flush_callback(terms[0], (void *)fb_flush);
326
    }
327
328
    return;
329
330
fail:
331
    pmm_free(terms[0], sizeof(struct flanterm_context));
332
    pmm_free(terms, sizeof(void *));
333
    terms_i = 0;
334
    terms = NULL;
335
#endif
336
}
tab: 248 wrap: offon