kernel: remove everything that is related to device/fs management

this is now a microkernel.
This commit is contained in:
2024-09-17 17:47:50 +01:00
parent 9b00f83ff1
commit 3f992d84fb
66 changed files with 213 additions and 65447 deletions

View File

@@ -28,7 +28,7 @@ include arch/$(SOCKS_ARCH)/config.mk
# Platform-independent kernel source files
####################################
KERNEL_SRC_DIRS := init kernel vm ds util obj sched dev test kxld
KERNEL_SRC_DIRS := init kernel vm ds util obj sched test
KERNEL_C_FILES := $(foreach dir,$(KERNEL_SRC_DIRS),$(shell find $(dir) -type f -name *.c))
KERNEL_CXX_FILES := $(foreach dir,$(KERNEL_SRC_DIRS),$(shell find $(dir) -type f -name *.cpp))
KERNEL_OBJ := $(addprefix $(BUILD_DIR)/,$(KERNEL_C_FILES:.c=.o) $(KERNEL_CXX_FILES:.cpp=.o))
@@ -48,19 +48,18 @@ CWARNINGS := -Wall -Werror -pedantic -Wno-language-extension-token -Wno-unused-f
OPTIMISATION_LEVEL := -O2
CFLAGS := $(CFLAGS) -DBUILD_ID=\"$(BUILD_ID)\" $(OPTIMISATION_LEVEL) -g -fPIC -std=gnu17 \
-Iinclude -Iarch/$(SOCKS_ARCH)/include -Ilibc/include $(CWARNINGS) \
$(INTERNAL_KEXT_INCLUDES) $(INTERNAL_KEXT_DEFINES)
-Iinclude -Iarch/$(SOCKS_ARCH)/include -Ilibc/include $(CWARNINGS)
KERNEL_DEFINES := -DSOCKS_INTERNAL=1
CXXFLAGS := $(CXXFLAGS) -DBUILD_ID=\"$(BUILD_ID)\" $(OPTIMISATION_LEVEL) -g -fPIC -std=gnu++17 \
-Iinclude -Iarch/$(SOCKS_ARCH)/include -Ilibc/include -Wno-language-extension-token $(CWARNINGS) \
$(INTERNAL_KEXT_INCLUDES) $(INTERNAL_KEXT_DEFINES)
-Iinclude -Iarch/$(SOCKS_ARCH)/include -Ilibc/include -Wno-language-extension-token $(CWARNINGS)
ASMFLAGS := $(ASMFLAGS) -DBUILD_ID=\"$(BUILD_ID)\"
LDFLAGS := $(LDFLAGS) -g -lgcc $(OPTIMISATION_LEVEL)
ALL_KERNEL_OBJECT_FILES := $(KERNEL_OBJ) $(ARCH_OBJ) $(LIBC_OBJ) $(INTERNAL_KEXT_OBJ)
ALL_KERNEL_OBJECT_FILES := $(KERNEL_OBJ) $(ARCH_OBJ) $(LIBC_OBJ)
ALL_KERNEL_DEPS := $(ALL_KERNEL_OBJECT_FILES:.o=.d)
all: $(BUILD_DIR)/$(KERNEL_EXEC) tools
@@ -105,12 +104,6 @@ install-cd: $(BUILD_DIR)/socks-kernel.iso
compile-db: $(BUILD_DIR)/compile_commands.json
kext-list:
@./tools/socks.kexttool list
kext-config:
@./tools/socks.kexttool select
tools:
@$(MAKE) -C tools

View File

@@ -1,39 +1,22 @@
#include <socks/pmap.h>
#include <socks/device.h>
#include <socks/arg.h>
#include <socks/tty.h>
#include <socks/kext.h>
#include <socks/clock.h>
#include <socks/types.h>
#include <socks/object.h>
#include <arch/e820.h>
#include <socks/init.h>
#include <socks/percpu.h>
#include <socks/cpu.h>
#include <socks/memblock.h>
#include <socks/vm.h>
#include <socks/printk.h>
#include <socks/arg.h>
#include <socks/clock.h>
#include <socks/console.h>
#include <socks/machine/cpu.h>
#include <socks/cpu.h>
#include <socks/init.h>
#include <socks/libc/stdio.h>
#ifdef KEXT_NET_DOORSTUCK_SOCKS_ACPI
#include <arch/acpi.h>
#endif
#ifdef KEXT_NET_DOORSTUCK_SOCKS_FBCON
#include <socks/fbcon.h>
#endif
#ifdef KEXT_NET_DOORSTUCK_SOCKS_SERIALCON
#include <socks/serialcon.h>
#endif
#include <socks/machine/cpu.h>
#include <socks/memblock.h>
#include <socks/object.h>
#include <socks/percpu.h>
#include <socks/pmap.h>
#include <socks/printk.h>
#include <socks/types.h>
#include <socks/vm.h>
#define PTR32(x) ((void *)((uintptr_t)(x)))
static ml_cpu_block g_bootstrap_cpu = {0};
static struct framebuffer_varinfo __bootfb_varinfo;
static struct framebuffer_fixedinfo __bootfb_fixedinfo;
/* start and end of kernel image (physical addresses) */
extern char __pstart[], __pend[];
@@ -52,10 +35,14 @@ static void early_vm_init(void)
uintptr_t alloc_end = VM_KERNEL_VOFFSET + 0x7fffffff;
memblock_init(alloc_start, alloc_end, VM_KERNEL_VOFFSET);
printk("memblock: allocating from [0x%llx-0x%llx]", alloc_start, alloc_end);
printk("memblock: allocating from [0x%llx-0x%llx]",
alloc_start,
alloc_end);
memblock_reserve(0x00, (uintptr_t)__pend);
printk("memblock: reserved bios+kernel at [0x%016llx-0x%016llx]", 0, (uintptr_t)__pend);
printk("memblock: reserved bios+kernel at [0x%016llx-0x%016llx]",
0,
(uintptr_t)__pend);
}
void early_console_init(void)
@@ -64,60 +51,10 @@ void early_console_init(void)
if (!dest) {
return;
}
#ifdef KEXT_NET_DOORSTUCK_SOCKS_FBCON
if (!strcmp(dest, "tty0")) {
early_vgacon_init();
}
#endif
#ifdef KEXT_NET_DOORSTUCK_SOCKS_SERIALCON
if (!strncmp(dest, "ttyS0", 5)) {
/* TODO allow specifying baud rate from command line */
unsigned int baud = 115200;
early_serialcon_init(baud);
}
#endif
}
static void init_bootfb(multiboot_info_t *mb)
{
__bootfb_varinfo.fb_xres = mb->framebuffer_width;
__bootfb_varinfo.fb_yres = mb->framebuffer_height;
__bootfb_varinfo.fb_bpp = mb->framebuffer_bpp;
__bootfb_varinfo.fb_stride = mb->framebuffer_pitch;
__bootfb_fixedinfo.fb_baseptr = mb->framebuffer_addr;
switch (mb->framebuffer_type) {
case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
__bootfb_varinfo.fb_flags = FB_MODE_PALETTE;
__bootfb_varinfo.fb_palette_addr = mb->framebuffer_palette_addr;
__bootfb_varinfo.fb_palette_nr_colours = mb->framebuffer_palette_num_colors;
break;
case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
__bootfb_varinfo.fb_flags = FB_MODE_RGB;
__bootfb_varinfo.fb_red.b_length = mb->framebuffer_red_mask_size;
__bootfb_varinfo.fb_red.b_offset = mb->framebuffer_red_field_position;
__bootfb_varinfo.fb_green.b_length = mb->framebuffer_green_mask_size;
__bootfb_varinfo.fb_green.b_offset = mb->framebuffer_green_field_position;
__bootfb_varinfo.fb_blue.b_length = mb->framebuffer_blue_mask_size;
__bootfb_varinfo.fb_blue.b_offset = mb->framebuffer_blue_field_position;
__bootfb_varinfo.fb_alpha.b_length = 0;
__bootfb_varinfo.fb_alpha.b_offset = 0;
break;
case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
__bootfb_fixedinfo.fb_baseptr = 0xb8000;
__bootfb_varinfo.fb_flags = FB_MODE_VGATEXT;
__bootfb_varinfo.fb_xcells = 80;
__bootfb_varinfo.fb_ycells = 25;
break;
default:
break;
}
}
static void use_uniprocessor_topology(void)
@@ -142,17 +79,15 @@ int ml_init(uintptr_t arg)
print_kernel_banner();
early_vm_init();
printk("video mode: %ux%u", mb->framebuffer_width, mb->framebuffer_height);
printk("video mode: %ux%u",
mb->framebuffer_width,
mb->framebuffer_height);
e820_scan(PTR32(mb->mmap_addr), mb->mmap_length);
pmap_bootstrap();
#ifdef KEXT_NET_DOORSTUCK_SOCKS_ACPI
acpi_scan_cpu_topology();
#else
use_uniprocessor_topology();
#endif
init_per_cpu_areas();
@@ -165,36 +100,25 @@ int ml_init(uintptr_t arg)
put_cpu(this_cpu);
struct vm_zone_descriptor vm_zones[] = {
{ .zd_id = VM_ZONE_DMA, .zd_node = 0, .zd_name = "dma", .zd_base = 0x00, .zd_limit = 0xffffff },
{ .zd_id = VM_ZONE_NORMAL, .zd_node = 0, .zd_name = "normal", .zd_base = 0x1000000, .zd_limit = UINTPTR_MAX },
{.zd_id = VM_ZONE_DMA,
.zd_node = 0,
.zd_name = "dma",
.zd_base = 0x00,
.zd_limit = 0xffffff},
{.zd_id = VM_ZONE_NORMAL,
.zd_node = 0,
.zd_name = "normal",
.zd_base = 0x1000000,
.zd_limit = UINTPTR_MAX},
};
vm_bootstrap(vm_zones, sizeof vm_zones / sizeof vm_zones[0]);
object_bootstrap();
init_kernel_kext();
sched_init();
device_init();
#ifdef KEXT_NET_DOORSTUCK_SOCKS_ACPI
acpi_init();
#endif
tty_bootstrap();
ml_int_enable();
return 0;
}
const struct framebuffer_varinfo *bootfb_varinfo(void)
{
return &__bootfb_varinfo;
}
const struct framebuffer_fixedinfo *bootfb_fixedinfo(void)
{
return &__bootfb_fixedinfo;
}

View File

