Compare commits
2 Commits
0fa2351940
...
cc00613c5d
Author | SHA1 | Date |
---|---|---|
TriMill | cc00613c5d | |
TriMill | bca17fe5b9 |
|
@ -1,2 +1,3 @@
|
|||
compile_flags.txt
|
||||
bin
|
||||
disk.img
|
||||
|
|
18
Makefile
18
Makefile
|
@ -1,6 +1,6 @@
|
|||
CC=i386-elf-gcc
|
||||
LD=i386-elf-ld
|
||||
CFLAGS=-ffreestanding -g -m32 -std=c2x -O2 -Wall -Wextra -pedantic -lgcc -isystem ./libk/include
|
||||
CFLAGS=-ffreestanding -ggdb -m32 -std=gnu17 -O3 -Wall -Wextra -pedantic -lgcc -isystem ./libk/include
|
||||
|
||||
C_SOURCE=$(shell find kernel -type f -name "*.c")
|
||||
C_OBJ=$(patsubst %.c,bin/%.o,$(C_SOURCE))
|
||||
|
@ -11,7 +11,7 @@ A_OBJ=$(patsubst %.asm,bin/%_asm.o,$(A_SOURCE))
|
|||
LIBK_SOURCE=$(shell find libk -type f -name "*.c")
|
||||
LIBK_OBJ=$(patsubst %.c,bin/%.o,$(LIBK_SOURCE))
|
||||
|
||||
.PHONY: test all run clean
|
||||
.PHONY: test all run clean mkdiskimg
|
||||
|
||||
all: bin/os.iso
|
||||
|
||||
|
@ -31,19 +31,25 @@ bin/libk.a: $(LIBK_OBJ)
|
|||
@mkdir -p $(@D)
|
||||
$(AR) rcs bin/libk.a $(LIBK_OBJ)
|
||||
|
||||
bin/kernel.bin: bin/libk.a $(A_OBJ) $(C_OBJ)
|
||||
bin/kernel.bin: bin/libk.a linker.ld $(A_OBJ) $(C_OBJ)
|
||||
@mkdir -p $(@D)
|
||||
$(LD) -nmagic -o bin/kernel.bin -T linker.ld $(A_OBJ) $(C_OBJ) bin/libk.a
|
||||
|
||||
bin/os.iso: bin/kernel.bin
|
||||
bin/os.iso: bin/kernel.bin grub.cfg
|
||||
@mkdir -p $(@D)
|
||||
@mkdir -p bin/iso/boot/grub
|
||||
cp grub.cfg bin/iso/boot/grub
|
||||
cp bin/kernel.bin bin/iso/boot
|
||||
grub-mkrescue -o bin/os.iso bin/iso
|
||||
|
||||
run: all
|
||||
qemu-system-i386 -cdrom bin/os.iso
|
||||
bin/disk.img:
|
||||
@mkdir -p bin
|
||||
cp disk.img bin/disk.img
|
||||
|
||||
run: bin/os.iso bin/disk.img
|
||||
qemu-system-i386 -cdrom bin/os.iso \
|
||||
-drive file=bin/disk.img,format=raw,if=ide \
|
||||
-boot order=d
|
||||
|
||||
clean:
|
||||
rm -rf bin
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "panic.h"
|
||||
#include "bootinfo.h"
|
||||
|
||||
#define CMDLINE_MAX 128
|
||||
|
||||
static char boot_cmdline[CMDLINE_MAX];
|
||||
|
||||
static uint32_t *read_tag(uint32_t *tag) {
|
||||
uint32_t type = tag[0];
|
||||
size_t size = tag[1];
|
||||
|
||||
switch(type) {
|
||||
case 0: return NULL;
|
||||
case 1: {
|
||||
size_t cmdline_len = size - 2 * sizeof(uint32_t);
|
||||
if(cmdline_len > CMDLINE_MAX) {
|
||||
panic("Command line argument length %d exceeds maximum length %d", cmdline_len, CMDLINE_MAX);
|
||||
}
|
||||
char* cmdline = (char*)(tag + 2);
|
||||
memcpy(boot_cmdline, cmdline, cmdline_len);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
if(size % 8 != 0) {
|
||||
size += 8 - (size % 8);
|
||||
}
|
||||
return tag + size / sizeof(uint32_t);
|
||||
}
|
||||
|
||||
void bootinfo_load(void *ptr) {
|
||||
uint32_t *p = ptr;
|
||||
p += 2;
|
||||
while(p != NULL) {
|
||||
p = read_tag(p);
|
||||
}
|
||||
}
|
||||
|
||||
char* bootinfo_get_cmdline(void) {
|
||||
return boot_cmdline;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void bootinfo_load(void* ptr);
|
||||
|
||||
char* bootinfo_get_cmdline(void);
|
|
@ -0,0 +1,127 @@
|
|||
#include <sys.h>
|
||||
|
||||
#include "ata.h"
|
||||
#include "pci.h"
|
||||
#include "../panic.h"
|
||||
|
||||
#define REG_DATA 0
|
||||
#define REG_ERR 1
|
||||
#define REG_FEATURES 1
|
||||
#define REG_SECTOR_CNT 2
|
||||
#define REG_SECTOR_NUM 3
|
||||
#define REG_LBA_LO 3
|
||||
#define REG_CYLINDER_LO 4
|
||||
#define REG_LBA_MID 4
|
||||
#define REG_CYLINDER_HI 5
|
||||
#define REG_LBA_HI 5
|
||||
#define REG_DRIVE_HEAD 6
|
||||
#define REG_STATUS 7
|
||||
#define REG_COMMAND 7
|
||||
|
||||
#define STAT_ERR 0x01
|
||||
#define STAT_IDX 0x02
|
||||
#define STAT_CORR 0x04
|
||||
#define STAT_DRQ 0x08
|
||||
#define STAT_SRV 0x10
|
||||
#define STAT_DF 0x20
|
||||
#define STAT_RDY 0x40
|
||||
#define STAT_BSY 0x80
|
||||
|
||||
static bool ata_init_impl(uint16_t base, uint16_t ctrl, struct AtaDevice *dev) {
|
||||
uint8_t status = inb(base + REG_STATUS);
|
||||
outb(base + REG_DRIVE_HEAD, 0xA0);
|
||||
outb(base + REG_SECTOR_CNT, 0x00);
|
||||
outb(base + REG_LBA_LO, 0x00);
|
||||
outb(base + REG_LBA_MID, 0x00);
|
||||
outb(base + REG_LBA_HI, 0x00);
|
||||
outb(base + REG_COMMAND, 0xEC);
|
||||
status = STAT_BSY;
|
||||
while(status & STAT_BSY) {
|
||||
status = inb(base + REG_STATUS);
|
||||
}
|
||||
if(inb(base + REG_LBA_MID) != 0 || inb(base + REG_LBA_HI) != 0) {
|
||||
panic("Device is not an ATA device");
|
||||
}
|
||||
while(!(status & (STAT_DRQ | STAT_ERR))) {
|
||||
status = inb(base + REG_STATUS);
|
||||
}
|
||||
if(status & STAT_ERR) {
|
||||
uint8_t err = inb(base + REG_ERR);
|
||||
panic("Error initializing ATA device: %X", err);
|
||||
}
|
||||
uint16_t data[256];
|
||||
for(int i = 0; i < 256; i++) {
|
||||
data[i] = inw(base + REG_DATA);
|
||||
}
|
||||
uint32_t sector_count = data[60] | (data[61] << 16);
|
||||
if(sector_count == 0) {
|
||||
panic("ATA device does not support LBA28");
|
||||
}
|
||||
dev->base = base;
|
||||
dev->ctrl = ctrl;
|
||||
dev->sector_count = sector_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ata_init(struct AtaDevice *atadev, struct PciDevice pcidev) {
|
||||
uint8_t prog_if = pci_rcfg_b(pcidev, PCI_PROG_IF_B);
|
||||
|
||||
if((prog_if & 0x7F) != 0) {
|
||||
panic("Could not initialize ATA device: unsupported prog_if %X", prog_if);
|
||||
}
|
||||
|
||||
atadev->pcidev = pcidev;
|
||||
|
||||
if(!ata_init_impl(0x1F0, 0x3F6, atadev)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ata_read(struct AtaDevice atadev, uint32_t lba, uint8_t sector_count, uint16_t buf[sector_count*256]) {
|
||||
outb(atadev.base + REG_DRIVE_HEAD, 0xE0 | ((lba >> 24) & 0x0F));
|
||||
outb(atadev.base + REG_FEATURES, 0x00);
|
||||
outb(atadev.base + REG_SECTOR_CNT, sector_count);
|
||||
outb(atadev.base + REG_LBA_LO, lba & 0xFF);
|
||||
outb(atadev.base + REG_LBA_MID, (lba >> 8) & 0xFF);
|
||||
outb(atadev.base + REG_LBA_HI, (lba >> 16) & 0xFF);
|
||||
outb(atadev.base + REG_COMMAND, 0x20);
|
||||
for(int i = 0; i < sector_count; i++) {
|
||||
while(true) {
|
||||
uint8_t status = inb(atadev.ctrl);
|
||||
if(status & STAT_DRQ) break;
|
||||
if(status & STAT_DF) panic("Drive failure");
|
||||
if(status & STAT_ERR) panic("Read disk error");
|
||||
}
|
||||
for(int j = 0; j < 256; j++) {
|
||||
buf[i*256 + j] = inw(atadev.base + REG_DATA);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ata_write(struct AtaDevice atadev, uint32_t lba, uint8_t sector_count, uint16_t buf[sector_count*256]) {
|
||||
outb(atadev.base + REG_DRIVE_HEAD, 0xE0 | ((lba >> 24) & 0x0F));
|
||||
outb(atadev.base + REG_FEATURES, 0x00);
|
||||
outb(atadev.base + REG_SECTOR_CNT, sector_count);
|
||||
outb(atadev.base + REG_LBA_LO, lba & 0xFF);
|
||||
outb(atadev.base + REG_LBA_MID, (lba >> 8) & 0xFF);
|
||||
outb(atadev.base + REG_LBA_HI, (lba >> 16) & 0xFF);
|
||||
outb(atadev.base + REG_COMMAND, 0x30);
|
||||
for(int i = 0; i < sector_count; i++) {
|
||||
while(true) {
|
||||
uint8_t status = inb(atadev.ctrl);
|
||||
if(status & STAT_DRQ) break;
|
||||
if(status & STAT_DF) panic("Drive failure");
|
||||
if(status & STAT_ERR) panic("Write disk error");
|
||||
}
|
||||
for(int j = 0; j < 256; j++) {
|
||||
outw(atadev.base + REG_DATA, buf[i*256 + j]);
|
||||
}
|
||||
}
|
||||
io_wait();
|
||||
outb(atadev.base + REG_COMMAND, 0xE7);
|
||||
while(inb(atadev.ctrl & STAT_BSY)) {}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "pci.h"
|
||||
|
||||
struct AtaDevice {
|
||||
struct PciDevice pcidev;
|
||||
uint16_t base;
|
||||
uint16_t ctrl;
|
||||
uint32_t sector_count;
|
||||
};
|
||||
|
||||
bool ata_init(struct AtaDevice *atadev, struct PciDevice pcidev);
|
||||
bool ata_read(struct AtaDevice atadev, uint32_t lba, uint8_t sector_count, uint16_t buf[sector_count*256]);
|
||||
bool ata_write(struct AtaDevice atadev, uint32_t lba, uint8_t sector_count, uint16_t buf[sector_count*256]);
|
|
@ -0,0 +1,134 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct Keycode {
|
||||
uint8_t key;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
#define KC_FLAG_KEY_DOWN 0x01
|
||||
#define KC_FLAG_KEY_UP 0x02
|
||||
#define KC_FLAG_ERROR 0x04
|
||||
|
||||
#define KEY_NONE 0x00
|
||||
#define KEY_UNKNOWN 0x01
|
||||
|
||||
#define KEY_ESCAPE 0x10
|
||||
#define KEY_1 0x11
|
||||
#define KEY_2 0x12
|
||||
#define KEY_3 0x13
|
||||
#define KEY_4 0x14
|
||||
#define KEY_5 0x15
|
||||
#define KEY_6 0x16
|
||||
#define KEY_7 0x17
|
||||
#define KEY_8 0x18
|
||||
#define KEY_9 0x19
|
||||
#define KEY_0 0x1A
|
||||
#define KEY_MINUS 0x1B
|
||||
#define KEY_EQUAL 0x1C
|
||||
#define KEY_BACKSPACE 0x1D
|
||||
#define KEY_L_SHIFT 0x1E
|
||||
#define KEY_R_SHIFT 0x1F
|
||||
|
||||
#define KEY_TAB 0x20
|
||||
#define KEY_Q 0x21
|
||||
#define KEY_W 0x22
|
||||
#define KEY_E 0x23
|
||||
#define KEY_R 0x24
|
||||
#define KEY_T 0x25
|
||||
#define KEY_Y 0x26
|
||||
#define KEY_U 0x27
|
||||
#define KEY_I 0x28
|
||||
#define KEY_O 0x29
|
||||
#define KEY_P 0x2A
|
||||
#define KEY_L_BRACE 0x2B
|
||||
#define KEY_R_BRACE 0x2C
|
||||
#define KEY_BACKSLASH 0x2D
|
||||
#define KEY_L_CTRL 0x2E
|
||||
#define KEY_R_CTRL 0x2F
|
||||
|
||||
#define KEY_CAPS_LOCK 0x30
|
||||
#define KEY_A 0x31
|
||||
#define KEY_S 0x32
|
||||
#define KEY_D 0x33
|
||||
#define KEY_F 0x34
|
||||
#define KEY_G 0x35
|
||||
#define KEY_H 0x36
|
||||
#define KEY_J 0x37
|
||||
#define KEY_K 0x38
|
||||
#define KEY_L 0x39
|
||||
#define KEY_SEMICOLON 0x3A
|
||||
#define KEY_QUOTE 0x3B
|
||||
#define KEY_ENTER 0x3C
|
||||
#define KEY_MENU 0x3D
|
||||
#define KEY_L_ALT 0x3E
|
||||
#define KEY_R_ALT 0x3F
|
||||
|
||||
#define KEY_SPACE 0x40
|
||||
#define KEY_Z 0x41
|
||||
#define KEY_X 0x42
|
||||
#define KEY_C 0x43
|
||||
#define KEY_V 0x44
|
||||
#define KEY_B 0x45
|
||||
#define KEY_N 0x46
|
||||
#define KEY_M 0x47
|
||||
#define KEY_COMMA 0x48
|
||||
#define KEY_PERIOD 0x49
|
||||
#define KEY_SLASH 0x4A
|
||||
#define KEY_BACKTICK 0x4B
|
||||
#define KEY_NUM_LOCK 0x4C
|
||||
#define KEY_SCROLL_LOCK 0x4D
|
||||
#define KEY_L_META 0x4E
|
||||
#define KEY_R_META 0x4F
|
||||
|
||||
#define KEY_NP_SLASH 0x50
|
||||
#define KEY_NP_7 0x51
|
||||
#define KEY_NP_8 0x52
|
||||
#define KEY_NP_9 0x53
|
||||
#define KEY_NP_ASTERISK 0x54
|
||||
#define KEY_NP_4 0x55
|
||||
#define KEY_NP_5 0x56
|
||||
#define KEY_NP_6 0x57
|
||||
#define KEY_NP_MINUS 0x58
|
||||
#define KEY_NP_1 0x59
|
||||
#define KEY_NP_2 0x5A
|
||||
#define KEY_NP_3 0x5B
|
||||
#define KEY_NP_PLUS 0x5C
|
||||
#define KEY_NP_0 0x5D
|
||||
#define KEY_NP_PERIOD 0x5E
|
||||
#define KEY_NP_ENTER 0x5F
|
||||
|
||||
#define KEY_PRINT_SCREEN 0x60
|
||||
#define KEY_PAUSE 0x61
|
||||
#define KEY_INSERT 0x62
|
||||
#define KEY_HOME 0x63
|
||||
#define KEY_PAGE_UP 0x64
|
||||
#define KEY_DELETE 0x65
|
||||
#define KEY_END 0x66
|
||||
#define KEY_PAGE_DOWN 0x67
|
||||
#define KEY_UP 0x68
|
||||
#define KEY_DOWN 0x69
|
||||
#define KEY_LEFT 0x6A
|
||||
#define KEY_RIGHT 0x6B
|
||||
// #define _ 0x6C
|
||||
// #define _ 0x6D
|
||||
// #define _ 0x6E
|
||||
// #define _ 0x6F
|
||||
|
||||
#define KEY_F1 0x70
|
||||
#define KEY_F2 0x71
|
||||
#define KEY_F3 0x72
|
||||
#define KEY_F4 0x73
|
||||
#define KEY_F5 0x74
|
||||
#define KEY_F6 0x75
|
||||
#define KEY_F7 0x76
|
||||
#define KEY_F8 0x77
|
||||
#define KEY_F9 0x78
|
||||
#define KEY_F10 0x79
|
||||
#define KEY_F11 0x7A
|
||||
#define KEY_F12 0x7B
|
||||
// #define _ 0x7C
|
||||
// #define _ 0x7D
|
||||
// #define _ 0x7E
|
||||
// #define _ 0x7F
|
|
@ -0,0 +1,157 @@
|
|||
#include <stdint.h>
|
||||
#include <sys.h>
|
||||
|
||||
#include "../panic.h"
|
||||
#include "pci.h"
|
||||
|
||||
#define CONF_ADDR 0xCF8
|
||||
#define CONF_DATA 0xCFC
|
||||
|
||||
#define TABLE_LEN 16
|
||||
|
||||
struct PciTableEntry {
|
||||
struct PciDevice device;
|
||||
uint16_t device_id;
|
||||
uint16_t vendor_id;
|
||||
uint8_t class;
|
||||
uint8_t subclass;
|
||||
uint8_t prog_if;
|
||||
uint8_t revision;
|
||||
};
|
||||
|
||||
static struct PciTableEntry pci_table[TABLE_LEN];
|
||||
static size_t pci_table_next = 0;
|
||||
|
||||
uint32_t pci_rcfg_d(struct PciDevice dev, uint8_t offset) {
|
||||
uint32_t addr = 0x80000000;
|
||||
addr |= ((uint32_t)dev.bus) << 16;
|
||||
addr |= ((uint32_t)dev.device) << 11;
|
||||
addr |= ((uint32_t)dev.function) << 8;
|
||||
addr |= offset & 0xFC;
|
||||
|
||||
outl(CONF_ADDR, addr);
|
||||
uint32_t in = inl(CONF_DATA);
|
||||
return in;
|
||||
}
|
||||
|
||||
uint16_t pci_rcfg_w(struct PciDevice dev, uint8_t offset) {
|
||||
uint32_t dword = pci_rcfg_d(dev, offset);
|
||||
return (uint16_t)((dword >> ((offset & 2) * 8)) & 0xFFFF);
|
||||
}
|
||||
|
||||
uint8_t pci_rcfg_b(struct PciDevice dev, uint8_t offset) {
|
||||
uint32_t dword = pci_rcfg_d(dev, offset);
|
||||
return (uint8_t)((dword >> ((offset & 3) * 8)) & 0xFF);
|
||||
}
|
||||
|
||||
void pci_wcfg_d(struct PciDevice dev, uint8_t offset, uint32_t dword) {
|
||||
uint32_t addr = 0x80000000;
|
||||
addr |= ((uint32_t)dev.bus) << 16;
|
||||
addr |= ((uint32_t)dev.device) << 11;
|
||||
addr |= ((uint32_t)dev.function) << 8;
|
||||
addr |= offset & 0xFC;
|
||||
|
||||
outl(CONF_ADDR, addr);
|
||||
outl(CONF_DATA, dword);
|
||||
}
|
||||
|
||||
void pci_wcfg_w(struct PciDevice dev, uint8_t offset, uint16_t word) {
|
||||
size_t shift = (offset & 2) * 8;
|
||||
uint32_t dword = pci_rcfg_d(dev, offset);
|
||||
dword &= ~(0xFFFF << shift);
|
||||
dword |= word << shift;
|
||||
pci_wcfg_d(dev, offset, dword);
|
||||
}
|
||||
|
||||
void pci_wcfg_b(struct PciDevice dev, uint8_t offset, uint8_t byte) {
|
||||
size_t shift = (offset & 3) * 8;
|
||||
uint32_t dword = pci_rcfg_d(dev, offset);
|
||||
dword &= ~(0xFF << shift);
|
||||
dword |= byte << shift;
|
||||
pci_wcfg_d(dev, offset, dword);
|
||||
}
|
||||
|
||||
//static void print_device(struct PciTableEntry *entry) {
|
||||
// printf("pci bus @0e%X@0f dev @0e%X@0f func @0e%X@0f",
|
||||
// entry->device.bus, entry->device.device, entry->device.function);
|
||||
//
|
||||
// printf("\tid @0c%X:%X@0f", entry->vendor_id, entry->device_id);
|
||||
//
|
||||
// printf("\tclass @0c%X:%X:%X@0f", entry->class, entry->subclass, entry->prog_if);
|
||||
// printf("\trev @0c%X@0f\n", entry->revision);
|
||||
//}
|
||||
|
||||
|
||||
static struct PciTableEntry *load_device(struct PciDevice dev) {
|
||||
if(pci_table_next >= TABLE_LEN) panic("Too many PCI devices: limit is %d", TABLE_LEN);
|
||||
struct PciTableEntry *entry = &pci_table[pci_table_next++];
|
||||
entry->device = dev;
|
||||
uint32_t dword0 = pci_rcfg_d(dev, 0);
|
||||
uint32_t dword2 = pci_rcfg_d(dev, 8);
|
||||
|
||||
entry->device_id = (dword0 >> 16) & 0xFFFF;
|
||||
entry->vendor_id = dword0 & 0xFFFF;
|
||||
|
||||
entry->class = (dword2 >> 24) & 0xFF;
|
||||
entry->subclass = (dword2 >> 16) & 0xFF;
|
||||
entry->prog_if = (dword2 >> 8) & 0xFF;
|
||||
entry->revision = dword2 & 0xFF;
|
||||
|
||||
//print_device(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
void pci_init(void) {
|
||||
pci_table_next = 0;
|
||||
struct PciDevice pcidev;
|
||||
for(int bus = 0; bus < 256; bus++) {
|
||||
pcidev.bus = bus;
|
||||
for(int dev = 0; dev < 32; dev++) {
|
||||
pcidev.device = dev;
|
||||
pcidev.function = 0;
|
||||
|
||||
uint16_t vendor = pci_rcfg_w(pcidev, 0);
|
||||
if(vendor == 0xFFFF) continue;
|
||||
|
||||
load_device(pcidev);
|
||||
|
||||
uint8_t header_type = pci_rcfg_b(pcidev, 14);
|
||||
|
||||
if(!(header_type & 0x80)) continue;
|
||||
for(int func = 1; func < 8; func++) {
|
||||
pcidev.function = func;
|
||||
|
||||
uint16_t vendor = pci_rcfg_w(pcidev, 0);
|
||||
if(vendor == 0xFFFF) continue;
|
||||
|
||||
load_device(pcidev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool pci_findby_class(struct PciDevice *dest, uint8_t class, uint8_t subclass, size_t *offset) {
|
||||
size_t o = 0;
|
||||
if(offset == NULL) offset = &o;
|
||||
for(; *offset < pci_table_next; (*offset)++) {
|
||||
struct PciTableEntry *entry = &pci_table[*offset];
|
||||
if(entry->class == class && entry->subclass == subclass) {
|
||||
*dest = entry->device;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pci_findby_id(struct PciDevice *dest, uint16_t device, uint16_t vendor, size_t *offset) {
|
||||
size_t o = 0;
|
||||
if(offset == NULL) offset = &o;
|
||||
for(; *offset < pci_table_next; (*offset)++) {
|
||||
struct PciTableEntry *entry = &pci_table[*offset];
|
||||
if(entry->device_id == device && entry->vendor_id == vendor) {
|
||||
*dest = entry->device;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// common
|
||||
#define PCI_VENDOR_W 0x00
|
||||
#define PCI_DEVICE_W 0x02
|
||||
#define PCI_COMMAND_W 0x04
|
||||
#define PCI_STATUS_W 0x06
|
||||
#define PCI_REVISION_B 0x08
|
||||
#define PCI_PROG_IF_B 0x09
|
||||
#define PCI_SUBCLASS_B 0x0A
|
||||
#define PCI_CLASS_B 0x0B
|
||||
#define PCI_CACHE_SIZE_B 0x0C
|
||||
#define PCI_LATENCY_TIMER_B 0x0D
|
||||
#define PCI_HEADER_TYPE_B 0x0E
|
||||
#define PCI_BIST_B 0x0F
|
||||
|
||||
// header type 0
|
||||
#define PCI_BAR0_D 0x10
|
||||
#define PCI_BAR1_D 0x14
|
||||
#define PCI_BAR2_D 0x18
|
||||
#define PCI_BAR3_D 0x1C
|
||||
#define PCI_BAR4_D 0x20
|
||||
#define PCI_BAR5_D 0x24
|
||||
#define PCI_CARDBUS_CIS_D 0x28
|
||||
#define PCI_SUBSYSTEM_VENDOR_W 0x2C
|
||||
#define PCI_SUBSYSTEM_W 0x2E
|
||||
#define PCI_EXPANSION_ROM_D 0x30
|
||||
#define PCI_CAP_PTR_B 0x34
|
||||
#define PCI_INT_LINE_B 0x3C
|
||||
#define PCI_INT_PIN_B 0x3D
|
||||
#define PCI_MIN_GRANT_B 0x3E
|
||||
#define PCI_MAX_LATENCY_B 0x3F
|
||||
|
||||
struct PciDevice {
|
||||
uint8_t bus: 8;
|
||||
uint8_t device: 5;
|
||||
uint8_t function: 3;
|
||||
};
|
||||
|
||||
void pci_init(void);
|
||||
|
||||
bool pci_findby_class(struct PciDevice *dest, uint8_t class, uint8_t subclass, size_t *offset);
|
||||
bool pci_findby_id(struct PciDevice *dest, uint16_t device, uint16_t vendor, size_t *offset);
|
||||
|
||||
uint32_t pci_rcfg_d(struct PciDevice dev, uint8_t offset);
|
||||
uint16_t pci_rcfg_w(struct PciDevice dev, uint8_t offset);
|
||||
uint8_t pci_rcfg_b(struct PciDevice dev, uint8_t offset);
|
||||
|
||||
void pci_wcfg_d(struct PciDevice dev, uint8_t offset, uint32_t dword);
|
||||
void pci_wcfg_w(struct PciDevice dev, uint8_t offset, uint16_t word);
|
||||
void pci_wcfg_b(struct PciDevice dev, uint8_t offset, uint8_t byte);
|
|
@ -0,0 +1,73 @@
|
|||
#include <stdint.h>
|
||||
#include <sys.h>
|
||||
#include "ps2ctrl.h"
|
||||
#include "../panic.h"
|
||||
#include "../interrupt/pic.h"
|
||||
|
||||
#define STATUS_OUT_BUF ((uint8_t)0x01)
|
||||
#define STATUS_IN_BUF ((uint8_t)0x02)
|
||||
|
||||
#define CONFIG_INT_0 ((uint8_t)0x01)
|
||||
#define CONFIG_INT_1 ((uint8_t)0x02)
|
||||
#define CONFIG_SYS ((uint8_t)0x04)
|
||||
#define CONFIG_CLOCK_0 ((uint8_t)0x10)
|
||||
#define CONFIG_CLOCK_1 ((uint8_t)0x20)
|
||||
#define CONFIG_TRANS ((uint8_t)0x40)
|
||||
|
||||
uint8_t ps2ctrl_in_status(void) {
|
||||
return inb(0x64);
|
||||
}
|
||||
|
||||
uint8_t ps2ctrl_in(void) {
|
||||
while((ps2ctrl_in_status() & STATUS_OUT_BUF) == 0) {
|
||||
io_wait();
|
||||
}
|
||||
return inb(0x60);
|
||||
}
|
||||
|
||||
void ps2ctrl_out_cmd(uint8_t cmd) {
|
||||
while((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
|
||||
io_wait();
|
||||
}
|
||||
outb(0x64, cmd);
|
||||
}
|
||||
|
||||
void ps2ctrl_out_data(uint8_t data) {
|
||||
while((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
|
||||
io_wait();
|
||||
}
|
||||
outb(0x60, data);
|
||||
}
|
||||
|
||||
static bool is_init = false;
|
||||
|
||||
void ps2ctrl_init(void) {
|
||||
is_init = false;
|
||||
pic_mask(1);
|
||||
// clear buffer
|
||||
inb(0x60);
|
||||
|
||||
// self-test
|
||||
ps2ctrl_out_cmd(0xAA);
|
||||
uint8_t response = ps2ctrl_in();
|
||||
if(response != 0x55) {
|
||||
panic("PS/2 controller failed to initialize");
|
||||
}
|
||||
|
||||
// set config
|
||||
ps2ctrl_out_cmd(0x20);
|
||||
uint8_t config = ps2ctrl_in();
|
||||
config = (config | CONFIG_INT_0) & ~CONFIG_TRANS & ~CONFIG_INT_1;
|
||||
ps2ctrl_out_cmd(0x60);
|
||||
ps2ctrl_out_data(config);
|
||||
|
||||
// enable port 0
|
||||
ps2ctrl_out_cmd(0xAE);
|
||||
|
||||
pic_unmask(1);
|
||||
is_init = true;
|
||||
}
|
||||
|
||||
bool ps2ctrl_is_init(void) {
|
||||
return is_init;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t ps2ctrl_in(void);
|
||||
uint8_t ps2ctrl_in_status(void);
|
||||
void ps2ctrl_out_cmd(uint8_t cmd);
|
||||
void ps2ctrl_out_data(uint8_t data);
|
||||
|
||||
void ps2ctrl_init(void);
|
||||
|
||||
bool ps2ctrl_is_init(void);
|
|
@ -0,0 +1,126 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include "../panic.h"
|
||||
#include "../interrupt/pic.h"
|
||||
#include <string.h>
|
||||
#include <sys.h>
|
||||
|
||||
#include "ps2ctrl.h"
|
||||
#include "ps2kb.h"
|
||||
#include "keycodes.h"
|
||||
|
||||
#define BUFFER_LEN 16
|
||||
|
||||
#define KEYCODE_ARRAY_LEN 0x84
|
||||
|
||||
static uint8_t scancodes[] = {
|
||||
// 00/08 01/09 02/0A 03/0B 04/0C 05/0D 06/0E 07/0F
|
||||
/*00*/ KEY_NONE, KEY_F9, KEY_NONE, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F12,
|
||||
/*08*/ KEY_NONE, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_BACKTICK, KEY_NONE,
|
||||
/*10*/ KEY_NONE, KEY_L_ALT, KEY_L_SHIFT, KEY_NONE, KEY_L_CTRL, KEY_Q, KEY_1, KEY_NONE,
|
||||
/*18*/ KEY_NONE, KEY_NONE, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_NONE,
|
||||
/*20*/ KEY_NONE, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_NONE,
|
||||
/*28*/ KEY_NONE, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_NONE,
|
||||
/*30*/ KEY_NONE, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_NONE,
|
||||
/*38*/ KEY_NONE, KEY_NONE, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_NONE,
|
||||
/*40*/ KEY_NONE, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_NONE,
|
||||
/*48*/ KEY_NONE, KEY_PERIOD, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_NONE,
|
||||
/*50*/ KEY_NONE, KEY_NONE, KEY_QUOTE, KEY_NONE, KEY_L_BRACE, KEY_EQUAL, KEY_NONE, KEY_NONE,
|
||||
/*58*/ KEY_CAPS_LOCK, KEY_R_SHIFT, KEY_ENTER, KEY_R_BRACE, KEY_NONE, KEY_BACKSLASH, KEY_NONE, KEY_NONE,
|
||||
/*60*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_BACKSPACE, KEY_NONE,
|
||||
/*68*/ KEY_NONE, KEY_NP_1, KEY_NONE, KEY_NP_4, KEY_NP_7, KEY_NONE, KEY_NONE, KEY_NONE,
|
||||
/*70*/ KEY_NP_0, KEY_NP_PERIOD, KEY_NP_2, KEY_NP_5, KEY_NP_6, KEY_NP_8, KEY_ESCAPE, KEY_NUM_LOCK,
|
||||
/*78*/ KEY_F11, KEY_NP_PLUS, KEY_NP_3, KEY_NP_MINUS, KEY_NP_ASTERISK, KEY_NP_9, KEY_SCROLL_LOCK, KEY_NONE,
|
||||
/*80*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_F7,
|
||||
};
|
||||
static uint8_t scancodes_ext[] = {
|
||||
// 00/08 01/09 02/0A 03/0B 04/0C 05/0D 06/0E 07/0F
|
||||
/*00*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
|
||||
/*08*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
|
||||
/*10*/ KEY_UNKNOWN, KEY_R_ALT, KEY_PRINT_SCREEN, KEY_NONE, KEY_R_CTRL, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
|
||||
/*18*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_L_META,
|
||||
/*20*/ KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_R_META,
|
||||
/*28*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_MENU,
|
||||
/*30*/ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
|
||||
/*38*/ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
|
||||
/*40*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
|
||||
/*48*/ KEY_UNKNOWN, KEY_NONE, KEY_NP_SLASH, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
|
||||
/*50*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
|
||||
/*58*/ KEY_NONE, KEY_NONE, KEY_NP_ENTER, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE,
|
||||
/*60*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
|
||||
/*68*/ KEY_NONE, KEY_END, KEY_NONE, KEY_LEFT, KEY_HOME, KEY_NONE, KEY_NONE, KEY_NONE,
|
||||
/*70*/ KEY_INSERT, KEY_DELETE, KEY_DOWN, KEY_NONE, KEY_RIGHT, KEY_UP, KEY_NONE, KEY_NONE,
|
||||
/*78*/ KEY_NONE, KEY_NONE, KEY_PAGE_DOWN, KEY_NONE, KEY_NONE, KEY_PAGE_UP, KEY_NONE, KEY_NONE,
|
||||
/*80*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
|
||||
};
|
||||
|
||||
static struct Keycode last_keycode;
|
||||
|
||||
static bool is_init = false;
|
||||
static bool state_keyup = false;
|
||||
static bool state_ext = false;
|
||||
|
||||
void ps2kb_init(void) {
|
||||
is_init = false;
|
||||
pic_mask(1);
|
||||
|
||||
uint8_t result;
|
||||
|
||||
ps2ctrl_out_data(0xFF);
|
||||
result = ps2ctrl_in();
|
||||
if(result != 0xFA) {
|
||||
panic("Failed to reset PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
|
||||
}
|
||||
result = ps2ctrl_in();
|
||||
if(result != 0xAA) {
|
||||
panic("Failed to reset PS/2 keyboard: expected 0xAA, got 0x%X\n", result);
|
||||
}
|
||||
|
||||
ps2ctrl_out_data(0xF4);
|
||||
result = ps2ctrl_in();
|
||||
if(result != 0xFA) {
|
||||
panic("Failed to enable PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
|
||||
}
|
||||
|
||||
pic_unmask(1);
|
||||
is_init = true;
|
||||
}
|
||||
|
||||
void ps2kb_recv(void) {
|
||||
if(!ps2ctrl_is_init() || !is_init) {
|
||||
inb(0x60);
|
||||
return;
|
||||
}
|
||||
uint8_t code = ps2ctrl_in();
|
||||
if (code == 0x00 || code == 0x0F) {
|
||||
last_keycode.key = KEY_NONE;
|
||||
last_keycode.flags = KC_FLAG_ERROR;
|
||||
} else if(code == 0xF0) {
|
||||
state_keyup = true;
|
||||
} else if(code == 0xE0) {
|
||||
state_ext = true;
|
||||
} else if(code <= KEYCODE_ARRAY_LEN) {
|
||||
uint8_t *scancode_table = state_ext ? scancodes_ext : scancodes;
|
||||
uint8_t keycode = scancode_table[code];
|
||||
if(keycode != KEY_NONE) {
|
||||
last_keycode.key = keycode;
|
||||
last_keycode.flags = state_keyup ? KC_FLAG_KEY_UP : KC_FLAG_KEY_DOWN;
|
||||
}
|
||||
state_keyup = false;
|
||||
state_ext = false;
|
||||
}
|
||||
}
|
||||
|
||||
struct Keycode ps2kb_get(void) {
|
||||
struct Keycode code;
|
||||
if(is_init) {
|
||||
code = last_keycode;
|
||||
} else {
|
||||
code.key = KEY_NONE;
|
||||
code.flags = KC_FLAG_ERROR;
|
||||
}
|
||||
last_keycode.key = KEY_NONE;
|
||||
last_keycode.flags = 0;
|
||||
return code;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "keycodes.h"
|
||||
|
||||
void ps2kb_init(void);
|
||||
|
||||
void ps2kb_recv(void);
|
||||
struct Keycode ps2kb_get(void);
|
|
@ -0,0 +1,59 @@
|
|||
#include <string.h>
|
||||
#include "../term.h"
|
||||
#include "../panic.h"
|
||||
#include "fat.h"
|
||||
|
||||
bool fat_init(struct FatInfo *fatinfo, struct AtaDevice dev, struct MbrPartition partition) {
|
||||
uint8_t boot_sector[512] __attribute__((aligned(2)));
|
||||
if(!ata_read(dev, partition.start_sector, 1, (void*)boot_sector)) return false;
|
||||
memcpy(&fatinfo->bpb, boot_sector, sizeof(struct FatBpb));
|
||||
memcpy(&fatinfo->ebpb.f16, boot_sector + sizeof(struct FatBpb), sizeof(struct Fat16Ebpb));
|
||||
fatinfo->type = FAT16;
|
||||
fatinfo->dev = dev;
|
||||
fatinfo->partition = partition;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int read_dir_entry_sector(struct FatFile *file, struct FatInfo *fatinfo, size_t sector, char* name) {
|
||||
uint8_t buf[512] __attribute__((aligned(2)));
|
||||
if(!ata_read(fatinfo->dev, fatinfo->partition.start_sector + sector, 1, (uint16_t*)buf)) panic("read fail");
|
||||
for(int i = 0; i < 512; i += 32) {
|
||||
if(buf[i] == 0) return 1; // reached end
|
||||
if(buf[i] == 0xE5) continue;
|
||||
if(buf[i+11] == 0x0F) continue;
|
||||
int j;
|
||||
for(j = 0; j < 11; j++) {
|
||||
if(buf[i + j] != name[j]) break;
|
||||
}
|
||||
if(j != 11) continue;
|
||||
memcpy(file->name, &buf[i], 11);
|
||||
file->start_cluster = buf[i+26] | (buf[i+27] << 8) | (buf[i+20] << 16) | (buf[i+21] << 24);
|
||||
file->size = buf[i+28] | (buf[i+29] << 8) | (buf[i+30] << 16) | (buf[i+31] << 24);
|
||||
file->attributes = buf[i+11];
|
||||
return 0; // found file
|
||||
}
|
||||
return 2; // next sector
|
||||
}
|
||||
|
||||
static bool read_dir_entry(struct FatFile *file, struct FatInfo *fatinfo, size_t start_sector, size_t sector_count, char* name) {
|
||||
for(size_t i = 0; i < sector_count; i++) {
|
||||
int result = read_dir_entry_sector(file, fatinfo, start_sector + i, name);
|
||||
if(result == 0) return true;
|
||||
if(result == 1) break;
|
||||
// continue if result == 2
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fat_test(struct FatInfo *fatinfo) {
|
||||
size_t root_start = fatinfo->bpb.reserved_sectors + fatinfo->bpb.fat_count * fatinfo->bpb.sectors_per_fat;
|
||||
size_t root_sectors = (fatinfo->bpb.root_entries * 32 + 511) / 512;
|
||||
printf("root start %d sectors %d\n", root_start, root_sectors);
|
||||
printf("%X\n", root_start * 512);
|
||||
struct FatFile file;
|
||||
read_dir_entry(&file, fatinfo, root_start, root_sectors, "FILE3 ");
|
||||
printf("start: 0x%X\n", file.start_cluster);
|
||||
printf("size: 0x%X\n", file.size);
|
||||
printf("attr: 0x%X\n", file.attributes);
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
#pragma once
|
||||
|
||||
#include "mbr.h"
|
||||
|
||||
enum FatType {
|
||||
FAT12,
|
||||
FAT16,
|
||||
FAT32,
|
||||
};
|
||||
|
||||
struct FatBpb {
|
||||
uint8_t _instrs[3];
|
||||
uint8_t oem_ident[8];
|
||||
uint16_t bytes_per_sector;
|
||||
uint8_t sectors_per_cluster;
|
||||
uint16_t reserved_sectors;
|
||||
uint8_t fat_count;
|
||||
uint16_t root_entries;
|
||||
uint16_t total_sectors_16;
|
||||
uint8_t media_descriptor;
|
||||
uint16_t sectors_per_fat;
|
||||
uint16_t sectors_per_track;
|
||||
uint16_t heads;
|
||||
uint32_t hidden_sectors;
|
||||
uint32_t total_sectors_32;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct Fat16Ebpb {
|
||||
uint8_t drive_number;
|
||||
uint8_t _reserved;
|
||||
uint8_t signature;
|
||||
uint32_t volume_id;
|
||||
uint8_t volume_label[11];
|
||||
uint8_t sys_ident[8];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct Fat32Ebpb {
|
||||
uint32_t sectors_per_fat;
|
||||
uint16_t flags;
|
||||
uint16_t version;
|
||||
uint32_t root_cluster;
|
||||
uint16_t fsinfo_sector;
|
||||
uint16_t backup_boot_sector;
|
||||
uint8_t _reserved0[12];
|
||||
uint8_t drive_number;
|
||||
uint8_t _reserved1;
|
||||
uint8_t signature;
|
||||
uint32_t serial_number;
|
||||
uint8_t volume_label[11];
|
||||
uint8_t system_ident[8];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct FatInfo {
|
||||
struct MbrPartition partition;
|
||||
struct AtaDevice dev;
|
||||
enum FatType type;
|
||||
struct FatBpb bpb;
|
||||
union {
|
||||
struct Fat16Ebpb f16;
|
||||
struct Fat32Ebpb f32;
|
||||
} ebpb;
|
||||
};
|
||||
|
||||
struct FatFile {
|
||||
uint8_t name[11];
|
||||
uint8_t attributes;
|
||||
uint32_t start_cluster;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
bool fat_init(struct FatInfo *fatinfo, struct AtaDevice dev, struct MbrPartition partition);
|
||||
bool fat_test(struct FatInfo *fatinfo);
|
|
@ -0,0 +1,19 @@
|
|||
#include "mbr.h"
|
||||
|
||||
bool mbr_get_partition(struct MbrPartition *dest, struct AtaDevice dev, int n) {
|
||||
if(n < 0 || n > 3) return false;
|
||||
uint8_t data[512] __attribute__(( aligned(2) ));
|
||||
if(!ata_read(dev, 0, 1, (void*)data)) return false;
|
||||
size_t offset = 0x1BE + n * 0x10;
|
||||
|
||||
uint8_t status = data[offset];
|
||||
if((status & 0x7F) != 0) return false;
|
||||
|
||||
dest->n = n;
|
||||
dest->bootable = status & 0x80 ? true : false;
|
||||
dest->type = data[offset + 4];
|
||||
dest->start_sector = data[offset+8] | (data[offset+9] << 8) | (data[offset+10] << 16) | (data[offset+11] << 24);
|
||||
dest->sector_count = data[offset+12] | (data[offset+13] << 8) | (data[offset+14] << 16) | (data[offset+15] << 24);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../drivers/ata.h"
|
||||
|
||||
struct MbrPartition {
|
||||
uint8_t n;
|
||||
uint8_t type;
|
||||
bool bootable;
|
||||
size_t start_sector;
|
||||
size_t sector_count;
|
||||
};
|
||||
|
||||
bool mbr_get_partition(struct MbrPartition *dest, struct AtaDevice device, int n);
|
|
@ -1,7 +1,7 @@
|
|||
extern idt_exception_handler
|
||||
extern idt_pic_timer
|
||||
extern idt_pic_keyboard
|
||||
extern idt_pic_handler
|
||||
extern idt_pic_eoi
|
||||
global isr_stub_table
|
||||
|
||||
%macro ISRErrorStub 1
|
||||
|
@ -15,25 +15,25 @@ isr_stub_%+%1:
|
|||
%macro PICGeneric 1
|
||||
isr_stub_%+%1:
|
||||
push dword %1
|
||||
call idt_pic_handler
|
||||
call idt_pic_eoi
|
||||
pop eax
|
||||
iret
|
||||
%endmacro
|
||||
|
||||
%macro PICTimer 1
|
||||
isr_stub_%+%1:
|
||||
push dword %1
|
||||
call idt_pic_handler
|
||||
call idt_pic_timer
|
||||
push dword %1
|
||||
call idt_pic_eoi
|
||||
pop eax
|
||||
iret
|
||||
%endmacro
|
||||
|
||||
%macro PICKeyboard 1
|
||||
isr_stub_%+%1:
|
||||
push dword %1
|
||||
call idt_pic_handler
|
||||
call idt_pic_keyboard
|
||||
push dword %1
|
||||
call idt_pic_eoi
|
||||
pop eax
|
||||
iret
|
||||
%endmacro
|
||||
|
@ -51,6 +51,7 @@ isr_stub_%+%1:
|
|||
%endmacro
|
||||
|
||||
section .text
|
||||
align 8
|
||||
%assign i 0
|
||||
%rep 32
|
||||
ISRErrorStub i
|
||||
|
@ -79,6 +80,7 @@ PICGeneric 47
|
|||
%endrep
|
||||
|
||||
section .rodata
|
||||
align 8
|
||||
isr_stub_table:
|
||||
%assign i 0x00
|
||||
%rep 256
|
||||
|
|
|
@ -3,55 +3,71 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys.h>
|
||||
|
||||
#include "idt.h"
|
||||
#include "../term.h"
|
||||
#include "pic.h"
|
||||
#include "../term.h"
|
||||
#include "../panic.h"
|
||||
#include "../drivers/ps2kb.h"
|
||||
#include "../drivers/ps2ctrl.h"
|
||||
|
||||
static int timer = 0;
|
||||
|
||||
void idt_pic_handler(uint8_t exception) {
|
||||
pic_eoi(exception - PIC_REMAP_OFFSET);
|
||||
void idt_pic_eoi(uint8_t exception) {
|
||||
pic_eoi(exception - PIC_REMAP_OFFSET);
|
||||
}
|
||||
|
||||
void idt_pic_timer(void) {
|
||||
uint32_t state = term_save();
|
||||
term_setcol(0x0a);
|
||||
char buf[20];
|
||||
itoa(timer, buf);
|
||||
term_setpos(0, 20);
|
||||
puts(" ");
|
||||
term_setpos(0, 20);
|
||||
puts(buf);
|
||||
timer += 1;
|
||||
term_load(state);
|
||||
uint32_t state = term_save();
|
||||
term_setcol(0x0a);
|
||||
term_setpos(60, 0);
|
||||
puts(" ");
|
||||
term_setpos(60, 0);
|
||||
printf("%d", timer);
|
||||
term_flush();
|
||||
timer += 1;
|
||||
term_load(state);
|
||||
}
|
||||
|
||||
void idt_pic_keyboard(void) {
|
||||
uint8_t c = inb(0x60);
|
||||
uint32_t state = term_save();
|
||||
term_setcol(0x0c);
|
||||
term_setpos(0, 21);
|
||||
puts(" ");
|
||||
term_setpos(0, 21);
|
||||
char buf[20];
|
||||
itoa(c, buf);
|
||||
puts(buf);
|
||||
term_load(state);
|
||||
ps2kb_recv();
|
||||
}
|
||||
|
||||
void idt_exception_handler(uint8_t exception) {
|
||||
switch(exception) {
|
||||
case 0x00:
|
||||
puts("Div by zero");
|
||||
break;
|
||||
case 0x08:
|
||||
puts("Double fault");
|
||||
break;
|
||||
default:
|
||||
puts("Error");
|
||||
break;
|
||||
}
|
||||
halt();
|
||||
char* msg;
|
||||
switch(exception) {
|
||||
case 0x00:
|
||||
msg = "Division by zero";
|
||||
break;
|
||||
case 0x02:
|
||||
msg = "NMI";
|
||||
break;
|
||||
case 0x04:
|
||||
msg = "Overflow";
|
||||
break;
|
||||
case 0x06:
|
||||
msg = "invalid opcode";
|
||||
break;
|
||||
case 0x08:
|
||||
msg = "double fault";
|
||||
break;
|
||||
case 0x0A:
|
||||
msg = "invalid task state segment";
|
||||
break;
|
||||
case 0x0C:
|
||||
msg = "stack segment fault";
|
||||
break;
|
||||
case 0x0D:
|
||||
msg = "general protection fault";
|
||||
break;
|
||||
case 0x0E:
|
||||
msg = "page fault";
|
||||
break;
|
||||
default:
|
||||
msg = "unknown exception";
|
||||
break;
|
||||
}
|
||||
panic("E%u: %s", exception, msg);
|
||||
}
|
||||
|
||||
__attribute__((aligned(0x10)))
|
||||
|
@ -72,7 +88,7 @@ void idt_init(void) {
|
|||
idtr.base = (uintptr_t)&idt[0];
|
||||
idtr.limit = (uint16_t)sizeof(struct IdtEntry) * IDT_SIZE - 1;
|
||||
|
||||
for(uint8_t i = 0; i < IDT_INTERRUPTS; i++) {
|
||||
for(int i = 0; i < IDT_INTERRUPTS; i++) {
|
||||
set_descriptor(i, isr_stub_table[i], 0x8e);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#define IDT_SIZE 256
|
||||
#define IDT_INTERRUPTS 48
|
||||
#define IDT_INTERRUPTS 256
|
||||
|
||||
struct IdtEntry {
|
||||
uint16_t isr_low;
|
||||
|
@ -18,18 +18,18 @@ struct Idtr {
|
|||
} __attribute__((packed));
|
||||
|
||||
typedef enum {
|
||||
IDT_FLAG_GATE_TASK = 0x5,
|
||||
IDT_FLAG_GATE_16BIT_INT = 0x6,
|
||||
IDT_FLAG_GATE_16BIT_TRAP = 0x7,
|
||||
IDT_FLAG_GATE_32BIT_INT = 0xE,
|
||||
IDT_FLAG_GATE_32BIT_TRAP = 0xF,
|
||||
IDT_FLAG_GATE_TASK = 0x5,
|
||||
IDT_FLAG_GATE_16BIT_INT = 0x6,
|
||||
IDT_FLAG_GATE_16BIT_TRAP = 0x7,
|
||||
IDT_FLAG_GATE_32BIT_INT = 0xE,
|
||||
IDT_FLAG_GATE_32BIT_TRAP = 0xF,
|
||||
|
||||
IDT_FLAG_RING0 = (0 << 5),
|
||||
IDT_FLAG_RING1 = (1 << 5),
|
||||
IDT_FLAG_RING2 = (2 << 5),
|
||||
IDT_FLAG_RING3 = (3 << 5),
|
||||
IDT_FLAG_RING0 = (0 << 5),
|
||||
IDT_FLAG_RING1 = (1 << 5),
|
||||
IDT_FLAG_RING2 = (2 << 5),
|
||||
IDT_FLAG_RING3 = (3 << 5),
|
||||
|
||||
IDT_FLAG_PRESENT = 0x80,
|
||||
IDT_FLAG_PRESENT = 0x80,
|
||||
|
||||
} IDTFlags;
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "pic.h"
|
||||
#include "../term.h"
|
||||
#include <sys.h>
|
||||
|
||||
#define PIC1_COMMAND_PORT 0x20
|
||||
|
@ -9,74 +8,72 @@
|
|||
|
||||
|
||||
void pic_remap(uint8_t offset) {
|
||||
char a1 = inb(PIC1_DATA_PORT);
|
||||
char a2 = inb(PIC2_DATA_PORT);
|
||||
// control word 1
|
||||
// 0x11: initialize, enable ICW4
|
||||
outb(PIC1_COMMAND_PORT, 0x11);
|
||||
io_wait();
|
||||
outb(PIC2_COMMAND_PORT, 0x11);
|
||||
io_wait();
|
||||
// control word 2
|
||||
// interrupt offset
|
||||
outb(PIC1_DATA_PORT, offset);
|
||||
io_wait();
|
||||
outb(PIC2_DATA_PORT, offset + 8);
|
||||
io_wait();
|
||||
// control word 3
|
||||
// primary pic: set which pin secondary is connected to
|
||||
// (pin 2)
|
||||
outb(PIC1_DATA_PORT, 0b00000100);
|
||||
io_wait();
|
||||
outb(PIC2_DATA_PORT, 2);
|
||||
io_wait();
|
||||
// control word 3
|
||||
// 0x01: enable 8086 mode
|
||||
outb(PIC1_DATA_PORT, 0x01);
|
||||
io_wait();
|
||||
outb(PIC2_DATA_PORT, 0x01);
|
||||
io_wait();
|
||||
// clear data registers
|
||||
outb(PIC1_DATA_PORT, a1);
|
||||
outb(PIC2_DATA_PORT, a2);
|
||||
char a1 = inb(PIC1_DATA_PORT);
|
||||
char a2 = inb(PIC2_DATA_PORT);
|
||||
// control word 1
|
||||
// 0x11: initialize, enable ICW4
|
||||
outb(PIC1_COMMAND_PORT, 0x11);
|
||||
io_wait();
|
||||
outb(PIC2_COMMAND_PORT, 0x11);
|
||||
io_wait();
|
||||
// control word 2
|
||||
// interrupt offset
|
||||
outb(PIC1_DATA_PORT, offset);
|
||||
io_wait();
|
||||
outb(PIC2_DATA_PORT, offset + 8);
|
||||
io_wait();
|
||||
// control word 3
|
||||
// primary pic: set which pin secondary is connected to
|
||||
// (pin 2)
|
||||
outb(PIC1_DATA_PORT, 0b00000100);
|
||||
io_wait();
|
||||
outb(PIC2_DATA_PORT, 2);
|
||||
io_wait();
|
||||
// control word 3
|
||||
// 0x01: enable 8086 mode
|
||||
outb(PIC1_DATA_PORT, 0x01);
|
||||
io_wait();
|
||||
outb(PIC2_DATA_PORT, 0x01);
|
||||
io_wait();
|
||||
// clear data registers
|
||||
outb(PIC1_DATA_PORT, a1);
|
||||
outb(PIC2_DATA_PORT, a2);
|
||||
}
|
||||
|
||||
void pic_mask(int irq) {
|
||||
uint8_t port;
|
||||
if(irq < 8) {
|
||||
port = PIC1_DATA_PORT;
|
||||
} else {
|
||||
irq -= 8;
|
||||
port = PIC2_DATA_PORT;
|
||||
}
|
||||
uint8_t mask = inb(port);
|
||||
outb(port, mask | (1 << irq));
|
||||
uint8_t port;
|
||||
if(irq < 8) {
|
||||
port = PIC1_DATA_PORT;
|
||||
} else {
|
||||
irq -= 8;
|
||||
port = PIC2_DATA_PORT;
|
||||
}
|
||||
uint8_t mask = inb(port);
|
||||
outb(port, mask | (1 << irq));
|
||||
}
|
||||
|
||||
void pic_unmask(int irq) {
|
||||
uint8_t port;
|
||||
if(irq < 8) {
|
||||
port = PIC1_DATA_PORT;
|
||||
} else {
|
||||
irq -= 8;
|
||||
port = PIC2_DATA_PORT;
|
||||
}
|
||||
uint8_t mask = inb(port);
|
||||
outb(port, mask & ~(1 << irq));
|
||||
uint8_t port;
|
||||
if(irq < 8) {
|
||||
port = PIC1_DATA_PORT;
|
||||
} else {
|
||||
irq -= 8;
|
||||
port = PIC2_DATA_PORT;
|
||||
}
|
||||
uint8_t mask = inb(port);
|
||||
outb(port, mask & ~(1 << irq));
|
||||
}
|
||||
|
||||
// completely disable the PIC
|
||||
void pic_disable() {
|
||||
outb(PIC1_DATA_PORT, 0xff);
|
||||
io_wait();
|
||||
outb(PIC2_DATA_PORT, 0xff);
|
||||
io_wait();
|
||||
void pic_disable(void) {
|
||||
outb(PIC1_DATA_PORT, 0xff);
|
||||
io_wait();
|
||||
outb(PIC2_DATA_PORT, 0xff);
|
||||
io_wait();
|
||||
}
|
||||
|
||||
// end of interrupt
|
||||
void pic_eoi(int irq) {
|
||||
if(irq >= 8) {
|
||||
outb(PIC2_COMMAND_PORT, 0x20);
|
||||
}
|
||||
outb(PIC1_COMMAND_PORT, 0x20);
|
||||
if(irq >= 8) {
|
||||
outb(PIC2_COMMAND_PORT, 0x20);
|
||||
}
|
||||
outb(PIC1_COMMAND_PORT, 0x20);
|
||||
}
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
void pic_remap(uint8_t offset);
|
||||
void pic_mask(int irq);
|
||||
void pic_unmask(int irq);
|
||||
void pic_disable();
|
||||
void pic_disable(void);
|
||||
void pic_eoi(int irq);
|
||||
|
|
|
@ -1,22 +1,54 @@
|
|||
#include <sys.h>
|
||||
#include <stdlib.h>
|
||||
#include "bootinfo.h"
|
||||
#include "drivers/ata.h"
|
||||
#include "drivers/keycodes.h"
|
||||
#include "drivers/ps2ctrl.h"
|
||||
#include "drivers/ps2kb.h"
|
||||
#include "drivers/pci.h"
|
||||
#include "fs/fat.h"
|
||||
#include "fs/mbr.h"
|
||||
#include "panic.h"
|
||||
#include "term.h"
|
||||
#include "interrupt/pic.h"
|
||||
#include "interrupt/idt.h"
|
||||
|
||||
extern void kmain(void) {
|
||||
term_clear();
|
||||
term_setcol(0x0f);
|
||||
puts("loading kernel\n");
|
||||
idt_init();
|
||||
puts("initialized idt\n");
|
||||
pic_remap(PIC_REMAP_OFFSET);
|
||||
puts("remapped pic\n");
|
||||
int_enable();
|
||||
puts("enabled interrupts\n");
|
||||
outb(0x60, 0xF4);
|
||||
puts("enabled keyboard\n");
|
||||
extern void kmain(void* boot_info) {
|
||||
term_clear();
|
||||
term_setcol(0x0f);
|
||||
bootinfo_load(boot_info);
|
||||
printf("cmdline: %s\n", bootinfo_get_cmdline());
|
||||
idt_init();
|
||||
pic_remap(PIC_REMAP_OFFSET);
|
||||
ps2ctrl_init();
|
||||
ps2kb_init();
|
||||
pci_init();
|
||||
|
||||
while(1) {
|
||||
int_wait();
|
||||
}
|
||||
struct PciDevice pcidev;
|
||||
if(!pci_findby_class(&pcidev, 0x01, 0x01, NULL)) {
|
||||
panic("Could not find IDE device");
|
||||
}
|
||||
|
||||
struct AtaDevice atadev;
|
||||
ata_init(&atadev, pcidev);
|
||||
struct MbrPartition part0;
|
||||
mbr_get_partition(&part0, atadev, 0);
|
||||
struct FatInfo fat;
|
||||
fat_init(&fat, atadev, part0);
|
||||
fat_test(&fat);
|
||||
|
||||
|
||||
while(1) {
|
||||
int_wait();
|
||||
struct Keycode code = ps2kb_get();
|
||||
if(code.key != KEY_NONE) {
|
||||
if(code.flags & KC_FLAG_ERROR) {
|
||||
printf("error: %X\n", code.key);
|
||||
} else if(code.flags & KC_FLAG_KEY_DOWN) {
|
||||
printf("pressed: %X\n", code.key);
|
||||
} else {
|
||||
printf("released: %X\n", code.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#include <sys.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include "term.h"
|
||||
#include "panic.h"
|
||||
|
||||
__attribute__((noreturn))
|
||||
void _panic_impl(char* msg, int line, char* file, ...) {
|
||||
int_disable();
|
||||
printf("BBBBBBBB\n");
|
||||
va_list args;
|
||||
va_start(args, file);
|
||||
term_clear();
|
||||
term_setpos(0, 0);
|
||||
term_setcol(0x0c);
|
||||
puts("!!!PANIC!!!\n");
|
||||
term_setcol(0x0f);
|
||||
vprintf(msg, args);
|
||||
printf("\nin %s at line %d\n", file, line);
|
||||
while(1) {
|
||||
halt();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#define panic(msg, ...) _panic_impl(msg, __LINE__, __FILE__ __VA_OPT__(,) __VA_ARGS__)
|
||||
|
||||
__attribute__((noreturn))
|
||||
void _panic_impl(char* msg, int line, char* file, ...);
|
|
@ -4,32 +4,35 @@ bits 32
|
|||
|
||||
; base, limit, access, flags
|
||||
%macro gdt_entry 4
|
||||
db %2 & 0xff
|
||||
db (%2 >> 8) & 0xff
|
||||
db %1 & 0xff
|
||||
db (%1 >> 8) & 0xff
|
||||
db (%1 >> 16) & 0xff
|
||||
db %3
|
||||
db ((%2 >> 16) & 0x0f) | (%4 << 4)
|
||||
db (%1 >> 24) & 0xff
|
||||
db %2 & 0xff
|
||||
db (%2 >> 8) & 0xff
|
||||
db %1 & 0xff
|
||||
db (%1 >> 8) & 0xff
|
||||
db (%1 >> 16) & 0xff
|
||||
db %3
|
||||
db ((%2 >> 16) & 0x0f) | (%4 << 4)
|
||||
db (%1 >> 24) & 0xff
|
||||
%endmacro
|
||||
|
||||
section .multiboot_header
|
||||
section .multiboot
|
||||
align 8
|
||||
mb_start:
|
||||
; header
|
||||
dd 0xe85250d6
|
||||
dd 0
|
||||
dd mb_end - mb_start
|
||||
dd 0x100000000 - (0xe85250d6 + (mb_end - mb_start))
|
||||
; null tag
|
||||
dw 0
|
||||
dw 0
|
||||
dd 8
|
||||
;
|
||||
mb_end:
|
||||
|
||||
section .bss
|
||||
align 16
|
||||
stack_start:
|
||||
resb 16384
|
||||
resb 16384
|
||||
stack_end:
|
||||
|
||||
section .rodata
|
||||
|
@ -40,27 +43,29 @@ gdt_entry 0, 0xFFFFF, 0x9A, 0xC
|
|||
gdt_entry 0, 0xFFFFF, 0x92, 0xC
|
||||
gdt_end:
|
||||
gdt_descriptor:
|
||||
dw gdt_end - gdt_start - 1
|
||||
dd gdt_start
|
||||
dw gdt_end - gdt_start - 1
|
||||
dd gdt_start
|
||||
|
||||
|
||||
section .text
|
||||
align 8
|
||||
start:
|
||||
cli
|
||||
lgdt [gdt_descriptor]
|
||||
jmp 0x08:after_lgdt
|
||||
cli
|
||||
lgdt [gdt_descriptor]
|
||||
jmp 0x08:after_lgdt
|
||||
after_lgdt:
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov esp, stack_end
|
||||
mov ebp, stack_end
|
||||
call kmain
|
||||
cli
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov esp, stack_end
|
||||
mov ebp, stack_end
|
||||
sti
|
||||
push ebx
|
||||
call kmain
|
||||
cli
|
||||
halt:
|
||||
hlt
|
||||
jmp halt
|
||||
hlt
|
||||
jmp halt
|
||||
|
|
185
kernel/term.c
185
kernel/term.c
|
@ -1,12 +1,18 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <string_volatile.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys.h>
|
||||
|
||||
#include "term.h"
|
||||
|
||||
static uint16_t* screen = (uint16_t*)0xb8000;
|
||||
static size_t x = 0;
|
||||
static size_t y = 0;
|
||||
static volatile uint16_t *screen = (uint16_t*)0xb8000;
|
||||
static size_t term_x = 0;
|
||||
static size_t term_y = 0;
|
||||
static uint8_t color = 0x0f;
|
||||
static uint16_t screen_buf[TERM_W * TERM_H * 2];
|
||||
|
||||
static inline uint16_t screen_entry(char c, uint8_t col) {
|
||||
return (uint16_t)c | ((uint16_t)col << 8);
|
||||
|
@ -15,49 +21,188 @@ static inline uint16_t screen_entry(char c, uint8_t col) {
|
|||
void putc(char c) {
|
||||
switch(c) {
|
||||
case '\n':
|
||||
x = TERM_W;
|
||||
term_x = TERM_W;
|
||||
break;
|
||||
case '\t':
|
||||
if(x % 8 == 0) x += 8;
|
||||
x += 7 - (x % 8);
|
||||
term_x += 8 - (term_x % 8);
|
||||
break;
|
||||
default:
|
||||
screen[x + y * TERM_W] = screen_entry(c, color);
|
||||
x += 1;
|
||||
screen_buf[term_x + term_y * TERM_W] = screen_entry(c, color);
|
||||
term_x += 1;
|
||||
break;
|
||||
}
|
||||
if(x >= TERM_W) {
|
||||
x = 0;
|
||||
y += 1;
|
||||
if(term_x >= TERM_W) {
|
||||
term_x = 0;
|
||||
term_y += 1;
|
||||
}
|
||||
if(term_y >= TERM_H) {
|
||||
term_scroll(1);
|
||||
}
|
||||
if(c == '\n') {
|
||||
term_flush();
|
||||
}
|
||||
}
|
||||
|
||||
void puts(char* s) {
|
||||
for(char* c = s; *c != '\0'; c++) {
|
||||
putc(*c);
|
||||
void puts(const char *s) {
|
||||
for(; *s != '\0'; s++) {
|
||||
putc(*s);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t hex2i(char hex) {
|
||||
if(hex < 'A') {
|
||||
return hex - '0';
|
||||
} else if(hex < 'a') {
|
||||
return hex - 'A' + 10;
|
||||
} else {
|
||||
return hex - 'a' + 10;
|
||||
}
|
||||
}
|
||||
|
||||
static char i2d(int i, bool upper) {
|
||||
if(i < 10) {
|
||||
return '0' + i;
|
||||
} else {
|
||||
return 'a' + (i - 10) + (upper ? 'A' - 'a' : 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void itoa(int n, char *buf, int base, bool upper) {
|
||||
if(n == 0) {
|
||||
buf[0] = '0';
|
||||
buf[1] = '\0';
|
||||
return;
|
||||
}
|
||||
if(n < 0) {
|
||||
n = -n;
|
||||
buf[0] = '-';
|
||||
buf++;
|
||||
}
|
||||
char *start = buf;
|
||||
while(n != 0) {
|
||||
*buf++ = i2d(n % base, upper);
|
||||
n /= base;
|
||||
}
|
||||
*buf-- = '\0';
|
||||
while(buf > start) {
|
||||
char tmp = *start;
|
||||
*start++ = *buf;
|
||||
*buf-- = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static void utoa(unsigned int n, char *buf, int base, bool upper) {
|
||||
if(n == 0) {
|
||||
buf[0] = '0';
|
||||
buf[1] = '\0';
|
||||
return;
|
||||
}
|
||||
char *start = buf;
|
||||
while(n != 0) {
|
||||
*buf++ = i2d(n % base, upper);
|
||||
n /= base;
|
||||
}
|
||||
*buf-- = '\0';
|
||||
while(buf > start) {
|
||||
char tmp = *start;
|
||||
*start++ = *buf;
|
||||
*buf-- = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void vprintf(const char *fstr, va_list args) {
|
||||
char buf[80];
|
||||
for(; *fstr != '\0'; fstr++) {
|
||||
if(*fstr == '%') {
|
||||
switch(*++fstr) {
|
||||
case '%':
|
||||
putc('%');
|
||||
break;
|
||||
case '@':
|
||||
putc('@');
|
||||
break;
|
||||
case 's':
|
||||
puts(va_arg(args, char*));
|
||||
break;
|
||||
case 'c':
|
||||
putc(va_arg(args, int));
|
||||
break;
|
||||
case 'd':
|
||||
itoa(va_arg(args, int), buf, 10, false);
|
||||
puts(buf);
|
||||
break;
|
||||
case 'u':
|
||||
utoa(va_arg(args, unsigned int), buf, 10, false);
|
||||
puts(buf);
|
||||
break;
|
||||
case 'x':
|
||||
utoa(va_arg(args, unsigned int), buf, 16, false);
|
||||
puts(buf);
|
||||
break;
|
||||
case 'X':
|
||||
utoa(va_arg(args, unsigned int), buf, 16, true);
|
||||
puts(buf);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(*fstr == '@') {
|
||||
uint8_t hi = hex2i(*++fstr);
|
||||
uint8_t lo = hex2i(*++fstr);
|
||||
term_setcol((hi << 4) | lo);
|
||||
} else {
|
||||
putc(*fstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void printf(const char *fstr, ...) {
|
||||
va_list args;
|
||||
va_start(args, fstr);
|
||||
vprintf(fstr, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
void term_clear(void) {
|
||||
memset(screen, 0, TERM_W * TERM_H * 2);
|
||||
memset(screen_buf, 0, TERM_W * TERM_H * 2);
|
||||
}
|
||||
|
||||
void term_setpos(size_t new_x, size_t new_y) {
|
||||
x = new_x;
|
||||
y = new_y;
|
||||
term_x = new_x;
|
||||
term_y = new_y;
|
||||
}
|
||||
|
||||
void term_setcol(uint8_t new_col) {
|
||||
color = new_col;
|
||||
}
|
||||
|
||||
void term_scroll(ptrdiff_t lines) {
|
||||
term_y -= lines;
|
||||
if(lines == 0) return;
|
||||
if(lines >= TERM_H || lines <= -TERM_H) {
|
||||
term_clear();
|
||||
} else if(lines > 0) {
|
||||
memmove(screen_buf, screen_buf + lines * TERM_W, 2 * (TERM_H - lines) * TERM_W);
|
||||
memset(screen_buf + (TERM_H - lines) * TERM_W, 0, 2 * lines * TERM_W);
|
||||
} else {
|
||||
memmove(screen_buf + lines * TERM_W, screen_buf + lines, (TERM_H + lines) * TERM_W);
|
||||
}
|
||||
}
|
||||
|
||||
void term_flush(void) {
|
||||
int_disable();
|
||||
memcpy_volatile(screen, screen_buf, TERM_W * TERM_H * 2);
|
||||
int_enable();
|
||||
}
|
||||
|
||||
uint32_t term_save(void) {
|
||||
return color | ((x + y * TERM_W) << 8);
|
||||
return color | ((term_x + term_y * TERM_W) << 8);
|
||||
}
|
||||
|
||||
void term_load(uint32_t state) {
|
||||
color = state & 0xff;
|
||||
state >>= 8;
|
||||
x = state % TERM_W;
|
||||
y = state / TERM_W;
|
||||
term_x = state % TERM_W;
|
||||
term_y = state / TERM_W;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define TERM_W 80
|
||||
#define TERM_H 25
|
||||
|
||||
void putc(char c);
|
||||
void puts(char* s);
|
||||
void puts(const char* s);
|
||||
void printf(const char* s, ...);
|
||||
void vprintf(const char* s, va_list args);
|
||||
void term_clear(void);
|
||||
void term_setcol(uint8_t new_col);
|
||||
void term_setpos(size_t new_x, size_t new_y);
|
||||
uint32_t term_save(void);
|
||||
void term_load(uint32_t pos);
|
||||
void term_scroll(ptrdiff_t lines);
|
||||
void term_flush(void);
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
enum {
|
||||
ESUCCESS,
|
||||
ENOENTRY,
|
||||
EDISKFAIL,
|
||||
};
|
|
@ -1,4 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
int atoi(const char* s);
|
||||
void itoa(int n, char* buf);
|
||||
|
|
|
@ -6,3 +6,6 @@ int memcmp(const void *lhs, const void *rhs, size_t n);
|
|||
void *memcpy(void *restrict dst, const void *restrict src, size_t n);
|
||||
void *memmove(void *dst, const void *src, size_t n);
|
||||
void *memset(void *dest, int c, size_t n);
|
||||
|
||||
char *strcpy(char *restrict dst, const char *restrict src);
|
||||
char *strncpy(char *restrict dst, const char *restrict src, size_t n);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#include <stddef.h>
|
||||
|
||||
volatile void *memmove_volatile(volatile void *dst, const volatile void *src, size_t n);
|
||||
volatile void *memset_volatile(volatile void *dest, int c, size_t n);
|
||||
volatile void *memcpy_volatile(volatile void *restrict dst, const volatile void *restrict src, volatile size_t n);
|
|
@ -1,12 +1,51 @@
|
|||
#include <stdint.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t inb(uint16_t port);
|
||||
void outb(uint16_t port, uint8_t val);
|
||||
void io_wait(void);
|
||||
static inline uint8_t inb(uint16_t port) {
|
||||
uint8_t ret;
|
||||
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void int_enable(void);
|
||||
void int_disable(void);
|
||||
void int_wait(void);
|
||||
static inline void outb(uint16_t port, uint8_t val) {
|
||||
__asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
|
||||
}
|
||||
|
||||
void halt(void);
|
||||
static inline uint16_t inw(uint16_t port) {
|
||||
uint16_t ret;
|
||||
__asm__ volatile ("inw %1, %0" : "=a"(ret) : "Nd"(port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void outw(uint16_t port, uint16_t val) {
|
||||
__asm__ volatile ("outw %0, %1" : : "a"(val), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline uint32_t inl(uint16_t port) {
|
||||
uint32_t ret;
|
||||
__asm__ volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void outl(uint16_t port, uint32_t val) {
|
||||
__asm__ volatile ("outl %0, %1" : : "a"(val), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline void io_wait(void) {
|
||||
outb(0x80, 0);
|
||||
}
|
||||
|
||||
static inline void int_enable(void) {
|
||||
__asm__ volatile ("sti");
|
||||
}
|
||||
|
||||
static inline void int_disable(void) {
|
||||
__asm__ volatile ("cli");
|
||||
}
|
||||
|
||||
static inline void int_wait(void) {
|
||||
__asm__ volatile ("sti; hlt");
|
||||
}
|
||||
|
||||
static inline void halt(void) {
|
||||
__asm__ volatile ("cli; hlt");
|
||||
}
|
||||
|
|
|
@ -17,30 +17,3 @@ int atoi(const char* s) {
|
|||
}
|
||||
return neg ? -n : n;
|
||||
}
|
||||
|
||||
void itoa(int n, char* buf) {
|
||||
if(n < 0) {
|
||||
n = -n;
|
||||
*buf = '-';
|
||||
buf++;
|
||||
} else if(n == 0) {
|
||||
buf[0] = '0';
|
||||
buf[1] = '\0';
|
||||
return;
|
||||
}
|
||||
char* start = buf;
|
||||
while(n > 0) {
|
||||
*buf= n % 10 + '0';
|
||||
n /= 10;
|
||||
buf++;
|
||||
}
|
||||
*buf = '\0';
|
||||
buf--;
|
||||
while(start < buf) {
|
||||
char tmp = *start;
|
||||
*start = *buf;
|
||||
*buf = tmp;
|
||||
start++;
|
||||
buf--;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,25 @@ void *memmove(void *dst, const void *src, size_t n) {
|
|||
void *memset(void *dest, int c, size_t n) {
|
||||
unsigned char *d = dest;
|
||||
while(n--) {
|
||||
*d = c;
|
||||
*d++ = c;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *strcpy(char *restrict dst, const char *restrict src) {
|
||||
while((*dst = *src) != '\0') {
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strncpy(char *restrict dst, const char *restrict src, size_t n) {
|
||||
while((*dst = *src) != '\0' && n != 0) {
|
||||
dst++;
|
||||
src++;
|
||||
n--;
|
||||
}
|
||||
memset(dst, 0, n);
|
||||
return dst;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
#include <stddef.h>
|
||||
#include "include/string_volatile.h"
|
||||
|
||||
volatile void *memmove_volatile(volatile void *dst, const volatile void *src, volatile size_t n) {
|
||||
volatile char *d = dst;
|
||||
volatile const char *s = src;
|
||||
if(s < d) {
|
||||
d += n;
|
||||
s += n;
|
||||
while(n--) {
|
||||
*--d = *--s;
|
||||
}
|
||||
} else {
|
||||
while(n--) {
|
||||
*d++ = *s++;
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
volatile void *memset_volatile(volatile void *dest, int c, volatile size_t n) {
|
||||
volatile unsigned char *d = dest;
|
||||
while(n--) {
|
||||
*d++ = c;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
volatile void *memcpy_volatile(volatile void *restrict dst, const volatile void *restrict src, volatile size_t n) {
|
||||
volatile char *d = dst;
|
||||
volatile const char *s = src;
|
||||
while(n--) {
|
||||
*d++ = *s++;
|
||||
}
|
||||
return dst;
|
||||
}
|
31
libk/sys.c
31
libk/sys.c
|
@ -1,31 +0,0 @@
|
|||
#include <stdint.h>
|
||||
|
||||
uint8_t inb(uint16_t port) {
|
||||
uint8_t ret;
|
||||
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void outb(uint16_t port, uint8_t val) {
|
||||
__asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
|
||||
}
|
||||
|
||||
void io_wait(void) {
|
||||
outb(0x80, 0);
|
||||
}
|
||||
|
||||
void int_enable(void) {
|
||||
__asm__ volatile ("sti");
|
||||
}
|
||||
|
||||
void int_disable(void) {
|
||||
__asm__ volatile ("cli");
|
||||
}
|
||||
|
||||
void int_wait(void) {
|
||||
__asm__ volatile ("hlt");
|
||||
}
|
||||
|
||||
void halt(void) {
|
||||
__asm__ volatile ("cli; hlt");
|
||||
}
|
18
linker.ld
18
linker.ld
|
@ -3,23 +3,23 @@ ENTRY(start)
|
|||
SECTIONS {
|
||||
. = 1M;
|
||||
|
||||
.boot :
|
||||
.boot BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.multiboot_header)
|
||||
*(.multiboot)
|
||||
}
|
||||
|
||||
.rodata :
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.bss)
|
||||
}
|
||||
|
||||
.text :
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.text)
|
||||
}
|
||||
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.bss)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/sh
|
||||
|
||||
DISKSIZE_MB=16
|
||||
DISK=disk.img
|
||||
OFFSET=1048576
|
||||
|
||||
dd if=/dev/zero of="$DISK" bs=1M count="$DISKSIZE_MB"
|
||||
|
||||
sfdisk "$DISK" <<EOF
|
||||
label: dos
|
||||
label-id: 0x7c295044
|
||||
device: disk.img
|
||||
unit: sectors
|
||||
sector-size: 512
|
||||
|
||||
disk.img1 : start= 2048, size= 30720, type=4
|
||||
EOF
|
||||
|
||||
LOOPDEV="$(losetup -f)"
|
||||
losetup "$LOOPDEV" "$DISK" -o "$OFFSET"
|
||||
mkfs.fat -F16 "$LOOPDEV"
|
||||
losetup -D "$DISK"
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/sh
|
||||
|
||||
DISK=disk.img
|
||||
MOUNTPOINT=mnt
|
||||
OFFSET=1048576
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "must be root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if mountpoint "$MOUNTPOINT" >/dev/null; then
|
||||
echo "unmounting"
|
||||
umount "$MOUNTPOINT"
|
||||
losetup -D "$DISK"
|
||||
else
|
||||
echo "mounting"
|
||||
LOOPDEV="$(losetup -f)"
|
||||
losetup "$LOOPDEV" "$DISK" -o "$OFFSET"
|
||||
mount "$LOOPDEV" "$MOUNTPOINT"
|
||||
fi
|
Loading…
Reference in New Issue