limine: Add support for multiple terminals and properly document it
This commit is contained in:
parent
15f111f5c3
commit
fb175747df
191
PROTOCOL.md
191
PROTOCOL.md
|
@ -19,6 +19,8 @@ languages.
|
||||||
All pointers are 64-bit wide. All pointers point to the object with the
|
All pointers are 64-bit wide. All pointers point to the object with the
|
||||||
higher half direct map offset already added to them, unless otherwise noted.
|
higher half direct map offset already added to them, unless otherwise noted.
|
||||||
|
|
||||||
|
The calling convention matches the SysV C ABI for the specific architecture.
|
||||||
|
|
||||||
### Executable formats
|
### Executable formats
|
||||||
|
|
||||||
The Limine protocol does not enforce any specific executable format, but
|
The Limine protocol does not enforce any specific executable format, but
|
||||||
|
@ -306,7 +308,7 @@ ID:
|
||||||
|
|
||||||
Request:
|
Request:
|
||||||
```c
|
```c
|
||||||
typedef void (*limine_terminal_callback)(uint64_t, uint64_t, uint64_t, uint64_t);
|
typedef void (*limine_terminal_callback)(struct limine_terminal *, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||||
|
|
||||||
struct limine_terminal_request {
|
struct limine_terminal_request {
|
||||||
uint64_t id[4];
|
uint64_t id[4];
|
||||||
|
@ -320,22 +322,201 @@ struct limine_terminal_request {
|
||||||
|
|
||||||
Response:
|
Response:
|
||||||
```c
|
```c
|
||||||
typedef void (*limine_terminal_write)(const char *, uint64_t);
|
|
||||||
|
|
||||||
struct limine_terminal_response {
|
struct limine_terminal_response {
|
||||||
uint64_t revision;
|
uint64_t revision;
|
||||||
|
uint64_t terminal_count;
|
||||||
|
struct limine_terminal **terminals;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
* `terminal_count` - How many terminals are present.
|
||||||
|
* `terminals` - Pointer to an array of `terminal_count` pointers to
|
||||||
|
`struct limine_terminal` structures.
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef void (*limine_terminal_write)(const char *, uint64_t);
|
||||||
|
|
||||||
|
struct limine_terminal {
|
||||||
uint32_t columns;
|
uint32_t columns;
|
||||||
uint32_t rows;
|
uint32_t rows;
|
||||||
|
struct limine_framebuffer *framebuffer;
|
||||||
limine_terminal_write write;
|
limine_terminal_write write;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* `columns` and `rows` - Columns and rows provided by the terminal.
|
* `columns` and `rows` - Columns and rows provided by the terminal.
|
||||||
|
* `framebuffer` - The framebuffer associated with this terminal.
|
||||||
* `write` - Physical pointer to the terminal write() function.
|
* `write` - Physical pointer to the terminal write() function.
|
||||||
|
The function is not thread-safe, nor reentrant, per-terminal.
|
||||||
|
This means multiple terminals may be called simultaneously, and multiple
|
||||||
|
callbacks may be handled simultaneously.
|
||||||
|
|
||||||
Note: Omitting this request will cause the bootloader to not initialise
|
Note: Omitting this request will cause the bootloader to not initialise
|
||||||
the terminal service. The terminal is further documented in the stivale2
|
the terminal service.
|
||||||
specification.
|
|
||||||
|
#### Terminal callback
|
||||||
|
|
||||||
|
The callback is a function that is part of the kernel, which is called by the
|
||||||
|
terminal during a `write()` call whenever an event or escape sequence cannot
|
||||||
|
be handled by the bootloader's terminal alone, and the kernel may want to be
|
||||||
|
notified in order to handle it itself.
|
||||||
|
|
||||||
|
Returning from the callback will resume the `write()` call which will return
|
||||||
|
to its caller normally.
|
||||||
|
|
||||||
|
Not returning from a callback may leave the terminal in an undefined state
|
||||||
|
and cause issues.
|
||||||
|
|
||||||
|
The callback function has the following prototype:
|
||||||
|
```c
|
||||||
|
void callback(struct limine_terminal *terminal, uint64_t type, uint64_t, uint64_t, uint64_t);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `terminal` argument is a pointer to the Limine terminal structure which
|
||||||
|
has the `write()` call that caused the callback.
|
||||||
|
|
||||||
|
The purpose of the last 3 arguments changes depending on the `type` argument.
|
||||||
|
|
||||||
|
The callback types are as follows:
|
||||||
|
|
||||||
|
* `LIMINE_TERMINAL_CB_DEC` - (type value: `10`)
|
||||||
|
|
||||||
|
This callback is triggered whenever a DEC Private Mode (DECSET/DECRST)
|
||||||
|
sequence is encountered that the terminal cannot handle alone. The arguments
|
||||||
|
to this callback are: `terminal`, `type`, `values_count`, `values`, `final`.
|
||||||
|
|
||||||
|
`values_count` is a count of how many values are in the array pointed to by
|
||||||
|
`values`. `values` is a pointer to an array of `uint32_t` values, which are
|
||||||
|
the values passed to the DEC private escape.
|
||||||
|
`final` is the final character in the DEC private escape sequence (typically
|
||||||
|
`l` or `h`).
|
||||||
|
|
||||||
|
* `LIMINE_TERMINAL_CB_BELL` - (type value: `20`)
|
||||||
|
|
||||||
|
This callback is triggered whenever a bell event is determined to be
|
||||||
|
necessary (such as when a bell character `\a` is encountered). The arguments
|
||||||
|
to this callback are: `terminal`, `type`, `unused1`, `unused2`, `unused3`.
|
||||||
|
|
||||||
|
* `LIMINE_TERMINAL_CB_PRIVATE_ID` - (type value: `30`)
|
||||||
|
|
||||||
|
This callback is triggered whenever the kernel has to respond to a DEC
|
||||||
|
private identification request. The arguments to this callback are:
|
||||||
|
`terminal`, `type`, `unused1`, `unused2`, `unused3`.
|
||||||
|
|
||||||
|
* `LIMINE_TERMINAL_CB_STATUS_REPORT` - (type value `40`)
|
||||||
|
|
||||||
|
This callback is triggered whenever the kernel has to respond to a ECMA-48
|
||||||
|
status report request. The arguments to this callback are: `terminal`,
|
||||||
|
`type`, `unused1`, `unused2`, `unused3`.
|
||||||
|
|
||||||
|
* `LIMINE_TERMINAL_CB_POS_REPORT` - (type value `50`)
|
||||||
|
|
||||||
|
This callback is triggered whenever the kernel has to respond to a ECMA-48
|
||||||
|
cursor position report request. The arguments to this callback are:
|
||||||
|
`terminal`, `type`, `x`, `y`, `unused3`. Where `x` and `y` represent the
|
||||||
|
cursor position at the time the callback is triggered.
|
||||||
|
|
||||||
|
* `LIMINE_TERMINAL_CB_KBD_LEDS` - (type value `60`)
|
||||||
|
|
||||||
|
This callback is triggered whenever the kernel has to respond to a keyboard
|
||||||
|
LED state change request. The arguments to this callback are: `terminal`,
|
||||||
|
`type`, `led_state`, `unused2`, `unused3`. `led_state` can have one of the
|
||||||
|
following values: `0, 1, 2, or 3`. These values mean: clear all LEDs, set
|
||||||
|
scroll lock, set num lock, and set caps lock LED, respectively.
|
||||||
|
|
||||||
|
* `LIMINE_TERMINAL_CB_MODE` - (type value: `70`)
|
||||||
|
|
||||||
|
This callback is triggered whenever an ECMA-48 Mode Switch sequence
|
||||||
|
is encountered that the terminal cannot handle alone. The arguments to this
|
||||||
|
callback are: `terminal`, `type`, `values_count`, `values`, `final`.
|
||||||
|
|
||||||
|
`values_count` is a count of how many values are in the array pointed to by
|
||||||
|
`values`. `values` is a pointer to an array of `uint32_t` values, which are
|
||||||
|
the values passed to the mode switch escape.
|
||||||
|
`final` is the final character in the mode switch escape sequence (typically
|
||||||
|
`l` or `h`).
|
||||||
|
|
||||||
|
* `LIMINE_TERMINAL_CB_LINUX` - (type value `80`)
|
||||||
|
|
||||||
|
This callback is triggered whenever a private Linux escape sequence
|
||||||
|
is encountered that the terminal cannot handle alone. The arguments to this
|
||||||
|
callback are: `terminal`, `type`, `values_count`, `values`, `unused3`.
|
||||||
|
|
||||||
|
`values_count` is a count of how many values are in the array pointed to by
|
||||||
|
`values`. `values` is a pointer to an array of `uint32_t` values, which are
|
||||||
|
the values passed to the Linux private escape.
|
||||||
|
|
||||||
|
#### Terminal context control
|
||||||
|
|
||||||
|
The `write()` function can additionally be used to set and restore terminal
|
||||||
|
context, and refresh the terminal fully.
|
||||||
|
|
||||||
|
In order to achieve this, special values for the `length` argument are
|
||||||
|
passed. These values are:
|
||||||
|
```c
|
||||||
|
#define LIMINE_TERMINAL_CTX_SIZE ((uint64_t)(-1))
|
||||||
|
#define LIMINE_TERMINAL_CTX_SAVE ((uint64_t)(-2))
|
||||||
|
#define LIMINE_TERMINAL_CTX_RESTORE ((uint64_t)(-3))
|
||||||
|
#define LIMINE_TERMINAL_FULL_REFRESH ((uint64_t)(-4))
|
||||||
|
```
|
||||||
|
|
||||||
|
For `CTX_SIZE`, the `ptr` variable has to point to a location to which the
|
||||||
|
terminal will *write* a single `uint64_t` which contains the size of the
|
||||||
|
terminal context.
|
||||||
|
|
||||||
|
For `CTX_SAVE` and `CTX_RESTORE`, the `ptr` variable has to point to a
|
||||||
|
location to which the terminal will *save* or *restore* its context from,
|
||||||
|
respectively.
|
||||||
|
This location must have a size congruent to the value received from
|
||||||
|
`CTX_SIZE`.
|
||||||
|
|
||||||
|
For `FULL_REFRESH`, the `ptr` variable is unused. This routine is to be used
|
||||||
|
after control of the framebuffer is taken over and the bootloader's terminal
|
||||||
|
has to *fully* repaint the framebuffer to avoid inconsistencies.
|
||||||
|
|
||||||
|
#### x86_64
|
||||||
|
|
||||||
|
Additionally, the kernel must ensure, when calling `write()`, that:
|
||||||
|
|
||||||
|
* Either the GDT provided by the bootloader is still properly loaded, or a
|
||||||
|
custom GDT is loaded with at least the following descriptors in this specific
|
||||||
|
order:
|
||||||
|
|
||||||
|
- Null descriptor
|
||||||
|
- 16-bit code descriptor. Base = `0`, limit = `0xffff`. Readable.
|
||||||
|
- 16-bit data descriptor. Base = `0`, limit = `0xffff`. Writable.
|
||||||
|
- 32-bit code descriptor. Base = `0`, limit = `0xffffffff`. Readable.
|
||||||
|
- 32-bit data descriptor. Base = `0`, limit = `0xffffffff`. Writable.
|
||||||
|
- 64-bit code descriptor. Base and limit irrelevant. Readable.
|
||||||
|
- 64-bit data descriptor. Base and limit irrelevant. Writable.
|
||||||
|
|
||||||
|
* The currently loaded virtual address space is still the one provided at
|
||||||
|
entry by the bootloader, or a custom virtual address space is loaded which
|
||||||
|
identity maps the framebuffer memory region associated with the terminal, and
|
||||||
|
all the bootloader reclaimable memory regions, with read, write, and execute
|
||||||
|
permissions.
|
||||||
|
|
||||||
|
* The routine is called *by its physical address* (the value of the function
|
||||||
|
pointer is already physical), which should be identity mapped.
|
||||||
|
|
||||||
|
* Bootloader-reclaimable memory entries are left untouched until after the
|
||||||
|
kernel is done utilising bootloader-provided facilities (this terminal being
|
||||||
|
one of them).
|
||||||
|
|
||||||
|
Notes regarding segment registers and FPU:
|
||||||
|
|
||||||
|
The values of the FS and GS segments are guaranteed preserved across the
|
||||||
|
call. All other segment registers may have their "hidden" portion
|
||||||
|
overwritten, but Limine guarantees that the "visible" portion is going to
|
||||||
|
be restored to the one used at the time of call before returning.
|
||||||
|
|
||||||
|
No registers other than the segment registers and general purpose registers
|
||||||
|
are going to be used. Especially, this means that there is no need to save
|
||||||
|
and restore FPU, SSE, or AVX state when calling the terminal write function.
|
||||||
|
|
||||||
|
#### Terminal characteristics
|
||||||
|
|
||||||
|
The terminal should strive for Linux console compatibility.
|
||||||
|
|
||||||
### Framebuffer Feature
|
### Framebuffer Feature
|
||||||
|
|
||||||
|
|
|
@ -292,7 +292,8 @@ void (*term_context_save)(uint64_t ptr);
|
||||||
void (*term_context_restore)(uint64_t ptr);
|
void (*term_context_restore)(uint64_t ptr);
|
||||||
void (*term_full_refresh)(void);
|
void (*term_full_refresh)(void);
|
||||||
|
|
||||||
void (*term_callback)(uint64_t, uint64_t, uint64_t, uint64_t) = NULL;
|
uint64_t term_arg = 0;
|
||||||
|
void (*term_callback)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t) = NULL;
|
||||||
|
|
||||||
struct term_context term_context;
|
struct term_context term_context;
|
||||||
|
|
||||||
|
@ -669,7 +670,11 @@ static void dec_private_parse(uint8_t c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (term_callback != NULL) {
|
if (term_callback != NULL) {
|
||||||
term_callback(TERM_CB_DEC, esc_values_i, (uintptr_t)esc_values, c);
|
if (term_arg != 0) {
|
||||||
|
term_callback(term_arg, TERM_CB_DEC, esc_values_i, (uintptr_t)esc_values, c);
|
||||||
|
} else {
|
||||||
|
term_callback(TERM_CB_DEC, esc_values_i, (uintptr_t)esc_values, c, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,7 +684,11 @@ static void linux_private_parse(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (term_callback != NULL) {
|
if (term_callback != NULL) {
|
||||||
term_callback(TERM_CB_LINUX, esc_values_i, (uintptr_t)esc_values, 0);
|
if (term_arg != 0) {
|
||||||
|
term_callback(term_arg, TERM_CB_LINUX, esc_values_i, (uintptr_t)esc_values, 0);
|
||||||
|
} else {
|
||||||
|
term_callback(TERM_CB_LINUX, esc_values_i, (uintptr_t)esc_values, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,7 +714,11 @@ static void mode_toggle(uint8_t c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (term_callback != NULL) {
|
if (term_callback != NULL) {
|
||||||
term_callback(TERM_CB_MODE, esc_values_i, (uintptr_t)esc_values, c);
|
if (term_arg != 0) {
|
||||||
|
term_callback(term_arg, TERM_CB_MODE, esc_values_i, (uintptr_t)esc_values, c);
|
||||||
|
} else {
|
||||||
|
term_callback(TERM_CB_MODE, esc_values_i, (uintptr_t)esc_values, c, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -819,7 +832,11 @@ static void control_sequence_parse(uint8_t c) {
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
if (term_callback != NULL) {
|
if (term_callback != NULL) {
|
||||||
term_callback(TERM_CB_PRIVATE_ID, 0, 0, 0);
|
if (term_arg != 0) {
|
||||||
|
term_callback(term_arg, TERM_CB_PRIVATE_ID, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
term_callback(TERM_CB_PRIVATE_ID, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
|
@ -849,19 +866,31 @@ static void control_sequence_parse(uint8_t c) {
|
||||||
switch (esc_values[0]) {
|
switch (esc_values[0]) {
|
||||||
case 5:
|
case 5:
|
||||||
if (term_callback != NULL) {
|
if (term_callback != NULL) {
|
||||||
term_callback(TERM_CB_STATUS_REPORT, 0, 0, 0);
|
if (term_arg != 0) {
|
||||||
|
term_callback(term_arg, TERM_CB_STATUS_REPORT, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
term_callback(TERM_CB_STATUS_REPORT, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
if (term_callback != NULL) {
|
if (term_callback != NULL) {
|
||||||
term_callback(TERM_CB_POS_REPORT, x + 1, y + 1, 0);
|
if (term_arg != 0) {
|
||||||
|
term_callback(term_arg, TERM_CB_POS_REPORT, x + 1, y + 1, 0);
|
||||||
|
} else {
|
||||||
|
term_callback(TERM_CB_POS_REPORT, x + 1, y + 1, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
if (term_callback != NULL) {
|
if (term_callback != NULL) {
|
||||||
term_callback(TERM_CB_KBD_LEDS, esc_values[0], 0, 0);
|
if (term_arg != 0) {
|
||||||
|
term_callback(term_arg, TERM_CB_KBD_LEDS, esc_values[0], 0, 0);
|
||||||
|
} else {
|
||||||
|
term_callback(TERM_CB_KBD_LEDS, esc_values[0], 0, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'J':
|
case 'J':
|
||||||
|
@ -1066,7 +1095,11 @@ is_csi:
|
||||||
break;
|
break;
|
||||||
case 'Z':
|
case 'Z':
|
||||||
if (term_callback != NULL) {
|
if (term_callback != NULL) {
|
||||||
term_callback(TERM_CB_PRIVATE_ID, 0, 0, 0);
|
if (term_arg != 0) {
|
||||||
|
term_callback(term_arg, TERM_CB_PRIVATE_ID, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
term_callback(TERM_CB_PRIVATE_ID, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '(':
|
case '(':
|
||||||
|
@ -1185,7 +1218,11 @@ void term_putchar(uint8_t c) {
|
||||||
case '\a':
|
case '\a':
|
||||||
// The bell is handled by the kernel
|
// The bell is handled by the kernel
|
||||||
if (term_callback != NULL) {
|
if (term_callback != NULL) {
|
||||||
term_callback(TERM_CB_BELL, 0, 0, 0);
|
if (term_arg != 0) {
|
||||||
|
term_callback(term_arg, TERM_CB_BELL, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
term_callback(TERM_CB_BELL, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case 14:
|
case 14:
|
||||||
|
|
|
@ -103,7 +103,8 @@ extern void (*term_full_refresh)(void);
|
||||||
#define TERM_CTX_RESTORE ((uint64_t)(-3))
|
#define TERM_CTX_RESTORE ((uint64_t)(-3))
|
||||||
#define TERM_FULL_REFRESH ((uint64_t)(-4))
|
#define TERM_FULL_REFRESH ((uint64_t)(-4))
|
||||||
|
|
||||||
extern void (*term_callback)(uint64_t, uint64_t, uint64_t, uint64_t);
|
extern uint64_t term_arg;
|
||||||
|
extern void (*term_callback)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||||
|
|
||||||
extern bool term_autoflush;
|
extern bool term_autoflush;
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ static void *_get_request(uint64_t id[4]) {
|
||||||
extern symbol stivale2_term_write_entry;
|
extern symbol stivale2_term_write_entry;
|
||||||
extern void *stivale2_rt_stack;
|
extern void *stivale2_rt_stack;
|
||||||
extern uint64_t stivale2_term_callback_ptr;
|
extern uint64_t stivale2_term_callback_ptr;
|
||||||
void stivale2_term_callback(uint64_t, uint64_t, uint64_t, uint64_t);
|
void stivale2_term_callback(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool limine_load(char *config, char *cmdline) {
|
bool limine_load(char *config, char *cmdline) {
|
||||||
|
@ -552,6 +552,7 @@ FEAT_END
|
||||||
struct fb_info fb;
|
struct fb_info fb;
|
||||||
|
|
||||||
// Terminal feature
|
// Terminal feature
|
||||||
|
uint64_t *term_fb_ptr = NULL;
|
||||||
FEAT_START
|
FEAT_START
|
||||||
struct limine_terminal_request *terminal_request = get_request(LIMINE_TERMINAL_REQUEST);
|
struct limine_terminal_request *terminal_request = get_request(LIMINE_TERMINAL_REQUEST);
|
||||||
if (terminal_request == NULL) {
|
if (terminal_request == NULL) {
|
||||||
|
@ -561,6 +562,8 @@ FEAT_START
|
||||||
struct limine_terminal_response *terminal_response =
|
struct limine_terminal_response *terminal_response =
|
||||||
ext_mem_alloc(sizeof(struct limine_terminal_response));
|
ext_mem_alloc(sizeof(struct limine_terminal_response));
|
||||||
|
|
||||||
|
struct limine_terminal *terminal = ext_mem_alloc(sizeof(struct limine_terminal));
|
||||||
|
|
||||||
quiet = false;
|
quiet = false;
|
||||||
serial = false;
|
serial = false;
|
||||||
|
|
||||||
|
@ -579,18 +582,28 @@ FEAT_START
|
||||||
term_callback = (void *)terminal_request->callback;
|
term_callback = (void *)terminal_request->callback;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
term_arg = reported_addr(terminal);
|
||||||
|
|
||||||
#if defined (__i386__)
|
#if defined (__i386__)
|
||||||
if (stivale2_rt_stack == NULL) {
|
if (stivale2_rt_stack == NULL) {
|
||||||
stivale2_rt_stack = ext_mem_alloc(16384) + 16384;
|
stivale2_rt_stack = ext_mem_alloc(16384) + 16384;
|
||||||
}
|
}
|
||||||
|
|
||||||
terminal_response->write = (uintptr_t)(void *)stivale2_term_write_entry;
|
terminal->write = (uintptr_t)(void *)stivale2_term_write_entry;
|
||||||
#elif defined (__x86_64__)
|
#elif defined (__x86_64__)
|
||||||
terminal_response->write = (uintptr_t)term_write;
|
terminal->write = (uintptr_t)term_write;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
terminal_response->columns = term_cols;
|
term_fb_ptr = &terminal->framebuffer;
|
||||||
terminal_response->rows = term_rows;
|
|
||||||
|
terminal->columns = term_cols;
|
||||||
|
terminal->rows = term_rows;
|
||||||
|
|
||||||
|
uint64_t *term_list = ext_mem_alloc(1 * sizeof(uint64_t));
|
||||||
|
term_list[0] = reported_addr(terminal);
|
||||||
|
|
||||||
|
terminal_response->terminal_count = 1;
|
||||||
|
terminal_response->terminals = reported_addr(term_list);
|
||||||
|
|
||||||
terminal_request->response = reported_addr(terminal_response);
|
terminal_request->response = reported_addr(terminal_response);
|
||||||
|
|
||||||
|
@ -621,6 +634,10 @@ skip_fb_init:;
|
||||||
// For now we only support 1 framebuffer
|
// For now we only support 1 framebuffer
|
||||||
struct limine_framebuffer *fbp = ext_mem_alloc(sizeof(struct limine_framebuffer));
|
struct limine_framebuffer *fbp = ext_mem_alloc(sizeof(struct limine_framebuffer));
|
||||||
|
|
||||||
|
if (term_fb_ptr != NULL) {
|
||||||
|
*term_fb_ptr = reported_addr(fbp);
|
||||||
|
}
|
||||||
|
|
||||||
struct edid_info_struct *edid_info = get_edid_info();
|
struct edid_info_struct *edid_info = get_edid_info();
|
||||||
if (edid_info != NULL) {
|
if (edid_info != NULL) {
|
||||||
fbp->edid_size = sizeof(struct edid_info_struct);
|
fbp->edid_size = sizeof(struct edid_info_struct);
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
extern symbol stivale2_term_write_entry;
|
extern symbol stivale2_term_write_entry;
|
||||||
void *stivale2_rt_stack = NULL;
|
void *stivale2_rt_stack = NULL;
|
||||||
uint64_t stivale2_term_callback_ptr = 0;
|
uint64_t stivale2_term_callback_ptr = 0;
|
||||||
void stivale2_term_callback(uint64_t, uint64_t, uint64_t, uint64_t);
|
void stivale2_term_callback(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool stivale2_load(char *config, char *cmdline) {
|
bool stivale2_load(char *config, char *cmdline) {
|
||||||
|
|
|
@ -43,6 +43,7 @@ bits 64
|
||||||
mov rsi, [rbp + 16]
|
mov rsi, [rbp + 16]
|
||||||
mov rdx, [rbp + 24]
|
mov rdx, [rbp + 24]
|
||||||
mov rcx, [rbp + 32]
|
mov rcx, [rbp + 32]
|
||||||
|
mov r8, [rbp + 40]
|
||||||
|
|
||||||
call .get_got
|
call .get_got
|
||||||
.get_got:
|
.get_got:
|
||||||
|
|
|
@ -39,6 +39,7 @@ bits 64
|
||||||
mov rsi, [rbp + 16]
|
mov rsi, [rbp + 16]
|
||||||
mov rdx, [rbp + 24]
|
mov rdx, [rbp + 24]
|
||||||
mov rcx, [rbp + 32]
|
mov rcx, [rbp + 32]
|
||||||
|
mov r8, [rbp + 40]
|
||||||
|
|
||||||
mov rbx, rsp
|
mov rbx, rsp
|
||||||
mov rsp, [user_stack]
|
mov rsp, [user_stack]
|
||||||
|
|
16
limine.h
16
limine.h
|
@ -169,14 +169,22 @@ struct limine_framebuffer_request {
|
||||||
#define LIMINE_TERMINAL_CTX_RESTORE ((uint64_t)(-3))
|
#define LIMINE_TERMINAL_CTX_RESTORE ((uint64_t)(-3))
|
||||||
#define LIMINE_TERMINAL_FULL_REFRESH ((uint64_t)(-4))
|
#define LIMINE_TERMINAL_FULL_REFRESH ((uint64_t)(-4))
|
||||||
|
|
||||||
|
struct limine_terminal;
|
||||||
|
|
||||||
typedef void (*limine_terminal_write)(const char *, uint64_t);
|
typedef void (*limine_terminal_write)(const char *, uint64_t);
|
||||||
typedef void (*limine_terminal_callback)(uint64_t, uint64_t, uint64_t, uint64_t);
|
typedef void (*limine_terminal_callback)(struct limine_terminal *, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||||
|
|
||||||
|
struct limine_terminal {
|
||||||
|
uint32_t columns;
|
||||||
|
uint32_t rows;
|
||||||
|
LIMINE_PTR(struct limine_framebuffer *) framebuffer;
|
||||||
|
LIMINE_PTR(limine_terminal_write) write;
|
||||||
|
};
|
||||||
|
|
||||||
struct limine_terminal_response {
|
struct limine_terminal_response {
|
||||||
uint64_t revision;
|
uint64_t revision;
|
||||||
uint32_t columns;
|
uint64_t terminal_count;
|
||||||
uint32_t rows;
|
LIMINE_PTR(struct limine_terminal **) terminals;
|
||||||
LIMINE_PTR(limine_terminal_write) write;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct limine_terminal_request {
|
struct limine_terminal_request {
|
||||||
|
|
|
@ -138,7 +138,7 @@ extern char kernel_start[];
|
||||||
|
|
||||||
static void limine_main(void) {
|
static void limine_main(void) {
|
||||||
if (_terminal_request.response) {
|
if (_terminal_request.response) {
|
||||||
stivale2_print = _terminal_request.response->write;
|
stivale2_print = _terminal_request.response->terminals[0]->write;
|
||||||
}
|
}
|
||||||
|
|
||||||
e9_printf("\nWe're alive");
|
e9_printf("\nWe're alive");
|
||||||
|
@ -323,9 +323,14 @@ FEAT_START
|
||||||
}
|
}
|
||||||
struct limine_terminal_response *term_response = _terminal_request.response;
|
struct limine_terminal_response *term_response = _terminal_request.response;
|
||||||
e9_printf("Terminal feature, revision %d", term_response->revision);
|
e9_printf("Terminal feature, revision %d", term_response->revision);
|
||||||
e9_printf("Columns: %d", term_response->columns);
|
e9_printf("%d terminal(s)", term_response->terminal_count);
|
||||||
e9_printf("Rows: %d", term_response->rows);
|
for (size_t i = 0; i < term_response->terminal_count; i++) {
|
||||||
e9_printf("Write function at: %x", term_response->write);
|
struct limine_terminal *terminal = term_response->terminals[i];
|
||||||
|
e9_printf("Columns: %d", terminal->columns);
|
||||||
|
e9_printf("Rows: %d", terminal->rows);
|
||||||
|
e9_printf("Using framebuffer: %x", terminal->framebuffer);
|
||||||
|
e9_printf("Write function at: %x", terminal->write);
|
||||||
|
}
|
||||||
FEAT_END
|
FEAT_END
|
||||||
|
|
||||||
for (;;);
|
for (;;);
|
||||||
|
|
Loading…
Reference in New Issue