@@ -1,17 +1,13 @@
#include <arch/irq.h>
#include <arch/ports.h>
#include <socks/sched.h>
#include <socks/cpu.h>
#include <socks/panic.h>
#include <socks/libc/string.h>
#include <socks/machine/irq.h>
#include <socks/machine/cpu.h>
#include <socks/machine/irq.h>
#include <socks/panic.h>
#include <socks/sched.h>
#include <stddef.h>
#ifdef KEXT_NET_DOORSTUCK_SOCKS_ACPI
#include <arch/acpi.h>
#endif
#define MAX_ISR_HANDLERS 16
extern void syscall_gate();
@@ -24,7 +20,12 @@ static struct idt idt;
static int idt_initialised = 0;
static uintptr_t int_entry_points[NR_IDT_ENTRIES];
static void set_idt_gate(struct idt *idt, uint8_t index, uintptr_t base, uint16_t sel, uint8_t flags)
static void set_idt_gate(
struct idt *idt,
uint8_t index,
uintptr_t base,
uint16_t sel,
uint8_t flags)
{
idt->i_entries[index].base_low = base & 0xFFFF;
idt->i_entries[index].base_middle = (base >> 16) & 0xFFFF;
@@ -44,13 +45,24 @@ static void gpf_handler(struct cpu_context *regs)
int table = (regs->err_no >> 1) & 0x03;
int index = (regs->err_no >> 3) & 0x1FFF;
panic_irq(regs, "general protection fault (%016llx %02x %02x %04x %016llx)",
regs->err_no, ext, table, index, regs->rip);
panic_irq(
regs,
"general protection fault (%016llx %02x %02x %04x %016llx)",
regs->err_no,
ext,
table,
index,
regs->rip);
}
static void pf_handler(struct cpu_context *regs)
{
panic_irq(regs, "page fault (%016llx %016llx %016llx)", pf_faultptr(), regs->rip, regs->err_no);
panic_irq(
regs,
"page fault (%016llx %016llx %016llx)",
pf_faultptr(),
regs->rip,
regs->err_no);
}
#if 0
@@ -125,7 +137,7 @@ int idt_init(struct idt_ptr *ptr)
int idt_load(struct idt_ptr *ptr)
{
__asm__ __volatile__("lidt (%0)" ::"r" (ptr));
__asm__ __volatile__("lidt (%0)" ::"r"(ptr));
return 0;
}
@@ -139,7 +151,6 @@ void isr_dispatch(struct cpu_context *regs)
}
}
#ifndef KEXT_NET_DOORSTUCK_SOCKS_ACPI
void irq_ack(unsigned int vec)
{
if (vec >= 40) {
@@ -148,7 +159,6 @@ void irq_ack(unsigned int vec)
outportb(0x20, 0x20);
}
#endif
void irq_dispatch(struct cpu_context *regs)
{
@@ -156,7 +166,8 @@ void irq_dispatch(struct cpu_context *regs)
irq_ack(regs->int_no);
struct queue *hooks = &irq_hooks[regs->int_no - IRQ0];
queue_foreach(struct irq_hook, hook, hooks, irq_entry) {
queue_foreach(struct irq_hook, hook, hooks, irq_entry)
{
hook->irq_callback();
}
@@ -169,7 +180,6 @@ void irq_dispatch(struct cpu_context *regs)
void syscall_dispatch(struct cpu_context *regs)
{
}
void hook_irq(enum irq_vector vec, struct irq_hook *hook)
@@ -443,260 +453,132 @@ extern void _irq222();
extern void _irq223();
static uintptr_t int_entry_points[NR_IDT_ENTRIES] = {
[0] = (uintptr_t)_isr0,
[1] = (uintptr_t)_isr1,
[2] = (uintptr_t)_isr2,
[3] = (uintptr_t)_isr3,
[4] = (uintptr_t)_isr4,
[5] = (uintptr_t)_isr5,
[6] = (uintptr_t)_isr6,
[7] = (uintptr_t)_isr7,
[8] = (uintptr_t)_isr8,
[9] = (uintptr_t)_isr9,
[10] = (uintptr_t)_isr10,
[11] = (uintptr_t)_isr11,
[12] = (uintptr_t)_isr12,
[13] = (uintptr_t)_isr13,
[14] = (uintptr_t)_isr14,
[15] = (uintptr_t)_isr15,
[16] = (uintptr_t)_isr16,
[17] = (uintptr_t)_isr17,
[18] = (uintptr_t)_isr18,
[19] = (uintptr_t)_isr19,
[20] = (uintptr_t)_isr20,
[21] = (uintptr_t)_isr21,
[22] = (uintptr_t)_isr22,
[23] = (uintptr_t)_isr23,
[24] = (uintptr_t)_isr24,
[25] = (uintptr_t)_isr25,
[26] = (uintptr_t)_isr26,
[27] = (uintptr_t)_isr27,
[28] = (uintptr_t)_isr28,
[29] = (uintptr_t)_isr29,
[30] = (uintptr_t)_isr30,
[31] = (uintptr_t)_isr31,
[32] = (uintptr_t)_irq0,
[33] = (uintptr_t)_irq1,
[34] = (uintptr_t)_irq2,
[35] = (uintptr_t)_irq3,
[36] = (uintptr_t)_irq4,
[37] = (uintptr_t)_irq5,
[38] = (uintptr_t)_irq6,
[39] = (uintptr_t)_irq7,
[40] = (uintptr_t)_irq8,
[41] = (uintptr_t)_irq9,
[42] = (uintptr_t)_irq10,
[43] = (uintptr_t)_irq11,
[44] = (uintptr_t)_irq12,
[45] = (uintptr_t)_irq13,
[46] = (uintptr_t)_irq14,
[47] = (uintptr_t)_irq15,
[48] = (uintptr_t)_irq16,
[49] = (uintptr_t)_irq17,
[50] = (uintptr_t)_irq18,
[51] = (uintptr_t)_irq19,
[52] = (uintptr_t)_irq20,
[53] = (uintptr_t)_irq21,
[54] = (uintptr_t)_irq22,
[55] = (uintptr_t)_irq23,
[56] = (uintptr_t)_irq24,
[57] = (uintptr_t)_irq25,
[58] = (uintptr_t)_irq26,
[59] = (uintptr_t)_irq27,
[60] = (uintptr_t)_irq28,
[61] = (uintptr_t)_irq29,
[62] = (uintptr_t)_irq30,
[63] = (uintptr_t)_irq31,
[64] = (uintptr_t)_irq32,
[65] = (uintptr_t)_irq33,
[66] = (uintptr_t)_irq34,
[67] = (uintptr_t)_irq35,
[68] = (uintptr_t)_irq36,
[69] = (uintptr_t)_irq37,
[70] = (uintptr_t)_irq38,
[71] = (uintptr_t)_irq39,
[72] = (uintptr_t)_irq40,
[73] = (uintptr_t)_irq41,
[74] = (uintptr_t)_irq42,
[75] = (uintptr_t)_irq43,
[76] = (uintptr_t)_irq44,
[77] = (uintptr_t)_irq45,
[78] = (uintptr_t)_irq46,
[79] = (uintptr_t)_irq47,
[80] = (uintptr_t)_irq48,
[81] = (uintptr_t)_irq49,
[82] = (uintptr_t)_irq50,
[83] = (uintptr_t)_irq51,
[84] = (uintptr_t)_irq52,
[85] = (uintptr_t)_irq53,
[86] = (uintptr_t)_irq54,
[87] = (uintptr_t)_irq55,
[88] = (uintptr_t)_irq56,
[89] = (uintptr_t)_irq57,
[90] = (uintptr_t)_irq58,
[91] = (uintptr_t)_irq59,
[92] = (uintptr_t)_irq60,
[93] = (uintptr_t)_irq61,
[94] = (uintptr_t)_irq62,
[95] = (uintptr_t)_irq63,
[96] = (uintptr_t)_irq64,
[97] = (uintptr_t)_irq65,
[98] = (uintptr_t)_irq66,
[99] = (uintptr_t)_irq67,
[100] = (uintptr_t)_irq68,
[101] = (uintptr_t)_irq69,
[102] = (uintptr_t)_irq70,
[103] = (uintptr_t)_irq71,
[104] = (uintptr_t)_irq72,
[105] = (uintptr_t)_irq73,
[106] = (uintptr_t)_irq74,
[107] = (uintptr_t)_irq75,
[108] = (uintptr_t)_irq76,
[109] = (uintptr_t)_irq77,
[110] = (uintptr_t)_irq78,
[111] = (uintptr_t)_irq79,
[112] = (uintptr_t)_irq80,
[113] = (uintptr_t)_irq81,
[114] = (uintptr_t)_irq82,
[115] = (uintptr_t)_irq83,
[116] = (uintptr_t)_irq84,
[117] = (uintptr_t)_irq85,
[118] = (uintptr_t)_irq86,
[119] = (uintptr_t)_irq87,
[120] = (uintptr_t)_irq88,
[121] = (uintptr_t)_irq89,
[122] = (uintptr_t)_irq90,
[123] = (uintptr_t)_irq91,
[124] = (uintptr_t)_irq92,
[125] = (uintptr_t)_irq93,
[126] = (uintptr_t)_irq94,
[127] = (uintptr_t)_irq95,
[128] = (uintptr_t)_irq96,
[129] = (uintptr_t)_irq97,
[130] = (uintptr_t)_irq98,
[131] = (uintptr_t)_irq99,
[132] = (uintptr_t)_irq100,
[133] = (uintptr_t)_irq101,
[134] = (uintptr_t)_irq102,
[135] = (uintptr_t)_irq103,
[136] = (uintptr_t)_irq104,
[137] = (uintptr_t)_irq105,
[138] = (uintptr_t)_irq106,
[139] = (uintptr_t)_irq107,
[140] = (uintptr_t)_irq108,
[141] = (uintptr_t)_irq109,
[142] = (uintptr_t)_irq110,
[143] = (uintptr_t)_irq111,
[144] = (uintptr_t)_irq112,
[145] = (uintptr_t)_irq113,
[146] = (uintptr_t)_irq114,
[147] = (uintptr_t)_irq115,
[148] = (uintptr_t)_irq116,
[149] = (uintptr_t)_irq117,
[150] = (uintptr_t)_irq118,
[151] = (uintptr_t)_irq119,
[152] = (uintptr_t)_irq120,
[153] = (uintptr_t)_irq121,
[154] = (uintptr_t)_irq122,
[155] = (uintptr_t)_irq123,
[156] = (uintptr_t)_irq124,
[157] = (uintptr_t)_irq125,
[158] = (uintptr_t)_irq126,
[159] = (uintptr_t)_irq127,
[160] = (uintptr_t)_irq128,
[161] = (uintptr_t)_irq129,
[162] = (uintptr_t)_irq130,
[163] = (uintptr_t)_irq131,
[164] = (uintptr_t)_irq132,
[165] = (uintptr_t)_irq133,
[166] = (uintptr_t)_irq134,
[167] = (uintptr_t)_irq135,
[168] = (uintptr_t)_irq136,
[169] = (uintptr_t)_irq137,
[170] = (uintptr_t)_irq138,
[171] = (uintptr_t)_irq139,
[172] = (uintptr_t)_irq140,
[173] = (uintptr_t)_irq141,
[174] = (uintptr_t)_irq142,
[175] = (uintptr_t)_irq143,
[176] = (uintptr_t)_irq144,
[177] = (uintptr_t)_irq145,
[178] = (uintptr_t)_irq146,
[179] = (uintptr_t)_irq147,
[180] = (uintptr_t)_irq148,
[181] = (uintptr_t)_irq149,
[182] = (uintptr_t)_irq150,
[183] = (uintptr_t)_irq151,
[184] = (uintptr_t)_irq152,
[185] = (uintptr_t)_irq153,
[186] = (uintptr_t)_irq154,
[187] = (uintptr_t)_irq155,
[188] = (uintptr_t)_irq156,
[189] = (uintptr_t)_irq157,
[190] = (uintptr_t)_irq158,
[191] = (uintptr_t)_irq159,
[192] = (uintptr_t)_irq160,
[193] = (uintptr_t)_irq161,
[194] = (uintptr_t)_irq162,
[195] = (uintptr_t)_irq163,
[196] = (uintptr_t)_irq164,
[197] = (uintptr_t)_irq165,
[198] = (uintptr_t)_irq166,
[199] = (uintptr_t)_irq167,
[200] = (uintptr_t)_irq168,
[201] = (uintptr_t)_irq169,
[202] = (uintptr_t)_irq170,
[203] = (uintptr_t)_irq171,
[204] = (uintptr_t)_irq172,
[205] = (uintptr_t)_irq173,
[206] = (uintptr_t)_irq174,
[207] = (uintptr_t)_irq175,
[208] = (uintptr_t)_irq176,
[209] = (uintptr_t)_irq177,
[210] = (uintptr_t)_irq178,
[211] = (uintptr_t)_irq179,
[212] = (uintptr_t)_irq180,
[213] = (uintptr_t)_irq181,
[214] = (uintptr_t)_irq182,
[215] = (uintptr_t)_irq183,
[216] = (uintptr_t)_irq184,
[217] = (uintptr_t)_irq185,
[218] = (uintptr_t)_irq186,
[219] = (uintptr_t)_irq187,
[220] = (uintptr_t)_irq188,
[221] = (uintptr_t)_irq189,
[222] = (uintptr_t)_irq190,
[223] = (uintptr_t)_irq191,
[224] = (uintptr_t)_irq192,
[225] = (uintptr_t)_irq193,
[226] = (uintptr_t)_irq194,
[227] = (uintptr_t)_irq195,
[228] = (uintptr_t)_irq196,
[229] = (uintptr_t)_irq197,
[230] = (uintptr_t)_irq198,
[231] = (uintptr_t)_irq199,
[232] = (uintptr_t)_irq200,
[233] = (uintptr_t)_irq201,
[234] = (uintptr_t)_irq202,
[235] = (uintptr_t)_irq203,
[236] = (uintptr_t)_irq204,
[237] = (uintptr_t)_irq205,
[238] = (uintptr_t)_irq206,
[239] = (uintptr_t)_irq207,
[240] = (uintptr_t)_irq208,
[241] = (uintptr_t)_irq209,
[242] = (uintptr_t)_irq210,
[243] = (uintptr_t)_irq211,
[244] = (uintptr_t)_irq212,
[245] = (uintptr_t)_irq213,
[246] = (uintptr_t)_irq214,
[247] = (uintptr_t)_irq215,
[248] = (uintptr_t)_irq216,
[249] = (uintptr_t)_irq217,
[250] = (uintptr_t)_irq218,
[251] = (uintptr_t)_irq219,
[252] = (uintptr_t)_irq220,
[253] = (uintptr_t)_irq221,
[254] = (uintptr_t)_irq222,
[255] = (uintptr_t)_irq223,
[0] = (uintptr_t)_isr0, [1] = (uintptr_t)_isr1,
[2] = (uintptr_t)_isr2, [3] = (uintptr_t)_isr3,
[4] = (uintptr_t)_isr4, [5] = (uintptr_t)_isr5,
[6] = (uintptr_t)_isr6, [7] = (uintptr_t)_isr7,
[8] = (uintptr_t)_isr8, [9] = (uintptr_t)_isr9,
[10] = (uintptr_t)_isr10, [11] = (uintptr_t)_isr11,
[12] = (uintptr_t)_isr12, [13] = (uintptr_t)_isr13,
[14] = (uintptr_t)_isr14, [15] = (uintptr_t)_isr15,
[16] = (uintptr_t)_isr16, [17] = (uintptr_t)_isr17,
[18] = (uintptr_t)_isr18, [19] = (uintptr_t)_isr19,
[20] = (uintptr_t)_isr20, [21] = (uintptr_t)_isr21,
[22] = (uintptr_t)_isr22, [23] = (uintptr_t)_isr23,
[24] = (uintptr_t)_isr24, [25] = (uintptr_t)_isr25,
[26] = (uintptr_t)_isr26, [27] = (uintptr_t)_isr27,
[28] = (uintptr_t)_isr28, [29] = (uintptr_t)_isr29,
[30] = (uintptr_t)_isr30, [31] = (uintptr_t)_isr31,
[32] = (uintptr_t)_irq0, [33] = (uintptr_t)_irq1,
[34] = (uintptr_t)_irq2, [35] = (uintptr_t)_irq3,
[36] = (uintptr_t)_irq4, [37] = (uintptr_t)_irq5,
[38] = (uintptr_t)_irq6, [39] = (uintptr_t)_irq7,
[40] = (uintptr_t)_irq8, [41] = (uintptr_t)_irq9,
[42] = (uintptr_t)_irq10, [43] = (uintptr_t)_irq11,
[44] = (uintptr_t)_irq12, [45] = (uintptr_t)_irq13,
[46] = (uintptr_t)_irq14, [47] = (uintptr_t)_irq15,
[48] = (uintptr_t)_irq16, [49] = (uintptr_t)_irq17,
[50] = (uintptr_t)_irq18, [51] = (uintptr_t)_irq19,
[52] = (uintptr_t)_irq20, [53] = (uintptr_t)_irq21,
[54] = (uintptr_t)_irq22, [55] = (uintptr_t)_irq23,
[56] = (uintptr_t)_irq24, [57] = (uintptr_t)_irq25,
[58] = (uintptr_t)_irq26, [59] = (uintptr_t)_irq27,
[60] = (uintptr_t)_irq28, [61] = (uintptr_t)_irq29,
[62] = (uintptr_t)_irq30, [63] = (uintptr_t)_irq31,
[64] = (uintptr_t)_irq32, [65] = (uintptr_t)_irq33,
[66] = (uintptr_t)_irq34, [67] = (uintptr_t)_irq35,
[68] = (uintptr_t)_irq36, [69] = (uintptr_t)_irq37,
[70] = (uintptr_t)_irq38, [71] = (uintptr_t)_irq39,
[72] = (uintptr_t)_irq40, [73] = (uintptr_t)_irq41,
[74] = (uintptr_t)_irq42, [75] = (uintptr_t)_irq43,
[76] = (uintptr_t)_irq44, [77] = (uintptr_t)_irq45,
[78] = (uintptr_t)_irq46, [79] = (uintptr_t)_irq47,
[80] = (uintptr_t)_irq48, [81] = (uintptr_t)_irq49,
[82] = (uintptr_t)_irq50, [83] = (uintptr_t)_irq51,
[84] = (uintptr_t)_irq52, [85] = (uintptr_t)_irq53,
[86] = (uintptr_t)_irq54, [87] = (uintptr_t)_irq55,
[88] = (uintptr_t)_irq56, [89] = (uintptr_t)_irq57,
[90] = (uintptr_t)_irq58, [91] = (uintptr_t)_irq59,
[92] = (uintptr_t)_irq60, [93] = (uintptr_t)_irq61,
[94] = (uintptr_t)_irq62, [95] = (uintptr_t)_irq63,
[96] = (uintptr_t)_irq64, [97] = (uintptr_t)_irq65,
[98] = (uintptr_t)_irq66, [99] = (uintptr_t)_irq67,
[100] = (uintptr_t)_irq68, [101] = (uintptr_t)_irq69,
[102] = (uintptr_t)_irq70, [103] = (uintptr_t)_irq71,
[104] = (uintptr_t)_irq72, [105] = (uintptr_t)_irq73,
[106] = (uintptr_t)_irq74, [107] = (uintptr_t)_irq75,
[108] = (uintptr_t)_irq76, [109] = (uintptr_t)_irq77,
[110] = (uintptr_t)_irq78, [111] = (uintptr_t)_irq79,
[112] = (uintptr_t)_irq80, [113] = (uintptr_t)_irq81,
[114] = (uintptr_t)_irq82, [115] = (uintptr_t)_irq83,
[116] = (uintptr_t)_irq84, [117] = (uintptr_t)_irq85,
[118] = (uintptr_t)_irq86, [119] = (uintptr_t)_irq87,
[120] = (uintptr_t)_irq88, [121] = (uintptr_t)_irq89,
[122] = (uintptr_t)_irq90, [123] = (uintptr_t)_irq91,
[124] = (uintptr_t)_irq92, [125] = (uintptr_t)_irq93,
[126] = (uintptr_t)_irq94, [127] = (uintptr_t)_irq95,
[128] = (uintptr_t)_irq96, [129] = (uintptr_t)_irq97,
[130] = (uintptr_t)_irq98, [131] = (uintptr_t)_irq99,
[132] = (uintptr_t)_irq100, [133] = (uintptr_t)_irq101,
[134] = (uintptr_t)_irq102, [135] = (uintptr_t)_irq103,
[136] = (uintptr_t)_irq104, [137] = (uintptr_t)_irq105,
[138] = (uintptr_t)_irq106, [139] = (uintptr_t)_irq107,
[140] = (uintptr_t)_irq108, [141] = (uintptr_t)_irq109,
[142] = (uintptr_t)_irq110, [143] = (uintptr_t)_irq111,
[144] = (uintptr_t)_irq112, [145] = (uintptr_t)_irq113,
[146] = (uintptr_t)_irq114, [147] = (uintptr_t)_irq115,
[148] = (uintptr_t)_irq116, [149] = (uintptr_t)_irq117,
[150] = (uintptr_t)_irq118, [151] = (uintptr_t)_irq119,
[152] = (uintptr_t)_irq120, [153] = (uintptr_t)_irq121,
[154] = (uintptr_t)_irq122, [155] = (uintptr_t)_irq123,
[156] = (uintptr_t)_irq124, [157] = (uintptr_t)_irq125,
[158] = (uintptr_t)_irq126, [159] = (uintptr_t)_irq127,
[160] = (uintptr_t)_irq128, [161] = (uintptr_t)_irq129,
[162] = (uintptr_t)_irq130, [163] = (uintptr_t)_irq131,
[164] = (uintptr_t)_irq132, [165] = (uintptr_t)_irq133,
[166] = (uintptr_t)_irq134, [167] = (uintptr_t)_irq135,
[168] = (uintptr_t)_irq136, [169] = (uintptr_t)_irq137,
[170] = (uintptr_t)_irq138, [171] = (uintptr_t)_irq139,
[172] = (uintptr_t)_irq140, [173] = (uintptr_t)_irq141,
[174] = (uintptr_t)_irq142, [175] = (uintptr_t)_irq143,
[176] = (uintptr_t)_irq144, [177] = (uintptr_t)_irq145,
[178] = (uintptr_t)_irq146, [179] = (uintptr_t)_irq147,
[180] = (uintptr_t)_irq148, [181] = (uintptr_t)_irq149,
[182] = (uintptr_t)_irq150, [183] = (uintptr_t)_irq151,
[184] = (uintptr_t)_irq152, [185] = (uintptr_t)_irq153,
[186] = (uintptr_t)_irq154, [187] = (uintptr_t)_irq155,
[188] = (uintptr_t)_irq156, [189] = (uintptr_t)_irq157,
[190] = (uintptr_t)_irq158, [191] = (uintptr_t)_irq159,
[192] = (uintptr_t)_irq160, [193] = (uintptr_t)_irq161,
[194] = (uintptr_t)_irq162, [195] = (uintptr_t)_irq163,
[196] = (uintptr_t)_irq164, [197] = (uintptr_t)_irq165,
[198] = (uintptr_t)_irq166, [199] = (uintptr_t)_irq167,
[200] = (uintptr_t)_irq168, [201] = (uintptr_t)_irq169,
[202] = (uintptr_t)_irq170, [203] = (uintptr_t)_irq171,
[204] = (uintptr_t)_irq172, [205] = (uintptr_t)_irq173,
[206] = (uintptr_t)_irq174, [207] = (uintptr_t)_irq175,
[208] = (uintptr_t)_irq176, [209] = (uintptr_t)_irq177,
[210] = (uintptr_t)_irq178, [211] = (uintptr_t)_irq179,
[212] = (uintptr_t)_irq180, [213] = (uintptr_t)_irq181,
[214] = (uintptr_t)_irq182, [215] = (uintptr_t)_irq183,
[216] = (uintptr_t)_irq184, [217] = (uintptr_t)_irq185,
[218] = (uintptr_t)_irq186, [219] = (uintptr_t)_irq187,
[220] = (uintptr_t)_irq188, [221] = (uintptr_t)_irq189,
[222] = (uintptr_t)_irq190, [223] = (uintptr_t)_irq191,
[224] = (uintptr_t)_irq192, [225] = (uintptr_t)_irq193,
[226] = (uintptr_t)_irq194, [227] = (uintptr_t)_irq195,
[228] = (uintptr_t)_irq196, [229] = (uintptr_t)_irq197,
[230] = (uintptr_t)_irq198, [231] = (uintptr_t)_irq199,
[232] = (uintptr_t)_irq200, [233] = (uintptr_t)_irq201,
[234] = (uintptr_t)_irq202, [235] = (uintptr_t)_irq203,
[236] = (uintptr_t)_irq204, [237] = (uintptr_t)_irq205,
[238] = (uintptr_t)_irq206, [239] = (uintptr_t)_irq207,
[240] = (uintptr_t)_irq208, [241] = (uintptr_t)_irq209,
[242] = (uintptr_t)_irq210, [243] = (uintptr_t)_irq211,
[244] = (uintptr_t)_irq212, [245] = (uintptr_t)_irq213,
[246] = (uintptr_t)_irq214, [247] = (uintptr_t)_irq215,
[248] = (uintptr_t)_irq216, [249] = (uintptr_t)_irq217,
[250] = (uintptr_t)_irq218, [251] = (uintptr_t)_irq219,
[252] = (uintptr_t)_irq220, [253] = (uintptr_t)_irq221,
[254] = (uintptr_t)_irq222, [255] = (uintptr_t)_irq223,
};

View File

@@ -37,13 +37,6 @@ SECTIONS {
*(.rodata*)
}
.kexts ALIGN(4K) : AT(ADDR(.kexts) - KERNEL_VMA)
{
__kexts_start = .;
*(.kextinfo)
__kexts_end = .;
}
.data.percpu ALIGN(4K) : AT(ADDR(.data.percpu) - KERNEL_VMA)
{
__percpu_start = .;

View File

@@ -1,333 +0,0 @@
#include <socks/device.h>
#include <socks/block.h>
#include <socks/util.h>
#include <socks/printk.h>
#include <socks/libc/stdio.h>
static DECLARE_BITMAP(block_device_ids, BLOCK_DEVICE_MAX);
static spin_lock_t block_device_ids_lock = SPIN_LOCK_INIT;
struct block_device *block_device_create(void)
{
struct device *dev = device_alloc();
if (!dev) {
return NULL;
}
dev->dev_type = DEV_TYPE_BLOCK;
return BLOCK_DEVICE(dev);
}
struct block_device *block_device_from_generic(struct device *dev)
{
dev->dev_type = DEV_TYPE_BLOCK;
return BLOCK_DEVICE(dev);
}
static kern_status_t do_read_blocks(struct block_device *blockdev, void *buf, sectors_t offset, size_t nr_sectors, size_t *sectors_read, socks_flags_t flags)
{
struct device *dev = block_device_base(blockdev);
struct iovec vec = { .io_buf = buf, .io_len = nr_sectors * blockdev->b_sector_size };
kern_status_t status = blockdev->b_ops->read_blocks(dev, offset, &nr_sectors, &vec, 1, flags);
*sectors_read = nr_sectors;
return status;
}
extern kern_status_t get_cached_sector(struct block_device *blockdev, sectors_t sector, socks_flags_t flags, void **bufp)
{
if (blockdev->b_flags & BLOCK_DEVICE_NO_BCACHE) {
return KERN_UNSUPPORTED;
}
kern_status_t status = KERN_OK;
struct bcache_sector cache_buf;
status = bcache_get(&blockdev->b_cache, sector, true, &cache_buf);
if (status != KERN_OK) {
return status;
}
if (!cache_buf.sect_present) {
size_t nr_read = 0;
/* TODO read all missing blocks in one go */
status = do_read_blocks(blockdev, cache_buf.sect_buf, sector, 1, &nr_read, flags);
if (status != KERN_OK) {
return status;
}
bcache_mark_present(&cache_buf);
}
*bufp = cache_buf.sect_buf;
return KERN_OK;
}
kern_status_t block_device_read_blocks(struct device *dev, void *buf, sectors_t offset, size_t nr_sectors, size_t *sectors_read, socks_flags_t flags)
{
struct block_device *blockdev = BLOCK_DEVICE(dev);
if (!blockdev) {
return KERN_INVALID_ARGUMENT;
}
if (!blockdev->b_ops || !blockdev->b_ops->read_blocks) {
return KERN_UNSUPPORTED;
}
if (offset >= blockdev->b_capacity) {
*sectors_read = 0;
return KERN_OK;
}
if (offset + nr_sectors >= blockdev->b_capacity) {
nr_sectors = blockdev->b_capacity - offset;
}
if (!nr_sectors) {
*sectors_read = 0;
return KERN_OK;
}
if (blockdev->b_flags & BLOCK_DEVICE_NO_BCACHE) {
return do_read_blocks(blockdev, buf, offset, nr_sectors, sectors_read, flags);
}
size_t nr_read = 0;
kern_status_t status = KERN_OK;
for (sectors_t i = 0; i < nr_sectors; i++) {
sectors_t sect = offset + i;
void *sect_cache_buf;
status = get_cached_sector(blockdev, sect, flags, &sect_cache_buf);
if (status != KERN_OK) {
*sectors_read = nr_read;
return status;
}
char *sect_dest_buf = (char *)buf + (i * blockdev->b_sector_size);
memcpy(sect_dest_buf, sect_cache_buf, blockdev->b_sector_size);
nr_read++;
}
*sectors_read = nr_read;
return KERN_OK;
}
kern_status_t block_device_read(struct device *dev, void *buf, size_t offset, size_t size, size_t *bytes_read, socks_flags_t flags)
{
struct block_device *blockdev = BLOCK_DEVICE(dev);
if (!blockdev) {
return KERN_INVALID_ARGUMENT;
}
kern_status_t status = KERN_OK;
if (blockdev->b_flags & BLOCK_DEVICE_NO_BCACHE) {
/* no bcache for this device, so the client has to read data at sector granularity. */
sectors_t sect_offset = offset / blockdev->b_sector_size;
size_t nr_sectors = size / blockdev->b_sector_size;
if ((sect_offset * blockdev->b_sector_size != offset) || (nr_sectors * blockdev->b_sector_size != size)) {
/* args are not sector-aligned */
return KERN_INVALID_ARGUMENT;
}
size_t sectors_read = 0;
status = block_device_read_blocks(dev, buf, sect_offset, nr_sectors, &sectors_read, flags);
*bytes_read = sectors_read * blockdev->b_sector_size;
return status;
}
char *dest = buf;
sectors_t first_sect = offset / blockdev->b_sector_size;
sectors_t last_sect = (offset + size) / blockdev->b_sector_size;
size_t nr_read = 0;
if (first_sect * blockdev->b_sector_size < offset) {
/* non-sector sized chunk at the start of the buffer. */
void *sector_cachebuf;
status = get_cached_sector(blockdev, first_sect, flags, &sector_cachebuf);
if (status != KERN_OK) {
*bytes_read = nr_read;
return status;
}
unsigned int in_sect_offset = (offset - (first_sect * blockdev->b_sector_size));
unsigned int in_sect_size = MIN(blockdev->b_sector_size - in_sect_offset, size);
char *p = (char *)sector_cachebuf + in_sect_offset;
memcpy(dest, p, in_sect_size);
dest += in_sect_size;
nr_read += in_sect_size;
first_sect++;
}
for (sectors_t i = first_sect; i < last_sect; i++) {
void *sector_cachebuf;
status = get_cached_sector(blockdev, i, flags, &sector_cachebuf);
if (status != KERN_OK) {
*bytes_read = nr_read;
return status;
}
char *p = sector_cachebuf;
memcpy(dest, p, blockdev->b_sector_size);
dest += blockdev->b_sector_size;
nr_read += blockdev->b_sector_size;
}
if (last_sect * blockdev->b_sector_size < offset + size && nr_read < size) {
/* non-sector sized chunk at the end of the buffer. */
void *sector_cachebuf;
status = get_cached_sector(blockdev, last_sect, flags, &sector_cachebuf);
if (status != KERN_OK) {
*bytes_read = nr_read;
return status;
}
unsigned int in_sect_size = (offset + size) - (last_sect * blockdev->b_sector_size);
char *p = sector_cachebuf;
memcpy(dest, p, in_sect_size);
nr_read += in_sect_size;
}
*bytes_read = nr_read;
return KERN_OK;
}
static kern_status_t generate_name(struct block_device *dev, char out[DEV_NAME_MAX])
{
snprintf(out, DEV_NAME_MAX, "disk%u", dev->b_id);
return KERN_OK;
}
kern_status_t block_device_register(struct device *dev)
{
struct block_device *blockdev = &dev->blk;
if (!(blockdev->b_flags & BLOCK_DEVICE_NO_BCACHE)) {
kern_status_t status = bcache_init(&blockdev->b_cache, blockdev->b_sector_size);
if (status != KERN_OK) {
return status;
}
}
unsigned long flags;
spin_lock_irqsave(&block_device_ids_lock, &flags);
unsigned int id = bitmap_lowest_clear(block_device_ids, BLOCK_DEVICE_MAX);
bitmap_set(block_device_ids, id);
spin_unlock_irqrestore(&block_device_ids_lock, flags);
blockdev->b_id = id;
char name[DEV_NAME_MAX];
generate_name(blockdev, name);
char path[OBJECT_PATH_MAX];
snprintf(path, sizeof path, "/dev/block/%s", name);
char size_string[32];
data_size_to_string(blockdev->b_sector_size * blockdev->b_capacity, size_string, sizeof size_string);
printk("dev: found %s %s block device '%s'", size_string, dev->dev_owner->drv_name, dev->dev_model_name);
return object_namespace_create_link(global_namespace(), path, &dev->dev_base);
}
struct device_type_ops block_type_ops = {
.register_device = block_device_register,
.read = block_device_read,
};
static BTREE_DEFINE_SIMPLE_GET(struct vm_page, sectors_t, p_bnode, p_blockid, get_block_page)
static BTREE_DEFINE_SIMPLE_INSERT(struct vm_page, p_bnode, p_blockid, put_block_page)
struct bcache *bcache_create(unsigned int block_size)
{
struct bcache *out = kmalloc(sizeof *out, VM_NORMAL);
if (!out) {
return NULL;
}
if (bcache_init(out, block_size) != KERN_OK) {
kfree(out);
return NULL;
}
return out;
}
void bcache_destroy(struct bcache *cache)
{
bcache_deinit(cache);
kfree(cache);
}
kern_status_t bcache_init(struct bcache *cache, unsigned int block_size)
{
memset(cache, 0x0, sizeof *cache);
cache->b_sector_size = block_size;
cache->b_sectors_per_page = VM_PAGE_SIZE / block_size;
return KERN_OK;
}
void bcache_deinit(struct bcache *cache)
{
struct btree_node *first_node = btree_first(&cache->b_pagetree);
if (!first_node) {
return;
}
struct vm_page *cur = BTREE_CONTAINER(struct vm_page, p_bnode, first_node);
while (cur) {
struct btree_node *next_node = btree_next(&cur->p_bnode);
struct vm_page *next = BTREE_CONTAINER(struct vm_page, p_bnode, next_node);
cur->p_flags &= ~(VM_PAGE_CACHE);
btree_delete(&cache->b_pagetree, &cur->p_bnode);
vm_page_free(cur);
cur = next;
}
}
kern_status_t bcache_get(struct bcache *cache, sectors_t at, bool create, struct bcache_sector *out)
{
unsigned int page_index = at % cache->b_sectors_per_page;
at /= cache->b_sectors_per_page;
struct vm_page *page = get_block_page(&cache->b_pagetree, at);
if (!page) {
if (!create) {
return KERN_NO_ENTRY;
}
page = vm_page_alloc(VM_PAGE_MIN_ORDER, VM_NORMAL);
if (!page) {
return KERN_NO_MEMORY;
}
page->p_flags |= VM_PAGE_CACHE;
bitmap_zero(page->p_blockbits, VM_MAX_SECTORS_PER_PAGE);
page->p_blockid = at;
}
out->sect_page = page;
out->sect_index = page_index;
out->sect_buf = vm_page_get_vaddr(page);
out->sect_present = bitmap_check(page->p_blockbits, page_index);
return KERN_OK;
}
void bcache_mark_present(struct bcache_sector *sect)
{
bitmap_set(sect->sect_page->p_blockbits, sect->sect_index);
}

View File

@@ -1,71 +0,0 @@
#include <socks/device.h>
#include <socks/libc/stdio.h>
static struct queue all_buses;
static spin_lock_t all_buses_lock;
struct bus_device *bus_device_create(void)
{
struct device *dev = device_alloc();
if (!dev) {
return NULL;
}
dev->dev_type = DEV_TYPE_BUS;
return BUS_DEVICE(dev);
}
kern_status_t scan_all_buses(void)
{
kern_status_t status = KERN_OK;
/* keep interrupts enabled while scanning for devices */
//spin_lock(&all_buses_lock);
queue_foreach(struct bus_device, bus, &all_buses, b_buslist) {
if (bus->b_ops && bus->b_ops->scan) {
status = bus->b_ops->scan(bus_device_base(bus));
}
if (status != KERN_OK) {
break;
}
}
//spin_unlock(&all_buses_lock);
return status;
}
struct bus_device *bus_device_from_generic(struct device *dev)
{
dev->dev_type = DEV_TYPE_BUS;
return BUS_DEVICE(dev);
}
static kern_status_t bus_device_register(struct device *dev)
{
struct bus_device *bus = &dev->bus;
unsigned long flags;
spin_lock_irqsave(&all_buses_lock, &flags);
queue_push_back(&all_buses, &bus->b_buslist);
spin_unlock_irqrestore(&all_buses_lock, flags);
char path[OBJECT_PATH_MAX];
snprintf(path, sizeof path, "/dev/bus/%s", dev->dev_name);
kern_status_t status = object_namespace_create_link(global_namespace(), path, &dev->dev_base);
if (status != KERN_OK) {
spin_lock_irqsave(&all_buses_lock, &flags);
queue_delete(&all_buses, &bus->b_buslist);
spin_unlock_irqrestore(&all_buses_lock, flags);
return status;
}
return status;
}
struct device_type_ops bus_type_ops = {
.register_device = bus_device_register,
};

View File

@@ -1,48 +0,0 @@
#include <socks/device.h>
struct char_device *char_device_create(void)
{
struct device *dev = device_alloc();
if (!dev) {
return NULL;
}
dev->dev_type = DEV_TYPE_CHAR;
return CHAR_DEVICE(dev);
}
struct char_device *char_device_from_generic(struct device *dev)
{
dev->dev_type = DEV_TYPE_CHAR;
return CHAR_DEVICE(dev);
}
static kern_status_t char_device_read(struct device *dev, void *buf, size_t offset, size_t size, size_t *bytes_read, socks_flags_t flags)
{
kern_status_t status = KERN_UNSUPPORTED;
struct char_device *cdev = CHAR_DEVICE(dev);
if (cdev->c_ops && cdev->c_ops->read) {
status = cdev->c_ops->read(dev, buf, offset, size, bytes_read, flags);
}
return status;
}
static kern_status_t char_device_write(struct device *dev, const void *buf, size_t offset, size_t size, size_t *bytes_read, socks_flags_t flags)
{
kern_status_t status = KERN_UNSUPPORTED;
struct char_device *cdev = CHAR_DEVICE(dev);
if (cdev->c_ops && cdev->c_ops->write) {
status = cdev->c_ops->write(dev, buf, offset, size, bytes_read, flags);
}
return status;
}
struct device_type_ops char_type_ops = {
.read = char_device_read,
.write = char_device_write,
};

View File

@@ -1,297 +0,0 @@
#include <socks/status.h>
#include <socks/object.h>
#include <socks/device.h>
#include <socks/printk.h>
#include <socks/bitmap.h>
#include <socks/libc/stdio.h>
#define DEVICE_CAST(p) OBJECT_C_CAST(struct device, dev_base, &device_type, p)
static struct object *dev_folder = NULL;
static struct device *__root_device = NULL;
static struct device *__misc_device = NULL;
static kern_status_t device_object_destroy(struct object *);
static kern_status_t device_object_read(struct object *obj, void *, size_t, size_t *, socks_flags_t);
static kern_status_t device_object_write(struct object *obj, const void *, size_t, size_t *, socks_flags_t);
static kern_status_t device_object_query_name(struct object *, char out[OBJECT_NAME_MAX]);
static kern_status_t device_object_get_child_at(struct object *, size_t, struct object **);
static kern_status_t device_object_get_child_named(struct object *, const char *, struct object **);
extern kern_status_t init_driver_tree(void);
extern struct device_type_ops char_type_ops;
extern struct device_type_ops block_type_ops;
extern struct device_type_ops input_type_ops;
extern struct device_type_ops framebuffer_type_ops;
extern struct device_type_ops bus_type_ops;
static struct device_type_ops *type_ops[] = {
[DEV_TYPE_UNKNOWN] = NULL,
[DEV_TYPE_BLOCK] = &block_type_ops,
[DEV_TYPE_CHAR] = &char_type_ops,
[DEV_TYPE_NET] = NULL,
[DEV_TYPE_INPUT] = &input_type_ops,
[DEV_TYPE_BUS] = &bus_type_ops,
[DEV_TYPE_FRAMEBUFFER] = &framebuffer_type_ops,
};
static struct object_type device_type = {
.ob_name = "device",
.ob_size = sizeof(struct device),
.ob_ops = {
.read = device_object_read,
.write = device_object_write,
.destroy = device_object_destroy,
.query_name = device_object_query_name,
.get_at = device_object_get_child_at,
.get_named = device_object_get_child_named,
}
};
static kern_status_t set_root_device(struct device *dev)
{
if (__root_device) {
set_remove_object(dev_folder, &__root_device->dev_base);
object_deref(&__root_device->dev_base);
}
object_ref(&dev->dev_base);
set_add_object(dev_folder, &dev->dev_base);
__root_device = dev;
return KERN_OK;
}
kern_status_t device_init(void)
{
object_type_register(&device_type);
dev_folder = set_create("dev");
object_publish(global_namespace(), "/", dev_folder);
kern_status_t status = init_driver_tree();
if (status != KERN_OK) {
return status;
}
struct bus_device *system_dev = bus_device_create();
struct device *system_dev_base = bus_device_base(system_dev);
snprintf(system_dev_base->dev_name, sizeof system_dev_base->dev_name, "system");
set_root_device(bus_device_base(system_dev));
struct bus_device *misc_dev = bus_device_create();
struct device *misc_dev_base = bus_device_base(misc_dev);
snprintf(misc_dev_base->dev_name, sizeof misc_dev_base->dev_name, "misc");
__misc_device = misc_dev_base;
struct driver *system = system_driver();
device_register(__root_device, system, NULL);
device_register(__misc_device, system, __root_device);
return KERN_OK;
}
struct device *root_device(void)
{
return __root_device;
}
struct device *misc_device(void)
{
return __misc_device;
}
struct device *device_alloc(void)
{
struct object *dev_object = object_create(&device_type);
if (!dev_object) {
return NULL;
}
return DEVICE_CAST(dev_object);
}
struct device *generic_device_create(void)
{
struct device *dev = device_alloc();
if (!dev) {
return NULL;
}
dev->dev_type = DEV_TYPE_UNKNOWN;
return dev;
}
kern_status_t device_read(struct device *dev, void *buf, size_t offset, size_t size, size_t *bytes_read, socks_flags_t flags)
{
kern_status_t status = KERN_UNSUPPORTED;
if (type_ops[dev->dev_type] && type_ops[dev->dev_type]->read) {
status = type_ops[dev->dev_type]->read(dev, buf, offset, size, bytes_read, flags);
}
return status;
}
kern_status_t device_write(struct device *dev, const void *buf, size_t offset, size_t size, size_t *bytes_written, socks_flags_t flags)
{
kern_status_t status = KERN_UNSUPPORTED;
if (type_ops[dev->dev_type] && type_ops[dev->dev_type]->write) {
status = type_ops[dev->dev_type]->write(dev, buf, offset, size, bytes_written, flags);
}
return status;
}
struct device *cast_to_device(struct object *obj)
{
return DEVICE_CAST(obj);
}
static kern_status_t device_object_read(struct object *obj, void *p, size_t offset, size_t *count, socks_flags_t flags)
{
struct device *dev = DEVICE_CAST(obj);
return device_read(dev, p, *count, offset, count, flags);
}
static kern_status_t device_object_write(struct object *obj, const void *p, size_t offset, size_t *count, socks_flags_t flags)
{
struct device *dev = DEVICE_CAST(obj);
return device_write(dev, p, *count, offset, count, flags);
}
static kern_status_t device_object_destroy(struct object *obj)
{
return KERN_OK;
}
static kern_status_t device_object_query_name(struct object *obj, char out[OBJECT_NAME_MAX])
{
struct device *dev = DEVICE_CAST(obj);
if (!dev) {
return KERN_INVALID_ARGUMENT;
}
strncpy(out, dev->dev_name, OBJECT_NAME_MAX - 1);
out[OBJECT_NAME_MAX - 1] = 0;
return KERN_OK;
}
static kern_status_t device_object_get_child_at(struct object *obj, size_t at, struct object **out)
{
struct device *dev = DEVICE_CAST(obj);
size_t i = 0;
queue_foreach(struct device, child, &dev->dev_children, dev_childent) {
if (i == at) {
*out = object_ref(&child->dev_base);
return KERN_OK;
}
i++;
}
return KERN_NO_ENTRY;
}
static kern_status_t device_object_get_child_named(struct object *obj, const char *name, struct object **out)
{
struct device *dev = DEVICE_CAST(obj);
if (!dev) {
return KERN_INVALID_ARGUMENT;
}
queue_foreach(struct device, child, &dev->dev_children, dev_childent) {
if (!strcmp(child->dev_name, name)) {
*out = object_ref(&child->dev_base);
return KERN_OK;
}
}
return KERN_NO_ENTRY;
}
static kern_status_t add_device_to_parent(struct device *dev, struct device *parent)
{
kern_status_t status = KERN_OK;
queue_foreach (struct device, child, &parent->dev_children, dev_childent) {
if (!strcmp(dev->dev_name, child->dev_name)) {
status = KERN_NAME_EXISTS;
break;
}
}
if (status != KERN_OK) {
return status;
}
queue_push_back(&parent->dev_children, &dev->dev_childent);
return KERN_OK;
}
kern_status_t device_register(struct device *dev, struct driver *owner, struct device *parent)
{
unsigned long flags;
device_lock_irqsave(dev, &flags);
if (dev->dev_owner) {
struct driver *prev_owner = dev->dev_owner;
/* migrate device to new driver */
driver_lock(prev_owner);
driver_remove_device(prev_owner, dev);
driver_free_minor(prev_owner, dev->dev_minor);
dev->dev_minor = DEV_MINOR_INVALID;
dev->dev_owner = NULL;
driver_unlock(prev_owner);
}
driver_lock(owner);
if (owner->drv_major == DEV_MAJOR_INVALID) {
driver_unlock(owner);
device_unlock_irqrestore(dev, flags);
/* TODO better error message for lack of resources? */
return KERN_INVALID_ARGUMENT;
}
unsigned int minor = driver_alloc_minor(owner);
if (minor == DEV_MINOR_INVALID) {
driver_unlock(owner);
device_unlock_irqrestore(dev, flags);
/* TODO better error message for lack of resources? */
return KERN_BUSY;
}
kern_status_t status = KERN_OK;
if (parent) {
status = add_device_to_parent(dev, parent);
}
if (status != KERN_OK) {
driver_unlock(owner);
device_unlock_irqrestore(dev, flags);
return status;
}
dev->dev_minor = minor;
dev->dev_owner = owner;
driver_add_device(owner, dev);
if (type_ops[dev->dev_type] && type_ops[dev->dev_type]->register_device) {
status = type_ops[dev->dev_type]->register_device(dev);
}
/* TODO remove device if registration failed */
driver_unlock(owner);
device_unlock_irqrestore(dev, flags);
return status;
}

View File

@@ -1,176 +0,0 @@
#include <socks/device.h>
#include <socks/printk.h>
#include <socks/bitmap.h>
#include <socks/btree.h>
#include <socks/kext.h>
#include <socks/vm.h>
static struct vm_cache driver_cache = {
.c_name = "driver",
.c_obj_size = sizeof(struct driver),
};
static DECLARE_BITMAP(major_numbers, DEV_MAJOR_MAX);
static struct btree drivers;
static spin_lock_t drivers_lock = SPIN_LOCK_INIT;
static struct driver *__system_driver;
BTREE_DEFINE_SIMPLE_INSERT(struct driver, drv_ent, drv_major, put_driver)
BTREE_DEFINE_SIMPLE_GET(struct driver, unsigned int, drv_ent, drv_major, get_driver_by_major)
BTREE_DEFINE_SIMPLE_INSERT(struct device, dev_driverent, dev_minor, put_device)
BTREE_DEFINE_SIMPLE_GET(struct device, unsigned int, dev_driverent, dev_minor, get_device_by_minor)
kern_status_t init_driver_tree(void)
{
vm_cache_init(&driver_cache);
bitmap_set(major_numbers, 0);
__system_driver = driver_create(kernel_kext(), "system");
driver_register(__system_driver);
return KERN_OK;
}
struct driver *driver_create(struct kext *self, const char *name)
{
if (!self || !name) {
return NULL;
}
struct driver *driver = vm_cache_alloc(&driver_cache, 0);
if (!driver) {
return NULL;
}
if (driver_init(driver, self, name) != KERN_OK) {
vm_cache_free(&driver_cache, driver);
return NULL;
}
return driver;
}
kern_status_t driver_destroy(struct driver *driver)
{
if (btree_first(&driver->drv_children)) {
return KERN_BUSY;
}
kern_status_t status = driver_deinit(driver);
if (status != KERN_OK) {
return status;
}
vm_cache_free(&driver_cache, driver);
return KERN_OK;
}
kern_status_t driver_init(struct driver *driver, struct kext *self, const char *name)
{
memset(driver, 0x0, sizeof *driver);
driver->drv_owner = self;
strncpy(driver->drv_name, name, sizeof driver->drv_name - 1);
driver->drv_name[sizeof driver->drv_name - 1] = 0;
bitmap_set(driver->drv_minors, DEV_MINOR_INVALID);
return KERN_OK;
}
kern_status_t driver_deinit(struct driver *driver)
{
/* TODO */
return KERN_UNIMPLEMENTED;
}
kern_status_t driver_register(struct driver *driver)
{
if (driver->drv_major != DEV_MAJOR_INVALID) {
return KERN_INVALID_ARGUMENT;
}
unsigned long flags;
spin_lock_irqsave(&drivers_lock, &flags);
struct btree_node *cur = btree_first(&drivers);
while (cur) {
struct driver *cur_driver = BTREE_CONTAINER(struct driver, drv_ent, cur);
if (driver->drv_owner == cur_driver->drv_owner && !strcmp(driver->drv_name, cur_driver->drv_name)) {
spin_unlock_irqrestore(&drivers_lock, flags);
return KERN_NAME_EXISTS;
}
cur = btree_next(cur);
}
unsigned long major = bitmap_lowest_clear(major_numbers, DEV_MAJOR_MAX);
bitmap_set(major_numbers, major);
driver->drv_major = major;
put_driver(&drivers, driver);
spin_unlock_irqrestore(&drivers_lock, flags);
return KERN_OK;
}
kern_status_t driver_unregister(struct driver *driver)
{
if (driver->drv_major == DEV_MAJOR_INVALID) {
return KERN_INVALID_ARGUMENT;
}
unsigned long flags;
spin_lock_irqsave(&drivers_lock, &flags);
btree_delete(&drivers, &driver->drv_ent);
bitmap_clear(major_numbers, driver->drv_major);
driver->drv_major = DEV_MAJOR_INVALID;
spin_unlock_irqrestore(&drivers_lock, flags);
return KERN_OK;
}
unsigned int driver_alloc_minor(struct driver *driver)
{
unsigned int minor = bitmap_lowest_clear(driver->drv_minors, DEV_MINOR_MAX);
if (minor == BITMAP_NPOS) {
return DEV_MINOR_INVALID;
}
bitmap_set(driver->drv_minors, minor);
return minor;
}
void driver_free_minor(struct driver *driver, unsigned int minor)
{
bitmap_clear(driver->drv_minors, minor);
}
struct driver *system_driver(void)
{
return __system_driver;
}
struct device *driver_get_device(struct driver *driver, unsigned int minor)
{
return get_device_by_minor(&driver->drv_children, minor);
}
kern_status_t driver_add_device(struct driver *driver, struct device *dev)
{
if (get_device_by_minor(&driver->drv_children, dev->dev_minor)) {
return KERN_NAME_EXISTS;
}
put_device(&driver->drv_children, dev);
return KERN_OK;
}
kern_status_t driver_remove_device(struct driver *driver, struct device *dev)
{
btree_delete(&driver->drv_children, &dev->dev_driverent);
return KERN_OK;
}

View File

@@ -1,94 +0,0 @@
#include <socks/device.h>
#include <socks/bitmap.h>
#include <socks/libc/stdio.h>
static DECLARE_BITMAP(fb_device_ids, FRAMEBUFFER_DEVICE_MAX);
static spin_lock_t fb_device_ids_lock = SPIN_LOCK_INIT;
struct framebuffer_device *framebuffer_device_create(void)
{
struct device *dev = device_alloc();
if (!dev) {
return NULL;
}
dev->dev_type = DEV_TYPE_FRAMEBUFFER;
return FRAMEBUFFER_DEVICE(dev);
}
struct framebuffer_device *framebuffer_device_from_generic(struct device *dev)
{
dev->dev_type = DEV_TYPE_FRAMEBUFFER;
return FRAMEBUFFER_DEVICE(dev);
}
static kern_status_t generate_name(struct framebuffer_device *dev, char out[DEV_NAME_MAX])
{
snprintf(out, DEV_NAME_MAX, "fb%u", dev->fb_id);
return KERN_OK;
}
kern_status_t framebuffer_device_register(struct device *dev)
{
unsigned long flags;
spin_lock_irqsave(&fb_device_ids_lock, &flags);
unsigned int id = bitmap_lowest_clear(fb_device_ids, INPUT_DEVICE_MAX);
bitmap_set(fb_device_ids, id);
spin_unlock_irqrestore(&fb_device_ids_lock, flags);
struct framebuffer_device *fbdev = &dev->fb;
fbdev->fb_id = id;
char name[DEV_NAME_MAX];
generate_name(fbdev, name);
char path[OBJECT_PATH_MAX];
snprintf(path, sizeof path, "/dev/video/%s", name);
return object_namespace_create_link(global_namespace(), path, &dev->dev_base);
}
kern_status_t framebuffer_get_fixedinfo(struct device *dev, struct framebuffer_fixedinfo *out)
{
struct framebuffer_device *fbdev = FRAMEBUFFER_DEVICE(dev);
if (!fbdev) {
return KERN_INVALID_ARGUMENT;
}
memcpy(out, &fbdev->fb_fixedinfo, sizeof *out);
return KERN_OK;
}
kern_status_t framebuffer_get_varinfo(struct device *dev, struct framebuffer_varinfo *out)
{
struct framebuffer_device *fbdev = FRAMEBUFFER_DEVICE(dev);
if (!fbdev) {
return KERN_INVALID_ARGUMENT;
}
memcpy(out, &fbdev->fb_varinfo, sizeof *out);
return KERN_OK;
}
kern_status_t framebuffer_set_varinfo(struct device *dev, const struct framebuffer_varinfo *varinfo)
{
struct framebuffer_device *fbdev = FRAMEBUFFER_DEVICE(dev);
if (!fbdev) {
return KERN_INVALID_ARGUMENT;
}
if (!fbdev->fb_ops || !fbdev->fb_ops->set_varinfo) {
return KERN_UNSUPPORTED;
}
kern_status_t status = fbdev->fb_ops->set_varinfo(dev, varinfo);
if (status == KERN_OK) {
memcpy(&fbdev->fb_varinfo, varinfo, sizeof *varinfo);
}
return status;
}
struct device_type_ops framebuffer_type_ops = {
.register_device = framebuffer_device_register,
};

View File

@@ -1,134 +0,0 @@
#include <socks/device.h>
#include <socks/input.h>
#include <socks/bitmap.h>
#include <socks/libc/stdio.h>
static DECLARE_BITMAP(input_device_ids, INPUT_DEVICE_MAX);
static spin_lock_t input_device_ids_lock = SPIN_LOCK_INIT;
struct input_device *input_device_create(void)
{
struct device *dev = device_alloc();
if (!dev) {
return NULL;
}
dev->dev_type = DEV_TYPE_INPUT;
struct input_device *input_dev = INPUT_DEVICE(dev);
if (ringbuffer_init(&input_dev->i_events, INPUT_DEVICE_EVENT_QUEUE_SIZE * sizeof(struct input_event)) != KERN_OK) {
/* TODO destroy device */
return NULL;
}
return INPUT_DEVICE(dev);
}
struct input_device *input_device_from_generic(struct device *dev)
{
dev->dev_type = DEV_TYPE_INPUT;
return INPUT_DEVICE(dev);
}
kern_status_t input_device_report_event(struct input_device *dev, const struct input_event *ev, bool noblock)
{
struct ringbuffer *event_queue = &dev->i_events;
socks_flags_t flags = S_NORMAL;
if (noblock) {
flags = S_NOBLOCK;
}
struct input_event new_ev = *ev;
enum input_event_hook_flags hook_flags = 0;
queue_foreach (struct input_event_hook, hook, &dev->i_hooks, hook_head) {
if (hook->hook_callback) {
hook->hook_callback(input_device_base(dev), &new_ev, &hook_flags, hook->hook_arg);
}
if (hook_flags & INPUT_HOOK_SQUASH_EVENT) {
break;
}
}
if (hook_flags & INPUT_HOOK_SQUASH_EVENT) {
return KERN_OK;
}
size_t r = ringbuffer_write(event_queue, sizeof new_ev, &new_ev, flags);
return r == sizeof *ev ? KERN_OK : KERN_WOULD_BLOCK;
}
kern_status_t input_device_read(struct device *dev, void *buf, size_t offset,
size_t size, size_t *bytes_read, socks_flags_t flags)
{
if (dev->dev_type != DEV_TYPE_INPUT || (size % sizeof (struct input_event)) != 0) {
return KERN_INVALID_ARGUMENT;
}
struct input_device *input_dev = INPUT_DEVICE(dev);
struct ringbuffer *event_queue = &input_dev->i_events;
size_t r = ringbuffer_read(event_queue, size, buf, flags);
if (bytes_read) {
*bytes_read = r;
}
return KERN_OK;
}
kern_status_t input_device_add_hook(struct device *dev, struct input_event_hook *hook)
{
struct input_device *inputdev = INPUT_DEVICE(dev);
if (!inputdev) {
return KERN_INVALID_ARGUMENT;
}
queue_push_back(&inputdev->i_hooks, &hook->hook_head);
return KERN_OK;
}
kern_status_t input_device_remove_hook(struct device *dev, struct input_event_hook *hook)
{
struct input_device *inputdev = INPUT_DEVICE(dev);
if (!inputdev) {
return KERN_INVALID_ARGUMENT;
}
queue_delete(&inputdev->i_hooks, &hook->hook_head);
return KERN_OK;
}
static kern_status_t generate_name(struct input_device *dev, char out[DEV_NAME_MAX])
{
snprintf(out, DEV_NAME_MAX, "input%u", dev->i_id);
return KERN_OK;
}
kern_status_t input_device_register(struct device *dev)
{
unsigned long flags;
spin_lock_irqsave(&input_device_ids_lock, &flags);
unsigned int id = bitmap_lowest_clear(input_device_ids, INPUT_DEVICE_MAX);
bitmap_set(input_device_ids, id);
spin_unlock_irqrestore(&input_device_ids_lock, flags);
struct input_device *inputdev = &dev->input;
inputdev->i_id = id;
char name[DEV_NAME_MAX];
generate_name(inputdev, name);
char path[OBJECT_PATH_MAX];
snprintf(path, sizeof path, "/dev/input/%s", name);
return object_namespace_create_link(global_namespace(), path, &dev->dev_base);
}
struct device_type_ops input_type_ops = {
.register_device = input_device_register,
.read = input_device_read,
};

View File

@@ -1,19 +0,0 @@
#include <socks/device.h>
struct net_device *net_device_create(void)
{
struct device *dev = device_alloc();
if (!dev) {
return NULL;
}
dev->dev_type = DEV_TYPE_NET;
return NET_DEVICE(dev);
}
struct net_device *net_device_from_generic(struct device *dev)
{
dev->dev_type = DEV_TYPE_NET;
return NET_DEVICE(dev);
}

View File

@@ -1,71 +0,0 @@
#ifndef SOCKS_FS_H_
#define SOCKS_FS_H_
#include <socks/device.h>
#include <socks/queue.h>
#define SUPERBLOCK_ID_MAX 32
struct kext;
struct inode;
struct dentry;
struct super_block;
enum filesystem_flags {
FS_REQUIRES_DEV = 0x01u,
};
struct super_block_ops {
kern_status_t(*write_inode)(struct inode *);
kern_status_t(*alloc_inode)(struct super_block *, struct inode **);
void(*destroy_inode)(struct inode *);
void(*destroy_super)(struct super_block *);
};
struct super_block {
struct device *s_dev;
unsigned long s_blocksize;
unsigned long s_flags;
struct dentry *s_root;
struct super_block_ops *s_ops;
char s_id[SUPERBLOCK_ID_MAX];
};
struct inode_ops {
kern_status_t(*create)(struct inode *, struct dentry *, umode_t);
kern_status_t(*mkdir)(struct inode *, struct dentry *, umode_t);
kern_status_t(*lookup)(struct inode *, struct dentry *, unsigned int);
};
struct dname {
uint64_t n_hash;
const char *n_str;
};
struct inode {
struct super_block *i_sb;
unsigned long i_ino;
unsigned long i_mode;
unsigned long i_uid;
unsigned long i_gid;
unsigned long i_nlink;
struct inode_ops *i_ops;
};
struct dentry {
struct dname d_name;
struct dentry *d_parent;
struct inode *d_inode;
};
struct filesystem_driver {
const char *fs_name;
struct kext *fs_owner;
struct queue_entry fs_head;
enum filesystem_flags fs_flags;
struct dentry *(*mount)(struct filesystem_driver *, struct device *, int flags);
};
#endif

View File

@@ -1,19 +1,19 @@
#include <stdint.h>
#include <socks/init.h>
#include <socks/arg.h>
#include <socks/clock.h>
#include <socks/input.h>
#include <socks/panic.h>
#include <socks/test.h>
#include <socks/printk.h>
#include <socks/cpu.h>
#include <socks/device.h>
#include <socks/tty.h>
#include <socks/init.h>
#include <socks/input.h>
#include <socks/kext.h>
#include <socks/object.h>
#include <socks/sched.h>
#include <socks/libc/stdio.h>
#include <socks/machine/init.h>
#include <socks/cpu.h>
#include <socks/object.h>
#include <socks/panic.h>
#include <socks/printk.h>
#include <socks/sched.h>
#include <socks/test.h>
#include <socks/tty.h>
#include <stdint.h>
#ifdef KEXT_NET_DOORSTUCK_SOCKS_FBCON
#include <socks/fbcon.h>
@@ -51,7 +51,8 @@ static void putchar(char c)
{
unsigned long flags;
struct queue *consoles = get_consoles(&flags);
queue_foreach(struct console, con, consoles, c_list) {
queue_foreach(struct console, con, consoles, c_list)
{
console_write(con, &c, 1);
}
@@ -62,98 +63,9 @@ void kernel_init(uintptr_t arg)
{
ml_init(arg);
kern_status_t status;
status = scan_internal_kexts();
if (status != KERN_OK) {
panic("scan_internal_kexts() failed with code %s", kern_status_string(status));
}
status = bring_internal_kexts_online();
if (status != KERN_OK) {
panic("bring_internal_kexts_online() failed with code %s", kern_status_string(status));
}
scan_all_buses();
printk("kernel_init() running on processor %u", this_cpu());
#ifdef KEXT_NET_DOORSTUCK_SOCKS_FBCON
struct object *fb;
status = object_get("/dev/video/fb0", &fb);
if (status == KERN_OK) {
#if 0
struct framebuffer_varinfo fb_mode;
struct device *fbdev = cast_to_device(fb);
framebuffer_get_varinfo(fbdev, &fb_mode);
fb_mode.fb_xres = 1024;
fb_mode.fb_yres = 768;
fb_mode.fb_bpp = 24;
fb_mode.fb_flags = FB_MODE_RGB;
framebuffer_set_varinfo(fbdev, &fb_mode);
#endif
start_console_on_framebuffer(cast_to_device(fb));
}
#endif
struct object *tty0;
status = object_get("/dev/tty/tty0", &tty0);
if (status == KERN_OK) {
tty_set_foreground(cast_to_device(tty0));
}
const char *console_tty_name = arg_value("kernel.console");
if (!console_tty_name) {
console_tty_name = "tty0";
}
char console_tty_path[128];
snprintf(console_tty_path, sizeof console_tty_path, "/dev/tty/%s", console_tty_name);
struct object *console_tty = NULL;
status = object_get(console_tty_path, &console_tty);
if (status == KERN_OK) {
register_tty_console();
struct device *console_tty_device = cast_to_device(console_tty);
redirect_printk_to_tty(console_tty_device);
object_deref(console_tty);
} else {
printk("console tty '%s' is unavailable.", console_tty_name);
}
create_kernel_thread(background_thread);
struct object *kbd;
run_all_tests();
status = object_get("/dev/input/input0", &kbd);
if (status == KERN_OK) {
tty_connect_foreground_input_device(cast_to_device(kbd));
}
struct object *disk;
status = object_get("/dev/block/disk0", &disk);
if (status == KERN_OK) {
unsigned char buf[32] = {0};
struct device *disk_dev = cast_to_device(disk);
size_t nread = 0;
device_lock(disk_dev);
status = device_read(disk_dev, buf, 1, 32, &nread, 0);
device_unlock(disk_dev);
if (status == KERN_OK) {
printk("read %zu bytes from /dev/block/disk0:", nread);
for (int i = 0; i < sizeof buf; i++) {
printk("%02xh", buf[i]);
}
} else {
printk("failed to read from block device (%s)", kern_status_string(status));
}
} else {
printk("cannot open block device (%s)", kern_status_string(status));
}
hang();
}

View File

@@ -1,162 +0,0 @@
#include <socks/tty.h>
#include <socks/device.h>
#include <socks/console.h>
#include <socks/input.h>
#include <socks/libc/stdio.h>
static struct char_device_ops tty_ops = {
.read = tty_read,
.write = tty_write,
};
static spin_lock_t foreground_lock = SPIN_LOCK_INIT;
static struct device *foreground = NULL;
static struct device *foreground_input = NULL;
static spin_lock_t kernel_console_tty_lock = SPIN_LOCK_INIT;
static struct device *kernel_console_tty = NULL;
static void tty_input_hook_callback(struct device *dev, struct input_event *ev, enum input_event_hook_flags *flags, void *arg)
{
struct device *fg_tty = foreground;
if (!fg_tty) {
return;
}
tty_report_event(fg_tty, ev);
*flags = 0;
}
static struct input_event_hook foreground_input_hook = {
.hook_callback = tty_input_hook_callback,
};
static void tty_console_write(struct console *con, const char *s, unsigned int len)
{
if (kernel_console_tty) {
size_t nr_written;
tty_write(kernel_console_tty, s, 0, len, &nr_written, 0);
}
}
static struct console tty_console = {
.c_name = "tty",
.c_write = tty_console_write,
};
void register_tty_console(void)
{
console_register(&tty_console);
}
void redirect_printk_to_tty(struct device *dest)
{
unsigned long flags;
spin_lock_irqsave(&kernel_console_tty_lock, &flags);
if (kernel_console_tty) {
device_deref(kernel_console_tty);
kernel_console_tty = NULL;
}
kernel_console_tty = device_ref(dest);
spin_unlock_irqrestore(&kernel_console_tty_lock, flags);
}
struct device *tty_device_create(void)
{
struct char_device *cdev = char_device_create();
if (!cdev) {
return NULL;
}
struct tty_device *tty_dev = kmalloc(sizeof *tty_dev, VM_NORMAL);
if (!tty_dev) {
object_deref(char_device_object(cdev));
return NULL;
}
kern_status_t status = ringbuffer_init(&tty_dev->tty_input, TTY_INPUT_QUEUE_SIZE * sizeof(char));
if (status != KERN_OK) {
kfree(tty_dev);
object_deref(char_device_object(cdev));
return NULL;
}
tty_dev->tty_ldisc = tty_default_line_discipline();
cdev->c_ops = &tty_ops;
cdev->c_tty = tty_dev;
return char_device_base(cdev);
}
static kern_status_t generate_name(struct tty_driver *owner, struct device *dev, char out[DEV_NAME_MAX])
{
/* minor numbers start at 1. subtract 1 to start at 0 instead */
snprintf(out, DEV_NAME_MAX, "%s%u", owner->tty_name, dev->dev_minor - 1);
return KERN_OK;
}
kern_status_t tty_device_register(struct device *dev, struct tty_driver *owner, struct device *parent)
{
kern_status_t status = device_register(dev, tty_driver_base(owner), parent);
if (status != KERN_OK) {
return status;
}
char link_name[DEV_NAME_MAX];
generate_name(owner, dev, link_name);
char link_path[OBJECT_PATH_MAX];
snprintf(link_path, sizeof link_path, "/dev/tty/%s", link_name);
return object_namespace_create_link(global_namespace(), link_path, &dev->dev_base);
}
void tty_set_foreground(struct device *tty)
{
unsigned long flags;
spin_lock_irqsave(&foreground_lock, &flags);
if (foreground) {
device_deref(foreground);
foreground = NULL;
}
foreground = device_ref(tty);
spin_unlock_irqrestore(&foreground_lock, flags);
}
kern_status_t tty_connect_foreground_input_device(struct device *input)
{
struct input_device *inputdev = INPUT_DEVICE(input);
if (!inputdev) {
return KERN_INVALID_ARGUMENT;
}
unsigned long flags;
spin_lock_irqsave(&foreground_lock, &flags);
if (foreground_input) {
struct device *prev = foreground_input;
foreground_input = NULL;
device_lock(prev);
input_device_remove_hook(prev, &foreground_input_hook);
device_unlock(prev);
device_deref(prev);
object_deref(&prev->dev_base);
}
foreground_input = device_ref(input);
device_lock(input);
input_device_add_hook(input, &foreground_input_hook);
device_unlock(input);
spin_unlock_irqrestore(&foreground_lock, flags);
return KERN_OK;
}

View File

@@ -1,71 +0,0 @@
#include <socks/tty.h>
static struct vm_cache tty_driver_cache = {
.c_name = "tty_driver",
.c_obj_size = sizeof(struct tty_driver),
};
static struct queue tty_drivers;
static spin_lock_t tty_drivers_lock;
kern_status_t tty_bootstrap(void)
{
vm_cache_init(&tty_driver_cache);
tty_drivers = QUEUE_INIT;
tty_drivers_lock = SPIN_LOCK_INIT;
return KERN_OK;
}
struct tty_driver *tty_driver_create(struct kext *self, const char *name)
{
struct tty_driver *driver = vm_cache_alloc(&tty_driver_cache, VM_NORMAL);
if (!driver) {
return NULL;
}
kern_status_t status = driver_init(&driver->tty_base, self, name);
if (status != KERN_OK) {
vm_cache_free(&tty_driver_cache, driver);
return NULL;
}
strncpy(driver->tty_name, name, sizeof driver->tty_name - 1);
return driver;
}
kern_status_t tty_driver_destroy(struct tty_driver *driver)
{
/* TODO */
return KERN_UNIMPLEMENTED;
}
kern_status_t tty_driver_register(struct tty_driver *driver)
{
kern_status_t status = driver_register(&driver->tty_base);
if (status != KERN_OK) {
return status;
}
unsigned long flags;
spin_lock_irqsave(&tty_drivers_lock, &flags);
queue_push_back(&tty_drivers, &driver->tty_head);
spin_unlock_irqrestore(&tty_drivers_lock, flags);
return KERN_OK;
}
kern_status_t tty_driver_unregister(struct tty_driver *driver)
{
if (driver->tty_base.drv_major == DEV_MAJOR_INVALID) {
return KERN_INVALID_ARGUMENT;
}
unsigned long flags;
spin_lock_irqsave(&tty_drivers_lock, &flags);
queue_delete(&tty_drivers, &driver->tty_head);
spin_unlock_irqrestore(&tty_drivers_lock, flags);
return driver_unregister(&driver->tty_base);
}

View File

@@ -1,401 +0,0 @@
#include <socks/tty.h>
#include <socks/input.h>
#include <socks/libc/ctype.h>
static void default_ldisc_write(struct device *, const struct input_event *);
static kern_status_t default_ldisc_read(struct device *tty, void *buf, size_t max, size_t *nr_read, socks_flags_t flags);
static char keycode_chars[] = {
[KEY_UNKNOWN] = ' ',
[KEY_A] = 'a',
[KEY_B] = 'b',
[KEY_C] = 'c',
[KEY_D] = 'd',
[KEY_E] = 'e',
[KEY_F] = 'f',
[KEY_G] = 'g',
[KEY_H] = 'h',
[KEY_I] = 'i',
[KEY_J] = 'j',
[KEY_K] = 'k',
[KEY_L] = 'l',
[KEY_M] = 'm',
[KEY_N] = 'n',
[KEY_O] = 'o',
[KEY_P] = 'p',
[KEY_Q] = 'q',
[KEY_R] = 'r',
[KEY_S] = 's',
[KEY_T] = 't',
[KEY_U] = 'u',
[KEY_V] = 'v',
[KEY_W] = 'w',
[KEY_X] = 'x',
[KEY_Y] = 'y',
[KEY_Z] = 'z',
[KEY_KEY_1] = '1',
[KEY_KEY_2] = '2',
[KEY_KEY_3] = '3',
[KEY_KEY_4] = '4',
[KEY_KEY_5] = '5',
[KEY_KEY_6] = '6',
[KEY_KEY_7] = '7',
[KEY_KEY_8] = '8',
[KEY_KEY_9] = '9',
[KEY_KEY_0] = '0',
[KEY_ENTER] = '\n',
[KEY_ESCAPE] = 0,
[KEY_BACKSPACE] = '\b',
[KEY_TAB] = ' ',
[KEY_SPACE] = ' ',
[KEY_MINUS] = '-',
[KEY_EQUALS] = '=',
[KEY_LEFT_BRACE] = '[',
[KEY_RIGHT_BRACE] = ']',
[KEY_BACKSLASH] = '\\',
[KEY_NON_US_HASH] = 0,
[KEY_SEMICOLON] = ';',
[KEY_APOSTROPHE] = '\'',
[KEY_GRAVE_ACCENT] = 0,
[KEY_COMMA] = ',',
[KEY_DOT] = '.',
[KEY_SLASH] = '/',
[KEY_CAPS_LOCK] = 0,
[KEY_F1] = 0,
[KEY_F2] = 0,
[KEY_F3] = 0,
[KEY_F4] = 0,
[KEY_F5] = 0,
[KEY_F6] = 0,
[KEY_F7] = 0,
[KEY_F8] = 0,
[KEY_F9] = 0,
[KEY_F10] = 0,
[KEY_F11] = 0,
[KEY_F12] = 0,
[KEY_PRINT_SCREEN] = 0,
[KEY_SCROLL_LOCK] = 0,
[KEY_PAUSE] = 0,
[KEY_INSERT] = 0,
[KEY_HOME] = 0,
[KEY_PAGE_UP] = 0,
[KEY_DELETE] = 0,
[KEY_END] = 0,
[KEY_PAGE_DOWN] = 0,
[KEY_RIGHT] = 0,
[KEY_LEFT] = 0,
[KEY_DOWN] = 0,
[KEY_UP] = 0,
[KEY_NUM_LOCK] = 0,
[KEY_KEYPAD_SLASH] = '/',
[KEY_KEYPAD_ASTERISK] = '*',
[KEY_KEYPAD_MINUS] = '-',
[KEY_KEYPAD_PLUS] = '+',
[KEY_KEYPAD_ENTER] = '\n',
[KEY_KEYPAD_1] = '1',
[KEY_KEYPAD_2] = '2',
[KEY_KEYPAD_3] = '3',
[KEY_KEYPAD_4] = '4',
[KEY_KEYPAD_5] = '5',
[KEY_KEYPAD_6] = '6',
[KEY_KEYPAD_7] = '7',
[KEY_KEYPAD_8] = '8',
[KEY_KEYPAD_9] = '9',
[KEY_KEYPAD_0] = '0',
[KEY_KEYPAD_DOT] = '.',
[KEY_NON_US_BACKSLASH] = 0,
[KEY_KEYPAD_EQUALS] = '=',
[KEY_MENU] = 0,
[KEY_LEFT_CTRL] = 0,
[KEY_LEFT_SHIFT] = 0,
[KEY_LEFT_ALT] = 0,
[KEY_LEFT_META] = 0,
[KEY_RIGHT_CTRL] = 0,
[KEY_RIGHT_SHIFT] = 0,
[KEY_RIGHT_ALT] = 0,
[KEY_RIGHT_META] = 0,
[KEY_MEDIA_MUTE] = 0,
[KEY_MEDIA_VOLUME_INCREMENT] = 0,
[KEY_MEDIA_VOLUME_DECREMENT] = 0,
};
static char keycode_chars_shift[] = {
[KEY_UNKNOWN] = ' ',
[KEY_A] = 'A',
[KEY_B] = 'B',
[KEY_C] = 'C',
[KEY_D] = 'D',
[KEY_E] = 'E',
[KEY_F] = 'F',
[KEY_G] = 'G',
[KEY_H] = 'H',
[KEY_I] = 'I',
[KEY_J] = 'J',
[KEY_K] = 'K',
[KEY_L] = 'L',
[KEY_M] = 'M',
[KEY_N] = 'N',
[KEY_O] = 'O',
[KEY_P] = 'P',
[KEY_Q] = 'Q',
[KEY_R] = 'R',
[KEY_S] = 'S',
[KEY_T] = 'T',
[KEY_U] = 'U',
[KEY_V] = 'V',
[KEY_W] = 'W',
[KEY_X] = 'X',
[KEY_Y] = 'Y',
[KEY_Z] = 'Z',
[KEY_KEY_1] = '!',
[KEY_KEY_2] = '"',
[KEY_KEY_3] = 0,
[KEY_KEY_4] = '$',
[KEY_KEY_5] = '%',
[KEY_KEY_6] = '^',
[KEY_KEY_7] = '&',
[KEY_KEY_8] = '*',
[KEY_KEY_9] = '(',
[KEY_KEY_0] = ')',
[KEY_ENTER] = '\n',
[KEY_ESCAPE] = 0,
[KEY_BACKSPACE] = '\b',
[KEY_TAB] = ' ',
[KEY_SPACE] = ' ',
[KEY_MINUS] = '_',
[KEY_EQUALS] = '+',
[KEY_LEFT_BRACE] = '{',
[KEY_RIGHT_BRACE] = '}',
[KEY_BACKSLASH] = '|',
[KEY_NON_US_HASH] = 0,
[KEY_SEMICOLON] = ':',
[KEY_APOSTROPHE] = '@',
[KEY_GRAVE_ACCENT] = 0,
[KEY_COMMA] = '<',
[KEY_DOT] = '>',
[KEY_SLASH] = '?',
[KEY_CAPS_LOCK] = 0,
[KEY_F1] = 0,
[KEY_F2] = 0,
[KEY_F3] = 0,
[KEY_F4] = 0,
[KEY_F5] = 0,
[KEY_F6] = 0,
[KEY_F7] = 0,
[KEY_F8] = 0,
[KEY_F9] = 0,
[KEY_F10] = 0,
[KEY_F11] = 0,
[KEY_F12] = 0,
[KEY_PRINT_SCREEN] = 0,
[KEY_SCROLL_LOCK] = 0,
[KEY_PAUSE] = 0,
[KEY_INSERT] = 0,
[KEY_HOME] = 0,
[KEY_PAGE_UP] = 0,
[KEY_DELETE] = 0,
[KEY_END] = 0,
[KEY_PAGE_DOWN] = 0,
[KEY_RIGHT] = 0,
[KEY_LEFT] = 0,
[KEY_DOWN] = 0,
[KEY_UP] = 0,
[KEY_NUM_LOCK] = 0,
[KEY_KEYPAD_SLASH] = '/',
[KEY_KEYPAD_ASTERISK] = '*',
[KEY_KEYPAD_MINUS] = '-',
[KEY_KEYPAD_PLUS] = '+',
[KEY_KEYPAD_ENTER] = '\n',
[KEY_KEYPAD_1] = '1',
[KEY_KEYPAD_2] = '2',
[KEY_KEYPAD_3] = '3',
[KEY_KEYPAD_4] = '4',
[KEY_KEYPAD_5] = '5',
[KEY_KEYPAD_6] = '6',
[KEY_KEYPAD_7] = '7',
[KEY_KEYPAD_8] = '8',
[KEY_KEYPAD_9] = '9',
[KEY_KEYPAD_0] = '0',
[KEY_KEYPAD_DOT] = '.',
[KEY_NON_US_BACKSLASH] = 0,
[KEY_KEYPAD_EQUALS] = '=',
[KEY_MENU] = 0,
[KEY_LEFT_CTRL] = 0,
[KEY_LEFT_SHIFT] = 0,
[KEY_LEFT_ALT] = 0,
[KEY_LEFT_META] = 0,
[KEY_RIGHT_CTRL] = 0,
[KEY_RIGHT_SHIFT] = 0,
[KEY_RIGHT_ALT] = 0,
[KEY_RIGHT_META] = 0,
[KEY_MEDIA_MUTE] = 0,
[KEY_MEDIA_VOLUME_INCREMENT] = 0,
[KEY_MEDIA_VOLUME_DECREMENT] = 0,
};
static struct tty_ldisc default_ldisc = {
.name = "n_tty",
.read = default_ldisc_read,
.write = default_ldisc_write,
};
static enum tty_modifier_key get_modifier_key(const struct input_event *ev)
{
switch (ev->ev_key.key) {
case KEY_LEFT_CTRL:
case KEY_RIGHT_CTRL:
return TTY_KEY_CTRL;
case KEY_LEFT_ALT:
case KEY_RIGHT_ALT:
return TTY_KEY_ALT;
case KEY_LEFT_SHIFT:
case KEY_RIGHT_SHIFT:
return TTY_KEY_SHIFT;
default:
return TTY_KEY_OTHER;
}
}
static bool is_arrow_key(const struct input_event *ev, char *ch)
{
bool ret = false;
switch (ev->ev_key.key) {
case KEY_UP:
ret = true;
*ch = 'A';
break;
case KEY_DOWN:
ret = true;
*ch = 'B';
break;
case KEY_RIGHT:
ret = true;
*ch = 'C';
break;
case KEY_LEFT:
ret = true;
*ch = 'D';
break;
default:
ret = false;
break;
}
return ret;
}
static void handle_modifier_keys(struct device *tty, enum tty_modifier_key modkey, const struct input_event *ev)
{
struct tty_device *ttydev = TTY_DEVICE(tty);
if (ev->ev_key.state == INPUT_KEYSTATE_DOWN) {
ttydev->tty_modstate |= modkey;
} else {
ttydev->tty_modstate &= ~modkey;
}
}
static void convert_ev_to_chars(struct device *tty, const struct input_event *ev)
{
if (ev->ev_key.state == INPUT_KEYSTATE_UP) {
return;
}
struct tty_device *ttydev = TTY_DEVICE(tty);
char echo[4];
int echo_len = 0;
char data[4];
int data_len = 0;
char c = keycode_chars[ev->ev_key.key];
if (ttydev->tty_modstate & TTY_KEY_CTRL) {
if (!isalpha(c)) {
return;
}
echo[0] = '^';
echo[1] = toupper(c);
echo_len = 2;
c = tolower(c);
c -= 97;
c++;
data[0] = c;
data_len = 1;
} else if (ttydev->tty_modstate & TTY_KEY_SHIFT) {
c = keycode_chars_shift[ev->ev_key.key];
echo[0] = c;
echo_len = 1;
data[0] = c;
data_len = 1;
} else if (is_arrow_key(ev, &c)) {
echo[0] = '^';
echo[1] = '[';
echo[2] = '[';
echo[3] = c;
echo_len = 4;
data[0] = 0x1b;
data[1] = '[';
data[2] = c;
data_len = 3;
} else if (c != 0) {
echo[0] = c;
echo_len = 1;
data[0] = c;
data_len = 1;
}
if (data_len == 0) {
return;
}
ringbuffer_write(&ttydev->tty_input, data_len, data, S_NOBLOCK);
size_t nr_written;
tty_write(tty, echo, 0, echo_len, &nr_written, S_NOBLOCK);
}
static kern_status_t canonical_read(struct device *tty, void *buf, size_t max, size_t *nr_read, socks_flags_t flags)
{
//struct tty_device *ttydev = TTY_DEVICE(tty);
//struct termios backup = ttydev
//char *linebuf = ttydev->tty_linebuf;
//unsigned int pos = 0, len = 0;
return KERN_OK;
}
static kern_status_t non_canonical_read(struct device *tty, void *buf, size_t max, size_t *nr_read, socks_flags_t flags)
{
return KERN_OK;
}
static kern_status_t default_ldisc_read(struct device *tty, void *buf, size_t max, size_t *nr_read, socks_flags_t flags)
{
struct tty_device *ttydev = TTY_DEVICE(tty);
if (ttydev->tty_config.c_lflag & ICANON) {
return canonical_read(tty, buf, max, nr_read, flags);
} else {
return non_canonical_read(tty, buf, max, nr_read, flags);
}
return KERN_OK;
}
static void default_ldisc_write(struct device *tty, const struct input_event *ev)
{
enum tty_modifier_key modkeys = get_modifier_key(ev);
if (modkeys != TTY_KEY_OTHER) {
handle_modifier_keys(tty, modkeys, ev);
} else {
convert_ev_to_chars(tty, ev);
}
}
struct tty_ldisc *tty_default_line_discipline(void)
{
return &default_ldisc;
}

View File

@@ -1,110 +0,0 @@
#include <socks/tty.h>
#include <socks/input.h>
#include <socks/printk.h>
static void newline(struct device *tty)
{
struct tty_device *ttydev = TTY_DEVICE(tty);
struct tty_driver *tty_driver = TTY_DRIVER(tty->dev_owner);
struct tty_driver_ops *ops = tty_driver->tty_ops;
ttydev->tty_xcur = 0;
ttydev->tty_ycur++;
if (ttydev->tty_ycur >= ttydev->tty_ycells) {
ttydev->tty_xcur = 0;
ttydev->tty_ycur = ttydev->tty_ycells - 1;
if (ops->tty_scroll) {
ops->tty_scroll(tty, TTY_SCROLL_DOWN, 1);
}
}
ops->tty_move_cursor(tty, ttydev->tty_xcur, ttydev->tty_ycur);
}
static void __putchar(struct device *tty, int c)
{
struct tty_device *ttydev = TTY_DEVICE(tty);
struct tty_driver *tty_driver = TTY_DRIVER(tty->dev_owner);
struct tty_driver_ops *ops = tty_driver->tty_ops;
ops->tty_putc(tty, c, ttydev->tty_xcur, ttydev->tty_ycur, ttydev->tty_curattrib);
ttydev->tty_xcur++;
if (ttydev->tty_xcur >= ttydev->tty_xcells) {
ttydev->tty_xcur = 0;
ttydev->tty_ycur++;
}
if (ttydev->tty_ycur >= ttydev->tty_ycells) {
ttydev->tty_xcur = 0;
ttydev->tty_ycur = ttydev->tty_ycells - 1;
if (ops->tty_scroll) {
ops->tty_scroll(tty, TTY_SCROLL_DOWN, 1);
}
}
ops->tty_move_cursor(tty, ttydev->tty_xcur, ttydev->tty_ycur);
}
static void putchar(struct device *tty, int c)
{
struct tty_driver *tty_driver = TTY_DRIVER(tty->dev_owner);
struct tty_driver_ops *ops = tty_driver->tty_ops;
if (!ops->tty_putc) {
return;
}
if (tty_driver->tty_type == TTY_DRIVER_SIMPLE) {
ops->tty_putc(tty, c, -1, -1, 0);
return;
}
switch (c) {
case '\n':
newline(tty);
break;
default:
__putchar(tty, c);
break;
}
}
kern_status_t tty_read(struct device *tty, void *buf, size_t offset, size_t max, size_t *nr_read, socks_flags_t flags)
{
kern_status_t status = KERN_UNSUPPORTED;
struct tty_device *ttydev = TTY_DEVICE(tty);
if (ttydev->tty_ldisc || ttydev->tty_ldisc->read) {
status = ttydev->tty_ldisc->read(tty, buf, max, nr_read, flags);
}
return status;
}
kern_status_t tty_write(struct device *tty, const void *buf, size_t offset, size_t len, size_t *nr_written, socks_flags_t flags)
{
size_t r = 0;
const char *s = buf;
for (size_t i = 0; i < len; i++) {
putchar(tty, s[i]);
r++;
}
*nr_written = r;
return KERN_OK;
}
kern_status_t tty_report_event(struct device *tty, const struct input_event *ev)
{
struct tty_device *ttydev = TTY_DEVICE(tty);
if (ttydev->tty_ldisc || ttydev->tty_ldisc->write) {
ttydev->tty_ldisc->write(tty, ev);
}
return KERN_OK;
}

View File

@@ -1,360 +0,0 @@
#include <socks/printk.h>
#include <socks/pci.h>
#include <socks/device.h>
#include <socks/kext.h>
#include <socks/pci.h>
#include <socks/util.h>
#include <socks/machine/init.h>
#include <socks/libc/stdio.h>
#include <socks/libc/ctype.h>
#include <arch/irq.h>
#include "ahci.h"
int find_cmdslot(volatile struct hba_port *port)
{
uint32_t slots = (port->sact | port->ci);
for (int i = 0; i < 32; i++)
{
if ((slots & 0x01u) == 0) {
return i;
}
slots >>= 1;
}
return -1;
}
static struct hba_cmd_table *create_cmd_table(struct iovec *vec, size_t nvec)
{
size_t sz = sizeof(struct hba_cmd_table) + (sizeof(struct hba_prdt_entry) * nvec);
struct hba_cmd_table *out = kzalloc(sz, VM_NORMAL);
for (size_t i = 0; i < nvec; i++) {
phys_addr_t vec_phys = vm_virt_to_phys(vec->io_buf);
out->prdt_entry[i].dba = vec_phys & 0xFFFFFFFF;
out->prdt_entry[i].dbau = (vec_phys >> 32) & 0xFFFFFFFF;
out->prdt_entry[i].dbc = vec->io_len - 1;
out->prdt_entry[i].i = (i == nvec - 1) ? 1 : 0;
}
return out;
}
static void free_cmd_table(struct hba_cmd_table *table)
{
kfree(table);
}
kern_status_t send_ata_command(struct ahci_device *dev, unsigned int cmd, struct iovec *vec, size_t nvec)
{
return send_ata_command_ex(dev, NULL, cmd, vec, nvec);
}
kern_status_t send_ata_command_ex(struct ahci_device *dev, struct fis_reg_h2d *fis, unsigned int cmd, struct iovec *vec, size_t nvec)
{
if (nvec == 0) {
return KERN_OK;
}
volatile struct hba_port *port = dev->port;
port->is = (uint32_t) -1;
int spin = 0;
int slot = find_cmdslot(port);
if (slot == -1) {
return KERN_BUSY;
}
struct hba_cmd_header *cmdheader = &dev->cmd_header[slot];
cmdheader->cfl = sizeof(struct fis_reg_h2d) / sizeof(uint32_t);
cmdheader->w = 0;
cmdheader->a = 0;
cmdheader->prdtl = nvec;
struct hba_cmd_table *cmdtbl = create_cmd_table(vec, nvec);
phys_addr_t cmdtbl_phys = vm_virt_to_phys(cmdtbl);
cmdheader->ctba = cmdtbl_phys & 0xFFFFFFFF;
cmdheader->ctbau = (cmdtbl_phys >> 32) & 0xFFFFFFFF;
struct fis_reg_h2d *cmdfis = (struct fis_reg_h2d*)(&cmdtbl->cfis);
if (fis) {
memcpy(cmdfis, fis, sizeof *cmdfis);
} else {
memset(cmdfis, 0x00, sizeof *cmdfis);
}
cmdfis->fis_type = FIS_TYPE_REG_H2D;
cmdfis->c = 1;
cmdfis->command = cmd;
while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && spin < 1000000) {
spin++;
}
if (spin == 1000000) {
free_cmd_table(cmdtbl);
return KERN_DEVICE_STUCK;
}
port->ci = 1 << slot;
while (1)
{
if ((port->ci & (1 << slot)) == 0) {
break;
}
if (port->is & HBA_PxIS_TFES) {
free_cmd_table(cmdtbl);
return KERN_IO_ERROR;
}
}
free_cmd_table(cmdtbl);
if (port->is & HBA_PxIS_TFES) {
return KERN_IO_ERROR;
}
return KERN_OK;
}
kern_status_t send_atapi_command(struct ahci_device *dev, struct scsi_command *cmd, struct iovec *vec, size_t nvec)
{
return send_atapi_command_ex(dev, NULL, cmd, vec, nvec);
}
kern_status_t send_atapi_command_ex(struct ahci_device *dev, struct fis_reg_h2d *fis, struct scsi_command *cmd, struct iovec *vec, size_t nvec)
{
if (nvec == 0) {
return KERN_OK;
}
volatile struct hba_port *port = dev->port;
port->is = (uint32_t) -1;
int spin = 0;
int slot = find_cmdslot(port);
if (slot == -1) {
return KERN_BUSY;
}
struct hba_cmd_header *cmdheader = &dev->cmd_header[slot];
memset(cmdheader, 0x0, sizeof *cmdheader);
cmdheader->cfl = sizeof(struct fis_reg_h2d) / sizeof(uint32_t);
cmdheader->w = 0;
cmdheader->a = 1;
cmdheader->prdtl = nvec;
struct hba_cmd_table *cmdtbl = create_cmd_table(vec, nvec);
phys_addr_t cmdtbl_phys = vm_virt_to_phys(cmdtbl);
cmdheader->ctba = cmdtbl_phys & 0xFFFFFFFF;
cmdheader->ctbau = (cmdtbl_phys >> 32) & 0xFFFFFFFF;
memcpy(&cmdtbl->acmd, cmd, sizeof *cmd);
struct fis_reg_h2d *cmdfis = (struct fis_reg_h2d *)(&cmdtbl->cfis);
if (fis) {
memcpy(cmdfis, fis, sizeof *cmdfis);
} else {
memset(cmdfis, 0x0, sizeof *cmdfis);
}
cmdfis->fis_type = FIS_TYPE_REG_H2D;
cmdfis->c = 1;
cmdfis->rsv0 = 0;
cmdfis->feature_l = 1;
cmdfis->command = ATA_CMD_PACKET;
while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && spin < 1000000) {
spin++;
}
if (spin == 1000000) {
free_cmd_table(cmdtbl);
return KERN_DEVICE_STUCK;
}
port->ci = 1 << slot;
while (1)
{
if ((port->ci & (1 << slot)) == 0) {
break;
}
if (port->is & HBA_PxIS_TFES) {
free_cmd_table(cmdtbl);
return KERN_IO_ERROR;
}
}
volatile int _i = 0;
while ((port->is & 0x01u) != 0x1) {
_i++;
}
free_cmd_table(cmdtbl);
if (port->is & HBA_PxIS_TFES) {
return KERN_IO_ERROR;
}
return KERN_OK;
}
kern_status_t identify_ata_device(struct ahci_device *dev, struct identify_device_data *out)
{
struct iovec vec = { .io_buf = out, .io_len = sizeof *out };
kern_status_t status = send_ata_command(dev, ATA_CMD_IDENTIFY_DEVICE, &vec, 1);
if (status != KERN_OK) {
return status;
}
out->model_number[39] = 0;
for (int i = 0; i < 40; i += 2) {
unsigned char c = out->model_number[i];
out->model_number[i] = out->model_number[i + 1];
out->model_number[i + 1] = c;
}
for (int i = sizeof out->model_number - 1; i >= 0; i--) {
if (isspace(out->model_number[i]) || out->model_number[i] == 0) {
out->model_number[i] = 0;
} else {
break;
}
}
return KERN_OK;
}
kern_status_t identify_atapi_device(struct ahci_device *dev, struct identify_device_data *out)
{
struct iovec vec = { .io_buf = out, .io_len = sizeof *out };
kern_status_t status = send_ata_command(dev, ATA_CMD_IDENTIFY_PACKET_DEVICE, &vec, 1);
if (status != KERN_OK) {
return status;
}
out->model_number[39] = 0;
for (int i = 0; i < 40; i += 2) {
unsigned char c = out->model_number[i];
out->model_number[i] = out->model_number[i + 1];
out->model_number[i + 1] = c;
}
for (int i = sizeof out->model_number - 1; i >= 0; i--) {
if (isspace(out->model_number[i]) || out->model_number[i] == 0) {
out->model_number[i] = 0;
} else {
break;
}
}
return KERN_OK;
}
// Start command engine
void start_cmd(volatile struct hba_port *port)
{
volatile int _i = 0;
while (port->cmd & HBA_PxCMD_CR) {
_i++;
}
port->cmd |= HBA_PxCMD_FRE;
port->cmd |= HBA_PxCMD_ST;
}
// Stop command engine
void stop_cmd(volatile struct hba_port *port)
{
port->cmd &= ~HBA_PxCMD_ST;
port->cmd &= ~HBA_PxCMD_FRE;
while(1) {
if (port->cmd & HBA_PxCMD_FR) {
continue;
}
if (port->cmd & HBA_PxCMD_CR) {
continue;
}
break;
}
}
void rebase_ahci_port(struct ahci_device *dev)
{
volatile struct hba_port *port = dev->port;
stop_cmd(port);
struct hba_cmd_header *cmdheader = dev->cmd_header;
phys_addr_t cmdheader_phys = vm_virt_to_phys(cmdheader);
port->clb = cmdheader_phys & 0xFFFFFFFF;
port->clbu = (cmdheader_phys >> 32) & 0xFFFFFFFF;
memset(cmdheader, 0, sizeof *cmdheader);
phys_addr_t fis_phys = vm_virt_to_phys(dev->rfis_data);
port->fb = fis_phys & 0xFFFFFFFF;
port->fbu = (fis_phys >> 32) & 0xFFFFFFFF;
memset(dev->rfis_data, 0, 256);
start_cmd(port);
}
static int check_type(volatile struct hba_port *port)
{
uint32_t ssts = port->ssts;
uint8_t ipm = (ssts >> 8) & 0x0F;
uint8_t det = ssts & 0x0F;
if (det != HBA_PORT_DET_PRESENT) {
return AHCI_DEV_NULL;
}
if (ipm != HBA_PORT_IPM_ACTIVE) {
return AHCI_DEV_NULL;
}
switch (port->sig) {
case SATA_SIG_ATAPI:
return AHCI_DEV_SATAPI;
case SATA_SIG_SEMB:
return AHCI_DEV_SEMB;
case SATA_SIG_PM:
return AHCI_DEV_PM;
default:
return AHCI_DEV_SATA;
}
}
void probe_ahci_ports(struct driver *driver, struct device *controller, volatile struct hba_config *abar,
void(*callback)(int, struct device *, volatile struct hba_port *, int))
{
uint32_t pi = abar->pi;
for (int i = 0; i < 32; i++) {
if (!(pi & 1)) {
pi >>= 1;
continue;
}
int dt = check_type(&abar->ports[i]);
switch (dt) {
case AHCI_DEV_SATA:
case AHCI_DEV_SATAPI:
break;
default:
pi >>= 1;
continue;
}
callback(i, controller, &abar->ports[i], dt);
pi >>= 1;
}
}

View File

@@ -1,728 +0,0 @@
#ifndef _AHCI_H_
#define _AHCI_H_
#include <socks/compiler.h>
#include <socks/status.h>
#include <stdint.h>
#include <stddef.h>
struct driver;
struct device;
struct iovec;
#define SATA_SIG_ATA 0x00000101 // SATA drive
#define SATA_SIG_ATAPI 0xEB140101 // SATAPI drive
#define SATA_SIG_SEMB 0xC33C0101 // Enclosure management bridge
#define SATA_SIG_PM 0x96690101 // Port multiplier
#define AHCI_DEV_NULL 0
#define AHCI_DEV_SATA 1
#define AHCI_DEV_SEMB 2
#define AHCI_DEV_PM 3
#define AHCI_DEV_SATAPI 4
#define HBA_PORT_IPM_ACTIVE 1
#define HBA_PORT_DET_PRESENT 3
#define AHCI_BASE 0x400000 // 4M
#define HBA_PxCMD_ST 0x0001
#define HBA_PxCMD_FRE 0x0010
#define HBA_PxCMD_FR 0x4000
#define HBA_PxCMD_CR 0x8000
#define HBA_PxIS_TFES 0x40000000
#define HBA_PxIS_DPS 0x20u
#define ATA_CMD_READ_DMA_EX 0x25u
#define ATA_CMD_IDENTIFY_DEVICE 0xECu
#define ATA_CMD_PACKET 0xA0u
#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1u
#define SCSI_CMD_READ 0xA8u
#define SCSI_CMD_READ_CAPACITY 0x25u
#define ATA_DEV_BUSY 0x80
#define ATA_DEV_DRQ 0x08
enum fis_type {
FIS_TYPE_REG_H2D = 0x27u,
FIS_TYPE_REG_D2H = 0x34u,
FIS_TYPE_DMA_ACT = 0x39u,
FIS_TYPE_DMA_SETUP = 0x41u,
FIS_TYPE_DATA = 0x46u,
FIS_TYPE_BIST = 0x58u,
FIS_TYPE_PIO_SETUP = 0x5F,
FIS_TYPE_DEV_BITS = 0xA1,
};
struct fis_reg_h2d {
uint8_t fis_type;
uint8_t pmport : 4;
uint8_t rsv0 : 3;
uint8_t c : 1;
uint8_t command;
uint8_t feature_l;
uint8_t lba0;
uint8_t lba1;
uint8_t lba2;
uint8_t device;
uint8_t lba3;
uint8_t lba4;
uint8_t lba5;
uint8_t feature_h;
uint8_t count_l;
uint8_t count_h;
uint8_t icc;
uint8_t control;
uint8_t rsv1[4];
} __packed;
struct fis_reg_d2h {
uint8_t fis_type;
uint8_t pmport : 4;
uint8_t rsv0 : 2;
uint8_t i : 1;
uint8_t rsv1 : 1;
uint8_t status;
uint8_t error;
uint8_t lba0;
uint8_t lba1;
uint8_t lba2;
uint8_t device;
uint8_t lba3;
uint8_t lba4;
uint8_t lba5;
uint8_t rsv2;
uint8_t count_l;
uint8_t count_h;
uint8_t rsv3[2];
uint8_t rsv4[4];
} __packed;
struct fis_data {
uint8_t fis_type;
uint8_t pmport : 4;
uint8_t rsv0 : 4;
uint8_t rsv1[2];
// data
} __packed;
struct fis_pio_setup {
uint8_t fis_type;
uint8_t pmport : 4;
uint8_t rsv0 : 1;
uint8_t d : 1;
uint8_t i : 1;
uint8_t rsv1 : 1;
uint8_t status;
uint8_t error;
uint8_t lba0;
uint8_t lba1;
uint8_t lba2;
uint8_t device;
uint8_t lba3;
uint8_t lba4;
uint8_t lba5;
uint8_t rsv2;
uint8_t count_l;
uint8_t count_h;
uint8_t rsv3;
uint8_t e_status;
uint16_t rc;
uint8_t rsv4[2];
} __packed;
struct fis_dma_setup {
uint8_t fis_type;
uint8_t pmport : 4;
uint8_t rsv0 : 1;
uint8_t d : 1;
uint8_t i : 1;
uint8_t a : 1;
uint8_t rsv1[2];
uint64_t dma_buffer_id;
uint32_t rsv2;
uint32_t dba_buffer_offset;
uint32_t dma_transfer_size;
uint32_t rsv3;
} __packed;
struct hba_cmd_header {
uint8_t cfl : 5;
uint8_t a : 1;
uint8_t w : 1;
uint8_t p : 1;
uint8_t r : 1;
uint8_t b : 1;
uint8_t c : 1;
uint8_t rsv0 : 1;
uint8_t pmp : 4;
uint16_t prdtl;
volatile uint32_t prdbc;
uint32_t ctba;
uint32_t ctbau;
uint32_t rsv1[4];
} __packed;
struct hba_prdt_entry {
uint32_t dba;
uint32_t dbau;
uint32_t rsv0;
uint32_t dbc : 22;
uint32_t rsv1 : 9;
uint32_t i : 1;
} __packed;
struct scsi_command {
uint8_t cmd;
union {
struct {
uint8_t rsvd[15];
} read_capacity;
struct {
uint8_t rdprotect : 3;
uint8_t dpo : 1;
uint8_t fua : 1;
uint8_t rarc : 1;
uint8_t obsolete : 2;
uint32_t lba;
uint32_t count;
} read;
} __packed;
} __packed;
struct hba_cmd_table {
uint8_t cfis[64];
struct scsi_command acmd;
uint8_t rsv[48];
struct hba_prdt_entry prdt_entry[];
} __packed;
struct hba_port
{
uint32_t clb;
uint32_t clbu;
uint32_t fb;
uint32_t fbu;
uint32_t is;
uint32_t ie;
uint32_t cmd;
uint32_t rsv0;
uint32_t tfd;
uint32_t sig;
uint32_t ssts;
uint32_t sctl;
uint32_t serr;
uint32_t sact;
uint32_t ci;
uint32_t sntf;
uint32_t fbs;
uint32_t rsv1[11];
uint32_t vendor[4];
} __packed;
struct hba_config {
uint32_t cap;
uint32_t ghc;
uint32_t is;
uint32_t pi;
uint32_t vs;
uint32_t ccc_ctl;
uint32_t ccc_ptl;
uint32_t em_loc;
uint32_t em_ctl;
uint32_t cap2;
uint32_t bohc;
uint8_t rsv[116];
uint8_t vendor[96];
struct hba_port ports[32];
} __packed;
struct identify_device_data {
union {
struct {
uint16_t reserved_1 : 1;
uint16_t retired_3 : 1;
uint16_t response_incomplete : 1;
uint16_t retired_2 : 3;
uint16_t fixed_device : 1;
uint16_t removable_media : 1;
uint16_t retired_1 : 7;
uint16_t device_type : 1;
} general_config;
struct {
/*
uint16_t is_atapi : 2;
uint16_t reserved_1: 1;
uint16_t command_set : 5;
uint16_t obsolete_1: 1;
uint16_t packet_drq_time : 2;
uint16_t reserved_2 : 2;
uint16_t identify_incomplete : 1;
uint16_t packet_size : 2;
*/
uint16_t packet_size : 2;
uint16_t identify_incomplete : 1;
uint16_t reserved_2 : 2;
uint16_t packet_drq_time : 2;
uint16_t obsolete_1: 1;
uint16_t command_set : 5;
uint16_t reserved_1: 1;
uint16_t is_atapi : 2;
} atapi_general_config;
};
uint16_t num_cylinders;
uint16_t specific_configuration;
uint16_t num_heads;
uint16_t retired_1[2];
uint16_t num_sectors_per_track;
uint16_t vendor_unique_1[3];
uint8_t serial_number[20];
uint16_t retired_2[2];
uint16_t obsolete_1;
uint8_t firmware_revision[8];
uint8_t model_number[40];
uint8_t maximum_block_transfer;
uint8_t vendor_unique_2;
struct {
uint16_t feature_supported : 1;
uint16_t reserved : 15;
} trusted_computing;
struct {
uint16_t reserved_word_50;
uint8_t current_long_physical_sector_alignment : 2;
uint8_t reserved_byte_49 : 6;
uint8_t dma_supported : 1;
uint8_t lba_supported : 1;
uint8_t iordy_disable : 1;
uint8_t iordy_supported : 1;
uint8_t reserved_1 : 1;
uint8_t standyby_timer_support : 1;
uint8_t reserved_2 : 2;
} capabilities;
uint16_t obsolete_words_51[2];
uint16_t translation_fields_valid : 3;
uint16_t reserved_3 : 5;
uint16_t free_fall_control_sensitivity : 8;
uint16_t number_of_current_cylinders;
uint16_t number_of_current_heads;
uint16_t current_sectors_per_track;
uint32_t current_sector_capacity;
uint8_t current_multi_sector_setting;
uint8_t multi_sector_setting_valid : 1;
uint8_t reserved_byte_59 : 3;
uint8_t sanitize_feature_supported : 1;
uint8_t crypto_scramble_ext_command_supported : 1;
uint8_t overwrite_ext_command_supported : 1;
uint8_t block_erase_ext_command_supported : 1;
uint32_t user_addressable_sectors;
uint16_t obsolete_word_62;
uint16_t multi_word_dma_support : 8;
uint16_t multi_word_dma_active : 8;
uint16_t advanced_pio_modes : 8;
uint16_t reserved_byte_64 : 8;
uint16_t minimum_mw_xfer_cycle_time;
uint16_t recommended_mw_xfer_cycle_time;
uint16_t minimum_pio_cycle_time;
uint16_t minimum_pio_cycle_time_iordy;
struct {
uint16_t zoned_capabilities : 2;
uint16_t non_volatile_write_cache : 1;
uint16_t extended_user_addressable_sectors_supported : 1;
uint16_t device_encrypts_all_user_data : 1;
uint16_t read_zero_after_trim_supported : 1;
uint16_t optional_28_bit_commands_supported : 1;
uint16_t ieee_1667 : 1;
uint16_t download_microcode_dma_supported : 1;
uint16_t set_max_set_password_unlock_dma_supported : 1;
uint16_t write_buffer_dma_supported : 1;
uint16_t read_buffer_dma_supported : 1;
uint16_t device_config_identify_set_dma_supported : 1;
uint16_t lpsaerc_supported : 1;
uint16_t deterministic_read_after_trim_supported : 1;
uint16_t c_fast_spec_supported : 1;
} additional_supported;
uint16_t reserved_words_70[5];
uint16_t queue_depth : 2;
uint16_t reserved_word_75[11];
struct {
uint16_t reserved_0 : 1;
uint16_t sata_gen_1 : 1;
uint16_t sata_gen_2 : 1;
uint16_t sata_gen_3 : 1;
uint16_t reserved_1 : 1;
uint16_t ncq : 1;
uint16_t hipm : 1;
uint16_t phy_events : 1;
uint16_t ncq_unload : 1;
uint16_t ncq_priority : 1;
uint16_t host_auto_ps : 1;
uint16_t device_auto_ps : 1;
uint16_t read_log_dma : 1;
uint16_t reserved_2 : 1;
uint16_t current_speed : 3;
uint16_t ncq_streaming : 1;
uint16_t ncq_queue_mgmt : 1;
uint16_t ncq_receive_send : 1;
uint16_t devsl_pto_reduced_pwr_state : 1;
uint16_t reserved_3 : 8;
} serial_ata_capabilities;
struct {
uint16_t reserved_0 : 1;
uint16_t non_zero_offsets : 1;
uint16_t dma_setup_auto_activate : 1;
uint16_t dipm : 1;
uint16_t in_order_data : 1;
uint16_t hardware_feature_control : 1;
uint16_t software_settings_preservation : 1;
uint16_t ncq_autosense : 1;
uint16_t devslp : 1;
uint16_t hybrid_information : 1;
uint16_t reserved_1 : 6;
} serial_ata_features_supported;
struct {
uint16_t reserved_0 : 1;
uint16_t non_zero_offsets : 1;
uint16_t dma_setup_auto_activate : 1;
uint16_t dipm : 1;
uint16_t in_order_data : 1;
uint16_t hardware_feature_control : 1;
uint16_t software_settings_preservation : 1;
uint16_t device_auto_ps : 1;
uint16_t devslp : 1;
uint16_t hybrid_information : 1;
uint16_t reserved_1 : 6;
} serial_ata_features_enabled;
uint16_t major_revision;
uint16_t minor_revision;
struct {
uint16_t smart_commands : 1;
uint16_t security_mode : 1;
uint16_t removable_media_feature : 1;
uint16_t power_management : 1;
uint16_t reserved_1 : 1;
uint16_t write_cache : 1;
uint16_t look_ahead : 1;
uint16_t release_interrupt : 1;
uint16_t service_interrupt : 1;
uint16_t device_reset : 1;
uint16_t host_protected_area : 1;
uint16_t obsolete_1 : 1;
uint16_t write_buffer : 1;
uint16_t read_buffer : 1;
uint16_t nop : 1;
uint16_t obsolete_2 : 1;
uint16_t download_microcode : 1;
uint16_t dma_queued : 1;
uint16_t cfa : 1;
uint16_t advanced_pm : 1;
uint16_t msn : 1;
uint16_t power_up_in_standby : 1;
uint16_t manual_power_up : 1;
uint16_t reserved_2 : 1;
uint16_t set_max : 1;
uint16_t acoustics : 1;
uint16_t big_lba : 1;
uint16_t device_config_overlay : 1;
uint16_t flush_cache : 1;
uint16_t flush_cache_ext : 1;
uint16_t word_valid_83 : 2;
uint16_t smart_error_log : 1;
uint16_t smart_self_test : 1;
uint16_t media_serial_number : 1;
uint16_t media_card_pass_through : 1;
uint16_t streaming_feature : 1;
uint16_t gp_logging : 1;
uint16_t write_fua : 1;
uint16_t write_queued_fua : 1;
uint16_t wwn_64_bit : 1;
uint16_t urg_read_stream : 1;
uint16_t urg_write_stream : 1;
uint16_t reserved_for_tech_report : 2;
uint16_t idle_with_unload_feature : 1;
uint16_t word_valid : 2;
} command_set_support;
struct {
uint16_t smart_commands : 1;
uint16_t security_mode : 1;
uint16_t removable_media_feature : 1;
uint16_t power_management : 1;
uint16_t reserved_1 : 1;
uint16_t write_cache : 1;
uint16_t look_ahead : 1;
uint16_t release_interrupt : 1;
uint16_t service_interrupt : 1;
uint16_t device_reset : 1;
uint16_t host_protected_area : 1;
uint16_t obsolete_1 : 1;
uint16_t write_buffer : 1;
uint16_t read_buffer : 1;
uint16_t nop : 1;
uint16_t obsolete_2 : 1;
uint16_t download_microcode : 1;
uint16_t dma_queued : 1;
uint16_t cfa : 1;
uint16_t advanced_pm : 1;
uint16_t msn : 1;
uint16_t power_up_in_standby : 1;
uint16_t manual_power_up : 1;
uint16_t reserved_2 : 1;
uint16_t set_max : 1;
uint16_t acoustics : 1;
uint16_t big_lba : 1;
uint16_t device_config_overlay : 1;
uint16_t flush_cache : 1;
uint16_t flush_cache_ext : 1;
uint16_t resrved_3 : 1;
uint16_t words_119_120_valid : 1;
uint16_t smart_error_log : 1;
uint16_t smart_self_test : 1;
uint16_t media_serial_number : 1;
uint16_t media_card_pass_through : 1;
uint16_t streaming_feature : 1;
uint16_t gp_logging : 1;
uint16_t write_fua : 1;
uint16_t write_queued_fua : 1;
uint16_t wwn_64_bit : 1;
uint16_t urg_read_stream : 1;
uint16_t urg_write_stream : 1;
uint16_t reserved_for_tech_report : 2;
uint16_t idle_with_unload_feature : 1;
uint16_t reserved_4 : 2;
} command_set_active;
uint16_t ultra_dma_support : 8;
uint16_t ultra_dma_active : 8;
struct {
uint16_t time_required : 15;
uint16_t extended_time_reported : 1;
} normal_security_erase_unit;
struct {
uint16_t time_required : 15;
uint16_t extended_time_reported : 1;
} enhanced_security_erase_unit;
uint16_t current_apm_level : 8;
uint16_t reserved_word_91 : 8;
uint16_t master_password_id;
uint16_t hardware_reset_result;
uint16_t current_acoustic_value : 8;
uint16_t recommended_acoustic_value : 8;
uint16_t stream_min_request_size;
uint16_t streaming_transfer_time_dma;
uint16_t streaming_access_latency_dmapio;
uint32_t streaming_perf_granularity;
uint32_t max_48_bit_lba_2;
uint16_t streaming_transfer_time;
uint16_t dsm_cap;
struct {
uint16_t logical_sectors_per_physical_sector : 4;
uint16_t reserved_0 : 8;
uint16_t logical_sector_longer_than_256_words : 1;
uint16_t multiple_logical_sectors_per_physical_sector : 1;
uint16_t reserved_1 : 2;
} physical_logical_sector_size;
uint16_t inter_seek_delay;
uint16_t world_wide_name[4];
uint16_t reserved_for_world_wide_name_128[4];
uint16_t reserved_for_tlc_technical_report;
uint16_t words_per_logical_sector[2];
struct {
uint16_t reserved_for_drq_technical_report : 1;
uint16_t write_read_verify : 1;
uint16_t write_uncorrectable_ext : 1;
uint16_t read_write_log_dma_ext : 1;
uint16_t download_microcode_mode_3 : 1;
uint16_t freefall_control : 1;
uint16_t sense_data_reporting : 1;
uint16_t extended_power_conditions : 1;
uint16_t reserved_0 : 6;
uint16_t word_valid : 2;
} command_set_support_ext;
struct {
uint16_t reserved_for_drq_technical_report : 1;
uint16_t write_read_verify : 1;
uint16_t write_uncorrectable_ext : 1;
uint16_t read_write_log_dma_ext : 1;
uint16_t download_microcode_mode_3 : 1;
uint16_t freefall_control : 1;
uint16_t sense_data_reporting : 1;
uint16_t extended_power_conditions : 1;
uint16_t reserved_0 : 6;
uint16_t reserved_1 : 2;
} command_set_active_ext;
uint16_t reserved_for_expanded_supportand_active[6];
uint16_t msn_support : 2;
uint16_t reserved_word_127 : 14;
struct {
uint16_t security_supported : 1;
uint16_t security_enabled : 1;
uint16_t security_locked : 1;
uint16_t security_frozen : 1;
uint16_t security_count_expired : 1;
uint16_t enhanced_security_erase_supported : 1;
uint16_t reserved_0 : 2;
uint16_t security_level : 1;
uint16_t reserved_1 : 7;
} security_status;
uint16_t reserved_word_129[31];
struct {
uint16_t maximum_current_in_ma : 12;
uint16_t cfa_power_mode_1_disabled : 1;
uint16_t cfa_power_mode_1_required : 1;
uint16_t reserved_0 : 1;
uint16_t word_160_supported : 1;
} cfa_power_mode_1;
uint16_t reserved_for_cfa_word_161[7];
uint16_t nominal_form_factor : 4;
uint16_t reserved_word_168 : 12;
struct {
uint16_t supports_trim : 1;
uint16_t reserved_0 : 15;
} data_set_management_feature;
uint16_t additional_product_id[4];
uint16_t reserved_for_cfa_word_174[2];
uint16_t current_media_serial_number[30];
struct {
uint16_t supported : 1;
uint16_t reserved_0 : 1;
uint16_t write_same_suported : 1;
uint16_t error_recovery_control_supported : 1;
uint16_t feature_control_suported : 1;
uint16_t data_tables_suported : 1;
uint16_t reserved_1 : 6;
uint16_t vendor_specific : 4;
} sct_command_transport;
uint16_t reserved_word_207[2];
struct {
uint16_t alignment_of_logical_within_physical : 14;
uint16_t word_209_supported : 1;
uint16_t reserved_0 : 1;
} block_alignment;
uint16_t write_read_verify_sector_count_mode_3_only[2];
uint16_t write_read_verify_sector_count_mode_2_only[2];
struct {
uint16_t nv_cache_power_mode_enabled : 1;
uint16_t reserved_0 : 3;
uint16_t nv_cache_feature_set_enabled : 1;
uint16_t reserved_1 : 3;
uint16_t nv_cache_power_mode_version : 4;
uint16_t nv_cache_feature_set_version : 4;
} nv_cache_capabilities;
uint16_t nv_cache_size_lsw;
uint16_t nv_cache_size_msw;
uint16_t nominal_media_rotation_rate;
uint16_t reserved_word_218;
struct {
uint8_t nv_cache_estimated_time_to_spin_up_in_seconds;
uint8_t reserved;
} nv_cache_options;
uint16_t write_read_verify_sector_count_mode : 8;
uint16_t reserved_word_220 : 8;
uint16_t reserved_word_221;
struct {
uint16_t major_version : 12;
uint16_t transport_type : 4;
} transport_major_version;
uint16_t transport_minor_version;
uint16_t reserved_word_224[6];
uint32_t extended_number_of_user_addressable_sectors[2];
uint16_t min_blocks_per_download_microcode_mode_03;
uint16_t max_blocks_per_download_microcode_mode_03;
uint16_t reserved_word_236[19];
uint16_t signature : 8;
uint16_t check_sum : 8;
} __packed;
struct scsi_read_capacity_data {
uint32_t last_sector;
uint32_t block_size;
} __packed;
struct rfis_data {
struct fis_dma_setup dma_setup;
char pad0[4];
struct fis_pio_setup pio_setup;
char pad1[12];
struct fis_reg_d2h reg_d2h;
} __packed;
struct ahci_device {
int port_no;
int type;
volatile struct hba_port *port;
struct hba_cmd_header cmd_header[32];
union {
char rfis_data[256];
struct rfis_data rfis;
};
};
/* struct scsi_command /must/ be exactly 16 bytes long, so that it fits properly
within struct hba_cmd_table */
_Static_assert(sizeof(struct scsi_command) == 16, "ahci: scsi_command must be 16 bytes");
_Static_assert(sizeof(struct fis_dma_setup) == 28, "ahci: fis_dma_setup must be 28 bytes");
_Static_assert(sizeof(struct fis_pio_setup) == 20, "ahci: fis_pio_set must be 20 bytes");
_Static_assert(sizeof(struct fis_reg_d2h) == 20, "ahci: fis_reg_d2h must be 20 bytes");
_Static_assert(offsetof(struct rfis_data, dma_setup) == 0, "offsetof dma_setup in rfis_data must be 0x00");
_Static_assert(offsetof(struct rfis_data, pio_setup) == 0x20, "offsetof dma_setup in rfis_data must be 0x20");
_Static_assert(offsetof(struct rfis_data, reg_d2h) == 0x40, "offsetof dma_setup in rfis_data must be 0x40");
extern struct driver *ahci_driver(void);
extern kern_status_t identify_ata_device(struct ahci_device *dev, struct identify_device_data *out);
extern kern_status_t identify_atapi_device(struct ahci_device *dev, struct identify_device_data *out);
extern kern_status_t send_ata_command(struct ahci_device *dev, unsigned int cmd, struct iovec *vec, size_t nvec);
extern kern_status_t send_ata_command_ex(struct ahci_device *dev, struct fis_reg_h2d *fis, unsigned int cmd, struct iovec *vec, size_t nvec);
extern kern_status_t send_atapi_command(struct ahci_device *dev, struct scsi_command *cmd, struct iovec *vec, size_t nvec);
extern kern_status_t send_atapi_command_ex(struct ahci_device *dev, struct fis_reg_h2d *fis, struct scsi_command *cmd, struct iovec *vec, size_t nvec);
extern void rebase_ahci_port(struct ahci_device *dev);
extern void probe_ahci_ports(struct driver *driver, struct device *controller, volatile struct hba_config *abar,
void(*callback)(int, struct device *, volatile struct hba_port *, int));
extern void create_device_from_ahci_port(int port_no, struct device *controller, volatile struct hba_port *port, int type);
#endif

View File

@@ -1,49 +0,0 @@
#include <socks/device.h>
#include "ahci.h"
kern_status_t ata_read_blocks(struct device *dev, sectors_t offset, size_t *count, struct iovec *vec, size_t nvec, socks_flags_t flags)
{
struct fis_reg_h2d fis = {0};
size_t c = *count;
c &= 0xFFFF;
fis.fis_type = FIS_TYPE_REG_H2D;
fis.count_l = (c & 0xFFu);
fis.count_h = (c >> 8) & 0xFFu;
fis.lba0 = offset & 0xFFu;
fis.lba1 = (offset >> 8) & 0xFFu;
fis.lba2 = (offset >> 16) & 0xFFu;
fis.lba3 = (offset >> 24) & 0xFFu;
fis.lba4 = (offset >> 32) & 0xFFu;
fis.lba5 = (offset >> 40) & 0xFFu;
fis.device = 1 << 6;
struct ahci_device *ahci_dev = dev->dev_priv;
kern_status_t status = send_ata_command_ex(ahci_dev, &fis, ATA_CMD_READ_DMA_EX, vec, nvec);
if (status == KERN_OK) {
*count = c;
} else {
*count = 0;
}
return status;
}
kern_status_t ata_write_blocks(struct device *dev, sectors_t offset, size_t *count, struct iovec *vec, size_t nvec, socks_flags_t flags)
{
return KERN_UNSUPPORTED;
}
kern_status_t ata_ioctl(struct device *dev, unsigned int req, void *argp)
{
return KERN_UNSUPPORTED;
}
struct block_device_ops ata_device_ops = {
.read_blocks = ata_read_blocks,
.write_blocks = ata_write_blocks,
.ioctl = ata_ioctl,
};

View File

@@ -1,22 +0,0 @@
#include <socks/device.h>
kern_status_t atapi_read_blocks(struct device *dev, sectors_t offset, size_t *count, struct iovec *vec, size_t nvec, socks_flags_t flags)
{
return KERN_UNSUPPORTED;
}
kern_status_t atapi_write_blocks(struct device *dev, sectors_t offset, size_t *count, struct iovec *vec, size_t nvec, socks_flags_t flags)
{
return KERN_UNSUPPORTED;
}
kern_status_t atapi_ioctl(struct device *dev, unsigned int req, void *argp)
{
return KERN_UNSUPPORTED;
}
struct block_device_ops atapi_device_ops = {
.read_blocks = atapi_read_blocks,
.write_blocks = atapi_write_blocks,
.ioctl = atapi_ioctl,
};

View File

@@ -1,77 +0,0 @@
#include <socks/device.h>
#include <socks/util.h>
#include <socks/printk.h>
#include <socks/libc/stdio.h>
#include "ahci.h"
extern struct block_device_ops ata_device_ops;
extern struct block_device_ops atapi_device_ops;
extern void create_device_from_ahci_port(int port_no, struct device *controller, volatile struct hba_port *port, int type)
{
struct block_device *bdev = block_device_create();
if (!bdev) {
return;
}
struct device *bdev_base = block_device_base(bdev);
struct ahci_device *ahci_dev = kmalloc(sizeof *ahci_dev, VM_NORMAL);
if (!ahci_dev) {
device_deref(bdev_base);
return;
}
ahci_dev->port = port;
ahci_dev->port_no = port_no;
ahci_dev->type = type;
bdev_base->dev_priv = ahci_dev;
rebase_ahci_port(ahci_dev);
snprintf(bdev_base->dev_name, sizeof bdev_base->dev_name, "ahci%d", port_no);
if (type == AHCI_DEV_SATA) {
struct identify_device_data identity_data = {0};
kern_status_t status = identify_ata_device(ahci_dev, &identity_data);
if (status != KERN_OK) {
kfree(ahci_dev);
device_deref(bdev_base);
return;
}
/* TODO read IDENTIFY DEVICE log to support non-512 sector sizes */
bdev->b_ops = &ata_device_ops;
bdev->b_sector_size = 512;
bdev->b_capacity = identity_data.user_addressable_sectors;
snprintf(bdev_base->dev_model_name, sizeof bdev_base->dev_model_name, "%s", identity_data.model_number);
} else if (type == AHCI_DEV_SATAPI) {
struct identify_device_data identity_data = {0};
kern_status_t status = identify_atapi_device(ahci_dev, &identity_data);
if (status != KERN_OK) {
kfree(ahci_dev);
device_deref(bdev_base);
return;
}
struct scsi_command cmd = {0};
cmd.cmd = SCSI_CMD_READ_CAPACITY;
struct scsi_read_capacity_data cmd_result = {0};
struct iovec vec = { .io_buf = &cmd_result, .io_len = sizeof cmd_result };
status = send_atapi_command(ahci_dev, &cmd, &vec, 1);
if (status != KERN_OK) {
printk("ahci: failed to contact ATAPI device: %s", kern_status_string(status));
return;
}
bdev->b_ops = &atapi_device_ops;
bdev->b_sector_size = big_to_host_u32(cmd_result.block_size);
bdev->b_capacity = big_to_host_u32(cmd_result.last_sector) + 1;
snprintf(bdev_base->dev_model_name, sizeof bdev_base->dev_model_name, "%s", identity_data.model_number);
}
device_register(bdev_base, ahci_driver(), controller);
}

View File

@@ -1,13 +0,0 @@
name: ahci
description: |
AHCI (SATA) disk driver
id: net.doorstuck.socks.ahci
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- main.c
- device.c
- ahci.c
- ata.c
- atapi.c
- ahci.h

View File

@@ -1,80 +0,0 @@
#include <socks/printk.h>
#include <socks/pci.h>
#include <socks/device.h>
#include <socks/kext.h>
#include <socks/pci.h>
#include <socks/util.h>
#include <socks/machine/init.h>
#include <socks/libc/stdio.h>
#include <socks/libc/ctype.h>
#include <arch/irq.h>
#include "ahci.h"
static struct pci_driver *__ahci_driver = NULL;
static volatile struct hba_config *hba_config = NULL;
static int irq_callback(void);
static struct irq_hook irq_hook = {
.irq_callback = irq_callback,
};
static struct pci_device_id ahci_device_ids[] = {
PCI_CLASS_ID(0x01, 0x06),
PCI_DEVICE_ID_INVALID,
};
struct driver *ahci_driver(void)
{
return pci_driver_base(__ahci_driver);
}
static kern_status_t ahci_scan(struct device *ahci_bus)
{
struct pci_device *pci_dev = device_get_pci_info(ahci_bus);
printk("ahci: probing ports on ahci controller at pci%04x:%02x.%02u", pci_dev->pci_bus, pci_dev->pci_slot, pci_dev->pci_func);
uint32_t abar = pci_device_read_field(ahci_bus, PCI_REG_BAR5, 4);
hba_config = vm_phys_to_virt(abar);
probe_ahci_ports(pci_driver_base(__ahci_driver), ahci_bus, hba_config, create_device_from_ahci_port);
return KERN_OK;
}
static struct bus_device_ops ahci_bus_ops = {
.scan = ahci_scan,
};
static int irq_callback(void)
{
printk("ahci: received IRQ");
return 0;
}
static kern_status_t ahci_probe(struct pci_driver *driver, struct device *dev)
{
struct bus_device *ahci_bus = bus_device_from_generic(dev);
ahci_bus->b_ops = &ahci_bus_ops;
snprintf(dev->dev_name, sizeof dev->dev_name, "ahci");
uint8_t irq_vec = pci_device_read_field(dev, PCI_REG_INTERRUPT_LINE, 1);
hook_irq(IRQ0 + irq_vec, &irq_hook);
return device_register(dev, pci_driver_base(__ahci_driver), NULL);
}
static kern_status_t online(struct kext *self)
{
printk("ahci: registering AHCI driver");
__ahci_driver = pci_driver_create(self, "ahci", ahci_device_ids);
if (!__ahci_driver) {
return KERN_NO_MEMORY;
}
__ahci_driver->probe = ahci_probe;
pci_driver_register(__ahci_driver);
return KERN_OK;
}
DEFINE_KEXT("net.doorstuck.socks.ahci",
online, NULL,
PCI_SUBSYSTEM_KEXT_ID);

View File

@@ -1,31 +0,0 @@
#include <arch/acpi.h>
#include <socks/printk.h>
#include <socks/device.h>
#include <socks/kext.h>
#include <socks/libc/stdio.h>
static kern_status_t acpi_bus_scan(struct device *dev)
{
return KERN_OK;
}
static struct bus_device_ops acpi_ops = {
.scan = acpi_bus_scan,
};
kern_status_t acpi_init(void)
{
apic_init();
smp_init();
struct bus_device *acpi_dev = bus_device_create();
struct device *base = bus_device_base(acpi_dev);
acpi_dev->b_ops = &acpi_ops;
snprintf(base->dev_name, sizeof base->dev_name, "acpi");
device_register(base, system_driver(), root_device());
return KERN_OK;
}
DEFINE_KEXT("net.doorstuck.socks.acpi", NULL, NULL, KEXT_NO_DEPENDENCIES);

View File

@@ -1,107 +0,0 @@
.global acpi_ap_lapic_id
.type acpi_ap_lapic_id, @function
acpi_ap_lapic_id:
push %rbp
mov %rsp, %rbp
push %rbx
mov $0x00000001, %eax
cpuid
shrq $0x18, %rbx
mov %rbx, %rax
pop %rbx
pop %rbp
ret
.extern __ap_stack_top
.extern __bsp_done
.extern __this_ap_ok
.extern __all_ap_ok
.extern ap_startup
.type ap_startup, @function
.global ap_trampoline
# this code will be relocated to 0x8000, sets up environment for calling a C function
.code16
.align 0x100
ap_trampoline:
cli
cld
ljmp $0, $0x8080
.align 16
_L8010_GDT_table:
.long 0, 0
.long 0x0000FFFF, 0x00CF9A00 # flat code
.long 0x0000FFFF, 0x008F9200 # flat data
.long 0x00000068, 0x00CF8900 # tss
_L8030_GDT_value:
.word _L8030_GDT_value - _L8010_GDT_table - 1
.long 0x8010
.long 0, 0
.align 64
_L8040_GDT64_table:
.long 0, 0
.long 0x0000ffff, 0x002f9a00 # kernel code
.long 0x0000ffff, 0x002f9200 # kernel data
_L8058_GDT64_value:
.word _L8058_GDT64_value - _L8040_GDT64_table - 1
.quad 0x8040
.align 64
_L8080:
xorw %ax, %ax
movw %ax, %ds
lgdtl 0x8030
movl %cr0, %eax
orl $1, %eax
movl %eax, %cr0
ljmp $8, $0x80a0
.align 32
.code32
_L80A0:
movw $16, %ax
movw %ax, %ds
movw %ax, %ss
# get our Local APIC ID
mov $1, %eax
cpuid
shrl $24, %ebx
movl %ebx, %edi
movl %cr4, %eax
orl $0x20, %eax
movl %eax, %cr4
movl $0x8ff8, %eax
movl (%eax), %eax
mov %eax, %cr3
movl $0xC0000080, %ecx
rdmsr
# enable long mode, syscall/sysret, and NX protection
orl $0x00000901, %eax
wrmsr
movl $0x8058, %eax
lgdt (%eax)
movl %cr0, %ecx
orl $0x8000002a, %ecx
movl %ecx, %cr0
ljmpl $0x08, $0x8100
.code64
.align 64
_L8100:
mov (__ap_stack_top), %rsp
movabsq $(ap_trampoline_exit), %rax
callq *%rax
hlt

View File

@@ -1,229 +0,0 @@
#include <socks/printk.h>
#include <socks/clock.h>
#include <socks/vm.h>
#include <socks/cpu.h>
#include <arch/acpi/io_apic.hpp>
#include <arch/acpi/local_apic.hpp>
#include <arch/acpi.h>
#include <arch/msr.h>
#include <arch/ports.h>
#include <arch/pit.h>
#define PIC1_DATA 0x21
#define PIC2_DATA 0xA1
#define IA32_APIC_BASE_MSR 0x1B
#define IA32_APIC_BASE_MSR_BSP 0x100
#define IA32_APIC_BASE_MSR_ENABLE 0x800
static int apic_enabled = 0;
static unsigned int bsp_id = (unsigned int)-1;
using namespace arch::acpi;
static struct queue io_apics;
extern "C" {
/* defined in apic_ctrl.S */
extern int check_apic(void);
}
static uintptr_t apic_get_base(void)
{
return rdmsr(IA32_APIC_BASE_MSR);
}
static void apic_set_base(uintptr_t addr)
{
wrmsr(IA32_APIC_BASE_MSR, addr);
}
static void disable_8259(void)
{
/* mask all interrupts on PICs 1 and 2 */
outportb(PIC1_DATA, 0xFF);
outportb(PIC2_DATA, 0xFF);
}
kern_status_t local_apic_enable(struct acpi_madt *madt)
{
apic_set_base(apic_get_base());
local_apic::find(madt, local_apic::get());
local_apic::get().write(0xF0, 0x1FF);
local_apic::get().ack();
return KERN_OK;
}
static io_apic *get_ioapic_for_irq(unsigned int vec)
{
queue_foreach (io_apic, ioapic, &io_apics, io_entry) {
if (vec >= ioapic->io_first_irq && vec < ioapic->io_first_irq + ioapic->io_nr_irq) {
return ioapic;
}
}
return nullptr;
}
static void configure_legacy_pic(void)
{
printk("acpi: APIC unavailable");
pit_start(HZ);
}
static void ioapic_init(uintptr_t base, unsigned int int_base)
{
uint32_t *base_vaddr = (uint32_t *)vm_phys_to_virt(base);
io_apic *apic = kmalloc_object(io_apic, VM_NORMAL, base_vaddr, int_base);
//printk("acpi: I/O APIC at 0x%llx; base=%u, irqs=%u", base, int_base, apic->io_nr_irq);
for (unsigned int i = 0; i < apic->io_nr_irq; i++) {
apic->map_irq(i, 32 + int_base + i);
}
queue_push_back(&io_apics, &apic->io_entry);
}
static int lapic_clock_irq(void)
{
if (this_cpu() == bsp_id) {
clock_advance(1);
}
return 0;
}
static struct irq_hook lapic_clock_irq_hook = {
{},
lapic_clock_irq,
};
void local_apic_config_timer(bool bsp)
{
local_apic& lapic = local_apic::get();
lapic.write(local_apic::TIMER_DIV, 0x3);
lapic.write(local_apic::TIMER_INITCOUNT, (uint32_t)-1);
clock_wait(10);
lapic.write(local_apic::LVT_TIMER, APIC_LVT_INT_MASKED);
if (bsp) {
/* mask IRQ0 to block interrupts from the PIT. */
io_apic *irq0_apic = get_ioapic_for_irq(0);
irq0_apic->mask_irq(0);
}
uint32_t total_ticks = 0xFFFFFFFF - lapic.read(local_apic::TIMER_CURCOUNT);
/* convert to LAPIC ticks per kernel clock tick */
total_ticks /= 10;
lapic.write(local_apic::LVT_TIMER, IRQ0 | APIC_LVT_TIMER_MODE_PERIODIC);
lapic.write(local_apic::TIMER_DIV, 0x3);
lapic.write(local_apic::TIMER_INITCOUNT, total_ticks);
}
static void parse_legacy_irq_override(struct acpi_madt *madt)
{
unsigned char *p = (unsigned char *)madt + sizeof *madt;
unsigned char *madt_end = (unsigned char *)madt + madt->m_base.s_length;
while (p < madt_end) {
struct acpi_madt_record *rec = (struct acpi_madt_record *)p;
struct acpi_madt_irqsrc_override*irq;
io_apic *handler = nullptr;
switch (rec->r_type) {
case ACPI_MADT_IRQSRC_OVERRIDE:
irq = (struct acpi_madt_irqsrc_override *)(rec + 1);
handler = get_ioapic_for_irq(irq->irq_srcvec);
handler->map_irq(irq->irq_srcvec, 32 + irq->irq_destvec);
break;
default:
break;
}
p += rec->r_length;
}
}
static void init_all_ioapic(struct acpi_madt *madt)
{
unsigned char *p = (unsigned char *)madt + sizeof *madt;
unsigned char *madt_end = (unsigned char *)madt + madt->m_base.s_length;
while (p < madt_end) {
struct acpi_madt_record *rec = (struct acpi_madt_record *)p;
struct acpi_madt_ioapic *ioapic;
switch (rec->r_type) {
case ACPI_MADT_IOAPIC:
ioapic = (struct acpi_madt_ioapic *)(rec + 1);
ioapic_init(ioapic->io_address, ioapic->io_intbase);
break;
default:
break;
}
p += rec->r_length;
}
parse_legacy_irq_override(madt);
}
kern_status_t ap_apic_init(void)
{
struct acpi_madt *madt = (struct acpi_madt *)acpi_find_sdt(ACPI_SIG_MADT);
local_apic_enable(madt);
//irq_enable();
local_apic_config_timer(false);
return KERN_OK;
}
/* only the bootstrap processor should call apic_init()
all other APs should call ap_apic_init() instead */
kern_status_t apic_init(void)
{
struct acpi_madt *madt = (struct acpi_madt *)acpi_find_sdt(ACPI_SIG_MADT);
if (check_apic() == 0 || !madt) {
configure_legacy_pic();
return KERN_UNSUPPORTED;
}
bsp_id = this_cpu();
init_all_ioapic(madt);
local_apic_enable(madt);
disable_8259();
apic_enabled = 1;
irq_enable();
pit_start(HZ);
local_apic_config_timer(true);
pit_stop();
hook_irq(IRQ0, &lapic_clock_irq_hook);
return KERN_OK;
}
void irq_ack(unsigned int vec)
{
if (apic_enabled) {
local_apic::get().ack();
} else {
if (vec >= 40) {
outportb(0xA0, 0x20);
}
outportb(0x20, 0x20);
}
}

View File

@@ -1,18 +0,0 @@
.global check_apic
.type check_apic, @function
check_apic:
push %rbp
mov %rsp, %rbp
push %rbx
mov $1, %rax
cpuid
andl $0x200, %edx
shr $9, %edx
mov %rdx, %rax
pop %rbx
pop %rbp
ret

View File

@@ -1,15 +0,0 @@
name: acpi
description: |
ACPI bus and SMP driver.
id: net.doorstuck.socks.acpi
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- acpi.c
- apic_ctrl.S
- local_apic.cpp
- smp.cpp
- apic.cpp
- ap_trampoline.S
- io_apic.cpp
- rsdp.c

View File

@@ -1,126 +0,0 @@
#ifndef ARCH_ACPI_H_
#define ARCH_ACPI_H_
#include <socks/compiler.h>
#include <socks/status.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ACPI_MADT_LAPIC 0x00
#define ACPI_MADT_IOAPIC 0x01
#define ACPI_MADT_IRQSRC_OVERRIDE 0x02
#define ACPI_MADT_LAPIC_OVERRIDE 0x05
#define ACPI_SIG_RSDP 0x2052545020445352ULL
#define ACPI_SIG_FADT 0x50434146
#define ACPI_SIG_MADT 0x43495041
#define AP_TRAMPOLINE_PADDR 0x8000
#define LAPIC_IPI_STATUS_REG 0x0280
#define LAPIC_IPI_DEST_REG 0x0310
#define LAPIC_IPI_ICR_REG 0x0300
struct acpi_rsdp_10 {
char r_sig[8];
uint8_t r_chksum;
char r_oem[6];
uint8_t r_revision;
uint32_t r_rsdt_ptr;
} __packed;
struct acpi_rsdp_20 {
struct acpi_rsdp_10 r_base;
uint32_t r_length;
uint64_t r_xsdt_ptr;
uint8_t r_chksum_ext;
uint8_t r_reserved[3];
} __packed;
struct acpi_rsdp {
union {
struct acpi_rsdp_10 rsdp_10;
struct acpi_rsdp_20 rsdp_20;
};
} __packed;
struct acpi_sdt {
char s_sig[4];
uint32_t s_length;
uint8_t s_revision;
uint8_t s_chksum;
char s_oem[6];
char s_oem_table[8];
uint32_t s_oem_revision;
uint32_t s_creator;
uint32_t s_creator_revision;
} __packed;
struct acpi_rsdt {
struct acpi_sdt r_header;
uint32_t r_tables[1];
} __packed;
struct acpi_xsdt {
struct acpi_sdt x_header;
uint64_t x_tables[1];
} __packed;
struct acpi_madt {
struct acpi_sdt m_base;
uint32_t m_lapic_ptr;
uint32_t m_flags;
} __packed;
struct acpi_madt_record {
uint8_t r_type;
uint8_t r_length;
} __packed;
struct acpi_madt_ioapic {
uint8_t io_apic_id;
uint8_t io_reserved;
uint32_t io_address;
uint32_t io_intbase;
} __packed;
struct acpi_madt_irqsrc_override {
uint8_t irq_bus;
/* the irq vector as delivered from the APIC to the CPU */
uint8_t irq_destvec;
/* the irq vector as delivered from the hardware to the APIC */
uint32_t irq_srcvec;
uint16_t irq_flags;
} __packed;
struct lapic_record {
uint8_t l_cpu_id;
uint8_t l_apic_id;
uint32_t l_flags;
} __packed;
struct lapic_override_record {
uint16_t l_reserved;
uint64_t l_lapic_ptr;
} __packed;
extern kern_status_t acpi_init(void);
extern kern_status_t acpi_scan_cpu_topology(void);
extern kern_status_t ap_apic_init(void);
extern kern_status_t apic_init(void);
extern kern_status_t smp_init(void);
extern struct acpi_sdt *acpi_find_sdt(uint32_t sig);
extern void irq_ack(unsigned int vec);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,41 +0,0 @@
#ifndef ARCH_ACPI_IOAPIC_HPP_
#define ARCH_ACPI_IOAPIC_HPP_
#include <stdint.h>
#include <socks/status.h>
#include <socks/queue.h>
namespace arch::acpi {
struct io_apic {
uint32_t *io_base = nullptr;
unsigned int io_first_irq = 0;
unsigned int io_nr_irq = 0;
struct queue_entry io_entry;
struct irq_entry {
uint64_t irq_vec : 8;
uint64_t irq_delivery : 3;
uint64_t irq_destmode : 1;
uint64_t irq_status : 1;
uint64_t irq_polarity : 1;
uint64_t irq_irr : 1;
uint64_t irq_triggermode : 1;
uint64_t irq_mask : 1;
uint64_t irq_resv : 39;
uint64_t irq_dest : 8;
};
io_apic(uint32_t *base, unsigned int first_irq);
uint32_t read(uint32_t reg);
void write(uint32_t reg, uint32_t val);
kern_status_t read_irq(unsigned int index, irq_entry &entry);
void write_irq(unsigned int index, const irq_entry &entry);
void map_irq(unsigned int src, unsigned int dest, unsigned int dest_cpu = 0);
void mask_irq(unsigned int vec);
void unmask_irq(unsigned int vec, unsigned int dest_cpu = (unsigned int)-1);
};
}
#endif

View File

@@ -1,43 +0,0 @@
#ifndef ARCH_ACPI_LOCAL_APIC_HPP_
#define ARCH_ACPI_LOCAL_APIC_HPP_
#include <socks/status.h>
#include <stdint.h>
#define APIC_LVT_INT_MASKED 0x10000
#define APIC_LVT_TIMER_MODE_PERIODIC 0x20000
struct acpi_madt;
namespace arch::acpi {
class local_apic {
uint32_t *base_ = nullptr;
public:
enum {
EOI = 0xB0,
IPI_STATUS = 0x280,
IPI_ICR = 0x300,
IPI_DEST = 0x310,
LVT_TIMER = 0x320,
TIMER_INITCOUNT = 0x380,
TIMER_CURCOUNT = 0x390,
TIMER_DIV = 0x3E0,
};
local_apic(uint32_t *base = nullptr);
static kern_status_t find(struct acpi_madt *madt, local_apic& out);
static local_apic& get(void);
uint32_t read(uint32_t reg);
void write(uint32_t reg, uint32_t val);
void ack();
uint32_t *ptr() const { return base_; }
void send_ipi(unsigned int dest, unsigned int data);
};
}
#endif

View File

@@ -1,91 +0,0 @@
#include <socks/compiler.h>
#include <socks/printk.h>
#include <arch/acpi/io_apic.hpp>
#define IOAPICID 0x00
#define IOAPICVER 0x01
#define IOAPICARB 0x02
#define IOAPICREDTBL(n) (0x10 + 2 * n)
namespace arch::acpi {
io_apic::io_apic(uint32_t *base, unsigned int first_irq) : io_base(base), io_first_irq(first_irq)
{
io_nr_irq = ((read(IOAPICVER) >> 16) + 1) & 0xFF;
}
uint32_t io_apic::read(uint32_t reg)
{
write_once(io_base, reg & 0xFF);
return read_once(io_base + 4);
}
void io_apic::write(uint32_t reg, uint32_t val)
{
write_once(io_base, reg & 0xFF);
write_once(io_base + 4, val);
}
kern_status_t io_apic::read_irq(unsigned int index, irq_entry &entry)
{
if (index >= io_nr_irq) {
return KERN_NO_ENTRY;
}
uint32_t *entry_data = (uint32_t *)&entry;
entry_data[0] = read(IOAPICREDTBL(index));
entry_data[1] = read(IOAPICREDTBL(index) + 1);
return KERN_OK;
}
void io_apic::write_irq(unsigned int index, const irq_entry &entry)
{
if (index >= io_nr_irq) {
return;
}
const uint32_t *entry_data = (const uint32_t *)&entry;
write(IOAPICREDTBL(index), entry_data[0]);
write(IOAPICREDTBL(index) + 1, entry_data[1]);
}
void io_apic::map_irq(unsigned int src, unsigned int dest, unsigned int dest_cpu)
{
io_apic::irq_entry irq{};
irq.irq_vec = dest;
irq.irq_dest = dest_cpu;
irq.irq_delivery = 0;
irq.irq_destmode = 0;
irq.irq_polarity = 0;
irq.irq_triggermode = 0;
irq.irq_mask = 0;
write_irq(src, irq);
}
void io_apic::mask_irq(unsigned int vec)
{
irq_entry irq;
if (read_irq(vec, irq) != KERN_OK) {
return;
}
irq.irq_mask = 1;
write_irq(vec, irq);
}
void io_apic::unmask_irq(unsigned int vec, unsigned int dest_cpu)
{
irq_entry irq;
if (read_irq(vec, irq) != KERN_OK) {
return;
}
irq.irq_mask = 0;
if (dest_cpu != (unsigned int)-1) {
irq.irq_dest = dest_cpu;
}
write_irq(vec, irq);
}
}

View File

@@ -1,75 +0,0 @@
#include <arch/acpi/local_apic.hpp>
#include <arch/acpi.h>
#include <socks/vm.h>
#include <socks/compiler.h>
#define LAPIC_REG_EOI 0xB0
namespace arch::acpi {
static local_apic lapic;
local_apic::local_apic(uint32_t *base) : base_(base)
{
}
kern_status_t local_apic::find(struct acpi_madt *madt, local_apic& out)
{
phys_addr_t local_apic = madt->m_lapic_ptr;
unsigned char *p = (unsigned char *)madt + sizeof *madt;
unsigned char *madt_end = (unsigned char *)madt + madt->m_base.s_length;
while (p < madt_end) {
struct acpi_madt_record *rec = (struct acpi_madt_record *)p;
struct lapic_override_record *lapic;
switch (rec->r_type) {
case ACPI_MADT_LAPIC_OVERRIDE:
lapic = (struct lapic_override_record *)(rec + 1);
out.base_ = (uint32_t *)vm_phys_to_virt(lapic->l_lapic_ptr);
return KERN_OK;
default:
break;
}
p += rec->r_length;
}
out.base_ = (uint32_t *)vm_phys_to_virt(local_apic);
return KERN_OK;
}
uint32_t local_apic::read(uint32_t reg)
{
return read_once(base_ + (reg >> 2));
}
void local_apic::write(uint32_t reg, uint32_t val)
{
write_once(base_ + (reg >> 2), val);
}
void local_apic::ack()
{
write(LAPIC_REG_EOI, 0);
}
void local_apic::send_ipi(unsigned int dest, unsigned int data)
{
uint32_t dest_val = (read(IPI_DEST) & 0x00FFFFFF) | (dest << 24);
write(IPI_STATUS, 0);
write(IPI_DEST, dest_val);
uint32_t icr_val = (read(IPI_ICR) & 0xFFF00000) | data;
write(IPI_ICR, icr_val);
do {
__asm__ __volatile__("pause" : : : "memory");
} while (read(IPI_ICR) & (1 << 12));
}
local_apic& local_apic::get(void)
{
return lapic;
}
}

View File

@@ -1,99 +0,0 @@
#include <arch/acpi.h>
#include <socks/vm.h>
#include <socks/printk.h>
#include <stddef.h>
static struct acpi_rsdp rsdp;
static struct acpi_rsdp_10 *search_for_rsdp(void)
{
uint64_t *start = vm_phys_to_virt(0x80000);
uint64_t *end = vm_phys_to_virt(0xFFFFF);
for (uint64_t *i = start; i < end; i++) {
if (*i == ACPI_SIG_RSDP) {
return (struct acpi_rsdp_10 *)i;
}
}
return NULL;
}
static int init_rsdt(void)
{
struct acpi_rsdp_10 *x = search_for_rsdp();
if (!x) {
return -1;
}
uint8_t *b = (uint8_t *)x;
size_t chksum = 0;
for (unsigned int i = 0; i < sizeof *x; i++) {
chksum += b[i];
}
if (chksum & 0xFF) {
return -1;
}
if (x->r_revision == 2) {
chksum = 0;
for (unsigned int i = sizeof *x; i < sizeof(struct acpi_rsdp_20); i++) {
chksum += b[i];
}
if (chksum & 0xFF) {
return -1;
}
}
memcpy(&rsdp.rsdp_20, x, sizeof rsdp.rsdp_20);
return 0;
}
static struct acpi_sdt *find_via_rsdt(uint32_t sig)
{
struct acpi_rsdt *rsdt = vm_phys_to_virt(rsdp.rsdp_10.r_rsdt_ptr);
unsigned long nr_tables = (rsdt->r_header.s_length - sizeof(struct acpi_sdt)) / sizeof(uint32_t);
for (unsigned long i = 0; i < nr_tables; i++) {
struct acpi_sdt *table = vm_phys_to_virt(rsdt->r_tables[i]);
if (*(uint32_t *)table == sig) {
return table;
}
}
return NULL;
}
static struct acpi_sdt *find_via_xsdt(uint32_t sig)
{
struct acpi_xsdt *xsdt = vm_phys_to_virt(rsdp.rsdp_20.r_xsdt_ptr);
unsigned long nr_tables = (xsdt->x_header.s_length - sizeof(struct acpi_sdt)) / sizeof(uint64_t);
for (unsigned long i = 0; i < nr_tables; i++) {
struct acpi_sdt *table = vm_phys_to_virt(xsdt->x_tables[i]);
if (*(uint32_t *)table == sig) {
return table;
}
}
return NULL;
}
struct acpi_sdt *acpi_find_sdt(uint32_t sig)
{
if (!rsdp.rsdp_10.r_sig[0]) {
if (init_rsdt() != 0) {
return NULL;
}
}
if (rsdp.rsdp_10.r_revision == 0) {
return find_via_rsdt(sig);
} else {
return find_via_xsdt(sig);
}
}

View File

@@ -1,189 +0,0 @@
#include <arch/acpi.h>
#include <arch/acpi/local_apic.hpp>
#include <socks/printk.h>
#include <socks/pmap.h>
#include <socks/vm.h>
#include <socks/cpu.h>
using namespace arch::acpi;
extern "C" uint8_t acpi_ap_lapic_id(void);
extern "C" char ap_trampoline[];
volatile struct vm_page *__ap_stack_page = NULL;
volatile uintptr_t __ap_stack_top = 0;
volatile uint8_t __this_ap_ok = 0;
volatile uint8_t __all_ap_ok = 0;
extern "C" void ap_trampoline_exit(void)
{
struct vm_page *stack_page = (struct vm_page *)__ap_stack_page;
__this_ap_ok = 1;
ml_cpu_block *this_cpu = (ml_cpu_block *)kmalloc(sizeof *this_cpu, VM_NORMAL);
memset(this_cpu, 0x00, sizeof *this_cpu);
ml_cpu_block_init(this_cpu);
ml_cpu_block_use(this_cpu);
unsigned int cpu_id = acpi_ap_lapic_id();
this_cpu->c_cpu_id = cpu_id;
struct cpu_data *self = get_this_cpu();
memset(self, 0x0, sizeof *self);
self->c_flags = CPU_ONLINE;
self->c_id = cpu_id;
this_cpu->c_data = self;
struct thread *this_thread = create_idle_thread();
this_thread->tr_id = cpu_id;
this_thread->tr_kstack = (struct vm_page *)stack_page;
self->c_rq.rq_idle = self->c_rq.rq_cur = this_thread;
put_cpu(self);
ap_apic_init();
cpu_set_online(cpu_id);
irq_enable();
idle();
}
static int init_ap(struct acpi_madt_record *rec, local_apic& lapic, uint8_t bsp_id)
{
struct lapic_record *ap_lapic = (struct lapic_record *)(rec + 1);
if (!(ap_lapic->l_flags & 0x1) && !(ap_lapic->l_flags & 0x2)) {
return -1;
}
if (ap_lapic->l_apic_id == bsp_id) {
//printk("acpi: core %u online [BSP]", ap_lapic->l_apic_id);
return 0;
}
__this_ap_ok = 0;
__ap_stack_page = vm_page_alloc(VM_PAGE_4K, VM_NORMAL);
__ap_stack_top = (uintptr_t)vm_page_get_vaddr((struct vm_page *)__ap_stack_page) + VM_PAGE_SIZE;
lapic.send_ipi(ap_lapic->l_apic_id, 0xC500);
lapic.send_ipi(ap_lapic->l_apic_id, 0x8500);
milli_sleep(10); // wait 10 msec
lapic.send_ipi(ap_lapic->l_apic_id, 0x4600 | (AP_TRAMPOLINE_PADDR >> VM_PAGE_SHIFT));
do {
ml_cpu_relax();
} while (__this_ap_ok == 0);
//printk("acpi: core %u online [AP]", ap_lapic->l_apic_id);
return 0;
}
kern_status_t bring_all_ap_online(void)
{
struct acpi_madt *madt = (struct acpi_madt *)acpi_find_sdt(ACPI_SIG_MADT);
if (!madt) {
return KERN_UNSUPPORTED;
}
uint8_t bsp_id = acpi_ap_lapic_id();
void *ap_trampoline_dest = vm_phys_to_virt(AP_TRAMPOLINE_PADDR);
memcpy(ap_trampoline_dest, ap_trampoline, VM_PAGE_SIZE);
pmap_t kernel_pmap = get_kernel_pmap();
uint32_t *pmap_ptr = (uint32_t *)vm_phys_to_virt(0x8ff8);
*pmap_ptr = kernel_pmap;
pmap_add(kernel_pmap, (void *)0x8000, 8, (enum vm_prot)(VM_PROT_READ | VM_PROT_EXEC), PMAP_NORMAL);
unsigned char *p = (unsigned char *)madt + sizeof *madt;
unsigned char *madt_end = (unsigned char *)madt + madt->m_base.s_length;
unsigned int nr_processors = 0;
while (p < madt_end) {
struct acpi_madt_record *rec = (struct acpi_madt_record *)p;
switch (rec->r_type) {
case ACPI_MADT_LAPIC:
if (init_ap(rec, local_apic::get(), bsp_id) == 0) {
nr_processors++;
}
break;
default:
break;
}
p += rec->r_length;
}
while (cpu_nr_available() != cpu_nr_online()) {
ml_cpu_relax();
}
printk("acpi: %u APs online", cpu_nr_online());
return KERN_OK;
}
static void no_smp_config(void)
{
cpu_set_available(0);
cpu_set_online(0);
ml_cpu_block *self = ml_this_cpu();
self->c_cpu_id = 0;
}
kern_status_t acpi_scan_cpu_topology(void)
{
struct acpi_madt *madt = (struct acpi_madt *)acpi_find_sdt(ACPI_SIG_MADT);
if (!madt) {
no_smp_config();
return KERN_UNSUPPORTED;
}
uint8_t bsp_id = acpi_ap_lapic_id();
//void *bsp_lapic = find_lapic(madt);
unsigned char *p = (unsigned char *)madt + sizeof *madt;
unsigned char *madt_end = (unsigned char *)madt + madt->m_base.s_length;
unsigned int nr_processors = 0;
while (p < madt_end) {
struct acpi_madt_record *rec = (struct acpi_madt_record *)p;
if (rec->r_type != ACPI_MADT_LAPIC) {
p += rec->r_length;
continue;
}
struct lapic_record *lapic = (struct lapic_record *)(rec + 1);
if (!(lapic->l_flags & 0x1) && !(lapic->l_flags & 0x2)) {
/* processor cannot be used */
continue;
}
cpu_set_available(lapic->l_apic_id);
nr_processors++;
p += rec->r_length;
}
cpu_set_online(bsp_id);
/* store the BSP ID in the current cpu block */
ml_cpu_block *self = ml_this_cpu();
self->c_cpu_id = bsp_id;
printk("acpi: found %u logical cores", nr_processors);
return KERN_OK;
}
kern_status_t smp_init(void)
{
return bring_all_ap_online();
}

View File

@@ -1,124 +0,0 @@
#include <socks/device.h>
#include <socks/printk.h>
#include <socks/pci.h>
static struct vm_cache pci_driver_cache = {
.c_name = "pci_driver",
.c_obj_size = sizeof(struct pci_driver),
};
static struct queue pci_drivers;
static spin_lock_t pci_drivers_lock;
kern_status_t init_pci_driver_cache(void)
{
vm_cache_init(&pci_driver_cache);
pci_drivers = QUEUE_INIT;
pci_drivers_lock = SPIN_LOCK_INIT;
return KERN_OK;
}
struct pci_driver *pci_driver_create(struct kext *self, const char *name, const struct pci_device_id *device_ids)
{
struct pci_driver *driver = vm_cache_alloc(&pci_driver_cache, VM_NORMAL);
if (!driver) {
return NULL;
}
kern_status_t status = driver_init(&driver->pci_base, self, name);
if (status != KERN_OK) {
vm_cache_free(&pci_driver_cache, driver);
return NULL;
}
driver->pci_target_devices = device_ids;
return driver;
}
kern_status_t pci_driver_destroy(struct pci_driver *driver)
{
/* TODO */
return KERN_UNIMPLEMENTED;
}
kern_status_t pci_driver_register(struct pci_driver *driver)
{
kern_status_t status = driver_register(&driver->pci_base);
if (status != KERN_OK) {
return status;
}
unsigned long flags;
spin_lock_irqsave(&pci_drivers_lock, &flags);
queue_push_back(&pci_drivers, &driver->pci_head);
spin_unlock_irqrestore(&pci_drivers_lock, flags);
return KERN_OK;
}
kern_status_t pci_driver_unregister(struct pci_driver *driver)
{
if (driver->pci_base.drv_major == DEV_MAJOR_INVALID) {
return KERN_INVALID_ARGUMENT;
}
unsigned long flags;
spin_lock_irqsave(&pci_drivers_lock, &flags);
queue_delete(&pci_drivers, &driver->pci_head);
spin_unlock_irqrestore(&pci_drivers_lock, flags);
return driver_unregister(&driver->pci_base);
}
static int scan_device_id_list(const struct pci_device_id *device_ids, const struct pci_device_id *query)
{
int best_score = 0;
for (unsigned int i = 0; ; i++) {
if (device_ids[i].pci_device_id == PCI_NONE && device_ids[i].pci_vendor_id == PCI_NONE && device_ids[i].pci_class_id == PCI_CLASS_ANY && device_ids[i].pci_subclass_id == PCI_CLASS_ANY) {
break;
}
int score = 0;
if (device_ids[i].pci_class_id == query->pci_class_id && device_ids[i].pci_subclass_id == query->pci_subclass_id && device_ids[i].pci_vendor_id == PCI_NONE && device_ids[i].pci_device_id == PCI_NONE) {
score = 1;
}
if (device_ids[i].pci_device_id == query->pci_device_id && device_ids[i].pci_vendor_id == query->pci_vendor_id) {
score = 2;
}
if (score > best_score) {
best_score = score;
}
}
return best_score;
}
struct pci_driver *find_driver_for_pci_device(const struct pci_device_id *query)
{
struct pci_driver *best_match = NULL;
int best_score = 0;
unsigned long flags;
spin_lock_irqsave(&pci_drivers_lock, &flags);
queue_foreach (struct pci_driver, driver, &pci_drivers, pci_head) {
const struct pci_device_id *device_ids = driver->pci_target_devices;
if (!device_ids) {
continue;
}
int score = scan_device_id_list(device_ids, query);
if (score > best_score) {
best_score = score;
best_match = driver;
}
}
spin_unlock_irqrestore(&pci_drivers_lock, flags);
return best_match;
}

View File

@@ -1,10 +0,0 @@
name: acpi
description: |
PCI bus driver.
id: net.doorstuck.socks.pci
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- main.c
- pci.c
- driver.c

View File

@@ -1,118 +0,0 @@
#ifndef SOCKS_PCI_H_
#define SOCKS_PCI_H_
#include <socks/device.h>
#include <stdint.h>
#define PCI_REG_VENDOR_ID 0x00 // 2
#define PCI_REG_DEVICE_ID 0x02 // 2
#define PCI_REG_COMMAND 0x04 // 2
#define PCI_REG_STATUS 0x06 // 2
#define PCI_REG_REVISION_ID 0x08 // 1
#define PCI_REG_PROG_IF 0x09 // 1
#define PCI_REG_SUBCLASS 0x0a // 1
#define PCI_REG_CLASS 0x0b // 1
#define PCI_REG_CACHE_LINE_SIZE 0x0c // 1
#define PCI_REG_LATENCY_TIMER 0x0d // 1
#define PCI_REG_HEADER_TYPE 0x0e // 1
#define PCI_REG_BIST 0x0f // 1
#define PCI_REG_BAR0 0x10 // 4
#define PCI_REG_BAR1 0x14 // 4
#define PCI_REG_BAR2 0x18 // 4
#define PCI_REG_BAR3 0x1C // 4
#define PCI_REG_BAR4 0x20 // 4
#define PCI_REG_BAR5 0x24 // 4
#define PCI_REG_INTERRUPT_LINE 0x3C // 1
#define PCI_REG_INTERRUPT_PIN 0x3D
#define PCI_REG_SECONDARY_BUS 0x19 // 1
#define PCI_HEADER_TYPE_DEVICE 0
#define PCI_HEADER_TYPE_BRIDGE 1
#define PCI_HEADER_TYPE_CARDBUS 2
#define PCI_TYPE_BRIDGE 0x0604
#define PCI_TYPE_SATA 0x0106
#define PCI_ADDRESS_PORT 0xCF8
#define PCI_VALUE_PORT 0xCFC
#define PCI_NONE 0xFFFF
#define PCI_CLASS_ANY 0xFF
#define PCI_SUBSYSTEM_KEXT_ID "net.doorstuck.socks.pci"
#define PCI_DEVICE_ID(vid, did) { .pci_vendor_id = (vid), .pci_device_id = (did), .pci_class_id = PCI_CLASS_ANY, .pci_subclass_id = PCI_CLASS_ANY }
#define PCI_CLASS_ID(cid, scid) { .pci_vendor_id = PCI_NONE, .pci_device_id = PCI_NONE, .pci_class_id = (cid), .pci_subclass_id = (scid) }
#define PCI_DEVICE_ID_FULL(vid, did, cid, scid) { .pci_vendor_id = (vid), .pci_device_id = (did), .pci_class_id = (cid), .pci_subclass_id = (scid) }
#define PCI_DEVICE_ID_INVALID PCI_DEVICE_ID_FULL(PCI_NONE, PCI_NONE, PCI_CLASS_ANY, PCI_CLASS_ANY)
struct pci_device_id {
uint16_t pci_vendor_id;
uint16_t pci_device_id;
uint8_t pci_class_id;
uint8_t pci_subclass_id;
};
struct pci_device {
struct pci_device_id pci_id;
unsigned int pci_bus, pci_slot, pci_func;
};
struct pci_driver {
struct driver pci_base;
struct queue_entry pci_head;
const struct pci_device_id *pci_target_devices;
kern_status_t(*probe)(struct pci_driver *, struct device *);
kern_status_t(*remove)(struct pci_driver *, struct device *);
};
static inline int pci_get_bus(uint32_t device)
{
return (uint8_t)((device >> 16));
}
static inline int pci_get_slot(uint32_t device)
{
return (uint8_t)((device >> 8));
}
static inline int pci_get_func(uint32_t device)
{
return (uint8_t)(device);
}
static inline uint32_t pci_get_addr(uint32_t device, int field)
{
return 0x80000000 | (pci_get_bus(device) << 16) | (pci_get_slot(device) << 11) | (pci_get_func(device) << 8) | ((field) & 0xFC);
}
static inline uint32_t pci_box_device(int bus, int slot, int func)
{
return (uint32_t)((bus << 16) | (slot << 8) | func);
}
extern struct pci_driver *pci_driver_create(struct kext *self, const char *name, const struct pci_device_id *device_ids);
extern kern_status_t pci_driver_destroy(struct pci_driver *driver);
extern kern_status_t pci_driver_register(struct pci_driver *driver);
extern kern_status_t pci_driver_unregister(struct pci_driver *driver);
static inline struct driver *pci_driver_base(struct pci_driver *driver)
{
return &driver->pci_base;
}
extern uint32_t pci_read_field(uint32_t device, int field, int size);
extern void pci_write_field(uint32_t device, int field, int size, uint32_t value);
extern uint16_t pci_find_type(uint32_t dev);
extern uint32_t pci_device_read_field(struct device *dev, int field, int size);
extern void pci_device_write_field(struct device *dev, int field, int size, uint32_t value);
static inline struct pci_device *device_get_pci_info(struct device *dev)
{
return dev->dev_bus_priv;
}
#endif

View File

@@ -1,92 +0,0 @@
#include <socks/kext.h>
#include <socks/vm.h>
#include <socks/device.h>
#include <socks/printk.h>
#include <socks/pci.h>
#include <socks/libc/stdio.h>
#include <arch/ports.h>
#include "pci.h"
struct driver *pci_driver = NULL;
struct bus_device *pci_bus = NULL;
static void init_pci_device(uint32_t device, uint16_t vendid, uint16_t devid, void *arg)
{
struct device *dev = generic_device_create();
snprintf(dev->dev_name, sizeof dev->dev_name, "%02x:%02x.%u",
pci_get_bus(device),
pci_get_slot(device),
pci_get_func(device));
uint8_t c = pci_read_field(device, PCI_REG_CLASS, 1);
uint8_t sc = pci_read_field(device, PCI_REG_SUBCLASS, 1);
printk("pci: found device %s (vend:%04x, dev:%04x, class:%02x, subclass:%02x)",
dev->dev_name, vendid, devid, c, sc);
struct pci_device *pci_dev = kmalloc(sizeof *pci_dev, VM_NORMAL);
if (!pci_dev) {
/* TODO destroy device */
return;
}
pci_dev->pci_id.pci_vendor_id = vendid;
pci_dev->pci_id.pci_device_id = devid;
pci_dev->pci_id.pci_class_id = c;
pci_dev->pci_id.pci_subclass_id = sc;
pci_dev->pci_bus = pci_get_bus(device);
pci_dev->pci_slot = pci_get_slot(device);
pci_dev->pci_func = pci_get_func(device);
dev->dev_bus_priv = pci_dev;
/* register as a generic device under the PCI driver.
if we find a suitable driver for this device, that device will re-register it as theirs. */
device_register(dev, pci_driver, bus_device_base(pci_bus));
struct pci_driver *driver = find_driver_for_pci_device(&pci_dev->pci_id);
if (driver && driver->probe) {
driver->probe(driver, dev);
}
}
static kern_status_t pci_bus_scan(struct device *bus)
{
printk("pci: scanning for devices...");
pci_enumerate_devices(init_pci_device, -1, NULL);
return KERN_OK;
}
static struct bus_device_ops pci_bus_ops = {
.scan = pci_bus_scan,
};
static kern_status_t online(struct kext *self)
{
pci_driver = driver_create(self, "pci");
if (!pci_driver) {
return KERN_NO_MEMORY;
}
kern_status_t status = init_pci_driver_cache();
if (status != KERN_OK) {
return status;
}
driver_register(pci_driver);
pci_bus = bus_device_create();
struct device *pci_base = bus_device_base(pci_bus);
snprintf(pci_base->dev_name, sizeof pci_base->dev_name, "pci");
pci_bus->b_ops = &pci_bus_ops;
device_register(pci_base, pci_driver, root_device());
printk("pci: subsystem initialised");
return KERN_OK;
}
DEFINE_KEXT(PCI_SUBSYSTEM_KEXT_ID,
online, NULL,
KEXT_NO_DEPENDENCIES);

View File

@@ -1,131 +0,0 @@
#include <socks/pci.h>
#include <arch/ports.h>
#include <socks/libc/stdio.h>
#include "pci.h"
static void pci_scan_bus(pci_func_t f, int type, int bus, void *arg);
void pci_write_field(uint32_t device, int field, int size, uint32_t value)
{
outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field));
outportl(PCI_VALUE_PORT, value);
}
uint32_t pci_read_field(uint32_t device, int field, int size)
{
outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field));
if (size == 4) {
uint32_t t = inportl(PCI_VALUE_PORT);
return t;
} else if (size == 2) {
uint16_t t = inportw(PCI_VALUE_PORT + (field & 2));
return t;
} else if (size == 1) {
uint8_t t = inportb(PCI_VALUE_PORT + (field & 3));
return t;
}
return 0xFFFF;
}
uint32_t pci_device_read_field(struct device *dev, int field, int size)
{
struct pci_device *pci_dev = dev->dev_bus_priv;
if (!pci_dev) {
return 0;
}
return pci_read_field(pci_box_device(pci_dev->pci_bus, pci_dev->pci_slot, pci_dev->pci_func), field, size);
}
void pci_device_write_field(struct device *dev, int field, int size, uint32_t value)
{
struct pci_device *pci_dev = dev->dev_bus_priv;
if (!pci_dev) {
return;
}
pci_write_field(pci_box_device(pci_dev->pci_bus, pci_dev->pci_slot, pci_dev->pci_func), field, size, value);
}
uint16_t pci_find_type(uint32_t dev)
{
return (pci_read_field(dev, PCI_REG_CLASS, 1) << 8) | pci_read_field(dev, PCI_REG_SUBCLASS, 1);
}
static void pci_scan_hit(pci_func_t f, uint32_t dev, void *arg)
{
int dev_vend = (int)pci_read_field(dev, PCI_REG_VENDOR_ID, 2);
int dev_dvid = (int)pci_read_field(dev, PCI_REG_DEVICE_ID, 2);
f(dev, dev_vend, dev_dvid, arg);
}
static void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func, void *arg)
{
uint32_t dev = pci_box_device(bus, slot, func);
if (type == -1 || type == pci_find_type(dev)) {
pci_scan_hit(f, dev, arg);
}
if (pci_find_type(dev) == PCI_TYPE_BRIDGE) {
pci_scan_bus(f, type, pci_read_field(dev, PCI_REG_SECONDARY_BUS, 1), arg);
}
}
static void pci_scan_slot(pci_func_t f, int type, int bus, int slot, void *arg)
{
uint32_t dev = pci_box_device(bus, slot, 0);
if (pci_read_field(dev, PCI_REG_VENDOR_ID, 2) == PCI_NONE) {
return;
}
pci_scan_func(f, type, bus, slot, 0, arg);
if (!pci_read_field(dev, PCI_REG_HEADER_TYPE, 1)) {
return;
}
for (int func = 1; func < 8; func++) {
uint32_t dev = pci_box_device(bus, slot, func);
if (pci_read_field(dev, PCI_REG_VENDOR_ID, 2) != PCI_NONE) {
pci_scan_func(f, type, bus, slot, func, arg);
}
}
}
static void pci_scan_bus(pci_func_t f, int type, int bus, void *arg)
{
for (int slot = 0; slot < 32; ++slot) {
pci_scan_slot(f, type, bus, slot, arg);
}
}
void pci_enumerate_devices(pci_func_t f, int type, void *arg)
{
if ((pci_read_field(0, PCI_REG_HEADER_TYPE, 1) & 0x80) == 0) {
pci_scan_bus(f, type, 0, arg);
return;
}
int hit = 0;
for (int func = 0; func < 8; ++func) {
uint32_t dev = pci_box_device(0, 0, func);
if (pci_read_field(dev, PCI_REG_VENDOR_ID, 2) == PCI_NONE) {
break;
}
hit = 1;
pci_scan_bus(f, type, func, arg);
}
if (hit) {
return;
}
for (int bus = 0; bus < 256; ++bus) {
for (int slot = 0; slot < 32; ++slot) {
pci_scan_slot(f, type, bus, slot, arg);
}
}
}

