kernel: remove everything that is related to device/fs management
this is now a microkernel.
This commit is contained in:
17
Makefile
17
Makefile
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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 = .;
|
||||
|
||||
333
dev/block.c
333
dev/block.c
@@ -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, §_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, §ors_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, §or_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, §or_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, §or_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);
|
||||
}
|
||||
71
dev/bus.c
71
dev/bus.c
@@ -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,
|
||||
};
|
||||
48
dev/char.c
48
dev/char.c
@@ -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,
|
||||
};
|
||||
297
dev/core.c
297
dev/core.c
@@ -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;
|
||||
}
|
||||
176
dev/driver.c
176
dev/driver.c
@@ -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;
|
||||
}
|
||||
94
dev/fb.c
94
dev/fb.c
@@ -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,
|
||||
};
|
||||
134
dev/input.c
134
dev/input.c
@@ -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,
|
||||
};
|
||||
19
dev/net.c
19
dev/net.c
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
112
init/main.c
112
init/main.c
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
110
kernel/tty/tty.c
110
kernel/tty/tty.c
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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");
|
||||
@@ -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
|
||||
@@ -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);
|
||||
176
kxld/internal.c
176
kxld/internal.c
@@ -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;
|
||||
}
|
||||
187
kxld/kext.c
187
kxld/kext.c
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user