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
|
WNOFLAGS := -Wno-discarded-qualifiers
|
||||||
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS) -nostdlib -nostartfiles -include include/kincl.h
|
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS) -nostdlib -nostartfiles -include include/kincl.h
|
||||||
LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib -nostartfiles
|
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
|
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 -d int,cpu_reset -D qemu.log # -audiodev pa,id=speaker -machine pcspk-audiodev=speaker
|
QEMUFLGS_EXT := -vga std
|
||||||
MOR_QEMUFLGS := -net none -netdev user,id=n0 -device rtl8139,netdev=n0 -serial file:serial.log
|
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
|
SRC_DIRS := kernel drivers lib
|
||||||
INCLUDE_DIRS := include
|
INCLUDE_DIRS := include
|
||||||
ARCH_DIR := arch
|
ARCH_DIR := arch
|
||||||
@ -26,6 +28,9 @@ BOOT_DIR := $(ISO_DIR)/boot
|
|||||||
GRUB_DIR := $(BOOT_DIR)/grub
|
GRUB_DIR := $(BOOT_DIR)/grub
|
||||||
GRUB_CFG := grub.cfg
|
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 ===
|
# === File collection ===
|
||||||
C_SRCS := $(foreach dir, $(SRC_DIRS), $(shell find $(dir) -name '*.c'))
|
C_SRCS := $(foreach dir, $(SRC_DIRS), $(shell find $(dir) -name '*.c'))
|
||||||
S_SRCS := $(foreach dir, $(ARCH_DIR), $(shell find $(dir) -name '*.s'))
|
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)
|
iso: $(TARGET)
|
||||||
@grub-file --is-x86-multiboot $(TARGET) && echo "multiboot confirmed" || (echo "not multiboot" && exit 1)
|
@grub-file --is-x86-multiboot $(TARGET) && echo "multiboot confirmed" || (echo "not multiboot" && exit 1)
|
||||||
mkdir -p $(GRUB_DIR)
|
mkdir -p $(GRUB_DIR)
|
||||||
cp $(TARGET) $(BOOT_DIR)/
|
cp $(TARGET) $(BOOT_DIR)
|
||||||
cp $(GRUB_CFG) $(GRUB_DIR)/
|
ifneq ($(IS_RPI),1)
|
||||||
|
cp $(GRUB_CFG) $(GRUB_DIR)
|
||||||
grub-mkrescue -o $(ISO) $(ISO_DIR)
|
grub-mkrescue -o $(ISO) $(ISO_DIR)
|
||||||
|
endif
|
||||||
|
|
||||||
# === Run in QEMU ===
|
# === Run in QEMU ===
|
||||||
run: iso
|
run: iso
|
||||||
@ -83,8 +90,12 @@ run: iso
|
|||||||
$(QEMU_MKE_IMG); \
|
$(QEMU_MKE_IMG); \
|
||||||
sudo mkfs.fat $(MKFS_FLAGS) espresso.img; \
|
sudo mkfs.fat $(MKFS_FLAGS) espresso.img; \
|
||||||
fi
|
fi
|
||||||
@echo
|
@echo $(IS_RPI)
|
||||||
qemu-system-i386 $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS)
|
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 ===
|
# === Clean all build artifacts ===
|
||||||
@ -99,9 +110,15 @@ clean_disk:
|
|||||||
commit:
|
commit:
|
||||||
ifndef MSG
|
ifndef MSG
|
||||||
$(error MSG required)
|
$(error MSG required)
|
||||||
|
endif
|
||||||
|
ifndef RELEASENUM
|
||||||
|
$(error RELEASENUM required)
|
||||||
endif
|
endif
|
||||||
git add .
|
git add .
|
||||||
git commit -m "$(MSG)"
|
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
|
.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))
|
#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;
|
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)
|
if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
|
||||||
{
|
{
|
||||||
printf("Invalid ELF file\n");
|
printf("Invalid ELF file\n");
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ehdr->e_machine != 3 || ehdr->e_type != 2)
|
if (ehdr->e_machine != 3 || ehdr->e_type != 2)
|
||||||
{
|
{
|
||||||
printf("Unsupported ELF type or architecture\n");
|
printf("Unsupported ELF type or architecture\n");
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf32_Phdr* phdrs = (Elf32_Phdr*)((uint8_t*)elf_data + ehdr->e_phoff);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
elf_executable_t* result = malloc(sizeof(elf_executable_t));
|
*ptr = malloc(sizeof(elf_executable_t));
|
||||||
result->entry_point = (elf_entry_t)(uintptr_t)ehdr->e_entry;
|
|
||||||
return result;
|
if (ptr)
|
||||||
|
{
|
||||||
|
(*ptr)->entry_point = (elf_entry_t)(uintptr_t) ehdr->e_entry;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
/*
|
||||||
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(void) drive;
|
||||||
|
|
||||||
fs.bytes_per_sector = boot_sector[11] | (boot_sector[12] << 8);
|
fs.bytes_per_sector = boot_sector[11] | (boot_sector[12] << 8);
|
||||||
fs.sectors_per_cluster = boot_sector[13];
|
fs.sectors_per_cluster = boot_sector[13];
|
||||||
fs.reserved_sector_count = boot_sector[14] | (boot_sector[15] << 8);
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx == fs.bytes_per_sector - 1)
|
if (idx == (uint32_t)(fs.bytes_per_sector - 1))
|
||||||
{
|
{
|
||||||
/* entry spans boundary -> read next sector */
|
/* entry spans boundary -> read next sector */
|
||||||
uint8_t next_sector[SECTOR_SIZE];
|
uint8_t next_sector[SECTOR_SIZE];
|
||||||
|
|||||||
@ -7,25 +7,7 @@
|
|||||||
|
|
||||||
/* we use something similar to the Linux kernel in terms of a VFS system */
|
/* 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)
|
#if 0
|
||||||
{
|
|
||||||
(void) __f;
|
|
||||||
terminal_write(__s, __l);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fdtable* vfs_init_kernel_fdtable(void)
|
struct fdtable* vfs_init_kernel_fdtable(void)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
struct fdtable* ft = malloc(sizeof(struct fdtable));
|
struct fdtable* ft = malloc(sizeof(struct fdtable));
|
||||||
struct file* _stdout = malloc(sizeof(struct file));
|
struct file* _stdout = malloc(sizeof(struct file));
|
||||||
struct file* _stdin = 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_offset = 0;
|
||||||
_stdout->f_refcount = 1;
|
_stdout->f_refcount = 1;
|
||||||
_stdout->f_ops = { .read = NULL, .write = vfs_handle_stdout };
|
_stdout->f_ops = { .read = NULL, .write = vfs_handle_stdout };
|
||||||
#endif
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int init_vfs(int argc, char** argv)
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_sector_size(uint8_t drive)
|
||||||
|
{
|
||||||
|
(void) drive;
|
||||||
|
return SECTOR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t ide_identify(uint8_t drive, uint16_t* buffer)
|
int32_t ide_identify(uint8_t drive, uint16_t* buffer)
|
||||||
{
|
{
|
||||||
uint16_t io = ATA_PRIMARY_IO;
|
uint16_t io = ATA_PRIMARY_IO;
|
||||||
|
|||||||
@ -61,7 +61,6 @@ int init_keyboard(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
registers_t* keyboard_handler(registers_t* regs)
|
registers_t* keyboard_handler(registers_t* regs)
|
||||||
{
|
{
|
||||||
if (!(inb(PS2_STATUS_PORT) & 1))
|
if (!(inb(PS2_STATUS_PORT) & 1))
|
||||||
@ -70,14 +69,78 @@ registers_t* keyboard_handler(registers_t* regs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t scancode = inb(PS2_DATA_PORT);
|
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;
|
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 */
|
/* Handle shift press/release */
|
||||||
if (scancode == 0x2A || scancode == 0x36)
|
/*if (scancode == 0x2A || scancode == 0x36)
|
||||||
{
|
{
|
||||||
mods |= MODIFIER_SHIFT;
|
mods |= MODIFIER_SHIFT;
|
||||||
return regs;
|
return regs;
|
||||||
@ -89,9 +152,11 @@ registers_t* keyboard_handler(registers_t* regs)
|
|||||||
}
|
}
|
||||||
else if (scancode == 0x3A)
|
else if (scancode == 0x3A)
|
||||||
{
|
{
|
||||||
TOGGLE_BIT(mods, 0); /* TOGGLE_BIT defined in types.h, should move elsewhere. */
|
TOGGLE_BIT(mods, 0);
|
||||||
return regs;
|
return regs;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
/*else if (scancode == 0xE0)
|
/*else if (scancode == 0xE0)
|
||||||
{
|
{
|
||||||
extended = true;
|
extended = true;
|
||||||
@ -127,22 +192,10 @@ registers_t* keyboard_handler(registers_t* regs)
|
|||||||
return;
|
return;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
bool release = scancode & 0x80;
|
/*bool release = scancode & 0x80;
|
||||||
scancode &= 0x7F;
|
scancode &= 0x7F;
|
||||||
|
|
||||||
if (release)
|
if (release)
|
||||||
{
|
{
|
||||||
return regs;
|
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;
|
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)
|
tty_t* tty_get_active(void)
|
||||||
{
|
{
|
||||||
return active_tty;
|
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)
|
void tty_backspace(tty_t* tty)
|
||||||
{
|
{
|
||||||
if (tty->head == tty->tail)
|
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;
|
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)
|
ssize_t tty_read_active(char* buf, size_t count)
|
||||||
{
|
{
|
||||||
return tty_read(active_tty, buf, 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();
|
IRQ_DISABLE();
|
||||||
spin_lock(&tty->lock);
|
spin_lock(&tty->lock);
|
||||||
|
|
||||||
if (!tty_empty(tty))
|
if (tty->char_available)
|
||||||
{
|
{
|
||||||
char c = tty->input_buffer[tty->tail];
|
char c = tty->last_char;
|
||||||
tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE;
|
tty->char_available = false;
|
||||||
tty->tail = next_index(tty->tail);
|
|
||||||
|
|
||||||
spin_unlock(&tty->lock);
|
|
||||||
IRQ_ENABLE(); /* change? *//*
|
|
||||||
|
|
||||||
buf[bytes_read++] = c;
|
|
||||||
|
|
||||||
if (is_canonical(tty) && c == '\n')
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
spin_unlock(&tty->lock);
|
spin_unlock(&tty->lock);
|
||||||
IRQ_ENABLE();
|
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)
|
ssize_t tty_read(tty_t* tty, char* buf, size_t count)
|
||||||
{
|
{
|
||||||
if (!tty || !buf)
|
if (!tty || !buf)
|
||||||
return -1;
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
size_t bytes = 0;
|
size_t bytes = 0;
|
||||||
|
|
||||||
@ -169,6 +223,9 @@ int init_tty(void)
|
|||||||
active_tty = t;
|
active_tty = t;
|
||||||
num_ttys = 1;
|
num_ttys = 1;
|
||||||
|
|
||||||
|
t->f_ops.read = tty_fread;
|
||||||
|
t->line_ready = false;
|
||||||
|
|
||||||
return 0;
|
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)
|
if (!tty || c == 0)
|
||||||
return;
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IRQ_DISABLE();
|
IRQ_DISABLE();
|
||||||
spin_lock(&tty->lock);
|
spin_lock(&tty->lock);
|
||||||
|
|
||||||
/* backspace */
|
raw_put(tty, c);
|
||||||
|
|
||||||
if (c == '\b')
|
if (c == '\b')
|
||||||
{
|
{
|
||||||
if (tty->head != tty->tail)
|
if (tty->head != tty->tail)
|
||||||
@ -255,9 +315,7 @@ void tty_input_char(tty_t* tty, char c)
|
|||||||
|
|
||||||
if (tty->flags & TTY_ECHO)
|
if (tty->flags & TTY_ECHO)
|
||||||
{
|
{
|
||||||
putc('\b');/*
|
putc('\b');
|
||||||
putc(' ');
|
|
||||||
putc('\b');*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +340,65 @@ void tty_input_char(tty_t* tty, char c)
|
|||||||
spin_unlock(&tty->lock);
|
spin_unlock(&tty->lock);
|
||||||
IRQ_ENABLE();
|
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)
|
if (tty->flags & TTY_ECHO)
|
||||||
{
|
{
|
||||||
putc(c);
|
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 pci_config_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset)
|
||||||
{
|
{
|
||||||
uint32_t address = 0;
|
uint32_t address = 0;
|
||||||
address |= (bus << 16); /* Bus number (bits 23-16) */
|
address |= (bus << 16); /* Bus number (bits 23-16) */
|
||||||
address |= (device << 11); /* Device number (bits 15-11) */
|
address |= (device << 11); /* Device number (bits 15-11) */
|
||||||
address |= (function << 8); /* Function number (bits 10-8) */
|
address |= (function << 8); /* Function number (bits 10-8) */
|
||||||
address |= (offset & 0xFC); /* Register offset (bits 7-0) */
|
address |= (offset & 0xFC); /* Register offset (bits 7-0) */
|
||||||
address |= (1 << 31); /* Enable configuration access */
|
address |= (1 << 31); /* Enable configuration access */
|
||||||
|
|
||||||
outl(PCI_CONFIG_ADDRESS, address); /* Write address to 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 */
|
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)
|
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);
|
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_ADDRESS, address); /* Send the address to PCI config space */
|
||||||
outl(PCI_CONFIG_DATA, value); /* Write data 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)
|
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)
|
for (size_t i = 0; i < size; i += 4)
|
||||||
{
|
{
|
||||||
uint32_t value = pci_config_read(bus, device, function, offset + i);
|
uint32_t value = pci_config_read(bus, device, function, offset + i);
|
||||||
|
|
||||||
size_t remaining = size - i;
|
size_t remaining = size - i;
|
||||||
if (remaining >= 4)
|
if (remaining >= 4)
|
||||||
{
|
{
|
||||||
*(uint32_t*)(buf + i) = value;
|
*(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)
|
void pci_init(void)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
printf("[ PCI ] Initializing PCI...\n");
|
printf("[ PCI ] Initializing PCI...\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pci_enumerate();
|
pci_enumerate();
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
printf("[ PCI ] PCI initialized\n");
|
printf("[ PCI ] PCI initialized\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void pci_enumerate(void)
|
void pci_enumerate(void)
|
||||||
{
|
{
|
||||||
for (uint16_t bus = 0; bus < 256; bus++) /* Maximum 256 buses */
|
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 (uint8_t function = 0; function < 8; function++) /* Maximum 8 functions per device */
|
for (uint8_t device = 0; device < 32; device++) /* Maximum 32 devices per bus */
|
||||||
{
|
{
|
||||||
struct pci_header pre_header;
|
for (uint8_t function = 0; function < 8; function++) /* Maximum 8 functions per device */
|
||||||
pci_config_read_block(bus, device, function, 0x00, &pre_header, sizeof(pre_header));
|
{
|
||||||
|
struct pci_header pre_header;
|
||||||
|
pci_config_read_block(bus, device, function, 0x00, &pre_header, sizeof(pre_header));
|
||||||
|
|
||||||
if (pre_header.vendor_id == 0xFFFF)
|
if (pre_header.vendor_id == 0xFFFF)
|
||||||
{
|
{
|
||||||
continue; /* No device present */
|
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)
|
if (pre_header.class_code == 0xB)
|
||||||
{
|
{
|
||||||
/*configure_ahci_controller(hdr);*/
|
printf("Processor found on PCI bus, what?!?!\n"); /* For some stupid reason, processors can be on the PCI bus? */
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/*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.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);*/
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
#include <vga/vga.h>
|
#include <vga/vga.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <port_io.h>
|
#include <port_io.h>
|
||||||
|
#include <new_tty.h>
|
||||||
|
#include <fs/vfs.h>
|
||||||
|
|
||||||
#include <tty.h>
|
#include <tty.h>
|
||||||
|
|
||||||
@ -18,6 +20,19 @@ void terminal_initialize(void)
|
|||||||
terminal_update_cursor();
|
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)
|
void terminal_get_cursor(int* row, int* column)
|
||||||
{
|
{
|
||||||
*row = (int) terminal_row;
|
*row = (int) terminal_row;
|
||||||
@ -106,7 +121,7 @@ void terminal_putchar(const char c)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (uc == '\b')
|
/*else if (uc == '\b')
|
||||||
{
|
{
|
||||||
if (terminal_column == 0)
|
if (terminal_column == 0)
|
||||||
{
|
{
|
||||||
@ -117,7 +132,7 @@ void terminal_putchar(const char c)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
terminal_update_cursor(); /* For good measure */
|
terminal_update_cursor();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -131,6 +146,31 @@ void terminal_putchar(const char c)
|
|||||||
|
|
||||||
terminal_update_cursor();
|
terminal_update_cursor();
|
||||||
|
|
||||||
|
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_update_cursor();
|
||||||
|
|
||||||
return;
|
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" {
|
menuentry "Espresso" {
|
||||||
multiboot /boot/espresso.elf
|
multiboot /boot/espresso.elf
|
||||||
|
boot
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,12 +36,13 @@ typedef struct {
|
|||||||
uint32_t p_align;
|
uint32_t p_align;
|
||||||
} Elf32_Phdr;
|
} Elf32_Phdr;
|
||||||
|
|
||||||
|
//typedef int (*elf_entry_t)(int, char**);
|
||||||
typedef int (*elf_entry_t)(void);
|
typedef int (*elf_entry_t)(void);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
elf_entry_t entry_point;
|
elf_entry_t entry_point;
|
||||||
} elf_executable_t;
|
} elf_executable_t;
|
||||||
|
|
||||||
elf_executable_t* load_elf32(void* elf_data);
|
int load_elf32(void* elf_data, elf_executable_t** ptr);
|
||||||
|
|
||||||
#endif
|
#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 read_sector(uint64_t lba, void* buffer);
|
||||||
int32_t write_sector(uint64_t lba, const void* buffer);
|
int32_t write_sector(uint64_t lba, const void* buffer);
|
||||||
|
|
||||||
|
int get_sector_size(uint8_t drive);
|
||||||
|
|
||||||
#endif
|
#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>
|
#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
|
#endif
|
||||||
|
|||||||
@ -13,5 +13,7 @@ static inline int div_round_up(int a, int b)
|
|||||||
return (a + b - 1) / b;
|
return (a + b - 1) / b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int abs(int x);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -4,11 +4,14 @@
|
|||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
|
#include <fs/vfs.h>
|
||||||
|
|
||||||
#include <processes.h>
|
#include <processes.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
|
|
||||||
|
|
||||||
#define TTY_BUFFER_SIZE 4096
|
#define TTY_BUFFER_SIZE 4096
|
||||||
|
#define TTY_RAW_BUFFER_SIZE 16
|
||||||
#define MAX_TTYS 8 /* to make things easy, might change later */
|
#define MAX_TTYS 8 /* to make things easy, might change later */
|
||||||
|
|
||||||
#define TTY_ECHO 0x10 /* 0b00010000 */
|
#define TTY_ECHO 0x10 /* 0b00010000 */
|
||||||
@ -16,7 +19,9 @@
|
|||||||
#define TTY_ACTIVE 0x01 /* 0b00000001 */
|
#define TTY_ACTIVE 0x01 /* 0b00000001 */
|
||||||
|
|
||||||
#define TTY_CANONICAL 0x40 /* 0b01000000 */
|
#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 */
|
#define TTY_NULL 0x80 /* 0b10000000 --- used to end the list of tty_t structs in the ttys array */
|
||||||
|
|
||||||
@ -44,7 +49,17 @@ typedef struct tty_t {
|
|||||||
bool canonical;
|
bool canonical;
|
||||||
bool line_ready;
|
bool line_ready;
|
||||||
|
|
||||||
|
/* for raw mode */
|
||||||
|
char raw_buf[TTY_RAW_BUFFER_SIZE];
|
||||||
|
size_t raw_head;
|
||||||
|
size_t raw_tail;
|
||||||
|
|
||||||
spinlock_t lock;
|
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 */
|
pid_t foreground_pgid; /* not used yet */
|
||||||
} tty_t;
|
} 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(tty_t* tty, char* buf, size_t count);
|
||||||
ssize_t tty_read_active(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* get_active_tty(void);
|
||||||
tty_t* tty_get_active(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);
|
tty_t* make_tty(uint32_t flags);
|
||||||
|
|
||||||
void tty_receive_char(char c, uint32_t kbd_mod);
|
void tty_receive_char(char c, uint32_t kbd_mod);
|
||||||
|
|||||||
@ -10,11 +10,23 @@ static inline uint32_t inl(uint16_t port)
|
|||||||
return rv;
|
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)
|
static inline __attribute__((always_inline)) void outl(uint16_t port, uint32_t data)
|
||||||
{
|
{
|
||||||
asm volatile ("outl %%eax, %%dx" : : "dN" (port), "a" (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)
|
static inline __attribute__((always_inline)) void outb(uint16_t port, uint8_t val)
|
||||||
{
|
{
|
||||||
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) : "memory");
|
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* strtok(char* str, const char* delim);
|
||||||
char* strchr(const char* s, int c);
|
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 lowers(char* str);
|
||||||
void uppers(char* str);
|
void uppers(char* str);
|
||||||
|
|
||||||
@ -35,4 +30,11 @@ int atoi(const char *str);
|
|||||||
long atol(const char *str);
|
long atol(const char *str);
|
||||||
double atof(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
|
#endif
|
||||||
|
|||||||
@ -37,6 +37,7 @@
|
|||||||
#include <drivers/ps2_keyboard.h>
|
#include <drivers/ps2_keyboard.h>
|
||||||
#include <drivers/keyboard.h>
|
#include <drivers/keyboard.h>
|
||||||
#include <drivers/pit.h>
|
#include <drivers/pit.h>
|
||||||
|
#include <drivers/graphics/vga.h>
|
||||||
/*#include <drivers/ahci.h>*/
|
/*#include <drivers/ahci.h>*/
|
||||||
#include <drivers/ide.h>
|
#include <drivers/ide.h>
|
||||||
#include <mm/mm.h>
|
#include <mm/mm.h>
|
||||||
@ -53,6 +54,7 @@
|
|||||||
#include <builtin_games/miner.h>
|
#include <builtin_games/miner.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern void _hang_asm(void);
|
extern void _hang_asm(void);
|
||||||
extern void _sti_asm(void);
|
extern void _sti_asm(void);
|
||||||
|
|
||||||
@ -153,6 +155,9 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic)
|
|||||||
printf("Guten tag and welcome to Espresso %s\n", KERNEL_VERSION);
|
printf("Guten tag and welcome to Espresso %s\n", KERNEL_VERSION);
|
||||||
|
|
||||||
extern void terminal_clear(void);
|
extern void terminal_clear(void);
|
||||||
|
|
||||||
|
//bga_defaults();
|
||||||
|
|
||||||
|
|
||||||
terminal_clear();
|
terminal_clear();
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ const char* shell_version = "0.0.2";
|
|||||||
|
|
||||||
char* prompt = NULL;
|
char* prompt = NULL;
|
||||||
int command = -1;
|
int command = -1;
|
||||||
bool _debug = true;
|
bool _debug = false;
|
||||||
|
|
||||||
int execute(void);
|
int execute(void);
|
||||||
|
|
||||||
@ -84,11 +84,13 @@ static char* commands[] = {
|
|||||||
"exec",
|
"exec",
|
||||||
|
|
||||||
"int16test",
|
"int16test",
|
||||||
|
|
||||||
|
"startbga",
|
||||||
|
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
const int NUM_COMMANDS = 19; /* Yes, including the NULL */
|
const int NUM_COMMANDS = 21; /* Yes, including the NULL */
|
||||||
|
|
||||||
void kshell_start(void)
|
void kshell_start(void)
|
||||||
{
|
{
|
||||||
@ -120,7 +122,7 @@ void kshell_start(void)
|
|||||||
|
|
||||||
command = -1;
|
command = -1;
|
||||||
|
|
||||||
if (strcmp(i, "") == 0)
|
if (strlen(i) == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -129,6 +131,9 @@ void kshell_start(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*char** argv = split(i, ' ');*/
|
||||||
|
|
||||||
|
|
||||||
for (int j = 0; j < NUM_COMMANDS; j++)
|
for (int j = 0; j < NUM_COMMANDS; j++)
|
||||||
{
|
{
|
||||||
if (strcmp(i, commands[j]) == 0)
|
if (strcmp(i, commands[j]) == 0)
|
||||||
@ -171,10 +176,10 @@ void kshell_start(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
printf("C: %s; %i\n", commands[command], command);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("C: %s; %i\n", commands[command], command);
|
|
||||||
|
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
} while (1);
|
} while (1);
|
||||||
@ -269,8 +274,8 @@ int execute(void)
|
|||||||
extern uint8_t __kernel_end;
|
extern uint8_t __kernel_end;
|
||||||
size_t kernel_size = (size_t)&__kernel_end - (size_t)&__kernel_start;
|
size_t kernel_size = (size_t)&__kernel_end - (size_t)&__kernel_start;
|
||||||
|
|
||||||
printf("Kernel start: 0x%x\n", (&__kernel_start));
|
printf("Kernel start: %p\n", (&__kernel_start));
|
||||||
printf("Kernel end: 0x%x\n", (&__kernel_end));
|
printf("Kernel end: %p\n", (&__kernel_end));
|
||||||
printf("Kernel size (bytes): %llu\n", (uint64_t) kernel_size);
|
printf("Kernel size (bytes): %llu\n", (uint64_t) kernel_size);
|
||||||
printf("Kernel size (kbytes): %llu\n", (((uint64_t) kernel_size) / 1000));
|
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);
|
printf("Kernel size (mbytes): %f\n", (((uint64_t) kernel_size) / 1000.0) / 1000.0);
|
||||||
@ -287,9 +292,11 @@ int execute(void)
|
|||||||
extern uint8_t __bss_start;
|
extern uint8_t __bss_start;
|
||||||
extern uint8_t __bss_end;
|
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)),
|
printf(".text: %i\n.data: %i\n.rodata: %i\n.bss: %i\n", ((&__kernel_text_end) - (&__kernel_text_start)),
|
||||||
((&__kernel_rodata_end) - (&__kernel_rodata_start)), ((&__bss_end) - (&__bss_start)));
|
((&__kernel_data_end) - (&__kernel_data_start)),
|
||||||
|
((&__kernel_rodata_end) - (&__kernel_rodata_start)),
|
||||||
|
((&__bss_end) - (&__bss_start)));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 8: {
|
case 8: {
|
||||||
@ -412,7 +419,7 @@ int execute(void)
|
|||||||
}
|
}
|
||||||
case 14:
|
case 14:
|
||||||
{
|
{
|
||||||
#if 0
|
#if 1
|
||||||
void taskA() { while (1) printf("A"); }
|
void taskA() { while (1) printf("A"); }
|
||||||
void taskB() { while (1) printf("B"); }
|
void taskB() { while (1) printf("B"); }
|
||||||
|
|
||||||
@ -516,13 +523,27 @@ int execute(void)
|
|||||||
|
|
||||||
printf("Parsing ELF headers\n");
|
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();
|
retv = f->entry_point();
|
||||||
|
|
||||||
printf("\nreturn value: %i\n", retv);
|
printf("\nreturn value: %i\n", retv);
|
||||||
|
|
||||||
|
b_1:
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
free(f);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -536,6 +557,17 @@ int execute(void)
|
|||||||
|
|
||||||
printf("test ran\n");
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,75 +2,230 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <drivers/ps2_keyboard.h>
|
|
||||||
|
#include <new_tty.h>
|
||||||
|
|
||||||
#include <builtin_games/miner.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_WIDTH = 80;
|
||||||
static const size_t VGA_HEIGHT = 25;
|
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)
|
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");
|
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 (gv.c != '\n' && gv.c != '\t')
|
||||||
|
|
||||||
while (b != '\n' && b != '\t')
|
|
||||||
{
|
{
|
||||||
sleep(10);
|
gv.c = getchar();
|
||||||
b = get_char();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b == '\t')
|
if (gv.c == '\t')
|
||||||
{
|
{
|
||||||
return;
|
goto quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t c = 0x0;
|
cls();*/
|
||||||
|
|
||||||
terminal_clear();
|
while (1)
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
sleep(10);
|
gv.c = getchar();
|
||||||
|
|
||||||
c = get_key();
|
if (gv.c == '\t')
|
||||||
|
|
||||||
if (c == 0xFFFA || c == 0x0)
|
|
||||||
{
|
{
|
||||||
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);
|
free(gv.map);
|
||||||
b = getchar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
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 <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <drivers/ps2_keyboard.h>
|
||||||
#include <kernel/syscall.h>
|
#include <kernel/syscall.h>
|
||||||
#include <tty.h>
|
#include <tty.h>
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ int write(uint32_t fd, void* data, size_t len)
|
|||||||
{
|
{
|
||||||
if (fd == STDOUT)
|
if (fd == STDOUT)
|
||||||
{
|
{
|
||||||
print_uint((uint32_t) len);
|
/*print_uint((uint32_t) len);*/
|
||||||
terminal_write((char*) data, len);
|
terminal_write((char*) data, len);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -30,8 +31,14 @@ int read(uint32_t fd, void* data, size_t max_len)
|
|||||||
|
|
||||||
if (fd == STDIN)
|
if (fd == STDIN)
|
||||||
{
|
{
|
||||||
char* sptr = (char*) data; /* this really shouldn't be needed... */
|
char* rd = gets_new(&rv);
|
||||||
sptr = 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
|
else
|
||||||
{
|
{
|
||||||
@ -45,12 +52,7 @@ extern bool ps2keyboard_initialized;
|
|||||||
|
|
||||||
char getchar(void)
|
char getchar(void)
|
||||||
{
|
{
|
||||||
if (ps2keyboard_initialized)
|
return tty_get_char();
|
||||||
{
|
|
||||||
return get_char();
|
|
||||||
}
|
|
||||||
|
|
||||||
return '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* getstring(void)
|
char* getstring(void)
|
||||||
@ -92,6 +94,8 @@ int getstr(char* dest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
strcpy(dest, p);
|
strcpy(dest, p);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void putc(char c)
|
void putc(char c)
|
||||||
|
|||||||
75
lib/string.c
75
lib/string.c
@ -492,3 +492,78 @@ void strlnstripip(char* s)
|
|||||||
s[len-1] = '\0';
|
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: ");
|
writestring("command: ");
|
||||||
|
|
||||||
char* istr;
|
char istr[128];
|
||||||
|
memset(istr, 0, sizeof(istr));
|
||||||
|
|
||||||
int rv = getstring(istr);
|
int rv = getstring(istr);
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ int main(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rv != 0)
|
if (rv < 0)
|
||||||
{
|
{
|
||||||
writestring("\nERROR: getstring did not return 0\n");
|
writestring("\nERROR: getstring did not return 0\n");
|
||||||
break;
|
break;
|
||||||
@ -54,6 +55,10 @@ int main(void)
|
|||||||
|
|
||||||
writestring("you entered: ");
|
writestring("you entered: ");
|
||||||
writestring(istr);
|
writestring(istr);
|
||||||
|
writestring("len: ");
|
||||||
|
print_uint((uint32_t) len);
|
||||||
|
writestring("\nfirst char: ");
|
||||||
|
writechar(*istr);
|
||||||
|
|
||||||
writestring(" ASCII -> ");
|
writestring(" ASCII -> ");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user