diff --git a/arch/x86_64/acpi/acpi.c b/arch/x86_64/acpi/acpi.c index 779972b..6b12040 100644 --- a/arch/x86_64/acpi/acpi.c +++ b/arch/x86_64/acpi/acpi.c @@ -22,7 +22,7 @@ kern_status_t acpi_init(void) acpi_dev->b_ops = &acpi_ops; snprintf(base->dev_name, sizeof base->dev_name, "acpi"); - device_register(base, root_device()); + device_register(base, system_driver(), root_device()); return KERN_OK; } diff --git a/arch/x86_64/init.c b/arch/x86_64/init.c index d6c3ba0..36ffaaa 100644 --- a/arch/x86_64/init.c +++ b/arch/x86_64/init.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -79,6 +80,8 @@ int ml_init(uintptr_t arg) vm_bootstrap(vm_zones, sizeof vm_zones / sizeof vm_zones[0]); object_bootstrap(); + init_kernel_kext(); + sched_init(); device_init(); diff --git a/dev/block.c b/dev/block.c index e50a50c..44fa8f3 100644 --- a/dev/block.c +++ b/dev/block.c @@ -8,5 +8,6 @@ struct block_device *block_device_create(void) } dev->dev_type = DEV_TYPE_BLOCK; + return BLOCK_DEVICE(dev); } diff --git a/dev/bus.c b/dev/bus.c index 1fcdcbc..3c1e542 100644 --- a/dev/bus.c +++ b/dev/bus.c @@ -8,5 +8,6 @@ struct bus_device *bus_device_create(void) } dev->dev_type = DEV_TYPE_BUS; + return BUS_DEVICE(dev); } diff --git a/dev/char.c b/dev/char.c index 238da97..27c959a 100644 --- a/dev/char.c +++ b/dev/char.c @@ -8,5 +8,6 @@ struct char_device *char_device_create(void) } dev->dev_type = DEV_TYPE_CHAR; + return CHAR_DEVICE(dev); } diff --git a/dev/core.c b/dev/core.c index 0d45e8a..bea49ad 100644 --- a/dev/core.c +++ b/dev/core.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #define DEVICE_CAST(p) OBJECT_C_CAST(struct device, dev_base, &device_type, p) @@ -15,6 +16,8 @@ static kern_status_t device_object_query_name(struct object *, char out[OBJECT_N 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); + static struct object_type device_type = { .ob_name = "device", .ob_size = sizeof(struct device), @@ -42,36 +45,31 @@ static kern_status_t set_root_device(struct device *dev) return KERN_OK; } -static kern_status_t device_generate_name(struct device *dev) -{ - switch (dev->dev_type) { - case DEV_TYPE_INPUT: - return input_device_generate_name(&dev->input); - default: - break; - } - - return KERN_UNSUPPORTED; -} - 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(system_dev_base); + __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; - device_register(__misc_device, __root_device); + struct driver *system = system_driver(); + + device_register(__root_device, system, NULL); + device_register(__misc_device, system, __root_device); return KERN_OK; } @@ -179,23 +177,11 @@ static kern_status_t device_object_get_child_named(struct object *obj, const cha return KERN_NO_ENTRY; } -kern_status_t device_register(struct device *dev, struct device *parent) +static kern_status_t add_device_to_parent(struct device *dev, struct device *parent) { - unsigned long flags; - device_lock_irqsave(dev, &flags); - kern_status_t status = KERN_OK; - if (dev->dev_name[0] == 0) { - status = device_generate_name(dev); - } - - if (status != KERN_OK) { - device_unlock_irqrestore(dev, flags); - return status; - } - - queue_foreach (struct device, child, &dev->dev_children, dev_childent) { + queue_foreach (struct device, child, &parent->dev_children, dev_childent) { if (!strcmp(dev->dev_name, child->dev_name)) { status = KERN_NAME_EXISTS; break; @@ -203,12 +189,56 @@ kern_status_t device_register(struct device *dev, struct device *parent) } if (status != KERN_OK) { - device_unlock_irqrestore(dev, flags); 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); + driver_lock(owner); + + 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); + + switch (dev->dev_type) { + case DEV_TYPE_INPUT: + status = input_device_register(INPUT_DEVICE(dev)); + break; + default: + break; + } + + + driver_unlock(owner); device_unlock_irqrestore(dev, flags); + return status; } diff --git a/dev/driver.c b/dev/driver.c new file mode 100644 index 0000000..501570e --- /dev/null +++ b/dev/driver.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include + +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; + } + + 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 driver; +} + +kern_status_t driver_destroy(struct driver *driver) +{ + if (btree_first(&driver->drv_children)) { + return KERN_BUSY; + } + + 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_UNIMPLEMENTED; +} + +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; +} diff --git a/dev/input.c b/dev/input.c index f6c0917..bf7c7a8 100644 --- a/dev/input.c +++ b/dev/input.c @@ -21,14 +21,6 @@ struct input_device *input_device_create(void) return NULL; } - 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); - - input_dev->i_id = id; - return INPUT_DEVICE(dev); } @@ -63,9 +55,27 @@ kern_status_t input_device_read(struct device *dev, void *buf, size_t size, size return KERN_OK; } -kern_status_t input_device_generate_name(struct input_device *dev) +static kern_status_t generate_name(struct input_device *dev, char out[DEV_NAME_MAX]) { - struct device *d = input_device_base(dev); - snprintf(d->dev_name, sizeof d->dev_name, "input%u", dev->i_id); + snprintf(out, DEV_NAME_MAX, "input%u", dev->i_id); return KERN_OK; } + +kern_status_t input_device_register(struct input_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); + + dev->i_id = id; + + char name[DEV_NAME_MAX]; + generate_name(dev, name); + char path[OBJECT_PATH_MAX]; + snprintf(path, sizeof path, "/dev/input/%s", name); + + struct device *base = input_device_base(dev); + return object_namespace_create_link(global_namespace(), path, &base->dev_base); +} diff --git a/dev/net.c b/dev/net.c index 773a36d..c3ba735 100644 --- a/dev/net.c +++ b/dev/net.c @@ -8,5 +8,6 @@ struct net_device *net_device_create(void) } dev->dev_type = DEV_TYPE_NET; + return NET_DEVICE(dev); } diff --git a/include/socks/device.h b/include/socks/device.h index 1616beb..02de1bc 100644 --- a/include/socks/device.h +++ b/include/socks/device.h @@ -2,7 +2,9 @@ #define SOCKS_DEVICE_H_ #include +#include #include +#include #include #include @@ -10,17 +12,22 @@ struct device; struct input_event; #define DEV_NAME_MAX OBJECT_NAME_MAX +#define DEV_MAJOR_MAX 1024 +#define DEV_MINOR_MAX 1024 +#define DEV_MAJOR_INVALID ((unsigned int)0) +#define DEV_MINOR_INVALID ((unsigned int)0) #define INPUT_DEVICE_EVENT_QUEUE_SIZE 128 #define INPUT_DEVICE_MAX 4096 -#define BLOCK_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_BLOCK ? &(dev)->blk : NULL); -#define CHAR_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_CHAR ? &(dev)->chr : NULL); -#define NET_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_NET ? &(dev)->net : NULL); -#define INPUT_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_INPUT ? &(dev)->input : NULL); -#define BUS_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_BUS ? &(dev)->bus : NULL); +#define BLOCK_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_BLOCK ? &(dev)->blk : NULL) +#define CHAR_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_CHAR ? &(dev)->chr : NULL) +#define NET_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_NET ? &(dev)->net : NULL) +#define INPUT_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_INPUT ? &(dev)->input : NULL) +#define BUS_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_BUS ? &(dev)->bus : NULL) enum device_type { + DEV_TYPE_UNKNOWN = 0, DEV_TYPE_BLOCK, DEV_TYPE_CHAR, DEV_TYPE_NET, @@ -78,10 +85,14 @@ struct bus_device { struct device { struct object dev_base; + unsigned int dev_minor; + enum device_type dev_type; struct device *dev_parent; + struct driver *dev_owner; struct queue dev_children; struct queue_entry dev_childent; + struct btree_node dev_driverent; char dev_name[DEV_NAME_MAX]; void *dev_priv; @@ -95,19 +106,48 @@ struct device { }; }; +struct driver; + +struct driver_ops { + kern_status_t(*bind)(struct driver *, struct device *, struct device *); +}; + +struct driver { + struct kext *drv_owner; + unsigned int drv_major; + DECLARE_BITMAP(drv_minors, DEV_MINOR_MAX); + char drv_name[DEV_NAME_MAX]; + struct btree drv_children; + struct btree_node drv_ent; + spin_lock_t drv_lock; + + void *drv_priv; + struct driver_ops *drv_ops; +}; + extern kern_status_t device_init(void); extern struct device *root_device(void); extern struct device *misc_device(void); extern struct device *device_alloc(void); +static inline void device_lock(struct device *dev) +{ + object_lock(&dev->dev_base); +} + +static inline void device_unlock(struct device *dev) +{ + object_unlock(&dev->dev_base); +} + static inline void device_lock_irqsave(struct device *dev, unsigned long *flags) { - object_lock(&dev->dev_base, flags); + object_lock_irqsave(&dev->dev_base, flags); } static inline void device_unlock_irqrestore(struct device *dev, unsigned long flags) { - object_unlock(&dev->dev_base, flags); + object_unlock_irqrestore(&dev->dev_base, flags); } extern kern_status_t device_read(struct device *dev, void *buf, size_t size, size_t *bytes_read, socks_flags_t flags); @@ -146,10 +186,40 @@ static inline struct device *bus_device_base(struct bus_device *dev) return (struct device *)((char *)dev - offsetof(struct device, bus)); } -extern kern_status_t device_register(struct device *dev, struct device *parent); +extern kern_status_t device_register(struct device *dev, struct driver *owner, struct device *parent); extern kern_status_t input_device_report_event(struct input_device *dev, const struct input_event *ev, bool noblock); extern kern_status_t input_device_read(struct device *dev, void *buf, size_t size, size_t *bytes_read, socks_flags_t flags); -extern kern_status_t input_device_generate_name(struct input_device *dev); +extern kern_status_t input_device_register(struct input_device *dev); + +extern struct driver *driver_create(struct kext *self, const char *name); +extern kern_status_t driver_destroy(struct driver *driver); +extern kern_status_t driver_register(struct driver *driver); +extern kern_status_t driver_unregister(struct driver *driver); +extern unsigned int driver_alloc_minor(struct driver *driver); +extern void driver_free_minor(struct driver *driver, unsigned int minor); +extern struct device *driver_get_device(struct driver *driver, unsigned int minor); +extern kern_status_t driver_add_device(struct driver *driver, struct device *dev); +extern struct driver *system_driver(void); + +static inline void driver_lock(struct driver *driver) +{ + spin_lock(&driver->drv_lock); +} + +static inline void driver_unlock(struct driver *driver) +{ + spin_unlock(&driver->drv_lock); +} + +static inline void driver_lock_irqsave(struct driver *driver, unsigned long *flags) +{ + spin_lock_irqsave(&driver->drv_lock, flags); +} + +static inline void driver_unlock_irqrestore(struct driver *driver, unsigned long flags) +{ + spin_unlock_irqrestore(&driver->drv_lock, flags); +} #endif diff --git a/include/socks/kext.h b/include/socks/kext.h index 7e67f45..43a0613 100644 --- a/include/socks/kext.h +++ b/include/socks/kext.h @@ -86,6 +86,9 @@ struct kext { extern kern_status_t scan_internal_kexts(void); extern kern_status_t bring_internal_kexts_online(void); +extern kern_status_t init_kernel_kext(void); +extern struct kext *kernel_kext(void); + extern kern_status_t kext_cache_init(void); extern struct kext *kext_alloc(void); extern void kext_release(struct kext *kext); diff --git a/include/socks/locks.h b/include/socks/locks.h index d35138b..f09cf6e 100644 --- a/include/socks/locks.h +++ b/include/socks/locks.h @@ -12,6 +12,9 @@ typedef __aligned(8) ml_hwlock_t spin_lock_t; #define SPIN_LOCK_INIT ML_HWLOCK_INIT +#define spin_lock(lck) ml_hwlock_lock(lck); +#define spin_unlock(lck) ml_hwlock_unlock(lck); + #define spin_lock_irqsave(lck, flags) ml_hwlock_lock_irqsave(lck, flags); #define spin_unlock_irqrestore(lck, flags) ml_hwlock_unlock_irqrestore(lck, flags); diff --git a/include/socks/sched.h b/include/socks/sched.h index 9a6db72..2e48612 100644 --- a/include/socks/sched.h +++ b/include/socks/sched.h @@ -173,12 +173,12 @@ extern void end_charge_period(void); static inline void task_lock_irqsave(struct task *task, unsigned long *flags) { - object_lock(&task->t_base, flags); + object_lock_irqsave(&task->t_base, flags); } static inline void task_unlock_irqrestore(struct task *task, unsigned long flags) { - object_unlock(&task->t_base, flags); + object_unlock_irqrestore(&task->t_base, flags); } extern struct thread *thread_alloc(void); diff --git a/include/socks/status.h b/include/socks/status.h index 27a03e1..c65c0d8 100644 --- a/include/socks/status.h +++ b/include/socks/status.h @@ -11,6 +11,7 @@ typedef unsigned int kern_status_t; #define KERN_NO_MEMORY (5) #define KERN_NO_ENTRY (6) #define KERN_WOULD_BLOCK (7) +#define KERN_BUSY (8) extern const char *kern_status_string(kern_status_t status); diff --git a/init/main.c b/init/main.c index cbac796..de86d28 100644 --- a/init/main.c +++ b/init/main.c @@ -182,31 +182,19 @@ void kernel_init(uintptr_t arg) printk("kernel_init() running on processor %u", this_cpu()); - run_all_tests(); create_kernel_thread(background_thread); struct object *kbd; - status = object_namespace_get_object(global_namespace(), "/dev/system/misc/input0", &kbd); + + run_all_tests(); + + status = object_namespace_get_object(global_namespace(), "/dev/input/input0", &kbd); if (status != KERN_OK) { printk("no keyboard available"); hang(); } - #if 0 - struct device *kbd_dev = cast_to_device(kbd_obj); - if (!kbd_dev) { - printk("no keyboard available"); - hang(); - } - - struct input_device *kbd = INPUT_DEVICE(kbd_dev); - if (!kbd) { - printk("no keyboard available"); - hang(); - } - #endif - while (1) { struct input_event ev; size_t r; diff --git a/kexts/drivers/input/ps2kbd/main.c b/kexts/drivers/input/ps2kbd/main.c index 677b716..c8bcda1 100644 --- a/kexts/drivers/input/ps2kbd/main.c +++ b/kexts/drivers/input/ps2kbd/main.c @@ -44,6 +44,7 @@ static const enum input_keycode *keymaps[] = { keymap_l4, }; +static struct driver *ps2_driver = NULL; static struct input_device *keyboard = NULL, *mouse = NULL; static void send_cmd(uint8_t cmd) @@ -201,21 +202,28 @@ static int init_controller(void) return 0; } -static kern_status_t create_devices(void) +static kern_status_t create_devices(struct kext *self) { + ps2_driver = driver_create(self, "ps2"); + if (!ps2_driver) { + return KERN_NO_MEMORY; + } + 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, misc_device()); + 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, misc_device()); + status = device_register(ms_base, ps2_driver, misc_device()); if (status != KERN_OK) { return status; } @@ -237,7 +245,7 @@ static kern_status_t online(struct kext *self) return KERN_UNSUPPORTED; } - kern_status_t status = create_devices(); + kern_status_t status = create_devices(self); if (status != KERN_OK) { return status; } diff --git a/kxld/internal.c b/kxld/internal.c index c3d1b3a..1349b40 100644 --- a/kxld/internal.c +++ b/kxld/internal.c @@ -74,6 +74,11 @@ static kern_status_t create_kext_from_info(struct kext_info *info, struct 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; @@ -122,7 +127,7 @@ kern_status_t resolve_internal_dependencies(void) return KERN_OK; } -kern_status_t scan_internal_kexts(void) +kern_status_t init_kernel_kext(void) { kext_cache_init(); @@ -138,7 +143,11 @@ kern_status_t scan_internal_kexts(void) 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;