summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/arch/amd64/paging.c1
-rw-r--r--src/kmain.c3
-rw-r--r--src/print.c696
3 files changed, 427 insertions, 273 deletions
diff --git a/src/arch/amd64/paging.c b/src/arch/amd64/paging.c
index fd24af4..a80737c 100644
--- a/src/arch/amd64/paging.c
+++ b/src/arch/amd64/paging.c
@@ -633,7 +633,6 @@ int kload_page(void *virt_addr) {
if (page->loaded)
return -1;
void *phys = alloc_phys_page();
- kprintf("0x%p\n", phys);
if (phys == NULL)
return -2;
page->loaded = 1;
diff --git a/src/kmain.c b/src/kmain.c
index ce8016d..b4ebadb 100644
--- a/src/kmain.c
+++ b/src/kmain.c
@@ -1,3 +1,4 @@
+#include <backtrace.h>
#include <fpu.h>
#include <acpi.h>
#include <memory.h>
@@ -18,6 +19,8 @@ void kmain(struct boot_info *info) {
char *test = kalloc(5);
*test = 1;
+ //log_backtrace();
+
while (1) {
screen_redraw();
// loop so we dont halt
diff --git a/src/print.c b/src/print.c
index fa16bab..8cab6e4 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1,6 +1,7 @@
#include <lib.h>
#include <serial.h>
#include <stdarg.h>
+#include <stdint.h>
void kputc(char c) {
serial_out(c);
@@ -31,54 +32,110 @@ struct format_precision {
};
enum format_modifier {
- MOD_NONE,
- MOD_INVALID,
- MOD_HALF_HALF,
- MOD_HALF,
- MOD_LONG_LONG,
- MOD_LONG,
+ MOD_NONE = 0,
+ MOD_HALF = 1,
+ MOD_HALF_HALF = 3,
+ MOD_LONG = 3,
+ MOD_LONG_LONG = 4,
+ MOD_INVALID = 5,
};
enum format_conversion {
- FMT_INT,
- FMT_UINT,
+ // decimal numbers
+ FMT_CHAR = 0,
+ FMT_INT = 4,
+ FMT_UINT = 5,
+ // otehr numbers
FMT_OCT,
FMT_HEX,
FMT_HEX_UPPER,
- FMT_CHAR,
+ // text
FMT_STR,
FMT_PTR,
- FMT_PTR_UPPER,
- FMT_PERCENT,
+ // misc
FMT_INVALID
};
-static enum format_flag read_flag(const char *format, const char **end) {
+enum format_length {
+ LEN_UCHAR,
+ LEN_CHAR,
+ LEN_USHORT,
+ LEN_SHORT,
+ LEN_UINT,
+ LEN_INT,
+ LEN_ULONG,
+ LEN_LONG,
+ LEN_ULONGLONG,
+ LEN_LONGLONG,
+ LEN_SIZET,
+ LEN_INVALID
+};
+
+struct spacing {
+ unsigned left;
+ unsigned length;
+ unsigned right;
+ bool zero;
+};
+
+enum charcase {
+ UPPERCASE,
+ LOWERCASE
+};
+
+enum printtype {
+ NONE,
+ OCTAL,
+ HEX
+};
+
+static enum printtype conversion_to_printtype(enum format_conversion conversion) {
+ switch (conversion) {
+ case FMT_OCT:
+ return OCTAL;
+ case FMT_HEX:
+ case FMT_HEX_UPPER:
+ return HEX;
+ default:
+ return NONE;
+ }
+}
- enum format_flag flag = FLG_NONE;
+static enum charcase conversion_to_charcase(enum format_conversion conversion) {
+ switch (conversion) {
+ case FMT_HEX_UPPER:
+ return UPPERCASE;
+ default:
+ return LOWERCASE;
+ }
+}
+
+static enum format_flag read_flags(const char *format, const char **end) {
+
+ enum format_flag flags = FLG_NONE;
for (; *format != '\0'; format++) {
switch (*format) {
case '#':
- flag |= FLG_ALTERNATE;
+ flags |= FLG_ALTERNATE;
break;
case '0':
- flag |= FLG_ZERO;
+ flags |= FLG_ZERO;
break;
case '-':
- flag |= FLG_LEFT_ALIGN;
+ flags |= FLG_LEFT_ALIGN;
break;
case '+':
- flag |= FLG_ADD_SIGN;
+ flags |= FLG_ADD_SIGN;
break;
default:
*end = format;
- return flag;
+ return flags;
}
}
*end = format;
- return flag;
+ return flags;
}
static struct format_width read_width(const char *format, const char **end) {
@@ -221,213 +278,344 @@ static enum format_conversion read_conversion(const char *format, const char **e
return FMT_STR;
case 'p':
return FMT_PTR;
- case 'P':
- return FMT_PTR_UPPER;
- case '%':
- return FMT_PERCENT;
default:
return FMT_INVALID;
}
}
-static void print_string(
- const char *str,
- enum format_flag flag,
- struct format_width width,
- struct format_precision precision
-) {
-
- size_t max_len = 0;
- size_t min_len = 0;
- size_t len = 0;
-
- if (width.defined)
- min_len = width.value;
-
- if (precision.defined) {
- max_len = precision.value;
- len = max_len;
- if (max_len < min_len)
- min_len = max_len;
- } else {
- len = strlen(str);
- }
-
- if (!(flag & FLG_LEFT_ALIGN) && len < min_len) {
- for (size_t i = 0; i < (min_len - len); i++) {
- kputc(' ');
- }
- }
-
- for (size_t i = 0; i < len; i++) {
- kputc(str[i]);
- }
-
- if ((flag & FLG_LEFT_ALIGN) && len < min_len) {
- for (size_t i = 0; i < (min_len - len); i++) {
- kputc(' ');
- }
- }
-}
-
-static char get_letter(
- char c,
- char base
+static char ctoa_print(
+ char c, // the single digit to convert to ascii
+ enum charcase cc // if this digit should be uppercase or lowercase
) {
+ char ascii_base = cc == UPPERCASE ? 'A' : 'a';
if (c >= 0 && c <= 9)
return c + '0';
c -= 10;
- return c + base;
+ return c + ascii_base;
}
-static char *get_decimal(
- long long num,
- char *buf,
- char sign,
- int radix,
- char base
+static char *ulltoa_print(
+ unsigned long long num, // the number to convert to ascii
+ unsigned radix, // the divisor for the number (base 10, octal, hex)
+ char *buf, // the buffer to write to
+ enum charcase cc, // if any a-z ascii should be uppercase or lowercase
+ bool addsign // add a sign even if its positive
) {
-
+ // we are printing the string backwards, add null byte
*buf = '\0';
buf--;
+ // if the number is zero, the while loop will never run
+ // so we have to add the zero digit ourselves
if (num == 0) {
*buf = '0';
buf--;
}
+ // for each digit, convert to ascii and add to buffer
while (num != 0) {
char i = num % radix;
- char c = get_letter(i, base);
+ char c = ctoa_print(i, cc);
*buf = c;
buf--;
num /= radix;
}
- if (sign) {
- *buf = sign;
+ // since this is the unsigned function, add a plus sign if
+ // requested
+ if (addsign) {
+ *buf = '+';
buf--;
}
- buf++;
+ buf++; // move forward one to be at the start of the string
return buf;
}
-static void print_unum(
- unsigned long long num,
- enum format_flag flag,
- struct format_width width,
- struct format_precision precision,
- bool isneg,
- int radix,
- char base
+static char *lltoa_print(
+ signed long long num, // the number to convert to ascii
+ unsigned radix, // the divistor for the number (base 10, octal, hex)
+ char *buf, // the buffer to write to
+ enum charcase cc, // if any a-z ascii should be uppercase or lowercase
+ bool addsign // add a sign even if its positive
) {
+ bool isneg = num < 0;
- size_t max_len = 0;
- size_t min_len = 0;
- size_t len = 0;
-
- char sign = 0;
if (isneg)
- sign = '-';
- else if (flag & FLG_ADD_SIGN)
- sign = '+';
+ num = -num;
+
+ buf = ulltoa_print(num, radix, buf, cc, !isneg && addsign);
+
+ if (isneg && num < 0) {
+ buf--;
+ *buf = '-';
+ }
- char buf[1024];
- char *str = get_decimal(
- num,
- buf + 1023,
- sign,
- radix,
- base
- );
+ return buf;
+}
- bool space_pre = (flag & FLG_LEFT_ALIGN) || !(flag & FLG_ZERO);
- if (!space_pre && radix == 16 && (flag & FLG_ALTERNATE)) {
- char x = base + ('x' - 'a');
- serial_out('0');
- serial_out(x);
+static void print_string_buffer(
+ const char *buf, // buffer containing the text we want to print
+ struct spacing spacing // the spacing on the left right and middle
+) {
+ for (unsigned i = 0; i < spacing.left; i++) {
+ kputc(' ');
}
- if (width.defined)
- min_len = width.value;
+ for (unsigned i = 0; i < spacing.length; i++) {
+ kputc(*buf++);
+ }
- if (precision.defined) {
- max_len = precision.value;
- len = max_len;
- if (max_len < min_len)
- min_len = max_len;
- } else {
- len = strlen(str);
+ for (unsigned i = 0; i < spacing.right; i++) {
+ kputc(' ');
}
+}
- bool zero_padded = false;
+static void print_number_buffer(
+ const char *buf, // buffer containing the text we want to print
+ struct spacing spacing, // the spacing on the left right and middle
+ enum printtype type,
+ enum charcase cc
+) {
- if (!(flag & FLG_LEFT_ALIGN) && len < min_len) {
- for (size_t i = 0; i < (min_len - len); i++) {
- (flag & FLG_ZERO) ? kputc('0') : kputc(' ');
+ // put the 0x at the start of the string
+ if (spacing.left && spacing.zero && type == HEX) {
+ if (cc == UPPERCASE) {
+ kputs("0X");
+ } else {
+ kputs("0x");
}
- if (flag & FLG_ZERO)
- zero_padded = true;
}
-
- if (space_pre && radix == 16 && (flag & FLG_ALTERNATE)) {
- char x = base + ('x' - 'a');
- serial_out('0');
- serial_out(x);
+
+ if ((!spacing.left || !spacing.zero) && type == OCTAL) {
+ kputc('0');
}
- if (space_pre && radix == 16 && flag & FLG_ALTERNATE) {
- char x = base + ('x' - 'a');
- serial_out('0');
- serial_out(x);
+ for (unsigned i = 0; i < spacing.left; i++) {
+ spacing.zero ? kputc('0') : kputc(' ');
}
- kputs(str);
+ if ((!spacing.left || !spacing.zero) && type == HEX) {
+ if (cc == UPPERCASE) {
+ kputs("0X");
+ } else {
+ kputs("0x");
+ }
+ }
- if (!zero_padded && (flag & FLG_ALTERNATE) && radix == 8)
- kputc('0');
+ for (unsigned i = 0; i < spacing.length; i++) {
+ kputc(*buf++);
+ }
+
+ for (unsigned i = 0; i < spacing.right; i++) {
+ kputc(' ');
+ }
+}
+
+static unsigned get_string_len(
+ const char *str,
+ struct format_precision precision
+) {
+ if (!precision.defined)
+ return strlen(str);
+ unsigned max = precision.value;
+ for (unsigned i = 0; i < max; i++) {
+ if (str[i] == '\0') {
+ // we broke early
+ // precision is greater then strlen
+ return i;
+ }
+ }
+ return max;
+}
+
+static struct spacing get_spacing(
+ struct format_width width,
+ struct format_precision precision,
+ enum format_flag flags,
+ unsigned length
+) {
+ struct spacing spacing;
+
+ unsigned min = 0,
+ max = 0;
- if ((flag & FLG_LEFT_ALIGN) && len < min_len) {
- for (size_t i = 0; i < (min_len - len); i++) {
- (flag & FLG_ZERO) ? kputc('0') : kputc(' ');
+ if (width.defined) {
+ min = width.value;
+ }
+
+ if (precision.defined) {
+ max = precision.value;
+ if (length > max) {
+ length = max;
}
+ if (min > max) {
+ min = max;
+ }
+ }
+
+ unsigned gap = 0;
+ if (max > length) {
+ gap = max - length;
+ }
+
+ spacing.length = length;
+
+ if (flags & FLG_LEFT_ALIGN) {
+ spacing.left = gap;
+ spacing.right = 0;
+ } else {
+ spacing.left = 0;
+ spacing.right = gap;
}
+
+ spacing.zero = (flags & FLG_ZERO);
+
+ return spacing;
}
-static void print_num(
- long long num,
- enum format_flag flag,
+static struct spacing get_string_spacing(
+ const char *str,
+ struct format_width width,
+ struct format_precision precision,
+ enum format_flag flags
+) {
+ unsigned length = get_string_len(str, precision);
+ return get_spacing(width, precision, flags, length);
+}
+
+static void print_string(
+ const char *str,
+ enum format_flag flags,
struct format_width width,
- struct format_precision precision,
- int radix,
- char base
+ struct format_precision precision
) {
- bool isneg = false;
+ struct spacing spacing =
+ get_string_spacing(str, width, precision, flags);
+ print_string_buffer(str, spacing);
+}
+
+static enum format_length apply_modifier(
+ enum format_conversion conversion,
+ enum format_modifier modifier
+) {
+ switch (conversion) {
+ case FMT_CHAR:
+ if (modifier == MOD_NONE)
+ return LEN_CHAR;
+ else
+ return LEN_INVALID;
+
+ case FMT_PTR:
+ if (modifier == MOD_NONE)
+ return LEN_SIZET;
+ else
+ return LEN_INVALID;
+
+ case FMT_INT:
+ if (modifier == MOD_LONG)
+ return LEN_LONG;
+ else if (modifier == MOD_LONG_LONG)
+ return LEN_LONGLONG;
+ else if (modifier == MOD_HALF)
+ return LEN_SHORT;
+ else if (modifier == MOD_HALF_HALF)
+ return LEN_CHAR;
+ else
+ return LEN_INT;
+
+ case FMT_UINT:
+ case FMT_OCT:
+ case FMT_HEX:
+ case FMT_HEX_UPPER:
+ if (modifier == MOD_LONG)
+ return LEN_ULONG;
+ else if (modifier == MOD_LONG_LONG)
+ return LEN_ULONGLONG;
+ else if (modifier == MOD_HALF)
+ return LEN_USHORT;
+ else if (modifier == MOD_HALF_HALF)
+ return LEN_UCHAR;
+ else
+ return LEN_UINT;
- if (num < 0) {
- num = ~num;
- isneg = true;
+ default:
+ return LEN_INVALID;
}
+}
- print_unum(
- num,
- flag,
- width,
- precision,
- isneg,
- radix,
- base
- );
+static unsigned printtype_to_radix(
+ enum printtype type
+) {
+ switch (type) {
+ case OCTAL:
+ return 8;
+ case HEX:
+ return 16;
+ case NONE:
+ default:
+ return 10;
+ }
+}
+
+static void print_signed_number(
+ signed long long num,
+ enum format_flag flags,
+ struct format_width width,
+ struct format_precision precision,
+ enum printtype type,
+ enum charcase cc
+) {
+ unsigned radix = printtype_to_radix(type);
+ char buf[256];
+ char *ptr = lltoa_print(num, radix, buf + 255, cc, flags & FLG_ADD_SIGN);
+ unsigned length = strlen(ptr);
+ struct spacing spacing =
+ get_spacing(width, precision, flags, length);
+ print_number_buffer(ptr, spacing, type, cc);
+}
+
+static void print_unsigned_number(
+ unsigned long long num,
+ enum format_flag flags,
+ struct format_width width,
+ struct format_precision precision,
+ enum printtype type,
+ enum charcase cc
+) {
+ unsigned radix = printtype_to_radix(type);
+ char buf[256];
+ char *ptr = ulltoa_print(num, radix, buf + 255, cc, flags & FLG_ADD_SIGN);
+ unsigned length = strlen(ptr);
+ struct spacing spacing =
+ get_spacing(width, precision, flags, length);
+ print_number_buffer(ptr, spacing, type, cc);
+}
+
+static bool is_conversion_number(enum format_conversion conversion) {
+ switch (conversion) {
+ case FMT_INT:
+ case FMT_UINT:
+ case FMT_OCT:
+ case FMT_HEX:
+ case FMT_HEX_UPPER:
+ case FMT_PTR:
+ return true;
+ case FMT_CHAR:
+ case FMT_STR:
+ case FMT_INVALID:
+ default:
+ return false;
+ }
}
void kvprintf(const char *format, va_list args) {
for (; *format != '\0'; format++) {
char c = *format;
if (c == '%') {
- enum format_flag flag;
+ enum format_flag flags;
struct format_width width;
struct format_precision precision;
enum format_modifier modifier;
@@ -435,34 +623,24 @@ void kvprintf(const char *format, va_list args) {
const char *ptr = format + 1;
- flag = read_flag(ptr, &ptr);
+ if (*(format + 1) == '%') {
+ kputc('%');
+ format++;
+ continue;
+ }
+
+ flags = read_flags(ptr, &ptr);
width = read_width(ptr, &ptr);
precision = read_precision(ptr, &ptr);
+
modifier = read_modifier(ptr, &ptr);
if (modifier == MOD_INVALID) {
- kputc('%');
- continue;
+ goto error;
}
conversion = read_conversion(ptr, &ptr);
- if (conversion == FMT_INVALID) {
- kputc('%');
- continue;
- }
-
- union {
- unsigned long long u;
- long long l;
- char c;
- const char *str;
- void *ptr;
- } data = {0};
-
- int radix = 0;
- char base = 0;
-
if (width.varys) {
int len = va_arg(args, int);
width.value = len;
@@ -473,106 +651,80 @@ void kvprintf(const char *format, va_list args) {
precision.value = len;
}
- switch (conversion) {
- case FMT_INT:
- if (modifier == MOD_NONE)
- data.l = va_arg(args, int);
- else if (modifier == MOD_HALF)
- data.l = (short) va_arg(args, int);
- else if (modifier == MOD_HALF_HALF)
- data.l = (char) va_arg(args, int);
- else if (modifier == MOD_LONG)
- data.l = va_arg(args, long);
- else if (modifier == MOD_LONG_LONG)
- data.l = va_arg(args, long long);
- radix = 10;
- print_num(
- data.l,
- flag,
- width,
- precision,
- radix,
- base
- );
- break;
- case FMT_UINT:
- case FMT_OCT:
- case FMT_HEX_UPPER:
- case FMT_HEX:
- if (modifier == MOD_NONE)
- data.u = va_arg(args, unsigned int);
- else if (modifier == MOD_HALF)
- data.u = (unsigned short) va_arg(args, unsigned int);
- else if (modifier == MOD_HALF_HALF)
- data.u = (unsigned char) va_arg(args, unsigned int);
- else if (modifier == MOD_LONG)
- data.u = va_arg(args, unsigned long);
- else if (modifier == MOD_LONG_LONG)
- data.u = va_arg(args, unsigned long long);
+ if (conversion == FMT_INVALID) {
+ goto error;
+ }
- if (conversion == FMT_UINT) {
- radix = 10;
- } else if (conversion == FMT_OCT) {
- radix = 8;
- } else if (conversion == FMT_HEX) {
- radix = 16;
- base = 'a';
- } else if (conversion == FMT_HEX_UPPER) {
- radix = 16;
- base = 'A';
- }
- goto printunum;
- break;
- case FMT_PTR:
- case FMT_PTR_UPPER:
- flag |= FLG_ZERO;
- data.u = va_arg(args, size_t);
- radix = 16;
- if (conversion == FMT_PTR)
- base = 'a';
- else
- base = 'A';
- goto printunum;
- break;
- printunum:
- print_unum(
- data.u,
- flag,
- width,
- precision,
- false,
- radix,
- base
- );
- break;
- case FMT_CHAR: {
- char buf[2];
- buf[0] = (char) va_arg(args, int);
- buf[1] = '\0';
- print_string(
- buf,
- flag,
- width,
- precision
- );
- break;
+ if (conversion == FMT_INT) {
+ enum format_length length =
+ apply_modifier(conversion, modifier);
+ enum printtype type = NONE;
+ enum charcase cc = LOWERCASE;
+
+ signed long long num = 0;
+ switch (length) {
+ case LEN_CHAR:
+ case LEN_SHORT:
+ case LEN_INT:
+ num = va_arg(args, signed int);
+ break;
+ case LEN_LONG:
+ num = va_arg(args, signed long);
+ break;
+ case LEN_LONGLONG:
+ num = va_arg(args, signed long long);
+ break;
+ default:
+ goto error;
+ }
+
+ print_signed_number(num, flags, width, precision, type, cc);
+ } else if (is_conversion_number(conversion)) {
+ enum format_length length =
+ apply_modifier(conversion, modifier);
+ enum printtype type =
+ conversion_to_printtype(conversion);
+ enum charcase cc =
+ conversion_to_charcase(conversion);
+
+ unsigned long long num = 0;
+ switch (length) {
+ case LEN_UCHAR:
+ case LEN_USHORT:
+ case LEN_UINT:
+ num = va_arg(args, unsigned int);
+ break;
+ case LEN_ULONG:
+ num = va_arg(args, unsigned long);
+ break;
+ case LEN_ULONGLONG:
+ num = va_arg(args, unsigned long long);
+ break;
+ case LEN_SIZET:
+ num = va_arg(args, size_t);
+ break;
+ default:
+ goto error;
}
- case FMT_STR:
- data.str = va_arg(args, const char*);
- print_string(
- data.str,
- flag,
- width,
- precision
- );
- break;
- case FMT_PERCENT:
- kputc('%');
- break;
- case FMT_INVALID:
- break;
+
+ print_unsigned_number(num, flags, width, precision, type, cc);
+ } else if (conversion == FMT_STR) {
+ char *str = va_arg(args, char *);
+ print_string(str, flags, width, precision);
+ } else if (conversion == FMT_CHAR) {
+ char temp[2];
+ temp[0] = va_arg(args, int);
+ temp[1] = '\0';
+ print_string(temp, flags, width, precision);
}
+
format = ptr - 1;
+ continue;
+
+error:
+ kputc('%');
+ format++;
+ continue;
} else {
kputc(c);
}