View File

@@ -1,18 +0,0 @@
#ifndef PCI_H_
#define PCI_H_
#include <stdint.h>
#include <socks/status.h>
struct pci_device_id;
typedef void (*pci_func_t)(uint32_t device, uint16_t vendor_id, uint16_t device_id, void *arg);
extern struct driver *pci_driver;
extern struct bus_device *pci_bus;
extern struct pci_driver *find_driver_for_pci_device(const struct pci_device_id *query);
extern kern_status_t init_pci_driver_cache(void);
extern void pci_enumerate_devices(pci_func_t f, int type, void *arg);
#endif

View File

@@ -1,8 +0,0 @@
name: ps2kbd
description: |
PS2 Keyboard and Mouse Driver
id: net.doorstuck.socks.ps2kbd
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- main.c

View File

@@ -1,459 +0,0 @@
#include <socks/printk.h>
#include <socks/input.h>
#include <socks/device.h>
#include <socks/kext.h>
#include <socks/libc/stdio.h>
#include <arch/ports.h>
#include <arch/irq.h>
#define PS2_CMD_P1ON 0xae
#define PS2_CMD_P1OFF 0xad
#define PS2_CMD_P2ON 0xa8
#define PS2_CMD_P2OFF 0xa7
#define PS2_CFG_P1_IRQ (1 << 0)
#define PS2_CFG_P2_IRQ (1 << 1)
#define PS2_CFG_SYSFLAG (1 << 2)
#define PS2_CFG_ZERO1 (1 << 3)
#define PS2_CFG_P1_CLOCK (1 << 4)
#define PS2_CFG_P2_CLOCK (1 << 5)
#define PS2_CFG_P1_TRL (1 << 6)
#define PS2_CFG_ZERO2 (1 << 7)
#define PS2_SC2_PSBRK 0xe1
#define PS2_SC2_RELEASED 0xf0
#define NEXT_MAP 0xffffffff
#define PS2_ACK 0xfa
#define PS2_RESEND 0xfe
#define PS2_IO_DATA 0x60
#define PS2_IO_STATUS 0x64
#define PS2_IO_CMD 0x64
static enum input_keycode keymap_l1[0xe1];
static enum input_keycode keymap_l2[0x7e];
static enum input_keycode keymap_l3[0xe1];
static enum input_keycode keymap_l4[0x7d];
static const enum input_keycode *keymaps[] = {
keymap_l1,
keymap_l2,
keymap_l3,
keymap_l4,
};
static struct driver *ps2_driver = NULL;
static struct input_device *keyboard = NULL, *mouse = NULL;
static void process_input(struct work_item *w);
static struct work_item ps2_work_item = {
.w_func = process_input,
};
static void send_cmd(uint8_t cmd)
{
/* prevent the compiler from optimising this away */
volatile int _i = 0;
while (inportb(PS2_IO_STATUS) & 0x2) {
_i++;
}
outportb(PS2_IO_CMD, cmd);
}
static void send_data(uint8_t data)
{
/* prevent the compiler from optimising this away */
volatile int _i = 0;
while (inportb(PS2_IO_STATUS) & 0x2) {
_i++;
}
outportb(PS2_IO_DATA, data);
}
static uint8_t recv_data()
{
/* prevent the compiler from optimising this away */
volatile int _i = 0;
while (!(inportb(PS2_IO_STATUS) & 0x1)) {
_i++;
}
return inportb(PS2_IO_DATA);
}
static int data_avail()
{
return inportb(PS2_IO_STATUS) & 0x1;
}
static void flush_buffer()
{
while (data_avail()) {
recv_data();
}
}
static uint8_t read_config()
{
send_cmd(0x20);
return recv_data();
}
static void set_config(uint8_t cfg)
{
send_cmd(0x60);
send_data(cfg);
}
static int int_handler(void)
{
schedule_work(&ps2_work_item);
return 0;
}
static void process_input(struct work_item *w)
{
static int scancode_level = 0;
static bool released = false;
if (scancode_level == PS2_SC2_PSBRK) {
/* TODO pause break keycode */
scancode_level = 0;
return;
}
while (data_avail()) {
unsigned char scancode = recv_data();
/* the only scancode set that begins with 0xe1 is the Pause key.
* Rather than try and interpret a sequence of 8 codes, we just
* assume the pause key was pressed */
if (scancode == PS2_SC2_PSBRK) {
flush_buffer();
/* TODO pause break keycode */
//mdk_input_event ev = { .type = MDK_INPUT_DEVICE_KEYBOARD };
scancode_level = PS2_SC2_PSBRK;
break;
}
if (scancode == PS2_SC2_RELEASED) {
released = true;
continue;
}
enum input_keycode c = keymaps[scancode_level][scancode];
if (c == NEXT_MAP) {
scancode_level++;
continue;
}
scancode_level = 0;
struct input_event ev;
ev.ev_type = INPUT_TYPE_KEY;
ev.ev_key.key = c;
ev.ev_key.state = released ? INPUT_KEYSTATE_UP : INPUT_KEYSTATE_DOWN;
input_device_report_event(keyboard, &ev, true);
released = false;
}
}
static int init_controller(void)
{
/* disable ps2 devices */
send_cmd(PS2_CMD_P1OFF);
send_cmd(PS2_CMD_P2OFF);
flush_buffer();
/* configure the controller */
uint8_t config = read_config();
config &= ~(PS2_CFG_P1_IRQ | PS2_CFG_P2_IRQ | PS2_CFG_P1_TRL);
set_config(config);
send_cmd(0xaa);
uint8_t response = recv_data();
if (response != 0x55) {
return -1;
}
set_config(config);
/* Switch to scancode set 2 */
send_data(0xf0);
send_data(0x02);
if (recv_data() != PS2_ACK) {
return -1;
}
/* enable 1st port */
send_cmd(PS2_CMD_P1ON);
/* enable interrupts */
config = read_config();
config |= PS2_CFG_P1_IRQ;
set_config(config);
/* perform keyboard test */
send_data(0xff);
uint8_t response1 = recv_data();
uint8_t response2 = recv_data();
if ((response1 != 0xaa && response2 != 0xfa) &&
(response1 != 0xfa && response2 != 0xaa)) {
return -1;
}
return 0;
}
static kern_status_t create_devices(struct kext *self)
{
ps2_driver = driver_create(self, "ps2");
if (!ps2_driver) {
return KERN_NO_MEMORY;
}
driver_register(ps2_driver);
struct input_device *kbd = input_device_create();
struct device *kbd_base = input_device_base(kbd);
snprintf(kbd_base->dev_name, sizeof kbd_base->dev_name, "ps2kbd");
struct input_device *ms = input_device_create();
struct device *ms_base = input_device_base(ms);
snprintf(ms_base->dev_name, sizeof ms_base->dev_name, "ps2mouse");
kern_status_t status = device_register(kbd_base, ps2_driver, misc_device());
if (status != KERN_OK) {
/* TODO destroy devices */
return status;
}
status = device_register(ms_base, ps2_driver, misc_device());
if (status != KERN_OK) {
return status;
}
keyboard = kbd;
mouse = ms;
return KERN_OK;
}
static struct irq_hook ps2_hook = {
.irq_callback = int_handler,
};
static kern_status_t online(struct kext *self)
{
printk("ps2: initialising controller...");
int result = init_controller();
if (result != 0) {
printk("ps2: controller initialisation failed");
return KERN_UNSUPPORTED;
}
printk("ps2: controller initialised");
kern_status_t status = create_devices(self);
if (status != KERN_OK) {
return status;
}
hook_irq(IRQ1, &ps2_hook);
return KERN_OK;
}
DEFINE_KEXT("net.doorstuck.socks.ps2kbd",
online, NULL,
KEXT_NO_DEPENDENCIES);
static enum input_keycode keymap_l1[0xe1] = {
[0x00] = KEY_UNKNOWN,
[0x01] = KEY_F9,
[0x02] = KEY_UNKNOWN,
[0x03] = KEY_F5,
[0x04] = KEY_F3,
[0x05] = KEY_F1,
[0x06] = KEY_F2,
[0x07] = KEY_F12,
[0x08] = KEY_UNKNOWN,
[0x09] = KEY_F10,
[0x0a] = KEY_F8,
[0x0b] = KEY_F6,
[0x0c] = KEY_F4,
[0x0d] = KEY_TAB,
[0x0e] = KEY_GRAVE_ACCENT,
[0x0f] = KEY_UNKNOWN,
[0x10] = KEY_UNKNOWN,
[0x11] = KEY_LEFT_ALT,
[0x12] = KEY_LEFT_SHIFT,
[0x13] = KEY_UNKNOWN,
[0x14] = KEY_LEFT_CTRL,
[0x15] = KEY_Q,
[0x16] = KEY_KEY_1,
[0x17] = KEY_UNKNOWN,
[0x18] = KEY_UNKNOWN,
[0x19] = KEY_UNKNOWN,
[0x1a] = KEY_Z,
[0x1b] = KEY_S,
[0x1c] = KEY_A,
[0x1d] = KEY_W,
[0x1e] = KEY_KEY_2,
[0x1f] = KEY_UNKNOWN,
[0x20] = KEY_UNKNOWN,
[0x21] = KEY_C,
[0x22] = KEY_X,
[0x23] = KEY_D,
[0x24] = KEY_E,
[0x25] = KEY_KEY_4,
[0x26] = KEY_KEY_3,
[0x27] = KEY_UNKNOWN,
[0x28] = KEY_UNKNOWN,
[0x29] = KEY_SPACE,
[0x2a] = KEY_V,
[0x2b] = KEY_F,
[0x2c] = KEY_T,
[0x2d] = KEY_R,
[0x2e] = KEY_KEY_5,
[0x2f] = KEY_UNKNOWN,
[0x30] = KEY_UNKNOWN,
[0x31] = KEY_N,
[0x32] = KEY_B,
[0x33] = KEY_H,
[0x34] = KEY_G,
[0x35] = KEY_Y,
[0x36] = KEY_KEY_6,
[0x37] = KEY_UNKNOWN,
[0x38] = KEY_UNKNOWN,
[0x39] = KEY_SPACE,
[0x3a] = KEY_M,
[0x3b] = KEY_J,
[0x3c] = KEY_U,
[0x3d] = KEY_KEY_7,
[0x3e] = KEY_KEY_8,
[0x3f] = KEY_UNKNOWN,
[0x40] = KEY_UNKNOWN,
[0x41] = KEY_COMMA,
[0x42] = KEY_K,
[0x43] = KEY_I,
[0x44] = KEY_O,
[0x45] = KEY_KEY_0,
[0x46] = KEY_KEY_9,
[0x47] = KEY_UNKNOWN,
[0x48] = KEY_UNKNOWN,
[0x49] = KEY_DOT,
[0x4a] = KEY_SLASH,
[0x4b] = KEY_L,
[0x4c] = KEY_SEMICOLON,
[0x4d] = KEY_P,
[0x4e] = KEY_MINUS,
[0x4f] = KEY_UNKNOWN,
[0x50] = KEY_UNKNOWN,
[0x51] = KEY_UNKNOWN,
[0x52] = KEY_APOSTROPHE,
[0x53] = KEY_UNKNOWN,
[0x54] = KEY_LEFT_BRACE,
[0x55] = KEY_EQUALS,
[0x56] = KEY_UNKNOWN,
[0x57] = KEY_UNKNOWN,
[0x58] = KEY_CAPS_LOCK,
[0x59] = KEY_RIGHT_SHIFT,
[0x5a] = KEY_ENTER,
[0x5b] = KEY_RIGHT_BRACE,
[0x5c] = KEY_UNKNOWN,
[0x5d] = KEY_BACKSLASH,
[0x5e] = KEY_UNKNOWN,
[0x5f] = KEY_UNKNOWN,
[0x60] = KEY_UNKNOWN,
[0x61] = KEY_UNKNOWN,
[0x62] = KEY_UNKNOWN,
[0x63] = KEY_UNKNOWN,
[0x64] = KEY_UNKNOWN,
[0x65] = KEY_UNKNOWN,
[0x66] = KEY_BACKSPACE,
[0x67] = KEY_UNKNOWN,
[0x68] = KEY_UNKNOWN,
[0x69] = KEY_KEYPAD_1,
[0x6a] = KEY_UNKNOWN,
[0x6b] = KEY_KEYPAD_4,
[0x6c] = KEY_KEYPAD_7,
[0x6d] = KEY_UNKNOWN,
[0x6e] = KEY_UNKNOWN,
[0x6f] = KEY_UNKNOWN,
[0x70] = KEY_KEYPAD_0,
[0x71] = KEY_KEYPAD_DOT,
[0x72] = KEY_KEYPAD_2,
[0x73] = KEY_KEYPAD_5,
[0x74] = KEY_KEYPAD_6,
[0x75] = KEY_KEYPAD_8,
[0x76] = KEY_ESCAPE,
[0x77] = KEY_NUM_LOCK,
[0x78] = KEY_F11,
[0x79] = KEY_KEYPAD_PLUS,
[0x7a] = KEY_KEYPAD_3,
[0x7b] = KEY_KEYPAD_MINUS,
[0x7c] = KEY_KEYPAD_ASTERISK,
[0x7d] = KEY_KEYPAD_9,
[0x7e] = KEY_SCROLL_LOCK,
[0x7f] = KEY_UNKNOWN,
[0xe0] = NEXT_MAP,
};
static enum input_keycode keymap_l2[0x7e] = {
[0x10] = KEY_UNKNOWN, /* WWW_SEARCH */
[0x11] = KEY_RIGHT_ALT,
[0x12] = NEXT_MAP,
[0x14] = KEY_RIGHT_CTRL,
[0x15] = KEY_UNKNOWN, /* MEDIA_PREV */
[0x18] = KEY_UNKNOWN, /* WWW_BOOKMARKS */
[0x1f] = KEY_LEFT_META,
[0x20] = KEY_UNKNOWN, /* WWW_REFRESH */
[0x21] = KEY_MEDIA_VOLUME_DECREMENT,
[0x23] = KEY_MEDIA_MUTE,
[0x27] = KEY_RIGHT_META,
[0x28] = KEY_UNKNOWN, /* WWW_STOP */
[0x2f] = KEY_UNKNOWN, /* RIGHT_MENU */
[0x2B] = KEY_UNKNOWN, /* CALCULATOR */
[0x30] = KEY_UNKNOWN, /* WWW_FORWARD */
[0x32] = KEY_MEDIA_VOLUME_INCREMENT,
[0x34] = KEY_UNKNOWN, /* MEDIA_PLAY_PAUSE */
[0x37] = KEY_UNKNOWN, /* POWER */
[0x38] = KEY_UNKNOWN, /* WWW_BACK */
[0x3a] = KEY_UNKNOWN, /* WWW_HOME */
[0x3b] = KEY_UNKNOWN, /* MEDIA_STOP */
[0x3f] = KEY_UNKNOWN, /* SLEEP */
[0x40] = KEY_UNKNOWN, /* CALCULATOR */
[0x48] = KEY_UNKNOWN, /* WWW_EMAIL */
[0x4a] = KEY_KEYPAD_SLASH,
[0x4d] = KEY_UNKNOWN, /* MEDIA_NEXT */
[0x50] = KEY_UNKNOWN, /* MEDIA_SELECT */
[0x5a] = KEY_KEYPAD_ENTER,
[0x5e] = KEY_UNKNOWN, /* WAKE */
[0x69] = KEY_END,
[0x6b] = KEY_LEFT,
[0x6c] = KEY_HOME,
[0x70] = KEY_INSERT,
[0x71] = KEY_DELETE,
[0x72] = KEY_DOWN,
[0x74] = KEY_RIGHT,
[0x75] = KEY_UP,
[0x7a] = KEY_PAGE_DOWN,
[0x7c] = KEY_PRINT_SCREEN,
[0x7d] = KEY_PAGE_UP,
};
static enum input_keycode keymap_l3[0xe1] = {
[0xe0] = NEXT_MAP,
};
static enum input_keycode keymap_l4[0x7d] = {
[0x7c] = KEY_PRINT_SCREEN,
};

