Cleanup the terminal system

This commit is contained in:
Baptiste Wicht 2016-09-24 19:45:58 +02:00
parent 565c364f6f
commit 321c6dcf5d
9 changed files with 307 additions and 124 deletions

View File

@ -16,30 +16,68 @@
namespace stdio {
/*!
* \brief Init the console
*/
void init_console();
/*!
* \brief A console
*/
struct console {
/*!
* \brief Init the console
*/
void init();
size_t get_columns() const ;
size_t get_rows() const ;
/*!
* \brief Returns the number of columns of the console
*/
size_t get_columns() const;
/*!
* \brief Returns the number of rows of the console
*/
size_t get_rows() const;
/*!
* \brief Print the given char to the console
* \param c The character to print
*/
void print(char c);
/*!
* \brief Clear the console
*/
void wipeout();
/*!
* \brief Set the active status of the console
* \param active The active status of the console
*/
void set_active(bool active);
/*!
* \brief Save the state of the console
*/
void save();
/*!
* \brief Restore the state of the console
*/
void restore();
private:
/*!
* \brief Move to the next line
*/
void next_line();
size_t current_line = 0;
size_t current_column = 0;
size_t current_line = 0; ///< The current line of the console
size_t current_column = 0; ///< The current column of the console
void* buffer = nullptr;
bool active = false;
void* buffer = nullptr; ///< The buffer to save the state
bool active = false; ///< The active status of the console
};
} // end of namespace stdio

View File

@ -14,14 +14,40 @@
namespace stdio {
/*!
* \brief Initialize the terminals
*/
void init_terminals();
/*!
* \brief Register the devices into the devfs
*/
void register_devices();
/*!
* \brief Finalize the terminals
*/
void finalize();
/*!
* \brief Switch the active terminal to the terminal with the given id
* \param id The terminal to activate
*/
void switch_terminal(size_t id);
/*!
* \brief Returns the number of terminals
*/
size_t terminals_count();
/*!
* \brief Returns the active terminal
*/
virtual_terminal& get_active_terminal();
/*!
* \brief Returns the terminal with the given id
*/
virtual_terminal& get_terminal(size_t id);
} //end of namespace stdio

View File

