Kernel: Serial: Add serial_printf function

This function can output with decorators (like printf from stdio)
This commit is contained in:
g1n 2021-08-07 12:58:04 +03:00
parent 99888ea24d
commit beaa4078f7
2 changed files with 87 additions and 16 deletions

View File

@ -7,12 +7,12 @@
void kernel_main(void) { void kernel_main(void) {
terminal_initialize(); terminal_initialize();
init_serial();
printf("Hello from OrionOS!\n"); printf("Hello from OrionOS!\n");
printf("Testing serial\n"); printf("Testing serial\n");
init_serial(); serial_printf("Test is success!\n");
serial_print("Test is success!\n"); serial_printf("Newline test\n");
serial_print("Newline test\n"); char * test_string = "test";
serial_print("No newline test "); serial_printf("This is string from variable: %s", test_string);
serial_print("No newline test");
printf("Test finished success!\n"); printf("Test finished success!\n");
} }

View File

@ -1,5 +1,8 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include <limits.h>
#include <stdbool.h>
#define PORT 0x3f8 // COM1 #define PORT 0x3f8 // COM1
@ -38,23 +41,91 @@ char read_serial() {
int is_transmit_empty() { int is_transmit_empty() {
return inb(PORT + 5) & 0x20; return inb(PORT + 5) & 0x20;
} }
void write_serial(char a) { void write_serial(char a) {
while (is_transmit_empty() == 0); while (is_transmit_empty() == 0);
outb(PORT, a); outb(PORT, a);
} }
void serial_print(const char* str, ...) { static bool print(const char* data, size_t length) {
size_t len = strlen(str); const unsigned char* bytes = (const unsigned char*) data;
for (size_t i=0; i < len; i++) { for (size_t i = 0; i < length; i++) {
if (str[i] == '\n') { if (bytes[i] == '\n') {
write_serial('\r'); write_serial('\r');
write_serial('\n'); write_serial('\n');
} else { } else {
write_serial(str[i]); write_serial(bytes[i]);
} }
} }
return true;
}
int serial_printf(const char* restrict format, ...) {
va_list parameters;
va_start(parameters, format);
int written = 0;
while (*format != '\0') {
size_t maxrem = INT_MAX - written;
if (format[0] != '%' || format[1] == '%') {
if (format[0] == '%')
format++;
size_t amount = 1;
while (format[amount] && format[amount] != '%')
amount++;
if (maxrem < amount) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(format, amount))
return -1;
format += amount;
written += amount;
continue;
}
const char* format_begun_at = format++;
if (*format == 'c') {
format++;
char c = (char) va_arg(parameters, int /* char promotes to int */);
if (!maxrem) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(&c, sizeof(c)))
return -1;
written++;
} else if (*format == 's') {
format++;
const char* str = va_arg(parameters, const char*);
size_t len = strlen(str);
if (maxrem < len) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(str, len))
return -1;
written += len;
} else {
format = format_begun_at;
size_t len = strlen(format);
if (maxrem < len) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(format, len))
return -1;
written += len;
format += len;
}
}
va_end(parameters);
return written;
} }
inline void outb(uint16_t port, uint8_t val) inline void outb(uint16_t port, uint8_t val)