View File

@@ -1,11 +0,0 @@
name: fbcon
description: |
VGA/Framebuffer kernel console.
id: net.doorstuck.socks.fbcon
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- main.c
- fbcon.c
- vgacon.c
- u_vga16.c

View File

@@ -1,94 +0,0 @@
#include <socks/tty.h>
#include "u_vga16.h"
#include "fbcon.h"
#define CELL_WIDTH 8
#define CELL_HEIGHT 16
static void fbcon_init(struct device *dev)
{
}
static void fbcon_deinit(struct device *dev)
{
}
static void fbcon_clear(struct device *dev, int x, int y, int width, int height)
{
}
static void fbcon_putc(struct device *dev, int c, int xpos, int ypos, tty_attrib_t attrib)
{
}
static void fbcon_set_cursor(struct device *dev, enum tty_cursor cur)
{
}
static void fbcon_move_cursor(struct device *dev, int x, int y)
{
}
static void fbcon_scroll(struct device *dev, enum tty_scroll_dir dir, int lines)
{
}
static struct tty_driver_ops fbcon_ops = {
.tty_init = fbcon_init,
.tty_deinit = fbcon_deinit,
.tty_clear = fbcon_clear,
.tty_putc = fbcon_putc,
.tty_set_cursor = fbcon_set_cursor,
.tty_move_cursor = fbcon_move_cursor,
.tty_scroll = fbcon_scroll,
};
kern_status_t init_fbcon_console(struct device *tty, struct device *fb)
{
struct char_device *cdev = CHAR_DEVICE(tty);
struct framebuffer_varinfo fb_mode;
struct framebuffer_fixedinfo fixedinfo;
struct tty_device *ttydev = cdev->c_tty;
struct fbcon_priv *priv = kmalloc(sizeof *priv, VM_NORMAL);
if (!priv) {
return KERN_NO_MEMORY;
}
kern_status_t status = framebuffer_get_varinfo(fb, &fb_mode);
if (status != KERN_OK) {
kfree(priv);
return status;
}
status = framebuffer_get_fixedinfo(fb, &fixedinfo);
if (status != KERN_OK) {
kfree(priv);
return status;
}
ttydev->tty_xcells = fb_mode.fb_xres / CELL_WIDTH;
ttydev->tty_ycells = fb_mode.fb_yres / CELL_HEIGHT;
ttydev->tty_xcur = 0;
ttydev->tty_ycur = 0;
priv->fbdev = fb;
priv->fb_pitch = fb_mode.fb_stride;
priv->fb_pixels = vm_phys_to_virt(fixedinfo.fb_baseptr);
priv->tty_ops = &fbcon_ops;
tty->dev_priv = priv;
memset(priv->fb_pixels, 0x00, fb_mode.fb_yres * fb_mode.fb_stride);
return KERN_OK;
}

