PCI, Serial, Shell improvements (VGA is broken)

This commit is contained in:
Nicholas Orlowsky 2025-02-03 16:24:00 -05:00
parent 50f5723733
commit dac2cff511
14 changed files with 125490 additions and 64 deletions

View file

@ -32,7 +32,7 @@ if (ARCH STREQUAL "i386")
endif()
add_executable(kernel.elf ${SOURCES} ${ASM_SOURCES})
set_target_properties(kernel.elf PROPERTIES LINK_FLAGS "-T ${LINKER_SCRIPT} -ffreestanding -O2 -nostdlib -lgcc -g ${ARCH_FLAG}")
set_target_properties(kernel.elf PROPERTIES LINK_FLAGS "-T ${LINKER_SCRIPT} -ffreestanding -O2 -nostdlib -lgcc -g ${ARCH_FLAG}" DEPENDS pci_supp)
add_custom_command(OUTPUT os.iso
COMMAND cp kernel.elf ../iso/boot/kernel.elf
COMMAND genisoimage -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -A os -input-charset utf8 -quiet -boot-info-table -o os.iso ../iso
@ -40,7 +40,13 @@ add_custom_command(OUTPUT os.iso
COMMENT "Generating OS ISO"
)
add_custom_target(pci_supp
COMMAND xxd -i ../build_supp/pci/pci.ids > ../kernel/pci_supp.c
COMMENT "Generating Supplemental PCI data"
)
# Run & Debug targets
add_custom_target(run COMMAND qemu-system-i386 -boot d -cdrom os.iso -m 512 -machine type=pc-i440fx-3.1 -monitor stdio -drive id=disk,file=/dev/null,if=none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 DEPENDS os.iso)
add_custom_target(run COMMAND qemu-system-i386 -boot d -m 512 -machine type=pc-i440fx-3.1 -serial stdio -device piix3-ide,id=ide -drive id=disk,file=/dev/null,format=raw,if=none -device ide-hd,drive=disk,bus=ide.1 -device ide-cd,drive=cdrom -drive id=cdrom,file=os.iso,media=cdrom,if=none DEPENDS os.iso)
add_custom_target(debug COMMAND ../debug.sh DEPENDS os.iso)

View file

@ -27,6 +27,16 @@ static inline unsigned char inb(int port) {
return val;
}
static inline void outl(uint32_t port, uint32_t val) {
__asm__ volatile("outl %k0, %k1" : : "a"(val), "Nd"(port) : "memory");
}
static inline uint32_t inl(uint32_t port) {
uint32_t val;
__asm__ volatile("inl %k1, %k0" : "=a"(val) : "Nd"(port) : "memory");
return val;
}
static inline void interrupt_disable() { __asm__ volatile("cli"); }
static inline void interrupt_enable() { __asm__ volatile("sti"); }

View file

@ -10,6 +10,7 @@ enum irq_code_t {
IRQCODE_PIT = 32,
IRQCODE_PS2 = 33,
IRQCODE_SYSCALL = 128,
IRQCODE_COM1 = 36,
};
void kb_handler() {
@ -69,6 +70,13 @@ void irq_handler(struct regs *r) {
kb_handler();
break;
};
case IRQCODE_COM1: {
char c = serial_rx();
c = c == '\r' ? '\n' : c;
c = c == 127 ? '\b' : c;
handle_keypress_char(c);
break;
};
}
// Send EOI to follower controller

36
kernel/drivers/serial.c Normal file
View file

@ -0,0 +1,36 @@
#pragma once
#include "../../arch/i386/asm.c"
#define COM1 (0x3F8)
int serial_init() {
outb(COM1 + 1, 0x01);
outb(COM1 + 3, 0x80);
outb(COM1 + 0, 0x03);
outb(COM1 + 1, 0x00);
outb(COM1 + 3, 0x03);
outb(COM1 + 2, 0xC7);
outb(COM1 + 4, 0x0B);
outb(COM1 + 4, 0x0F);
return 0;
}
int serial_has_tx() {
return inb(COM1 + 5) & 0x20;
}
int serial_has_rx() {
return inb(COM1 + 5) & 1;
}
void serial_tx(char a) {
while (serial_has_tx() == 0);
outb(COM1,a);
}
char serial_rx() {
while (serial_has_rx() == 0);
return inb(COM1);
}

View file

@ -1,6 +1,8 @@
#include "./drivers/serial.c"
#include "./pci.c"
#include "./rsdp.c"
#include "./scheduler.c"
#include "./vga.c"
#include "./rsdp.c"
#include <stdint.h>
#include "./test_processes.c"
@ -14,10 +16,10 @@ int kernel_main() {
outb(0x3D4, 0x0A);
outb(0x3D5, 0x20);
serial_init();
find_rsdp();
for(;;){}
pci_enumerate_devices();
clear_screen();
interrupt_disable();
@ -26,8 +28,8 @@ int kernel_main() {
init_process_table();
start_process("razzle", (char *) &test_razzle);
start_process("dazzle", (char *) &test_dazzle);
start_process("razzle", (char *)&test_razzle);
start_process("dazzle", (char *)&test_dazzle);
interrupt_enable();

View file

@ -3,7 +3,7 @@
#include <stdint.h>
// Below doesn't work!
//uint8_t streq(char *ptr, char* ptr2) {
// uint8_t streq(char *ptr, char* ptr2) {
// while (1 == 1) {
// if (*ptr != *ptr2) {
// return 0;
@ -20,13 +20,23 @@
uint8_t memseq(char *ptr, char *ptr2, uint32_t len) {
for (uint32_t i = 0; i < len; i++) {
if (ptr[i] != ptr2[i]) {
return 0;
}
if (ptr[i] != ptr2[i]) {
return 0;
}
}
return 1;
}
uint8_t streq(char *str, char *str2) {
for (uint32_t i = 0;; i++) {
if (str[i] != str2[i]) {
return 0;
} else if (str[i] == '\0' && str2[i] == '\0') {
return 1;
}
}
}
void memset(char *ptr, char data, uint32_t len) {
for (uint32_t i = 0; i < len; i++) {
ptr[i] = data;

220
kernel/pci.c Normal file
View file

@ -0,0 +1,220 @@
#pragma once
#include "./pci_supp.c"
#include "vga.c"
#include <stdint.h>
#ifdef ARCH_I386
#include "../arch/i386/asm.c"
#endif
#define PCI_NO_VENDOR (0xFFFF)
#define PCI_MAX_NAMESIZE (128)
#define PCI_MAX_DEVICES (256)
struct pci_device {
uint16_t device_id;
uint16_t vendor_id;
char device_name[PCI_MAX_NAMESIZE];
char vendor_name[PCI_MAX_NAMESIZE];
uint32_t bar[6];
uint8_t class_code;
uint8_t subclass_code;
};
static struct pci_device pci_devices_list[PCI_MAX_DEVICES];
static uint32_t pci_devices_count;
uint16_t pci_read_config(uint8_t bus, uint8_t slot, uint8_t function,
uint8_t offset) {
uint32_t address = ((bus << 16) | (slot << 11) | (function << 8) |
(offset & 0xFC) | (8 << 28));
outl(0xCF8, address);
return (uint16_t)((inl(0xCFC) >> ((offset & 2) * 8)) & 0xFFFF);
}
enum PCI_PARSE_STATE {
PPS_NUM_1,
PPS_NUM_2,
PPS_NUM_3,
PPS_NUM_4,
PPS_SP,
PPS_NAME,
PPS_NEXTLN,
PPS_TAB
};
enum PCI_PARSE_SSTATE { PPSS_VENDOR, PPSS_DEVICE };
uint32_t ascii_byte_to_num(char c) {
if (c >= '0' && c <= '9') {
return 0x0 + (c - '0');
} else if (c >= 'A' && c <= 'F') {
return 0xA + (c - 'A');
} else if (c >= 'a' && c <= 'f') {
return 0xA + (c - 'a');
} else {
return -1;
}
}
void pci_get_vendor_dev_name(uint16_t vendor_id, uint16_t device_id,
char *vendor_name, char *device_name) {
int len = ___build_supp_pci_pci_ids_len;
unsigned char *buf = &___build_supp_pci_pci_ids[0];
int pps = PPS_NUM_1;
int ppss = PPSS_VENDOR;
int j = 0;
for (int i = 0; i < len; ++i) {
// if we encounter newline, reset state
if (buf[i] == '\n') {
if (pps == PPS_NAME && ppss == PPSS_VENDOR) {
ppss = PPSS_DEVICE;
pps = PPS_TAB;
vendor_name[j] = '\0';
j = 0;
}
if (pps == PPS_NAME && ppss == PPSS_DEVICE) {
device_name[j] = '\0';
return;
}
pps = ppss == PPSS_VENDOR ? PPS_NUM_1 : PPS_TAB;
continue;
}
// If we're waiting for next line, don't do anything else
if (pps == PPS_NEXTLN)
continue;
// If we see a tab, we don't want to read device ids, so
// just ignore
if (buf[i] == '\t' && ppss == PPSS_VENDOR) {
pps = PPS_NEXTLN;
continue;
}
// If we see a tab, we don't want to read device ids, so
// just ignore
if (buf[i] == '\t' && ppss == PPSS_DEVICE) {
if (pps == PPS_TAB) {
pps = PPS_NUM_1;
} else {
pps = PPS_NEXTLN;
}
continue;
}
// If we see a comment, ignore
if (buf[i] == '#' && pps == PPS_NUM_1) {
pps = PPS_NEXTLN;
continue;
}
uint32_t tablenum = ascii_byte_to_num(buf[i]);
uint32_t vid = ppss == PPSS_VENDOR ? vendor_id : device_id;
switch (pps) {
case PPS_NUM_1:
vid = (vid >> 12) & 0xF;
if (vid == tablenum) {
pps = PPS_NUM_2;
} else {
pps = PPS_NEXTLN;
}
break;
case PPS_NUM_2:
vid = (vid >> 8) & 0xF;
if (vid == tablenum) {
pps = PPS_NUM_3;
} else {
pps = PPS_NEXTLN;
}
break;
case PPS_NUM_3:
vid = (vid >> 4) & 0xF;
if (vid == tablenum) {
pps = PPS_NUM_4;
} else {
pps = PPS_NEXTLN;
}
break;
case PPS_NUM_4:
vid = vid & 0xF;
if (vid == tablenum) {
pps = PPS_SP;
} else {
pps = PPS_NEXTLN;
}
break;
case PPS_SP:
if (buf[i + 1] == ' ') {
pps = PPS_SP;
} else {
pps = PPS_NAME;
}
break;
case PPS_NAME:
if (ppss == PPSS_VENDOR) {
vendor_name[j] = buf[i];
j++;
} else {
device_name[j] = buf[i];
j++;
}
break;
}
}
device_name[0] = '\0';
vendor_name[0] = '\0';
}
struct pci_device pci_get_device(uint8_t bus, uint8_t slot) {
struct pci_device found_dev;
found_dev.vendor_id = pci_read_config(bus, slot, 0, 0);
found_dev.device_id = pci_read_config(bus, slot, 0, 2);
if (found_dev.vendor_id != PCI_NO_VENDOR) {
pci_get_vendor_dev_name(found_dev.vendor_id, found_dev.device_id,
&found_dev.vendor_name[0],
&found_dev.device_name[0]);
for (uint8_t i = 0; i < 6; i++) {
found_dev.bar[i] =
(uint32_t)(pci_read_config(bus, slot, 0, 0x12 + (i * 4)) << 16) |
(pci_read_config(bus, slot, 0, 0x10 + (i * 4)));
}
uint16_t class_subclass = pci_read_config(bus, slot, 0, 4);
found_dev.class_code = class_subclass & 0xFF;
found_dev.subclass_code = (class_subclass >> 8) & 0xFF;
}
if (found_dev.vendor_name[0] == '\0' ||
found_dev.vendor_id == PCI_NO_VENDOR) {
strncpy("Unknown Vendor", &found_dev.vendor_name[0], 15);
strncpy("Unknown Device", &found_dev.device_name[0], 15);
}
return found_dev;
}
void pci_enumerate_devices() {
for (uint8_t bus = 0;; ++bus) {
for (uint8_t slot = 0;; ++slot) {
struct pci_device dev = pci_get_device(bus, slot);
if (dev.vendor_id != PCI_NO_VENDOR) {
pci_devices_list[pci_devices_count++] = dev;
printf_nolock("pci: %d.%d: PCI device found bus %d slot %d vendor %x, "
"device %x (%d %d)\n",
bus, slot, bus, slot, dev.vendor_id, dev.device_id,
dev.class_code, dev.subclass_code);
printf_nolock("pci: %d.%d: %s %s\n", bus, slot, dev.vendor_name,
dev.device_name);
}
if (slot == 255)
break;
}
if (bus == 255)
break;
}
}

124888
kernel/pci_supp.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -258,6 +258,18 @@ void init_ps2() {
}
}
void handle_keypress_char(char c) {
if (c != '\0') {
for(uint32_t i = 0; i < MAX_PROCESSES; i++) {
if(ps2_waiters[i].alloc) {
process_table[ps2_waiters[i].pid].registers.eax = c;
ps2_waiters[i].alloc = 0;
process_table[ps2_waiters[i].pid].state = TASKSTATE_ready;
}
}
}
}
void handle_keypress(uint8_t char_code) {
struct key_event_t event;
if ((char_code & 0b11000000) == 0b10000000) {
@ -286,15 +298,7 @@ void handle_keypress(uint8_t char_code) {
default: {
if (event.is_down) {
char c = keycode_to_char(event.key);
if (c != '\0') {
for(uint32_t i = 0; i < MAX_PROCESSES; i++) {
if(ps2_waiters[i].alloc) {
process_table[ps2_waiters[i].pid].registers.eax = c;
ps2_waiters[i].alloc = 0;
process_table[ps2_waiters[i].pid].state = TASKSTATE_ready;
}
}
}
handle_keypress_char(c);
}
break;
}

112
kernel/rsdp.c Normal file
View file

@ -0,0 +1,112 @@
#pragma once
#include <stdint.h>
#include "memory.c"
#include "vga.c"
struct rsdp_t {
char signature[8];
uint8_t checksum;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
} __attribute__ ((packed));
struct xsdp_t {
char signature[8];
uint8_t checksum;
char oem_id[6];
uint8_t revision;
uint32_t unused;
uint32_t length;
uint32_t xsdt_addr_hi;
uint32_t xsdt_addr_lo;
uint8_t checksum_ext;
uint8_t unused_[3];
} __attribute__ ((packed));
struct acpi_header_t {
char signature[4];
uint32_t length;
uint8_t revision;
uint8_t checksum;
char oem_id[6];
char oem_table_id[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_division;
} __attribute__ ((packed));
struct rsdt_t {
struct acpi_header_t header;
uint32_t pointer[64];
};
uint8_t validate(struct rsdp_t *ptr) {
char sig[] = "RSD PTR ";
if (!memseq(ptr->signature, sig, 8)) return 0;
uint8_t *rsdp_bytes = (uint8_t *) ptr;
uint8_t sum = 0;
for(uint8_t i = 0; i < 20; i++) {
sum += rsdp_bytes[i];
}
if (sum == 0 && ptr->revision == 2) {
printf_nolock("acpi: ACPI v2+ not yet supported :(\n");
for(;;){}
// TODO: test with ACPI 2 System
struct xsdp_t *r2_ptr = (struct xsdp_t*) ptr;
uint8_t *xsdp_bytes = ((uint8_t *) r2_ptr) + 8;
for(uint8_t i = 0; i < 16; i++) {
sum += xsdp_bytes[i];
}
}
return sum == 0;
}
char* find_table(struct rsdt_t* table, char* sig) {
uint32_t entries = (table->header.length - sizeof table->header) / 4;
for (uint32_t i = 0; i < entries; i++) {
struct acpi_header_t* entry = (struct acpi_header_t*) table->pointer[i];
if (memseq(entry->signature, sig, 4)) {
printf_nolock("Found %s / %s\n", entry->oem_id, entry->signature);
printf_nolock("Signature: %s\n", entry->signature);
printf_nolock("Length : %d\n", entry->length);
printf_nolock("Oem ID : %s\n", entry->oem_id);
printf_nolock("Checksum : %d\n", entry->checksum);
return (void*)entry;
}
}
printf_nolock("Not Found");
return 0;
}
void find_rsdp() {
struct rsdp_t *ptr;
volatile uint8_t found = 0;
for (uint32_t addr = 0x00000000; addr <= 0x000FFFFF; addr++) {
ptr = (struct rsdp_t *) addr;
if (validate(ptr)) {
found = 1;
break;
}
}
if (!found) {
uint8_t* ebda = (uint8_t*)(*((uint16_t*)0x40e) << 4);
for (uint32_t i = 0; i <= 1024; i += 16) {
ptr = (struct rsdp_t*) ebda;
if (validate(ptr)) {
found = 1;
break;
}
}
}
printf_nolock("acpi: RSDP Found [OEM: %s, SIG: %s]\n", ptr->oem_id, ptr->signature);
}

View file

@ -14,6 +14,7 @@
enum task_state_t { TASKSTATE_unused, TASKSTATE_ready, TASKSTATE_blocked };
struct task_struct {
uint32_t pid;
enum task_state_t state;
struct regs registers;
unsigned int address_base;
@ -59,6 +60,7 @@ void start_process(char *name, char *entrypoint) {
process_table[pid].allocd_addr = (char *)process_table[pid].address_base;
process_table[pid].state = TASKSTATE_ready;
process_table[pid].process_name = balloc_pid(16, pid);
process_table[pid].pid = pid;
strncpy(name, process_table[pid].process_name, 16);
initialize_registers(&process_table[pid].registers, entrypoint,

View file

@ -2,12 +2,14 @@
#include "scheduler.c"
#include "ps2.c"
#include "pci.c"
#include "vga.c"
#ifdef ARCH_I386
#include "../arch/i386/syscall.c"
#endif
enum syscall_type_d { SYSCALL_yield, SYSCALL_getc, SYSCALL_exit };
enum syscall_type_d { SYSCALL_yield, SYSCALL_getc, SYSCALL_exit, SYSCALL_lspci, SYSCALL_lsproc };
void yield() { INVOKE_SYSCALL(SYSCALL_yield); }
char getc() {
@ -19,6 +21,53 @@ char getc() {
: "=r"(result)
);
return result;
}
uint32_t lspci(struct pci_device* devlist, uint32_t len) {
int result = 0;
__asm__ volatile (
"movl %0, %%ebx"
: : "r"((uint32_t) devlist) : "%ebx"
);
__asm__ volatile (
"movl %0, %%ecx"
: : "r"(len) : "%ecx"
);
INVOKE_SYSCALL(SYSCALL_lspci);
__asm__ volatile (
"movl %%eax, %k0"
: "=r"(result)
);
return result;
}
uint32_t lsproc(struct task_struct* proclist, uint32_t len) {
int result = 0;
__asm__ volatile (
"movl %0, %%ebx"
: : "r"((uint32_t) proclist) : "%ebx"
);
__asm__ volatile (
"movl %0, %%ecx"
: : "r"(len) : "%ecx"
);
INVOKE_SYSCALL(SYSCALL_lsproc);
__asm__ volatile (
"movl %%eax, %k0"
: "=r"(result)
);
return result;
}
@ -35,6 +84,7 @@ void syscall(struct regs *r) {
int syscall_no = r->eax;
switch (syscall_no) {
case SYSCALL_yield: {
__syscall_yield(r);
break;
@ -55,6 +105,37 @@ void syscall(struct regs *r) {
break;
};
case SYSCALL_lspci: {
uint32_t len = r->ecx;
len = len < pci_devices_count ? len : pci_devices_count;
struct pci_device* devlist = (struct pci_device*) r->ebx;
for (uint32_t i = 0; i < len; ++i) {
devlist[i] = pci_devices_list[i];
}
r->eax = len;
break;
};
case SYSCALL_lsproc: {
uint32_t len = r->ecx;
struct task_struct*proclist = (struct task_struct*) r->ebx;
uint32_t i = 0, j = 0;
for (; i < len; ++i, ++j) {
for(; j < MAX_PROCESSES && process_table[j].state == TASKSTATE_unused; ++j) {}
if (j == MAX_PROCESSES) break;
proclist[i] = process_table[j];
}
r->eax = i;
break;
};
case SYSCALL_exit: {
process_table[current_pid].state = TASKSTATE_unused;
__syscall_yield(r);

View file

@ -8,23 +8,29 @@
#include "./scheduler.c"
#include "./spin_lock.c"
#include "./syscall.c"
#include "./vga.c"
#include "./scheduler.c"
uint32_t lock2 = 0;
uint32_t counter;
void test_razzle() {
for (uint32_t i = 0;; i++) {
sl_acquire(&lock2);
row = 1;
col = 0;
printf("%s (pid %d): %u \n", process_table[current_pid].process_name,
current_pid, i);
counter = 0;
sl_release(&lock2);
for (;;) {
sl_acquire(&lock2);
counter++;
//row = 1;
//col = 0;
//printf("%s (pid %d): %u \n", process_table[current_pid].process_name,
// current_pid, i);
sl_release(&lock2);
yield();
}
}
void cpuid() {
void sh_cpuid() {
char model[13];
uint32_t res[3];
__asm__ volatile ("mov $0, %%eax; cpuid; mov %%ebx, %0; mov %%edx, %1; mov %%ecx, %2;" : "=r" (res[0]), "=r" (res[1]), "=r" (res[2]) ::"ebx", "ecx", "edx");
@ -35,61 +41,92 @@ void cpuid() {
model[(i*4) + 3] = (res[i] >> 24) & 0xFF;
}
model[12] = '\0';
printf("%s", model);
printf("%s\n", model);
}
void sh_lspci() {
struct pci_device devlist[7];
int devices = lspci(&devlist[0], 7);
for(int j = 0; j < devices; ++j) {
printf("%s %s (%d %d)\n", devlist[j].vendor_name, devlist[j].device_name, devlist[j].class_code, devlist[j].subclass_code);
printf("Device ID: %x\n", devlist[j].device_id);
printf("Vendor ID: %x\n", devlist[j].vendor_id);
printf("Bar 5 : %x %u\n\n", devlist[j].bar[5], devlist[j].bar[5]);
}
}
void sh_lsproc() {
struct task_struct proclist[7];
int procs = lsproc(&proclist[0], 7);
for(int j = 0; j < procs; ++j) {
switch (proclist[j].state) {
case TASKSTATE_ready:
printf("R");
break;
case TASKSTATE_blocked:
printf("B");
break;
default:
printf("?");
break;
}
printf(" %d: %s", proclist[j].pid, proclist[j].process_name);
printf("\n");
}
}
void test_dazzle() {
char prompt[] = "you@razzle ~$";
char prompt[] = "you@razzle ~$ ";
char command[2048];
uint32_t cr = 2;
printf("%s", prompt);
for (uint32_t i = sizeof(prompt);;) {
uint32_t i = 0;
for (;;) {
char c = getc();
sl_acquire(&lock2);
row = cr;
col = i;
switch(c) {
case '\b':
if (i == 0) {
i = 79;
cr--;
} else {
i--;
}
col = i;
row = cr;
printf(" ");
command[i--] = '\0';
printf("\b \b");
break;
case '\n':
command[i] = '\0';
i = 0;
cr++;
row++;
col = 0;
cpuid();
cr++;
col = i;
row = cr;
printf("\n");
if (streq(command, "lspci")) {
sh_lspci();
} else if (streq(command, "cpuid")) {
sh_cpuid();
} else if (streq(command, "help")) {
printf("dazzle, the shell for RAZZLE\n");
printf("--------------------------------------------------------\n");
printf("help : print this menu\n");
printf("cpuid : print CPU vendor id string\n");
printf("lspci : print list of PCI devices\n");
printf("lsproc : print list of running processes\n");
printf("counter : print counter maintained by background process\n");
} else if (streq(command, "counter")) {
printf("%d\n", counter);
} else if (streq(command, "lsproc")) {
sh_lsproc();
} else {
printf("Unknown command\n");
}
printf("%s", prompt);
i = sizeof(prompt);
break;
default:
printf("%c", c);
command[((cr-2)*80) + i] = c;
i++;
command[i++] = c;
break;
}
if (i >= 80) {
i = 0;
cr++;
}
sl_release(&lock2);
yield();
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "./spin_lock.c"
#include "./drivers/serial.c"
#include <stdarg.h>
#include <stdint.h>
@ -36,6 +37,7 @@ void putc(char c) {
}
row = (row + 1) % HEIGHT;
col = 0;
serial_tx('\n');
return;
}
@ -43,12 +45,15 @@ void putc(char c) {
col--;
vram[(row * WIDTH * 2) + (col * 2)] = ' ';
vram[(row * WIDTH * 2) + (col * 2 + 1)] = color_code;
serial_tx('\b');
return;
}
vram[(row * WIDTH * 2) + (col * 2)] = c;
vram[(row * WIDTH * 2) + (col * 2 + 1)] = color_code;
col++;
serial_tx(c);
}
void print_uint(unsigned int x, uint8_t base) {
@ -79,13 +84,18 @@ void print_int(int x, uint8_t base) {
}
}
void print_hex(int x) {
void print_hex(uint32_t x) {
putc('0');
putc('x');
uint8_t fp = 1;
do {
unsigned int digit = (x & 0xF0000000) >> 28;
putc((digit < 10) ? (digit + '0') : (digit - 10 + 'A'));
uint32_t digit = (x & 0xF0000000) >> 28;
if (digit != 0 || !fp || x == 0) {
putc((digit < 10) ? (digit + '0') : (digit - 10 + 'A'));
fp = 0;
}
x <<= 4;
} while (x != 0);
}