diff --git a/kernel/command.c b/kernel/command.c index c2e435d..37d5dbc 100644 --- a/kernel/command.c +++ b/kernel/command.c @@ -85,6 +85,8 @@ void print(const char *arg) { print_bootinfo(); } else if (strcmp(arg, "pci") == 0) { pci_print_info(); + } else if (strcmp(arg, "pci_caps") == 0) { + pci_dump_caps(); } else if (strcmp(arg, "ide") == 0) { ide_print_devices(); } else { diff --git a/kernel/cpu/syscall_handler.c b/kernel/cpu/syscall_handler.c index 3fc0bbb..03d6182 100644 --- a/kernel/cpu/syscall_handler.c +++ b/kernel/cpu/syscall_handler.c @@ -12,10 +12,17 @@ void syscall_handle(isr_registers_t *registers) { task_start_first(); break; case SYSCALL_YIELD_JOB: + task_ensure_enabled(); task_switch_next(); break; case SYSCALL_YIELD_IRQ: + task_ensure_enabled(); task_wait_irq(registers->ebx); + break; + case SYSCALL_SUSPEND: + task_ensure_enabled(); + task_suspend(); + break; default: break; } diff --git a/kernel/drivers/ide.c b/kernel/drivers/ide.c index 5e9059a..aca63cd 100644 --- a/kernel/drivers/ide.c +++ b/kernel/drivers/ide.c @@ -14,6 +14,7 @@ #include #include #include +#include #define ATA_SR_BSY 0x80 // Busy #define ATA_SR_DRDY 0x40 // Drive ready @@ -135,6 +136,8 @@ typedef struct { uint8_t print_error: 1; } ide_block_device_info; +mutex_t *ide_lock = NULL; + uint8_t ide_read(uint8_t channel, uint8_t reg); void ide_write(uint8_t channel, uint8_t reg, uint8_t data); @@ -437,6 +440,12 @@ uint8_t ide_pci_initialize(pci_device *device) { return PCI_INIT_FAIL; } + if (ide_lock != NULL) { + k_panics("IDE already initialized\n"); + } + ide_lock = mutex_create(); + mutex_acquire(ide_lock); + // disable IRQ ide_write(ATA_PRIMARY, ATA_REG_CONTROL, 2); ide_write(ATA_SECONDARY, ATA_REG_CONTROL, 2); @@ -518,6 +527,7 @@ uint8_t ide_pci_initialize(pci_device *device) { count++; } } + mutex_release(ide_lock); ide_register_block_devices(); return PCI_INIT_OK; @@ -673,5 +683,8 @@ uint8_t ide_access(uint8_t direction, uint8_t drive, uint32_t lba, uint8_t numse || ide_devices[drive].type == IDE_ATAPI) { return 0xF1; } - return ide_read_ata_access(direction, drive, lba, numsects, target); + mutex_acquire(ide_lock); + uint8_t result = ide_read_ata_access(direction, drive, lba, numsects, target); + mutex_release(ide_lock); + return result; } diff --git a/kernel/drivers/pci.c b/kernel/drivers/pci.c index 068812c..23dae78 100644 --- a/kernel/drivers/pci.c +++ b/kernel/drivers/pci.c @@ -87,6 +87,22 @@ void pci_config_write_byte(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offs port_byte_out(PORT_PCI_CONFIG_DATA, value); } +pci_command_register_t pci_get_config(pci_device *device) { + pci_command_register_t status; + status.value = pci_config_read_word(device->bus, device->slot, device->func, PCI_CONFIG_COMMAND); + return status; +} + +void pci_set_status(pci_device *device, pci_status_register_t status) { + pci_config_write_word(device->bus, device->slot, device->func, PCI_CONFIG_STATUS, status.value); +} + +pci_status_register_t pci_get_status(pci_device *device) { + pci_status_register_t status; + status.value = pci_config_read_word(device->bus, device->slot, device->func, PCI_CONFIG_STATUS); + return status; +} + uint16_t pci_get_vendor_id(uint8_t bus, uint8_t slot, uint8_t func) { return pci_config_read_word(bus, slot, func, PCI_CONFIG_VENDOR_ID); } @@ -193,6 +209,31 @@ void pci_print_info() { } } +void pci_dump_caps_internal(pci_device *device) { + if (pci_devices->headerType >= 0x02) { + printf("\tNot supported for PCI-to-CardBus bridge\n"); + return; + } + if (!pci_get_status(device).status.capabilities_list) { + printf("\tNo caps\n"); + return; + } + uint8_t cap_ptr = pci_config_read_byte(device->bus, device->slot, device->func, PCI_CONFIG_CAP_POINTER); + printf("\t%x\n", cap_ptr); + // todo traverse +} + +void pci_dump_caps() { + for (int i = 0; i < last_pci_device_index; ++i) { + printf("PCI BSF: %2x/%2x/%2x, CSI: %2x/%2x/%2x, V/D: %4x/%4x, driver: %s\n", + pci_devices[i].bus, pci_devices[i].slot, pci_devices[i].func, + pci_devices[i].class, pci_devices[i].subclass, pci_devices[i].programInterface, + pci_devices[i].vendorId, pci_devices[i].deviceId, + (pci_devices[i].pci_driver == NULL ? "none" : pci_devices[i].pci_driver->name)); + pci_dump_caps_internal(&pci_devices[i]); + } +} + void pci_init_bar(pci_device *device, uint8_t bar_index) { if (device->headerType != 0x00) { k_panics("Only header 0x00 supported for now"); diff --git a/kernel/drivers/pci.h b/kernel/drivers/pci.h index d684aa3..33705a2 100644 --- a/kernel/drivers/pci.h +++ b/kernel/drivers/pci.h @@ -6,6 +6,8 @@ #define NEW_KERNEL_PCI_H #include +#include +#include #define PCI_CLASS_MASS_STORAGE 0x01 @@ -130,8 +132,47 @@ typedef struct pci_device { } driver_state; } pci_device; +typedef union { + uint16_t value; + struct { + bool io_space: 1; + bool mem_space: 1; + bool bus_master: 1; + bool special_cycles: 1; + bool mem_write_invalidate_enable: 1; + bool vga_palette_snoop: 1; + bool parity_error_response: 1; + uint8_t reserved: 1; + bool serr_enable: 1; + bool fast_b2b_enable: 1; + bool interrupt_disable: 1; + uint8_t reserved2: 5; + } packed command; +} pci_command_register_t; + +typedef union { + uint16_t value; + struct { + uint8_t reserved: 3; + bool interrupt_status: 1; + bool capabilities_list: 1; + bool speed_66mhz_capable: 1; + uint8_t reserved2: 1; + bool fast_b2b_capable: 1; + bool master_data_parity_error: 1; + uint8_t devsel_timing: 2; + bool signaled_target_abort: 1; + bool received_target_abort: 1; + bool received_master_abort: 1; + bool signaled_system_error: 1; + bool detected_parity_error: 1; + } packed status; +} pci_status_register_t; + void pci_print_info(); +void pci_dump_caps(); + uint32_t pci_register_driver(const pci_driver *pci_driver); void pci_sort_drivers(); diff --git a/kernel/drivers/vgascreen.c b/kernel/drivers/vgascreen.c index a271b68..6ddb257 100644 --- a/kernel/drivers/vgascreen.c +++ b/kernel/drivers/vgascreen.c @@ -70,13 +70,29 @@ int print_char(char character, int col, int row, char attributes) { offset = get_cursor_offset(); } - if (character == '\n') { - row = get_offset_row(offset); - offset = get_offset(0, row + 1); - } else { - _vga_character_memory[offset] = character; - _vga_character_memory[offset + 1] = attributes; - offset += 2; + switch (character) { + case '\n': + row = get_offset_row(offset); + offset = get_offset(0, row + 1); + break; + case '\t': + col = (col + 4) & (~0b11); + if (col > VGA_COL_MAX) { + row = get_offset_row(offset); + offset = get_offset(0, row + 1); + } else { + offset = get_offset(col, row); + } + break; + case '\r': + row = get_offset_row(offset); + offset = get_offset(0, row); + break; + default: + _vga_character_memory[offset] = character; + _vga_character_memory[offset + 1] = attributes; + offset += 2; + break; } if (offset >= (VGA_COL_MAX * 2 * VGA_ROW_MAX)) { diff --git a/kernel/libk/syscall.c b/kernel/libk/syscall.c index d701114..ba53df9 100644 --- a/kernel/libk/syscall.c +++ b/kernel/libk/syscall.c @@ -30,3 +30,7 @@ void syscall_yield_job() { void syscall_yield_irq(uint16_t irq) { syscall2(SYSCALL_YIELD_IRQ, irq ); } + +void syscall_job_suspend() { + syscall1(SYSCALL_SUSPEND); +} diff --git a/kernel/libk/syscall.h b/kernel/libk/syscall.h index 87eefa8..3278e5c 100644 --- a/kernel/libk/syscall.h +++ b/kernel/libk/syscall.h @@ -10,6 +10,7 @@ #define SYSCALL_START_SCHEDULER 0x01 #define SYSCALL_YIELD_JOB 0x02 #define SYSCALL_YIELD_IRQ 0x03 +#define SYSCALL_SUSPEND 0x04 void noreturn syscall_start_scheduler(); @@ -17,4 +18,6 @@ void syscall_yield_job(); void syscall_yield_irq(uint16_t irq); +void syscall_job_suspend(); + #endif //NEW_KERNEL_SYSCALL_H diff --git a/kernel/mem/paging.c b/kernel/mem/paging.c new file mode 100644 index 0000000..84abf40 --- /dev/null +++ b/kernel/mem/paging.c @@ -0,0 +1,58 @@ +// +// Created by rick on 21-02-21. +// + +#include "paging.h" +#include +#include +#include + +#define TABLE_ADDR_MASK 0xFFFFF000 +#define DIRECTORY_SIZE 1024 + +const uint32_t x = TABLE_ADDR_MASK; +typedef struct { + union { + struct { + bool present: 1; + bool read_write: 1; + bool user_mode: 1; + bool write_through: 1; + bool cache_disabled: 1; + bool accessed: 1; + char ignored: 1; + bool page_size: 1; + bool global: 1; // ignored + uint8_t avail: 3; + } packed; + uint32_t addr; + }; +} packed page_directory_entry; + +typedef struct { + union { + struct { + bool present: 1; + bool read_write: 1; + bool user_supervisor: 1; + bool write_through: 1; + bool cache_disabled: 1; + bool accessed: 1; + bool dirty: 1; + char ignored: 1; + bool global: 1; + uint8_t available: 3; + } packed; + uint32_t addr; + }; +} packed page_table_entry; + +page_directory_entry page_directory[DIRECTORY_SIZE] at_aligned(4096); + +void page_pre_init() { + for (int i = 0; i < DIRECTORY_SIZE; ++i) { + page_directory[i].read_write = true; + page_directory[i].user_mode = false; + page_directory[i].present = false; + } +} \ No newline at end of file diff --git a/kernel/mem/paging.h b/kernel/mem/paging.h new file mode 100644 index 0000000..1a5f3a6 --- /dev/null +++ b/kernel/mem/paging.h @@ -0,0 +1,8 @@ +// +// Created by rick on 21-02-21. +// + +#ifndef NEW_KERNEL_PAGING_H +#define NEW_KERNEL_PAGING_H + +#endif //NEW_KERNEL_PAGING_H diff --git a/kernel/tasks/locking.c b/kernel/tasks/locking.c index 8ac6188..5ccd199 100644 --- a/kernel/tasks/locking.c +++ b/kernel/tasks/locking.c @@ -3,3 +3,136 @@ // #include "locking.h" +#include +#include +#include +#include +#include + +typedef struct lock_fifo_entry { + uint32_t tid; + struct lock_fifo_entry *next; +} lock_fifo_entry_t; + +struct semaphore { + volatile int32_t value; + lock_fifo_entry_t *first_wait; + lock_fifo_entry_t *last_wait; +}; + +struct mutex { + volatile bool value; + lock_fifo_entry_t *first_wait; + lock_fifo_entry_t *last_wait; +}; + +struct spinlock { + volatile uint32_t lock; +}; + +semaphore_t *semaphore_create() { + semaphore_t *semaphore = malloc(sizeof(semaphore_t)); + semaphore->value = 1; + return semaphore; +} + +void semaphore_wait(semaphore_t *semaphore) { + if (__sync_sub_and_fetch(&semaphore->value, 1) == 0) { + return; // first to lock + } + task_lock_acquire(); + lock_fifo_entry_t *lock = malloc(sizeof(lock_fifo_entry_t)); + lock->tid = task_get_current_tid(); + if (semaphore->first_wait == NULL) { + semaphore->first_wait = lock; + } else { + semaphore->last_wait->next = lock; + } + semaphore->last_wait = lock; + task_lock_free(); + syscall_job_suspend(); +} + +void semaphore_signal(semaphore_t *semaphore) { + if (__sync_add_and_fetch(&semaphore->value, 1) == 1) { + return; // last in queue + } + task_lock_acquire(); + task_signal(semaphore->first_wait->tid); + lock_fifo_entry_t *first_entry = semaphore->first_wait; + semaphore->first_wait = first_entry->next; + free(first_entry); + task_lock_free(); +} + +void semaphore_free(semaphore_t *semaphore) { + if (semaphore->value < 1) { + printf("WARN: freeing semaphore which still has a task waiting\n"); + } + free(semaphore); +} + +mutex_t *mutex_create() { + mutex_t *mutex = malloc(sizeof(mutex_t)); + mutex->value = 1; + return mutex; +} + +void mutex_acquire(mutex_t *mutex) { + if (__sync_bool_compare_and_swap(&mutex->value, true, false) == true) { + return; // first one to lock + } + task_lock_acquire(); + lock_fifo_entry_t *lock = malloc(sizeof(lock_fifo_entry_t)); + lock->tid = task_get_current_tid(); + if (mutex->first_wait == NULL) { + mutex->first_wait = lock; + } else { + mutex->last_wait->next = lock; + } + mutex->last_wait = lock; + task_lock_free(); + syscall_job_suspend(); +} + +void mutex_release(mutex_t *mutex) { + task_lock_acquire(); + if (mutex->first_wait == NULL) { + mutex->value = true; + task_lock_free(); + return; // no one left + } + lock_fifo_entry_t *entry = mutex->first_wait; + task_signal(entry->tid); + mutex->first_wait = entry->next; + free(entry); + task_lock_free(); +} + +void mutex_free(mutex_t *mutex) { + if (mutex->value != true) { + printf("WARN: freeing mutex which still has a task waiting\n"); + } + free(mutex); +} + +spinlock_t *spinlock_create() { + return malloc(sizeof(spinlock_t)); +} + +void spinlock_acquire(spinlock_t *spinlock) { + while (!__sync_bool_compare_and_swap(&spinlock->lock, false, true)); + __sync_synchronize(); +} + +void spinlock_release(spinlock_t *spinlock) { + __sync_synchronize(); + spinlock->lock = false; +} + +void spinlock_free(spinlock_t *spinlock) { + if (spinlock->lock != false) { + printf("WARN: freeing spinlock which is still spinning\n"); + } + free(spinlock); +} diff --git a/kernel/tasks/locking.h b/kernel/tasks/locking.h index 6943a1e..ed21efe 100644 --- a/kernel/tasks/locking.h +++ b/kernel/tasks/locking.h @@ -5,4 +5,36 @@ #ifndef NEW_KERNEL_LOCKING_H #define NEW_KERNEL_LOCKING_H +#include + +typedef struct semaphore semaphore_t; + +typedef struct mutex mutex_t; + +typedef struct spinlock spinlock_t; + +semaphore_t *semaphore_create(); + +void semaphore_wait(semaphore_t *semaphore); + +void semaphore_signal(semaphore_t *semaphore); + +void semaphore_free(semaphore_t *semaphore); + +mutex_t *mutex_create(); + +void mutex_acquire(mutex_t *mutex); + +void mutex_release(mutex_t *mutex); + +void mutex_free(mutex_t *mutex); + +spinlock_t *spinlock_create(); + +void spinlock_acquire(spinlock_t *spinlock); + +void spinlock_release(spinlock_t *spinlock); + +void spinlock_free(spinlock_t *spinlock); + #endif //NEW_KERNEL_LOCKING_H diff --git a/kernel/tasks/task.c b/kernel/tasks/task.c index 6c6b377..03d3250 100644 --- a/kernel/tasks/task.c +++ b/kernel/tasks/task.c @@ -10,6 +10,7 @@ #include #include +#include #define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE)) @@ -17,7 +18,9 @@ #define TASK_STATE_RUNNABLE (1 << 0) #define TASK_STATE_RUNNING (1 << 1) #define TASK_STATE_WAIT_IRQ (1 << 2) +#define TASK_STATE_WAIT_SIGNAL (1 << 3) +#define TASK_STATE_STOPPED (1 << 6) #define TASK_STATE_ERROR (1 << 7) @@ -44,7 +47,7 @@ typedef struct { char alignment[4]; } packed task_stack_start; -bool task_locked = false; +volatile uint32_t task_locked = 0; task_t *idle_task = NULL; task_t *first_task = NULL; @@ -67,12 +70,45 @@ void cdecl noreturn task_entry_point(task_entrypoint entrypoint, void *entry_dat while (true); // halt } +void task_ensure_enabled() { + if (current_task == NULL) { + k_panics("Tasking should be enabled\n"); + } +} + void task_lock_acquire() { - task_locked = true; + if (__sync_add_and_fetch(&task_locked, 1) == UINT32_MAX) { + k_panics("To many task locks"); + }; } void task_lock_free() { - task_locked = false; + if (__sync_sub_and_fetch(&task_locked, 1) == UINT32_MAX) { + k_panics("To many task free's"); + } +} + +uint32_t task_get_current_tid() { + return current_task->tid; +} + +void task_signal(uint32_t tid) { + task_t *t = first_task; + while (t != NULL) { + if (t->tid == tid) { + if (t->state != TASK_STATE_WAIT_SIGNAL) { + // todo + } + t->state = TASK_STATE_RUNNABLE; + break; + } + t = t->next; + } +} + +void task_suspend() { + current_task->state = TASK_STATE_WAIT_SIGNAL; + task_switch_next(); } void noreturn task_idle(void *data) { @@ -98,7 +134,7 @@ void task_wait_irq(uint16_t irq_bits) { } void task_switch_next_inner(task_t *next_task) { - if (task_locked) { + if (task_locked != 0) { return; // don't switch while the task is locked } if (next_task == current_task) { @@ -115,6 +151,9 @@ void task_switch_next_inner(task_t *next_task) { } void task_start_first() { + if (task_locked > 0) { + k_panics("Tasking locked before start\n"); + } task_switch_next_inner(first_task); } @@ -203,5 +242,13 @@ uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) { return new_task->tid; } -void task_end(uint32_t pid) { +void task_end(uint32_t tid) { + task_t *t = first_task; + while (t != NULL) { + if (t->tid == tid) { + t->state = TASK_STATE_STOPPED; + break; + } + t = t->next; + } } diff --git a/kernel/tasks/task.h b/kernel/tasks/task.h index fad684d..2c9e75b 100644 --- a/kernel/tasks/task.h +++ b/kernel/tasks/task.h @@ -21,10 +21,18 @@ void task_switch_next(); uint32_t task_spawn(task_entrypoint, void *entry_data); -void task_end(uint32_t pid); +void task_end(uint32_t tid); + +void task_suspend(); + +uint32_t task_get_current_tid(); + +void task_signal(uint32_t tid); void task_lock_acquire(); +void task_ensure_enabled(); + void task_lock_free(); #endif //NEW_KERNEL_TASK_H