@ -23,7 +23,13 @@ namespace stdio {
constexpr const size_t INPUT_BUFFER_SIZE = 256;
/*!
* \brief A virtual terminal
*/
struct virtual_terminal {
/*!
* \brief Construct a new virtual_terminal
*/
virtual_terminal(){}
virtual_terminal(const virtual_terminal& rhs) = delete;
@ -32,6 +38,10 @@ struct virtual_terminal {
virtual_terminal(virtual_terminal&& rhs) = delete;
virtual_terminal& operator=(virtual_terminal&& rhs) = delete;
/*!
* \brief Print the given char to the terminal
* \param c The character to print
*/
void print(char c);
/*!
@ -76,13 +86,36 @@ struct virtual_terminal {
*/
size_t read_input_raw(size_t ms);
/*!
* \brief Set the canonical mode of the terminal
* \param can The canonical mode of the terminal
*/
void set_canonical(bool can);
/*!
* \brief Set the mouse mode of the terminal
* \param can The mouse mode of the terminal
*/
void set_mouse(bool m);
/*!
* \brief Returns true if the terminal is in canonical mode, false otherwise
*/
bool is_canonical() const;
/*!
* \brief Returns true if the terminal is in mouse mode, false otherwise
*/
bool is_mouse() const;
/*!
* \brief Set the active mode of the terminal
*/
void set_active(bool);
/*!
* \brief Returns the console linked to this terminal
*/
console& get_console();
size_t id;

View File

@ -10,12 +10,41 @@
#include <types.hpp>
/*!
* \brief A textual console
*/
struct text_console {
/*!
* \brief Initialize the console
*/
void init();
/*!
* \brief Returns the number of lines of the console
*/
size_t lines();
/*!
* \brief Returns the number of columns of the console
*/
size_t columns();
/*!
* \brief Clear the text console
*/
void clear();
/*!
* \brief Scroll up one line
*/
void scroll_up();
/*!
* \brief Print a char at the given line and column
* \param line The line at which to print the char
* \param column The column at which to print the char
* \param c The char to print
*/
void print_char(size_t line, size_t column, char c);
};

View File

@ -10,22 +10,75 @@
#include <types.hpp>
/*!
* \brief A VESA console
*/
struct vesa_console {
/*!
* \brief Initialize the console
*/
void init();
size_t lines() const ;
size_t columns() const ;
/*!
* \brief Returns the number of lines of the console
*/
size_t lines() const;
/*!
* \brief Returns the number of columns of the console
*/
size_t columns() const;
/*!
* \brief Clear the vesa console
*/
void clear();
/*!
* \brief Clear the given vesa console state
* \param buffer The VESA console state
*/
void clear(void* buffer);
/*!
* \brief Scroll up one line
*/
void scroll_up();
/*!
* \brief Scroll up one line on the given vesa console state
* \param buffer The VESA console state
*/
void scroll_up(void* buffer);
/*!
* \brief Print a char at the given line and column
* \param line The line at which to print the char
* \param column The column at which to print the char
* \param c The char to print
*/
void print_char(size_t line, size_t column, char c);
/*!
* \brief Print a char at the given line and column on the given vesa console state
* \param buffer The VESA console state
* \param line The line at which to print the char
* \param column The column at which to print the char
* \param c The char to print
*/
void print_char(void* buffer, size_t line, size_t column, char c);
/*!
* \brief Save the state of the console
* \param buffer The buffer to save to
* \return the buffer the state was saved to
*/
void* save(void* buffer);
/*!
* \brief Restore the state of the console
* \param buffer The buffer to restore from
*/
void restore(void* buffer);
};

View File

@ -26,24 +26,24 @@ bool text = true;
} //end of anonymous namespace
void stdio::init_console(){
void stdio::init_console() {
text = !vesa::enabled();
if(text){
if (text) {
t_console.init();
} else {
v_console.init();
}
}
void stdio::console::init(){
if(!text){
void stdio::console::init() {
if (!text) {
buffer = vesa::create_buffer();
}
}
size_t stdio::console::get_rows() const {
if(text){
if (text) {
return t_console.lines();
} else {
return v_console.lines();
@ -51,30 +51,30 @@ size_t stdio::console::get_rows() const {
}
size_t stdio::console::get_columns() const {
if(text){
if (text) {
return t_console.columns();
} else {
return v_console.columns();
}
}
void stdio::console::print(char key){
if(key == '\n'){
void stdio::console::print(char key) {
if (key == '\n') {
next_line();
} else if(key == '\r'){
} else if (key == '\r') {
// Ignore \r for now
} else if(key == '\b'){
} else if (key == '\b') {
--current_column;
print(' ');
--current_column;
} else if(key == '\t'){
} else if (key == '\t') {
print(' ');
print(' ');
} else {
if(text){
if (text) {
t_console.print_char(current_line, current_column, key);
} else {
if(active){
if (active) {
v_console.print_char(current_line, current_column, key);
} else {
v_console.print_char(buffer, current_line, current_column, key);
@ -83,51 +83,51 @@ void stdio::console::print(char key){
++current_column;
if(current_column == console::get_columns()){
if (current_column == console::get_columns()) {
next_line();
}
}
}
void stdio::console::wipeout(){
if(text){
void stdio::console::wipeout() {
if (text) {
t_console.clear();
} else {
if(active){
if (active) {
v_console.clear();
} else {
v_console.clear(buffer);
}
}
current_line = 0;
current_line = 0;
current_column = 0;
}
void stdio::console::save(){
void stdio::console::save() {
thor_assert(!text, "save/restore of the text console is not yet supported");
buffer = v_console.save(buffer);
}
void stdio::console::restore(){
void stdio::console::restore() {
thor_assert(!text, "save/restore of the text console is not yet supported");
v_console.restore(buffer);
}
void stdio::console::set_active(bool active){
void stdio::console::set_active(bool active) {
this->active = active;
}
void stdio::console::next_line(){
void stdio::console::next_line() {
++current_line;
if(current_line == console::get_rows()){
if(text){
if (current_line == console::get_rows()) {
if (text) {
t_console.scroll_up();
} else {
if(active){
if (active) {
v_console.scroll_up();
} else {
v_console.scroll_up(buffer);

View File

@ -27,7 +27,7 @@ size_t active_terminal;
std::array<stdio::virtual_terminal, MAX_TERMINALS> terminals;
void input_thread(void* data){
void input_thread(void* data) {
auto& terminal = *reinterpret_cast<stdio::virtual_terminal*>(data);
auto pid = scheduler::get_pid();
@ -35,62 +35,62 @@ void input_thread(void* data){
logging::logf(logging::log_level::TRACE, "stdio: Input Thread for terminal %u started (pid:%u)\n", terminal.id, pid);
bool shift = false;
bool alt = false;
bool alt = false;
while(true){
while (true) {
// Wait for some input
scheduler::block_process(pid);
// Handle keyboard input
while(!terminal.keyboard_buffer.empty()){
while (!terminal.keyboard_buffer.empty()) {
auto key = terminal.keyboard_buffer.pop();
if(terminal.canonical){
if (terminal.canonical) {
//Key released
if(key & 0x80){
if (key & 0x80) {
key &= ~(0x80);
if(alt && key == keyboard::KEY_F1){
if (alt && key == keyboard::KEY_F1) {
stdio::switch_terminal(0);
} else if(alt && key == keyboard::KEY_F2){
} else if (alt && key == keyboard::KEY_F2) {
stdio::switch_terminal(1);
} else if(alt && key == keyboard::KEY_F3){
} else if (alt && key == keyboard::KEY_F3) {
stdio::switch_terminal(2);
}
if(key == keyboard::KEY_LEFT_SHIFT || key == keyboard::KEY_RIGHT_SHIFT){
if (key == keyboard::KEY_LEFT_SHIFT || key == keyboard::KEY_RIGHT_SHIFT) {
shift = false;
}
if(key == keyboard::KEY_ALT){
if (key == keyboard::KEY_ALT) {
alt = false;
}
}
//Key pressed
else {
if(key == keyboard::KEY_LEFT_SHIFT || key == keyboard::KEY_RIGHT_SHIFT){
if (key == keyboard::KEY_LEFT_SHIFT || key == keyboard::KEY_RIGHT_SHIFT) {
shift = true;
} else if(key == keyboard::KEY_ALT){
} else if (key == keyboard::KEY_ALT) {
alt = true;
} else if(key == keyboard::KEY_BACKSPACE){
if(!terminal.input_buffer.empty()){
} else if (key == keyboard::KEY_BACKSPACE) {
if (!terminal.input_buffer.empty()) {
terminal.input_buffer.pop_last();
terminal.print('\b');
}
} else {
auto qwertz_key =
shift
? keyboard::shift_key_to_ascii(key)
: keyboard::key_to_ascii(key);
? keyboard::shift_key_to_ascii(key)
: keyboard::key_to_ascii(key);
if(qwertz_key){
if (qwertz_key) {
terminal.input_buffer.push(qwertz_key);
terminal.print(qwertz_key);
if(qwertz_key == '\n'){
if (qwertz_key == '\n') {
// Transfer current line to the canonical buffer
while(!terminal.input_buffer.empty()){
while (!terminal.input_buffer.empty()) {
terminal.canonical_buffer.push(terminal.input_buffer.pop());
}
@ -112,10 +112,10 @@ void input_thread(void* data){
}
// Handle mouse input
while(!terminal.mouse_buffer.empty()){
while (!terminal.mouse_buffer.empty()) {
auto key = terminal.mouse_buffer.pop();
if(!terminal.canonical && terminal.mouse){
if (!terminal.canonical && terminal.is_mouse()) {
terminal.raw_buffer.push(key);
terminal.input_queue.notify_one();
@ -128,10 +128,10 @@ void input_thread(void* data){
} //end of anonymous namespace
void stdio::init_terminals(){
void stdio::init_terminals() {
size_t id = 0;
for(auto& terminal : terminals){
for (auto& terminal : terminals) {
terminal.id = id++;
terminal.active = false;
terminal.canonical = true;
@ -140,25 +140,25 @@ void stdio::init_terminals(){
// Initialize the active terminal
active_terminal = 0;
active_terminal = 0;
terminals[active_terminal].active = true;
terminals[active_terminal].get_console().set_active(true);
}
void stdio::register_devices(){
for(auto& terminal : terminals){
void stdio::register_devices() {
for (auto& terminal : terminals) {
std::string name = std::string("tty") + std::to_string(terminal.id);
devfs::register_device("/dev/", name, devfs::device_type::CHAR_DEVICE, tty_driver, &terminal);
}
}
void stdio::finalize(){
for(auto& terminal : terminals){
void stdio::finalize() {
for (auto& terminal : terminals) {
auto* user_stack = new char[scheduler::user_stack_size];
auto* kernel_stack = new char[scheduler::kernel_stack_size];
auto& input_process = scheduler::create_kernel_task_args("tty_input", user_stack, kernel_stack, &input_thread, &terminal);
auto& input_process = scheduler::create_kernel_task_args("tty_input", user_stack, kernel_stack, &input_thread, &terminal);
input_process.ppid = 1;
input_process.priority = scheduler::DEFAULT_PRIORITY;
@ -172,22 +172,22 @@ void stdio::finalize(){
}
}
size_t stdio::terminals_count(){
size_t stdio::terminals_count() {
return MAX_TERMINALS;
}
stdio::virtual_terminal& stdio::get_active_terminal(){
stdio::virtual_terminal& stdio::get_active_terminal() {
return terminals[active_terminal];
}
stdio::virtual_terminal& stdio::get_terminal(size_t id){
stdio::virtual_terminal& stdio::get_terminal(size_t id) {
thor_assert(id < MAX_TERMINALS, "Out of bound tty");
return terminals[id];
}
void stdio::switch_terminal(size_t id){
if(active_terminal != id){
void stdio::switch_terminal(size_t id) {
if (active_terminal != id) {
logging::logf(logging::log_level::TRACE, "stdio: Switch activate virtual terminal %u\n", id);
// Effectively switch the terminal

View File

@ -17,12 +17,12 @@
#include "print.hpp"
void stdio::virtual_terminal::print(char key){
void stdio::virtual_terminal::print(char key) {
cons.print(key);
}
void stdio::virtual_terminal::send_input(char key){
if(!input_thread_pid){
void stdio::virtual_terminal::send_input(char key) {
if (!input_thread_pid) {
return;
}
@ -34,8 +34,8 @@ void stdio::virtual_terminal::send_input(char key){
scheduler::unblock_process_hint(input_thread_pid);
}
void stdio::virtual_terminal::send_mouse_input(std::keycode key){
if(!input_thread_pid){
void stdio::virtual_terminal::send_mouse_input(std::keycode key) {
if (!input_thread_pid) {
return;
}
@ -47,16 +47,16 @@ void stdio::virtual_terminal::send_mouse_input(std::keycode key){
scheduler::unblock_process_hint(input_thread_pid);
}
size_t stdio::virtual_terminal::read_input_can(char* buffer, size_t max){
size_t stdio::virtual_terminal::read_input_can(char* buffer, size_t max) {
size_t read = 0;
while(true){
while(!canonical_buffer.empty()){
while (true) {
while (!canonical_buffer.empty()) {
auto c = canonical_buffer.pop();
buffer[read++] = c;
if(read >= max || c == '\n'){
if (read >= max || c == '\n') {
return read;
}
}
@ -66,45 +66,45 @@ size_t stdio::virtual_terminal::read_input_can(char* buffer, size_t max){
}
// TODO In case of max < read, the timeout is not respected
size_t stdio::virtual_terminal::read_input_can(char* buffer, size_t max, size_t ms){
size_t stdio::virtual_terminal::read_input_can(char* buffer, size_t max, size_t ms) {
size_t read = 0;
while(true){
while(!canonical_buffer.empty()){
while (true) {
while (!canonical_buffer.empty()) {
auto c = canonical_buffer.pop();
buffer[read++] = c;
if(read >= max || c == '\n'){
if (read >= max || c == '\n') {
return read;
}
}
if(!ms){
if (!ms) {
return read;
}
if(!input_queue.wait_for(ms)){
if (!input_queue.wait_for(ms)) {
return read;
}
}
}
size_t stdio::virtual_terminal::read_input_raw(){
if(raw_buffer.empty()){
size_t stdio::virtual_terminal::read_input_raw() {
if (raw_buffer.empty()) {
input_queue.wait();
}
return raw_buffer.pop();
}
size_t stdio::virtual_terminal::read_input_raw(size_t ms){
if(raw_buffer.empty()){
if(!ms){
size_t stdio::virtual_terminal::read_input_raw(size_t ms) {
if (raw_buffer.empty()) {
if (!ms) {
return static_cast<size_t>(std::keycode::TIMEOUT);
}
if(!input_queue.wait_for(ms)){
if (!input_queue.wait_for(ms)) {
return static_cast<size_t>(std::keycode::TIMEOUT);
}
}
@ -114,13 +114,13 @@ size_t stdio::virtual_terminal::read_input_raw(size_t ms){
return raw_buffer.pop();
}
void stdio::virtual_terminal::set_canonical(bool can){
void stdio::virtual_terminal::set_canonical(bool can) {
logging::logf(logging::log_level::TRACE, "Switched terminal %u canonical mode from %u to %u\n", id, uint64_t(canonical), uint64_t(can));
canonical = can;
}
void stdio::virtual_terminal::set_mouse(bool m){
void stdio::virtual_terminal::set_mouse(bool m) {
logging::logf(logging::log_level::TRACE, "Switched terminal %u mouse handling mode from %u to %u\n", id, uint64_t(mouse), uint64_t(m));
mouse = m;
@ -130,8 +130,12 @@ bool stdio::virtual_terminal::is_canonical() const {
return canonical;
}
void stdio::virtual_terminal::set_active(bool active){
if(this->active == active){
bool stdio::virtual_terminal::is_mouse() const {
return mouse;
}
void stdio::virtual_terminal::set_active(bool active) {
if (this->active == active) {
return;
}
@ -139,13 +143,13 @@ void stdio::virtual_terminal::set_active(bool active){
cons.set_active(active);
if(active){
if (active) {
cons.restore();
} else {
cons.save();
}
}
stdio::console& stdio::virtual_terminal::get_console(){
stdio::console& stdio::virtual_terminal::get_console() {
return cons;
}

View File

@ -12,70 +12,70 @@
namespace {
enum vga_color {
BLACK = 0,
BLUE = 1,
GREEN = 2,
CYAN = 3,
RED = 4,
MAGENTA = 5,
BROWN = 6,
LIGHT_GREY = 7,
DARK_GREY = 8,
LIGHT_BLUE = 9,
LIGHT_GREEN = 10,
LIGHT_CYAN = 11,
LIGHT_RED = 12,
BLACK = 0,
BLUE = 1,
GREEN = 2,
CYAN = 3,
RED = 4,
MAGENTA = 5,
BROWN = 6,
LIGHT_GREY = 7,
DARK_GREY = 8,
LIGHT_BLUE = 9,
LIGHT_GREEN = 10,
LIGHT_CYAN = 11,
LIGHT_RED = 12,
LIGHT_MAGENTA = 13,
LIGHT_BROWN = 14,
WHITE = 15,
LIGHT_BROWN = 14,
WHITE = 15,
};
uint8_t make_color(vga_color fg, vga_color bg){
uint8_t make_color(vga_color fg, vga_color bg) {
return fg | bg << 4;
}
uint16_t make_vga_entry(char c, uint8_t color){
uint16_t c16 = c;
uint16_t make_vga_entry(char c, uint8_t color) {
uint16_t c16 = c;
uint16_t color16 = color;
return c16 | color16 << 8;
}
} //end of anonymous namespace
void text_console::init(){
void text_console::init() {
//Nothing special to init
}
size_t text_console::lines(){
size_t text_console::lines() {
return 25;
}
size_t text_console::columns(){
size_t text_console::columns() {
return 80;
}
void text_console::clear(){
for(int line = 0; line < 25; ++line){
for(uint64_t column = 0; column < 80; ++column){
void text_console::clear() {
for (int line = 0; line < 25; ++line) {
for (uint64_t column = 0; column < 80; ++column) {
print_char(line, column, ' ');
}
}
}
void text_console::scroll_up(){
void text_console::scroll_up() {
auto vga_buffer_fast = reinterpret_cast<uint64_t*>(0x0B8000);
auto destination = vga_buffer_fast;
auto source = &vga_buffer_fast[20];
auto destination = vga_buffer_fast;
auto source = &vga_buffer_fast[20];
std::copy_n(source, 24 * 20, destination);
auto vga_buffer = reinterpret_cast<uint16_t*>(0x0B8000);
for(uint64_t i = 0; i < 80; ++i){
for (uint64_t i = 0; i < 80; ++i) {
vga_buffer[24 * 80 + i] = make_vga_entry(' ', make_color(WHITE, BLACK));
}
}
void text_console::print_char(size_t line, size_t column, char c){
void text_console::print_char(size_t line, size_t column, char c) {
uint16_t* vga_buffer = reinterpret_cast<uint16_t*>(0x0B8000);
vga_buffer[line * 80 + column] = make_vga_entry(c, make_color(WHITE, BLACK));