View File

@@ -1,24 +0,0 @@
#ifndef FBCON_H_
#define FBCON_H_
#include <socks/status.h>
#include <stdint.h>
struct fbcon_priv {
struct device *fbdev;
union {
uint32_t *fb_pixels;
uint16_t *fb_cells;
};
unsigned long fb_pitch;
struct tty_driver_ops *tty_ops;
};
struct device;
struct tty_driver_ops;
extern kern_status_t init_fbcon_console(struct device *tty, struct device *fb);
extern kern_status_t init_vgacon_console(struct device *tty, struct device *fb);
#endif

View File

@@ -1,11 +0,0 @@
#ifndef SOCKS_FBCON_H_
#define SOCKS_FBCON_H_
#include <socks/status.h>
struct device;
extern kern_status_t start_console_on_framebuffer(struct device *fb);
extern void early_vgacon_init(void);
#endif

View File

@@ -1,97 +0,0 @@
#include <socks/printk.h>
#include <socks/device.h>
#include <socks/kext.h>
#include <socks/tty.h>
#include <socks/libc/stdio.h>
#include "fbcon.h"
static struct tty_driver *fbcon_driver = NULL;
static void tty_clear(struct device *dev, int x, int y, int width, int height)
{
struct fbcon_priv *priv = dev->dev_priv;
priv->tty_ops->tty_clear(dev, x, y, width, height);
}
static void tty_putc(struct device *dev, int c, int xpos, int ypos, tty_attrib_t attrib)
{
struct fbcon_priv *priv = dev->dev_priv;
priv->tty_ops->tty_putc(dev, c, xpos, ypos, attrib);
}
static void tty_set_cursor(struct device *dev, enum tty_cursor cur)
{
struct fbcon_priv *priv = dev->dev_priv;
priv->tty_ops->tty_set_cursor(dev, cur);
}
static void tty_move_cursor(struct device *dev, int x, int y)
{
struct fbcon_priv *priv = dev->dev_priv;
priv->tty_ops->tty_move_cursor(dev, x, y);
}
static void tty_scroll(struct device *dev, enum tty_scroll_dir dir, int lines)
{
struct fbcon_priv *priv = dev->dev_priv;
priv->tty_ops->tty_scroll(dev, dir, lines);
}
static struct tty_driver_ops tty_ops = {
.tty_clear = tty_clear,
.tty_putc = tty_putc,
.tty_set_cursor = tty_set_cursor,
.tty_move_cursor = tty_move_cursor,
.tty_scroll = tty_scroll,
};
static kern_status_t online(struct kext *self)
{
fbcon_driver = tty_driver_create(self, "tty");
if (!fbcon_driver) {
return KERN_NO_MEMORY;
}
fbcon_driver->tty_ops = &tty_ops;
fbcon_driver->tty_type = TTY_DRIVER_FULL;
tty_driver_register(fbcon_driver);
return KERN_OK;
}
kern_status_t start_console_on_framebuffer(struct device *fb)
{
struct framebuffer_varinfo fb_mode;
framebuffer_get_varinfo(fb, &fb_mode);
struct device *tty = tty_device_create();
/* TODO actual IDs for FB tty devices */
snprintf(tty->dev_name, sizeof tty->dev_name, "ttyFB0");
kern_status_t status;
if (fb_mode.fb_flags & FB_MODE_VGATEXT) {
status = init_vgacon_console(tty, fb);
} else {
status = init_fbcon_console(tty, fb);
}
if (status != KERN_OK) {
/* TODO destroy tty device */
return status;
}
status = tty_device_register(tty, fbcon_driver, misc_device());
if (status != KERN_OK) {
/* TODO destroy tty device */
return status;
}
return status;
}
DEFINE_KEXT("net.doorstuck.socks.fbcon",
online, NULL,
KEXT_NO_DEPENDENCIES);

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +0,0 @@
#ifndef U_VGA16_H_
#define U_VGA16_H_
struct bitmap_font {
unsigned char Width; ///< max. character width
unsigned char Height; ///< character height
unsigned short Chars; ///< number of characters in font
const unsigned char *Widths; ///< width of each character
const unsigned short *Index; ///< encoding to character index
const unsigned char *Bitmap; ///< bitmap of all characters
};
extern const struct bitmap_font fbcon_font;
#endif

