diff --git a/kernel/arch/riscv64/syscall_table.json b/kernel/arch/riscv64/syscall_table.json index f9ca784aa..ec0bcafad 100644 --- a/kernel/arch/riscv64/syscall_table.json +++ b/kernel/arch/riscv64/syscall_table.json @@ -3087,17 +3087,213 @@ "abi": "c" }, { - "name": "listxattr", - "nr": 194, - "nr_args": 3, + "name": "mlock", + "nr": 176, + "nr_args": 2, + "args": [ + [ + "const void *", + "addr" + ], + [ + "size_t", + "len" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "munlock", + "nr": 177, + "nr_args": 2, + "args": [ + [ + "const void *", + "addr" + ], + [ + "size_t", + "len" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "mlockall", + "nr": 178, + "nr_args": 1, + "args": [ + [ + "int", + "flags" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "munlockall", + "nr": 179, + "nr_args": 0, + "args": [], + "return_type": "int", + "abi": "c" + }, + { + "name": "setxattr", + "nr": 188, + "nr_args": 5, "args": [ [ "const char *", "path" ], [ - "char *", - "list" + "const char *", + "name" + ], + [ + "const void *", + "value" + ], + [ + "size_t", + "size" + ], + [ + "int", + "flags" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "lsetxattr", + "nr": 189, + "nr_args": 5, + "args": [ + [ + "const char *", + "path" + ], + [ + "const char *", + "name" + ], + [ + "const void *", + "value" + ], + [ + "size_t", + "size" + ], + [ + "int", + "flags" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "fsetxattr", + "nr": 190, + "nr_args": 5, + "args": [ + [ + "int", + "fd" + ], + [ + "const char *", + "name" + ], + [ + "const void *", + "value" + ], + [ + "size_t", + "size" + ], + [ + "int", + "flags" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "getxattr", + "nr": 191, + "nr_args": 5, + "args": [ + [ + "const char *", + "path" + ], + [ + "const char *", + "name" + ], + [ + "void *", + "value" + ], + [ + "size_t", + "size" + ] + ], + "return_type": "ssize_t", + "abi": "c" + }, + { + "name": "lgetxattr", + "nr": 192, + "nr_args": 5, + "args": [ + [ + "const char *", + "path" + ], + [ + "const char *", + "name" + ], + [ + "void *", + "value" + ], + [ + "size_t", + "size" + ] + ], + "return_type": "ssize_t", + "abi": "c" + }, + { + "name": "fgetxattr", + "nr": 193, + "nr_args": 5, + "args": [ + [ + "int", + "fd" + ], + [ + "const char *", + "name" + ], + [ + "void *", + "value" ], [ "size_t", @@ -3127,5 +3323,56 @@ ], "return_type": "ssize_t", "abi": "c" + }, + { + "name": "removexattr", + "nr": 197, + "nr_args": 2, + "args": [ + [ + "const char *", + "path" + ], + [ + "const char *", + "name" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "lremovexattr", + "nr": 198, + "nr_args": 2, + "args": [ + [ + "const char *", + "path" + ], + [ + "const char *", + "name" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "fremovexattr", + "nr": 199, + "nr_args": 2, + "args": [ + [ + "int", + "fd" + ], + [ + "const char *", + "name" + ] + ], + "return_type": "int", + "abi": "c" } ] diff --git a/kernel/arch/x86_64/syscall_table.json b/kernel/arch/x86_64/syscall_table.json index 5345b8ebe..2962a32e4 100644 --- a/kernel/arch/x86_64/syscall_table.json +++ b/kernel/arch/x86_64/syscall_table.json @@ -3131,6 +3131,61 @@ "return_type": "int", "abi": "c" }, + { + "name": "mlock", + "nr": 176, + "nr_args": 2, + "args": [ + [ + "const void *", + "addr" + ], + [ + "size_t", + "len" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "munlock", + "nr": 177, + "nr_args": 2, + "args": [ + [ + "const void *", + "addr" + ], + [ + "size_t", + "len" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "mlockall", + "nr": 178, + "nr_args": 1, + "args": [ + [ + "int", + "flags" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "munlockall", + "nr": 179, + "nr_args": 0, + "args": [], + "return_type": "int", + "abi": "c" + }, { "name": "listxattr", "nr": 194, @@ -3152,6 +3207,168 @@ "return_type": "ssize_t", "abi": "c" }, + { + "name": "setxattr", + "nr": 188, + "nr_args": 5, + "args": [ + [ + "const char *", + "path" + ], + [ + "const char *", + "name" + ], + [ + "const void *", + "value" + ], + [ + "size_t", + "size" + ], + [ + "int", + "flags" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "lsetxattr", + "nr": 189, + "nr_args": 5, + "args": [ + [ + "const char *", + "path" + ], + [ + "const char *", + "name" + ], + [ + "const void *", + "value" + ], + [ + "size_t", + "size" + ], + [ + "int", + "flags" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "fsetxattr", + "nr": 190, + "nr_args": 5, + "args": [ + [ + "int", + "fd" + ], + [ + "const char *", + "name" + ], + [ + "const void *", + "value" + ], + [ + "size_t", + "size" + ], + [ + "int", + "flags" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "getxattr", + "nr": 191, + "nr_args": 5, + "args": [ + [ + "const char *", + "path" + ], + [ + "const char *", + "name" + ], + [ + "void *", + "value" + ], + [ + "size_t", + "size" + ] + ], + "return_type": "ssize_t", + "abi": "c" + }, + { + "name": "lgetxattr", + "nr": 192, + "nr_args": 5, + "args": [ + [ + "const char *", + "path" + ], + [ + "const char *", + "name" + ], + [ + "void *", + "value" + ], + [ + "size_t", + "size" + ] + ], + "return_type": "ssize_t", + "abi": "c" + }, + { + "name": "fgetxattr", + "nr": 193, + "nr_args": 5, + "args": [ + [ + "int", + "fd" + ], + [ + "const char *", + "name" + ], + [ + "void *", + "value" + ], + [ + "size_t", + "size" + ] + ], + "return_type": "ssize_t", + "abi": "c" + }, { "name": "llistxattr", "nr": 195, @@ -3172,5 +3389,56 @@ ], "return_type": "ssize_t", "abi": "c" + }, + { + "name": "removexattr", + "nr": 197, + "nr_args": 2, + "args": [ + [ + "const char *", + "path" + ], + [ + "const char *", + "name" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "lremovexattr", + "nr": 198, + "nr_args": 2, + "args": [ + [ + "const char *", + "path" + ], + [ + "const char *", + "name" + ] + ], + "return_type": "int", + "abi": "c" + }, + { + "name": "fremovexattr", + "nr": 199, + "nr_args": 2, + "args": [ + [ + "int", + "fd" + ], + [ + "const char *", + "name" + ] + ], + "return_type": "int", + "abi": "c" } ] diff --git a/kernel/drivers/net/e1000/e1000.cpp b/kernel/drivers/net/e1000/e1000.cpp index 8a22097d7..1485ddb93 100644 --- a/kernel/drivers/net/e1000/e1000.cpp +++ b/kernel/drivers/net/e1000/e1000.cpp @@ -1,7 +1,9 @@ /* - * Copyright (c) 2016, 2017 Pedro Falcato - * This file is part of Onyx, and is released under the terms of the MIT License + * Copyright (c) 2016 - 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information + * + * SPDX-License-Identifier: GPL-2.0-only */ #include "e1000.h" @@ -811,6 +813,7 @@ int e1000_probe(struct device *__dev) n->rx_end = e1000_rxend; nicdev->nic_netif = n; n->dll_ops = ð_ops; + n->tx_queue_len = number_tx_desc; memcpy(n->mac_address, nicdev->e1000_internal_mac_address, 6); netif_register_if(n); @@ -830,5 +833,5 @@ int e1000_init(void) MODULE_INIT(e1000_init); MODULE_INSERT_VERSION(); -MODULE_LICENSE(MODULE_LICENSE_MIT); +MODULE_LICENSE(MODULE_LICENSE_GPL2); MODULE_AUTHOR("Pedro Falcato"); diff --git a/kernel/drivers/net/rtl8168/rtl8168.cpp b/kernel/drivers/net/rtl8168/rtl8168.cpp index f489b2179..bddd97b64 100644 --- a/kernel/drivers/net/rtl8168/rtl8168.cpp +++ b/kernel/drivers/net/rtl8168/rtl8168.cpp @@ -1,9 +1,9 @@ /* - * Copyright (c) 2021 - 2022 Pedro Falcato - * This file is part of Onyx, and is released under the terms of the MIT License + * Copyright (c) 2021 - 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: GPL-2.0-only */ #include "rtl8168.h" @@ -549,6 +549,7 @@ int rtl8168_device::init() n->rx_end = rtl8168_rx_end; netif_ = n; n->dll_ops = ð_ops; + n->tx_queue_len = number_tx_desc; memcpy(n->mac_address, mac_, 6); netif_register_if(n); @@ -618,5 +619,5 @@ int rtl8168_init(void) MODULE_INIT(rtl8168_init); MODULE_INSERT_VERSION(); -MODULE_LICENSE(MODULE_LICENSE_MIT); +MODULE_LICENSE(MODULE_LICENSE_GPL2); MODULE_AUTHOR("Pedro Falcato"); diff --git a/kernel/drivers/nvme/nvme.cpp b/kernel/drivers/nvme/nvme.cpp index 3166b2334..fd983d085 100644 --- a/kernel/drivers/nvme/nvme.cpp +++ b/kernel/drivers/nvme/nvme.cpp @@ -401,7 +401,7 @@ int nvme_device::setup_prp(struct request *breq, nvme_namespace *ns) // allocate another page if (!current_list_page || (list_index == prp_entries - 1 && has_next)) { - current_list_page = alloc_page(PAGE_ALLOC_NO_ZERO); + current_list_page = alloc_page(GFP_ATOMIC | PAGE_ALLOC_NO_ZERO); if (!current_list_page) { st = -ENOMEM; diff --git a/kernel/drivers/ps2/controller.cpp b/kernel/drivers/ps2/controller.cpp index 128472a4b..b719e6f8c 100644 --- a/kernel/drivers/ps2/controller.cpp +++ b/kernel/drivers/ps2/controller.cpp @@ -1,9 +1,9 @@ /* - * Copyright (c) 2016 - 2022 Pedro Falcato - * This file is part of Onyx, and is released under the terms of the MIT License + * Copyright (c) 2016 - 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: GPL-2.0-only */ #include #include @@ -21,14 +21,19 @@ extern void send_event_to_kernel(unsigned char keycode); irqstatus_t ps2_irq(struct irq_context *ctx, void *cookie) { + struct ps2_controller *controller; + struct ps2_port *port; unsigned char status; - struct ps2_port *port = (ps2_port *) cookie; + port = (struct ps2_port *) cookie; + controller = port->controller; - status = inb(port->controller->command_port); + status = inb(controller->command_port); if (status & PS2_STATUS_OUTPUT_BUFFER_FULL) { + /* The real port comes from looking at the status */ + port = &controller->ports[(status & PS2_STATUS_AUX) != 0]; if (port->on_byte) port->on_byte(port); } @@ -137,7 +142,7 @@ void ps2_wait_for_input_buffer(struct ps2_controller *controller) void ps2_wait_for_byte(struct ps2_controller *controller) { - while (inb(controller->command_port) & PS2_STATUS_OUTPUT_BUFFER_FULL) + while (!(inb(controller->command_port) & PS2_STATUS_OUTPUT_BUFFER_FULL)) cpu_relax(); } @@ -269,7 +274,7 @@ int ps2_reset_device(struct ps2_port *port) { /* The mouse outputs another byte */ ps2_wait_for_byte(port->controller); - inb(port->controller->data_port); + pr_info("ps2: mouse type %u\n", inb(port->controller->data_port)); } port->has_device = true; @@ -387,6 +392,8 @@ int ps2_probe(struct device *device) if (controller->ports[0].has_device) ps2_keyboard_init(&controller->ports[0]); + if (controller->ports[1].has_device) + ps2_mouse_init(&controller->ports[1]); if (ps2_enable_irqs(controller) < 0) printf("ps2: Could not enable irqs\n"); @@ -425,9 +432,10 @@ struct driver ps2_mouse_driver = {.name = "ps2mouse", struct driver ps2_platform_driver = {.name = "ps2", .bus_type_node = {&ps2_platform_driver}}; -struct device ps2_platform_device -{ - "ps2", nullptr, nullptr +struct device ps2_platform_device{ + "ps2", + nullptr, + nullptr, }; int ps2_probe_keyboard(device *device) diff --git a/kernel/drivers/ps2/keyboard.cpp b/kernel/drivers/ps2/keyboard.cpp index 77234c0e4..799f961fd 100644 --- a/kernel/drivers/ps2/keyboard.cpp +++ b/kernel/drivers/ps2/keyboard.cpp @@ -1,13 +1,14 @@ /* - * Copyright (c) 2018 - 2021 Pedro Falcato - * This file is part of Onyx, and is released under the terms of the MIT License + * Copyright (c) 2018 - 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: GPL-2.0-only */ #include +#include #include #include #include @@ -15,96 +16,107 @@ #include "ps2.h" -unsigned int set1_keymap[] = { - KEYMAP_NOT_MAPPED, - KEYMAP_KEY_ESC, - KEYMAP_KEY_1, - KEYMAP_KEY_2, - KEYMAP_KEY_3, - KEYMAP_KEY_4, - KEYMAP_KEY_5, - KEYMAP_KEY_6, - KEYMAP_KEY_7, - KEYMAP_KEY_8, - KEYMAP_KEY_9, - KEYMAP_KEY_0, - KEYMAP_KEY_MINUS, - KEYMAP_KEY_EQUALS, - KEYMAP_KEY_BACKSPACE, - KEYMAP_KEY_TAB, - KEYMAP_KEY_Q, - KEYMAP_KEY_W, - KEYMAP_KEY_E, - KEYMAP_KEY_R, - KEYMAP_KEY_T, - KEYMAP_KEY_Y, - KEYMAP_KEY_U, - KEYMAP_KEY_I, - KEYMAP_KEY_O, - KEYMAP_KEY_P, - KEYMAP_KEY_LEFTBRACE, - KEYMAP_KEY_RIGHTBRACE, - KEYMAP_KEY_ENTER, - KEYMAP_KEY_LCTRL, - KEYMAP_KEY_A, - KEYMAP_KEY_S, - KEYMAP_KEY_D, - KEYMAP_KEY_F, - KEYMAP_KEY_G, - KEYMAP_KEY_H, - KEYMAP_KEY_J, - KEYMAP_KEY_K, - KEYMAP_KEY_L, - KEYMAP_KEY_SEMICOLON, - KEYMAP_KEY_APOSTROPHE, - KEYMAP_KEY_GRAVE, - KEYMAP_KEY_LSHIFT, - KEYMAP_KEY_BACKSLASH, - KEYMAP_KEY_Z, - KEYMAP_KEY_X, - KEYMAP_KEY_C, - KEYMAP_KEY_V, - KEYMAP_KEY_B, - KEYMAP_KEY_N, - KEYMAP_KEY_M, - KEYMAP_KEY_COMMA, - KEYMAP_KEY_DOT, - KEYMAP_KEY_SLASH, - KEYMAP_KEY_RSHIFT, - KEYMAP_KEY_KEYPAD_ASTERISK, - KEYMAP_KEY_LALT, - KEYMAP_KEY_SPACE, - KEYMAP_KEY_CAPS_LOCK, - KEYMAP_KEY_F1, - KEYMAP_KEY_F2, - KEYMAP_KEY_F3, - KEYMAP_KEY_F4, - KEYMAP_KEY_F5, - KEYMAP_KEY_F6, - KEYMAP_KEY_F7, - KEYMAP_KEY_F8, - KEYMAP_KEY_F9, - KEYMAP_KEY_F10, - KEYMAP_KEY_KEYPAD_NUMLCK, - KEYMAP_KEY_KEYPAD_SCRLK, - KEYMAP_KEY_KEYPAD_7, - KEYMAP_KEY_KEYPAD_8, - KEYMAP_KEY_KEYPAD_9, - KEYMAP_KEY_KEYPAD_MINUS, - KEYMAP_KEY_KEYPAD_4, - KEYMAP_KEY_KEYPAD_5, - KEYMAP_KEY_KEYPAD_6, - KEYMAP_KEY_KEYPAD_PLUS, - KEYMAP_KEY_KEYPAD_1, - KEYMAP_KEY_KEYPAD_2, - KEYMAP_KEY_KEYPAD_3, - KEYMAP_KEY_KEYPAD_0, - KEYMAP_KEY_KEYPAD_DOT, - KEYMAP_NOT_MAPPED, - KEYMAP_NOT_MAPPED, - KEYMAP_102ND, - KEYMAP_KEY_F11, - KEYMAP_KEY_F12, +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +// clang-format off +static unsigned int set1_keymap[] = { + KEY_RESERVED, + KEY_ESC, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + KEY_MINUS, + KEY_EQUAL, + KEY_BACKSPACE, + KEY_TAB, + KEY_Q, + KEY_W, + KEY_E, + KEY_R, + KEY_T, + KEY_Y, + KEY_U, + KEY_I, + KEY_O, + KEY_P, + KEY_LEFTBRACE, + KEY_RIGHTBRACE, + KEY_ENTER, + KEY_LEFTCTRL, + KEY_A, + KEY_S, + KEY_D, + KEY_F, + KEY_G, + KEY_H, + KEY_J, + KEY_K, + KEY_L, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_GRAVE, + KEY_LEFTSHIFT, + KEY_BACKSLASH, + KEY_Z, + KEY_X, + KEY_C, + KEY_V, + KEY_B, + KEY_N, + KEY_M, + KEY_COMMA, + KEY_DOT, + KEY_SLASH, + KEY_RIGHTSHIFT, + KEY_KPASTERISK, + KEY_LEFTALT, + KEY_SPACE, + KEY_CAPSLOCK, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_NUMLOCK, + KEY_SCROLLLOCK, + KEY_KP7, + KEY_KP8, + KEY_KP9, + KEY_KPMINUS, + KEY_KP4, + KEY_KP5, + KEY_KP6, + KEY_KPPLUS, + KEY_KP1, + KEY_KP2, + KEY_KP3, + KEY_KP0, + KEY_KPDOT, + KEY_RESERVED, + KEY_RESERVED, + KEY_102ND, + KEY_F11, + KEY_F12, +}; + +// clang-format on + +static unsigned int two_bytes[] = { + KEY_LEFTALT, KEY_RIGHTCTRL, KEY_INSERT, KEY_DELETE, KEY_HOME, KEY_END, + KEY_PAGEUP, KEY_PAGEDOWN, KEY_LEFT, KEY_UP, KEY_DOWN, KEY_RIGHT, + KEY_LEFTMETA, KEY_MENU, KEY_KPSLASH, KEY_KPENTER, KEY_SYSRQ, }; #define PS2_TWO_BYTE_CODE 0xe0 @@ -115,42 +127,42 @@ unsigned int ps2_keyb_get_two_byte_key(uint8_t bytes[2]) switch (second_byte) { - case 0x38: - return KEYMAP_KEY_LALT; - case 0x1d: - return KEYMAP_KEY_RCTRL; - case 0x52: - return KEYMAP_KEY_INSERT; - case 0x53: - return KEYMAP_KEY_DEL; - case 0x47: - return KEYMAP_KEY_HOME; - case 0x4f: - return KEYMAP_KEY_END; - case 0x49: - return KEYMAP_KEY_PGUP; - case 0x51: - return KEYMAP_KEY_PGDN; - case 0x4b: - return KEYMAP_KEY_ARROW_LEFT; - case 0x48: - return KEYMAP_KEY_ARROW_UP; - case 0x50: - return KEYMAP_KEY_ARROW_DOWN; - case 0x4d: - return KEYMAP_KEY_ARROW_RIGHT; - case 0x5b: - return KEYMAP_KEY_WINKEY; - case 0x5d: - return KEYMAP_KEY_MENU; - case 0x35: - return KEYMAP_KEY_KEYPAD_SLASH; - case 0x1c: - return KEYMAP_KEY_KEYPAD_ENTER; - case 0x37: - return KEYMAP_KEY_PRTSC; - default: - return KEYMAP_NOT_MAPPED; + case 0x38: + return KEY_LEFTALT; + case 0x1d: + return KEY_RIGHTCTRL; + case 0x52: + return KEY_INSERT; + case 0x53: + return KEY_DELETE; + case 0x47: + return KEY_HOME; + case 0x4f: + return KEY_END; + case 0x49: + return KEY_PAGEUP; + case 0x51: + return KEY_PAGEDOWN; + case 0x4b: + return KEY_LEFT; + case 0x48: + return KEY_UP; + case 0x50: + return KEY_DOWN; + case 0x4d: + return KEY_RIGHT; + case 0x5b: + return KEY_LEFTMETA; + case 0x5d: + return KEY_MENU; + case 0x35: + return KEY_KPSLASH; + case 0x1c: + return KEY_KPENTER; + case 0x37: + return KEY_SYSRQ; + default: + return KEY_RESERVED; } } @@ -176,7 +188,7 @@ void ps2_on_byte(struct ps2_port *port) for (int i = 0; i < 5; i++) ps2_read_data(port); - keycode = KEYMAP_KEY_PAUSE; + keycode = KEY_PAUSE; release = true; } else @@ -186,7 +198,7 @@ void ps2_on_byte(struct ps2_port *port) keycode = set1_keymap[bytes[0]]; } - if (keycode == KEYMAP_NOT_MAPPED) + if (keycode == KEY_RESERVED) { #if CONFIG_DEBUG_KEYBOARD_PANIC_ON_UNKNOWN panic("BUG: keycode %u not mapped!\n", keycode); @@ -218,9 +230,29 @@ void ps2_set_typematic_rate(struct ps2_port *port) void ps2_keyboard_init(struct ps2_port *port) { + struct input_device *dev = &port->dev; + port->on_byte = ps2_on_byte; ps2_set_typematic_rate(port); memset(&port->dev.state, 0, sizeof(struct input_state)); + dev->input_id.bustype = BUS_I8042; + dev->input_id.product = 1; + dev->input_id.vendor = 1; + dev->input_id.version = 1; + dev->feature_bits = (1UL << EV_SYN) | (1UL << EV_KEY); + + for (unsigned int i = 0; i < ARRAY_SIZE(set1_keymap); i++) + { + if (set1_keymap[i] == KEY_RESERVED) + continue; + input_add_key(dev, set1_keymap[i]); + } + + for (unsigned int i = 0; i < ARRAY_SIZE(two_bytes); i++) + input_add_key(dev, two_bytes[i]); + memset(&dev->properties, 0, sizeof(dev->properties)); + dev->grab = NULL; + dev->phys = "isa0060/serio0"; input_device_register(&port->dev); } diff --git a/kernel/drivers/ps2/mouse.cpp b/kernel/drivers/ps2/mouse.cpp new file mode 100644 index 000000000..41aeb2649 --- /dev/null +++ b/kernel/drivers/ps2/mouse.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016 - 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License + * check LICENSE at the root directory for more information + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#include + +#include +#include +#include +#include +#include + +#include "ps2.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#define PS2_MOUSE_LEFT (1 << 0) +#define PS2_MOUSE_RIGHT (1 << 1) +#define PS2_MOUSE_MIDDLE (1 << 2) +#define PS2_MOUSE_YSIGN (1 << 5) +#define PS2_MOUSE_XSIGN (1 << 4) + +extern "C" void evdev_submit_event(struct input_device *dev, struct evdev_input_event *ev); + +#define TIMESPEC_TO_TIMEVAL(tv, ts) \ + ((tv)->tv_sec = (ts)->tv_sec, (tv)->tv_usec = (ts)->tv_nsec / 1000, (void) 0) + +static void ps2_on_byte(struct ps2_port *port) +{ + struct evdev_input_event evdev_ev = {}; + struct input_event ev; + uint8_t bytes[4] = {}; + struct timespec ts; + int x, y; + + bytes[0] = ps2_read_data(port); + bytes[1] = ps2_read_data(port); + bytes[2] = ps2_read_data(port); + + x = bytes[1] ? bytes[1] - ((bytes[0] << 4) & 0x100) : 0; + y = bytes[2] ? bytes[2] - ((bytes[0] << 3) & 0x100) : 0; + + evdev_ev.code = REL_Y; + evdev_ev.type = EV_REL; + evdev_ev.value = -y; + clock_gettime_kernel(CLOCK_REALTIME, &ts); + TIMESPEC_TO_TIMEVAL(&evdev_ev.time, &ts); + evdev_submit_event(&port->dev, &evdev_ev); + evdev_ev.code = REL_X; + evdev_ev.type = EV_REL; + evdev_ev.value = x; + evdev_submit_event(&port->dev, &evdev_ev); + evdev_ev.code = SYN_REPORT; + evdev_ev.type = EV_SYN; + evdev_ev.value = 1; + evdev_submit_event(&port->dev, &evdev_ev); + ev.type = INPUT_EVENT_TYPE_KEYBOARD; + ev.code = (keycode_t) BTN_LEFT; + ev.flags = (bytes[0] & PS2_MOUSE_LEFT); + input_device_submit_event(&port->dev, &ev); + ev.code = (keycode_t) BTN_RIGHT; + ev.flags = (bytes[0] & PS2_MOUSE_RIGHT); + input_device_submit_event(&port->dev, &ev); + ev.code = (keycode_t) BTN_MIDDLE; + ev.flags = (bytes[0] & PS2_MOUSE_MIDDLE); + input_device_submit_event(&port->dev, &ev); +} + +int ps2_reset_device(struct ps2_port *port); + +static void ps2_enable_mouse(struct ps2_port *port) +{ + uint8_t response = 0; + + ps2_reset_device(port); + + do + { + if (ps2_send_command_to_device(port, 0xf4, true, &response) == PS2_CMD_TIMEOUT) + return; + } while (response == 0xfe); +} + +void ps2_mouse_init(struct ps2_port *port) +{ + struct input_device *dev = &port->dev; + + port->on_byte = ps2_on_byte; + + ps2_enable_mouse(port); + memset(&port->dev.state, 0, sizeof(struct input_state)); + dev->input_id.bustype = BUS_I8042; + dev->input_id.product = 1; + dev->input_id.vendor = 1; + dev->input_id.version = 1; + dev->feature_bits = (1UL << EV_SYN) | (1UL << EV_KEY) | (1UL << EV_REL); + + memset(&dev->properties, 0, sizeof(dev->properties)); + dev->grab = NULL; + dev->phys = "isa0060/serio0"; + input_add_key(&port->dev, BTN_LEFT); + input_add_key(&port->dev, BTN_RIGHT); + input_add_key(&port->dev, BTN_MIDDLE); + input_device_register(&port->dev); +} diff --git a/kernel/drivers/ps2/ps2.h b/kernel/drivers/ps2/ps2.h index 71a0f1c3f..db67743ff 100644 --- a/kernel/drivers/ps2/ps2.h +++ b/kernel/drivers/ps2/ps2.h @@ -1,9 +1,9 @@ /* - * Copyright (c) 2016 - 2021 Pedro Falcato - * This file is part of Onyx, and is released under the terms of the MIT License + * Copyright (c) 2016 - 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: GPL-2.0-only */ #ifndef _ONYX_PS2_H @@ -28,6 +28,7 @@ #define PS2_STATUS_OUTPUT_BUFFER_FULL (1 << 0) #define PS2_STATUS_INPUT_BUFFER_FULL (1 << 1) +#define PS2_STATUS_AUX (1 << 5) #define PS2_CMD_DISABLE_SECOND_PORT 0xa7 #define PS2_CMD_ENABLE_SECOND_PORT 0xa8 @@ -74,6 +75,7 @@ struct ps2_controller }; void ps2_keyboard_init(struct ps2_port *port); +void ps2_mouse_init(struct ps2_port *port); uint8_t ps2_send_command_to_device(struct ps2_port *port, uint8_t command, bool get_response, uint8_t *response); void ps2_wait_for_input_buffer(struct ps2_controller *controller); diff --git a/kernel/drivers/virtio/network/network.cpp b/kernel/drivers/virtio/network/network.cpp index 44334188e..36e36cc07 100644 --- a/kernel/drivers/virtio/network/network.cpp +++ b/kernel/drivers/virtio/network/network.cpp @@ -1,10 +1,11 @@ /* - * Copyright (c) 2020 - 2022 Pedro Falcato - * This file is part of Onyx, and is released under the terms of the MIT License + * Copyright (c) 2020 - 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: GPL-2.0-only */ + #include "network.hpp" #include @@ -310,6 +311,7 @@ bool network_vdev::perform_subsystem_initialization() nif->poll_rx = virtio::network_vdev::__poll_rx; nif->rx_end = virtio::network_vdev::__rx_end; nif->dll_ops = ð_ops; + nif->tx_queue_len = get_max_virtq_size(network_transmitq); cul::slice m{nif->mac_address, 6}; get_mac(m); diff --git a/kernel/include/onyx/buffer.h b/kernel/include/onyx/buffer.h index ebc51c73d..b4069e863 100644 --- a/kernel/include/onyx/buffer.h +++ b/kernel/include/onyx/buffer.h @@ -171,6 +171,7 @@ ssize_t buffer_writepage(struct vm_object *obj, struct page *page, size_t offset ssize_t bbuffer_readpage(struct page *p, size_t off, struct inode *ino); int buffer_readpages(struct readpages_state *state, struct inode *ino); +bool buffer_release_folio(struct folio *folio, gfp_t gfp); __END_CDECLS diff --git a/kernel/include/onyx/initrd.h b/kernel/include/onyx/initrd.h index 8db4c867c..ba35a72b3 100644 --- a/kernel/include/onyx/initrd.h +++ b/kernel/include/onyx/initrd.h @@ -38,6 +38,8 @@ typedef struct star_header #define TAR_TYPE_CHAR_SPECIAL '3' #define TAR_TYPE_BLOCK_SPECIAL '4' #define TAR_TYPE_DIR '5' +#define TAR_TYPE_LONGNAME 'L' +#define TAR_TYPE_LONGLINK 'K' static inline size_t tar_get_size(const char *in) { diff --git a/kernel/include/onyx/input-event-codes.h b/kernel/include/onyx/input-event-codes.h new file mode 100644 index 000000000..30f3c9eaa --- /dev/null +++ b/kernel/include/onyx/input-event-codes.h @@ -0,0 +1,1003 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Input event codes + * + * *** IMPORTANT *** + * This file is not only included from C-code but also from devicetree source + * files. As such this file MUST only contain comments and defines. + * + * Copyright (c) 1999-2002 Vojtech Pavlik + * Copyright (c) 2015 Hans de Goede + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#ifndef _UAPI_INPUT_EVENT_CODES_H +#define _UAPI_INPUT_EVENT_CODES_H + +/* + * Device properties and quirks + */ + +#define INPUT_PROP_POINTER 0x00 /* needs a pointer */ +#define INPUT_PROP_DIRECT 0x01 /* direct input devices */ +#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */ +#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */ +#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */ +#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */ +#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */ +#define INPUT_PROP_PRESSUREPAD 0x07 /* pressure triggers clicks */ + +#define INPUT_PROP_MAX 0x1f +#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) + +/* + * Event types + */ + +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_SW 0x05 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f +#define EV_CNT (EV_MAX+1) + +/* + * Synchronization events. + */ + +#define SYN_REPORT 0 +#define SYN_CONFIG 1 +#define SYN_MT_REPORT 2 +#define SYN_DROPPED 3 +#define SYN_MAX 0xf +#define SYN_CNT (SYN_MAX+1) + +/* + * Keys and buttons + * + * Most of the keys/buttons are modeled after USB HUT 1.12 + * (see http://www.usb.org/developers/hidpage). + * Abbreviations in the comments: + * AC - Application Control + * AL - Application Launch Button + * SC - System Control + */ + +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 + +#define KEY_ZENKAKUHANKAKU 85 +#define KEY_102ND 86 +#define KEY_F11 87 +#define KEY_F12 88 +#define KEY_RO 89 +#define KEY_KATAKANA 90 +#define KEY_HIRAGANA 91 +#define KEY_HENKAN 92 +#define KEY_KATAKANAHIRAGANA 93 +#define KEY_MUHENKAN 94 +#define KEY_KPJPCOMMA 95 +#define KEY_KPENTER 96 +#define KEY_RIGHTCTRL 97 +#define KEY_KPSLASH 98 +#define KEY_SYSRQ 99 +#define KEY_RIGHTALT 100 +#define KEY_LINEFEED 101 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_MACRO 112 +#define KEY_MUTE 113 +#define KEY_VOLUMEDOWN 114 +#define KEY_VOLUMEUP 115 +#define KEY_POWER 116 /* SC System Power Down */ +#define KEY_KPEQUAL 117 +#define KEY_KPPLUSMINUS 118 +#define KEY_PAUSE 119 +#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */ + +#define KEY_KPCOMMA 121 +#define KEY_HANGEUL 122 +#define KEY_HANGUEL KEY_HANGEUL +#define KEY_HANJA 123 +#define KEY_YEN 124 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 +#define KEY_COMPOSE 127 + +#define KEY_STOP 128 /* AC Stop */ +#define KEY_AGAIN 129 +#define KEY_PROPS 130 /* AC Properties */ +#define KEY_UNDO 131 /* AC Undo */ +#define KEY_FRONT 132 +#define KEY_COPY 133 /* AC Copy */ +#define KEY_OPEN 134 /* AC Open */ +#define KEY_PASTE 135 /* AC Paste */ +#define KEY_FIND 136 /* AC Search */ +#define KEY_CUT 137 /* AC Cut */ +#define KEY_HELP 138 /* AL Integrated Help Center */ +#define KEY_MENU 139 /* Menu (show menu) */ +#define KEY_CALC 140 /* AL Calculator */ +#define KEY_SETUP 141 +#define KEY_SLEEP 142 /* SC System Sleep */ +#define KEY_WAKEUP 143 /* System Wake Up */ +#define KEY_FILE 144 /* AL Local Machine Browser */ +#define KEY_SENDFILE 145 +#define KEY_DELETEFILE 146 +#define KEY_XFER 147 +#define KEY_PROG1 148 +#define KEY_PROG2 149 +#define KEY_WWW 150 /* AL Internet Browser */ +#define KEY_MSDOS 151 +#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */ +#define KEY_SCREENLOCK KEY_COFFEE +#define KEY_ROTATE_DISPLAY 153 /* Display orientation for e.g. tablets */ +#define KEY_DIRECTION KEY_ROTATE_DISPLAY +#define KEY_CYCLEWINDOWS 154 +#define KEY_MAIL 155 +#define KEY_BOOKMARKS 156 /* AC Bookmarks */ +#define KEY_COMPUTER 157 +#define KEY_BACK 158 /* AC Back */ +#define KEY_FORWARD 159 /* AC Forward */ +#define KEY_CLOSECD 160 +#define KEY_EJECTCD 161 +#define KEY_EJECTCLOSECD 162 +#define KEY_NEXTSONG 163 +#define KEY_PLAYPAUSE 164 +#define KEY_PREVIOUSSONG 165 +#define KEY_STOPCD 166 +#define KEY_RECORD 167 +#define KEY_REWIND 168 +#define KEY_PHONE 169 /* Media Select Telephone */ +#define KEY_ISO 170 +#define KEY_CONFIG 171 /* AL Consumer Control Configuration */ +#define KEY_HOMEPAGE 172 /* AC Home */ +#define KEY_REFRESH 173 /* AC Refresh */ +#define KEY_EXIT 174 /* AC Exit */ +#define KEY_MOVE 175 +#define KEY_EDIT 176 +#define KEY_SCROLLUP 177 +#define KEY_SCROLLDOWN 178 +#define KEY_KPLEFTPAREN 179 +#define KEY_KPRIGHTPAREN 180 +#define KEY_NEW 181 /* AC New */ +#define KEY_REDO 182 /* AC Redo/Repeat */ + +#define KEY_F13 183 +#define KEY_F14 184 +#define KEY_F15 185 +#define KEY_F16 186 +#define KEY_F17 187 +#define KEY_F18 188 +#define KEY_F19 189 +#define KEY_F20 190 +#define KEY_F21 191 +#define KEY_F22 192 +#define KEY_F23 193 +#define KEY_F24 194 + +#define KEY_PLAYCD 200 +#define KEY_PAUSECD 201 +#define KEY_PROG3 202 +#define KEY_PROG4 203 +#define KEY_ALL_APPLICATIONS 204 /* AC Desktop Show All Applications */ +#define KEY_DASHBOARD KEY_ALL_APPLICATIONS +#define KEY_SUSPEND 205 +#define KEY_CLOSE 206 /* AC Close */ +#define KEY_PLAY 207 +#define KEY_FASTFORWARD 208 +#define KEY_BASSBOOST 209 +#define KEY_PRINT 210 /* AC Print */ +#define KEY_HP 211 +#define KEY_CAMERA 212 +#define KEY_SOUND 213 +#define KEY_QUESTION 214 +#define KEY_EMAIL 215 +#define KEY_CHAT 216 +#define KEY_SEARCH 217 +#define KEY_CONNECT 218 +#define KEY_FINANCE 219 /* AL Checkbook/Finance */ +#define KEY_SPORT 220 +#define KEY_SHOP 221 +#define KEY_ALTERASE 222 +#define KEY_CANCEL 223 /* AC Cancel */ +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 +#define KEY_MEDIA 226 + +#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video + outputs (Monitor/LCD/TV-out/etc) */ +#define KEY_KBDILLUMTOGGLE 228 +#define KEY_KBDILLUMDOWN 229 +#define KEY_KBDILLUMUP 230 + +#define KEY_SEND 231 /* AC Send */ +#define KEY_REPLY 232 /* AC Reply */ +#define KEY_FORWARDMAIL 233 /* AC Forward Msg */ +#define KEY_SAVE 234 /* AC Save */ +#define KEY_DOCUMENTS 235 + +#define KEY_BATTERY 236 + +#define KEY_BLUETOOTH 237 +#define KEY_WLAN 238 +#define KEY_UWB 239 + +#define KEY_UNKNOWN 240 + +#define KEY_VIDEO_NEXT 241 /* drive next video source */ +#define KEY_VIDEO_PREV 242 /* drive previous video source */ +#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ +#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual + brightness control is off, + rely on ambient */ +#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO +#define KEY_DISPLAY_OFF 245 /* display device to off state */ + +#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */ +#define KEY_WIMAX KEY_WWAN +#define KEY_RFKILL 247 /* Key that controls all radios */ + +#define KEY_MICMUTE 248 /* Mute / unmute the microphone */ + +/* Code 255 is reserved for special needs of AT keyboard driver */ + +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 + +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 +#define BTN_TASK 0x117 + +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_PINKIE 0x125 +#define BTN_BASE 0x126 +#define BTN_BASE2 0x127 +#define BTN_BASE3 0x128 +#define BTN_BASE4 0x129 +#define BTN_BASE5 0x12a +#define BTN_BASE6 0x12b +#define BTN_DEAD 0x12f + +#define BTN_GAMEPAD 0x130 +#define BTN_SOUTH 0x130 +#define BTN_A BTN_SOUTH +#define BTN_EAST 0x131 +#define BTN_B BTN_EAST +#define BTN_C 0x132 +#define BTN_NORTH 0x133 +#define BTN_X BTN_NORTH +#define BTN_WEST 0x134 +#define BTN_Y BTN_WEST +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c +#define BTN_THUMBL 0x13d +#define BTN_THUMBR 0x13e + +#define BTN_DIGI 0x140 +#define BTN_TOOL_PEN 0x140 +#define BTN_TOOL_RUBBER 0x141 +#define BTN_TOOL_BRUSH 0x142 +#define BTN_TOOL_PENCIL 0x143 +#define BTN_TOOL_AIRBRUSH 0x144 +#define BTN_TOOL_FINGER 0x145 +#define BTN_TOOL_MOUSE 0x146 +#define BTN_TOOL_LENS 0x147 +#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */ +#define BTN_STYLUS3 0x149 +#define BTN_TOUCH 0x14a +#define BTN_STYLUS 0x14b +#define BTN_STYLUS2 0x14c +#define BTN_TOOL_DOUBLETAP 0x14d +#define BTN_TOOL_TRIPLETAP 0x14e +#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */ + +#define BTN_WHEEL 0x150 +#define BTN_GEAR_DOWN 0x150 +#define BTN_GEAR_UP 0x151 + +#define KEY_OK 0x160 +#define KEY_SELECT 0x161 +#define KEY_GOTO 0x162 +#define KEY_CLEAR 0x163 +#define KEY_POWER2 0x164 +#define KEY_OPTION 0x165 +#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */ +#define KEY_TIME 0x167 +#define KEY_VENDOR 0x168 +#define KEY_ARCHIVE 0x169 +#define KEY_PROGRAM 0x16a /* Media Select Program Guide */ +#define KEY_CHANNEL 0x16b +#define KEY_FAVORITES 0x16c +#define KEY_EPG 0x16d +#define KEY_PVR 0x16e /* Media Select Home */ +#define KEY_MHP 0x16f +#define KEY_LANGUAGE 0x170 +#define KEY_TITLE 0x171 +#define KEY_SUBTITLE 0x172 +#define KEY_ANGLE 0x173 +#define KEY_FULL_SCREEN 0x174 /* AC View Toggle */ +#define KEY_ZOOM KEY_FULL_SCREEN +#define KEY_MODE 0x175 +#define KEY_KEYBOARD 0x176 +#define KEY_ASPECT_RATIO 0x177 /* HUTRR37: Aspect */ +#define KEY_SCREEN KEY_ASPECT_RATIO +#define KEY_PC 0x178 /* Media Select Computer */ +#define KEY_TV 0x179 /* Media Select TV */ +#define KEY_TV2 0x17a /* Media Select Cable */ +#define KEY_VCR 0x17b /* Media Select VCR */ +#define KEY_VCR2 0x17c /* VCR Plus */ +#define KEY_SAT 0x17d /* Media Select Satellite */ +#define KEY_SAT2 0x17e +#define KEY_CD 0x17f /* Media Select CD */ +#define KEY_TAPE 0x180 /* Media Select Tape */ +#define KEY_RADIO 0x181 +#define KEY_TUNER 0x182 /* Media Select Tuner */ +#define KEY_PLAYER 0x183 +#define KEY_TEXT 0x184 +#define KEY_DVD 0x185 /* Media Select DVD */ +#define KEY_AUX 0x186 +#define KEY_MP3 0x187 +#define KEY_AUDIO 0x188 /* AL Audio Browser */ +#define KEY_VIDEO 0x189 /* AL Movie Browser */ +#define KEY_DIRECTORY 0x18a +#define KEY_LIST 0x18b +#define KEY_MEMO 0x18c /* Media Select Messages */ +#define KEY_CALENDAR 0x18d +#define KEY_RED 0x18e +#define KEY_GREEN 0x18f +#define KEY_YELLOW 0x190 +#define KEY_BLUE 0x191 +#define KEY_CHANNELUP 0x192 /* Channel Increment */ +#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */ +#define KEY_FIRST 0x194 +#define KEY_LAST 0x195 /* Recall Last */ +#define KEY_AB 0x196 +#define KEY_NEXT 0x197 +#define KEY_RESTART 0x198 +#define KEY_SLOW 0x199 +#define KEY_SHUFFLE 0x19a +#define KEY_BREAK 0x19b +#define KEY_PREVIOUS 0x19c +#define KEY_DIGITS 0x19d +#define KEY_TEEN 0x19e +#define KEY_TWEN 0x19f +#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */ +#define KEY_GAMES 0x1a1 /* Media Select Games */ +#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */ +#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */ +#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */ +#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */ +#define KEY_EDITOR 0x1a6 /* AL Text Editor */ +#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */ +#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */ +#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */ +#define KEY_DATABASE 0x1aa /* AL Database App */ +#define KEY_NEWS 0x1ab /* AL Newsreader */ +#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */ +#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ +#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ +#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ +#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE +#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ +#define KEY_LOGOFF 0x1b1 /* AL Logoff */ + +#define KEY_DOLLAR 0x1b2 +#define KEY_EURO 0x1b3 + +#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */ +#define KEY_FRAMEFORWARD 0x1b5 +#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ +#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */ +#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ +#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ +#define KEY_IMAGES 0x1ba /* AL Image Browser */ +#define KEY_NOTIFICATION_CENTER 0x1bc /* Show/hide the notification center */ +#define KEY_PICKUP_PHONE 0x1bd /* Answer incoming call */ +#define KEY_HANGUP_PHONE 0x1be /* Decline incoming call */ +#define KEY_LINK_PHONE 0x1bf /* AL Phone Syncing */ + +#define KEY_DEL_EOL 0x1c0 +#define KEY_DEL_EOS 0x1c1 +#define KEY_INS_LINE 0x1c2 +#define KEY_DEL_LINE 0x1c3 + +#define KEY_FN 0x1d0 +#define KEY_FN_ESC 0x1d1 +#define KEY_FN_F1 0x1d2 +#define KEY_FN_F2 0x1d3 +#define KEY_FN_F3 0x1d4 +#define KEY_FN_F4 0x1d5 +#define KEY_FN_F5 0x1d6 +#define KEY_FN_F6 0x1d7 +#define KEY_FN_F7 0x1d8 +#define KEY_FN_F8 0x1d9 +#define KEY_FN_F9 0x1da +#define KEY_FN_F10 0x1db +#define KEY_FN_F11 0x1dc +#define KEY_FN_F12 0x1dd +#define KEY_FN_1 0x1de +#define KEY_FN_2 0x1df +#define KEY_FN_D 0x1e0 +#define KEY_FN_E 0x1e1 +#define KEY_FN_F 0x1e2 +#define KEY_FN_S 0x1e3 +#define KEY_FN_B 0x1e4 +#define KEY_FN_RIGHT_SHIFT 0x1e5 + +#define KEY_BRL_DOT1 0x1f1 +#define KEY_BRL_DOT2 0x1f2 +#define KEY_BRL_DOT3 0x1f3 +#define KEY_BRL_DOT4 0x1f4 +#define KEY_BRL_DOT5 0x1f5 +#define KEY_BRL_DOT6 0x1f6 +#define KEY_BRL_DOT7 0x1f7 +#define KEY_BRL_DOT8 0x1f8 +#define KEY_BRL_DOT9 0x1f9 +#define KEY_BRL_DOT10 0x1fa + +#define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */ +#define KEY_NUMERIC_1 0x201 /* and other keypads */ +#define KEY_NUMERIC_2 0x202 +#define KEY_NUMERIC_3 0x203 +#define KEY_NUMERIC_4 0x204 +#define KEY_NUMERIC_5 0x205 +#define KEY_NUMERIC_6 0x206 +#define KEY_NUMERIC_7 0x207 +#define KEY_NUMERIC_8 0x208 +#define KEY_NUMERIC_9 0x209 +#define KEY_NUMERIC_STAR 0x20a +#define KEY_NUMERIC_POUND 0x20b +#define KEY_NUMERIC_A 0x20c /* Phone key A - HUT Telephony 0xb9 */ +#define KEY_NUMERIC_B 0x20d +#define KEY_NUMERIC_C 0x20e +#define KEY_NUMERIC_D 0x20f + +#define KEY_CAMERA_FOCUS 0x210 +#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */ + +#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */ +#define KEY_TOUCHPAD_ON 0x213 +#define KEY_TOUCHPAD_OFF 0x214 + +#define KEY_CAMERA_ZOOMIN 0x215 +#define KEY_CAMERA_ZOOMOUT 0x216 +#define KEY_CAMERA_UP 0x217 +#define KEY_CAMERA_DOWN 0x218 +#define KEY_CAMERA_LEFT 0x219 +#define KEY_CAMERA_RIGHT 0x21a + +#define KEY_ATTENDANT_ON 0x21b +#define KEY_ATTENDANT_OFF 0x21c +#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */ +#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */ + +#define BTN_DPAD_UP 0x220 +#define BTN_DPAD_DOWN 0x221 +#define BTN_DPAD_LEFT 0x222 +#define BTN_DPAD_RIGHT 0x223 + +#define BTN_GRIPL 0x224 +#define BTN_GRIPR 0x225 +#define BTN_GRIPL2 0x226 +#define BTN_GRIPR2 0x227 + +#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ +#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */ +#define KEY_REFRESH_RATE_TOGGLE 0x232 /* Display refresh rate toggle */ + +#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ +#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */ +#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */ +#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */ +#define KEY_APPSELECT 0x244 /* AL Select Task/Application */ +#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */ +#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ +#define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */ +#define KEY_KBD_LAYOUT_NEXT 0x248 /* AC Next Keyboard Layout Select */ +#define KEY_EMOJI_PICKER 0x249 /* Show/hide emoji picker (HUTRR101) */ +#define KEY_DICTATE 0x24a /* Start or Stop Voice Dictation Session (HUTRR99) */ +#define KEY_CAMERA_ACCESS_ENABLE 0x24b /* Enables programmatic access to camera devices. (HUTRR72) */ +#define KEY_CAMERA_ACCESS_DISABLE 0x24c /* Disables programmatic access to camera devices. (HUTRR72) */ +#define KEY_CAMERA_ACCESS_TOGGLE 0x24d /* Toggles the current state of the camera access control. (HUTRR72) */ +#define KEY_ACCESSIBILITY 0x24e /* Toggles the system bound accessibility UI/command (HUTRR116) */ +#define KEY_DO_NOT_DISTURB 0x24f /* Toggles the system-wide "Do Not Disturb" control (HUTRR94)*/ + +#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ +#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ + +/* + * Keycodes for hotkeys toggling the electronic privacy screen found on some + * laptops on/off. Note when the embedded-controller turns on/off the eprivacy + * screen itself then the state should be reported through drm connecter props: + * https://www.kernel.org/doc/html/latest/gpu/drm-kms.html#standard-connector-properties + * Except when implementing the drm connecter properties API is not possible + * because e.g. the firmware does not allow querying the presence and/or status + * of the eprivacy screen at boot. + */ +#define KEY_EPRIVACY_SCREEN_ON 0x252 +#define KEY_EPRIVACY_SCREEN_OFF 0x253 + +#define KEY_KBDINPUTASSIST_PREV 0x260 +#define KEY_KBDINPUTASSIST_NEXT 0x261 +#define KEY_KBDINPUTASSIST_PREVGROUP 0x262 +#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263 +#define KEY_KBDINPUTASSIST_ACCEPT 0x264 +#define KEY_KBDINPUTASSIST_CANCEL 0x265 + +/* Diagonal movement keys */ +#define KEY_RIGHT_UP 0x266 +#define KEY_RIGHT_DOWN 0x267 +#define KEY_LEFT_UP 0x268 +#define KEY_LEFT_DOWN 0x269 + +#define KEY_ROOT_MENU 0x26a /* Show Device's Root Menu */ +/* Show Top Menu of the Media (e.g. DVD) */ +#define KEY_MEDIA_TOP_MENU 0x26b +#define KEY_NUMERIC_11 0x26c +#define KEY_NUMERIC_12 0x26d +/* + * Toggle Audio Description: refers to an audio service that helps blind and + * visually impaired consumers understand the action in a program. Note: in + * some countries this is referred to as "Video Description". + */ +#define KEY_AUDIO_DESC 0x26e +#define KEY_3D_MODE 0x26f +#define KEY_NEXT_FAVORITE 0x270 +#define KEY_STOP_RECORD 0x271 +#define KEY_PAUSE_RECORD 0x272 +#define KEY_VOD 0x273 /* Video on Demand */ +#define KEY_UNMUTE 0x274 +#define KEY_FASTREVERSE 0x275 +#define KEY_SLOWREVERSE 0x276 +/* + * Control a data application associated with the currently viewed channel, + * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.) + */ +#define KEY_DATA 0x277 +#define KEY_ONSCREEN_KEYBOARD 0x278 +/* Electronic privacy screen control */ +#define KEY_PRIVACY_SCREEN_TOGGLE 0x279 + +/* Select an area of screen to be copied */ +#define KEY_SELECTIVE_SCREENSHOT 0x27a + +/* Move the focus to the next or previous user controllable element within a UI container */ +#define KEY_NEXT_ELEMENT 0x27b +#define KEY_PREVIOUS_ELEMENT 0x27c + +/* Toggle Autopilot engagement */ +#define KEY_AUTOPILOT_ENGAGE_TOGGLE 0x27d + +/* Shortcut Keys */ +#define KEY_MARK_WAYPOINT 0x27e +#define KEY_SOS 0x27f +#define KEY_NAV_CHART 0x280 +#define KEY_FISHING_CHART 0x281 +#define KEY_SINGLE_RANGE_RADAR 0x282 +#define KEY_DUAL_RANGE_RADAR 0x283 +#define KEY_RADAR_OVERLAY 0x284 +#define KEY_TRADITIONAL_SONAR 0x285 +#define KEY_CLEARVU_SONAR 0x286 +#define KEY_SIDEVU_SONAR 0x287 +#define KEY_NAV_INFO 0x288 +#define KEY_BRIGHTNESS_MENU 0x289 + +/* + * Some keyboards have keys which do not have a defined meaning, these keys + * are intended to be programmed / bound to macros by the user. For most + * keyboards with these macro-keys the key-sequence to inject, or action to + * take, is all handled by software on the host side. So from the kernel's + * point of view these are just normal keys. + * + * The KEY_MACRO# codes below are intended for such keys, which may be labeled + * e.g. G1-G18, or S1 - S30. The KEY_MACRO# codes MUST NOT be used for keys + * where the marking on the key does indicate a defined meaning / purpose. + * + * The KEY_MACRO# codes MUST also NOT be used as fallback for when no existing + * KEY_FOO define matches the marking / purpose. In this case a new KEY_FOO + * define MUST be added. + */ +#define KEY_MACRO1 0x290 +#define KEY_MACRO2 0x291 +#define KEY_MACRO3 0x292 +#define KEY_MACRO4 0x293 +#define KEY_MACRO5 0x294 +#define KEY_MACRO6 0x295 +#define KEY_MACRO7 0x296 +#define KEY_MACRO8 0x297 +#define KEY_MACRO9 0x298 +#define KEY_MACRO10 0x299 +#define KEY_MACRO11 0x29a +#define KEY_MACRO12 0x29b +#define KEY_MACRO13 0x29c +#define KEY_MACRO14 0x29d +#define KEY_MACRO15 0x29e +#define KEY_MACRO16 0x29f +#define KEY_MACRO17 0x2a0 +#define KEY_MACRO18 0x2a1 +#define KEY_MACRO19 0x2a2 +#define KEY_MACRO20 0x2a3 +#define KEY_MACRO21 0x2a4 +#define KEY_MACRO22 0x2a5 +#define KEY_MACRO23 0x2a6 +#define KEY_MACRO24 0x2a7 +#define KEY_MACRO25 0x2a8 +#define KEY_MACRO26 0x2a9 +#define KEY_MACRO27 0x2aa +#define KEY_MACRO28 0x2ab +#define KEY_MACRO29 0x2ac +#define KEY_MACRO30 0x2ad + +/* + * Some keyboards with the macro-keys described above have some extra keys + * for controlling the host-side software responsible for the macro handling: + * -A macro recording start/stop key. Note that not all keyboards which emit + * KEY_MACRO_RECORD_START will also emit KEY_MACRO_RECORD_STOP if + * KEY_MACRO_RECORD_STOP is not advertised, then KEY_MACRO_RECORD_START + * should be interpreted as a recording start/stop toggle; + * -Keys for switching between different macro (pre)sets, either a key for + * cycling through the configured presets or keys to directly select a preset. + */ +#define KEY_MACRO_RECORD_START 0x2b0 +#define KEY_MACRO_RECORD_STOP 0x2b1 +#define KEY_MACRO_PRESET_CYCLE 0x2b2 +#define KEY_MACRO_PRESET1 0x2b3 +#define KEY_MACRO_PRESET2 0x2b4 +#define KEY_MACRO_PRESET3 0x2b5 + +/* + * Some keyboards have a buildin LCD panel where the contents are controlled + * by the host. Often these have a number of keys directly below the LCD + * intended for controlling a menu shown on the LCD. These keys often don't + * have any labeling so we just name them KEY_KBD_LCD_MENU# + */ +#define KEY_KBD_LCD_MENU1 0x2b8 +#define KEY_KBD_LCD_MENU2 0x2b9 +#define KEY_KBD_LCD_MENU3 0x2ba +#define KEY_KBD_LCD_MENU4 0x2bb +#define KEY_KBD_LCD_MENU5 0x2bc + +/* Performance Boost key (Alienware)/G-Mode key (Dell) */ +#define KEY_PERFORMANCE 0x2bd + +#define BTN_TRIGGER_HAPPY 0x2c0 +#define BTN_TRIGGER_HAPPY1 0x2c0 +#define BTN_TRIGGER_HAPPY2 0x2c1 +#define BTN_TRIGGER_HAPPY3 0x2c2 +#define BTN_TRIGGER_HAPPY4 0x2c3 +#define BTN_TRIGGER_HAPPY5 0x2c4 +#define BTN_TRIGGER_HAPPY6 0x2c5 +#define BTN_TRIGGER_HAPPY7 0x2c6 +#define BTN_TRIGGER_HAPPY8 0x2c7 +#define BTN_TRIGGER_HAPPY9 0x2c8 +#define BTN_TRIGGER_HAPPY10 0x2c9 +#define BTN_TRIGGER_HAPPY11 0x2ca +#define BTN_TRIGGER_HAPPY12 0x2cb +#define BTN_TRIGGER_HAPPY13 0x2cc +#define BTN_TRIGGER_HAPPY14 0x2cd +#define BTN_TRIGGER_HAPPY15 0x2ce +#define BTN_TRIGGER_HAPPY16 0x2cf +#define BTN_TRIGGER_HAPPY17 0x2d0 +#define BTN_TRIGGER_HAPPY18 0x2d1 +#define BTN_TRIGGER_HAPPY19 0x2d2 +#define BTN_TRIGGER_HAPPY20 0x2d3 +#define BTN_TRIGGER_HAPPY21 0x2d4 +#define BTN_TRIGGER_HAPPY22 0x2d5 +#define BTN_TRIGGER_HAPPY23 0x2d6 +#define BTN_TRIGGER_HAPPY24 0x2d7 +#define BTN_TRIGGER_HAPPY25 0x2d8 +#define BTN_TRIGGER_HAPPY26 0x2d9 +#define BTN_TRIGGER_HAPPY27 0x2da +#define BTN_TRIGGER_HAPPY28 0x2db +#define BTN_TRIGGER_HAPPY29 0x2dc +#define BTN_TRIGGER_HAPPY30 0x2dd +#define BTN_TRIGGER_HAPPY31 0x2de +#define BTN_TRIGGER_HAPPY32 0x2df +#define BTN_TRIGGER_HAPPY33 0x2e0 +#define BTN_TRIGGER_HAPPY34 0x2e1 +#define BTN_TRIGGER_HAPPY35 0x2e2 +#define BTN_TRIGGER_HAPPY36 0x2e3 +#define BTN_TRIGGER_HAPPY37 0x2e4 +#define BTN_TRIGGER_HAPPY38 0x2e5 +#define BTN_TRIGGER_HAPPY39 0x2e6 +#define BTN_TRIGGER_HAPPY40 0x2e7 + +/* We avoid low common keys in module aliases so they don't get huge. */ +#define KEY_MIN_INTERESTING KEY_MUTE +#define KEY_MAX 0x2ff +#define KEY_CNT (KEY_MAX+1) + +/* + * Relative axes + */ + +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_RX 0x03 +#define REL_RY 0x04 +#define REL_RZ 0x05 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +/* + * 0x0a is reserved and should not be used in input drivers. + * It was used by HID as REL_MISC+1 and userspace needs to detect if + * the next REL_* event is correct or is just REL_MISC + n. + * We define here REL_RESERVED so userspace can rely on it and detect + * the situation described above. + */ +#define REL_RESERVED 0x0a +#define REL_WHEEL_HI_RES 0x0b +#define REL_HWHEEL_HI_RES 0x0c +#define REL_MAX 0x0f +#define REL_CNT (REL_MAX+1) + +/* + * Absolute axes + */ + +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_WHEEL 0x08 +#define ABS_GAS 0x09 +#define ABS_BRAKE 0x0a +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_PRESSURE 0x18 +#define ABS_DISTANCE 0x19 +#define ABS_TILT_X 0x1a +#define ABS_TILT_Y 0x1b +#define ABS_TOOL_WIDTH 0x1c + +#define ABS_VOLUME 0x20 +#define ABS_PROFILE 0x21 + +#define ABS_MISC 0x28 + +/* + * 0x2e is reserved and should not be used in input drivers. + * It was used by HID as ABS_MISC+6 and userspace needs to detect if + * the next ABS_* event is correct or is just ABS_MISC + n. + * We define here ABS_RESERVED so userspace can rely on it and detect + * the situation described above. + */ +#define ABS_RESERVED 0x2e + +#define ABS_MT_SLOT 0x2f /* MT slot being modified */ +#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ +#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ +#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ +#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ +#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ +#define ABS_MT_POSITION_X 0x35 /* Center X touch position */ +#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */ +#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */ +#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ +#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ +#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ +#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */ +#define ABS_MT_TOOL_X 0x3c /* Center X tool position */ +#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */ + + +#define ABS_MAX 0x3f +#define ABS_CNT (ABS_MAX+1) + +/* + * Switch events + */ + +#define SW_LID 0x00 /* set = lid shut */ +#define SW_TABLET_MODE 0x01 /* set = tablet mode */ +#define SW_HEADPHONE_INSERT 0x02 /* set = inserted */ +#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" + set = radio enabled */ +#define SW_RADIO SW_RFKILL_ALL /* deprecated */ +#define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ +#define SW_DOCK 0x05 /* set = plugged into dock */ +#define SW_LINEOUT_INSERT 0x06 /* set = inserted */ +#define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */ +#define SW_VIDEOOUT_INSERT 0x08 /* set = inserted */ +#define SW_CAMERA_LENS_COVER 0x09 /* set = lens covered */ +#define SW_KEYPAD_SLIDE 0x0a /* set = keypad slide out */ +#define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */ +#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */ +#define SW_LINEIN_INSERT 0x0d /* set = inserted */ +#define SW_MUTE_DEVICE 0x0e /* set = device disabled */ +#define SW_PEN_INSERTED 0x0f /* set = pen inserted */ +#define SW_MACHINE_COVER 0x10 /* set = cover closed */ +#define SW_USB_INSERT 0x11 /* set = USB audio device connected */ +#define SW_MAX 0x11 +#define SW_CNT (SW_MAX+1) + +/* + * Misc events + */ + +#define MSC_SERIAL 0x00 +#define MSC_PULSELED 0x01 +#define MSC_GESTURE 0x02 +#define MSC_RAW 0x03 +#define MSC_SCAN 0x04 +#define MSC_TIMESTAMP 0x05 +#define MSC_MAX 0x07 +#define MSC_CNT (MSC_MAX+1) + +/* + * LEDs + */ + +#define LED_NUML 0x00 +#define LED_CAPSL 0x01 +#define LED_SCROLLL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_SLEEP 0x05 +#define LED_SUSPEND 0x06 +#define LED_MUTE 0x07 +#define LED_MISC 0x08 +#define LED_MAIL 0x09 +#define LED_CHARGING 0x0a +#define LED_MAX 0x0f +#define LED_CNT (LED_MAX+1) + +/* + * Autorepeat values + */ + +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 +#define REP_CNT (REP_MAX+1) + +/* + * Sounds + */ + +#define SND_CLICK 0x00 +#define SND_BELL 0x01 +#define SND_TONE 0x02 +#define SND_MAX 0x07 +#define SND_CNT (SND_MAX+1) + +#endif diff --git a/kernel/include/onyx/input/device.h b/kernel/include/onyx/input/device.h index d10e3a8ea..0512f544e 100644 --- a/kernel/include/onyx/input/device.h +++ b/kernel/include/onyx/input/device.h @@ -1,26 +1,73 @@ /* - * Copyright (c) 2020 Pedro Falcato + * Copyright (c) 2020 - 2025 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information + * + * SPDX-License-Identifier: GPL-2.0-only */ #ifndef _ONYX_INPUT_DEVICE_H #define _ONYX_INPUT_DEVICE_H +#include #include #include +#include +#include +#include + +#include +#include struct input_device { const char *name; - struct inode *devfs_inode; + const char *phys; struct input_state state; struct list_head list; + struct spinlock client_list_lock; + struct list_head client_list; + struct input_id input_id; + unsigned long feature_bits; + unsigned long key_bits[BITS_TO_LONGS(KEY_CNT)]; + unsigned long properties[BITS_TO_LONGS(INPUT_PROP_CNT)]; + unsigned long leds; + unsigned long switch_bits; + struct evdev_client __rcu *grab; +}; + +static inline void input_add_key(struct input_device *dev, unsigned int key) +{ + dev->key_bits[key / BITS_PER_LONG] |= (1UL << (key % BITS_PER_LONG)); +} + +struct evdev_input_event +{ + struct timeval time; + unsigned short type; + unsigned short code; + int value; }; +struct evdev_client +{ + struct evdev_input_event *buffer; + u32 write; + u32 read; + u32 buf_size; + struct spinlock buffer_lock; + struct input_device *dev; + struct rcu_head rcu_head; + struct list_head node; + struct wait_queue wq; +}; + +__BEGIN_CDECLS struct input_event; void input_device_register(struct input_device *dev); void input_device_unregister(struct input_device *dev); void input_device_submit_event(struct input_device *dev, struct input_event *ev); +__END_CDECLS + #endif diff --git a/kernel/include/onyx/input/keys.h b/kernel/include/onyx/input/keys.h index a7ddf294a..a04e05efc 100644 --- a/kernel/include/onyx/input/keys.h +++ b/kernel/include/onyx/input/keys.h @@ -115,6 +115,7 @@ typedef enum key KEYMAP_KEY_PAUSE, KEYMAP_102ND, KEYMAP_NOT_MAPPED, + KEYMAP_MAX = 0x300, } keycode_t; struct keymap diff --git a/kernel/include/onyx/input/state.h b/kernel/include/onyx/input/state.h index c0fc33cc3..00535a8dc 100644 --- a/kernel/include/onyx/input/state.h +++ b/kernel/include/onyx/input/state.h @@ -17,10 +17,10 @@ struct input_state bool caps_enabled; bool alt_pressed; bool ctrl_pressed; - unsigned long keys_pressed[2]; + unsigned long keys_pressed[4]; }; -void input_state_set_key_state(keycode_t key, bool pressed, struct input_state *is); +void input_state_set_key_state(unsigned key, bool pressed, struct input_state *is); bool input_state_key_is_pressed(keycode_t key, struct input_state *is); bool input_state_toggle_key(keycode_t key, struct input_state *is); diff --git a/kernel/include/onyx/maple_tree.h b/kernel/include/onyx/maple_tree.h index d04976866..d5588ad42 100644 --- a/kernel/include/onyx/maple_tree.h +++ b/kernel/include/onyx/maple_tree.h @@ -207,7 +207,7 @@ extern int lock_is_held_type(const struct lockdep_map *lock, int read); static inline int lock_is_held(const struct lockdep_map *lock) { - return lock_is_held_type(lock, -1); + return lock_is_held_type(lock, -1); } #endif @@ -771,7 +771,7 @@ static inline void __mas_set_range(struct ma_state *mas, unsigned long start, un { /* Ensure the range starts within the current slot */ // Onyx patch - remove when WARN_ON is properly implemented. - // MAS_WARN_ON(mas, mas_is_active(mas) && (mas->index > start || mas->last < start)); + MAS_WARN_ON(mas, mas_is_active(mas) && (mas->index > start || mas->last < start)); mas->index = start; mas->last = last; } @@ -862,7 +862,7 @@ static inline void mt_clear_in_rcu(struct maple_tree *mt) if (mt_external_lock(mt)) { - // WARN_ON(!mt_lock_is_held(mt)); + WARN_ON(!mt_lock_is_held(mt)); mt->ma_flags &= ~MT_FLAGS_USE_RCU; } else @@ -884,7 +884,7 @@ static inline void mt_set_in_rcu(struct maple_tree *mt) if (mt_external_lock(mt)) { - // WARN_ON(!mt_lock_is_held(mt)); + WARN_ON(!mt_lock_is_held(mt)); mt->ma_flags |= MT_FLAGS_USE_RCU; } else diff --git a/kernel/include/onyx/mm/page_zone.h b/kernel/include/onyx/mm/page_zone.h index 43fa19071..0c0690f20 100644 --- a/kernel/include/onyx/mm/page_zone.h +++ b/kernel/include/onyx/mm/page_zone.h @@ -85,6 +85,7 @@ struct page_zone unsigned long merges; struct page_lru zone_lru; struct spinlock lock; + long pagestats[PAGE_STATS_MAX]; struct page_pcpu_data pcpu[CONFIG_SMP_NR_CPUS] __align_cache; }; @@ -108,6 +109,8 @@ static inline void page_zone_init(page_zone *zone, const char *name, unsigned lo page_lru_init(&zone->zone_lru); for (int i = 0; i < CONFIG_SMP_NR_CPUS; i++) zone->pcpu[i].init(); + for (int i = 0; i < PAGE_STATS_MAX; i++) + zone->pagestats[i] = 0; } #endif diff --git a/kernel/include/onyx/mm/vm_object.h b/kernel/include/onyx/mm/vm_object.h index d03b03a16..d48811369 100644 --- a/kernel/include/onyx/mm/vm_object.h +++ b/kernel/include/onyx/mm/vm_object.h @@ -66,6 +66,7 @@ struct vm_object_ops ssize_t (*readpage)(struct page *page, size_t offset, struct inode *ino); int (*prepare_write)(struct inode *ino, struct page *page, size_t page_off, size_t offset, size_t len); + bool (*release_folio)(struct folio *folio, gfp_t gfp); }; #define VMO_FLAG_LOCK_FUTURE_PAGES (1 << 0) diff --git a/kernel/include/onyx/net/netif.h b/kernel/include/onyx/net/netif.h index ca14e45bf..048828f80 100644 --- a/kernel/include/onyx/net/netif.h +++ b/kernel/include/onyx/net/netif.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2024 Pedro Falcato + * Copyright (c) 2017 - 2026 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * @@ -72,6 +72,7 @@ struct netif unsigned int flags; unsigned int mtu; + unsigned int tx_queue_len; unsigned char mac_address[6]; struct sockaddr_in local_ip; @@ -144,7 +145,6 @@ __BEGIN_CDECLS void netif_register_if(struct netif *netif); int netif_unregister_if(struct netif *netif); struct netif *netif_choose(void); -void netif_get_ipv4_addr(struct sockaddr_in *s, struct netif *netif); struct netif *netif_from_if(uint32_t oif); struct netif *netif_from_name(const char *name); int netif_do_rx(void); diff --git a/kernel/include/onyx/net/netlink.h b/kernel/include/onyx/net/netlink.h new file mode 100644 index 000000000..91f0c7adc --- /dev/null +++ b/kernel/include/onyx/net/netlink.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 - 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License + * check LICENSE at the root directory for more information + * + * SPDX-License-Identifier: GPL-2.0-only + */ +#ifndef _ONYX_NET_NETLINK_H +#define _ONYX_NET_NETLINK_H + +#include + +#include + +struct netlink_sock +{ + struct socket sock; + struct list_head buf_list; + struct wait_queue wq; + struct list_head bind_node; + pid_t pid; + unsigned int groups; +}; + +__BEGIN_CDECLS + +struct nl_extack +{ + const char *msg; +}; + +void do_rtnetlink_send(struct netlink_sock *nlsk, struct packetbuf *pbf, struct nl_extack *extack); + +struct nlmsghdr *nl_put(struct packetbuf *pbf, pid_t pid, u32 seq, u16 type, u16 flags, u32 len); +int nl_done(struct packetbuf *pbf, pid_t pid, u32 seq, int err); +void netlink_ack(struct netlink_sock *nlsk, struct packetbuf *in_pbf, struct nlmsghdr *msg, int err, + struct nl_extack *extack); +__END_CDECLS + +#endif diff --git a/kernel/include/onyx/net/rtnetlink.h b/kernel/include/onyx/net/rtnetlink.h new file mode 100644 index 000000000..1a7529466 --- /dev/null +++ b/kernel/include/onyx/net/rtnetlink.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License + * check LICENSE at the root directory for more information + * + * SPDX-License-Identifier: GPL-2.0-only + */ +#ifndef _ONYX_NET_RTNETLINK_H +#define _ONYX_NET_RTNETLINK_H + +#include +#include + +#include + +typedef int (*rtnl_handler_t)(struct netlink_sock *nlsk, struct packetbuf *pbf, + struct nlmsghdr *nlh, struct rtgenmsg *rth); + +__BEGIN_CDECLS +void rtnl_register(int family, rtnl_handler_t handler); +int nla_put(struct packetbuf *pbf, u16 type, u16 len, const void *data); +int nla_put_str(struct packetbuf *pbf, u16 type, const char *str); +int nla_put_u32(struct packetbuf *pbf, u16 type, u32 data); + +__END_CDECLS +#endif diff --git a/kernel/include/onyx/page.h b/kernel/include/onyx/page.h index 2c8aed7ce..781d71804 100644 --- a/kernel/include/onyx/page.h +++ b/kernel/include/onyx/page.h @@ -826,6 +826,8 @@ FOLIOFLAG_OPS(head, HEAD); FOLIOFLAG_OPS(readahead, READAHEAD); FOLIOFLAG_OPS(locked, LOCKED); FOLIOFLAG_OPS(anon, ANON); +FOLIOFLAG_OPS(buffer, BUFFER); +FOLIOFLAG_OPS(writeback, WRITEBACK); struct vm_object *page_vmobj(struct page *page); struct vm_object *folio_vmobj(struct folio *folio); diff --git a/kernel/include/onyx/process.h b/kernel/include/onyx/process.h index 101948799..d234828e7 100644 --- a/kernel/include/onyx/process.h +++ b/kernel/include/onyx/process.h @@ -611,6 +611,11 @@ static inline struct file *get_task_exe(struct process *task) return filp; } +static inline bool fatal_signal_pending(void) +{ + return signal_is_pending() && sigismember(&get_current_process()->sigqueue.pending, SIGKILL); +} + __END_CDECLS #ifdef __cplusplus diff --git a/kernel/include/onyx/scheduler.h b/kernel/include/onyx/scheduler.h index a597cfe5b..7cf86b5a8 100644 --- a/kernel/include/onyx/scheduler.h +++ b/kernel/include/onyx/scheduler.h @@ -86,6 +86,10 @@ typedef struct thread struct registers *regs; unsigned int pagefault_disabled; +#ifdef CONFIG_DEBUG_SCHEDULER + hrtime_t last_finish; + hrtime_t last_switch_in; +#endif #ifdef CONFIG_KCOV struct kcov_data *kcov_data; @@ -122,6 +126,10 @@ typedef struct thread : refcount{}, canary{}, kernel_stack{}, kernel_stack_top{}, owner{}, entry{}, flags{}, id{}, status{}, priority{}, cpu{}, next{}, prev_prio{}, next_prio{}, fpu_area{}, sem_prev{}, sem_next{}, lock{}, errno_val{}, addr_limit{}, ctid{}, cputime_info{}, aspace{}, plug{} +#ifdef CONFIG_DEBUG_SCHEDULER + , + last_finish{}, last_switch_in{} +#endif #ifdef __x86_64__ , fs{}, gs{} diff --git a/kernel/include/onyx/timer.h b/kernel/include/onyx/timer.h index 435595ec0..939a048a5 100644 --- a/kernel/include/onyx/timer.h +++ b/kernel/include/onyx/timer.h @@ -74,6 +74,7 @@ struct timer void *priv; struct list_head event_list; struct spinlock event_list_lock; + struct clockevent *executing; void (*set_oneshot)(hrtime_t in_future); void (*set_periodic)(unsigned long freq); void (*disable_timer)(void); @@ -84,4 +85,9 @@ struct timer *platform_get_timer(void); void timer_queue_clockevent(struct clockevent *ev); void timer_handle_events(struct timer *t); +static inline bool clockevent_active(struct clockevent *ev) +{ + return READ_ONCE(ev->timer) != NULL; +} + #endif diff --git a/kernel/include/uapi/evdev.h b/kernel/include/uapi/evdev.h new file mode 100644 index 000000000..e2f215a95 --- /dev/null +++ b/kernel/include/uapi/evdev.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License + * check LICENSE at the root directory for more information + * + * SPDX-License-Identifier: GPL-2.0-only + */ +#ifndef _UAPI_EVDEV_H +#define _UAPI_EVDEV_H + +#include + +struct input_id +{ + __u16 bustype; + __u16 vendor; + __u16 product; + __u16 version; +}; + +#define ID_BUS 0 +#define ID_VENDOR 1 +#define ID_PRODUCT 2 +#define ID_VERSION 3 + +#define BUS_PCI 0x01 +#define BUS_ISAPNP 0x02 +#define BUS_USB 0x03 +#define BUS_HIL 0x04 +#define BUS_BLUETOOTH 0x05 +#define BUS_VIRTUAL 0x06 + +#define BUS_ISA 0x10 +#define BUS_I8042 0x11 +#define BUS_XTKBD 0x12 +#define BUS_RS232 0x13 +#define BUS_GAMEPORT 0x14 +#define BUS_PARPORT 0x15 +#define BUS_AMIGA 0x16 +#define BUS_ADB 0x17 +#define BUS_I2C 0x18 +#define BUS_HOST 0x19 +#define BUS_GSC 0x1A +#define BUS_ATARI 0x1B +#define BUS_SPI 0x1C +#define BUS_RMI 0x1D +#define BUS_CEC 0x1E +#define BUS_INTEL_ISHTP 0x1F +#define BUS_AMD_SFH 0x20 +#define BUS_SDW 0x21 + +#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ +#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ +#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */ +#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */ + +#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */ +#define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry) +#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */ +#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry) +#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */ + +#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ +#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ +#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ +#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) /* get device properties */ +#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) +#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) + +#define EVIOCGBIT(ev, len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) /* get event bits */ + +#define EVIOCGRAB _IOW('E', 0x90, int) + +#endif diff --git a/kernel/include/uapi/netlink.h b/kernel/include/uapi/netlink.h index 9d4a1f832..58501b914 100644 --- a/kernel/include/uapi/netlink.h +++ b/kernel/include/uapi/netlink.h @@ -4,7 +4,7 @@ typedef unsigned int __socklen_t; typedef unsigned short __sa_family_t; -#include +#include typedef __sa_family_t __kernel_sa_family_t; diff --git a/kernel/kernel/block/block.cpp b/kernel/kernel/block/block.cpp index 7e3301801..1a6ea0be6 100644 --- a/kernel/kernel/block/block.cpp +++ b/kernel/kernel/block/block.cpp @@ -115,11 +115,9 @@ static void buffer_write_readpages_endio(struct bio_req *bio) NO_THREAD_SAFETY_A for (size_t i = 0; i < bio->nr_vecs; i++) { struct page_iov *iov = &bio->vec[i]; - DCHECK(page_locked(iov->page)); struct block_buf *head = (struct block_buf *) iov->page->priv; spin_lock(&head->pagestate_lock); - bool uptodate = true; for (struct block_buf *b = head; b != nullptr; b = b->next) { @@ -130,19 +128,47 @@ static void buffer_write_readpages_endio(struct bio_req *bio) NO_THREAD_SAFETY_A wake_address(b); continue; } - - if (!bb_test_flag(b, BLOCKBUF_FLAG_UPTODATE)) - uptodate = false; } spin_unlock(&head->pagestate_lock); + } +} - if (uptodate) +static int wait_pending_areads(struct page *page, struct block_buf *head) +{ + struct block_buf *buf; + bool all_uptodate; + int err; + +retry: + spin_lock(&head->pagestate_lock); + all_uptodate = true; + buf = head; + for (; buf; buf = buf->next) + { + if (bb_test_flag(buf, BLOCKBUF_FLAG_AREAD)) + { + spin_unlock(&head->pagestate_lock); + wait_for( + buf, + [](void *ptr) -> bool { + struct block_buf *b = (struct block_buf *) ptr; + return !bb_test_flag(b, BLOCKBUF_FLAG_AREAD); + }, + 0, 0); + goto retry; + } + else if (!bb_test_flag(buf, BLOCKBUF_FLAG_UPTODATE)) { - if ((bio->flags & BIO_STATUS_MASK) == BIO_REQ_DONE) - page_set_uptodate(iov->page); + all_uptodate = false; } } + + if (all_uptodate) + page_set_uptodate(page); + err = 0; + spin_unlock(&head->pagestate_lock); + return err; } static int block_readpage_write(struct vm_object *vm_obj, off_t offset, size_t len, @@ -224,20 +250,7 @@ static int block_readpage_write(struct vm_object *vm_obj, off_t offset, size_t l } } - for (struct block_buf *buf = (struct block_buf *) page->priv; buf; buf = buf->next) - { - if (bb_test_flag(buf, BLOCKBUF_FLAG_AREAD)) - wait_for( - buf, - [](void *ptr) -> bool { - struct block_buf *b = (struct block_buf *) ptr; - return !bb_test_flag(b, BLOCKBUF_FLAG_AREAD); - }, - 0, 0); - } - - return 0; - + return wait_pending_areads(page, (struct block_buf *) page->priv); out_err: return st; } @@ -246,7 +259,7 @@ static int block_write_begin(struct file *filp, struct vm_object *vm_obj, off_t struct page **ppage) NO_THREAD_SAFETY_ANALYSIS { struct page *page; - int st = filemap_find_page(filp->f_ino, offset >> PAGE_SHIFT, + int st = filemap_find_page(filp->f_mapping->ino, offset >> PAGE_SHIFT, FIND_PAGE_ACTIVATE | FIND_PAGE_NO_READPAGE | FIND_PAGE_LOCK, &page, &filp->f_ra_state); if (st < 0) @@ -315,6 +328,7 @@ static const struct vm_object_ops block_vm_obj_ops = { .writepages = filemap_writepages, .readpages = buffer_readpages, .readpage = bbuffer_readpage, + .release_folio = buffer_release_folio, }; static struct lock_class_key bdev_truncate_lock_key; diff --git a/kernel/kernel/fork.c b/kernel/kernel/fork.c index 66ced3ff8..8b52af210 100644 --- a/kernel/kernel/fork.c +++ b/kernel/kernel/fork.c @@ -305,6 +305,13 @@ static pid_t kernel_clone(struct clone_args *args) write_lock(&tasklist_lock); spin_lock(&child->sighand->signal_lock); + if (fatal_signal_pending()) + { + /* Someone's racing a zap with this clone. Error out. */ + err = -EINTR; + goto err_free_thread; + } + if (flags & (CLONE_THREAD | CLONE_PARENT)) { /* Our parent (if CLONE_THREAD or CLONE_PARENT) is the current's parent. Regular UNIX @@ -370,6 +377,10 @@ static pid_t kernel_clone(struct clone_args *args) } return pid; +err_free_thread: + spin_unlock(&child->sighand->signal_lock); + write_unlock(&tasklist_lock); + thread_put(new_thread); err_put_mm: mmput(child->address_space); err_put_signal: @@ -381,7 +392,7 @@ static pid_t kernel_clone(struct clone_args *args) err_put_files: exit_files(child); err_put_pid: - put_pid(child->pid_struct); + pid_remove_pid(child->pid_struct, child); free_proc: kfree(child); return err; diff --git a/kernel/kernel/fs/buffer.cpp b/kernel/kernel/fs/buffer.cpp index 3f769213b..2c51619c4 100644 --- a/kernel/kernel/fs/buffer.cpp +++ b/kernel/kernel/fs/buffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2024 Pedro Falcato + * Copyright (c) 2020 - 2026 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * @@ -93,6 +93,7 @@ ssize_t buffer_writepage(struct vm_object *obj, struct page *page, size_t offset if (bio_submit_request(blkdev, r) < 0) { + page_end_writeback(page); bio_put(r); return -EIO; } @@ -203,8 +204,16 @@ void block_buf_sync(struct block_buf *buf) { /* TODO: Only write *this* buffer, instead of the whole page */ struct page *page = buf->this_page; + ssize_t err; + lock_page(page); - buffer_writepage(page->owner, page, page->pageoff << PAGE_SHIFT); + err = buffer_writepage(page->owner, page, page->pageoff << PAGE_SHIFT); + if (err < 0) + { + pr_warn("buffer(%s): failed to sync buffer for block %lu: %zd\n", buf->dev->name.c_str(), + buf->block_nr, err); + } + page_wait_writeback(page); } @@ -243,11 +252,11 @@ void page_destroy_block_bufs(struct page *page) while (b) { next = b->next; - block_buf_free(b); - b = next; } + + page->priv = 0; } /* Hmmm - I don't like this. Like linux, We're limiting ourselves to @@ -257,6 +266,8 @@ void page_destroy_block_bufs(struct page *page) ssize_t bbuffer_readpage(struct page *p, size_t off, struct inode *ino) { auto blkdev = reinterpret_cast(ino->i_helper); + u64 nblocks = blkdev->nr_sectors; + DCHECK(blkdev != nullptr); sector_t sec_nr = off / blkdev->sector_size; @@ -268,18 +279,19 @@ ssize_t bbuffer_readpage(struct page *p, size_t off, struct inode *ino) } auto block_size = blkdev->block_size; + auto nr_blocks = PAGE_SIZE / block_size; struct bio_req *r = bio_alloc(GFP_NOIO, 1); if (!r) return -EIO; + struct page_iov &vec = r->vec[0]; + r->sector_number = sec_nr; r->flags = BIO_REQ_READ_OP; - struct page_iov &vec = r->vec[0]; - vec.length = PAGE_SIZE; + vec.length = (sec_nr + nr_blocks > nblocks ? nblocks - sec_nr : nr_blocks) * block_size; vec.page = p; vec.page_off = 0; - auto nr_blocks = PAGE_SIZE / block_size; size_t starting_block_nr = off / block_size; size_t curr_off = 0; @@ -302,6 +314,8 @@ ssize_t bbuffer_readpage(struct page *p, size_t off, struct inode *ino) } b->block_nr = starting_block_nr + i; + if (b->block_nr >= nblocks) + bb_test_and_set(b, BLOCKBUF_FLAG_HOLE | BLOCKBUF_FLAG_UPTODATE); b->block_size = block_size; b->dev = blkdev; @@ -600,95 +614,102 @@ extern const struct file_ops buffer_ops = { .directio = buffer_directio, }; -struct block_buf *sb_read_block(const struct superblock *sb, unsigned long block) +static int folio_create_buffers(struct folio *folio, unsigned long start_block, + unsigned long block_size, struct blockdev *blkdev) { - struct blockdev *dev = sb->s_bdev; - size_t real_off = sb->s_block_size * block; - size_t aligned_off = real_off & -PAGE_SIZE; - - struct page *page; - - int st = filemap_find_page(dev->b_ino, real_off >> PAGE_SHIFT, 0, &page, nullptr); - - if (st < 0) - return nullptr; - - auto buf = reinterpret_cast(page->priv); + size_t nr_blocks = PAGE_SIZE / block_size; + struct page *page = folio_to_page(folio); + unsigned long nblocks; + size_t curr_off = 0; + WARN_ON(!folio_test_locked(folio)); + WARN_ON(folio_test_buffer(folio)); + WARN_ON(folio->priv != 0); - while (buf && buf->block_nr != block) - { - buf = buf->next; - } + nblocks = blkdev->nr_sectors / (block_size / blkdev->sector_size); - if (unlikely(!buf)) + for (size_t i = 0; i < nr_blocks; i++) { - size_t page_off = real_off - aligned_off; - sector_t aligned_block = aligned_off / sb->s_block_size; -#if 0 - printk("Aligned block: %lx\n", aligned_block); - printk("Aligned off %lx real off %lx\n", aligned_off, real_off); -#endif - sector_t block_nr = aligned_block + ((real_off - aligned_off) / sb->s_block_size); - - if (!(buf = page_add_blockbuf(page, page_off))) + struct block_buf *b; + if (!(b = page_add_blockbuf(page, curr_off))) { - page_unref(page); - return nullptr; + page_destroy_block_bufs(page); + return -ENOMEM; } - buf->block_nr = block_nr; - buf->block_size = sb->s_block_size; - buf->dev = sb->s_bdev; + b->block_nr = start_block + i; + if (b->block_nr >= nblocks) + bb_test_and_set(b, BLOCKBUF_FLAG_HOLE | BLOCKBUF_FLAG_UPTODATE); + b->block_size = block_size; + b->dev = blkdev; + curr_off += block_size; } - block_buf_get(buf); - - page_unref(page); - - return buf; + folio_set_buffer(folio); + return 0; } -struct block_buf *bdev_read_block(struct blockdev *bdev, unsigned long block) +static struct block_buf *find_or_create_buffers(struct folio *folio, unsigned long block, + unsigned long block_size, struct blockdev *bdev) { - size_t real_off = bdev->block_size * block; - size_t aligned_off = real_off & -PAGE_SIZE; - - struct page *page; - - int st = filemap_find_page(bdev->b_ino, real_off >> PAGE_SHIFT, 0, &page, nullptr); - - if (st < 0) - return nullptr; + unsigned long start_block; + struct block_buf *buf; + int err; - auto buf = reinterpret_cast(page->priv); + if (!folio_test_buffer(folio)) + { + start_block = (folio->pageoff * PAGE_SIZE) / block_size; + err = folio_create_buffers(folio, start_block, block_size, bdev); + if (err) + return NULL; + } - while (buf && buf->block_nr != block) - buf = buf->next; + buf = (struct block_buf *) folio->priv; + DCHECK(buf != NULL); - if (unlikely(!buf)) + while (buf) { - size_t page_off = real_off - aligned_off; - sector_t aligned_block = aligned_off / bdev->block_size; - sector_t block_nr = aligned_block + ((real_off - aligned_off) / bdev->block_size); - - if (!(buf = page_add_blockbuf(page, page_off))) + if (buf->block_nr == block) { - page_unref(page); - return nullptr; + block_buf_get(buf); + return buf; } - buf->block_nr = block_nr; - buf->block_size = bdev->block_size; - buf->dev = bdev; + buf = buf->next; } - block_buf_get(buf); + /* Not supposed to happen */ + WARN_ON_ONCE(1); + return NULL; +} - page_unref(page); +static struct block_buf *__read_block_cache(struct blockdev *bdev, unsigned int block_size, + unsigned long block) +{ + size_t real_off = block_size * block; + struct block_buf *buf = NULL; + struct folio *folio; + + int st = filemap_find_folio(bdev->b_ino, real_off >> PAGE_SHIFT, + FIND_PAGE_LOCK | FIND_PAGE_ACTIVATE, &folio, nullptr); + if (st < 0) + return nullptr; + buf = find_or_create_buffers(folio, block, block_size, bdev); + folio_unlock(folio); + folio_put(folio); return buf; } +struct block_buf *sb_read_block(const struct superblock *sb, unsigned long block) +{ + return __read_block_cache(sb->s_bdev, sb->s_block_size, block); +} + +struct block_buf *bdev_read_block(struct blockdev *bdev, unsigned long block) +{ + return __read_block_cache(bdev, bdev->block_size, block); +} + void block_buf_dirty(block_buf *buf) { if (!bb_test_and_set(buf, BLOCKBUF_FLAG_DIRTY)) @@ -701,6 +722,7 @@ void block_buf_dirty(block_buf *buf) void page_remove_block_buf(struct page *page, size_t offset, size_t end) { + WARN_ON(!page_locked(page)); block_buf **pp = (block_buf **) &page->priv; while (*pp != nullptr) @@ -843,7 +865,37 @@ void block_buf_forget_inode(struct block_buf *buf) void buffer_free_page(struct vm_object *vmo, struct page *page) { - if (page_flag_set(page, PAGE_FLAG_BUFFER)) - page_destroy_block_bufs(page); + WARN_ON(page_test_buffer(page)); + WARN_ON(page->priv != 0); free_page(page); } + +bool buffer_release_folio(struct folio *folio, gfp_t gfp) +{ + struct block_buf *buf; + + /* In no way should folios in this state reach us */ + WARN_ON(!folio_test_locked(folio)); + WARN_ON(folio_test_dirty(folio) || folio_test_writeback(folio)); + + /* We are excluded against grabbing refs by the folio lock */ + if (!folio_test_buffer(folio)) + return true; + + buf = (struct block_buf *) folio->priv; + while (buf) + { + /* Refcount incremented? Can't do it */ + if (buf->refc > 1) + return false; + /* Being read async? Can't do it */ + if (bb_test_flag(buf, BLOCKBUF_FLAG_AREAD)) + return false; + buf = buf->next; + } + + /* We can free these buffers, lets give it a shot. */ + page_destroy_block_bufs(folio_to_page(folio)); + folio_clear_buffer(folio); + return true; +} diff --git a/kernel/kernel/fs/coredump.c b/kernel/kernel/fs/coredump.c index bf78cbd1f..274e0157e 100644 --- a/kernel/kernel/fs/coredump.c +++ b/kernel/kernel/fs/coredump.c @@ -124,7 +124,7 @@ static int coredump_collect_vmas(struct core_state *core) } } - if (cvma->flags & VM_DONTDUMP) + if (cvma->flags & (VM_DONTDUMP | VM_PFNMAP)) cvma->dump_len = 0; nr_vmas++; diff --git a/kernel/kernel/fs/dev.cpp b/kernel/kernel/fs/dev.cpp index 3fd309759..f6a9ec299 100644 --- a/kernel/kernel/fs/dev.cpp +++ b/kernel/kernel/fs/dev.cpp @@ -718,4 +718,5 @@ __init void devfs_init() panic("Could not register devfs"); devfs_add_dir("shm", 0777); devfs_add_dir("pts", 0755); + devfs_add_dir("input", 0755); } diff --git a/kernel/kernel/fs/ext2/ext2.cpp b/kernel/kernel/fs/ext2/ext2.cpp index 851fbd8a3..25cb1ec1c 100644 --- a/kernel/kernel/fs/ext2/ext2.cpp +++ b/kernel/kernel/fs/ext2/ext2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 - 2025 Pedro Falcato + * Copyright (c) 2016 - 2026 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * @@ -438,7 +438,7 @@ int ext2_open(struct dentry *dir, const char *name, struct dentry *dentry) struct inode *inode = ext2_get_inode(fs, inode_num); if (!inode) - return -errno; + return -ENOMEM; d_finish_lookup(dentry, inode); return 0; } @@ -453,6 +453,7 @@ static const struct vm_object_ops ext2_vm_obj_ops = { .readpages = ext2_readpages, .readpage = ext2_readpage, .prepare_write = ext2_prepare_write, + .release_folio = buffer_release_folio, }; struct inode *ext2_fs_ino_to_vfs_ino(struct ext2_inode *inode, uint32_t inumber, diff --git a/kernel/kernel/fs/ext2/ext2_ll.cpp b/kernel/kernel/fs/ext2/ext2_ll.cpp index be64f05a8..fb5e7b0c2 100644 --- a/kernel/kernel/fs/ext2/ext2_ll.cpp +++ b/kernel/kernel/fs/ext2/ext2_ll.cpp @@ -428,7 +428,7 @@ int ext2_retrieve_dirent(inode *inode, const char *name, ext2_superblock *fs, if (read_res < 0) { - st = -errno; + st = read_res; goto out; } diff --git a/kernel/kernel/fs/poll.cpp b/kernel/kernel/fs/poll.cpp index 1c25d5ffb..16b393730 100644 --- a/kernel/kernel/fs/poll.cpp +++ b/kernel/kernel/fs/poll.cpp @@ -1,7 +1,9 @@ /* - * Copyright (c) 2019 Pedro Falcato + * Copyright (c) 2019 - 2026 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information + * + * SPDX-License-Identifier: GPL-2.0-only */ #include @@ -313,7 +315,7 @@ int sys_pselect(int nfds, fd_set *ureadfds, fd_set *uwritefds, fd_set *uexceptfd if (nfds < 0) return -EINVAL; - if (nfds >= FD_SETSIZE) + if (nfds > FD_SETSIZE) return -EINVAL; bool infinite_sleep = true; diff --git a/kernel/kernel/fs/tmpfs.cpp b/kernel/kernel/fs/tmpfs.cpp index 56123f2b0..77e0a8159 100644 --- a/kernel/kernel/fs/tmpfs.cpp +++ b/kernel/kernel/fs/tmpfs.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -486,3 +487,49 @@ const struct super_ops tmpfs_sb_ops = { .shutdown = sb_generic_shutdown, .free_inode = tmpfs_free_inode, }; + +static tmpfs_superblock *shmemfs_sb; + +__init void shmem_init() +{ + shmemfs_sb = new tmpfs_superblock(0); + CHECK(shmemfs_sb); +} + +/** + * @brief Create a new shmem file + * + * @param len Length, in bytes + * @return Opened struct file, or NULL + */ +struct file *anon_get_shmem(size_t len) +{ + struct dentry *dentry; + struct file *f; + tmpfs_inode *ino = shmemfs_sb->alloc_inode(0777 | S_IFREG, 0); + if (!ino) + return nullptr; + ino->i_size = -1UL; + + /* Note for future me: While this solution basically works, it does not properly work if we care + * about merging of MAP_SHARED or mremap. That will take some more annoying codepaths that e.g + * properly adjust the length of the inode. + */ + dentry = dentry_create("[anon_shmem]", ino, nullptr); + if (!dentry) + goto err; + dget(dentry); + + f = inode_to_file(ino); + if (!f) + goto err; + + f->f_dentry = dentry; + return f; +err: + if (dentry) + dput(dentry); + if (ino) + inode_unref(ino); + return nullptr; +} diff --git a/kernel/kernel/fs/xattr.c b/kernel/kernel/fs/xattr.c index 1c10f2cdc..e2ee53095 100644 --- a/kernel/kernel/fs/xattr.c +++ b/kernel/kernel/fs/xattr.c @@ -21,3 +21,48 @@ ssize_t sys_llistxattr(const char *path, char *list, size_t size) { return -ENOTSUP; } + +int sys_setxattr(const char *path, const char *name, const void *value, size_t size, int flags) +{ + return -ENOTSUP; +} + +int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) +{ + return -ENOTSUP; +} + +int sys_fsetxattr(int fd, const char *name, const void *value, size_t size, int flags) +{ + return -ENOTSUP; +} + +ssize_t sys_getxattr(const char *path, const char *name, void *value, size_t size) +{ + return -ENOTSUP; +} + +ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size) +{ + return -ENOTSUP; +} + +ssize_t sys_fgetxattr(int fd, const char *name, void *value, size_t size) +{ + return -ENOTSUP; +} + +int sys_removexattr(const char *path, const char *name) +{ + return -ENOTSUP; +} + +int sys_lremovexattr(const char *path, const char *name) +{ + return -ENOTSUP; +} + +int sys_fremovexattr(int fd, const char *name) +{ + return -ENOTSUP; +} diff --git a/kernel/kernel/initrd.cpp b/kernel/kernel/initrd.cpp index 8b8538442..d079ff6f9 100644 --- a/kernel/kernel/initrd.cpp +++ b/kernel/kernel/initrd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 - 2025 Pedro Falcato + * Copyright (c) 2016 - 2026 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * @@ -40,15 +40,45 @@ unsigned int parse_perms_from_tar(tar_header_t *entry) .unwrap(); } +static char tar_longname[PATH_MAX]; +static unsigned int longname_len; +static bool has_longname; +static char tar_longlink[PATH_MAX]; +static unsigned int longlink_len; +static bool has_longlink; + void tar_handle_entry(tar_header_t *entry, onx::stream &str) { char *full_filename; if (memcmp(entry->magic, "ustar ", 5)) panic("Tar entry with invalid magic value"); + auto filenamelen = strnlen(entry->filename, 100); size_t len; - if (entry->prefix[0] != '\0') + if (entry->typeflag == TAR_TYPE_LONGNAME) + { + longname_len = tar_get_size(entry->size); + str.read(cul::slice{(unsigned char *) tar_longname, longname_len}).unwrap(); + has_longname = true; + return; + } + else if (entry->typeflag == TAR_TYPE_LONGLINK) + { + longlink_len = tar_get_size(entry->size); + str.read(cul::slice{(unsigned char *) tar_longlink, longlink_len}).unwrap(); + has_longlink = true; + tar_longlink[longlink_len] = '\0'; + return; + } + + if (has_longname) + { + full_filename = (char *) memdup(tar_longname, longname_len + 1); + len = longname_len; + has_longname = false; + } + else if (entry->prefix[0] != '\0') { auto prefixlen = strnlen(entry->prefix, 155); full_filename = (char *) malloc(prefixlen + filenamelen + 2); // Additional char for / @@ -112,7 +142,6 @@ void tar_handle_entry(tar_header_t *entry, onx::stream &str) auto ex = vfs_open(AT_FDCWD, full_filename, O_RDWR | O_CREAT, perms); if (ex.has_error()) panic("Could not create file from initrd - errno %d", ex.error()); - filp = ex.value(); size_t size = tar_get_size(entry->size); str.splice(size, filp).unwrap(); @@ -126,6 +155,11 @@ void tar_handle_entry(tar_header_t *entry, onx::stream &str) else if (entry->typeflag == TAR_TYPE_SYMLNK) { char *buffer = (char *) entry->linkname; + if (has_longlink) + { + buffer = tar_longlink; + has_longlink = false; + } int st = symlink_vfs(full_filename, buffer, AT_FDCWD); CHECK(st == 0); } diff --git a/kernel/kernel/input/Makefile b/kernel/kernel/input/Makefile index f1be44385..e050a35c6 100644 --- a/kernel/kernel/input/Makefile +++ b/kernel/kernel/input/Makefile @@ -1,3 +1,3 @@ -input-y+= device.o state.o +input-y+= device.o state.o evdev.o obj-y+= $(patsubst %, kernel/input/%, $(input-y)) diff --git a/kernel/kernel/input/device.cpp b/kernel/kernel/input/device.cpp index a5f532fca..16b53b5be 100644 --- a/kernel/kernel/input/device.cpp +++ b/kernel/kernel/input/device.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -21,16 +22,26 @@ static DEFINE_SPINLOCK(input_dev_list_lock); static struct list_head input_dev_list = LIST_HEAD_INIT(input_dev_list); static atomic input_id = 0; -void input_device_register(input_device *dev) +extern "C" struct file_ops evdev_fops; + +void input_device_register(struct input_device *dev) { char new_name[64] = {}; - if (snprintf(new_name, 64, "input%u", input_id++) < 0) + if (snprintf(new_name, 64, "event%u", input_id++) < 0) return; char *n = strdup(new_name); if (!n) panic("Out of memory strdup'ing name"); dev->name = n; + INIT_LIST_HEAD(&dev->client_list); + spinlock_init(&dev->client_list_lock); + memset(&dev->leds, 0, sizeof(dev->leds)); + memset(&dev->switch_bits, 0, sizeof(dev->switch_bits)); + auto ex = dev_register_chardevs(0, 1, 0, &evdev_fops, n); + auto cdev = ex.unwrap(); + cdev->private_ = dev; + cdev->show_with_name(new_name, "input/", 0660); scoped_lock guard{input_dev_list_lock}; list_add_tail(&dev->list, &input_dev_list); } @@ -41,37 +52,58 @@ void input_device_unregister(struct input_device *dev) list_remove(&dev->list); } +extern "C" void evdev_submit_event(struct input_device *dev, struct evdev_input_event *ev); + int vterm_submit_event(struct input_device *dev, struct input_event *ev); +#define TIMESPEC_TO_TIMEVAL(tv, ts) \ + ((tv)->tv_sec = (ts)->tv_sec, (tv)->tv_usec = (ts)->tv_nsec / 1000, (void) 0) + void input_device_submit_event(struct input_device *dev, struct input_event *ev) { + struct evdev_input_event evdev_ev = {}; + struct timespec ts; bool pressed = ev->flags & INPUT_EVENT_FLAG_PRESSED; - input_state_set_key_state(ev->code, pressed, &dev->state); + evdev_ev.code = ev->code; + evdev_ev.type = EV_KEY; + evdev_ev.value = pressed ? 1 : 0; + clock_gettime_kernel(CLOCK_REALTIME, &ts); + TIMESPEC_TO_TIMEVAL(&evdev_ev.time, &ts); + evdev_submit_event(dev, &evdev_ev); + evdev_ev.code = SYN_REPORT; + evdev_ev.type = EV_SYN; + evdev_ev.value = 1; + evdev_submit_event(dev, &evdev_ev); /* TODO: Should this be vterm-specific code? GUI apps probably * just want the keypresses. */ + input_state_set_key_state(ev->code, pressed, &dev->state); switch (ev->code) { - case KEYMAP_KEY_LSHIFT: - case KEYMAP_KEY_RSHIFT: + case KEY_LEFTSHIFT: + case KEY_RIGHTSHIFT: dev->state.shift_pressed = pressed; break; - case KEYMAP_KEY_CAPS_LOCK: + case KEY_CAPSLOCK: dev->state.caps_enabled = !(dev->state.caps_enabled); break; - case KEYMAP_KEY_LALT: - case KEYMAP_KEY_ALTGR: + case KEY_LEFTALT: + case KEY_RIGHTALT: dev->state.alt_pressed = pressed; break; - case KEYMAP_KEY_LCTRL: - case KEYMAP_KEY_RCTRL: + case KEY_LEFTCTRL: + case KEY_RIGHTCTRL: dev->state.ctrl_pressed = pressed; break; default: break; } + /* vterm will not look at this event. */ + if (rcu_access_pointer(dev->grab)) + return; + vterm_submit_event(dev, ev); } diff --git a/kernel/kernel/input/evdev.c b/kernel/kernel/input/evdev.c new file mode 100644 index 000000000..9d19684e0 --- /dev/null +++ b/kernel/kernel/input/evdev.c @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2025 - 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License + * check LICENSE at the root directory for more information + * + * SPDX-License-Identifier: GPL-2.0-only + */ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +static void evdev_append_client(struct input_device *dev, struct evdev_client *client) +{ + spin_lock(&dev->client_list_lock); + list_add_tail_rcu(&client->node, &dev->client_list); + spin_unlock(&dev->client_list_lock); +} + +static void evdev_post_event(struct evdev_client *client, struct evdev_input_event *ev) +{ + unsigned long flags = spin_lock_irqsave(&client->buffer_lock); + + if (client->write - client->read == client->buf_size) + { + /* Full? Bump read ahead */ + client->read++; + } + + memcpy(&client->buffer[client->write & (client->buf_size - 1)], ev, + sizeof(struct evdev_input_event)); + client->write++; + spin_unlock_irqrestore(&client->buffer_lock, flags); + wait_queue_wake_all(&client->wq); +} + +void evdev_submit_event(struct input_device *dev, struct evdev_input_event *ev) +{ + struct evdev_client *client; + struct evdev_client *grab; + + rcu_read_lock(); + grab = rcu_access_pointer(dev->grab); + list_for_each_entry_rcu (client, &dev->client_list, node) + { + if (grab && grab != client) + continue; + evdev_post_event(client, ev); + } + rcu_read_unlock(); +} + +static int evdev_open(struct file *filp) +{ + struct input_device *dev = filp->f_ino->i_helper; + struct evdev_client *client; + + client = kmalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + client->buf_size = 64; + client->buffer = kcalloc(client->buf_size, sizeof(struct evdev_input_event), GFP_KERNEL); + if (!client->buffer) + { + kfree(client); + return -ENOMEM; + } + + client->write = client->read = 0; + client->dev = dev; + spinlock_init(&client->buffer_lock); + evdev_append_client(dev, client); + filp->private_data = client; + init_wait_queue_head(&client->wq); + return 0; +} + +static bool evdev_consume_event(struct evdev_client *ev, struct evdev_input_event *event) +{ + bool consumed = false; + unsigned long flags = spin_lock_irqsave(&ev->buffer_lock); + + if (ev->read != ev->write) + { + memcpy(event, &ev->buffer[ev->read & (ev->buf_size - 1)], sizeof(struct evdev_input_event)); + ev->read++; + consumed = true; + } + + spin_unlock_irqrestore(&ev->buffer_lock, flags); + return consumed; +} + +static ssize_t evdev_read_iter(struct file *filp, size_t offset, struct iovec_iter *iter, + unsigned int flags) +{ + struct evdev_client *client; + struct evdev_input_event ev; + ssize_t err = 0, tmp; + + client = filp->private_data; + if (iter->bytes != 0 && iter->bytes < sizeof(struct evdev_input_event)) + return -EINVAL; + + for (;;) + { + if (client->read == client->write && (filp->f_flags & O_NONBLOCK)) + return -EAGAIN; + + while (iter->bytes >= sizeof(struct evdev_input_event) && evdev_consume_event(client, &ev)) + { + tmp = copy_to_iter(iter, &ev, sizeof(struct evdev_input_event)); + if (tmp > 0) + err += tmp; + else + err = err ?: tmp; + } + + if (err) + break; + err = wait_for_event_interruptible(&client->wq, client->read != client->write); + if (err) + break; + } + + return err; +} + +static short evdev_poll(void *poll_file, short events, struct file *filp) +{ + struct evdev_client *client = filp->private_data; + unsigned long flags; + short revents = 0; + + flags = spin_lock_irqsave(&client->buffer_lock); + if (client->read != client->write) + revents |= POLLIN; + else + poll_wait_helper(poll_file, &client->wq); + + spin_unlock_irqrestore(&client->buffer_lock, flags); + return events & revents; +} + +#define EV_VERSION 0x010001 + +static int evdev_copy_str(const char *string, unsigned int len, void *argp) +{ + int to_copy = min(len, strlen(string) + 1); + + return copy_to_user(argp, string, to_copy) ? -EFAULT : to_copy; +} + +static int evdev_copy_bits(void *user, void *buf, unsigned int iocsize, unsigned int len) +{ + if (len > iocsize) + len = iocsize; + return copy_to_user(user, buf, len) ? -EFAULT : (int) len; +} + +static int do_eviocgbit(struct input_device *dev, unsigned int ev_type, void *buf, + unsigned int iocsize) +{ + unsigned long dummy = 0; + unsigned long *bits = &dummy; + unsigned int len = sizeof(dummy); + + switch (ev_type) + { + case 0: + bits = &dev->feature_bits; + len = sizeof(dev->feature_bits); + break; + case EV_KEY: + bits = dev->key_bits; + len = sizeof(dev->key_bits); + break; + case EV_SW: + bits = &dev->switch_bits; + len = sizeof(dev->switch_bits); + break; + case EV_LED: + bits = &dev->leds; + len = sizeof(dev->leds); + break; + case EV_REL: + case EV_ABS: + case EV_MSC: + case EV_SND: + case EV_REP: + case EV_FF: + case EV_PWR: + case EV_FF_STATUS: + break; + default: + return -EINVAL; + } + + return evdev_copy_bits(buf, bits, iocsize, len); +} + +static int evdev_grab(struct evdev_client *client, struct input_device *dev) +{ + unsigned long flags; + int err = -EBUSY; + + flags = spin_lock_irqsave(&dev->client_list_lock); + + if (dev->grab) + goto out; + + rcu_assign_pointer(dev->grab, client); + err = 0; +out: + spin_unlock_irqrestore(&dev->client_list_lock, flags); + return err; +} + +static int evdev_ungrab(struct evdev_client *client, struct input_device *dev) +{ + unsigned long flags; + int err = -EINVAL; + + flags = spin_lock_irqsave(&dev->client_list_lock); + + if (dev->grab != client) + goto out; + + rcu_assign_pointer(dev->grab, NULL); + err = 0; +out: + spin_unlock_irqrestore(&dev->client_list_lock, flags); + return err; +} + +static void evdev_drop_events(struct evdev_client *client, int type) +{ + unsigned long flags; + + flags = spin_lock_irqsave(&client->buffer_lock); + + /* TODO: Write this... */ +#if 0 + for (unsigned long pos = client->read, read = client->read; pos != client->write; pos++) + { + if (client->buffer[pos & (client->buf_size - 1)].type != type) + continue; + + /* front of queue? increment read */ + if (pos == client->read) + { + client->read++; + continue; + } + + /* We're not in front of the queue, thus we need to copy it back manually */ + + ev->read++; + consumed = true; + } +#endif + spin_unlock_irqrestore(&client->buffer_lock, flags); +} + +static int do_eviocgkey(struct input_device *dev, struct evdev_client *client, unsigned int iocsize, + void *argp) +{ + /* Remove EV_KEY inputs from our buffer, so the client doesn't register things twice. */ + /* TODO: We should probably have a lock on this. */ + return evdev_copy_bits(argp, dev->state.keys_pressed, iocsize, sizeof(dev->state.keys_pressed)); +} + +static unsigned int evdev_ioctl(int request, void *argp, struct file *file) +{ + struct evdev_client *client = file->private_data; + struct input_device *dev = client->dev; + unsigned int iocsize; + + pr_info("evdev: ioctl %x\n", request); + + switch (request) + { + case EVIOCGVERSION: { + int version = EV_VERSION; + return copy_to_user(argp, &version, sizeof(version)); + } + case EVIOCGID: { + return copy_to_user(argp, &dev->input_id, sizeof(struct input_id)); + } + case EVIOCGRAB: { + if (argp) + return evdev_grab(client, dev); + else + return evdev_ungrab(client, dev); + } + } + + /* yuck */ +#define _IOC_RAWSIZMASK ((int) (_IOC_SIZEMASK << 16)) +#define _IOC_NOSIZE(request) ((request) & ~_IOC_RAWSIZMASK) + iocsize = _IOC_SIZE(request); + switch (_IOC_NOSIZE(request)) + { + case EVIOCGNAME(0): + return evdev_copy_str(dev->name, iocsize, argp); + case EVIOCGPROP(0): + return evdev_copy_bits(argp, &dev->properties, iocsize, sizeof(dev->properties)); + case EVIOCGPHYS(0): + return evdev_copy_str(dev->phys, iocsize, argp); + case EVIOCGUNIQ(0): + return evdev_copy_str("", iocsize, argp); + case EVIOCGKEY(0): + return do_eviocgkey(dev, client, iocsize, argp); + case EVIOCGLED(0): + return evdev_copy_bits(argp, &dev->leds, iocsize, sizeof(dev->leds)); + case EVIOCGSW(0): + return evdev_copy_bits(argp, &dev->switch_bits, iocsize, sizeof(dev->switch_bits)); + } + + /* yuck x2 */ + if (_IOC_TYPE(request) != 'E') + return -EINVAL; + if ((_IOC_NR(request) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) + return do_eviocgbit(dev, _IOC_NR(request) & EV_MAX, argp, iocsize); + return -ENOTTY; +} + +static void evdev_destroy(struct rcu_head *head) +{ + struct evdev_client *client = container_of(head, struct evdev_client, rcu_head); + + kfree(client->buffer); + kfree(client); +} + +static void evdev_release(struct file *filp) +{ + struct evdev_client *client = filp->private_data; + struct input_device *dev = client->dev; + unsigned long flags; + + flags = spin_lock_irqsave(&dev->client_list_lock); + if (dev->grab == client) + rcu_assign_pointer(dev->grab, NULL); + list_remove_rcu(&client->node); + spin_unlock_irqrestore(&dev->client_list_lock, flags); + + /* RCU-delay the destruction */ + call_rcu(&client->rcu_head, evdev_destroy); +} + +const struct file_ops evdev_fops = { + .on_open = evdev_open, + .read_iter = evdev_read_iter, + .poll = evdev_poll, + .ioctl = evdev_ioctl, + .release = evdev_release, +}; diff --git a/kernel/kernel/input/state.cpp b/kernel/kernel/input/state.cpp index 2cc2b54b5..97c625bd7 100644 --- a/kernel/kernel/input/state.cpp +++ b/kernel/kernel/input/state.cpp @@ -8,7 +8,7 @@ static constexpr unsigned int keys_per_long = (sizeof(unsigned long) * CHAR_BIT); -void input_state_set_key_state(keycode_t key, bool pressed, struct input_state *is) +void input_state_set_key_state(unsigned key, bool pressed, struct input_state *is) { unsigned int idx = key / keys_per_long; unsigned int bit_idx = key % keys_per_long; diff --git a/kernel/kernel/mm/Makefile b/kernel/kernel/mm/Makefile index 5b3243299..7620e401c 100644 --- a/kernel/kernel/mm/Makefile +++ b/kernel/kernel/mm/Makefile @@ -1,5 +1,6 @@ mm-y:= bootmem.o page.o pagealloc.o vm_object.o vm.o vmalloc.o reclaim.o anon.o \ - mincore.o page_lru.o swap.o rmap.o slab_cache_pool.o madvise.o page_frag.o + mincore.o page_lru.o swap.o rmap.o slab_cache_pool.o madvise.o page_frag.o \ + mlock.o mm-$(CONFIG_KUNIT)+= vm_tests.o mm-$(CONFIG_X86)+= memory.o mm-$(CONFIG_RISCV)+= memory.o diff --git a/kernel/kernel/mm/anon.cpp b/kernel/kernel/mm/anon.c similarity index 63% rename from kernel/kernel/mm/anon.cpp rename to kernel/kernel/mm/anon.c index aa3ab36d9..08d727237 100644 --- a/kernel/kernel/mm/anon.cpp +++ b/kernel/kernel/mm/anon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 - 2024 Pedro Falcato + * Copyright (c) 2023 - 2026 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * @@ -9,20 +9,22 @@ #include #include #include +#include #include -#include #include #include int vm_anon_fault(struct vm_pf_context *ctx); -const struct vm_operations anon_vmops = {.fault = vm_anon_fault}; +const struct vm_operations anon_vmops = { + .fault = vm_anon_fault, +}; int vm_anon_fault(struct vm_pf_context *ctx) { struct vm_area_struct *vma = ctx->entry; struct fault_info *info = ctx->info; - struct page *page = nullptr; + struct page *page = NULL; pte_t *ptep; struct spinlock *lock; @@ -75,49 +77,3 @@ int vm_anon_fault(struct vm_pf_context *ctx) info->error_info = VM_SIGSEGV; return -ENOMEM; } - -static tmpfs_superblock *shmemfs_sb; - -__init void shmem_init() -{ - shmemfs_sb = new tmpfs_superblock(0); - CHECK(shmemfs_sb); -} - -/** - * @brief Create a new shmem file - * - * @param len Length, in bytes - * @return Opened struct file, or NULL - */ -struct file *anon_get_shmem(size_t len) -{ - struct dentry *dentry; - struct file *f; - tmpfs_inode *ino = shmemfs_sb->alloc_inode(0777 | S_IFREG, 0); - if (!ino) - return nullptr; - ino->i_size = -1UL; - - /* Note for future me: While this solution basically works, it does not properly work if we care - * about merging of MAP_SHARED or mremap. That will take some more annoying codepaths that e.g - * properly adjust the length of the inode. - */ - dentry = dentry_create("[anon_shmem]", ino, nullptr); - if (!dentry) - goto err; - dget(dentry); - - f = inode_to_file(ino); - if (!f) - goto err; - - f->f_dentry = dentry; - return f; -err: - if (dentry) - dput(dentry); - if (ino) - inode_unref(ino); - return nullptr; -} diff --git a/kernel/kernel/mm/asan/asan.cpp b/kernel/kernel/mm/asan/asan.cpp index 4f2115616..e30fe14cf 100644 --- a/kernel/kernel/mm/asan/asan.cpp +++ b/kernel/kernel/mm/asan/asan.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -235,7 +236,7 @@ void kasan_fail(unsigned long addr, size_t size, bool write, unsigned char b) panic(buffer); } -#define KASAN_MISALIGNMENT(x) ((x) &KASAN_N_MASK) +#define KASAN_MISALIGNMENT(x) ((x) & KASAN_N_MASK) void kasan_check_memory_fast(unsigned long addr, size_t size, bool write) { diff --git a/kernel/kernel/mm/mlock.c b/kernel/kernel/mm/mlock.c new file mode 100644 index 000000000..0d765028d --- /dev/null +++ b/kernel/kernel/mm/mlock.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License + * check LICENSE at the root directory for more information + * + * SPDX-License-Identifier: GPL-2.0-only + */ +#include + +int sys_mlock(const void *addr, size_t len) +{ + return 0; +} + +int sys_munlock(const void *addr, size_t len) +{ + return 0; +} + +int sys_mlockall(int flags) +{ + return 0; +} + +int sys_munlockall(void) +{ + return 0; +} diff --git a/kernel/kernel/mm/page_lru.c b/kernel/kernel/mm/page_lru.c index fb6e5ba89..36ae62644 100644 --- a/kernel/kernel/mm/page_lru.c +++ b/kernel/kernel/mm/page_lru.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 - 2025 Pedro Falcato + * Copyright (c) 2024 - 2026 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * @@ -69,11 +69,13 @@ static void folio_batch_add_lru(struct folio_batch *batch) void folio_add_lru(struct folio *folio) { - struct percpu_batches *batches = get_per_cpu_ptr(lru_batches); - local_lock(&batches->lock); + struct percpu_batches *batches; + + local_lock(&lru_batches.lock); + batches = get_per_cpu_ptr(lru_batches); if (!folio_batch_add(&batches->lru_add, folio)) folio_batch_add_lru(&batches->lru_add); - local_unlock(&batches->lock); + local_unlock(&lru_batches.lock); } void folio_remove_lru(struct folio *folio) @@ -158,7 +160,7 @@ static void folio_batch_activate_lru(struct folio_batch *batch) static void folio_activate(struct folio *folio) { - struct percpu_batches *batches = get_per_cpu_ptr(lru_batches); + struct percpu_batches *batches; if (!folio_test_clear_lru(folio)) { @@ -168,10 +170,31 @@ static void folio_activate(struct folio *folio) return; } - local_lock(&batches->lock); + local_lock(&lru_batches.lock); + batches = get_per_cpu_ptr(lru_batches); if (!folio_batch_add(&batches->activate, folio)) folio_batch_activate_lru(&batches->activate); - local_unlock(&batches->lock); + local_unlock(&lru_batches.lock); +} + +static void folio_set_active_local(struct folio *folio) +{ + struct percpu_batches *batches; + unsigned int i; + + local_lock(&lru_batches.lock); + batches = get_per_cpu_ptr(lru_batches); + + for (i = 0; i < batches->lru_add.nr; i++) + { + if (batches->lru_add.batch[i] == folio) + { + folio_set_active(folio); + break; + } + } + + local_unlock(&lru_batches.lock); } void folio_promote_referenced(struct folio *folio) @@ -194,9 +217,9 @@ void folio_promote_referenced(struct folio *folio) } else { - /* We're in a page batch (or bound to be added by someone else). Just set the active bit and - * they'll take care of it. */ - folio_set_active(folio); + /* We're in a page batch. Just set the active bit and the LRU add logic will take care of + * it. But we can only do it to ourselves without racing. */ + folio_set_active_local(folio); } } @@ -208,7 +231,9 @@ static void folio_batch_deactivate_lru(struct folio_batch *batch) for (unsigned int i = 0; i < batch->nr; i++) { folio = batch->batch[i]; - CHECK(!folio_test_lru(folio)); + /* Someone added it to an LRU just now? It's possible. Just ignore, then. */ + if (folio_test_lru(folio)) + continue; newlru = folio_to_page_lru(folio); if (lru != newlru) { @@ -231,7 +256,7 @@ static void folio_batch_deactivate_lru(struct folio_batch *batch) void page_lru_demote_reclaim(struct folio *folio) { - struct percpu_batches *batches = get_per_cpu_ptr(lru_batches); + struct percpu_batches *batches; if (folio_test_dirty(folio) || folio_test_locked(folio)) return; @@ -239,8 +264,9 @@ void page_lru_demote_reclaim(struct folio *folio) if (!folio_test_clear_lru(folio)) return; - local_lock(&batches->lock); + local_lock(&lru_batches.lock); + batches = get_per_cpu_ptr(lru_batches); if (!folio_batch_add(&batches->deactivate, folio)) folio_batch_deactivate_lru(&batches->deactivate); - local_unlock(&batches->lock); + local_unlock(&lru_batches.lock); } diff --git a/kernel/kernel/mm/pagealloc.cpp b/kernel/kernel/mm/pagealloc.cpp index 7b44db62f..7b6c05f40 100644 --- a/kernel/kernel/mm/pagealloc.cpp +++ b/kernel/kernel/mm/pagealloc.cpp @@ -144,7 +144,7 @@ static void pagedaemon(void * /*arg*/) } } -static void do_direct_reclaim(int order, int attempt, unsigned int gfp_flags) +static int do_direct_reclaim(int order, int attempt, unsigned int gfp_flags) { struct reclaim_data data; data.attempt = attempt; @@ -153,7 +153,7 @@ static void do_direct_reclaim(int order, int attempt, unsigned int gfp_flags) data.mode = RECLAIM_MODE_DIRECT; pr_info("pagealloc: Doing direct reclaim: order %d, attempt %d, gfp_flags %x\n", order, attempt, gfp_flags); - page_do_reclaim(&data); + return page_do_reclaim(&data); } static struct page *page_zone_alloc_core(page_zone *zone, unsigned int gfp_flags, @@ -863,7 +863,7 @@ static __always_inline void prepare_pages_after_alloc(struct page *page, unsigne } } -#define PAGE_ALLOC_MAX_RECLAIM_ATTEMPT 5 +#define PAGE_ALLOC_MAX_RECLAIM_ATTEMPT 16 void stack_trace(); static void pagestats_accumulate_for_zone(struct page_zone *zone, @@ -871,8 +871,7 @@ static void pagestats_accumulate_for_zone(struct page_zone *zone, { for (unsigned int i = 0; i < PAGE_STATS_MAX; i++) { - for (unsigned int j = 0; j < CONFIG_SMP_NR_CPUS; j++) - pagestats[i] += zone->pcpu[i].pagestats[i]; + pagestats[i] += zone->pagestats[i]; } } @@ -926,10 +925,20 @@ static void dump_oom_log(void) pr_warn("%lu pages RAM\n", nr_global_pages.load()); } +static void try_continue_alloc(unsigned int order, unsigned int *attempt, int progress) +{ + /* For high order, always assume that we may not have made forward progress. */ + if (order > 0 || !progress) + (*attempt)++; + else + *attempt = 0; +} + struct page *page_node::alloc_order(unsigned int order, unsigned long flags) { struct page *page = nullptr; unsigned int attempt = 0; + int progress = 1; if (flags & __GFP_MAY_RECLAIM && !(flags & (__GFP_NOWAIT | __GFP_ATOMIC))) { @@ -962,7 +971,7 @@ struct page *page_node::alloc_order(unsigned int order, unsigned long flags) break; if (flags & __GFP_DIRECT_RECLAIM) - do_direct_reclaim(order, attempt, flags); + progress = do_direct_reclaim(order, attempt, flags) >= 0; else if (flags & __GFP_WAKE_PAGEDAEMON) { unsigned long cur_seq = wake_up_pagedaemon(order, attempt); @@ -976,7 +985,7 @@ struct page *page_node::alloc_order(unsigned int order, unsigned long flags) else goto failure; /* No reclaim, just fail */ - attempt++; + try_continue_alloc(order, &attempt, progress); } if (unlikely(!page)) @@ -1122,20 +1131,59 @@ static struct page_zone *folio_to_zone(struct folio *folio) return main_node.pick_zone((unsigned long) folio_to_phys(folio)); } -void inc_folio_stat(struct folio *folio, enum page_stat stat) +static __noinline long sync_stat_pcpu(struct page_zone *zone, enum page_stat stat) +{ + long to_add; + long result = 0; + + for (unsigned int i = 0; i < get_nr_cpus(); i++) + { + to_add = __atomic_exchange_n(&zone->pcpu[i].pagestats[stat], 0, __ATOMIC_RELAXED); + result = __atomic_add_fetch(&zone->pagestats[stat], to_add, __ATOMIC_RELAXED); + } + + return result; +} + +static __noinline void inc_stat_slowpath(struct page_zone *zone, struct page_pcpu_data *pcpu, + enum page_stat stat) +{ + long to_add = __atomic_exchange_n(&pcpu->pagestats[stat], 0, __ATOMIC_RELAXED); + long res; + + /* Add to_add to the zonestats */ + res = __atomic_add_fetch(&zone->pagestats[stat], to_add, __ATOMIC_RELAXED); + if (unlikely(res < 0)) + { + /* Something is off here, but it can happen. Recalculate everything and warn if we actually + * went negative. This is not supposed to happen. */ + WARN_ON_ONCE(sync_stat_pcpu(zone, stat) < 0); + } +} + +#define STAT_THRESHOLD 32 + +static void mod_folio_stat(struct folio *folio, enum page_stat stat, long off) { struct page_zone *zone = folio_to_zone(folio); + struct page_pcpu_data *pcpu; + sched_disable_preempt(); - zone->pcpu[get_cpu_nr()].pagestats[stat] += folio_nr_pages(folio); + pcpu = &zone->pcpu[get_cpu_nr()]; + __atomic_add_fetch(&pcpu->pagestats[stat], off, __ATOMIC_RELAXED); + if (pcpu->pagestats[stat] > STAT_THRESHOLD || pcpu->pagestats[stat] < -STAT_THRESHOLD) + inc_stat_slowpath(zone, pcpu, stat); sched_enable_preempt(); } +void inc_folio_stat(struct folio *folio, enum page_stat stat) +{ + mod_folio_stat(folio, stat, folio_nr_pages(folio)); +} + void dec_folio_stat(struct folio *folio, enum page_stat stat) { - struct page_zone *zone = folio_to_zone(folio); - sched_disable_preempt(); - zone->pcpu[get_cpu_nr()].pagestats[stat] -= folio_nr_pages(folio); - sched_enable_preempt(); + mod_folio_stat(folio, stat, -folio_nr_pages(folio)); } void inc_page_stat(struct page *page, enum page_stat stat) @@ -1155,12 +1203,8 @@ void page_accumulate_stats(unsigned long pages[PAGE_STATS_MAX]) for_every_node([&pages](page_node &node) { node.for_every_zone([&pages](struct page_zone *zone) { - for (auto &pcpu : zone->pcpu) - { - for (unsigned int j = 0; j < PAGE_STATS_MAX; j++) - pages[j] += pcpu.pagestats[j]; - } - + for (unsigned int j = 0; j < PAGE_STATS_MAX; j++) + pages[j] += zone->pagestats[j]; return true; }); @@ -1194,7 +1238,7 @@ unsigned long page_reclaim_target(gfp_t gfp, unsigned int order) bool may = false; unsigned long free_target = pages_under_high_watermark(); if (free_target > 0) - return free_target; + return free_target > 32 ? free_target : 32; /* Everything is over the high watermark. Check if we indeed can accomplish this allocation. * This does a slight emulation of alloc_page logic paths. diff --git a/kernel/kernel/mm/reclaim.c b/kernel/kernel/mm/reclaim.c index 85d1e9e2c..ed9bf63b7 100644 --- a/kernel/kernel/mm/reclaim.c +++ b/kernel/kernel/mm/reclaim.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 - 2024 Pedro Falcato + * Copyright (c) 2023 - 2026 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * @@ -109,10 +109,7 @@ struct page_flag }; /* 10 = strlen(PAGE_FLAG_) */ -#define X(macro) \ - { \ - .val = macro, .name = #macro + 10 \ - } +#define X(macro) {.val = macro, .name = #macro + 10} #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -231,7 +228,6 @@ static enum lru_result shrink_page(struct reclaim_data *data, goto rotate; } - DCHECK_PAGE(page->owner, page); struct vm_object *obj; unsigned int vm_flags = 0; @@ -274,7 +270,8 @@ static enum lru_result shrink_page(struct reclaim_data *data, * will know to demote the page back to INACTIVE head, so we look at it again (hopefully * clean). */ - rmap_try_to_unmap(page); + if (page_mapcount(page) > 0) + rmap_try_to_unmap(page); if (page_mapcount(page) > 0) { @@ -290,6 +287,7 @@ static enum lru_result shrink_page(struct reclaim_data *data, obj = page_vmobj(page); if (page_flag_set(page, PAGE_FLAG_DIRTY)) { + DCHECK_PAGE(obj, page); enum pageout_result res = pageout(data, page, obj); switch (res) { @@ -324,10 +322,28 @@ static enum lru_result shrink_page(struct reclaim_data *data, } } + if (page_flag_set(page, PAGE_FLAG_WRITEBACK)) + { + /* No can do. */ + unlock_page(page); + return LRU_ACTIVATE; + } + + if (obj && page_test_buffer(page)) + { + WARN_ON(!obj->ops->release_folio); + if (!obj->ops->release_folio(page_folio(page), GFP_NOFS)) + { + /* Can't free, oops. */ + unlock_page(page); + return LRU_ROTATE; + } + } + /* This should be a stable reference. TODO: What if truncation? What if the inode goes away * after the unlock? */ // pr_info("removing page %p\n", page); - if (!vm_obj_remove_page(obj, page)) + if (!obj || !vm_obj_remove_page(obj, page)) { /* If we failed to remove the page, it's busy */ unlock_page(page); @@ -425,6 +441,8 @@ static void isolate_pages(struct page_lru *lru, enum lru_state list, struct list continue; } + WARN_ON(page_flag_set(page, PAGE_BUDDY)); + if (!page_test_lru(page)) { /* We *cannot* remove a page off the LRU if flag-wise it's not even there. That will @@ -433,9 +451,10 @@ static void isolate_pages(struct page_lru *lru, enum lru_state list, struct list continue; } - /* Not sure if we need a page_try_get here... */ - page_ref(page); - DCHECK(page->ref > 1); + /* It's possible to be on the LRU with 0 references, since removing from the LRU is part of + * the process of whacking a folio/page. */ + if (!page_try_get(page)) + continue; page_clear_lru(page); list_remove(&page->lru_node); dec_page_stat(page, NR_INACTIVE_FILE + page_to_state(page)); diff --git a/kernel/kernel/mm/rmap.c b/kernel/kernel/mm/rmap.c index fbf148630..eed78f576 100644 --- a/kernel/kernel/mm/rmap.c +++ b/kernel/kernel/mm/rmap.c @@ -224,7 +224,7 @@ static long rmap_get_page_refs_anon(struct page *page, unsigned int *vm_flags) struct refs_info info = {}; info.vm_flags = vm_flags; int st = - rmap_walk_anon(&(struct rmap_walk_info){.walk_one = rmap_get_page_refs_one, &info}, page); + rmap_walk_anon(&(struct rmap_walk_info) {.walk_one = rmap_get_page_refs_one, &info}, page); if (st < 0) return st; return info.references; @@ -234,6 +234,9 @@ long rmap_get_page_references(struct page *page, unsigned int *vm_flags) { if (page_flag_set(page, PAGE_FLAG_ANON)) return rmap_get_page_refs_anon(page, vm_flags); + /* Truncated? _has_ to have 0 references.*/ + if (!page->owner) + return 0; return vm_obj_get_page_references(page->owner, page, vm_flags); } diff --git a/kernel/kernel/mm/vm.c b/kernel/kernel/mm/vm.c index abf03314c..266d5da45 100644 --- a/kernel/kernel/mm/vm.c +++ b/kernel/kernel/mm/vm.c @@ -169,9 +169,8 @@ static void validate_mm_tree(struct mm_address_space *mm) print_tree: pr_err("mm: dumping vmas for mm %p...\n", mm); mas_set(&vmi.mas, 0); - mas_for_each(&vmi.mas, entry_, -1UL) + mas_for_each(&vmi.mas, vma, -1UL) { - struct vm_area_struct *vma = (struct vm_area_struct *) entry_; const char *name = "[anon]"; if (vma->vm_file) name = vma->vm_file->f_dentry->d_name; @@ -840,8 +839,16 @@ void *vm_mmap(void *addr, size_t length, int prot, int flags, struct file *file, { if (flags & MAP_FIXED) __vm_munmap(mm, addr, pages << PAGE_SHIFT); + else + { + vma = mas_find(&vmi.mas, ULONG_MAX); + if (vma && vma->vm_start < virt + aligned_len) + virt = 0; + vma = NULL; + } } - else + + if (!virt) { if (vm_alloc_address(&vmi, VM_ADDRESS_USER | extra_flags, aligned_len, VM_TYPE_REGULAR) < 0) goto enomem; @@ -1594,9 +1601,9 @@ int vm_handle_page_fault(struct fault_info *info) } if (sched_is_preemption_disabled()) - panic("Page fault while preemption was disabled\n"); + panic("Page fault at %pS while preemption was disabled\n", info->ip); if (irq_is_disabled()) - panic("Page fault while IRQs were disabled\n"); + panic("Page fault at %pS while IRQs were disabled\n", info->ip); /* Surrender immediately if there's no user address space */ if (!as) @@ -2679,7 +2686,7 @@ int get_phys_pages(void *_addr, unsigned int flags, struct page **pages, size_t { struct vm_area_struct *reg = vm_find_region(mm, (void *) addr); - if (!reg) + if (!reg || reg->vm_flags & VM_PFNMAP) { ret = GPP_ACCESS_FAULT; goto out; diff --git a/kernel/kernel/mm/vm_object.cpp b/kernel/kernel/mm/vm_object.cpp index 60fb3924c..374906494 100644 --- a/kernel/kernel/mm/vm_object.cpp +++ b/kernel/kernel/mm/vm_object.cpp @@ -227,6 +227,8 @@ static int vm_obj_get_pages(struct vm_object *obj, unsigned long start, unsigned if (!batchlen--) break; struct page *page = (struct page *) cursor.get(); + /* Invariant: While page_lock is held, the refcount is consistent. */ + DCHECK_PAGE(page->ref > 0, page); batch[batchidx++] = page; page_ref(page); cursor.advance(); @@ -286,6 +288,7 @@ static int vmo_purge_pages(unsigned long start, unsigned long end, for (int i = 0; i < found; i++) { lock_page(pagebatch[i]); + CHECK_PAGE(pagebatch[i]->owner == vmo, pagebatch[i]); page_wait_writeback(pagebatch[i]); } @@ -304,6 +307,12 @@ static int vmo_purge_pages(unsigned long start, unsigned long end, if (unlikely(page_test_clear_dirty(old_p))) filemap_unaccount_dirty(old_p, vmo); + if (page_test_buffer(old_p)) + { + /* This is not supposed to happen... */ + WARN_ON(!vmo->ops->release_folio(page_folio(old_p), GFP_KERNEL)); + } + unlock_page(old_p); /* Unref it twice, once for the vm_obj_get_pages, and another for the page cache * reference */ @@ -609,19 +618,25 @@ void vm_obj_clean_page(struct vm_object *obj, struct page *page) bool vm_obj_remove_page(struct vm_object *obj, struct page *page) { + bool success = false; DCHECK_PAGE(page_locked(page), page); DCHECK_PAGE(page_vmobj(page) == obj, page); DCHECK_PAGE(page->ref != 0, page); + DCHECK_PAGE(page_mapcount(page) == 0, page); unsigned int expected_refs = 2 + (page_mapcount(page) > 0); - if (!page_ref_freeze(page, expected_refs)) - return false; + spin_lock(&obj->page_lock); + if (!page_ref_freeze(page, expected_refs)) + goto out; obj->vm_pages.store(page_pgoff(page), 0); if (page_test_swap(page)) swap_unset_swapcache(swpval_to_swp_entry(page->priv)); page->owner = NULL; - return true; + success = true; +out: + spin_unlock(&obj->page_lock); + return success; } long vm_obj_get_page_references(struct vm_object *obj, struct page *page, unsigned int *vm_flags) diff --git a/kernel/kernel/net/Makefile b/kernel/kernel/net/Makefile index 6304edbcd..ac9f6b696 100644 --- a/kernel/kernel/net/Makefile +++ b/kernel/kernel/net/Makefile @@ -1,7 +1,7 @@ net-$(CONFIG_NET):= ethernet.o netif.o netkernel.o ipv4/icmp.o ipv4/ipv4.o ipv4/ipv4_netkernel.o \ ipv4/arp.o ipv6/ipv6.o udp.o packetbuf.o tcp.o loopback.o \ checksum.o neighbour.o inet.o ipv6/ndp.o ipv6/icmpv6.o ipv6/ipv6_netkernel.o \ - socket_table.o inet_cork.o unix.o tcp_input.o + socket_table.o inet_cork.o unix.o tcp_input.o netlink.o rtnetlink.o net-y:=$(net-y) network.o socket.o hostname.o diff --git a/kernel/kernel/net/ipv4/icmp.cpp b/kernel/kernel/net/ipv4/icmp.cpp index 62949d626..7c0d71ec0 100644 --- a/kernel/kernel/net/ipv4/icmp.cpp +++ b/kernel/kernel/net/ipv4/icmp.cpp @@ -421,7 +421,6 @@ ssize_t icmp_socket::recvmsg(kernel_msghdr *msg, int flags) if (ssize_t err = buf->copy_iter(*msg->msg_iter, flags & MSG_PEEK ? PBF_COPY_ITER_PEEK : 0); err != to_read) return err < 0 ? err : -EFAULT; - msg->msg_controllen = 0; if (!(flags & MSG_PEEK)) { diff --git a/kernel/kernel/net/ipv6/icmpv6.cpp b/kernel/kernel/net/ipv6/icmpv6.cpp index 23ef20b71..d440d16fe 100644 --- a/kernel/kernel/net/ipv6/icmpv6.cpp +++ b/kernel/kernel/net/ipv6/icmpv6.cpp @@ -425,8 +425,6 @@ ssize_t icmp6_socket::recvmsg(kernel_msghdr *msg, int flags) err != to_read) return err < 0 ? err : -EFAULT; - msg->msg_controllen = 0; - if (!(flags & MSG_PEEK)) { list_remove(&buf->list_node); diff --git a/kernel/kernel/net/loopback.cpp b/kernel/kernel/net/loopback.cpp index 5d04f6835..463dae757 100644 --- a/kernel/kernel/net/loopback.cpp +++ b/kernel/kernel/net/loopback.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2022 Pedro Falcato + * Copyright (c) 2020 - 2026 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * @@ -91,7 +91,7 @@ void loopback_init() n->poll_rx = loopback_pollrx; n->rx_end = [](netif *nif) {}; // rx_end does nothing for us, as we do not have interrupts. n->dll_ops = ð_ops; - + n->tx_queue_len = 1024; netif_register_if(n); if_inet6_addr addr; diff --git a/kernel/kernel/net/netif.cpp b/kernel/kernel/net/netif.cpp index 549e6541d..6acbc1c47 100644 --- a/kernel/kernel/net/netif.cpp +++ b/kernel/kernel/net/netif.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2022 Pedro Falcato + * Copyright (c) 2017 - 2025 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -236,11 +237,6 @@ int netif_send_packet(netif *netif, packetbuf *buf) return -ENODEV; } -void netif_get_ipv4_addr(struct sockaddr_in *s, struct netif *netif) -{ - memcpy(&s, &netif->local_ip, sizeof(struct sockaddr)); -} - netif *netif_from_name(const char *name) { scoped_lock g{netif_list_lock}; @@ -484,24 +480,186 @@ class netif_table_nk : public netkernel::netkernel_object } }; +static int netif_dump_if(struct packetbuf *pbf, struct netif *iff, pid_t pid, u32 seq) +{ + struct ifinfomsg *msg; + struct nlmsghdr *nlh; + static const struct rtnl_link_stats fake_stats = {0}; + static const u8 brdcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + int err; + + nlh = nl_put(pbf, pid, seq, RTM_NEWLINK, NLM_F_MULTI, sizeof(*msg)); + if (!nlh) + return -EMSGSIZE; + + msg = (struct ifinfomsg *) NLMSG_DATA(nlh); + msg->ifi_family = AF_UNSPEC; + msg->ifi_change = 0xffffffff; + msg->ifi_index = iff->if_id; + msg->ifi_type = iff->flags & NETIF_LOOPBACK ? ARPHRD_LOOPBACK : ARPHRD_ETHER; + msg->ifi_flags = 0; + + if (iff->flags & NETIF_LINKUP) + msg->ifi_flags |= IFF_UP; + if (iff->flags & NETIF_LOOPBACK) + msg->ifi_flags |= IFF_LOOPBACK; + + err = nla_put_str(pbf, IFLA_IFNAME, iff->name); + if (err) + return err; + + if (nla_put(pbf, IFLA_ADDRESS, 6, iff->mac_address) || + nla_put(pbf, IFLA_BROADCAST, 6, brdcast) || nla_put_u32(pbf, IFLA_MTU, iff->mtu) || + nla_put(pbf, IFLA_STATS, sizeof(fake_stats), &fake_stats) || + nla_put_u32(pbf, IFLA_TXQLEN, iff->tx_queue_len)) + return -EMSGSIZE; + nlh->nlmsg_len = pbf->tail - (unsigned char *) nlh; + return 0; +} + +static int netif_getlink(struct netlink_sock *nlsk, struct packetbuf *pbf, struct nlmsghdr *nlh, + struct rtgenmsg *rth) +{ + int err = 0; + + spin_lock(&netif_list_lock); + + for (auto &nif : netif_list) + { + err = netif_dump_if(pbf, nif, nlsk->pid, nlh->nlmsg_seq); + if (err) + break; + } + + spin_unlock(&netif_list_lock); + return err || nl_done(pbf, nlsk->pid, nlh->nlmsg_seq, 0); +} + +static int dump_v4_addr(struct packetbuf *pbf, struct netif *iff, pid_t pid, u32 seq) +{ + struct ifaddrmsg *msg; + struct nlmsghdr *nlh; + int err; + + nlh = nl_put(pbf, pid, seq, RTM_NEWADDR, NLM_F_MULTI, sizeof(*msg)); + if (!nlh) + return -EMSGSIZE; + + msg = (struct ifaddrmsg *) NLMSG_DATA(nlh); + msg->ifa_family = AF_INET; + msg->ifa_flags = IFA_F_PERMANENT; + msg->ifa_scope = 0; + msg->ifa_prefixlen = count_bits(iff->ipv4_submask); + msg->ifa_index = iff->if_id; + + err = nla_put_str(pbf, IFA_LABEL, iff->name); + if (err) + return err; + + if (nla_put_u32(pbf, IFA_ADDRESS, iff->local_ip.sin_addr.s_addr)) + return -EMSGSIZE; + nlh->nlmsg_len = pbf->tail - (unsigned char *) nlh; + return 0; +} + +static int dump_v6_addr(struct packetbuf *pbf, struct netif *iff, pid_t pid, u32 seq, + struct netif_inet6_addr *addr) +{ + struct ifaddrmsg *msg; + struct nlmsghdr *nlh; + int err; + + nlh = nl_put(pbf, pid, seq, RTM_NEWADDR, NLM_F_MULTI, sizeof(*msg)); + if (!nlh) + return -EMSGSIZE; + + msg = (struct ifaddrmsg *) NLMSG_DATA(nlh); + msg->ifa_family = AF_INET6; + msg->ifa_flags = IFA_F_PERMANENT; + msg->ifa_scope = 0; + + /* TODO: Seems hardcoded? */ + if (addr->flags & INET6_ADDR_LOCAL) + msg->ifa_scope = 2; + else if (addr->flags & INET6_ADDR_GLOBAL) + msg->ifa_scope = 0xe; + + msg->ifa_prefixlen = addr->prefix_len; + msg->ifa_index = iff->if_id; + + err = nla_put_str(pbf, IFA_LABEL, iff->name); + if (err) + return err; + + if (nla_put(pbf, IFA_ADDRESS, 16, &addr->address)) + return -EMSGSIZE; + nlh->nlmsg_len = pbf->tail - (unsigned char *) nlh; + return 0; +} + +static int netif_dump_ifaddr(struct packetbuf *pbf, struct netif *iff, pid_t pid, u32 seq, + int family) +{ + int err; + + if (family == AF_INET || family == AF_UNSPEC) + { + if (iff->local_ip.sin_addr.s_addr != 0) + { + err = dump_v4_addr(pbf, iff, pid, seq); + if (err) + return -EMSGSIZE; + } + } + + if (family == AF_INET6 || family == AF_UNSPEC) + { + struct netif_inet6_addr *addr; + scoped_rwslock g{iff->inet6_addr_list_lock}; + + list_for_each_entry (addr, &iff->inet6_addr_list, list_node) + { + err = dump_v6_addr(pbf, iff, pid, seq, addr); + if (err) + return -EMSGSIZE; + } + } + + return 0; +} + +static int netif_getaddr(struct netlink_sock *nlsk, struct packetbuf *pbf, struct nlmsghdr *nlh, + struct rtgenmsg *rth) +{ + int err = 0; + + spin_lock(&netif_list_lock); + + for (auto &nif : netif_list) + { + err = netif_dump_ifaddr(pbf, nif, nlsk->pid, nlh->nlmsg_seq, rth->rtgen_family); + if (err) + break; + } + + spin_unlock(&netif_list_lock); + return err || nl_done(pbf, nlsk->pid, nlh->nlmsg_seq, 0); +} + void netif_init_netkernel() { auto root = netkernel::open({"", 0}); - auto nif_member = make_shared("netif"); assert(nif_member != nullptr); - nif_member->set_flags(NETKERNEL_OBJECT_PATH_ELEMENT); - assert(root->add_child(nif_member) == true); - auto nt = make_shared(); assert(nt != nullptr); - auto generic_nt = cast(nt); - assert(nif_member->add_child(generic_nt)); + rtnl_register(RTM_GETLINK, netif_getlink); + rtnl_register(RTM_GETADDR, netif_getaddr); } INIT_LEVEL_CORE_KERNEL_ENTRY(netif_init_netkernel); diff --git a/kernel/kernel/net/netkernel.cpp b/kernel/kernel/net/netkernel.cpp index 9f631a8f0..2390f64cc 100644 --- a/kernel/kernel/net/netkernel.cpp +++ b/kernel/kernel/net/netkernel.cpp @@ -260,8 +260,6 @@ ssize_t netkernel_socket::recvmsg(struct kernel_msghdr *msg, int flags) if (was_read != iovlen) return was_read < 0 ? was_read : -EFAULT; - msg->msg_controllen = 0; - if (!(flags & MSG_PEEK)) { if (buf->length() == 0) diff --git a/kernel/kernel/net/netlink.c b/kernel/kernel/net/netlink.c new file mode 100644 index 000000000..377337273 --- /dev/null +++ b/kernel/kernel/net/netlink.c @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2025 - 2026 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License + * check LICENSE at the root directory for more information + * + * SPDX-License-Identifier: GPL-2.0-only + */ +#define DEFINE_CURRENT +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define NLHASH_SIZE 16 +static struct slab_cache *nlsock_cachep; +static struct list_head nlhash[NLHASH_SIZE]; +static DEFINE_SPINLOCK(nlhash_lock); + +static inline unsigned int nl_pid_hash(pid_t pid) +{ + return pid & (NLHASH_SIZE - 1); +} + +struct nlmsghdr *nl_put(struct packetbuf *pbf, pid_t pid, u32 seq, u16 type, u16 flags, u32 len) +{ + struct nlmsghdr *nlh; + unsigned int total; + + total = len + sizeof(*nlh); + nlh = pbf_put(pbf, NLMSG_ALIGN(total)); + if (!nlh) + return NULL; + + nlh->nlmsg_flags = flags; + nlh->nlmsg_pid = pid; + nlh->nlmsg_seq = seq; + nlh->nlmsg_type = type; + nlh->nlmsg_len = total; + + if (NLMSG_ALIGN(total) > total) + { + /* Had to pad, zero the tail */ + memset(NLMSG_DATA(nlh) + total, 0, NLMSG_ALIGN(total) - total); + } + + return nlh; +} + +int nl_done(struct packetbuf *pbf, pid_t pid, u32 seq, int err) +{ + struct nlmsghdr *hdr; + + hdr = nl_put(pbf, pid, seq, NLMSG_DONE, 0, sizeof(int)); + if (!hdr) + return -ENOMEM; + *(int *) NLMSG_DATA(hdr) = err; + return 0; +} + +static void netlink_destroy(struct socket *sock) +{ + struct netlink_sock *nlsk = (struct netlink_sock *) sock; + struct packetbuf *pbf, *next; + + if (sock->bound) + { + spin_lock(&nlhash_lock); + list_remove(&nlsk->bind_node); + spin_unlock(&nlhash_lock); + } + + list_for_each_entry_safe (pbf, next, &nlsk->buf_list, list_node) + { + list_remove(&pbf->list_node); + pbf_put_ref(pbf); + } +} + +static int netlink_getsockopt(struct socket *sock, int level, int optname, void *val, + socklen_t *len) +{ + if (level == SOL_SOCKET) + return getsockopt_socket_level(sock, optname, val, len); + return -ENOPROTOOPT; +} + +static int netlink_setsockopt(struct socket *sock, int level, int optname, const void *val, + socklen_t len) +{ + if (level == SOL_SOCKET) + return setsockopt_socket_level(sock, optname, val, len); + return -ENOPROTOOPT; +} + +static void nl_pbf_dtor(struct packetbuf *pbf) +{ + sock_discharge_pbf(pbf->sock, pbf); +} + +static void do_netlink_send(struct netlink_sock *nlsk, struct packetbuf *pbf) +{ + struct nl_extack extack = {}; + if (nlsk->sock.proto == NETLINK_ROUTE) + do_rtnetlink_send(nlsk, pbf, &extack); +} + +void netlink_ack(struct netlink_sock *nlsk, struct packetbuf *in_pbf, struct nlmsghdr *msg, int err, + struct nl_extack *extack) +{ + struct packetbuf *pbf; + bool wants_req = err != 0; + struct nlmsghdr *new_msg; + struct nlmsgerr *msgerr; + size_t size; + + pbf = pbf_alloc_sk(GFP_KERNEL, &nlsk->sock, PAGE_SIZE); + if (!pbf) + return; + + size = sizeof(*msg); + if (wants_req) + size = msg->nlmsg_len; + + new_msg = nl_put(pbf, nlsk->pid, msg->nlmsg_seq, NLMSG_ERROR, wants_req ? 0 : NLM_F_CAPPED, + size + sizeof(int)); + if (!new_msg) + goto err; + msgerr = NLMSG_DATA(new_msg); + msgerr->error = err; + memcpy(&msgerr->msg, msg, sizeof(*msg)); + if (wants_req) + memcpy(msg + 1, in_pbf->data, msg->nlmsg_len - sizeof(*msg)); + WARN_ON(extack->msg); + list_add_tail(&pbf->list_node, &nlsk->buf_list); + wait_queue_wake_all(&nlsk->wq); + return; +err: + pbf_free(pbf); +} + +static ssize_t netlink_sendmsg(struct socket *sock, const struct kernel_msghdr *msg, int flags) +{ + struct packetbuf *pbf; + ssize_t ret; + + ret = iovec_iter_bytes(msg->msg_iter); + pbf = pbf_alloc_sk(GFP_KERNEL, sock, ret); + if (!pbf) + return -ENOMEM; + + ret = copy_from_iter(msg->msg_iter, pbf_put(pbf, ret), ret); + if (ret < 0) + { + pbf_free(pbf); + return -EFAULT; + } + + if (!sock_charge_pbf(sock, pbf)) + { + /* Failed to charge write space, stop. */ + pbf_free(pbf); + return -ENOBUFS; + } + + pbf->dtor = nl_pbf_dtor; + do_netlink_send((struct netlink_sock *) sock, pbf); + pbf_put_ref(pbf); + return ret; +} + +static void nl_fill_name(struct kernel_msghdr *msg) +{ + struct sockaddr_nl *nladdr = (struct sockaddr_nl *) msg->msg_name; + + nladdr->nl_family = AF_NETLINK; + nladdr->nl_groups = 0; + nladdr->nl_pad = 0; + nladdr->nl_pid = 0; + if (msg->msg_namelen > sizeof(*nladdr)) + msg->msg_namelen = sizeof(*nladdr); +} + +static ssize_t netlink_recvmsg(struct socket *sock_, struct kernel_msghdr *msg, int flags) +{ + ssize_t ret = 0; + unsigned int pbuf_len; + struct iovec_iter *iter = msg->msg_iter; + struct packetbuf *pbf; + struct netlink_sock *sock = (struct netlink_sock *) sock_; + + hybrid_lock(&sock_->socket_lock); + + if (sock_->sock_err) + { + ret = sock_->sock_err; + sock_->sock_err = 0; + goto out_unlock; + } + + if (list_is_empty(&sock->buf_list) && (flags & MSG_DONTWAIT)) + { + ret = -EWOULDBLOCK; + goto out_unlock; + } + + ret = wait_for_event_socklocked_interruptible_2(&sock->wq, !list_is_empty(&sock->buf_list), + sock_); + if (ret) + goto out_unlock; + + pbf = list_first_entry(&sock->buf_list, struct packetbuf, list_node); + if (!pbf) + goto out_unlock; + + pbuf_len = pbf_length(pbf); + ret = copy_from_pbf(pbf, iter, flags & MSG_PEEK ? PBF_COPY_ITER_PEEK : 0); + if (ret < 0) + goto out_unlock; + + if (ret != pbuf_len) + { + if (flags & MSG_TRUNC) + ret = pbuf_len; + msg->msg_flags |= MSG_TRUNC; + } + + if (!(flags & MSG_PEEK)) + { + list_remove(&pbf->list_node); + pbf_put_ref(pbf); + } + + if (msg->msg_name) + nl_fill_name(msg); + +out_unlock: + __unlock_sock(&sock_->socket_lock, sock_); + return ret; +} + +static short netlink_poll(struct socket *sock, void *poll_file, short events) +{ + struct netlink_sock *nlsk = (struct netlink_sock *) sock; + short avail_events = 0; + + hybrid_lock(&sock->socket_lock); + + if (sock_may_write(sock)) + avail_events |= POLLOUT; + + if (events & POLLIN) + { + if (!list_is_empty(&nlsk->buf_list)) + avail_events |= POLLIN; + else + poll_wait_helper(poll_file, &nlsk->wq); + } + + __unlock_sock(&sock->socket_lock, sock); + return avail_events & events; +} + +static bool validate_nladdr(const struct sockaddr_nl *nladdr, socklen_t addrlen) +{ + if (addrlen != sizeof(*nladdr)) + return false; + if (nladdr->nl_family != AF_NETLINK) + return false; + if (nladdr->nl_pad != 0) + return false; + return true; +} + +static struct netlink_sock *nl_find_socket(pid_t pid) +{ + struct netlink_sock *sock; + + lockdep_assert_held(&nlhash_lock); + list_for_each_entry (sock, &nlhash[nl_pid_hash(pid)], bind_node) + { + if (sock->pid == pid) + return sock; + } + + return NULL; +} + +static pid_t nl_allocate_pid(void) +{ + pid_t pid = current->pid_; + int i; + + lockdep_assert_held(&nlhash_lock); + /* First, default to current->pid. If this is already used, then use a pseudo-random function + * over the negative range of ints to find a port. Avoid the negative errno space. */ + if (!nl_find_socket(pid)) + return pid; + + for (;;) + { + spin_unlock(&nlhash_lock); + do + { + pid = arc4random(); + } while (pid > -MAX_ERRNO); + spin_lock(&nlhash_lock); + /* Try a couple of pids in a row */ + for (i = 0; i < 10; i++) + { + if (!nl_find_socket(pid + i)) + return pid + i; + } + } +} + +static int netlink_bind(struct socket *sock, struct sockaddr *addr, socklen_t addrlen) +{ + struct sockaddr_nl *nladdr = (struct sockaddr_nl *) addr; + struct netlink_sock *nlsk; + int err; + + if (!validate_nladdr(nladdr, addrlen)) + return -EINVAL; + + spin_lock(&nlhash_lock); + + err = -EADDRINUSE; + if (nladdr->nl_pid != 0) + { + /* We have a specific pid that is desired. Check if it's not already bound. */ + if (nl_find_socket(nladdr->nl_pid)) + goto out; + } + else + nladdr->nl_pid = nl_allocate_pid(); + + nlsk = container_of(sock, struct netlink_sock, sock); + nlsk->pid = nladdr->nl_pid; + nlsk->groups = nladdr->nl_groups; + list_add_tail(&nlsk->bind_node, &nlhash[nl_pid_hash(nlsk->pid)]); + err = 0; + sock->bound = true; + /* TODO: handle groups */ +out: + spin_unlock(&nlhash_lock); + return err; +} + +static int netlink_getsockname(struct socket *sock, struct sockaddr *addr, socklen_t *addrlen) +{ + struct netlink_sock *nlsk = (struct netlink_sock *) sock; + struct sockaddr_nl *nladdr = (struct sockaddr_nl *) addr; + int err = -EINVAL; + + hybrid_lock(&sock->socket_lock); + if (!sock->bound) + goto out; + + *addrlen = sizeof(struct sockaddr_nl); + nladdr->nl_family = AF_NETLINK; + nladdr->nl_pad = 0; + nladdr->nl_pid = nlsk->pid; + nladdr->nl_groups = nlsk->groups; + err = 0; +out: + __unlock_sock(&sock->socket_lock, sock); + return err; +} + +static const struct socket_ops netlink_ops = { + .destroy = netlink_destroy, + .listen = sock_default_listen, + .accept = sock_default_accept, + .bind = netlink_bind, + .connect = sock_default_connect, + .sendmsg = netlink_sendmsg, + .recvmsg = netlink_recvmsg, + .getsockname = netlink_getsockname, + .getpeername = sock_default_getpeername, + .getsockopt = netlink_getsockopt, + .setsockopt = netlink_setsockopt, + .shutdown = sock_default_shutdown, + .close = sock_default_close, + .poll = netlink_poll, +}; + +struct socket *netlink_create_socket(int type) +{ + struct netlink_sock *nlsock; + + nlsock = kmem_cache_alloc(nlsock_cachep, GFP_KERNEL); + if (!nlsock) + return NULL; + + socket_init(&nlsock->sock); + nlsock->sock.type = type; + nlsock->sock.sock_ops = &netlink_ops; + init_wait_queue_head(&nlsock->wq); + INIT_LIST_HEAD(&nlsock->buf_list); + nlsock->pid = 0; + nlsock->groups = 0; + return &nlsock->sock; +} + +__init void netlink_init(void) +{ + nlsock_cachep = kmem_cache_create("netlink_sock", sizeof(struct netlink_sock), + _Alignof(struct netlink_sock), KMEM_CACHE_PANIC, NULL); + for (int i = 0; i < NLHASH_SIZE; i++) + INIT_LIST_HEAD(&nlhash[i]); +} diff --git a/kernel/kernel/net/packetbuf.cpp b/kernel/kernel/net/packetbuf.cpp index e440f9d52..5fa587bf3 100644 --- a/kernel/kernel/net/packetbuf.cpp +++ b/kernel/kernel/net/packetbuf.cpp @@ -59,7 +59,7 @@ bool pbf_allocate_space(struct packetbuf *pbf, size_t length) auto nr_pages = vm_size_to_pages(length); - page *pages = alloc_page_list(nr_pages, PAGE_ALLOC_NO_ZERO); + page *pages = alloc_page_list(nr_pages, GFP_ATOMIC | PAGE_ALLOC_NO_ZERO); if (!pages) return false; @@ -190,7 +190,7 @@ packetbuf *packetbuf_clone(packetbuf *original) static int allocate_page_vec(page_iov &v) { - page *p = alloc_page(0); + page *p = alloc_page(GFP_KERNEL); if (!p) return -ENOMEM; @@ -394,9 +394,6 @@ ssize_t packetbuf::copy_iter(iovec_iter &iter, unsigned int flags) vec->page_off += st; vec->length -= st; current_iov_off = 0; - DCHECK(vec->page_off <= PAGE_SIZE); - DCHECK(vec->length <= PAGE_SIZE); - DCHECK(vec->page_off + vec->length <= PAGE_SIZE); } } diff --git a/kernel/kernel/net/rtnetlink.c b/kernel/kernel/net/rtnetlink.c new file mode 100644 index 000000000..db274dd61 --- /dev/null +++ b/kernel/kernel/net/rtnetlink.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2025 Pedro Falcato + * This file is part of Onyx, and is released under the terms of the GPLv2 License + * check LICENSE at the root directory for more information + * + * SPDX-License-Identifier: GPL-2.0-only + */ +#include + +#include + +enum rtnl_kinds +{ + RTNL_KIND_NEW, + RTNL_KIND_DEL, + RTNL_KIND_GET, + RTNL_KIND_SET +}; + +#define RTNL_KIND_MASK 3 + +static inline enum rtnl_kinds rtnl_msgtype_kind(int msgtype) +{ + return msgtype & RTNL_KIND_MASK; +} + +static rtnl_handler_t handlers[RTM_NR_MSGTYPES]; + +void rtnl_register(int family, rtnl_handler_t handler) +{ + handlers[family - RTM_BASE] = handler; +} + +static int do_handle_rtnl(struct netlink_sock *nlsk, struct packetbuf *pbf, struct nlmsghdr *nlh) +{ + struct packetbuf *new_pbf; + rtnl_handler_t handler; + struct rtgenmsg *rth; + int type, err; + + type = nlh->nlmsg_type; + pr_warn("rtnl send %u flags %x\n", type, nlh->nlmsg_flags); + if (type > RTM_MAX) + return -EOPNOTSUPP; + + if (nlh->nlmsg_len - sizeof(*nlh) < sizeof(*rth)) + { + /* We must have at least one byte of payload, for rtgenmsg */ + return -EINVAL; + } + + rth = (struct rtgenmsg *) (nlh + 1); + + handler = handlers[nlh->nlmsg_type - RTM_BASE]; + if (!handler) + return -EOPNOTSUPP; + + new_pbf = pbf_alloc_sk(GFP_KERNEL, &nlsk->sock, PAGE_SIZE); + if (!new_pbf) + return -ENOMEM; + err = handler(nlsk, new_pbf, nlh, rth); + if (err < 0) + { + pbf_free(new_pbf); + pr_warn("err %d\n", err); + return err; + } + + pr_warn("pbf len %u\n", pbf_length(new_pbf)); + list_add_tail(&new_pbf->list_node, &nlsk->buf_list); + wait_queue_wake_all(&nlsk->wq); + pr_warn("done yay\n"); + return err; +} + +void do_rtnetlink_send(struct netlink_sock *nlsk, struct packetbuf *pbf, struct nl_extack *extack) +{ + struct nlmsghdr *msg; + int err; + + while ((msg = pbf_pull(pbf, sizeof(struct nlmsghdr))) != NULL) + { + if (msg->nlmsg_len < sizeof(struct nlmsghdr) || + msg->nlmsg_len - sizeof(struct nlmsghdr) > pbf_length(pbf)) + break; + + err = 0; + if (msg->nlmsg_type < NLMSG_MIN_TYPE || !(msg->nlmsg_flags & NLM_F_REQUEST)) + goto ack; + + err = do_handle_rtnl(nlsk, pbf, msg); + ack: + if (msg->nlmsg_flags & NLM_F_ACK || err) + netlink_ack(nlsk, pbf, msg, err, extack); + pbf_pull(pbf, msg->nlmsg_len - sizeof(*msg)); + } +} + +int nla_put(struct packetbuf *pbf, u16 type, u16 len, const void *data) +{ + struct rtattr *attr; + int size; + + size = sizeof(*attr) + len; + attr = pbf_put(pbf, NLA_ALIGN(size)); + if (!attr) + return -EMSGSIZE; + + attr->rta_len = size; + attr->rta_type = type; + if (NLA_ALIGN(size) > size) + memset(RTA_DATA(attr) + size, 0, NLA_ALIGN(size) - size); + memcpy(RTA_DATA(attr), data, len); + return 0; +} + +int nla_put_str(struct packetbuf *pbf, u16 type, const char *str) +{ + size_t len = strlen(str) + 1; + + return nla_put(pbf, type, len, str); +} + +int nla_put_u32(struct packetbuf *pbf, u16 type, u32 data) +{ + return nla_put(pbf, type, sizeof(u32), &data); +} diff --git a/kernel/kernel/net/socket.cpp b/kernel/kernel/net/socket.cpp index e05485f26..69ea38157 100644 --- a/kernel/kernel/net/socket.cpp +++ b/kernel/kernel/net/socket.cpp @@ -695,6 +695,7 @@ int check_af_support(int domain) case AF_UNIX: case AF_INET6: case AF_NETKERNEL: + case AF_NETLINK: return 0; default: return -1; @@ -716,6 +717,8 @@ int net_autodetect_protocol(int type, int domain) /* AF_NETKERNEL is an outlier since it's usable in both types */ if (domain == AF_NETKERNEL) return NETKERNEL_PROTO; + if (domain == AF_NETLINK) + return 0; switch (type & type_mask) { @@ -772,6 +775,8 @@ static void socket_sanity_check(socket *sock) DCHECK(sock_ops->poll); } +extern "C" struct socket *netlink_create_socket(int type); + socket *socket_create(int domain, int type, int protocol) { socket *socket = nullptr; @@ -791,6 +796,9 @@ socket *socket_create(int domain, int type, int protocol) case AF_NETKERNEL: socket = netkernel::create_socket(type); break; + case AF_NETLINK: + socket = netlink_create_socket(type); + break; default: return errno = EAFNOSUPPORT, nullptr; } @@ -1396,7 +1404,7 @@ ssize_t socket_recvmsg(socket *sock, msghdr *umsg, int flags) if (msg.msg_control) { - if (copy_to_user(msg.msg_control, g.msg_control, kmsg.msg_controllen) < 0) + if (copy_to_user(msg.msg_control, g.msg_control, msg.msg_controllen) < 0) return -EFAULT; } diff --git a/kernel/kernel/net/tcp.cpp b/kernel/kernel/net/tcp.cpp index 843d11908..c259900b7 100644 --- a/kernel/kernel/net/tcp.cpp +++ b/kernel/kernel/net/tcp.cpp @@ -505,6 +505,11 @@ void tcp_stop_retransmit(struct tcp_socket *sock) sock->retrans_pending = 0; } +static void tcp_stop_timers(struct tcp_socket *sock) +{ + timer_cancel_event(&sock->retransmit_timer); +} + static bool tcp_snd_wnd_check(struct tcp_socket *tp, struct packetbuf *pbf) { CHECK(pbf->tpi.seq == 0); @@ -643,8 +648,6 @@ int tcp_connect(struct socket *sock_, struct sockaddr *addr, socklen_t addrlen, int tcp_getsockname(struct socket *sock_, sockaddr *addr, socklen_t *len) { struct tcp_socket *sock = TCP_SOCK(sock_); - if (!sock->bound) - return -EINVAL; sock->copy_addr_to_sockaddr(sock->src_addr, addr, len); return 0; @@ -874,7 +877,7 @@ static int tcp_append_to_segment(struct tcp_socket *tp, struct packetbuf *pbf, tcp_add_pbf_frag(pbf, &pf); pbf->total_len += pf.len; len += pf.len; - write_space -= len; + write_space -= pf.len; pbf->tpi.seq_len += pf.len; } @@ -1016,8 +1019,9 @@ static struct packetbuf *tcp_get_segment(struct tcp_socket *sock, int flags) if (list_is_empty(&sock->read_queue) && sock->shutdown_state & SHUTDOWN_RD) return NULL; - st = wait_for_event_socklocked_interruptible_2(&sock->rx_wq, - !list_is_empty(&sock->read_queue), sock); + st = wait_for_event_socklocked_interruptible_2( + &sock->rx_wq, !list_is_empty(&sock->read_queue) || sock->shutdown_state & SHUTDOWN_RD, + sock); } return buf; @@ -1094,7 +1098,6 @@ static ssize_t tcp_recvmsg(struct socket *sock_, struct kernel_msghdr *msg, int tcp_update_rmem_window(sock, bytes_read); } - msg->msg_controllen = 0; return bytes_read; } @@ -1199,6 +1202,7 @@ void tcp_destroy_sock(struct tcp_socket *sock) struct packetbuf *pbf, *next; DCHECK(sock->dead); tcp_stop_retransmit(sock); + tcp_stop_timers(sock); list_for_each_entry_safe (pbf, next, &sock->on_wire_queue, list_node) { @@ -1221,11 +1225,7 @@ void tcp_destroy_sock(struct tcp_socket *sock) pbf_free(pbf); } - /* HACK. The TCP code wants to cancel the timer, if active. We *may* be executed by a timer - * right now. Which makes our life complicated, and deadlocks trying to kill it. Such is life. - * Make sure we do not try to cancel it. - */ - sock->retransmit_timer.timer = NULL; + WARN_ON(clockevent_active(&sock->retransmit_timer)); WARN_ON(sock->sk_send_queued > 0); if (WARN_ON(sock->sk_rmem > 0)) diff --git a/kernel/kernel/net/tcp_input.cpp b/kernel/kernel/net/tcp_input.cpp index 208995bc5..83b7859f0 100644 --- a/kernel/kernel/net/tcp_input.cpp +++ b/kernel/kernel/net/tcp_input.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2025 Pedro Falcato + * Copyright (c) 2020 - 2026 Pedro Falcato * This file is part of Onyx, and is released under the terms of the GPLv2 License * check LICENSE at the root directory for more information * @@ -758,6 +758,7 @@ static int tcp_drop_connreq(struct tcp_connreq *conn) { parent->socket_lock.unlock_bh(); spin_unlock(&conn->tc_lock); + parent->unref(); return -ESTALE; } else @@ -784,7 +785,6 @@ static void tcp_do_synack_retransmit(struct clockevent *ce) spin_lock(&conn->tc_lock); if (conn->retry == TCP_SYNACK_RETRIES) { - ce->flags &= ~CLOCKEVENT_FLAG_PULSE; tcp_drop_connreq(conn); rcu_read_unlock(); return; @@ -793,7 +793,7 @@ static void tcp_do_synack_retransmit(struct clockevent *ce) tcp_send_synack(conn); conn->retry++; ce->deadline = clocksource_get_time() + (TCP_SYNACK_RTO_NS << conn->retry); - ce->flags |= CLOCKEVENT_FLAG_PULSE; + timer_queue_clockevent(ce); spin_unlock(&conn->tc_lock); rcu_read_unlock(); } @@ -998,6 +998,7 @@ static int tcp_input_conn(struct tcp_connreq *conn, struct packetbuf *pbf) if (!parent->ref_not_zero()) { tcp_set_state(sock, TCP_STATE_CLOSED); + rcu_read_unlock(); sock->unref(); return 0; } diff --git a/kernel/kernel/net/udp.cpp b/kernel/kernel/net/udp.cpp index a1ae0c752..65939a485 100644 --- a/kernel/kernel/net/udp.cpp +++ b/kernel/kernel/net/udp.cpp @@ -600,8 +600,6 @@ ssize_t udp_socket::recvmsg(kernel_msghdr *msg, int flags) if (was_read < 0) return was_read; - msg->msg_controllen = 0; - if (!(flags & MSG_PEEK)) { list_remove(&buf->list_node); diff --git a/kernel/kernel/net/unix.cpp b/kernel/kernel/net/unix.cpp index 6e27011b6..6b51f49a1 100644 --- a/kernel/kernel/net/unix.cpp +++ b/kernel/kernel/net/unix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 - 2025 Pedro Falcato + * Copyright (c) 2022 - 2026 Pedro Falcato * This file is part of Onyx, and is released under the terms of the MIT License * check LICENSE at the root directory for more information * @@ -994,8 +994,6 @@ static int unix_scm_rights(struct unix_pbf_info *info, struct cmsghdr *cmsg) static int unix_pbf_init(packetbuf *pbf, const struct kernel_msghdr *msg) { struct unix_pbf_info *info = pbf_to_unix(pbf); - info->nfiles = 0; - info->rights = nullptr; if (!msg) return 0; @@ -1103,6 +1101,9 @@ ssize_t un_socket::queue_data(const struct kernel_msghdr *msg) if (!pbuf) return -ENOBUFS; + /* Pre-initialize the AF_UNIX pbf info (used for SCM_RIGHTS, etc). This makes sure buffer + * concatenation doesn't have to deal with weird state. */ + memset(pbf_to_unix(pbuf.get()), 0, sizeof(struct unix_pbf_info)); size_t length = cul::min(PACKETBUF_MAX_NR_PAGES << PAGE_SHIFT, iovec_iter_bytes(iter)); if (!pbuf->allocate_space(length)) return -ENOBUFS; @@ -1232,7 +1233,6 @@ static int unix_put_cmsg(struct unix_pbf_info *pbf, struct kernel_msghdr *msg) if (!unix_has_anciliary(pbf)) { - msg->msg_controllen = 0; return 0; } @@ -1355,8 +1355,6 @@ ssize_t un_socket::recvmsg_dgram(struct kernel_msghdr *msg, int flags) } } - msg->msg_controllen = 0; - return read; } diff --git a/kernel/kernel/sched/mutex.cpp b/kernel/kernel/sched/mutex.cpp index 2fc1c0413..1b9fa78e6 100644 --- a/kernel/kernel/sched/mutex.cpp +++ b/kernel/kernel/sched/mutex.cpp @@ -137,7 +137,6 @@ static void mutex_prepare_sleep(struct mutex *mutex, int state, struct mutex_wai { MUST_HOLD_LOCK(&mutex->llock); set_current_state(state); - DCHECK(!(waiter->flags & MUTEX_WAITER_QUEUED)); if (!(waiter->flags & MUTEX_WAITER_QUEUED)) { diff --git a/kernel/kernel/sched/scheduler.cpp b/kernel/kernel/sched/scheduler.cpp index d03307881..cec1a5ec0 100644 --- a/kernel/kernel/sched/scheduler.cpp +++ b/kernel/kernel/sched/scheduler.cpp @@ -328,6 +328,8 @@ thread_t *sched_find_next() return __sched_find_next(get_cpu_nr()); } +static void dump_thread(struct thread *thread); + thread_t *sched_find_runnable(void) { thread_t *thread = sched_find_next(); @@ -337,6 +339,11 @@ thread_t *sched_find_runnable(void) } atomic_and_relaxed(thread->flags, ~THREAD_IN_QUEUE); WARN_ON(thread->cpu != get_cpu_nr()); + if (get_current_thread() != thread) + { + if (WARN_ON(thread->on_cpu)) + dump_thread(thread); + } return thread; } @@ -432,15 +439,54 @@ void sched_decrease_quantum(clockevent *ev) ev->deadline = clocksource_get_time() + NS_PER_MS; } +static void dump_thread(struct thread *thread) +{ + struct registers *regs; + + pr_warn("thread id %u entry %pS status %u flags %u\n", thread->id, thread->entry, + thread->status, thread->flags); + if (thread->owner) + pr_warn("belonging to %s[%d], last switched %lu ms ago\n", thread->owner->comm, + thread->owner->pid_, + (clocksource_get_time() - thread->owner->last_switch_time) / NS_PER_MS); + regs = (struct registers *) thread->kernel_stack; + (void) regs; +#ifdef CONFIG_DEBUG_SCHEDULER + pr_warn("last seen at ip %pS, last switch-in %lu ms ago, last finish " + "switch %lu ms ago\n", + (void *) regs->rip, (clocksource_get_time() - thread->last_switch_in) / NS_PER_MS, + (clocksource_get_time() - thread->last_finish) / NS_PER_MS); + pr_warn("raw ts: in %lu swtch %lu finish %lu\n", thread->last_switch_in / NS_PER_US, + thread->owner ? thread->owner->last_switch_time / NS_PER_US : 0, + thread->last_finish / NS_PER_US); +#endif +} + void sched_load_thread(struct thread *prev, thread *thread, unsigned int cpu) { struct mm_address_space *mm = prev->active_mm ?: prev->aspace; + CHECK(prev->on_cpu); + if (prev != thread) + { + CHECK(thread != get_current_thread()); + if (WARN_ON(thread->on_cpu)) + { + pr_warn("thread %p has on_cpu %d for cpu %u (curr %u)\n", thread, thread->on_cpu, + thread->cpu, cpu); + dump_thread(thread); + } + } + write_per_cpu(current_thread, thread); spin_unlock_irqrestore(get_per_cpu_ptr_any(scheduler_lock, cpu), irq_save_and_disable()); errno = thread->errno_val; WRITE_ONCE(thread->on_cpu, 1); +#ifdef CONFIG_DEBUG_SCHEDULER + thread->last_switch_in = clocksource_get_time(); + prev->last_finish = clocksource_get_time(); +#endif native::arch_load_thread(thread, cpu); if (!(thread->flags & THREAD_KERNEL)) @@ -454,12 +500,6 @@ void sched_load_thread(struct thread *prev, thread *thread, unsigned int cpu) native::arch_load_process(thread->owner, thread, cpu); cpumask_unset_atomic(&mm->active_mask, cpu); } - - if (prev->active_mm) - { - mmdrop(mm); - prev->active_mm = NULL; - } } else { @@ -469,14 +509,15 @@ void sched_load_thread(struct thread *prev, thread *thread, unsigned int cpu) CHECK(thread->active_mm == NULL); thread->active_mm = mm; mmgrab(mm); - if (prev->active_mm) - { - mmdrop(mm); - prev->active_mm = NULL; - } } } + if (thread != prev && prev->active_mm) + { + mmdrop(mm); + prev->active_mm = NULL; + } + write_per_cpu(sched_quantum, SCHED_QUANTUM); cputime_restart_accounting(thread); @@ -523,8 +564,10 @@ NO_ASAN void sched_load_finish(thread *prev_thread, thread *next_thread) extern "C" void finish_switch(struct thread *prev) { - if (!prev) - return; + WARN_ON(prev == get_current_thread()); +#ifdef CONFIG_DEBUG_SCHEDULER + prev->last_finish = clocksource_get_time(); +#endif __atomic_store_n(&prev->on_cpu, 0, __ATOMIC_RELEASE); if (prev->status == THREAD_DEAD) thread_put(prev); @@ -597,6 +640,13 @@ extern "C" void *sched_schedule(void *last_stack) trace_sched_slice_begin(curr_thread->id, curr_thread->owner ? curr_thread->owner->pid_ : 0, curr_thread->owner ? curr_thread->owner->comm : NULL); } + else + { + write_per_cpu(sched_quantum, SCHED_QUANTUM); + sched_unlock(curr_thread, CPU_FLAGS_NO_IRQ); + irq_enable(); + return last_stack; + } sched_load_finish(source_thread, curr_thread); __builtin_unreachable(); @@ -733,7 +783,7 @@ void sched_init_cpu(unsigned int cpu) t->priority = SCHED_PRIO_VERY_LOW; t->cpu = cpu; - + t->on_cpu = 1; write_per_cpu_any(current_thread, t, cpu); write_per_cpu_any(sched_quantum, SCHED_QUANTUM, cpu); write_per_cpu_any(preemption_counter, 0, cpu); @@ -768,6 +818,7 @@ int sched_init(void) assert(t != NULL); t->priority = SCHED_PRIO_NORMAL; + t->on_cpu = 1; // sched_start_thread_for_cpu(t, get_cpu_nr()); write_per_cpu(sched_quantum, SCHED_QUANTUM); @@ -1086,7 +1137,10 @@ static bool __thread_wake_up(thread *thread, unsigned int cpu, unsigned int stat return true; } - new_cpu = sched_allocate_processor(); + if (__atomic_load_n(&thread->on_cpu, __ATOMIC_ACQUIRE) > 0) + new_cpu = cpu; + else + new_cpu = sched_allocate_processor(); WRITE_ONCE(thread->status, THREAD_RUNNABLE); if (new_cpu != cpu) { @@ -1380,6 +1434,13 @@ int sched_transition_to_user_thread(thread *thread) thread->flags &= ~THREAD_KERNEL; thread->set_aspace(thread->owner->get_aspace()); + vm_load_aspace(thread->owner->get_aspace(), get_cpu_nr()); + if (thread->active_mm) + { + mmdrop(thread->active_mm); + thread->active_mm = NULL; + } + return st; } diff --git a/kernel/kernel/timer.cpp b/kernel/kernel/timer.cpp index ea38a596b..1b69fea42 100644 --- a/kernel/kernel/timer.cpp +++ b/kernel/kernel/timer.cpp @@ -54,6 +54,7 @@ void timer_handle_events(struct timer *t) { bool atomic_context = irq_is_disabled(); bool has_raised_softirq = false; + bool is_pulse; struct list_head to_handle; INIT_LIST_HEAD(&to_handle); @@ -122,18 +123,29 @@ void timer_handle_events(struct timer *t) { struct clockevent *ev = container_of(l, struct clockevent, list_node); list_remove(&ev->list_node); + is_pulse = ev->flags & CLOCKEVENT_FLAG_PULSE; + cpu_flags = spin_lock_irqsave(&t->event_list_lock); + /* Pulse clockevents are guaranteed to stay alive after the callback. Others aren't. */ + if (!is_pulse) + { + /* Cancel it, cancel it now! */ + WRITE_ONCE(ev->timer, NULL); + atomic_and_relaxed(ev->flags, ~(CLOCKEVENT_FLAG_PENDING | CLOCKEVENT_FLAG_POISON)); + } + + t->executing = ev; + spin_unlock_irqrestore(&t->event_list_lock, cpu_flags); ev->callback(ev); - if (ev->flags & CLOCKEVENT_FLAG_PULSE) + cpu_flags = spin_lock_irqsave(&t->event_list_lock); + t->executing = NULL; + spin_unlock_irqrestore(&t->event_list_lock, cpu_flags); + + if (is_pulse && ev->flags & CLOCKEVENT_FLAG_PULSE) { ev->flags &= ~CLOCKEVENT_FLAG_POISON; timer_queue_clockevent(ev); } - else - { - WRITE_ONCE(ev->timer, NULL); - atomic_and_relaxed(ev->flags, ~(CLOCKEVENT_FLAG_PENDING | CLOCKEVENT_FLAG_POISON)); - } } } } diff --git a/kernel/kernel/tty/pty.c b/kernel/kernel/tty/pty.c index 76548790f..ebd3542da 100644 --- a/kernel/kernel/tty/pty.c +++ b/kernel/kernel/tty/pty.c @@ -141,43 +141,30 @@ static unsigned int pty_ioctl(int request, void *argp, struct tty *tty) return -ENOTTY; } -/* yuck yuck yuck yuck yuck */ -#define DEFINE_NEW_HACKY_FILE(filp) \ - struct inode _ino; \ - struct file _f; \ - _ino.i_helper = (filp)->private_data; \ - _f.f_ino = &_ino; \ - _f.private_data = (filp)->private_data; - static size_t ptydevfs_write(size_t offset, size_t len, void *ubuffer, struct file *f) { - DEFINE_NEW_HACKY_FILE(f); - return ttydevfs_write(offset, len, ubuffer, &_f); + return ttydevfs_write(offset, len, ubuffer, f); } static size_t ptydevfs_read(size_t offset, size_t count, void *buffer, struct file *this_) { - DEFINE_NEW_HACKY_FILE(this_); - return ttydevfs_read(offset, count, buffer, &_f); + return ttydevfs_read(offset, count, buffer, this_); } static ssize_t ptydevfs_read_iter(struct file *filp, size_t offset, struct iovec_iter *iter, unsigned int flags) { - DEFINE_NEW_HACKY_FILE(filp); - return ttydevfs_read_iter(&_f, offset, iter, flags); + return ttydevfs_read_iter(filp, offset, iter, flags); } static unsigned int pty_ioctl_redir(int request, void *argp, struct file *dev) { - DEFINE_NEW_HACKY_FILE(dev); - return tty_ioctl(request, argp, &_f); + return tty_ioctl(request, argp, dev); } static short pty_poll(void *poll_file, short events, struct file *f) { - DEFINE_NEW_HACKY_FILE(f); - return tty_poll(poll_file, events, &_f); + return tty_poll(poll_file, events, f); } /* TODO: It's hacky that we need to define all these file ops. And that we need to redirect the pty diff --git a/kernel/kernel/tty/vt/vterm.cpp b/kernel/kernel/tty/vt/vterm.cpp index f1157d481..a482a6f29 100644 --- a/kernel/kernel/tty/vt/vterm.cpp +++ b/kernel/kernel/tty/vt/vterm.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1805,7 +1806,7 @@ int vterm_receive_input(char *c) struct key_action { - keycode_t key; + unsigned int key; const char *action; const char *shift_action; const char *ctrl_action; @@ -1814,154 +1815,154 @@ struct key_action }; struct key_action key_actions[] = { - {KEYMAP_KEY_A, "a", "A", "\01"}, - {KEYMAP_KEY_B, "b", "B", "\02"}, - {KEYMAP_KEY_C, "c", "C", "\03"}, - {KEYMAP_KEY_D, "d", "D", "\04"}, - {KEYMAP_KEY_E, "e", "E", "\05"}, - {KEYMAP_KEY_F, "f", "F", "\06"}, - {KEYMAP_KEY_G, "g", "G", "\07"}, - {KEYMAP_KEY_H, "h", "H", "\010"}, - {KEYMAP_KEY_I, "i", "I", "\011"}, - {KEYMAP_KEY_J, "j", "J", "\012"}, - {KEYMAP_KEY_K, "k", "K", "\013"}, - {KEYMAP_KEY_L, "l", "L", "\014"}, - {KEYMAP_KEY_M, "m", "M", "\015"}, - {KEYMAP_KEY_N, "n", "N", "\016"}, - {KEYMAP_KEY_O, "o", "O", "\017"}, - {KEYMAP_KEY_P, "p", "P", "\020"}, - {KEYMAP_KEY_Q, "q", "Q", "\021"}, - {KEYMAP_KEY_R, "r", "R", "\022"}, - {KEYMAP_KEY_S, "s", "S", "\023"}, - {KEYMAP_KEY_T, "t", "T", "\024"}, - {KEYMAP_KEY_U, "u", "U", "\025"}, - {KEYMAP_KEY_V, "v", "V", "\026"}, - {KEYMAP_KEY_W, "w", "W", "\027"}, - {KEYMAP_KEY_X, "x", "X", "\030"}, - {KEYMAP_KEY_Y, "y", "Y", "\031"}, - {KEYMAP_KEY_Z, "z", "Z", "\032"}, - {KEYMAP_KEY_0, "0", ")"}, - {KEYMAP_KEY_1, "1", "!"}, - {KEYMAP_KEY_2, "2", "@"}, - {KEYMAP_KEY_3, "3", "#"}, - {KEYMAP_KEY_4, "4", "$"}, - {KEYMAP_KEY_5, "5", "%"}, - {KEYMAP_KEY_6, "6", "^"}, - {KEYMAP_KEY_7, "7", "&"}, - {KEYMAP_KEY_8, "8", "*"}, - {KEYMAP_KEY_9, "9", "("}, - {KEYMAP_KEY_COMMA, ",", "<"}, - {KEYMAP_KEY_DOT, ".", ">"}, - {KEYMAP_KEY_KEYPAD_0, "0"}, - {KEYMAP_KEY_KEYPAD_1, "1"}, - {KEYMAP_KEY_KEYPAD_2, "2"}, - {KEYMAP_KEY_KEYPAD_3, "3"}, - {KEYMAP_KEY_KEYPAD_4, "4"}, - {KEYMAP_KEY_KEYPAD_5, "5"}, - {KEYMAP_KEY_KEYPAD_6, "6"}, - {KEYMAP_KEY_KEYPAD_7, "7"}, - {KEYMAP_KEY_KEYPAD_8, "8"}, - {KEYMAP_KEY_KEYPAD_9, "9"}, - {KEYMAP_KEY_MINUS, "-", "_"}, - {KEYMAP_KEY_EQUALS, "=", "+"}, - {KEYMAP_KEY_LEFTBRACE, "[", "{"}, - {KEYMAP_KEY_RIGHTBRACE, "]", "}"}, - {KEYMAP_KEY_ENTER, "\r"}, - {KEYMAP_KEY_SEMICOLON, ";", ":"}, - {KEYMAP_KEY_GRAVE, "`", "~"}, - {KEYMAP_KEY_TAB, "\t"}, - {KEYMAP_KEY_APOSTROPHE, "'", "\""}, - {KEYMAP_KEY_SLASH, "/", "?"}, - {KEYMAP_KEY_BACKSLASH, "|"}, - {KEYMAP_KEY_BACKSPACE, "\x7f"}, - {KEYMAP_KEY_KEYPAD_DOT, "."}, - {KEYMAP_KEY_KEYPAD_SLASH, "/"}, - {KEYMAP_KEY_KEYPAD_ASTERISK, "*"}, - {KEYMAP_KEY_KEYPAD_MINUS, "-"}, - {KEYMAP_KEY_KEYPAD_PLUS, "+"}, - {KEYMAP_KEY_KEYPAD_ENTER, "\n"}, - {KEYMAP_KEY_SPACE, " ", " "}, - {KEYMAP_KEY_ARROW_LEFT, "\033[D", NULL, "\033[1;5D"}, - {KEYMAP_KEY_ARROW_UP, "\033[A", NULL, "\033[1;5A"}, - {KEYMAP_KEY_ARROW_DOWN, "\033[B", NULL, "\033[1;5B"}, - {KEYMAP_KEY_ARROW_RIGHT, "\033[C", NULL, "\033[1;5C"}, - {KEYMAP_KEY_ESC, "\033"}, + {KEY_A, "a", "A", "\01"}, + {KEY_B, "b", "B", "\02"}, + {KEY_C, "c", "C", "\03"}, + {KEY_D, "d", "D", "\04"}, + {KEY_E, "e", "E", "\05"}, + {KEY_F, "f", "F", "\06"}, + {KEY_G, "g", "G", "\07"}, + {KEY_H, "h", "H", "\010"}, + {KEY_I, "i", "I", "\011"}, + {KEY_J, "j", "J", "\012"}, + {KEY_K, "k", "K", "\013"}, + {KEY_L, "l", "L", "\014"}, + {KEY_M, "m", "M", "\015"}, + {KEY_N, "n", "N", "\016"}, + {KEY_O, "o", "O", "\017"}, + {KEY_P, "p", "P", "\020"}, + {KEY_Q, "q", "Q", "\021"}, + {KEY_R, "r", "R", "\022"}, + {KEY_S, "s", "S", "\023"}, + {KEY_T, "t", "T", "\024"}, + {KEY_U, "u", "U", "\025"}, + {KEY_V, "v", "V", "\026"}, + {KEY_W, "w", "W", "\027"}, + {KEY_X, "x", "X", "\030"}, + {KEY_Y, "y", "Y", "\031"}, + {KEY_Z, "z", "Z", "\032"}, + {KEY_0, "0", ")"}, + {KEY_1, "1", "!"}, + {KEY_2, "2", "@"}, + {KEY_3, "3", "#"}, + {KEY_4, "4", "$"}, + {KEY_5, "5", "%"}, + {KEY_6, "6", "^"}, + {KEY_7, "7", "&"}, + {KEY_8, "8", "*"}, + {KEY_9, "9", "("}, + {KEY_COMMA, ",", "<"}, + {KEY_DOT, ".", ">"}, + {KEY_KP0, "0"}, + {KEY_KP1, "1"}, + {KEY_KP2, "2"}, + {KEY_KP3, "3"}, + {KEY_KP4, "4"}, + {KEY_KP5, "5"}, + {KEY_KP6, "6"}, + {KEY_KP7, "7"}, + {KEY_KP8, "8"}, + {KEY_KP9, "9"}, + {KEY_MINUS, "-", "_"}, + {KEY_EQUAL, "=", "+"}, + {KEY_LEFTBRACE, "[", "{"}, + {KEY_RIGHTBRACE, "]", "}"}, + {KEY_ENTER, "\r"}, + {KEY_SEMICOLON, ";", ":"}, + {KEY_GRAVE, "`", "~"}, + {KEY_TAB, "\t"}, + {KEY_APOSTROPHE, "'", "\""}, + {KEY_SLASH, "/", "?"}, + {KEY_BACKSLASH, "|"}, + {KEY_BACKSPACE, "\x7f"}, + {KEY_KPDOT, "."}, + {KEY_KPSLASH, "/"}, + {KEY_KPASTERISK, "*"}, + {KEY_KPMINUS, "-"}, + {KEY_KPPLUS, "+"}, + {KEY_KPENTER, "\n"}, + {KEY_SPACE, " ", " "}, + {KEY_LEFT, "\033[D", NULL, "\033[1;5D"}, + {KEY_UP, "\033[A", NULL, "\033[1;5A"}, + {KEY_DOWN, "\033[B", NULL, "\033[1;5B"}, + {KEY_RIGHT, "\033[C", NULL, "\033[1;5C"}, + {KEY_ESC, "\033"}, }; struct key_action pt_pt_key_actions[] = { - {KEYMAP_KEY_A, "a", "A", "\01"}, - {KEYMAP_KEY_B, "b", "B", "\02"}, - {KEYMAP_KEY_C, "c", "C", "\03"}, - {KEYMAP_KEY_D, "d", "D", "\04"}, - {KEYMAP_KEY_E, "e", "E", "\05"}, - {KEYMAP_KEY_F, "f", "F", "\06"}, - {KEYMAP_KEY_G, "g", "G", "\07"}, - {KEYMAP_KEY_H, "h", "H", "\010"}, - {KEYMAP_KEY_I, "i", "I", "\011"}, - {KEYMAP_KEY_J, "j", "J", "\012"}, - {KEYMAP_KEY_K, "k", "K", "\013"}, - {KEYMAP_KEY_L, "l", "L", "\014"}, - {KEYMAP_KEY_M, "m", "M", "\015"}, - {KEYMAP_KEY_N, "n", "N", "\016"}, - {KEYMAP_KEY_O, "o", "O", "\017"}, - {KEYMAP_KEY_P, "p", "P", "\020"}, - {KEYMAP_KEY_Q, "q", "Q", "\021"}, - {KEYMAP_KEY_R, "r", "R", "\022"}, - {KEYMAP_KEY_S, "s", "S", "\023"}, - {KEYMAP_KEY_T, "t", "T", "\024"}, - {KEYMAP_KEY_U, "u", "U", "\025"}, - {KEYMAP_KEY_V, "v", "V", "\026"}, - {KEYMAP_KEY_W, "w", "W", "\027"}, - {KEYMAP_KEY_X, "x", "X", "\030"}, - {KEYMAP_KEY_Y, "y", "Y", "\031"}, - {KEYMAP_KEY_Z, "z", "Z", "\032"}, - {KEYMAP_KEY_0, "0", "=", NULL, "}"}, - {KEYMAP_KEY_1, "1", "!"}, - {KEYMAP_KEY_2, "2", "\"", NULL, "@"}, - {KEYMAP_KEY_3, "3", "#", NULL, "£"}, - {KEYMAP_KEY_4, "4", "$", NULL, "§"}, - {KEYMAP_KEY_5, "5", "%", NULL, "€"}, - {KEYMAP_KEY_6, "6", "&"}, - {KEYMAP_KEY_7, "7", "/", NULL, "{"}, - {KEYMAP_KEY_8, "8", "(", NULL, "["}, - {KEYMAP_KEY_9, "9", ")", NULL, "]"}, - {KEYMAP_KEY_COMMA, ",", ";"}, - {KEYMAP_KEY_DOT, ".", ":"}, - {KEYMAP_KEY_KEYPAD_0, "0"}, - {KEYMAP_KEY_KEYPAD_1, "1"}, - {KEYMAP_KEY_KEYPAD_2, "2"}, - {KEYMAP_KEY_KEYPAD_3, "3"}, - {KEYMAP_KEY_KEYPAD_4, "4"}, - {KEYMAP_KEY_KEYPAD_5, "5"}, - {KEYMAP_KEY_KEYPAD_6, "6"}, - {KEYMAP_KEY_KEYPAD_7, "7"}, - {KEYMAP_KEY_KEYPAD_8, "8"}, - {KEYMAP_KEY_KEYPAD_9, "9"}, - {KEYMAP_KEY_MINUS, "'", "?"}, - {KEYMAP_KEY_EQUALS, "«", "»"}, - {KEYMAP_KEY_LEFTBRACE, "+", "*"}, - {KEYMAP_KEY_RIGHTBRACE, "´", "`"}, - {KEYMAP_KEY_ENTER, "\r"}, - {KEYMAP_KEY_SEMICOLON, "ç", "Ç"}, - {KEYMAP_KEY_GRAVE, "\\", "|"}, - {KEYMAP_KEY_TAB, "\t"}, - {KEYMAP_KEY_APOSTROPHE, "º", "ª"}, - {KEYMAP_KEY_SLASH, "-", "_"}, - {KEYMAP_KEY_BACKSLASH, "~", "^"}, - {KEYMAP_KEY_BACKSPACE, "\x7f"}, - {KEYMAP_KEY_KEYPAD_DOT, "."}, - {KEYMAP_KEY_KEYPAD_SLASH, "/"}, - {KEYMAP_KEY_KEYPAD_ASTERISK, "*"}, - {KEYMAP_KEY_KEYPAD_MINUS, "-"}, - {KEYMAP_KEY_KEYPAD_PLUS, "+"}, - {KEYMAP_KEY_KEYPAD_ENTER, "\n"}, - {KEYMAP_KEY_SPACE, " ", " "}, - {KEYMAP_102ND, "<", ">"}, - {KEYMAP_KEY_ARROW_LEFT, "\033[D", NULL, "\033[1;5D"}, - {KEYMAP_KEY_ARROW_UP, "\033[A", NULL, "\033[1;5A"}, - {KEYMAP_KEY_ARROW_DOWN, "\033[B", NULL, "\033[1;5B"}, - {KEYMAP_KEY_ARROW_RIGHT, "\033[C", NULL, "\033[1;5C"}, - {KEYMAP_KEY_ESC, "\033"}, + {KEY_A, "a", "A", "\01"}, + {KEY_B, "b", "B", "\02"}, + {KEY_C, "c", "C", "\03"}, + {KEY_D, "d", "D", "\04"}, + {KEY_E, "e", "E", "\05"}, + {KEY_F, "f", "F", "\06"}, + {KEY_G, "g", "G", "\07"}, + {KEY_H, "h", "H", "\010"}, + {KEY_I, "i", "I", "\011"}, + {KEY_J, "j", "J", "\012"}, + {KEY_K, "k", "K", "\013"}, + {KEY_L, "l", "L", "\014"}, + {KEY_M, "m", "M", "\015"}, + {KEY_N, "n", "N", "\016"}, + {KEY_O, "o", "O", "\017"}, + {KEY_P, "p", "P", "\020"}, + {KEY_Q, "q", "Q", "\021"}, + {KEY_R, "r", "R", "\022"}, + {KEY_S, "s", "S", "\023"}, + {KEY_T, "t", "T", "\024"}, + {KEY_U, "u", "U", "\025"}, + {KEY_V, "v", "V", "\026"}, + {KEY_W, "w", "W", "\027"}, + {KEY_X, "x", "X", "\030"}, + {KEY_Y, "y", "Y", "\031"}, + {KEY_Z, "z", "Z", "\032"}, + {KEY_0, "0", "=", NULL, "}"}, + {KEY_1, "1", "!"}, + {KEY_2, "2", "\"", NULL, "@"}, + {KEY_3, "3", "#", NULL, "£"}, + {KEY_4, "4", "$", NULL, "§"}, + {KEY_5, "5", "%", NULL, "€"}, + {KEY_6, "6", "&"}, + {KEY_7, "7", "/", NULL, "{"}, + {KEY_8, "8", "(", NULL, "["}, + {KEY_9, "9", ")", NULL, "]"}, + {KEY_COMMA, ",", ";"}, + {KEY_DOT, ".", ":"}, + {KEY_KP0, "0"}, + {KEY_KP1, "1"}, + {KEY_KP2, "2"}, + {KEY_KP3, "3"}, + {KEY_KP4, "4"}, + {KEY_KP5, "5"}, + {KEY_KP6, "6"}, + {KEY_KP7, "7"}, + {KEY_KP8, "8"}, + {KEY_KP9, "9"}, + {KEY_MINUS, "'", "?"}, + {KEY_EQUAL, "«", "»"}, + {KEY_LEFTBRACE, "+", "*"}, + {KEY_RIGHTBRACE, "´", "`"}, + {KEY_ENTER, "\r"}, + {KEY_SEMICOLON, "ç", "Ç"}, + {KEY_GRAVE, "\\", "|"}, + {KEY_TAB, "\t"}, + {KEY_APOSTROPHE, "º", "ª"}, + {KEY_SLASH, "-", "_"}, + {KEY_BACKSLASH, "~", "^"}, + {KEY_BACKSPACE, "\x7f"}, + {KEY_KPDOT, "."}, + {KEY_KPSLASH, "/"}, + {KEY_KPASTERISK, "*"}, + {KEY_KPMINUS, "-"}, + {KEY_KPPLUS, "+"}, + {KEY_KPENTER, "\n"}, + {KEY_SPACE, " ", " "}, + {KEY_102ND, "<", ">"}, + {KEY_LEFT, "\033[D", NULL, "\033[1;5D"}, + {KEY_UP, "\033[A", NULL, "\033[1;5A"}, + {KEY_DOWN, "\033[B", NULL, "\033[1;5B"}, + {KEY_RIGHT, "\033[C", NULL, "\033[1;5C"}, + {KEY_ESC, "\033"}, }; const size_t nr_actions = sizeof(key_actions) / sizeof(key_actions[0]); @@ -1979,7 +1980,7 @@ static bool is_numpad_code(keycode_t code) switch (code) { /* Ew... Depends on the KEYPAD's enum layout */ - case KEYMAP_KEY_KEYPAD_7 ... KEYMAP_KEY_KEYPAD_PLUS: + case KEY_KP7 ... KEY_KPDOT: return true; default: return false; @@ -1990,23 +1991,23 @@ static const char *numpad_replacement(keycode_t code, const char *str) { switch (code) { - case KEYMAP_KEY_KEYPAD_7: + case KEY_KP7: return "\033[H"; - case KEYMAP_KEY_KEYPAD_8: + case KEY_KP8: return "\033[A"; - case KEYMAP_KEY_KEYPAD_9: + case KEY_KP9: return "\033[5~"; - case KEYMAP_KEY_KEYPAD_4: + case KEY_KP4: return "\033[D"; - case KEYMAP_KEY_KEYPAD_5: + case KEY_KP5: return "\033[E"; - case KEYMAP_KEY_KEYPAD_6: + case KEY_KP6: return "\033[C"; - case KEYMAP_KEY_KEYPAD_1: + case KEY_KP1: return "\033[F"; - case KEYMAP_KEY_KEYPAD_2: + case KEY_KP2: return "\033[B"; - case KEYMAP_KEY_KEYPAD_3: + case KEY_KP3: return "\033[6~"; default: return str; @@ -2020,11 +2021,11 @@ int vterm_handle_key(struct vterm *vt, struct input_device *dev, struct input_ev return 0; #ifdef CONFIG_SCHED_DUMP_THREADS_MAGIC /* Don't have this enabled by default */ - if (ev->code == KEYMAP_KEY_KEYPAD_NUMLCK) + if (ev->code == KEY_NUMLOCK) sched_dump_threads(); #endif - if (ev->code == KEYMAP_KEY_KEYPAD_NUMLCK) + if (ev->code == KEY_NUMLOCK) vt->numlck = !vt->numlck; struct key_action *acts = pt_pt_key_actions; diff --git a/kernel/lib/libk/stdio/sprintf.c b/kernel/lib/libk/stdio/sprintf.c index 92f8d1f4b..ba9c8b796 100644 --- a/kernel/lib/libk/stdio/sprintf.c +++ b/kernel/lib/libk/stdio/sprintf.c @@ -702,8 +702,8 @@ static int __vfprintf(struct stream *stream, const char *s, va_list va) ret += st; continue; print_str: - st = printf_do_string(stream, va_arg(va, const char *), spec.fwidth, spec.precision, - spec.flags); + st = printf_do_string(stream, va_arg(va, const char *) ?: "(null)", spec.fwidth, + spec.precision, spec.flags); if (st < 0) { ret = st;