0.0.2d: Added BGA support, graphics!
This commit is contained in:
31
Makefile
31
Makefile
@ -12,9 +12,11 @@ NASMFLAGS := -f elf32
|
||||
WNOFLAGS := -Wno-discarded-qualifiers
|
||||
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS) -nostdlib -nostartfiles -include include/kincl.h
|
||||
LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib -nostartfiles
|
||||
QEMUFLAGS := -no-shutdown -boot d -cdrom $(ISO) -drive file=$(FAT16_DISK),format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1
|
||||
QEMUFLGS_EXT := -vga std -d int,cpu_reset -D qemu.log # -audiodev pa,id=speaker -machine pcspk-audiodev=speaker
|
||||
QEMUFLAGS := -no-shutdown -drive file=$(FAT16_DISK),format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1
|
||||
QEMUFLGS_EXT := -vga std
|
||||
MOR_QEMUFLGS := -net none -netdev user,id=n0 -device rtl8139,netdev=n0 -serial file:serial.log
|
||||
QEMU_BOOT_FLG := -boot d -cdrom $(ISO)
|
||||
QEMU_BOOT_RPI := -kernel $(TARGET)
|
||||
SRC_DIRS := kernel drivers lib
|
||||
INCLUDE_DIRS := include
|
||||
ARCH_DIR := arch
|
||||
@ -26,6 +28,9 @@ BOOT_DIR := $(ISO_DIR)/boot
|
||||
GRUB_DIR := $(BOOT_DIR)/grub
|
||||
GRUB_CFG := grub.cfg
|
||||
|
||||
# === Host checks ===
|
||||
IS_RPI := $(shell [ -f /proc/device-tree/model ] && grep -qi "Raspberry Pi" /proc/device-tree/model && echo 1 || echo 0)
|
||||
|
||||
# === File collection ===
|
||||
C_SRCS := $(foreach dir, $(SRC_DIRS), $(shell find $(dir) -name '*.c'))
|
||||
S_SRCS := $(foreach dir, $(ARCH_DIR), $(shell find $(dir) -name '*.s'))
|
||||
@ -73,9 +78,11 @@ $(TARGET): ./arch/x86/boot/boot.o $(filter-out boot.o, $(OBJ_LINK_LIST))
|
||||
iso: $(TARGET)
|
||||
@grub-file --is-x86-multiboot $(TARGET) && echo "multiboot confirmed" || (echo "not multiboot" && exit 1)
|
||||
mkdir -p $(GRUB_DIR)
|
||||
cp $(TARGET) $(BOOT_DIR)/
|
||||
cp $(GRUB_CFG) $(GRUB_DIR)/
|
||||
cp $(TARGET) $(BOOT_DIR)
|
||||
ifneq ($(IS_RPI),1)
|
||||
cp $(GRUB_CFG) $(GRUB_DIR)
|
||||
grub-mkrescue -o $(ISO) $(ISO_DIR)
|
||||
endif
|
||||
|
||||
# === Run in QEMU ===
|
||||
run: iso
|
||||
@ -83,8 +90,12 @@ run: iso
|
||||
$(QEMU_MKE_IMG); \
|
||||
sudo mkfs.fat $(MKFS_FLAGS) espresso.img; \
|
||||
fi
|
||||
@echo
|
||||
qemu-system-i386 $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS)
|
||||
@echo $(IS_RPI)
|
||||
ifeq ($(IS_RPI),1)
|
||||
qemu-system-i386 $(QEMU_BOOT_RPI) $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS)
|
||||
else
|
||||
qemu-system-i386 $(QEMU_BOOT_FLG) $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS)
|
||||
endif
|
||||
|
||||
|
||||
# === Clean all build artifacts ===
|
||||
@ -99,9 +110,15 @@ clean_disk:
|
||||
commit:
|
||||
ifndef MSG
|
||||
$(error MSG required)
|
||||
endif
|
||||
ifndef RELEASENUM
|
||||
$(error RELEASENUM required)
|
||||
endif
|
||||
git add .
|
||||
git commit -m "$(MSG)"
|
||||
git push
|
||||
git push origin main
|
||||
|
||||
git tag -a "$(RELEASENUM)" -m "Espresso $(RELEASENUM)"
|
||||
git push origin "$(RELEASENUM)"
|
||||
|
||||
.PHONY: all clean clean_disk iso run debug build buildc
|
||||
|
||||
@ -1 +0,0 @@
|
||||
I'm back (maybe?)
|
||||
@ -11,7 +11,7 @@
|
||||
#define ALIGN_UP(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
||||
|
||||
|
||||
elf_executable_t* load_elf32(void* elf_data)
|
||||
int load_elf32(void* elf_data, elf_executable_t** ptr)
|
||||
{
|
||||
Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;
|
||||
|
||||
@ -19,13 +19,13 @@ elf_executable_t* load_elf32(void* elf_data)
|
||||
if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
|
||||
{
|
||||
printf("Invalid ELF file\n");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ehdr->e_machine != 3 || ehdr->e_type != 2)
|
||||
{
|
||||
printf("Unsupported ELF type or architecture\n");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Elf32_Phdr* phdrs = (Elf32_Phdr*)((uint8_t*)elf_data + ehdr->e_phoff);
|
||||
@ -60,10 +60,17 @@ elf_executable_t* load_elf32(void* elf_data)
|
||||
#endif
|
||||
}
|
||||
|
||||
elf_executable_t* result = malloc(sizeof(elf_executable_t));
|
||||
result->entry_point = (elf_entry_t)(uintptr_t)ehdr->e_entry;
|
||||
return result;
|
||||
*ptr = malloc(sizeof(elf_executable_t));
|
||||
|
||||
return NULL;
|
||||
if (ptr)
|
||||
{
|
||||
(*ptr)->entry_point = (elf_entry_t)(uintptr_t) ehdr->e_entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
elf_executable_t* result = malloc(sizeof(elf_executable_t));
|
||||
result->entry_point = (elf_entry_t)(uintptr_t)ehdr->e_entry;*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
#include <types.h>
|
||||
#include <string.h>
|
||||
#include <drivers/ide.h>
|
||||
|
||||
#include <fs/ekfs.h>
|
||||
|
||||
/* work on this later */
|
||||
#if 0
|
||||
|
||||
/* note: __l being 0 is allowed, because that way read() can be used to tell if a file exists (with return value 0) */
|
||||
int ekfs_read(struct ekfs_file* __f, void* __b, size_t __l)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (!__f || !__b || (!__f->f_inode))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we assume drive 0 is already mounted */
|
||||
|
||||
char buffer[512];
|
||||
memset(buffer, 0, 512);
|
||||
|
||||
int num_sectors = __f->f_inode->i_len / 512;
|
||||
|
||||
if ((__l / 512) > num_sectors)
|
||||
{
|
||||
return EKFS_E_FILETOOSMALL;
|
||||
}
|
||||
|
||||
int read_sectors = num_sectors;
|
||||
|
||||
for (int i = 0; i < read_sectors; i++);
|
||||
{
|
||||
rv = read_sector(__f->f_inode->i_start, buffer);
|
||||
|
||||
if (rv != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -20,6 +20,8 @@ int fat16_mount(uint8_t drive)
|
||||
return -1;
|
||||
}
|
||||
|
||||
(void) drive;
|
||||
|
||||
fs.bytes_per_sector = boot_sector[11] | (boot_sector[12] << 8);
|
||||
fs.sectors_per_cluster = boot_sector[13];
|
||||
fs.reserved_sector_count = boot_sector[14] | (boot_sector[15] << 8);
|
||||
@ -53,7 +55,7 @@ static int read_fat_entry(uint16_t cluster, uint16_t* out_value)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (idx == fs.bytes_per_sector - 1)
|
||||
if (idx == (uint32_t)(fs.bytes_per_sector - 1))
|
||||
{
|
||||
/* entry spans boundary -> read next sector */
|
||||
uint8_t next_sector[SECTOR_SIZE];
|
||||
|
||||
@ -7,25 +7,7 @@
|
||||
|
||||
/* we use something similar to the Linux kernel in terms of a VFS system */
|
||||
|
||||
#define MAX_FDS 64
|
||||
|
||||
struct inode {
|
||||
size_t size;
|
||||
int permissions;
|
||||
void *fs_data; /* FS-specific */
|
||||
};
|
||||
|
||||
struct file_ops {
|
||||
int (*read)(struct file*, char*, size_t);
|
||||
int (*write)(struct file*, const char*, size_t);
|
||||
};
|
||||
|
||||
struct file {
|
||||
struct inode* f_inode;
|
||||
size_t f_offset;
|
||||
size_t f_refcount;
|
||||
const struct file_ops f_ops;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -35,17 +17,9 @@ struct fdtable {
|
||||
|
||||
|
||||
|
||||
int vfs_handle_stdout(struct file* __f, const char* __s, size_t __l)
|
||||
{
|
||||
(void) __f;
|
||||
terminal_write(__s, __l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct fdtable* vfs_init_kernel_fdtable(void)
|
||||
{
|
||||
#if 0
|
||||
struct fdtable* ft = malloc(sizeof(struct fdtable));
|
||||
struct file* _stdout = malloc(sizeof(struct file));
|
||||
struct file* _stdin = malloc(sizeof(struct file));
|
||||
@ -59,9 +33,9 @@ struct fdtable* vfs_init_kernel_fdtable(void)
|
||||
_stdout->f_offset = 0;
|
||||
_stdout->f_refcount = 1;
|
||||
_stdout->f_ops = { .read = NULL, .write = vfs_handle_stdout };
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int init_vfs(int argc, char** argv)
|
||||
{
|
||||
|
||||
173
drivers/graphics/vga.c
Normal file
173
drivers/graphics/vga.c
Normal file
@ -0,0 +1,173 @@
|
||||
#include <types.h>
|
||||
#include <mm/paging.h>
|
||||
#include <stdio.h>
|
||||
#include <port_io.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <drivers/graphics/vga.h>
|
||||
|
||||
#define VBE_DISPI_IOPORT_INDEX 0x01CE
|
||||
#define VBE_DISPI_IOPORT_DATA 0x01CF
|
||||
|
||||
#define VBE_DISPI_INDEX_ID 0x0
|
||||
#define VBE_DISPI_INDEX_XRES 0x1
|
||||
#define VBE_DISPI_INDEX_YRES 0x2
|
||||
#define VBE_DISPI_INDEX_BPP 0x3
|
||||
#define VBE_DISPI_INDEX_ENABLE 0x4
|
||||
#define VBE_DISPI_INDEX_BANK 0x5
|
||||
#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
|
||||
#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
|
||||
#define VBE_DISPI_INDEX_X_OFFSET 0x8
|
||||
#define VBE_DISPI_INDEX_Y_OFFSET 0x9
|
||||
|
||||
#define VBE_DISPI_DISABLED 0x00
|
||||
#define VBE_DISPI_ENABLED 0x01
|
||||
#define VBE_DISPI_LFB_ENABLED 0x40
|
||||
|
||||
static bool bga_init = false;
|
||||
static bool bga_error = false;
|
||||
|
||||
uint32_t current_bpp = 0;
|
||||
uint32_t current_xres = 0;
|
||||
uint32_t current_yres = 0;
|
||||
|
||||
static struct bga_framebuffer bga_fb;
|
||||
|
||||
void init_bga_framebuffer(uint32_t* _p)
|
||||
{
|
||||
uint32_t width = 1024;
|
||||
uint32_t height = 768;
|
||||
uint32_t bpp = 32;
|
||||
|
||||
uint32_t pitch = width * (bpp / 8);
|
||||
|
||||
uint32_t fb_size = pitch * height;
|
||||
|
||||
fb_size = (fb_size + 0xFFF) & ~0xFFF;
|
||||
|
||||
uint8_t* bp = (uint8_t*) _p;
|
||||
|
||||
for (uint32_t off = 0; off < fb_size; off += 0x1000)
|
||||
{
|
||||
map_page(bp + off, bp + off);
|
||||
}
|
||||
|
||||
|
||||
bga_fb.addr = _p;
|
||||
bga_fb.bpp = bpp;
|
||||
bga_fb.height = height;
|
||||
bga_fb.width = width;
|
||||
bga_fb.pitch = pitch;
|
||||
|
||||
bga_init = true;
|
||||
}
|
||||
|
||||
uint8_t* bga_get_framebuffer(void)
|
||||
{
|
||||
return bga_fb.addr;
|
||||
}
|
||||
|
||||
void bga_write_register(uint16_t index, uint16_t data)
|
||||
{
|
||||
outw(VBE_DISPI_IOPORT_INDEX, index);
|
||||
outw(VBE_DISPI_IOPORT_DATA, data);
|
||||
}
|
||||
|
||||
uint16_t bga_read_register(uint16_t index)
|
||||
{
|
||||
outw(VBE_DISPI_IOPORT_INDEX, index);
|
||||
return inw(VBE_DISPI_IOPORT_DATA);
|
||||
}
|
||||
|
||||
void bga_set_video_mode(uint32_t width, uint32_t height, uint32_t bit_depth)
|
||||
{
|
||||
bga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
|
||||
bga_write_register(VBE_DISPI_INDEX_XRES, width);
|
||||
bga_write_register(VBE_DISPI_INDEX_YRES, height);
|
||||
bga_write_register(VBE_DISPI_INDEX_BPP, bit_depth);
|
||||
bga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
|
||||
|
||||
/* now we check to see if any info we gave was rejected, in which case everything would be the way it was before we wrote the configuration info. */
|
||||
uint16_t bpp = bga_read_register(VBE_DISPI_INDEX_BPP);
|
||||
if (bpp != bit_depth)
|
||||
{
|
||||
bga_error = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_bpp = bit_depth;
|
||||
current_xres = width;
|
||||
current_yres = height;
|
||||
}
|
||||
}
|
||||
|
||||
void bga_defaults(void)
|
||||
{
|
||||
// Disable device while changing settings
|
||||
bga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
|
||||
|
||||
// Set resolution
|
||||
bga_write_register(VBE_DISPI_INDEX_XRES, 1024);
|
||||
bga_write_register(VBE_DISPI_INDEX_YRES, 768);
|
||||
bga_write_register(VBE_DISPI_INDEX_BPP, 32);
|
||||
|
||||
// Enable graphics + linear framebuffer
|
||||
bga_write_register(
|
||||
VBE_DISPI_INDEX_ENABLE,
|
||||
VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
/*void bga_putpixel(uint32_t x, uint32_t y, uint32_t color)
|
||||
{
|
||||
if (current_bpp == 16)
|
||||
{
|
||||
uint16_t* fb = (uint16_t*) bga_framebuffer;
|
||||
uint32_t idx = (y * current_xres + x) * 2;
|
||||
|
||||
*(fb + idx) = (uint16_t) color;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
void bga_putpixel(uint32_t x, uint32_t y, uint32_t color)
|
||||
{
|
||||
uint32_t bytes_per_pixel = bga_fb.bpp / 8;
|
||||
|
||||
uint8_t* pixel = (uint8_t*)bga_fb.addr + (y * bga_fb.pitch) + (x * bytes_per_pixel);
|
||||
|
||||
*(volatile uint32_t*)pixel = color;
|
||||
}
|
||||
|
||||
void bga_drawline(int x0, int y0, int x1, int y1, uint32_t color)
|
||||
{
|
||||
int dx = abs(x1 - x0);
|
||||
int dy = abs(y1 - y0);
|
||||
|
||||
int sx = (x0 < x1) ? 1 : -1;
|
||||
int sy = (y0 < y1) ? 1 : -1;
|
||||
|
||||
int err = dx - dy;
|
||||
|
||||
while (1)
|
||||
{
|
||||
bga_putpixel(x0, y0, color);
|
||||
|
||||
if (x0 == x1 && y0 == y1)
|
||||
break;
|
||||
|
||||
int e2 = err * 2;
|
||||
|
||||
if (e2 > -dy)
|
||||
{
|
||||
err -= dy;
|
||||
x0 += sx;
|
||||
}
|
||||
|
||||
if (e2 < dx)
|
||||
{
|
||||
err += dx;
|
||||
y0 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,6 +35,12 @@ static int32_t ide_wait_ready(uint16_t io)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_sector_size(uint8_t drive)
|
||||
{
|
||||
(void) drive;
|
||||
return SECTOR_SIZE;
|
||||
}
|
||||
|
||||
int32_t ide_identify(uint8_t drive, uint16_t* buffer)
|
||||
{
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
|
||||
@ -61,7 +61,6 @@ int init_keyboard(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
registers_t* keyboard_handler(registers_t* regs)
|
||||
{
|
||||
if (!(inb(PS2_STATUS_PORT) & 1))
|
||||
@ -71,13 +70,77 @@ registers_t* keyboard_handler(registers_t* regs)
|
||||
|
||||
uint8_t scancode = inb(PS2_DATA_PORT);
|
||||
|
||||
if (scancode & 0x80)
|
||||
if (scancode == 0xE0)
|
||||
{
|
||||
extended = true;
|
||||
return regs;
|
||||
}
|
||||
|
||||
bool is_release = scancode & 0x80;
|
||||
uint8_t key = scancode & 0x7F;
|
||||
|
||||
if (extended)
|
||||
{
|
||||
if (is_release)
|
||||
{
|
||||
if (key == 0x1D)
|
||||
{
|
||||
mods &= ~MODIFIER_RCTRL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key == 0x1D)
|
||||
{
|
||||
mods |= MODIFIER_RCTRL;
|
||||
}
|
||||
}
|
||||
|
||||
/* delete key, should add this functionality */
|
||||
/*if (key == 0x53)*/
|
||||
|
||||
extended = false;
|
||||
return regs;
|
||||
}
|
||||
|
||||
if (is_release)
|
||||
{
|
||||
if (key == 0x2A || key == 0x36)
|
||||
{
|
||||
mods &= ~MODIFIER_SHIFT;
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key == 0x2A || key == 0x36)
|
||||
{
|
||||
mods |= MODIFIER_SHIFT;
|
||||
return regs;
|
||||
}
|
||||
else if (key == 0x3A)
|
||||
{
|
||||
mods ^= MODIFIER_CAPS;
|
||||
return regs;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t c = (uint16_t) scancode_map[scancode];
|
||||
|
||||
if (c)
|
||||
{
|
||||
//tty_receive_char(c, mods);
|
||||
char ch = tty_translate_char(c, mods);
|
||||
tty_input_char(tty_get_active(), ch);
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
|
||||
/* Handle shift press/release */
|
||||
if (scancode == 0x2A || scancode == 0x36)
|
||||
/*if (scancode == 0x2A || scancode == 0x36)
|
||||
{
|
||||
mods |= MODIFIER_SHIFT;
|
||||
return regs;
|
||||
@ -89,9 +152,11 @@ registers_t* keyboard_handler(registers_t* regs)
|
||||
}
|
||||
else if (scancode == 0x3A)
|
||||
{
|
||||
TOGGLE_BIT(mods, 0); /* TOGGLE_BIT defined in types.h, should move elsewhere. */
|
||||
TOGGLE_BIT(mods, 0);
|
||||
return regs;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
/*else if (scancode == 0xE0)
|
||||
{
|
||||
extended = true;
|
||||
@ -127,22 +192,10 @@ registers_t* keyboard_handler(registers_t* regs)
|
||||
return;
|
||||
}*/
|
||||
|
||||
bool release = scancode & 0x80;
|
||||
/*bool release = scancode & 0x80;
|
||||
scancode &= 0x7F;
|
||||
|
||||
if (release)
|
||||
{
|
||||
return regs;
|
||||
}
|
||||
|
||||
uint16_t c = (uint16_t) scancode_map[scancode];
|
||||
|
||||
if (c)
|
||||
{
|
||||
//tty_receive_char(c, mods);
|
||||
char ch = tty_translate_char(c, mods);
|
||||
tty_input_char(tty_get_active(), ch);
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
}*/
|
||||
|
||||
@ -33,11 +33,27 @@ static inline bool is_canonical(tty_t* tty)
|
||||
return (tty->flags & TTY_CANONICAL) != 0;
|
||||
}
|
||||
|
||||
static void raw_put(tty_t* tty, char c)
|
||||
{
|
||||
size_t next = (tty->raw_head + 1) % TTY_RAW_BUFFER_SIZE;
|
||||
|
||||
if (next != tty->raw_tail) // avoid overflow
|
||||
{
|
||||
tty->raw_buf[tty->raw_head] = c;
|
||||
tty->raw_head = next;
|
||||
}
|
||||
}
|
||||
|
||||
tty_t* tty_get_active(void)
|
||||
{
|
||||
return active_tty;
|
||||
}
|
||||
|
||||
int tty_fread(struct file* f, char* b, size_t s)
|
||||
{
|
||||
return (int) tty_read_active(b, s);
|
||||
}
|
||||
|
||||
void tty_backspace(tty_t* tty)
|
||||
{
|
||||
if (tty->head == tty->tail)
|
||||
@ -48,50 +64,88 @@ void tty_backspace(tty_t* tty)
|
||||
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) / TTY_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
void tty_and_flags(tty_t* tty, uint32_t flags)
|
||||
{
|
||||
tty->flags &= flags;
|
||||
}
|
||||
|
||||
uint32_t tty_get_flags(tty_t* tty)
|
||||
{
|
||||
return tty->flags;
|
||||
}
|
||||
|
||||
ssize_t tty_read_active(char* buf, size_t count)
|
||||
{
|
||||
return tty_read(active_tty, buf, count);
|
||||
}
|
||||
|
||||
/*ssize_t tty_read(tty_t* tty, char* buf, size_t count)
|
||||
/*
|
||||
this is special, because when this is called the char returned by this function
|
||||
is NOT added to the TTY buffer.
|
||||
This can be changed however by setting flag TTY_ADDCHAR_ALWAYS.
|
||||
*/
|
||||
/*char tty_get_char(void)
|
||||
{
|
||||
size_t bytes_read = 0;
|
||||
tty_t* tty = get_active_tty();
|
||||
if (!tty)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (bytes_read < count)
|
||||
while (1)
|
||||
{
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
if (!tty_empty(tty))
|
||||
if (tty->char_available)
|
||||
{
|
||||
char c = tty->input_buffer[tty->tail];
|
||||
tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE;
|
||||
tty->tail = next_index(tty->tail);
|
||||
char c = tty->last_char;
|
||||
tty->char_available = false;
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE(); /* change? *//*
|
||||
|
||||
buf[bytes_read++] = c;
|
||||
|
||||
if (is_canonical(tty) && c == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
return c;
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
}
|
||||
}*/
|
||||
|
||||
char tty_get_char(void)
|
||||
{
|
||||
tty_t* tty = get_active_tty();
|
||||
if (!tty)
|
||||
return 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
if (tty->raw_head != tty->raw_tail)
|
||||
{
|
||||
char c = tty->raw_buf[tty->raw_tail];
|
||||
tty->raw_tail = (tty->raw_tail + 1) % TTY_RAW_BUFFER_SIZE;
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t tty_read(tty_t* tty, char* buf, size_t count)
|
||||
{
|
||||
if (!tty || !buf)
|
||||
return -1;
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t bytes = 0;
|
||||
|
||||
@ -169,6 +223,9 @@ int init_tty(void)
|
||||
active_tty = t;
|
||||
num_ttys = 1;
|
||||
|
||||
t->f_ops.read = tty_fread;
|
||||
t->line_ready = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -238,15 +295,18 @@ void tty_receive_char(char c, uint32_t kbd_mod)
|
||||
}
|
||||
}
|
||||
|
||||
void tty_input_char(tty_t* tty, char c)
|
||||
/*void tty_input_char(tty_t* tty, char c)
|
||||
{
|
||||
if (!tty || c == 0)
|
||||
return;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
/* backspace */
|
||||
raw_put(tty, c);
|
||||
|
||||
if (c == '\b')
|
||||
{
|
||||
if (tty->head != tty->tail)
|
||||
@ -255,9 +315,7 @@ void tty_input_char(tty_t* tty, char c)
|
||||
|
||||
if (tty->flags & TTY_ECHO)
|
||||
{
|
||||
putc('\b');/*
|
||||
putc(' ');
|
||||
putc('\b');*/
|
||||
putc('\b');
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,6 +340,65 @@ void tty_input_char(tty_t* tty, char c)
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
if (tty->flags & TTY_ECHO)
|
||||
{
|
||||
putc(c);
|
||||
}
|
||||
}*/
|
||||
|
||||
void tty_input_char(tty_t* tty, char c)
|
||||
{
|
||||
if (!tty || c == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
/* RAW queue always gets input */
|
||||
raw_put(tty, c);
|
||||
|
||||
if (!(tty->flags & TTY_RAW))
|
||||
{
|
||||
/* canonical behavior */
|
||||
|
||||
if (c == '\b')
|
||||
{
|
||||
if (tty->head != tty->tail)
|
||||
{
|
||||
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE;
|
||||
|
||||
putc('\b');
|
||||
putc(' ');
|
||||
putc('\b');
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t next = next_index(tty->head);
|
||||
|
||||
if (next != tty->tail)
|
||||
{
|
||||
tty->input_buffer[tty->head] = c;
|
||||
tty->head = next;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
tty->line_ready = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
if (tty->flags & TTY_ECHO)
|
||||
{
|
||||
putc(c);
|
||||
|
||||
132
drivers/pci.c
132
drivers/pci.c
@ -17,96 +17,104 @@
|
||||
|
||||
uint32_t pci_config_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset)
|
||||
{
|
||||
uint32_t address = 0;
|
||||
address |= (bus << 16); /* Bus number (bits 23-16) */
|
||||
address |= (device << 11); /* Device number (bits 15-11) */
|
||||
address |= (function << 8); /* Function number (bits 10-8) */
|
||||
address |= (offset & 0xFC); /* Register offset (bits 7-0) */
|
||||
address |= (1 << 31); /* Enable configuration access */
|
||||
uint32_t address = 0;
|
||||
address |= (bus << 16); /* Bus number (bits 23-16) */
|
||||
address |= (device << 11); /* Device number (bits 15-11) */
|
||||
address |= (function << 8); /* Function number (bits 10-8) */
|
||||
address |= (offset & 0xFC); /* Register offset (bits 7-0) */
|
||||
address |= (1 << 31); /* Enable configuration access */
|
||||
|
||||
outl(PCI_CONFIG_ADDRESS, address); /* Write address to PCI config space */
|
||||
return inl(PCI_CONFIG_DATA); /* Read data from PCI config space */
|
||||
outl(PCI_CONFIG_ADDRESS, address); /* Write address to PCI config space */
|
||||
return inl(PCI_CONFIG_DATA); /* Read data from PCI config space */
|
||||
}
|
||||
|
||||
void pci_config_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value)
|
||||
{
|
||||
uint32_t address = 0x80000000 | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC);
|
||||
outl(PCI_CONFIG_ADDRESS, address); /* Send the address to PCI config space */
|
||||
outl(PCI_CONFIG_DATA, value); /* Write data to PCI config space */
|
||||
uint32_t address = 0x80000000 | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC);
|
||||
outl(PCI_CONFIG_ADDRESS, address); /* Send the address to PCI config space */
|
||||
outl(PCI_CONFIG_DATA, value); /* Write data to PCI config space */
|
||||
}
|
||||
|
||||
void pci_config_read_block(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, void* buffer, size_t size)
|
||||
{
|
||||
uint8_t* buf = (uint8_t*)buffer;
|
||||
uint8_t* buf = (uint8_t*)buffer;
|
||||
|
||||
for (size_t i = 0; i < size; i += 4)
|
||||
{
|
||||
uint32_t value = pci_config_read(bus, device, function, offset + i);
|
||||
for (size_t i = 0; i < size; i += 4)
|
||||
{
|
||||
uint32_t value = pci_config_read(bus, device, function, offset + i);
|
||||
|
||||
size_t remaining = size - i;
|
||||
if (remaining >= 4)
|
||||
{
|
||||
*(uint32_t*)(buf + i) = value;
|
||||
size_t remaining = size - i;
|
||||
if (remaining >= 4)
|
||||
{
|
||||
*(uint32_t*)(buf + i) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t j = 0; j < remaining; ++j)
|
||||
{
|
||||
buf[i + j] = (value >> (8 * j)) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t j = 0; j < remaining; ++j)
|
||||
{
|
||||
buf[i + j] = (value >> (8 * j)) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pci_init(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("[ PCI ] Initializing PCI...\n");
|
||||
printf("[ PCI ] Initializing PCI...\n");
|
||||
#endif
|
||||
|
||||
pci_enumerate();
|
||||
pci_enumerate();
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PCI ] PCI initialized\n");
|
||||
printf("[ PCI ] PCI initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void pci_enumerate(void)
|
||||
{
|
||||
for (uint16_t bus = 0; bus < 256; bus++) /* Maximum 256 buses */
|
||||
{
|
||||
for (uint8_t device = 0; device < 32; device++) /* Maximum 32 devices per bus */
|
||||
for (uint16_t bus = 0; bus < 256; bus++) /* Maximum 256 buses */
|
||||
{
|
||||
for (uint8_t function = 0; function < 8; function++) /* Maximum 8 functions per device */
|
||||
{
|
||||
struct pci_header pre_header;
|
||||
pci_config_read_block(bus, device, function, 0x00, &pre_header, sizeof(pre_header));
|
||||
|
||||
if (pre_header.vendor_id == 0xFFFF)
|
||||
for (uint8_t device = 0; device < 32; device++) /* Maximum 32 devices per bus */
|
||||
{
|
||||
continue; /* No device present */
|
||||
for (uint8_t function = 0; function < 8; function++) /* Maximum 8 functions per device */
|
||||
{
|
||||
struct pci_header pre_header;
|
||||
pci_config_read_block(bus, device, function, 0x00, &pre_header, sizeof(pre_header));
|
||||
|
||||
if (pre_header.vendor_id == 0xFFFF)
|
||||
{
|
||||
continue; /* No device present */
|
||||
}
|
||||
|
||||
if (pre_header.class_code == 0xB)
|
||||
{
|
||||
printf("Processor found on PCI bus, what?!?!\n"); /* For some stupid reason, processors can be on the PCI bus? */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pre_header.header_type == 0x00)
|
||||
{
|
||||
struct pci_header_type_0 hdr;
|
||||
pci_config_read_block(bus, device, function, 0x00, &hdr, sizeof(hdr));
|
||||
|
||||
if (hdr.class_code == 0x1 && hdr.subclass == 0x6 && hdr.prog_if == 0x1)
|
||||
{
|
||||
/*configure_ahci_controller(hdr);*/
|
||||
}
|
||||
|
||||
if (hdr.class_code == 0x03)
|
||||
{
|
||||
uint32_t bar0 = hdr.bar0;
|
||||
extern void init_bga_framebuffer(uint32_t* _p);
|
||||
init_bga_framebuffer((uint32_t*) bar0);
|
||||
printf("Found framebffer addr 0x%x on device %x \n", bar0, hdr.device_id);
|
||||
}
|
||||
|
||||
|
||||
/*printf("PCI device: cc: %x sc: %x pi: %x b: %x d: %x f: %x int: %x\n", hdr.class_code, hdr.subclass, hdr.prog_if, bus, device, function, (uint32_t) hdr.interrupt_line);*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pre_header.class_code == 0xB)
|
||||
{
|
||||
printf("Processor found on PCI bus, what?!?!\n"); /* For some stupid reason, processors can be on the PCI bus? */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pre_header.header_type == 0x00)
|
||||
{
|
||||
struct pci_header_type_0 hdr;
|
||||
pci_config_read_block(bus, device, function, 0x00, &hdr, sizeof(hdr));
|
||||
|
||||
if (hdr.class_code == 0x1 && hdr.subclass == 0x6 && hdr.prog_if == 0x1)
|
||||
{
|
||||
/*configure_ahci_controller(hdr);*/
|
||||
}
|
||||
|
||||
|
||||
/*printf("PCI device: cc: %x sc: %x pi: %x b: %x d: %x f: %x int: %x\n", hdr.class_code, hdr.subclass, hdr.prog_if, bus, device, function, (uint32_t) hdr.interrupt_line);*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
#include <vga/vga.h>
|
||||
#include <stdio.h>
|
||||
#include <port_io.h>
|
||||
#include <new_tty.h>
|
||||
#include <fs/vfs.h>
|
||||
|
||||
#include <tty.h>
|
||||
|
||||
@ -18,6 +20,19 @@ void terminal_initialize(void)
|
||||
terminal_update_cursor();
|
||||
}
|
||||
|
||||
ssize_t tty_write(struct file* f, const char* buf, size_t size)
|
||||
{
|
||||
/*struct tty* tty = (struct tty*)f->private_data;*/
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
/*tty_putchar(tty, buf[i]);*/ /* do this when we have multiple TTY outputs & stuff */
|
||||
terminal_putchar(buf[i]);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void terminal_get_cursor(int* row, int* column)
|
||||
{
|
||||
*row = (int) terminal_row;
|
||||
@ -106,6 +121,33 @@ void terminal_putchar(const char c)
|
||||
|
||||
return;
|
||||
}
|
||||
/*else if (uc == '\b')
|
||||
{
|
||||
if (terminal_column == 0)
|
||||
{
|
||||
if (terminal_row > 0)
|
||||
{
|
||||
terminal_row--;
|
||||
terminal_column = VGA_WIDTH - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_update_cursor();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_column--;
|
||||
}
|
||||
|
||||
terminal_putentryat(' ', terminal_color, terminal_column, terminal_row);
|
||||
|
||||
terminal_update_cursor();
|
||||
|
||||
return;
|
||||
}*/
|
||||
else if (uc == '\b')
|
||||
{
|
||||
if (terminal_column == 0)
|
||||
@ -117,7 +159,7 @@ void terminal_putchar(const char c)
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_update_cursor(); /* For good measure */
|
||||
terminal_update_cursor();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -127,8 +169,6 @@ void terminal_putchar(const char c)
|
||||
terminal_column--;
|
||||
}
|
||||
|
||||
terminal_putentryat(' ', terminal_color, terminal_column, terminal_row);
|
||||
|
||||
terminal_update_cursor();
|
||||
|
||||
return;
|
||||
|
||||
BIN
espresso.img
Normal file
BIN
espresso.img
Normal file
Binary file not shown.
177
files/idt.c
177
files/idt.c
@ -1,177 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <port_io.h>
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#include <drivers/idt.h>
|
||||
|
||||
|
||||
#define IDT_MAX_DESCRIPTORS 256
|
||||
|
||||
#define PIC1_COMMAND 0x20
|
||||
#define PIC1_DATA 0x21
|
||||
#define PIC2_COMMAND 0xA0
|
||||
#define PIC2_DATA 0xA1
|
||||
|
||||
/*
|
||||
Most of the code is this file (and idt.h) are taken from the osdev wiki: https://wiki.osdev.org/Interrupts_Tutorial, though not all of it.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint16_t isr_low; // The lower 16 bits of the ISR's address
|
||||
uint16_t kernel_cs; // The GDT segment selector that the CPU will load into CS before calling the ISR
|
||||
uint8_t reserved; // Set to zero
|
||||
uint8_t attributes; // Type and attributes; see the IDT page
|
||||
uint16_t isr_high; // The higher 16 bits of the ISR's address
|
||||
} __attribute__((packed)) idt_entry_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
} __attribute__((packed)) idtr_t;
|
||||
|
||||
__attribute__((aligned(0x10)))
|
||||
|
||||
static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance
|
||||
|
||||
static idtr_t idtr;
|
||||
|
||||
static bool vectors[IDT_MAX_DESCRIPTORS];
|
||||
|
||||
extern void* isr_stub_table[];
|
||||
|
||||
void idt_init(void)
|
||||
{
|
||||
idtr.base = (uintptr_t)&idt[0];
|
||||
idtr.limit = (uint16_t)sizeof(idt_entry_t) * IDT_MAX_DESCRIPTORS - 1;
|
||||
|
||||
for (uint8_t vector = 0; vector < 32; vector++)
|
||||
{
|
||||
idt_set_descriptor(vector, isr_stub_table[vector], 0x8E);
|
||||
vectors[vector] = true;
|
||||
}
|
||||
|
||||
extern void* irq_stub_table[];
|
||||
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
{
|
||||
idt_set_descriptor(32 + i, irq_stub_table[i], 0x8E);
|
||||
}
|
||||
|
||||
|
||||
asm volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */
|
||||
asm volatile ("sti"); /* set the interrupt flag */
|
||||
}
|
||||
|
||||
void interrupt_dispatcher(registers_t* regs)
|
||||
{
|
||||
if (regs->int_no < 32)
|
||||
{
|
||||
exception_handler(regs);
|
||||
}
|
||||
else if (regs->int_no < 48)
|
||||
{
|
||||
uint32_t irq = regs->int_no - 32;
|
||||
irq_handler(irq, regs);
|
||||
|
||||
if (irq >= 8)
|
||||
{
|
||||
outb(0xA0, 0x20); /* acknowledge the IRQ to slave PIC */
|
||||
}
|
||||
|
||||
outb(0x20, 0x20); /* acknowledge the IRQ to master PIC */
|
||||
}
|
||||
}
|
||||
|
||||
__noreturn
|
||||
void exception_handler(registers_t* regs)
|
||||
{
|
||||
uint32_t int_no = regs->int_no;
|
||||
uint32_t err_code = regs->err_code;
|
||||
|
||||
switch (int_no)
|
||||
{
|
||||
case 0:
|
||||
printf("Divide by zero exception (or other division error)\n");
|
||||
break;
|
||||
case 2:
|
||||
printf("NMI encountered\n");
|
||||
break;
|
||||
case 6: /* XXX: NOTE: this can be used to emulate instructions that do not exist on the current CPU :NOTE :XXX */
|
||||
printf("Invalid opcode encountered\n");
|
||||
break;
|
||||
case 7: /* XXX: NOTE: use this for FPU emulation and for saving/restoring FPU registers in a multiprocessing enviroment :NOTE :XXX */
|
||||
printf("FPU instructions used, but FPU is nonexistant/disabled\n");
|
||||
break;
|
||||
case 13:
|
||||
printf("General Protection Fault: err=0x%x at %p\n", err_code, regs->eip);
|
||||
break;
|
||||
case 14:
|
||||
{
|
||||
uint32_t cr2;
|
||||
asm volatile ("mov %%cr2, %0" : "=r"(cr2));
|
||||
printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Unhandled exception #%u, err=0x%x at %p\n", int_no, err_code, regs->eip);
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t cs, ds, es, ss;
|
||||
asm volatile ("mov %%cs, %0" : "=r"(cs));
|
||||
asm volatile ("mov %%ds, %0" : "=r"(ds));
|
||||
asm volatile ("mov %%es, %0" : "=r"(es));
|
||||
asm volatile ("mov %%ss, %0" : "=r"(ss));
|
||||
|
||||
printf("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss);
|
||||
|
||||
asm volatile ("cli; hlt");
|
||||
|
||||
/* Will never be reached */
|
||||
while (true)
|
||||
{
|
||||
asm volatile ("hlt" ::: "memory");
|
||||
}
|
||||
}
|
||||
|
||||
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags)
|
||||
{
|
||||
idt_entry_t* descriptor = &idt[vector];
|
||||
|
||||
descriptor->isr_low = (uint32_t) isr & 0xFFFF;
|
||||
descriptor->kernel_cs = 0x08;
|
||||
descriptor->attributes = flags;
|
||||
descriptor->isr_high = (uint32_t) isr >> 16;
|
||||
descriptor->reserved = 0;
|
||||
}
|
||||
|
||||
void pic_remap(void)
|
||||
{
|
||||
uint8_t a1, a2;
|
||||
|
||||
/* save masks */
|
||||
a1 = inb(PIC1_DATA);
|
||||
a2 = inb(PIC2_DATA);
|
||||
|
||||
/* start initialization sequence (in cascade mode) */
|
||||
outb(PIC1_COMMAND, 0x11);
|
||||
outb(PIC2_COMMAND, 0x11);
|
||||
|
||||
/* set vector offset */
|
||||
outb(PIC1_DATA, 0x20); /* IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39) */
|
||||
outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47) */
|
||||
|
||||
/* tell the master PIC about Slave PIC at IRQ2 (0000 0100) */
|
||||
outb(PIC1_DATA, 0x04);
|
||||
|
||||
/* tell the slave PIC its cascade identity (0000 0010) */
|
||||
outb(PIC2_DATA, 0x02);
|
||||
|
||||
/* set 8086/88 mode */
|
||||
outb(PIC1_DATA, 0x01);
|
||||
outb(PIC2_DATA, 0x01);
|
||||
|
||||
/* restore saved masks */
|
||||
outb(PIC1_DATA, a1);
|
||||
outb(PIC2_DATA, a2);
|
||||
}
|
||||
18
files/idt.h
18
files/idt.h
@ -1,18 +0,0 @@
|
||||
#ifndef _IDT_H
|
||||
#define _IDT_H
|
||||
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#include <types.h>
|
||||
|
||||
|
||||
void idt_init(void);
|
||||
|
||||
void pic_remap(void);
|
||||
|
||||
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags);
|
||||
|
||||
void exception_handler(registers_t* regs);
|
||||
|
||||
|
||||
#endif
|
||||
69
files/irq.c
69
files/irq.c
@ -1,69 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
#include <drivers/pit.h>
|
||||
#include <port_io.h>
|
||||
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#define MAX_IRQ_HANDLERS 128 /* the maximum number of irq handlers */
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t irq_no;
|
||||
irq_func_t func;
|
||||
} irq_handler_t;
|
||||
|
||||
uint32_t num_irq_handlers = 0;
|
||||
irq_handler_t handler_list[MAX_IRQ_HANDLERS];
|
||||
|
||||
static volatile uint32_t num_irqs_missed = 0;
|
||||
|
||||
void irq_init(void)
|
||||
{
|
||||
for (int i = 0; i < MAX_IRQ_HANDLERS; i++)
|
||||
{
|
||||
handler_list[i].irq_no = 0;
|
||||
handler_list[i].func = NULL;
|
||||
}
|
||||
set_irq_handler(0, (irq_func_t) pit_handler);
|
||||
set_irq_handler(1, (irq_func_t) ps2_keyboard_handler);
|
||||
}
|
||||
|
||||
void irq_handler(uint32_t irq, registers_t* regs)
|
||||
{
|
||||
uint8_t funcs_called = 0;
|
||||
|
||||
if (num_irq_handlers > 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < num_irq_handlers; i++)
|
||||
{
|
||||
if (handler_list[i].irq_no == irq && handler_list[i].func != NULL)
|
||||
{
|
||||
handler_list[i].func(regs);
|
||||
funcs_called++;
|
||||
/* PIC IRQ acknowledgement happens in idt.c */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (funcs_called == 0)
|
||||
{
|
||||
num_irqs_missed++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t get_interrupts_missed(void)
|
||||
{
|
||||
return num_irqs_missed;
|
||||
}
|
||||
|
||||
void set_irq_handler(uint32_t num, irq_func_t handler)
|
||||
{
|
||||
if (num < MAX_IRQ_HANDLERS)
|
||||
{
|
||||
handler_list[num].irq_no = num;
|
||||
handler_list[num].func = handler;
|
||||
|
||||
num_irq_handlers++;
|
||||
}
|
||||
}
|
||||
43
files/irq.h
43
files/irq.h
@ -1,43 +0,0 @@
|
||||
#ifndef _IRQ_H
|
||||
#define _IRQ_H
|
||||
|
||||
#include <types.h>
|
||||
/*
|
||||
typedef struct registers {
|
||||
uint32_t ds, es, fs, gs;
|
||||
|
||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
|
||||
|
||||
uint32_t int_no;
|
||||
uint32_t err_code;
|
||||
|
||||
uint32_t eip, cs, eflags;
|
||||
} registers_t;
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint32_t ds, es, fs, gs;
|
||||
|
||||
uint32_t eax, ecx, edx, ebx;
|
||||
uint32_t esp, ebp, esi, edi;
|
||||
|
||||
uint32_t int_no;
|
||||
uint32_t err_code;
|
||||
|
||||
uint32_t eip, cs, eflags;
|
||||
} registers_t;
|
||||
|
||||
|
||||
typedef void (*irq_func_t)(registers_t*);
|
||||
|
||||
|
||||
void irq_init(void);
|
||||
|
||||
void irq_handler(uint32_t irq, registers_t* regs);
|
||||
|
||||
void set_irq_handler(uint32_t num, irq_func_t handler);
|
||||
/*void add_irq_handler(uint32_t num, irq_func_t* handler);*/
|
||||
|
||||
uint32_t get_interrupts_missed(void);
|
||||
|
||||
#endif
|
||||
154
files/isr.asm
154
files/isr.asm
@ -1,154 +0,0 @@
|
||||
[BITS 32]
|
||||
|
||||
[GLOBAL isr_stub_table]
|
||||
[GLOBAL irq_stub_table]
|
||||
[GLOBAL interrupt_entry]
|
||||
|
||||
extern interrupt_dispatcher
|
||||
|
||||
section .text
|
||||
|
||||
; ============================================================
|
||||
; COMMON INTERRUPT ENTRY
|
||||
; ============================================================
|
||||
|
||||
interrupt_entry:
|
||||
|
||||
; Stack already contains:
|
||||
; err_code
|
||||
; int_no
|
||||
; eip
|
||||
; cs
|
||||
; eflags
|
||||
|
||||
pusha ; eax, ecx, edx, ebx, esp, ebp, esi, edi
|
||||
|
||||
;push ds
|
||||
;push es
|
||||
;push fs
|
||||
;push gs
|
||||
|
||||
push gs
|
||||
push fs
|
||||
push es
|
||||
push ds
|
||||
|
||||
|
||||
mov ax, 0x10 ; load kernel data selector
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
push esp ; pass pointer to registers_t
|
||||
call interrupt_dispatcher
|
||||
add esp, 4
|
||||
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
|
||||
popa
|
||||
|
||||
add esp, 8 ; remove int_no + err_code
|
||||
|
||||
iret
|
||||
|
||||
|
||||
; ============================================================
|
||||
; IRQ STUBS
|
||||
; ============================================================
|
||||
|
||||
%macro IRQ 1
|
||||
irq_stub_%+%1:
|
||||
push dword 0 ; fake error code
|
||||
push dword (32 + %1) ; vector number
|
||||
jmp interrupt_entry
|
||||
%endmacro
|
||||
|
||||
IRQ 0
|
||||
IRQ 1
|
||||
IRQ 2
|
||||
IRQ 3
|
||||
IRQ 4
|
||||
IRQ 5
|
||||
IRQ 6
|
||||
IRQ 7
|
||||
IRQ 8
|
||||
IRQ 9
|
||||
IRQ 10
|
||||
IRQ 11
|
||||
IRQ 12
|
||||
IRQ 13
|
||||
IRQ 14
|
||||
IRQ 15
|
||||
|
||||
irq_stub_table:
|
||||
%assign i 0
|
||||
%rep 16
|
||||
dd irq_stub_%+i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
|
||||
; ============================================================
|
||||
; EXCEPTION STUBS
|
||||
; ============================================================
|
||||
|
||||
%macro ISR_NOERR 1
|
||||
isr_stub_%+%1:
|
||||
push dword 0 ; fake error code
|
||||
push dword %1 ; interrupt number
|
||||
jmp interrupt_entry
|
||||
%endmacro
|
||||
|
||||
%macro ISR_ERR 1
|
||||
isr_stub_%+%1:
|
||||
push dword %1 ; interrupt number
|
||||
jmp interrupt_entry
|
||||
%endmacro
|
||||
|
||||
|
||||
; Exceptions 0–31
|
||||
|
||||
ISR_NOERR 0
|
||||
ISR_NOERR 1
|
||||
ISR_NOERR 2
|
||||
ISR_NOERR 3
|
||||
ISR_NOERR 4
|
||||
ISR_NOERR 5
|
||||
ISR_NOERR 6
|
||||
ISR_NOERR 7
|
||||
ISR_ERR 8
|
||||
ISR_NOERR 9
|
||||
ISR_ERR 10
|
||||
ISR_ERR 11
|
||||
ISR_ERR 12
|
||||
ISR_ERR 13
|
||||
ISR_ERR 14
|
||||
ISR_NOERR 15
|
||||
ISR_NOERR 16
|
||||
ISR_ERR 17
|
||||
ISR_NOERR 18
|
||||
ISR_NOERR 19
|
||||
ISR_NOERR 20
|
||||
ISR_NOERR 21
|
||||
ISR_NOERR 22
|
||||
ISR_NOERR 23
|
||||
ISR_NOERR 24
|
||||
ISR_NOERR 25
|
||||
ISR_NOERR 26
|
||||
ISR_NOERR 27
|
||||
ISR_NOERR 28
|
||||
ISR_NOERR 29
|
||||
ISR_ERR 30
|
||||
ISR_NOERR 31
|
||||
|
||||
isr_stub_table:
|
||||
%assign i 0
|
||||
%rep 32
|
||||
dd isr_stub_%+i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
164
files/kernel.c
164
files/kernel.c
@ -1,164 +0,0 @@
|
||||
/* Check if the compiler thinks you are targeting the wrong operating system. */
|
||||
#if defined(__linux__)
|
||||
#error "You are not using a cross-compiler, you will most certainly run into trouble"
|
||||
#endif
|
||||
|
||||
/* This tutorial will only work for the 32-bit ix86 targets. */
|
||||
#if !defined(__i386__)
|
||||
#error "This kernel needs to be compiled with a ix86-elf compiler"
|
||||
#endif
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <kernel/boot.h>
|
||||
#include <kernel/kshell.h>
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
#include <gdt.h>
|
||||
#include <drivers/idt.h>
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#include <scheduler.h>
|
||||
|
||||
#include <multiboot.h>
|
||||
|
||||
#include <drivers/pci.h>
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
#include <drivers/pit.h>
|
||||
/*#include <drivers/ahci.h>*/
|
||||
#include <drivers/ide.h>
|
||||
#include <mm/mm.h>
|
||||
#include <fs/fat32.h>
|
||||
/*#include <fs/duckfs.h>*/
|
||||
#include <fs/vfs.h>
|
||||
#include <fs/sfs.h>
|
||||
|
||||
#include <vector_extensions/sse.h>
|
||||
|
||||
#include <kernel/intro.h>
|
||||
|
||||
#include <builtin_games/miner.h>
|
||||
|
||||
#include <fs/ssfs.h>
|
||||
|
||||
|
||||
extern void _hang_asm(void);
|
||||
extern void _sti_asm(void);
|
||||
|
||||
void idle_task(void)
|
||||
{
|
||||
while (1)
|
||||
asm volatile("hlt");
|
||||
}
|
||||
|
||||
|
||||
void kernel_main(multiboot_info_t* mbd, uint32_t magic)
|
||||
{
|
||||
|
||||
/* --- BEGIN INITIALIZATION SECTION --- */
|
||||
|
||||
/* We need to initialize the terminal so that any error/debugging messages show. */
|
||||
terminal_initialize();
|
||||
|
||||
printf("Loading Espresso %s... ", KERNEL_VERSION);
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ DEBUG BUILD ]");
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
|
||||
terminal_setcolor(VGA_COLOR_RED);
|
||||
|
||||
/* Make sure the magic number matches for memory mapping */
|
||||
if(magic != MULTIBOOT_BOOTLOADER_MAGIC)
|
||||
{
|
||||
printf("[ ERROR ] invalid magic number!\n");
|
||||
_hang_asm();
|
||||
}
|
||||
|
||||
/* Check bit 6 to see if we have a valid memory map */
|
||||
if(!(mbd->flags >> 6 & 0x1))
|
||||
{
|
||||
printf("[ ERROR ] invalid memory map given by GRUB bootloader\n");
|
||||
_hang_asm();
|
||||
}
|
||||
|
||||
gdt_install(false);
|
||||
|
||||
pic_remap(); /* must be done before idt_init() */
|
||||
|
||||
idt_init();
|
||||
|
||||
_sti_asm();
|
||||
|
||||
irq_init(); /* MUST be done after pic_remap() and idt_init() */
|
||||
|
||||
terminal_setcolor(VGA_COLOR_GREEN);
|
||||
|
||||
pmm_init(mbd);
|
||||
|
||||
paging_init();
|
||||
|
||||
heap_init(0xC2000000, 0x80000);
|
||||
|
||||
#ifdef _DEBUG
|
||||
printd("Testing SSE...\n");
|
||||
#endif
|
||||
int32_t sse_test_result = test_sse();
|
||||
if (sse_test_result != 0)
|
||||
{
|
||||
printf("[ SSE ] SSE test failed with RV %d\n", sse_test_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printd("SSE test passed\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
pit_init();
|
||||
|
||||
keyboard_init();
|
||||
|
||||
ide_initialize();
|
||||
|
||||
pci_init();
|
||||
|
||||
scheduler_init();
|
||||
|
||||
/* --- END INITIALIZATION SECTION --- */
|
||||
|
||||
|
||||
terminal_setcolor(VGA_COLOR_LIGHT_GREEN);
|
||||
|
||||
printf("Guten tag and welcome to Espresso %s\n", KERNEL_VERSION);
|
||||
|
||||
//terminal_clear();
|
||||
|
||||
create_task(kshell_start);
|
||||
create_task(idle_task);
|
||||
|
||||
extern task_t* task_list;
|
||||
extern task_t* current_task;
|
||||
|
||||
current_task = task_list;
|
||||
|
||||
printf("in kernel_main\n");
|
||||
|
||||
/*extern void terminal_clear(void);
|
||||
|
||||
terminal_clear();
|
||||
|
||||
kshell_start(1, NULL);*/
|
||||
|
||||
for(;;) /* Loop infinitely. We only do something when an interrupt/syscall happens now. */
|
||||
{
|
||||
asm volatile("hlt" ::: "memory");
|
||||
}
|
||||
}
|
||||
62
files/pit.c
62
files/pit.c
@ -1,62 +0,0 @@
|
||||
#include <types.h>
|
||||
#include <port_io.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <scheduler.h>
|
||||
|
||||
#include <drivers/pit.h>
|
||||
|
||||
|
||||
#define PIT_CHANNEL0 0x40
|
||||
#define PIT_COMMAND 0x43
|
||||
#define PIT_IRQ_LINE 0
|
||||
#define PIT_FREQUENCY_BASE 1193182
|
||||
|
||||
volatile uint64_t pit_ticks = 0;
|
||||
bool pit_initialized = false;
|
||||
|
||||
void pit_init(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("[ PIT ] Initializing the PIT...\n");
|
||||
#endif
|
||||
|
||||
uint16_t divisor = (uint16_t) 1193;
|
||||
|
||||
/* Send command byte */
|
||||
outb(PIT_COMMAND, 0x36); /* Channel 0, low/high byte, mode 3 (square wave), binary */
|
||||
|
||||
/* Send divisor low and high byte */
|
||||
outb(PIT_CHANNEL0, (uint8_t)(divisor & 0xFF)); /* Low byte */
|
||||
outb(PIT_CHANNEL0, (uint8_t)((divisor >> 8) & 0xFF)); /* High byte */
|
||||
|
||||
pit_initialized = true;
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PIT ] PIT Initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void pit_handler(void)
|
||||
{
|
||||
pit_ticks++;
|
||||
}
|
||||
|
||||
/*void pit_sleep(uint64_t ms)
|
||||
{
|
||||
uint64_t target = pit_ticks + ms;
|
||||
while (pit_ticks < target)
|
||||
{
|
||||
asm volatile ("hlt");
|
||||
}
|
||||
}*/
|
||||
|
||||
void pit_sleep(uint64_t ms)
|
||||
{
|
||||
extern task_t* current_task;
|
||||
|
||||
current_task->wakeup_tick = pit_ticks + ms;
|
||||
current_task->state = TASK_SLEEPING;
|
||||
|
||||
asm volatile("int $32"); /* force reschedule immediately */
|
||||
}
|
||||
@ -1,158 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#include <scheduler.h>
|
||||
|
||||
#define STACK_SIZE 4096
|
||||
|
||||
task_t* task_list = NULL;
|
||||
task_t* current_task = NULL;
|
||||
uint32_t next_task_id = 1;
|
||||
|
||||
static void schedule(void);
|
||||
|
||||
/* scheduler init */
|
||||
void scheduler_init(void)
|
||||
{
|
||||
set_irq_handler(0, (irq_func_t) scheduler_tick);
|
||||
}
|
||||
|
||||
static void schedule(void)
|
||||
{
|
||||
if (!task_list)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* wake sleeping tasks */
|
||||
task_t* t = task_list;
|
||||
|
||||
extern uint64_t pit_ticks;
|
||||
|
||||
do
|
||||
{
|
||||
if (t->state == TASK_SLEEPING && pit_ticks >= t->wakeup_tick)
|
||||
{
|
||||
t->state = TASK_READY;
|
||||
}
|
||||
|
||||
t = t->next;
|
||||
}
|
||||
while (t != task_list);
|
||||
|
||||
/* find next ready task */
|
||||
task_t* start = current_task;
|
||||
|
||||
do
|
||||
{
|
||||
current_task = current_task->next;
|
||||
|
||||
if (current_task->state == TASK_READY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (current_task != start);
|
||||
}
|
||||
|
||||
|
||||
/* tick handler */
|
||||
void scheduler_tick(registers_t* regs)
|
||||
{
|
||||
if (!task_list)
|
||||
{
|
||||
printf("!task_list\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_task)
|
||||
{
|
||||
printf("!current_task\n");
|
||||
current_task = task_list;
|
||||
}
|
||||
|
||||
/* save current task state */
|
||||
*(current_task->regs) = *regs;
|
||||
|
||||
/* pick next */
|
||||
schedule();
|
||||
|
||||
/* load next task state */
|
||||
*regs = *(current_task->regs);
|
||||
}
|
||||
|
||||
/* task creation */
|
||||
task_t* create_task(void (*entry)())
|
||||
{
|
||||
task_t* task = malloc(sizeof(task_t));
|
||||
|
||||
if (!task)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(task, 0, sizeof(task_t));
|
||||
|
||||
/* allocate stack */
|
||||
uint8_t* stack = malloc(STACK_SIZE);
|
||||
|
||||
if (!stack)
|
||||
{
|
||||
free(task);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("Creating task %i @ %p\n", next_task_id, entry);
|
||||
|
||||
/*
|
||||
align stack to 16 bytes for safety (SSE friendly).
|
||||
stack grows downward.
|
||||
*/
|
||||
uintptr_t stack_top = (uintptr_t)(stack + STACK_SIZE);
|
||||
stack_top &= ~0xF;
|
||||
|
||||
registers_t* regs = (registers_t*) (stack_top - sizeof(registers_t));
|
||||
memset(regs, 0, sizeof(registers_t));
|
||||
|
||||
/* initialize register frame */
|
||||
regs->eip = (uint32_t) entry;
|
||||
regs->cs = 0x08; /* Kernel code segment */
|
||||
regs->eflags = 0x202; /* IF=1 */
|
||||
|
||||
task->id = next_task_id++;
|
||||
task->regs = regs;
|
||||
task->stack_base = (uint32_t*) stack;
|
||||
task->state = TASK_READY;
|
||||
|
||||
/* insert into circular list */
|
||||
if (!task_list)
|
||||
{
|
||||
task_list = task;
|
||||
task->next = task;
|
||||
}
|
||||
else
|
||||
{
|
||||
task_t* last = task_list;
|
||||
while (last->next != task_list)
|
||||
{
|
||||
last = last->next;
|
||||
}
|
||||
|
||||
last->next = task;
|
||||
task->next = task_list;
|
||||
}
|
||||
|
||||
printf("Task %i @ %p created successfully\n", next_task_id - 1, entry);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
/* task destruction */
|
||||
void destroy_task(task_t* task)
|
||||
{
|
||||
free(task->stack_base);
|
||||
free(task);
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
#ifndef _SCHEDULER_H
|
||||
#define _SCHEDULER_H
|
||||
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#include <types.h>
|
||||
|
||||
typedef enum {
|
||||
TASK_READY,
|
||||
TASK_RUNNING,
|
||||
TASK_SLEEPING,
|
||||
TASK_BLOCKED,
|
||||
TASK_TERMINATED,
|
||||
} task_state_t;
|
||||
|
||||
typedef struct task {
|
||||
uint32_t id;
|
||||
|
||||
registers_t* regs; /* pointer to saved register frame */
|
||||
uint32_t* stack_base; /* original malloc() pointer */
|
||||
|
||||
task_state_t state;
|
||||
struct task* next;
|
||||
|
||||
uint64_t wakeup_tick;
|
||||
} task_t;
|
||||
|
||||
void scheduler_init(void);
|
||||
task_t* create_task(void (*entry)());
|
||||
void scheduler_tick(registers_t* regs);
|
||||
|
||||
#endif
|
||||
5
grub.cfg
5
grub.cfg
@ -1,4 +1,9 @@
|
||||
|
||||
set gfxmode=1024x768x32
|
||||
set gfxpayload=keep
|
||||
terminal_output gfxterm
|
||||
|
||||
menuentry "Espresso" {
|
||||
multiboot /boot/espresso.elf
|
||||
boot
|
||||
}
|
||||
|
||||
@ -36,12 +36,13 @@ typedef struct {
|
||||
uint32_t p_align;
|
||||
} Elf32_Phdr;
|
||||
|
||||
//typedef int (*elf_entry_t)(int, char**);
|
||||
typedef int (*elf_entry_t)(void);
|
||||
|
||||
typedef struct {
|
||||
elf_entry_t entry_point;
|
||||
} elf_executable_t;
|
||||
|
||||
elf_executable_t* load_elf32(void* elf_data);
|
||||
int load_elf32(void* elf_data, elf_executable_t** ptr);
|
||||
|
||||
#endif
|
||||
|
||||
26
include/drivers/graphics/vga.h
Normal file
26
include/drivers/graphics/vga.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _VGA_GRAPHICS_H
|
||||
#define _VGA_GRAPHICS_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
struct bga_framebuffer
|
||||
{
|
||||
volatile uint8_t* addr;
|
||||
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
|
||||
uint32_t pitch; /* bytes per scanline */
|
||||
uint32_t bpp;
|
||||
};
|
||||
|
||||
|
||||
void bga_defaults(void);
|
||||
void bga_set_video_mode(uint32_t width, uint32_t height, uint32_t bit_depth);
|
||||
|
||||
void bga_putpixel(uint32_t x, uint32_t y, uint32_t color);
|
||||
|
||||
|
||||
void bga_drawline(int x0, int y0, int x1, int y1, uint32_t color);
|
||||
|
||||
#endif
|
||||
@ -44,4 +44,6 @@ int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const voi
|
||||
int32_t read_sector(uint64_t lba, void* buffer);
|
||||
int32_t write_sector(uint64_t lba, const void* buffer);
|
||||
|
||||
int get_sector_size(uint8_t drive);
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
//#ifndef _ESPRESSO_KERNEL_FS_H
|
||||
#if 0
|
||||
#define _ESPRESSO_KERNEL_FS_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#define EKFS_FILENAME_MAX_LEN 64
|
||||
|
||||
enum {
|
||||
EKFS_E_FILETOOSMALL = -16;
|
||||
};
|
||||
|
||||
struct ekfs_inode {
|
||||
char i_name[EKFS_FILENAME_MAX_LEN];
|
||||
|
||||
uint64_t i_start; /* LBA48 */
|
||||
size_t i_len; /* rounded up to the nearest multiple of 512 */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ekfs_ops {
|
||||
int (*read)(struct ekfs_file*, void*, size_t);
|
||||
int (*write)(struct ekfs_file*, void*, size_t);
|
||||
};
|
||||
|
||||
struct ekfs_file {
|
||||
struct ekfs_inode* f_inode;
|
||||
|
||||
size_t f_offset;
|
||||
size_t f_refcount;
|
||||
|
||||
struct ekfs_ops f_ops;
|
||||
};
|
||||
|
||||
|
||||
int ekfs_read(struct ekfs_file* __f, void* __b, size_t __l);
|
||||
|
||||
#endif
|
||||
@ -4,7 +4,32 @@
|
||||
#include <types.h>
|
||||
|
||||
|
||||
#define MAX_FDS 64
|
||||
|
||||
struct file;
|
||||
|
||||
struct inode {
|
||||
size_t size;
|
||||
int permissions;
|
||||
/* | | */
|
||||
/* \/ FS-specific \/ */
|
||||
union {
|
||||
void* fs_data;
|
||||
void* private_data;
|
||||
};
|
||||
};
|
||||
|
||||
struct file_ops {
|
||||
int (*read)(struct file*, char*, size_t);
|
||||
int (*write)(struct file*, const char*, size_t);
|
||||
};
|
||||
|
||||
struct file {
|
||||
struct inode* f_inode;
|
||||
size_t f_offset;
|
||||
size_t f_refcount;
|
||||
const struct file_ops* f_ops;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -13,5 +13,7 @@ static inline int div_round_up(int a, int b)
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
|
||||
int abs(int x);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -4,11 +4,14 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <fs/vfs.h>
|
||||
|
||||
#include <processes.h>
|
||||
#include <sync.h>
|
||||
|
||||
|
||||
#define TTY_BUFFER_SIZE 4096
|
||||
#define TTY_RAW_BUFFER_SIZE 16
|
||||
#define MAX_TTYS 8 /* to make things easy, might change later */
|
||||
|
||||
#define TTY_ECHO 0x10 /* 0b00010000 */
|
||||
@ -16,7 +19,9 @@
|
||||
#define TTY_ACTIVE 0x01 /* 0b00000001 */
|
||||
|
||||
#define TTY_CANONICAL 0x40 /* 0b01000000 */
|
||||
#define TTY_RAW 0x04 /* 0b00000100 */
|
||||
|
||||
#define TTY_ADDCHAR_ALWAYS 0x02 /* 0b00000010 */
|
||||
|
||||
#define TTY_NULL 0x80 /* 0b10000000 --- used to end the list of tty_t structs in the ttys array */
|
||||
|
||||
@ -44,8 +49,18 @@ typedef struct tty_t {
|
||||
bool canonical;
|
||||
bool line_ready;
|
||||
|
||||
/* for raw mode */
|
||||
char raw_buf[TTY_RAW_BUFFER_SIZE];
|
||||
size_t raw_head;
|
||||
size_t raw_tail;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
size_t user_input_start;
|
||||
size_t user_input_end;
|
||||
|
||||
struct file_ops f_ops;
|
||||
|
||||
pid_t foreground_pgid; /* not used yet */
|
||||
} tty_t;
|
||||
|
||||
@ -60,9 +75,14 @@ int init_tty(void);
|
||||
ssize_t tty_read(tty_t* tty, char* buf, size_t count);
|
||||
ssize_t tty_read_active(char* buf, size_t count);
|
||||
|
||||
char tty_get_char(void);
|
||||
|
||||
tty_t* get_active_tty(void);
|
||||
tty_t* tty_get_active(void);
|
||||
|
||||
void tty_and_flags(tty_t* tty, uint32_t flags);
|
||||
uint32_t tty_get_flags(tty_t* tty);
|
||||
|
||||
tty_t* make_tty(uint32_t flags);
|
||||
|
||||
void tty_receive_char(char c, uint32_t kbd_mod);
|
||||
|
||||
@ -10,11 +10,23 @@ static inline uint32_t inl(uint16_t port)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline uint16_t inw(uint16_t port)
|
||||
{
|
||||
uint16_t rv;
|
||||
asm volatile ("inw %%dx, %%ax" : "=a" (rv) : "dN" (port));
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void outl(uint16_t port, uint32_t data)
|
||||
{
|
||||
asm volatile ("outl %%eax, %%dx" : : "dN" (port), "a" (data));
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void outw(uint16_t port, uint16_t val)
|
||||
{
|
||||
asm volatile ( "outw %0, %1" : : "a"(val), "Nd"(port) : "memory");
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void outb(uint16_t port, uint8_t val)
|
||||
{
|
||||
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) : "memory");
|
||||
|
||||
@ -17,11 +17,6 @@ char* strdup(const char* s);
|
||||
char* strtok(char* str, const char* delim);
|
||||
char* strchr(const char* s, int c);
|
||||
|
||||
/* these functions are NOT in the standard C library */
|
||||
int num_strchr(const char* s, int c);
|
||||
char* strnlstrip(const char* __s);
|
||||
void strlnstripip(char* s);
|
||||
|
||||
void lowers(char* str);
|
||||
void uppers(char* str);
|
||||
|
||||
@ -35,4 +30,11 @@ int atoi(const char *str);
|
||||
long atol(const char *str);
|
||||
double atof(const char *str);
|
||||
|
||||
/* these functions are NOT in the standard C library */
|
||||
int num_strchr(const char* s, int c);
|
||||
char* strnlstrip(const char* __s);
|
||||
void strlnstripip(char* s);
|
||||
char** split(const char* str, char delim);
|
||||
void free_split(char** parts);
|
||||
|
||||
#endif
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
#include <drivers/keyboard.h>
|
||||
#include <drivers/pit.h>
|
||||
#include <drivers/graphics/vga.h>
|
||||
/*#include <drivers/ahci.h>*/
|
||||
#include <drivers/ide.h>
|
||||
#include <mm/mm.h>
|
||||
@ -53,6 +54,7 @@
|
||||
#include <builtin_games/miner.h>
|
||||
|
||||
|
||||
|
||||
extern void _hang_asm(void);
|
||||
extern void _sti_asm(void);
|
||||
|
||||
@ -154,6 +156,9 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic)
|
||||
|
||||
extern void terminal_clear(void);
|
||||
|
||||
//bga_defaults();
|
||||
|
||||
|
||||
terminal_clear();
|
||||
|
||||
kshell_start();
|
||||
|
||||
@ -21,7 +21,7 @@ const char* shell_version = "0.0.2";
|
||||
|
||||
char* prompt = NULL;
|
||||
int command = -1;
|
||||
bool _debug = true;
|
||||
bool _debug = false;
|
||||
|
||||
int execute(void);
|
||||
|
||||
@ -85,10 +85,12 @@ static char* commands[] = {
|
||||
|
||||
"int16test",
|
||||
|
||||
"startbga",
|
||||
|
||||
NULL,
|
||||
};
|
||||
|
||||
const int NUM_COMMANDS = 19; /* Yes, including the NULL */
|
||||
const int NUM_COMMANDS = 21; /* Yes, including the NULL */
|
||||
|
||||
void kshell_start(void)
|
||||
{
|
||||
@ -120,7 +122,7 @@ void kshell_start(void)
|
||||
|
||||
command = -1;
|
||||
|
||||
if (strcmp(i, "") == 0)
|
||||
if (strlen(i) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -129,6 +131,9 @@ void kshell_start(void)
|
||||
break;
|
||||
}
|
||||
|
||||
/*char** argv = split(i, ' ');*/
|
||||
|
||||
|
||||
for (int j = 0; j < NUM_COMMANDS; j++)
|
||||
{
|
||||
if (strcmp(i, commands[j]) == 0)
|
||||
@ -171,9 +176,9 @@ void kshell_start(void)
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("C: %s; %i\n", commands[command], command);
|
||||
printf("C: %s; %i\n", commands[command], command);
|
||||
}
|
||||
|
||||
execute();
|
||||
|
||||
@ -269,8 +274,8 @@ int execute(void)
|
||||
extern uint8_t __kernel_end;
|
||||
size_t kernel_size = (size_t)&__kernel_end - (size_t)&__kernel_start;
|
||||
|
||||
printf("Kernel start: 0x%x\n", (&__kernel_start));
|
||||
printf("Kernel end: 0x%x\n", (&__kernel_end));
|
||||
printf("Kernel start: %p\n", (&__kernel_start));
|
||||
printf("Kernel end: %p\n", (&__kernel_end));
|
||||
printf("Kernel size (bytes): %llu\n", (uint64_t) kernel_size);
|
||||
printf("Kernel size (kbytes): %llu\n", (((uint64_t) kernel_size) / 1000));
|
||||
printf("Kernel size (mbytes): %f\n", (((uint64_t) kernel_size) / 1000.0) / 1000.0);
|
||||
@ -287,8 +292,10 @@ int execute(void)
|
||||
extern uint8_t __bss_start;
|
||||
extern uint8_t __bss_end;
|
||||
|
||||
printf(".text: %i\n.data: %i\n.rodata: %i\n.bss: %i\n", ((&__kernel_text_end) - (&__kernel_text_start)), ((&__kernel_data_end) - (&__kernel_data_start)),
|
||||
((&__kernel_rodata_end) - (&__kernel_rodata_start)), ((&__bss_end) - (&__bss_start)));
|
||||
printf(".text: %i\n.data: %i\n.rodata: %i\n.bss: %i\n", ((&__kernel_text_end) - (&__kernel_text_start)),
|
||||
((&__kernel_data_end) - (&__kernel_data_start)),
|
||||
((&__kernel_rodata_end) - (&__kernel_rodata_start)),
|
||||
((&__bss_end) - (&__bss_start)));
|
||||
|
||||
break;
|
||||
}
|
||||
@ -412,7 +419,7 @@ int execute(void)
|
||||
}
|
||||
case 14:
|
||||
{
|
||||
#if 0
|
||||
#if 1
|
||||
void taskA() { while (1) printf("A"); }
|
||||
void taskB() { while (1) printf("B"); }
|
||||
|
||||
@ -516,14 +523,28 @@ int execute(void)
|
||||
|
||||
printf("Parsing ELF headers\n");
|
||||
|
||||
elf_executable_t* f = load_elf32(buffer);
|
||||
elf_executable_t* f = NULL;
|
||||
int j = load_elf32(buffer, &f);
|
||||
|
||||
printf("Attempting execution of executable...\n");
|
||||
if (j != 0)
|
||||
{
|
||||
printf("Invalid ELF file\n");
|
||||
goto b_1;
|
||||
}
|
||||
|
||||
printf("Attempting execution of executable at (%p)...\n", f->entry_point);
|
||||
|
||||
retv = f->entry_point();
|
||||
|
||||
printf("\nreturn value: %i\n", retv);
|
||||
|
||||
b_1:
|
||||
|
||||
if (f)
|
||||
{
|
||||
free(f);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 18:
|
||||
@ -536,6 +557,17 @@ int execute(void)
|
||||
|
||||
printf("test ran\n");
|
||||
|
||||
break;
|
||||
}
|
||||
case 19:
|
||||
{
|
||||
extern void bga_defaults(void);
|
||||
|
||||
bga_defaults();
|
||||
|
||||
extern void bga_drawline(int, int, int, int, uint32_t);
|
||||
bga_drawline(0, 0, 100, 100, 0x00FFFF00);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,75 +2,230 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
|
||||
#include <new_tty.h>
|
||||
|
||||
#include <builtin_games/miner.h>
|
||||
|
||||
|
||||
#define PLAYER '@'
|
||||
#define SHOP '$'
|
||||
#define STONE '#'
|
||||
#define IRON ';'
|
||||
#define COAL ':'
|
||||
#define COPPER '^'
|
||||
#define GOLD '%'
|
||||
#define RUBY '*'
|
||||
#define DIAMOND '~'
|
||||
#define PLATINUM '&'
|
||||
#define NOTHING ' '
|
||||
|
||||
|
||||
/*
|
||||
static const size_t VGA_WIDTH = 80;
|
||||
static const size_t VGA_HEIGHT = 25;
|
||||
*/
|
||||
|
||||
/* clear screen */
|
||||
void cls(void)
|
||||
{
|
||||
terminal_clear();
|
||||
}
|
||||
|
||||
static bool pointer_valid(void* ptr)
|
||||
{
|
||||
if (ptr/* && (ptr < (heap_end + 4096))*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool valid_pointer(void* ptr)
|
||||
{
|
||||
return pointer_valid(ptr);
|
||||
}
|
||||
|
||||
/*const char PLAYER = '@';
|
||||
const char ENEMY = '*';
|
||||
const char PLAYER_BULLET = '^';
|
||||
const char ENEMY_BULLET = '`'
|
||||
const char BOMB = '*';
|
||||
const char EMPTY = ' ';*/
|
||||
|
||||
#define MAP_ROWS 25
|
||||
#define MAP_COLUMNS 25
|
||||
|
||||
#define PLAYER_STARTING_POS (MAP_COLUMNS / 2) /* for MAP_COLUMNS being 25, this will be 12. */
|
||||
|
||||
#define STARTING_ENEMY_NUM 4
|
||||
|
||||
enum {
|
||||
PLAYER = '@',
|
||||
PLAYER_BULLET = '^',
|
||||
ENEMY = '%',
|
||||
ENEMY_BULLET = '`',
|
||||
BOMB = '*',
|
||||
EMPTY = ' ',
|
||||
};
|
||||
|
||||
struct bullet {
|
||||
bool players; /* if enemies, false */
|
||||
|
||||
int row;
|
||||
int column;
|
||||
};
|
||||
|
||||
struct game_vars {
|
||||
tty_t* tty;
|
||||
uint32_t stored_tty_flags;
|
||||
|
||||
int v;
|
||||
|
||||
char c;
|
||||
|
||||
int player_score;
|
||||
int player_credits;
|
||||
|
||||
bool error;
|
||||
|
||||
int num_enemies;
|
||||
int num_enemy_step;
|
||||
char** map; /* char map[MAP_ROWS][MAP_COLUMNS] */
|
||||
|
||||
bool enemys[MAP_COLUMNS]; /* enemy bitmap */
|
||||
|
||||
struct bullet* bullets;
|
||||
int num_bullets;
|
||||
};
|
||||
|
||||
|
||||
void init_map(struct game_vars* gv)
|
||||
{
|
||||
for (int i = 0; i < MAP_ROWS; i++)
|
||||
{
|
||||
for (int j = 0; j < MAP_COLUMNS; j++)
|
||||
{
|
||||
gv->map[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
gv->map[0][PLAYER_STARTING_POS] = PLAYER;
|
||||
|
||||
int enemy_pos = 0;
|
||||
|
||||
for (int b = 0; b < STARTING_ENEMY_NUM; b++)
|
||||
{
|
||||
gv->map[24][enemy_pos] = ENEMY;
|
||||
enemy_pos++;
|
||||
gv->num_enemies++;
|
||||
gv->enemys[b] = true;
|
||||
}
|
||||
|
||||
if (!valid_pointer(gv->map))
|
||||
{
|
||||
gv->error = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ai(struct game_vars* gv)
|
||||
{
|
||||
for (int i = 0; i < MAP_COLUMNS; i++)
|
||||
{
|
||||
if ((gv->map[24][i] == ENEMY) && (gv->map[0][i] == PLAYER))
|
||||
{
|
||||
gv->map[23][i] = ENEMY_BULLET;
|
||||
int num_bullets = gv->num_bullets;
|
||||
gv->bullets[num_bullets].players = false;
|
||||
gv->bullets[num_bullets].column = i;
|
||||
gv->bullets[num_bullets].row = 23;
|
||||
gv->num_bullets++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tick(struct game_vars* gv)
|
||||
{
|
||||
for (int i = 0; i < gv->num_bullets; i++)
|
||||
{
|
||||
struct bullet* b = &gv->bullets[i];
|
||||
gv->map[b->row][b->column] = EMPTY;
|
||||
b->column++;
|
||||
b->row++;
|
||||
gv->map[b->row][b->column] = b->players ? PLAYER_BULLET : ENEMY_BULLET;
|
||||
}
|
||||
}
|
||||
|
||||
int init_game(struct game_vars* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
ptr->error = false;
|
||||
|
||||
init_map(ptr);
|
||||
|
||||
ptr->num_enemy_step++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void miner_main(void)
|
||||
{
|
||||
terminal_clear();
|
||||
#if 0
|
||||
cls();
|
||||
|
||||
struct game_vars gv = { .tty = get_active_tty(), .stored_tty_flags = tty_get_flags(get_active_tty()),
|
||||
.v = 0, .c = 0,
|
||||
.player_score = 0, .player_credits = 0,
|
||||
.error = false,
|
||||
.num_enemies = STARTING_ENEMY_NUM, .num_enemy_step = 0,
|
||||
.map = malloc(MAP_COLUMNS * MAP_ROWS),
|
||||
.bullets = NULL, .num_bullets = 0,
|
||||
};
|
||||
|
||||
memset(gv.enemys, 0, sizeof(gv.enemys));
|
||||
|
||||
if (!gv.map)
|
||||
{
|
||||
goto quit;
|
||||
}
|
||||
|
||||
printf("gv.map = %p\n", gv.map);
|
||||
|
||||
gv.tty->flags |= TTY_RAW;
|
||||
gv.tty->flags &= ~TTY_CANONICAL;
|
||||
gv.tty->flags &= ~TTY_ECHO; /* disable echo */
|
||||
|
||||
printf("\n\tMiner\n\t\tMine ores to sell for money and upgrade your drone\n\n\n\t\t\tHIT ENTER TO CONTINUE, TAB TO EXIT\n");
|
||||
|
||||
char b = get_char();
|
||||
|
||||
while (b != '\n' && b != '\t')
|
||||
/*while (gv.c != '\n' && gv.c != '\t')
|
||||
{
|
||||
sleep(10);
|
||||
b = get_char();
|
||||
gv.c = getchar();
|
||||
}
|
||||
|
||||
if (b == '\t')
|
||||
if (gv.c == '\t')
|
||||
{
|
||||
return;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
uint16_t c = 0x0;
|
||||
cls();*/
|
||||
|
||||
terminal_clear();
|
||||
|
||||
while (true)
|
||||
while (1)
|
||||
{
|
||||
sleep(10);
|
||||
gv.c = getchar();
|
||||
|
||||
c = get_key();
|
||||
|
||||
if (c == 0xFFFA || c == 0x0)
|
||||
if (gv.c == '\t')
|
||||
{
|
||||
continue;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
break;
|
||||
sleep(500);
|
||||
}
|
||||
|
||||
b = getchar();
|
||||
quit:
|
||||
|
||||
while (b == 0x5)
|
||||
gv.tty->flags = gv.stored_tty_flags;
|
||||
if (gv.map && pointer_valid(gv.map))
|
||||
{
|
||||
sleep(10);
|
||||
b = getchar();
|
||||
free(gv.map);
|
||||
}
|
||||
|
||||
terminal_clear();
|
||||
cls();
|
||||
|
||||
printf("Goodbye!\n");
|
||||
|
||||
sleep(2000);
|
||||
|
||||
cls();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -35,3 +35,9 @@ uint64_t int_pow(uint64_t base, uint32_t exp)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int abs(int x)
|
||||
{
|
||||
return (x < 0) ? -x : x;
|
||||
}
|
||||
|
||||
24
lib/stdio.c
24
lib/stdio.c
@ -1,7 +1,8 @@
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
#include <types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
#include <kernel/syscall.h>
|
||||
#include <tty.h>
|
||||
|
||||
@ -13,7 +14,7 @@ int write(uint32_t fd, void* data, size_t len)
|
||||
{
|
||||
if (fd == STDOUT)
|
||||
{
|
||||
print_uint((uint32_t) len);
|
||||
/*print_uint((uint32_t) len);*/
|
||||
terminal_write((char*) data, len);
|
||||
}
|
||||
else
|
||||
@ -30,8 +31,14 @@ int read(uint32_t fd, void* data, size_t max_len)
|
||||
|
||||
if (fd == STDIN)
|
||||
{
|
||||
char* sptr = (char*) data; /* this really shouldn't be needed... */
|
||||
sptr = gets_new(&rv);
|
||||
char* rd = gets_new(&rv);
|
||||
size_t sz = strlen(rd);
|
||||
memcpy(data, rd, (sz < max_len) ? sz : max_len);
|
||||
|
||||
if (!rd)
|
||||
{
|
||||
printf("rd is NULL!\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -45,12 +52,7 @@ extern bool ps2keyboard_initialized;
|
||||
|
||||
char getchar(void)
|
||||
{
|
||||
if (ps2keyboard_initialized)
|
||||
{
|
||||
return get_char();
|
||||
}
|
||||
|
||||
return '\0';
|
||||
return tty_get_char();
|
||||
}
|
||||
|
||||
char* getstring(void)
|
||||
@ -92,6 +94,8 @@ int getstr(char* dest)
|
||||
}
|
||||
|
||||
strcpy(dest, p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void putc(char c)
|
||||
|
||||
75
lib/string.c
75
lib/string.c
@ -492,3 +492,78 @@ void strlnstripip(char* s)
|
||||
s[len-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
char** split(const char* str, char delim)
|
||||
{
|
||||
if (!str)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t count = 1;
|
||||
for (const char* p = str; *p; p++)
|
||||
{
|
||||
if (*p == delim)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
char** result = malloc((count + 1) * sizeof(char*));
|
||||
if (!result)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t idx = 0;
|
||||
const char* start = str;
|
||||
|
||||
for (const char* p = str; ; p++)
|
||||
{
|
||||
if (*p == delim || *p == '\0')
|
||||
{
|
||||
size_t len = p - start;
|
||||
|
||||
char* token = malloc(len + 1);
|
||||
if (!token)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
token[i] = start[i];
|
||||
}
|
||||
|
||||
token[len] = '\0';
|
||||
|
||||
result[idx++] = token;
|
||||
|
||||
start = p + 1;
|
||||
|
||||
if (*p == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result[idx] = NULL; /* null-terminate the array */
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void free_split(char** parts)
|
||||
{
|
||||
if (!parts)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; parts[i] != NULL; i++)
|
||||
{
|
||||
free(parts[i]);
|
||||
}
|
||||
|
||||
free(parts);
|
||||
}
|
||||
|
||||
BIN
user/hello.elf
BIN
user/hello.elf
Binary file not shown.
@ -28,7 +28,8 @@ int main(void)
|
||||
{
|
||||
writestring("command: ");
|
||||
|
||||
char* istr;
|
||||
char istr[128];
|
||||
memset(istr, 0, sizeof(istr));
|
||||
|
||||
int rv = getstring(istr);
|
||||
|
||||
@ -38,7 +39,7 @@ int main(void)
|
||||
break;
|
||||
}
|
||||
|
||||
if (rv != 0)
|
||||
if (rv < 0)
|
||||
{
|
||||
writestring("\nERROR: getstring did not return 0\n");
|
||||
break;
|
||||
@ -54,6 +55,10 @@ int main(void)
|
||||
|
||||
writestring("you entered: ");
|
||||
writestring(istr);
|
||||
writestring("len: ");
|
||||
print_uint((uint32_t) len);
|
||||
writestring("\nfirst char: ");
|
||||
writechar(*istr);
|
||||
|
||||
writestring(" ASCII -> ");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user