View File

@@ -1,229 +0,0 @@
#include <socks/tty.h>
#include <socks/libc/string.h>
#include <socks/libc/ctype.h>
#include <arch/ports.h>
#include <socks/console.h>
#include <socks/vm.h>
#include <socks/printk.h>
#include <stdint.h>
#include "fbcon.h"
#define VGA_PORT_CMD 0x3D4
#define VGA_PORT_DATA 0x3D5
#define VGA_CHAR(ch, attrib) ((uint16_t)(ch) | ((uint16_t)(attrib) << 8))
#define DEFAULT_ATTRIB 0x07
static uint16_t *g_console_fb = (uint16_t *)(VM_KERNEL_VOFFSET + 0xb8000);
static const unsigned int k_console_width = 80;
static const unsigned int k_console_height = 25;
static unsigned int g_console_cursor_xpos = 0;
static unsigned int g_console_cursor_ypos = 0;
static void init_vga_cursor(void)
{
unsigned int start = 0, end = 15;
outportb(VGA_PORT_CMD, 0x0A);
outportb(VGA_PORT_DATA, (inportb(VGA_PORT_DATA) & 0xC0) | start);
outportb(VGA_PORT_CMD, 0x0B);
outportb(VGA_PORT_DATA, (inportb(VGA_PORT_DATA) & 0xE0) | end);
}
static void move_vga_cursor(unsigned int x, unsigned int y)
{
unsigned int offset = y * k_console_width + x;
outportb(VGA_PORT_CMD, 0x0F);
outportb(VGA_PORT_DATA, (uint8_t)(offset & 0xFF));
outportb(VGA_PORT_CMD, 0x0E);
outportb(VGA_PORT_DATA, (uint8_t)((offset >> 8) & 0xFF));
}
static void scroll_display(void)
{
uint16_t *src = g_console_fb + k_console_width;
uint16_t *dst = g_console_fb;
size_t n = k_console_width * (k_console_height - 1) * 2;
memmove(dst, src, n);
dst = g_console_fb + ((k_console_height - 1) * k_console_width);
for (int i = 0; i < k_console_width; i++) {
dst[i] = VGA_CHAR(0, DEFAULT_ATTRIB);
}
}
static void handle_ctrl(int c)
{
switch (c) {
case '\n':
g_console_cursor_xpos = 0;
g_console_cursor_ypos++;
if (g_console_cursor_ypos >= k_console_height) {
scroll_display();
g_console_cursor_ypos = k_console_height - 1;
}
break;
default:
break;
}
move_vga_cursor(g_console_cursor_xpos, g_console_cursor_ypos);
}
static void vgacon_putchar(int c)
{
if (iscntrl(c)) {
handle_ctrl(c);
return;
}
g_console_fb[(g_console_cursor_ypos * k_console_width) + g_console_cursor_xpos] = VGA_CHAR(c, DEFAULT_ATTRIB);
g_console_cursor_xpos++;
if (g_console_cursor_xpos >= k_console_width) {
g_console_cursor_xpos = 0;
g_console_cursor_ypos++;
}
if (g_console_cursor_ypos >= k_console_height) {
scroll_display();
g_console_cursor_ypos = k_console_height - 1;
g_console_cursor_xpos = 0;
}
move_vga_cursor(g_console_cursor_xpos, g_console_cursor_ypos);
}
static void vgacon_write(struct console *con, const char *s, unsigned int len)
{
for (unsigned int i = 0; i < len; i++) {
vgacon_putchar(s[i]);
}
}
static struct console early_vgacon = {
.c_name = "vgacon",
.c_flags = CON_BOOT,
.c_write = vgacon_write,
.c_lock = SPIN_LOCK_INIT,
};
void early_vgacon_init(void)
{
g_console_cursor_xpos = 0;
g_console_cursor_ypos = 0;
for (int i = 0; i < k_console_width * k_console_height; i++) {
g_console_fb[i] = DEFAULT_ATTRIB << 8;
}
init_vga_cursor();
move_vga_cursor(g_console_cursor_xpos, g_console_cursor_ypos);
console_register(&early_vgacon);
early_printk_init(&early_vgacon);
}
static void vgacon_init(struct device *dev)
{
}
static void vgacon_deinit(struct device *dev)
{
}
static void vgacon_clear(struct device *dev, int x, int y, int width, int height)
{
}
static void vgacon_putc(struct device *dev, int c, int xpos, int ypos, tty_attrib_t attrib)
{
struct tty_device *ttydev = TTY_DEVICE(dev);
struct fbcon_priv *priv = dev->dev_priv;
priv->fb_cells[(ypos * ttydev->tty_xcells) + xpos] = VGA_CHAR(c, attrib);
}
static void vgacon_set_cursor(struct device *dev, enum tty_cursor cur)
{
}
static void vgacon_move_cursor(struct device *dev, int x, int y)
{
move_vga_cursor(x, y);
}
static void vgacon_scroll(struct device *dev, enum tty_scroll_dir dir, int lines)
{
uint16_t *src = g_console_fb + (k_console_width * lines);
uint16_t *dst = g_console_fb;
size_t n = k_console_width * (k_console_height - lines) * 2;
memmove(dst, src, n);
dst = g_console_fb + ((k_console_height - lines) * k_console_width);
for (int i = 0; i < k_console_width * lines; i++) {
dst[i] = VGA_CHAR(0, DEFAULT_ATTRIB);
}
}
static struct tty_driver_ops vgacon_ops = {
.tty_init = vgacon_init,
.tty_deinit = vgacon_deinit,
.tty_clear = vgacon_clear,
.tty_putc = vgacon_putc,
.tty_set_cursor = vgacon_set_cursor,
.tty_move_cursor = vgacon_move_cursor,
.tty_scroll = vgacon_scroll,
};
kern_status_t init_vgacon_console(struct device *tty, struct device *fb)
{
struct char_device *cdev = CHAR_DEVICE(tty);
struct framebuffer_varinfo fb_mode;
struct framebuffer_fixedinfo fixedinfo;
struct tty_device *ttydev = cdev->c_tty;
struct fbcon_priv *priv = kzalloc(sizeof *priv, VM_NORMAL);
if (!priv) {
return KERN_NO_MEMORY;
}
kern_status_t status = framebuffer_get_varinfo(fb, &fb_mode);
if (status != KERN_OK) {
kfree(priv);
return status;
}
status = framebuffer_get_fixedinfo(fb, &fixedinfo);
if (status != KERN_OK) {
kfree(priv);
return status;
}
ttydev->tty_xcells = fb_mode.fb_xcells;
ttydev->tty_ycells = fb_mode.fb_ycells;
ttydev->tty_xcur = g_console_cursor_xpos;
ttydev->tty_ycur = g_console_cursor_ypos;
ttydev->tty_curattrib = DEFAULT_ATTRIB;
priv->fbdev = fb;
priv->fb_pitch = fb_mode.fb_stride;
priv->fb_cells = vm_phys_to_virt(fixedinfo.fb_baseptr);
priv->tty_ops = &vgacon_ops;
tty->dev_priv = priv;
return KERN_OK;
}

