push
This commit is contained in:
@@ -0,0 +1,826 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "../../include/io/ports.h"
|
||||
#include "../../include/io/serial.h"
|
||||
|
||||
static volatile uint8_t serial_lock = 0;
|
||||
static uint16_t default_serial_port = 0;
|
||||
|
||||
void serial_initialize(uint16_t port, uint32_t baud_rate) {
|
||||
outb(port + 1, 0x00);
|
||||
|
||||
uint16_t divisor = 115200 / baud_rate;
|
||||
outb(port + 3, 0x80);
|
||||
outb(port + 0, divisor & 0xFF);
|
||||
outb(port + 1, (divisor >> 8) & 0xFF);
|
||||
|
||||
outb(port + 3, 0x03);
|
||||
outb(port + 2, 0xC7);
|
||||
outb(port + 4, 0x0B);
|
||||
outb(port + 4, 0x1E);
|
||||
outb(port + 0, 0xAE);
|
||||
|
||||
if (inb(port + 0) != 0xAE) {
|
||||
return;
|
||||
}
|
||||
|
||||
outb(port + 4, 0x0F);
|
||||
|
||||
default_serial_port = port;
|
||||
}
|
||||
|
||||
uint16_t serial_get_default_port(void) {
|
||||
return default_serial_port;
|
||||
}
|
||||
|
||||
void serial_set_default_port(uint16_t port) {
|
||||
default_serial_port = port;
|
||||
}
|
||||
|
||||
void serial_force_unlock(void) {
|
||||
__sync_lock_release(&serial_lock);
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
int serial_received_port(uint16_t port) {
|
||||
return inb(port + 5) & 1;
|
||||
}
|
||||
|
||||
int serial_received(void) {
|
||||
if (default_serial_port == 0) return 0;
|
||||
return serial_received_port(default_serial_port);
|
||||
}
|
||||
|
||||
char serial_read_port(uint16_t port) {
|
||||
while (serial_received_port(port) == 0);
|
||||
return inb(port);
|
||||
}
|
||||
|
||||
char serial_read(void) {
|
||||
if (default_serial_port == 0) return 0;
|
||||
return serial_read_port(default_serial_port);
|
||||
}
|
||||
|
||||
int serial_is_transmit_empty_port(uint16_t port) {
|
||||
return inb(port + 5) & 0x20;
|
||||
}
|
||||
|
||||
int serial_is_transmit_empty(void) {
|
||||
if (default_serial_port == 0) return 1;
|
||||
return serial_is_transmit_empty_port(default_serial_port);
|
||||
}
|
||||
|
||||
void serial_write_port(uint16_t port, char c) {
|
||||
while (serial_is_transmit_empty_port(port) == 0);
|
||||
outb(port, c);
|
||||
}
|
||||
|
||||
void serial_write(char c) {
|
||||
if (default_serial_port == 0) return;
|
||||
serial_write_port(default_serial_port, c);
|
||||
}
|
||||
|
||||
void serial_writestring_port(uint16_t port, const char* str) {
|
||||
while (*str) {
|
||||
serial_write_port(port, *str++);
|
||||
}
|
||||
}
|
||||
|
||||
void serial_writestring(const char* str) {
|
||||
if (default_serial_port == 0) return;
|
||||
uint64_t flags;
|
||||
asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory");
|
||||
while (__sync_lock_test_and_set(&serial_lock, 1))
|
||||
__asm__ volatile("pause" ::: "memory");
|
||||
serial_writestring_port(default_serial_port, str);
|
||||
__sync_lock_release(&serial_lock);
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory", "cc");
|
||||
}
|
||||
|
||||
|
||||
void serial_writebuf(const char* buf, size_t len) {
|
||||
if (default_serial_port == 0 || !buf || len == 0) return;
|
||||
uint64_t flags;
|
||||
asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory");
|
||||
while (__sync_lock_test_and_set(&serial_lock, 1))
|
||||
__asm__ volatile("pause" ::: "memory");
|
||||
for (size_t i = 0; i < len; i++)
|
||||
serial_write_port(default_serial_port, buf[i]);
|
||||
__sync_lock_release(&serial_lock);
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory", "cc");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void reverse_string(char* str, int length) {
|
||||
int start = 0;
|
||||
int end = length - 1;
|
||||
while (start < end) {
|
||||
char temp = str[start];
|
||||
str[start] = str[end];
|
||||
str[end] = temp;
|
||||
start++;
|
||||
end--;
|
||||
}
|
||||
}
|
||||
|
||||
static void uint_to_str(uint64_t value, char* buffer, int base, bool uppercase) {
|
||||
char* ptr = buffer;
|
||||
|
||||
if (base < 2 || base > 36) {
|
||||
*ptr = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
const char* digits = uppercase ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" :
|
||||
"0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
if (value == 0) {
|
||||
*ptr++ = '0';
|
||||
*ptr = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
while (value > 0) {
|
||||
int digit = value % base;
|
||||
*ptr++ = digits[digit];
|
||||
value /= base;
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
reverse_string(buffer, ptr - buffer);
|
||||
}
|
||||
|
||||
static void int_to_str(int64_t value, char* buffer, int base, bool uppercase) {
|
||||
if (value < 0 && (base == 10 || base == 8)) {
|
||||
buffer[0] = '-';
|
||||
uint_to_str(-value, buffer + 1, base, uppercase);
|
||||
} else {
|
||||
uint_to_str(value, buffer, base, uppercase);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t pow10_u64(int n) {
|
||||
uint64_t r = 1;
|
||||
while (n-- > 0) r *= 10;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int double_to_string(double value, char* buffer, int precision) {
|
||||
if (isnan(value)) {
|
||||
strcpy(buffer, "nan");
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (isinf(value)) {
|
||||
if (value < 0) {
|
||||
strcpy(buffer, "-inf");
|
||||
return 4;
|
||||
} else {
|
||||
strcpy(buffer, "inf");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (precision < 0) precision = 6;
|
||||
if (precision > 16) precision = 16;
|
||||
|
||||
bool negative = (value < 0);
|
||||
double abs_val = negative ? -value : value;
|
||||
|
||||
uint64_t mult = pow10_u64(precision);
|
||||
double scaled = abs_val * mult + 0.5;
|
||||
uint64_t int_scaled = (uint64_t)scaled;
|
||||
|
||||
uint64_t int_part = int_scaled / mult;
|
||||
uint64_t frac_part = int_scaled % mult;
|
||||
|
||||
char* ptr = buffer;
|
||||
if (negative) *ptr++ = '-';
|
||||
|
||||
char int_buf[32];
|
||||
char* p = int_buf + sizeof(int_buf) - 1;
|
||||
*p = '\0';
|
||||
|
||||
if (int_part == 0) {
|
||||
*--p = '0';
|
||||
} else {
|
||||
uint64_t n = int_part;
|
||||
while (n > 0) {
|
||||
*--p = '0' + (n % 10);
|
||||
n /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
size_t int_len = (int_buf + sizeof(int_buf) - 1) - p;
|
||||
memcpy(ptr, p, int_len);
|
||||
ptr += int_len;
|
||||
|
||||
if (precision > 0) {
|
||||
*ptr++ = '.';
|
||||
|
||||
char frac_buf[32];
|
||||
char* f = frac_buf + sizeof(frac_buf) - 1;
|
||||
*f = '\0';
|
||||
|
||||
if (frac_part == 0) {
|
||||
for (int i = 0; i < precision; i++) {
|
||||
*--f = '0';
|
||||
}
|
||||
} else {
|
||||
uint64_t n = frac_part;
|
||||
int count = 0;
|
||||
while (n > 0) {
|
||||
*--f = '0' + (n % 10);
|
||||
n /= 10;
|
||||
count++;
|
||||
}
|
||||
while (count < precision) {
|
||||
*--f = '0';
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
size_t frac_len = (frac_buf + sizeof(frac_buf) - 1) - f;
|
||||
memcpy(ptr, f, frac_len);
|
||||
ptr += frac_len;
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
return ptr - buffer;
|
||||
}
|
||||
|
||||
static int double_to_scientific(double value, char* buffer, int precision, bool uppercase) {
|
||||
if (isnan(value)) {
|
||||
strcpy(buffer, "nan");
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (isinf(value)) {
|
||||
if (value < 0) {
|
||||
strcpy(buffer, "-inf");
|
||||
return 4;
|
||||
} else {
|
||||
strcpy(buffer, "inf");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (value == 0.0) {
|
||||
if (precision < 0) precision = 6;
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
for (int i = 0; i < precision; i++) {
|
||||
buffer[2 + i] = '0';
|
||||
}
|
||||
buffer[2 + precision] = uppercase ? 'E' : 'e';
|
||||
buffer[3 + precision] = '+';
|
||||
buffer[4 + precision] = '0';
|
||||
buffer[5 + precision] = '0';
|
||||
buffer[6 + precision] = '\0';
|
||||
return 6 + precision;
|
||||
}
|
||||
|
||||
if (precision < 0) precision = 6;
|
||||
if (precision > 16) precision = 16;
|
||||
|
||||
double abs_val = value < 0 ? -value : value;
|
||||
int exponent = 0;
|
||||
|
||||
if (abs_val >= 10.0) {
|
||||
while (abs_val >= 10.0) {
|
||||
abs_val /= 10.0;
|
||||
exponent++;
|
||||
}
|
||||
} else if (abs_val < 1.0 && abs_val > 0.0) {
|
||||
while (abs_val < 1.0) {
|
||||
abs_val *= 10.0;
|
||||
exponent--;
|
||||
}
|
||||
}
|
||||
|
||||
if (value < 0) abs_val = -abs_val;
|
||||
|
||||
int len = double_to_string(abs_val, buffer, precision);
|
||||
|
||||
char e_char = uppercase ? 'E' : 'e';
|
||||
buffer[len++] = e_char;
|
||||
|
||||
if (exponent >= 0) {
|
||||
buffer[len++] = '+';
|
||||
} else {
|
||||
buffer[len++] = '-';
|
||||
exponent = -exponent;
|
||||
}
|
||||
|
||||
if (exponent < 10) {
|
||||
buffer[len++] = '0';
|
||||
buffer[len++] = '0' + exponent;
|
||||
} else {
|
||||
buffer[len++] = '0' + (exponent / 10);
|
||||
buffer[len++] = '0' + (exponent % 10);
|
||||
}
|
||||
|
||||
buffer[len] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
static int double_to_general(double value, char* buffer, int precision, bool uppercase) {
|
||||
double abs_val = value < 0 ? -value : value;
|
||||
|
||||
if (abs_val == 0.0) {
|
||||
strcpy(buffer, "0");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (precision < 0) precision = 6;
|
||||
if (precision == 0) precision = 1;
|
||||
|
||||
bool use_scientific = (abs_val >= 1e6 || (abs_val < 1e-4 && abs_val > 0));
|
||||
|
||||
if (use_scientific) {
|
||||
return double_to_scientific(value, buffer, precision - 1, uppercase);
|
||||
}
|
||||
|
||||
int digits_before = 0;
|
||||
double temp = abs_val;
|
||||
while (temp >= 1.0) {
|
||||
temp /= 10.0;
|
||||
digits_before++;
|
||||
}
|
||||
if (digits_before == 0) digits_before = 1;
|
||||
|
||||
int decimal_places = precision - digits_before;
|
||||
if (decimal_places < 0) decimal_places = 0;
|
||||
|
||||
return double_to_string(value, buffer, decimal_places);
|
||||
}
|
||||
|
||||
void serial_printf_port(uint16_t port, const char* format, ...) {
|
||||
uint64_t flags;
|
||||
asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory");
|
||||
while (__sync_lock_test_and_set(&serial_lock, 1)) {
|
||||
__asm__ volatile("pause" ::: "memory");
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
char buffer[256];
|
||||
const char* ptr = format;
|
||||
|
||||
while (*ptr) {
|
||||
if (*ptr != '%') {
|
||||
serial_write_port(port, *ptr);
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* percent_start = ptr++;
|
||||
|
||||
while (*ptr == '0' || *ptr == '-' || *ptr == '+' || *ptr == ' ' || *ptr == '#') {
|
||||
ptr++;
|
||||
}
|
||||
|
||||
int width = 0;
|
||||
while (*ptr >= '0' && *ptr <= '9') {
|
||||
width = width * 10 + (*ptr - '0');
|
||||
ptr++;
|
||||
}
|
||||
|
||||
int precision = -1;
|
||||
if (*ptr == '.') {
|
||||
ptr++;
|
||||
precision = 0;
|
||||
while (*ptr >= '0' && *ptr <= '9') {
|
||||
precision = precision * 10 + (*ptr - '0');
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
bool has_ll = false;
|
||||
bool has_l = false;
|
||||
bool has_size_t = false;
|
||||
|
||||
if (*ptr == 'z') {
|
||||
ptr++;
|
||||
has_size_t = true;
|
||||
} else if (*ptr == 'l') {
|
||||
ptr++;
|
||||
if (*ptr == 'l') {
|
||||
ptr++;
|
||||
has_ll = true;
|
||||
} else {
|
||||
has_l = true;
|
||||
}
|
||||
} else if (*ptr == 'h') {
|
||||
ptr++;
|
||||
if (*ptr == 'h') ptr++;
|
||||
} else if (*ptr == 'L' || *ptr == 'j' || *ptr == 't') {
|
||||
ptr++;
|
||||
}
|
||||
|
||||
switch (*ptr) {
|
||||
case 'c': {
|
||||
char c = (char)va_arg(args, int);
|
||||
serial_write_port(port, c);
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
const char* str = va_arg(args, const char*);
|
||||
if (!str) {
|
||||
str = "(null)";
|
||||
}
|
||||
serial_writestring_port(port, str);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd':
|
||||
case 'i': {
|
||||
int64_t num;
|
||||
if (has_size_t) {
|
||||
num = (int64_t)va_arg(args, size_t);
|
||||
} else if (has_ll) {
|
||||
num = va_arg(args, int64_t);
|
||||
} else if (has_l) {
|
||||
num = (int64_t)va_arg(args, long);
|
||||
} else {
|
||||
num = (int64_t)va_arg(args, int);
|
||||
}
|
||||
int_to_str(num, buffer, 10, false);
|
||||
serial_writestring_port(port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'u': {
|
||||
uint64_t num;
|
||||
if (has_size_t) {
|
||||
num = (uint64_t)va_arg(args, size_t);
|
||||
} else if (has_ll) {
|
||||
num = va_arg(args, uint64_t);
|
||||
} else if (has_l) {
|
||||
num = (uint64_t)va_arg(args, unsigned long);
|
||||
} else {
|
||||
num = (uint64_t)va_arg(args, unsigned int);
|
||||
}
|
||||
uint_to_str(num, buffer, 10, false);
|
||||
serial_writestring_port(port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'x': {
|
||||
uint64_t num;
|
||||
if (has_size_t) {
|
||||
num = (uint64_t)va_arg(args, size_t);
|
||||
} else if (has_ll) {
|
||||
num = va_arg(args, uint64_t);
|
||||
} else if (has_l) {
|
||||
num = (uint64_t)va_arg(args, unsigned long);
|
||||
} else {
|
||||
num = (uint64_t)va_arg(args, unsigned int);
|
||||
}
|
||||
uint_to_str(num, buffer, 16, false);
|
||||
serial_writestring_port(port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'X': {
|
||||
uint64_t num;
|
||||
if (has_size_t) {
|
||||
num = (uint64_t)va_arg(args, size_t);
|
||||
} else if (has_ll) {
|
||||
num = va_arg(args, uint64_t);
|
||||
} else if (has_l) {
|
||||
num = (uint64_t)va_arg(args, unsigned long);
|
||||
} else {
|
||||
num = (uint64_t)va_arg(args, unsigned int);
|
||||
}
|
||||
uint_to_str(num, buffer, 16, true);
|
||||
serial_writestring_port(port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'o': {
|
||||
uint64_t num;
|
||||
if (has_size_t) {
|
||||
num = (uint64_t)va_arg(args, size_t);
|
||||
} else if (has_ll) {
|
||||
num = va_arg(args, uint64_t);
|
||||
} else if (has_l) {
|
||||
num = (uint64_t)va_arg(args, unsigned long);
|
||||
} else {
|
||||
num = (uint64_t)va_arg(args, unsigned int);
|
||||
}
|
||||
uint_to_str(num, buffer, 8, false);
|
||||
serial_writestring_port(port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p': {
|
||||
void* ptr_val = va_arg(args, void*);
|
||||
serial_writestring_port(port, "0x");
|
||||
uint_to_str((uintptr_t)ptr_val, buffer, 16, false);
|
||||
serial_writestring_port(port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'f':
|
||||
case 'F': {
|
||||
double num = va_arg(args, double);
|
||||
double_to_string(num, buffer, precision);
|
||||
serial_writestring_port(port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'e':
|
||||
case 'E': {
|
||||
double num = va_arg(args, double);
|
||||
double_to_scientific(num, buffer, precision, (*ptr == 'E'));
|
||||
serial_writestring_port(port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'g':
|
||||
case 'G': {
|
||||
double num = va_arg(args, double);
|
||||
double_to_general(num, buffer, precision, (*ptr == 'G'));
|
||||
serial_writestring_port(port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'a':
|
||||
case 'A': {
|
||||
double num = va_arg(args, double);
|
||||
double_to_scientific(num, buffer, precision, (*ptr == 'A'));
|
||||
buffer[0] = '0';
|
||||
buffer[1] = 'x';
|
||||
serial_writestring_port(port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'n': {
|
||||
int* count_ptr = va_arg(args, int*);
|
||||
*count_ptr = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case '%': {
|
||||
serial_write_port(port, '%');
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
for (const char* p = percent_start; p <= ptr; p++) {
|
||||
serial_write_port(port, *p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*ptr != '\0') {
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
__sync_lock_release(&serial_lock);
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory", "cc");
|
||||
}
|
||||
|
||||
void serial_printf(const char* format, ...) {
|
||||
if (default_serial_port == 0) return;
|
||||
uint64_t flags;
|
||||
asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory");
|
||||
while (__sync_lock_test_and_set(&serial_lock, 1)) {
|
||||
__asm__ volatile("pause" ::: "memory");
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
char buffer[256];
|
||||
const char* ptr = format;
|
||||
|
||||
while (*ptr) {
|
||||
if (*ptr != '%') {
|
||||
serial_write_port(default_serial_port, *ptr);
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* percent_start = ptr++;
|
||||
|
||||
while (*ptr == '0' || *ptr == '-' || *ptr == '+' || *ptr == ' ' || *ptr == '#') {
|
||||
ptr++;
|
||||
}
|
||||
|
||||
int width = 0;
|
||||
while (*ptr >= '0' && *ptr <= '9') {
|
||||
width = width * 10 + (*ptr - '0');
|
||||
ptr++;
|
||||
}
|
||||
|
||||
int precision = -1;
|
||||
if (*ptr == '.') {
|
||||
ptr++;
|
||||
precision = 0;
|
||||
while (*ptr >= '0' && *ptr <= '9') {
|
||||
precision = precision * 10 + (*ptr - '0');
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
bool has_ll = false;
|
||||
bool has_l = false;
|
||||
bool has_size_t = false;
|
||||
|
||||
if (*ptr == 'z') {
|
||||
ptr++;
|
||||
has_size_t = true;
|
||||
} else if (*ptr == 'l') {
|
||||
ptr++;
|
||||
if (*ptr == 'l') {
|
||||
ptr++;
|
||||
has_ll = true;
|
||||
} else {
|
||||
has_l = true;
|
||||
}
|
||||
} else if (*ptr == 'h') {
|
||||
ptr++;
|
||||
if (*ptr == 'h') ptr++;
|
||||
} else if (*ptr == 'L' || *ptr == 'j' || *ptr == 't') {
|
||||
ptr++;
|
||||
}
|
||||
|
||||
switch (*ptr) {
|
||||
case 'c': {
|
||||
char c = (char)va_arg(args, int);
|
||||
serial_write_port(default_serial_port, c);
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
const char* str = va_arg(args, const char*);
|
||||
if (!str) {
|
||||
str = "(null)";
|
||||
}
|
||||
serial_writestring_port(default_serial_port, str);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd':
|
||||
case 'i': {
|
||||
int64_t num;
|
||||
if (has_size_t) {
|
||||
num = (int64_t)va_arg(args, size_t);
|
||||
} else if (has_ll) {
|
||||
num = va_arg(args, int64_t);
|
||||
} else if (has_l) {
|
||||
num = (int64_t)va_arg(args, long);
|
||||
} else {
|
||||
num = (int64_t)va_arg(args, int);
|
||||
}
|
||||
int_to_str(num, buffer, 10, false);
|
||||
serial_writestring_port(default_serial_port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'u': {
|
||||
uint64_t num;
|
||||
if (has_size_t) {
|
||||
num = (uint64_t)va_arg(args, size_t);
|
||||
} else if (has_ll) {
|
||||
num = va_arg(args, uint64_t);
|
||||
} else if (has_l) {
|
||||
num = (uint64_t)va_arg(args, unsigned long);
|
||||
} else {
|
||||
num = (uint64_t)va_arg(args, unsigned int);
|
||||
}
|
||||
uint_to_str(num, buffer, 10, false);
|
||||
serial_writestring_port(default_serial_port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'x': {
|
||||
uint64_t num;
|
||||
if (has_size_t) {
|
||||
num = (uint64_t)va_arg(args, size_t);
|
||||
} else if (has_ll) {
|
||||
num = va_arg(args, uint64_t);
|
||||
} else if (has_l) {
|
||||
num = (uint64_t)va_arg(args, unsigned long);
|
||||
} else {
|
||||
num = (uint64_t)va_arg(args, unsigned int);
|
||||
}
|
||||
uint_to_str(num, buffer, 16, false);
|
||||
serial_writestring_port(default_serial_port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'X': {
|
||||
uint64_t num;
|
||||
if (has_size_t) {
|
||||
num = (uint64_t)va_arg(args, size_t);
|
||||
} else if (has_ll) {
|
||||
num = va_arg(args, uint64_t);
|
||||
} else if (has_l) {
|
||||
num = (uint64_t)va_arg(args, unsigned long);
|
||||
} else {
|
||||
num = (uint64_t)va_arg(args, unsigned int);
|
||||
}
|
||||
uint_to_str(num, buffer, 16, true);
|
||||
serial_writestring_port(default_serial_port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'o': {
|
||||
uint64_t num;
|
||||
if (has_size_t) {
|
||||
num = (uint64_t)va_arg(args, size_t);
|
||||
} else if (has_ll) {
|
||||
num = va_arg(args, uint64_t);
|
||||
} else if (has_l) {
|
||||
num = (uint64_t)va_arg(args, unsigned long);
|
||||
} else {
|
||||
num = (uint64_t)va_arg(args, unsigned int);
|
||||
}
|
||||
uint_to_str(num, buffer, 8, false);
|
||||
serial_writestring_port(default_serial_port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p': {
|
||||
void* ptr_val = va_arg(args, void*);
|
||||
serial_writestring_port(default_serial_port, "0x");
|
||||
uint_to_str((uintptr_t)ptr_val, buffer, 16, false);
|
||||
serial_writestring_port(default_serial_port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'f':
|
||||
case 'F': {
|
||||
double num = va_arg(args, double);
|
||||
double_to_string(num, buffer, precision);
|
||||
serial_writestring_port(default_serial_port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'e':
|
||||
case 'E': {
|
||||
double num = va_arg(args, double);
|
||||
double_to_scientific(num, buffer, precision, (*ptr == 'E'));
|
||||
serial_writestring_port(default_serial_port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'g':
|
||||
case 'G': {
|
||||
double num = va_arg(args, double);
|
||||
double_to_general(num, buffer, precision, (*ptr == 'G'));
|
||||
serial_writestring_port(default_serial_port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'a':
|
||||
case 'A': {
|
||||
double num = va_arg(args, double);
|
||||
double_to_scientific(num, buffer, precision, (*ptr == 'A'));
|
||||
buffer[0] = '0';
|
||||
buffer[1] = 'x';
|
||||
serial_writestring_port(default_serial_port, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'n': {
|
||||
int* count_ptr = va_arg(args, int*);
|
||||
*count_ptr = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case '%': {
|
||||
serial_write_port(default_serial_port, '%');
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
for (const char* p = percent_start; p <= ptr; p++) {
|
||||
serial_write_port(default_serial_port, *p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*ptr != '\0') {
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
__sync_lock_release(&serial_lock);
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory", "cc");
|
||||
}
|
||||
Reference in New Issue
Block a user