View File

@@ -1,8 +0,0 @@
name: serialcon
description: |
Serial port console.
id: net.doorstuck.socks.serialcon
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- main.c

View File

@@ -1,27 +0,0 @@
#ifndef ARCH_SERIAL_H_
#define ARCH_SERIAL_H_
#ifdef __cplusplus
extern "C" {
#endif
#define SERIAL_PORT_A 0x3F8
#define SERIAL_PORT_B 0x2F8
#define SERIAL_PORT_C 0x3E8
#define SERIAL_PORT_D 0x2E8
extern void serial_putchar(int port, char ch);
extern void serial_wait(int device);
extern void serial_send_byte(int device, char out);
extern char serial_recv_byte(int device);
extern int serial_rcvd(int device);
extern void early_serialcon_init(int baud);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,216 +0,0 @@
#include <socks/printk.h>
#include <socks/device.h>
#include <socks/kext.h>
#include <socks/tty.h>
#include <socks/libc/stdio.h>
#include <arch/ports.h>
#include <arch/irq.h>
#include <socks/serialcon.h>
#define COM1 0x3F8
#define COM2 0x2F8
#define COM3 0x3E8
#define COM4 0x2E8
static struct tty_driver *serialcon_driver = NULL;
static int transmit_empty(int device)
{
return inportb(device + 5) & 0x20;
}
static int serial_received(int device)
{
return inportb(device + 5) & 0x1;
}
void serial_send_byte(int device, char out)
{
volatile unsigned int _count = 0;
while (!transmit_empty(device)) {
_count++;
}
outportb(device, out);
while (!transmit_empty(device)) {
_count++;
}
}
char serial_recv_byte(int device)
{
volatile unsigned int _count = 0;
while (!serial_received(device)) {
_count++;
}
char c = inportb(device);
outportb(device + 5, inportb(device + 5) & ~0x1);
return c;
}
void serial_putchar(int port, char ch)
{
if (ch == '\n') {
serial_send_byte(port, '\r');
}
serial_send_byte(port, ch);
}
void serialcon_write(struct console *con, const char *s, unsigned int len)
{
for (unsigned int i = 0; i < len; i++) {
serial_putchar(COM1, s[i]);
}
}
static int get_baud_divisor(int baud)
{
int freq = 115200;
int best_baud = -1;
int best_div = -1;
for (int i = 1; i < 254; i++) {
int this_baud = freq / i;
if (this_baud == baud) {
return i;
}
if (best_baud == -1) {
best_baud = this_baud;
best_div = i;
continue;
}
if (this_baud < baud && best_baud > baud) {
/* TODO pick divisor that gives the closest baud rate */
return best_div;
}
best_baud = this_baud;
best_div = i;
}
return best_div;
}
static void init_serial_port(int port, int baud)
{
int baud_div = get_baud_divisor(baud);
outportb(port + 1, 0x00); // Disable all interrupts
outportb(port + 3, 0x80); // Enable DLAB (set baud rate divisor)
outportb(port + 0, baud_div); // Set divisor
outportb(port + 1, 0x00);
outportb(port + 3, 0x03); // 8 bits, no parity, one stop bit
outportb(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outportb(port + 4, 0x0B); // IRQs enabled, RTS/DSR set
outportb(port + 4, 0x1E); // Set in loopback mode, test the serial chip
outportb(port + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
volatile unsigned int q = 0;
while (!serial_received(port)) {
q++;
}
// Check if serial is faulty (i.e: not same byte as sent)
if(inportb(port + 0) != 0xAE) {
return;
}
// If serial is not faulty set it in normal operation mode
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
outportb(port + 1, 0x01);
outportb(port + 4, 0x0F);
printk("serial: port %x initialised", port);
}
static struct console serialcon = {
.c_name = "serialcon",
.c_flags = CON_BOOT,
.c_write = serialcon_write,
.c_lock = SPIN_LOCK_INIT,
};
static int serial_irq1(void)
{
if (serial_received(COM1)) {
unsigned char c = serial_recv_byte(COM1);
printk("serial: COM1 received %c", c);
}
if (serial_received(COM3)) {
unsigned char c = serial_recv_byte(COM3);
printk("serial: COM3 received %c", c);
}
return 0;
}
static struct irq_hook irq1_hook = {
.irq_callback = serial_irq1,
};
void early_serialcon_init(int baud)
{
hook_irq(IRQ4, &irq1_hook);
init_serial_port(COM1, baud);
console_register(&serialcon);
}
static void serialcon_putc(struct device *dev, int c, int xpos, int ypos, tty_attrib_t attrib)
{
unsigned int port = (uintptr_t)dev->dev_priv;
serial_putchar(port, c);
}
static struct tty_driver_ops serialcon_ops = {
.tty_putc = serialcon_putc,
};
static kern_status_t online(struct kext *self)
{
serialcon_driver = tty_driver_create(self, "ttyS");
if (!serialcon_driver) {
return KERN_NO_MEMORY;
}
serialcon_driver->tty_ops = &serialcon_ops;
tty_driver_register(serialcon_driver);
struct device *ttyS0 = tty_device_create();
struct device *ttyS1 = tty_device_create();
struct device *ttyS2 = tty_device_create();
struct device *ttyS3 = tty_device_create();
ttyS0->dev_priv = (void *)COM1;
ttyS1->dev_priv = (void *)COM2;
ttyS2->dev_priv = (void *)COM3;
ttyS3->dev_priv = (void *)COM4;
snprintf(ttyS0->dev_name, sizeof ttyS0->dev_name, "ttyS0");
snprintf(ttyS1->dev_name, sizeof ttyS1->dev_name, "ttyS1");
snprintf(ttyS2->dev_name, sizeof ttyS2->dev_name, "ttyS2");
snprintf(ttyS3->dev_name, sizeof ttyS3->dev_name, "ttyS3");
init_serial_port(COM1, 115200);
init_serial_port(COM2, 115200);
init_serial_port(COM3, 115200);
init_serial_port(COM4, 115200);
tty_device_register(ttyS0, serialcon_driver, misc_device());
tty_device_register(ttyS1, serialcon_driver, misc_device());
tty_device_register(ttyS2, serialcon_driver, misc_device());
tty_device_register(ttyS3, serialcon_driver, misc_device());
return KERN_OK;
}
DEFINE_KEXT("net.doorstuck.socks.serialcon",
online, NULL,
KEXT_NO_DEPENDENCIES);

View File

@@ -1,8 +0,0 @@
name: qemufb
description: |
QEMU virtual video controller driver.
id: net.doorstuck.socks.qemufb
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- main.c

View File

@@ -1,112 +0,0 @@
#include <socks/printk.h>
#include <socks/pci.h>
#include <socks/device.h>
#include <socks/kext.h>
#include <socks/machine/init.h>
#include <socks/libc/stdio.h>
#define VBE_DISPI_INDEX_ID 0x00u
#define VBE_DISPI_INDEX_XRES 0x01u
#define VBE_DISPI_INDEX_YRES 0x02u
#define VBE_DISPI_INDEX_BPP 0x03u
#define VBE_DISPI_INDEX_ENABLE 0x04u
#define VBE_DISPI_INDEX_BANK 0x05u
#define VBE_DISPI_INDEX_VIRT_WIDTH 0x06u
#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x07u
#define VBE_DISPI_INDEX_X_OFFSET 0x08u
#define VBE_DISPI_INDEX_Y_OFFSET 0x09u
#define VBE_DISPI_LFB_ENABLED 0x40
static struct pci_driver *qemufb_driver = NULL;
static struct pci_device_id qemufb_device_ids[] = {
PCI_DEVICE_ID(0x1234, 0x1111),
PCI_DEVICE_ID_INVALID,
};
static inline uint16_t dispi_mmio_offset(int index)
{
return (0x500 + (index << 1)) >> 1;
}
static kern_status_t qemufb_set_varinfo(struct device *dev, const struct framebuffer_varinfo *varinfo)
{
struct framebuffer_device *fbdev = FRAMEBUFFER_DEVICE(dev);
uint32_t mmio_base = pci_device_read_field(dev, PCI_REG_BAR2, 4);
uint16_t *mmio = vm_phys_to_virt(mmio_base);
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_ENABLE)] = 0;
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_XRES)] = varinfo->fb_xres;
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_YRES)] = varinfo->fb_yres;
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_BPP)] = varinfo->fb_bpp;
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_ENABLE)] = 1 | VBE_DISPI_LFB_ENABLED;
if (mmio[dispi_mmio_offset(VBE_DISPI_INDEX_XRES)] != varinfo->fb_xres ||
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_YRES)] != varinfo->fb_yres ||
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_BPP)] != varinfo->fb_bpp) {
return KERN_UNSUPPORTED;
}
fbdev->fb_fixedinfo.fb_baseptr = pci_device_read_field(dev, PCI_REG_BAR0, 4) & ~(VM_PAGE_SIZE - 1);
return KERN_OK;
}
static struct framebuffer_device_ops qemufb_ops = {
.set_varinfo = qemufb_set_varinfo,
};
static kern_status_t qemufb_probe(struct pci_driver *driver, struct device *dev)
{
struct framebuffer_device *fb = framebuffer_device_from_generic(dev);
(void)fb;
snprintf(dev->dev_name, sizeof dev->dev_name, "qemufb");
fb->fb_ops = &qemufb_ops;
uint32_t mmio_base = pci_device_read_field(dev, PCI_REG_BAR2, 4);
uint16_t *mmio = vm_phys_to_virt(mmio_base);
struct framebuffer_varinfo *varinfo = &fb->fb_varinfo;
struct framebuffer_fixedinfo *fixedinfo = &fb->fb_fixedinfo;
varinfo->fb_flags = FB_MODE_RGB;
varinfo->fb_xres = mmio[dispi_mmio_offset(VBE_DISPI_INDEX_XRES)];
varinfo->fb_yres = mmio[dispi_mmio_offset(VBE_DISPI_INDEX_YRES)];
varinfo->fb_bpp = mmio[dispi_mmio_offset(VBE_DISPI_INDEX_BPP)];
varinfo->fb_stride = varinfo->fb_bpp / 8;
fixedinfo->fb_baseptr = pci_device_read_field(dev, PCI_REG_BAR0, 4) & (VM_PAGE_SIZE - 1);
if (!varinfo->fb_xres) {
/* no mode data. assume that we're in VGA text mode */
varinfo->fb_xres = 640;
varinfo->fb_yres = 400;
varinfo->fb_bpp = 16;
varinfo->fb_flags = FB_MODE_VGATEXT;
varinfo->fb_xcells = 80;
varinfo->fb_ycells = 25;
varinfo->fb_stride = 80 * 25 * 2;
fixedinfo->fb_baseptr = 0xb8000;
}
return device_register(dev, pci_driver_base(qemufb_driver), NULL);
}
static kern_status_t online(struct kext *self)
{
printk("qemufb: registering PCI driver");
qemufb_driver = pci_driver_create(self, "qemufb", qemufb_device_ids);
if (!qemufb_driver) {
return KERN_NO_MEMORY;
}
qemufb_driver->probe = qemufb_probe;
pci_driver_register(qemufb_driver);
return KERN_OK;
}
DEFINE_KEXT("net.doorstuck.socks.qemufb",
online, NULL,
PCI_SUBSYSTEM_KEXT_ID);

View File

@@ -1,8 +0,0 @@
name: vesafb
description: |
Boot-time VESA framebuffer driver.
id: net.doorstuck.socks.vesafb
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- main.c

View File

@@ -1,65 +0,0 @@
#include <socks/printk.h>
#include <socks/device.h>
#include <socks/kext.h>
#include <socks/machine/init.h>
#include <socks/libc/stdio.h>
static struct driver *vesa_driver = NULL;
static struct framebuffer_device *vesafb = NULL;
static kern_status_t set_varinfo(struct device *dev, const struct framebuffer_varinfo *info)
{
return KERN_UNSUPPORTED;
}
static struct framebuffer_device_ops vesa_ops = {
.set_varinfo = set_varinfo,
};
static void init_vesa(struct framebuffer_device *dev)
{
struct framebuffer_varinfo *varinfo = &dev->fb_varinfo;
struct framebuffer_fixedinfo *fixedinfo = &dev->fb_fixedinfo;
memcpy(varinfo, bootfb_varinfo(), sizeof *varinfo);
memcpy(fixedinfo, bootfb_fixedinfo(), sizeof *fixedinfo);
}
static kern_status_t online(struct kext *self)
{
const struct framebuffer_fixedinfo *fixedinfo = bootfb_fixedinfo();
if (!fixedinfo->fb_baseptr) {
/* No VESA information avaiable, cannot create device. */
return KERN_OK;
}
vesa_driver = driver_create(self, "vesafb");
if (!vesa_driver) {
return KERN_NO_MEMORY;
}
driver_register(vesa_driver);
struct framebuffer_device *fb = framebuffer_device_create();
fb->fb_ops = &vesa_ops;
init_vesa(fb);
struct device *fb_base = framebuffer_device_base(fb);
snprintf(fb_base->dev_name, sizeof fb_base->dev_name, "vesafb");
kern_status_t status = device_register(fb_base, vesa_driver, misc_device());
if (status != KERN_OK) {
driver_unregister(vesa_driver);
driver_destroy(vesa_driver);
return status;
}
vesafb = fb;
return KERN_OK;
}
DEFINE_KEXT("net.doorstuck.socks.vesafb",
online, NULL,
KEXT_NO_DEPENDENCIES);

View File

@@ -1,9 +0,0 @@
name: hello-world
description: |
A sample kernel extension, demonstrating the structure of a kext.
No actual functionality.
id: net.doorstuck.socks.hello-world
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- main.c

View File

@@ -1,12 +0,0 @@
#include <socks/printk.h>
#include <socks/kext.h>
static kern_status_t online(struct kext *self)
{
printk("Hello, world!");
return KERN_OK;
}
DEFINE_KEXT("net.doorstuck.socks.hello-world",
online, NULL,
"net.doorstuck.socks.test-base");

View File

@@ -1,9 +0,0 @@
name: test-base
description: |
A sample kernel extension, demonstrating the structure of a kext.
No actual functionality.
id: net.doorstuck.socks.test-base
license: BSD-3-Clause
copyright: Copyright © Max Wash 2023
sources:
- main.c

View File

@@ -1,12 +0,0 @@
#include <socks/printk.h>
#include <socks/kext.h>
static kern_status_t online(struct kext *self)
{
printk("Kernel extension base online");
return KERN_OK;
}
DEFINE_KEXT("net.doorstuck.socks.test-base",
online, NULL,
KEXT_NO_DEPENDENCIES);

View File

@@ -1,176 +0,0 @@
#include <socks/kext.h>
#include <socks/printk.h>
#include <socks/vm.h>
#include <socks/util.h>
#include <socks/libc/stdio.h>
static struct kext *self = NULL;
extern struct btree kext_tree;
extern char __kexts_start[];
extern char __kexts_end[];
static kern_status_t collect_dependencies(struct kext *kext, struct kext_info *info)
{
if (!info->k_dependencies) {
return KERN_OK;
}
unsigned int i;
for (i = 0; info->k_dependencies[i]; i++);
kext->k_nr_dependencies = i;
if (!kext->k_nr_dependencies) {
return KERN_OK;
}
kext->k_dependencies = kmalloc(kext->k_nr_dependencies * sizeof (struct kext *), VM_NORMAL);
if (!kext->k_dependencies) {
kext_release(kext);
return KERN_NO_MEMORY;
}
for (i = 0; info->k_dependencies[i]; i++) {
struct kext *dep = kext_get_by_id(info->k_dependencies[i]);
if (!dep) {
kfree(kext->k_dependencies);
printk("kxld: internal kext has unresolved dependency:");
printk("kxld: * kext '%s'", kext->k_ident);
printk("kxld: depends on unknown kext '%s'", info->k_dependencies[i]);
return KERN_NO_ENTRY;
}
kext->k_dependencies[i] = dep;
}
return KERN_OK;
}
static kern_status_t create_kext_from_info(struct kext_info *info, struct kext **out)
{
struct kext *kext = kext_alloc();
if (!kext) {
return KERN_NO_MEMORY;
}
strncpy(kext->k_ident, info->k_ident, sizeof kext->k_ident);
kext->k_ident[sizeof kext->k_ident - 1] = 0;
kext->k_ident_hash = hash_string(kext->k_ident);
kext->k_flags = KEXT_INTERNAL;
kext->k_online = info->k_online;
kext->k_offline = info->k_offline;
kext->k_dependencies = NULL;
kext->k_nr_dependencies = 0;
if (info->k_dependencies) {
unsigned int i;
for (i = 0; info->k_dependencies[i]; i++);
kext->k_nr_dependencies = i;
}
*out = kext;
return KERN_OK;
}
struct kext *kernel_kext(void)
{
return self;
}
kern_status_t register_internal_kexts(void)
{
struct kext_info *cur = (struct kext_info *)__kexts_start;
struct kext_info *end = (struct kext_info *)__kexts_end;
while (cur < end) {
struct kext *kext;
kern_status_t status = create_kext_from_info(cur, &kext);
if (status != KERN_OK) {
return status;
}
status = kext_register(kext);
if (status != KERN_OK) {
kext_release(kext);
return status;
}
cur = (struct kext_info *)((char *)cur + __KEXT_INFO_ALIGNMENT);
}
return KERN_OK;
}
kern_status_t resolve_internal_dependencies(void)
{
struct kext_info *cur = (struct kext_info *)__kexts_start;
struct kext_info *end = (struct kext_info *)__kexts_end;
while (cur < end) {
struct kext *kext = kext_get_by_id(cur->k_ident);
if (!kext) {
return KERN_NO_ENTRY;
}
kern_status_t status = collect_dependencies(kext, cur);
kext_release(kext);
if (status != KERN_OK) {
return status;
}
cur = (struct kext_info *)((char *)cur + __KEXT_INFO_ALIGNMENT);
}
return KERN_OK;
}
kern_status_t init_kernel_kext(void)
{
kext_cache_init();
self = kext_alloc();
if (!self) {
return KERN_NO_MEMORY;
}
snprintf(self->k_ident, sizeof self->k_ident, "%s", KERNEL_KEXT_ID);
self->k_flags = KEXT_INTERNAL | KEXT_ONLINE;
self->k_nr_dependencies = 0;
self->k_dependencies = NULL;
kext_register(self);
return KERN_OK;
}
kern_status_t scan_internal_kexts(void)
{
kern_status_t status = register_internal_kexts();
if (status != KERN_OK) {
return status;
}
status = resolve_internal_dependencies();
return status;
}
kern_status_t bring_internal_kexts_online(void)
{
struct btree_node *cur = btree_first(&kext_tree);
while (cur) {
struct kext *kext = BTREE_CONTAINER(struct kext, k_node, cur);
kern_status_t status = kext_bring_online(kext);
if (status != KERN_OK) {
return status;
}
cur = btree_next(cur);
}
return KERN_OK;
}

View File

@@ -1,187 +0,0 @@
#include <socks/kext.h>
#include <socks/btree.h>
#include <socks/vm.h>
#include <socks/util.h>
#include <socks/object.h>
#include <stddef.h>
#define KEXT_CAST(p) OBJECT_C_CAST(struct kext, k_base, &kext_type, p)
static spin_lock_t kext_tree_lock = SPIN_LOCK_INIT;
static struct object *kext_set;
struct btree kext_tree;
static struct object_type kext_type;
static kern_status_t kext_query_name(struct object *obj, char out[OBJECT_NAME_MAX])
{
struct kext *kext = KEXT_CAST(obj);
strncpy(out, kext->k_ident, OBJECT_NAME_MAX - 1);
out[OBJECT_NAME_MAX - 1] = 0;
return KERN_OK;
}
static kern_status_t kext_destroy(struct object *obj)
{
struct kext *kext = KEXT_CAST(obj);
if (kext->k_dependencies) {
kfree(kext->k_dependencies);
}
return KERN_OK;
}
static struct object_type kext_type = {
.ob_name = "kext",
.ob_size = sizeof(struct kext),
.ob_header_offset = offsetof(struct kext, k_base),
.ob_ops = {
.query_name = kext_query_name,
},
};
static struct kext *kext_get(const char *ident)
{
uint64_t ident_hash = hash_string(ident);
struct btree_node *cur = kext_tree.b_root;
while (cur) {
struct kext *cur_node = BTREE_CONTAINER(struct kext, k_node, cur);
if (ident_hash > cur_node->k_ident_hash) {
cur = btree_right(cur);
} else if (ident_hash < cur_node->k_ident_hash) {
cur = btree_left(cur);
} else if (!strcmp(cur_node->k_ident, ident)) {
return cur_node;
}
}
return NULL;
}
static void kext_add(struct kext *kext)
{
if (!kext_tree.b_root) {
kext_tree.b_root = &kext->k_node;
btree_insert_fixup(&kext_tree, &kext->k_node);
return;
}
struct btree_node *cur = kext_tree.b_root;
while (1) {
struct kext *cur_node = BTREE_CONTAINER(struct kext, k_node, cur);
struct btree_node *next = NULL;
if (kext->k_ident_hash > cur_node->k_ident_hash) {
next = btree_right(cur);
if (!next) {
btree_put_right(cur, &kext->k_node);
break;
}
} else if (kext->k_ident_hash < cur_node->k_ident_hash) {
next = btree_left(cur);
if (!next) {
btree_put_left(cur, &kext->k_node);
break;
}
} else {
return;
}
cur = next;
}
btree_insert_fixup(&kext_tree, &kext->k_node);
}
static void kext_remove(struct kext *kext)
{
btree_delete(&kext_tree, &kext->k_node);
}
struct kext *kext_get_by_id(const char *ident)
{
unsigned long flags;
spin_lock_irqsave(&kext_tree_lock, &flags);
struct kext *kext = kext_get(ident);
if (kext) {
struct object *kext_obj = &kext->k_base;
object_ref(kext_obj);
}
spin_unlock_irqrestore(&kext_tree_lock, flags);
return kext;
}
kern_status_t kext_cache_init(void)
{
object_type_register(&kext_type);
kext_set = set_create("kexts");
object_publish(global_namespace(), "/", kext_set);
return KERN_OK;
}
struct kext *kext_alloc(void)
{
struct object *kext_obj = object_create(&kext_type);
if (!kext_obj) {
return NULL;
}
return KEXT_CAST(kext_obj);
}
void kext_release(struct kext *kext)
{
object_deref(&kext->k_base);
}
kern_status_t kext_register(struct kext *kext)
{
unsigned long flags;
spin_lock_irqsave(&kext_tree_lock, &flags);
struct kext *n = kext_get(kext->k_ident);
if (n) {
spin_unlock_irqrestore(&kext_tree_lock, flags);
return KERN_NAME_EXISTS;
}
struct object *kext_obj = &kext->k_base;
object_ref(kext_obj);
kext_add(kext);
set_add_object(kext_set, kext_obj);
spin_unlock_irqrestore(&kext_tree_lock, flags);
return KERN_OK;
}
kern_status_t kext_bring_online(struct kext *kext)
{
if (kext->k_flags & KEXT_ONLINE) {
return KERN_OK;
}
kern_status_t status;
for (unsigned int i = 0; i < kext->k_nr_dependencies; i++) {
status = kext_bring_online(kext->k_dependencies[i]);
if (status != KERN_OK) {
return status;
}
}
if (kext->k_online) {
status = kext->k_online(kext);
if (status != KERN_OK) {
return status;
}
}
kext->k_flags |= KEXT_ONLINE;
return KERN_OK;
}