Browse Source

Implement serial logging. Finish modularizing power management.

coderain 6 years ago
parent
commit
b3e9524c23

+ 44 - 5
drivers/acpica/src/osmlxf.c

@@ -18,6 +18,7 @@
  */
 
 #include <common.h>
+#include <log.h>
 #include <heap.h>
 #include <memory.h>
 #include <thread.h>
@@ -25,6 +26,8 @@
 #include <timer.h>
 #include <interrupt.h>
 #include <acpi.h>
+#include <stdio.h>
+#include <power.h>
 
 const char driver_name[] = "acpica";
 
@@ -78,7 +81,9 @@ ACPI_STATUS AcpiOsSignal(UINT32 Function, void *Info)
 
 void AcpiOsVprintf(const char *Format, va_list Args)
 {
-    vprintf(Format, Args);
+    char buffer[MAX_LOG_MESSAGE_SIZE];
+    vsnprintf(buffer, MAX_LOG_MESSAGE_SIZE, Format, Args);
+    log_write(LOG_NORMAL, buffer);
 }
 
 void AcpiOsPrintf(const char *Format, ...)
@@ -308,11 +313,45 @@ ACPI_STATUS AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, UIN
      return AE_SUPPORT; // TODO
 }
 
+dword_t acpica_set_state(power_state_t state)
+{
+    switch (state)
+    {
+    case POWER_STATE_STANDBY:
+    case POWER_STATE_SUSPEND:
+        /* Not implemented */
+        return ERR_NOSYSCALL;
+
+    case POWER_STATE_OFF:
+        AcpiEnterSleepStatePrep(ACPI_STATE_S5);
+        disable_ints();
+        AcpiEnterSleepState(ACPI_STATE_S5);
+        break;
+
+    default:
+        return ERR_INVALID;
+    }
+
+    return ERR_SUCCESS;
+}
+
 dword_t driver_load(const char *parameters)
 {
-    if (ACPI_FAILURE(AcpiInitializeSubsystem())) return ERR_HARDWARE;
-    if (ACPI_FAILURE(AcpiInitializeTables(NULL, 16, FALSE))) return ERR_HARDWARE;
-    if (ACPI_FAILURE(AcpiLoadTables())) return ERR_HARDWARE;
-    if (ACPI_FAILURE(AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION))) return ERR_HARDWARE;
+    static power_callbacks_t callbacks = {
+        .set_state = acpica_set_state,
+    };
+
+    dword_t ret = register_power_callbacks(&callbacks);
+    if (ret != ERR_SUCCESS) return ret;
+
+    if (ACPI_FAILURE(AcpiInitializeSubsystem())
+        || ACPI_FAILURE(AcpiInitializeTables(NULL, 16, FALSE))
+        || ACPI_FAILURE(AcpiLoadTables())
+        || ACPI_FAILURE(AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION)))
+    {
+        register_power_callbacks(NULL);
+        return ERR_HARDWARE;
+    }
+
     return ERR_SUCCESS;
 }

+ 1 - 0
drivers/ps2/src/main.c

@@ -23,6 +23,7 @@
 #include <device.h>
 #include <timer.h>
 #include <heap.h>
+#include <stdio.h>
 
 const char driver_name[] = "ps2";
 

+ 1 - 0
drivers/serial/src/main.c

@@ -23,6 +23,7 @@
 #include <memory.h>
 #include <thread.h>
 #include <heap.h>
+#include <stdio.h>
 
 const char driver_name[] = "serial";
 

+ 1 - 1
grub.cfg

@@ -1,5 +1,5 @@
 menuentry "Monolithium OS" {
-    multiboot2 /boot/monolithium manager:Floppy0/MANAGER
+    multiboot2 /boot/monolithium manager:Floppy0/MANAGER debug:COM1
     module2 /boot/drivers/acpica.drv
     module2 /boot/drivers/fatfs.drv
     module2 /boot/drivers/floppy.drv

+ 2 - 2
kernel/Makefile

@@ -18,7 +18,7 @@
 #
 
 # Settings
-DEBUG  = yes
+DEBUG = yes
 
 # Compilers and tools
 CC = i686-elf-gcc
@@ -38,7 +38,7 @@ ASMFLAGS = -felf
 LDFLAGS = -T link.ld -L $(LIBGCC_DIR) -L ../crt -lgcc -lmlcrt -lgcc
 
 ifeq ($(DEBUG), yes)
-    CFLAGS += -g
+    CFLAGS += -g -DDEBUG
 else
     CFLAGS += -O3
 endif

+ 12 - 47
kernel/include/common.h

@@ -29,12 +29,19 @@
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 
-#define VIDEO_MEMORY 0xF0000000
+#define VIDEO_MEMORY      0xF0000000
 #define TEXT_VIDEO_MEMORY 0xB8000
-#define TEXT_COLOR_BLUE  0x01
-#define TEXT_COLOR_GREEN 0x02
-#define TEXT_COLOR_RED   0x04
-#define TEXT_COLOR_STRONG 0x08
+#define TEXT_WIDTH        80
+#define TEXT_HEIGHT       25
+
+#define DOUBLE_HORIZONTAL_BAR    0xCD
+#define DOUBLE_VERTICAL_BAR      0xBA
+#define DOUBLE_CORNER_LEFT_MID   0xBA
+#define DOUBLE_CORNER_LEFT_DOWN  0xBB
+#define DOUBLE_CORNER_LEFT_UP    0xBC
+#define DOUBLE_CORNER_RIGHT_UP   0xC8
+#define DOUBLE_CORNER_RIGHT_DOWN 0xC9
+#define DOUBLE_CORNER_RIGHT_MID  0xCC
 
 #define IO_PORT_FUNCTIONS(s, t) \
     static inline t inport##s(word_t port) \
@@ -109,46 +116,4 @@ static inline void disable_nmi()
     outportb(0x70, inportb(0x70) | 0x80);
 }
 
-static inline void set_bit(dword_t *bitfield, dword_t bit)
-{
-    bitfield[bit >> 5] |= 1 << (bit & 0x1F);
-}
-
-static inline void clear_bit(dword_t *bitfield, dword_t bit)
-{
-    bitfield[bit >> 5] &= ~(1 << (bit & 0x1F));
-}
-
-static inline bool_t test_bit(dword_t *bitfield, dword_t bit)
-{
-    return (bitfield[bit >> 5] & (1 << (bit & 0x1F))) ? TRUE : FALSE;
-}
-
-static inline void push_to_stack(uintptr_t *stack, uintptr_t value)
-{
-    *stack -= sizeof(uintptr_t);
-    *((uintptr_t*)(*stack)) = value;
-}
-
-static inline uintptr_t pop_from_stack(uintptr_t *stack)
-{
-    uintptr_t value = *((uintptr_t*)(*stack));
-    *stack += sizeof(uintptr_t);
-    return value;
-}
-
-void putchar(char character);
-void puts(const char *string);
-void clearscreen();
-void set_text_color(byte_t color);
-int vsnprintf(char *output, dword_t count, const char *format, va_list args);
-int vsprintf(char *output, const char *format, va_list args);
-int snprintf(char *output, dword_t count, const char *format, ...);
-int vprintf(const char *format, va_list args);
-int printf(const char *format, ...);
-int sprintf(char *output, const char *format, ...);
-const char *get_error_string(dword_t err_code);
-int max(int a, int b);
-int min(int a, int b);
-
 #endif

+ 0 - 2
kernel/include/exec/aout.h

@@ -81,6 +81,4 @@ typedef struct
 
 #pragma pack(pop)
 
-dword_t load_aout(handle_t file, process_params_t *parameters, thread_state_t *initial_state);
-
 #endif

+ 81 - 0
kernel/include/log.h

@@ -0,0 +1,81 @@
+/*
+ * log.h
+ *
+ * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <common.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#define MAX_LOG_MESSAGE_SIZE 256
+
+#ifdef DEBUG
+#define TRACE(x) log_write(LOG_DEBUG, x)
+#define FTRACE(x, args...) log_write(LOG_DEBUG, x, args)
+#else
+#define TRACE(x)
+#define FTRACE(x, ...)
+#endif
+
+typedef enum
+{
+    LOG_DEBUG,
+    LOG_NORMAL,
+    LOG_WARNING,
+    LOG_ERROR,
+    LOG_CRITICAL,
+} log_level_t;
+
+extern char *debug_channel;
+extern log_level_t debug_min_level;
+
+void append_log_entry(const char *source, log_level_t level, const char *message);
+
+static inline void log_write(log_level_t level, const char *format, ...)
+{
+    extern const char driver_name[];
+    static char log_buffer[MAX_LOG_MESSAGE_SIZE] = "";
+
+    va_list ap;
+    va_start(ap, format);
+    char message[MAX_LOG_MESSAGE_SIZE];
+    vsnprintf(message, MAX_LOG_MESSAGE_SIZE, format, ap);
+    va_end(ap);
+
+    char *ptr = message;
+    while (*ptr)
+    {
+        char *end = strchr(ptr, '\n');
+        if (end) *end = '\0';
+        else break;
+
+        char full_message[2 * MAX_LOG_MESSAGE_SIZE];
+        strcpy(full_message, log_buffer);
+        strcat(full_message, ptr);
+        append_log_entry(driver_name, level, full_message);
+        *log_buffer = '\0';
+
+        ptr = end + 1;
+    }
+
+    strcat(log_buffer, ptr);
+}
+
+#endif

+ 1 - 0
kernel/include/module.h

@@ -45,6 +45,7 @@ typedef struct
     list_entry_t segments;
 } module_t;
 
+module_t *get_module_from_address(void *address);
 dword_t module_load_from_physical(module_t *module, const char *parameters);
 dword_t module_unload(module_t *module);
 

+ 11 - 0
kernel/include/pci.h

@@ -23,6 +23,16 @@
 #include <common.h>
 #include <sdk/list.h>
 
+#define PCI_FIELD_REG(h, p) (OFFSET_OF(h, p) >> 2)
+#define PCI_FIELD_BIT_OFFSET(h, p) ((OFFSET_OF(h, p) & 3) << 3)
+#define PCI_FIELD_SIZE_MASK(h, p) ((sizeof(((h*)NULL)->p) == 1) ? 0xFF : ((sizeof(((h*)NULL)->p) == 2) ? 0xFFFF : 0xFFFFFFFF))
+#define PCI_FIELD_MASK(h, p) (PCI_FIELD_SIZE_MASK(h, p) << PCI_FIELD_BIT_OFFSET(h, p))
+#define PCI_READ_VALUE(d, h, p) ((pci_read((d), PCI_FIELD_REG(h, p)) >> PCI_FIELD_BIT_OFFSET(h, p)) & PCI_FIELD_SIZE_MASK(h, p))
+#define PCI_WRITE_VALUE(d, h, p, v) pci_write((d),                      \
+                                              PCI_FIELD_REG(h, p),      \
+                                              (((v) << PCI_FIELD_BIT_OFFSET(h, p)) & PCI_FIELD_MASK(h, p)) \
+                                              | (pci_read((d), PCI_FIELD_REG(h, p)) & ~PCI_FIELD_MASK(h, p)))
+
 #pragma pack(push, 1)
 
 typedef struct
@@ -99,6 +109,7 @@ enum
     PCI_NETWORK_DEVICE,
     PCI_DISPLAY_DEVICE,
     PCI_MULTIMEDIA_DEVICE,
+    PCI_MEMORY_DEVICE,
     PCI_BRIDGE_DEVICE,
     PCI_COMMUNICATION_DEVICE,
     PCI_PERIPHERAL_DEVICE,

+ 15 - 0
kernel/include/power.h

@@ -22,6 +22,21 @@
 
 #include <sdk/power.h>
 
+typedef enum
+{
+    POWER_STATE_STANDBY = 1,
+    POWER_STATE_SUSPEND,
+    POWER_STATE_OFF,
+} power_state_t;
+
+typedef dword_t (*power_set_state_proc_t)(power_state_t state);
+
+typedef struct
+{
+    power_set_state_proc_t set_state;
+} power_callbacks_t;
+
 dword_t power_init(void);
+dword_t register_power_callbacks(power_callbacks_t *callbacks);
 
 #endif

+ 1 - 1
kernel/include/process.h

@@ -78,6 +78,6 @@ void init_user_stack(uintptr_t *stack_pointer, process_params_t *parameters);
 void process_cleanup(object_t *proc);
 void destroy_process(process_t *process);
 process_t *switch_process(process_t *new_process);
-void process_init();
+void process_init(void);
 
 #endif

+ 0 - 2
kernel/include/thread.h

@@ -35,8 +35,6 @@
 
 #define SAFE_EFLAGS_MASK 0x00000CD5
 
-typedef dword_t (*thread_procedure_t)(void*);
-
 typedef enum
 {
     WAIT_NEVER,

+ 0 - 433
kernel/src/common.c

@@ -1,433 +0,0 @@
-/*
- * common.c
- *
- * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <common.h>
-#include <heap.h>
-#include <video.h>
-#include <thread.h>
-#include <timer.h>
-
-static dword_t terminal_row = 0, terminal_col = 0;
-static byte_t terminal_color = 0x07;
-
-bool_t video_initialized = FALSE;
-
-const char *get_error_string(dword_t err_num)
-{
-    static const char *error_strings[] = {
-        "ERR_SUCCESS",
-        "ERR_NOTFOUND",
-        "ERR_FORBIDDEN",
-        "ERR_INVALID",
-        "ERR_EXISTS",
-        "ERR_NOMEMORY",
-        "ERR_HARDWARE",
-        "ERR_BUSY",
-        "ERR_NOMEDIA",
-        "ERR_NOTRESP",
-        "ERR_WRITEPROT",
-        "ERR_NOSYSCALL",
-        "ERR_TIMEOUT",
-        "ERR_BADPTR",
-        "ERR_CANCELED",
-        "ERR_ISDIR",
-        "ERR_ISNOTDIR",
-        "ERR_DISKFULL",
-        "ERR_MEDIACHG"
-    };
-
-    if (err_num == 0)
-    {
-        return error_strings[0];
-    }
-    else if (err_num >= 0xE0000000)
-    {
-        if (err_num < MAX_ERR) return error_strings[err_num - 0xE0000000];
-    }
-
-    return NULL;
-}
-
-void set_text_color(byte_t color)
-{
-    terminal_color = color;
-}
-
-void clearscreen(void)
-{
-    word_t *video_mem = (word_t*)TEXT_VIDEO_MEMORY;
-    memset(video_mem, 0x00, TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t));
-}
-
-static void scroll(void)
-{
-    word_t *video_mem = (word_t*)(video_initialized ? VIDEO_MEMORY : TEXT_VIDEO_MEMORY);
-    memcpy(video_mem, &video_mem[TEXT_WIDTH], TEXT_WIDTH * (TEXT_HEIGHT - 1) * 2);
-    memset(&video_mem[(TEXT_HEIGHT - 1) * TEXT_WIDTH], 0, TEXT_WIDTH * 2);
-}
-
-void putchar(char character)
-{
-    if (character == '\n')
-    {
-        if (terminal_row < (TEXT_HEIGHT - 1)) terminal_row++;
-        else scroll();
-
-        terminal_col = 0;
-    }
-    else if (character == '\t')
-    {
-        terminal_col++;
-        while(terminal_col % 8) terminal_col++;
-    }
-    else if (character == '\r')
-    {
-        terminal_col = 0;
-    }
-    else
-    {
-        word_t *video_mem = (word_t*)(video_initialized ? VIDEO_MEMORY : TEXT_VIDEO_MEMORY);
-        video_mem[terminal_row * TEXT_WIDTH + terminal_col] = character | (terminal_color << 8);
-        terminal_col++;
-    }
-
-    if (terminal_col == TEXT_WIDTH)
-    {
-        if (terminal_row < (TEXT_HEIGHT - 1)) terminal_row++;
-        else scroll();
-        terminal_col = 0;
-    }
-
-    if (video_initialized)
-    {
-        video_cursor_location_t params = {
-            .row = terminal_row,
-            .column = terminal_col
-        };
-
-        device_t *video_device = get_char_device("Video0");
-        if (video_device) device_ioctl_internal(video_device, IOCTL_VIDEO_SET_TEXT_CURSOR, &params, sizeof(params), NULL, 0);
-    }
-    else
-    {
-        dword_t index = terminal_row * 80 + terminal_col;
-        outportb(VGA_CRTC_INDEX, 0x0F);
-        outportb(VGA_CRTC_DATA, (byte_t) (index & 0xFF));
-        outportb(VGA_CRTC_INDEX, 0x0E);
-        outportb(VGA_CRTC_DATA, (byte_t) ((index >> 8) & 0xFF));
-    }
-}
-
-void puts(const char *string)
-{
-    while (*string) putchar(*(string++));
-    putchar('\n');
-}
-
-int vsnprintf(char *output, dword_t count, const char *format, va_list args)
-{
-    int ret = 0;
-    const char *ptr;
-    const char *valid_flags = "-+ #0";
-
-    for (ptr = format; *ptr != '\0'; ptr++)
-    {
-        if (*ptr != '%')
-        {
-            if (count <= 1) break;
-            output[ret++] = *ptr;
-            count--;
-            continue;
-        }
-
-        ptr++;
-
-        int i;
-        char *p;
-        char padding_char = ' ', sign = '\0';
-        int padding = 0;
-        bool_t alternative = FALSE;
-        bool_t left_justify = FALSE;
-        bool_t external_width = FALSE;
-        bool_t external_precision = FALSE;
-        int width = 0, precision = -1;
-
-        while (*ptr)
-        {
-            char *flag = strchr(valid_flags, *ptr);
-            if (flag == NULL) break;
-
-            ptr++;
-
-            switch (*flag)
-            {
-            case '+':
-                sign = '+';
-                break;
-
-            case '-':
-                left_justify = TRUE;
-                break;
-
-            case ' ':
-                sign = ' ';
-                break;
-
-            case '#':
-                alternative = TRUE;
-                break;
-
-            case '0':
-                padding_char = '0';
-                break;
-            }
-        }
-
-        UNUSED_PARAMETER(alternative); // TODO
-
-        if (*ptr == '*') external_width = TRUE;
-        else width = strtol(ptr, (char**)&ptr, 10);
-
-        if (*ptr == '.')
-        {
-            ptr++;
-            if (*ptr == '*') external_precision = TRUE;
-            else precision = strtol(ptr, (char**)&ptr, 10);
-        }
-
-        char specifier = *ptr;
-
-        switch (specifier)
-        {
-        case '%':
-            if (count <= 1) goto done;
-            output[ret++] = '%';
-            count--;
-            break;
-
-        case 'c':
-            if (external_width) width = *va_arg(args, int*);
-            padding = width - 1;
-
-            if (!left_justify)
-            {
-                for (i = 0; i < padding; i++)
-                {
-                    if (count <= 1) goto done;
-                    output[ret++] = padding_char;
-                    count--;
-                }
-            }
-
-            if (count <= 1) goto done;
-            output[ret++] = va_arg(args, int);
-            count--;
-
-            if (left_justify)
-            {
-                for (i = 0; i < padding; i++)
-                {
-                    if (count <= 1) goto done;
-                    output[ret++] = padding_char;
-                    count--;
-                }
-            }
-
-            break;
-
-        case 'p':
-            padding_char = '0';
-            width = 8;
-            specifier = 'X';
-
-        case 'd':
-        case 'u':
-        case 'i':
-        case 'o':
-        case 'x':
-        case 'X':
-        {
-            char num_buffer[256];
-            int number = va_arg(args, int);
-            int number_base;
-
-            if (specifier == 'o') number_base = 8;
-            else if (tolower(specifier) == 'x') number_base = 16;
-            else number_base = 10;
-
-            if ((number > 0) && (sign != 0))
-            {
-                itoa(number, &num_buffer[1], number_base);
-                num_buffer[0] = sign;
-            }
-            else
-            {
-                itoa(number, num_buffer, number_base);
-            }
-
-            if (external_width) width = *va_arg(args, int*);
-            if (external_precision) precision = *va_arg(args, int*);
-
-            if ((int)strlen(num_buffer) < precision)
-            {
-                int leading_zeros = precision - strlen(num_buffer);
-                memmove(&num_buffer[leading_zeros], &num_buffer[0], leading_zeros);
-                for (i = 0; i < leading_zeros; i++) num_buffer[i] = '0';
-            }
-
-            padding = (int)width - (int)strlen(num_buffer);
-
-            if (!left_justify)
-            {
-                for (i = 0; i < padding; i++)
-                {
-                    if (count <= 1) goto done;
-                    output[ret++] = padding_char;
-                    count--;
-                }
-            }
-
-            for (p = num_buffer; *p != '\0'; p++)
-            {
-                if (count <= 1) goto done;
-                output[ret++] = *p;
-                count--;
-            }
-
-            if (left_justify && width)
-            {
-                for (i = 0; i < padding; i++)
-                {
-                    if (count <= 1) goto done;
-                    output[ret++] = padding_char;
-                    count--;
-                }
-            }
-
-            break;
-        }
-
-        case 's':
-        {
-            char *string = va_arg(args, char*);
-            if (external_width) width = *va_arg(args, int*);
-            if (external_precision) precision = *va_arg(args, int*);
-            padding = (int)width - (int)strlen(string);
-
-            if (!left_justify)
-            {
-                for (i = 0; i < padding; i++)
-                {
-                    if (count <= 1) goto done;
-                    output[ret++] = padding_char;
-                    count--;
-                }
-            }
-
-            for (i = 0, p = string; *p != '\0' && (precision < 0 || i < precision); p++, i++)
-            {
-                if (count <= 1) goto done;
-                output[ret++] = *p;
-                count--;
-            }
-
-            if (left_justify)
-            {
-                for (i = 0; i < padding; i++)
-                {
-                    if (count <= 1) goto done;
-                    output[ret++] = padding_char;
-                    count--;
-                }
-            }
-
-            break;
-        }
-
-        case 'f':
-        case 'F':
-        case 'e':
-        case 'E':
-        case 'g':
-        case 'G':
-            // TODO: print decimal
-            UNUSED_PARAMETER(precision);
-            UNUSED_PARAMETER(external_precision);
-            break;
-
-        case 'n':
-        {
-            int *printed_chars = va_arg(args, int*);
-            *printed_chars = ret;
-            break;
-        }
-        }
-    }
-
-done:
-    output[ret] = '\0';
-    return ret;
-}
-
-int snprintf(char *output, dword_t count, const char *format, ...)
-{
-    va_list args;
-    va_start(args, format);
-    int ret = vsnprintf(output, count, format, args);
-    va_end(args);
-    return ret;
-}
-
-int vsprintf(char *output, const char *format, va_list args)
-{
-    return vsnprintf(output, (dword_t)-1, format, args);
-}
-
-int vprintf(const char *format, va_list args)
-{
-    char buffer[256];
-    int ret = vsnprintf(buffer, 256, format, args);
-
-    char *ptr = &buffer[0];
-    while (*ptr) putchar(*(ptr++));
-    return ret;
-}
-
-int sprintf(char *output, const char *format, ...)
-{
-    va_list args;
-    va_start(args, format);
-    int ret = vsprintf(output, format, args);
-    va_end(args);
-    return ret;
-}
-
-int printf(const char *format, ...)
-{
-    va_list args;
-    va_start(args, format);
-    int ret = vprintf(format, args);
-    va_end(args);
-    return ret;
-}
-
-int abs(int x)
-{
-    return (x < 0) ? -x : x;
-}

+ 229 - 0
kernel/src/crash.c

@@ -0,0 +1,229 @@
+/*
+ * crash.c
+ *
+ * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <exception.h>
+#include <process.h>
+#include <module.h>
+#include <memory.h>
+#include <log.h>
+#include <exec/elf.h>
+
+#define MAX_BACKTRACE 256
+
+/* The background is a fabulous compromise between blue and red */
+#define CRASH_SCREEN_ATTRIBUTE 0x5F
+
+extern bool_t video_initialized;
+
+extern const char *lookup_kernel_symbol_name(uintptr_t address);
+
+static char screen[TEXT_WIDTH * TEXT_HEIGHT + 1] = { 0 };
+static const char *screen_template[TEXT_HEIGHT] = {
+    "",
+    "                              >>> KERNEL CRASH <<<",
+    "",
+    " A fatal error has occurred in the Monolithium kernel.  The system cannot",
+    " continue from this point in a reliable manner, and has been shut down.",
+    " Please contact the developers so that similar issues can be prevented or",
+    " avoided in the future.",
+    "",
+    " Error: %.71s",
+    " %.78s",
+    " In %s line %u",
+    " Modules involved: %.60s",
+    "",
+    " If serial logging is enabled, more information might be available in the log.",
+};
+
+void __attribute__((noreturn)) kernel_crash(const char *message, registers_t *regs, const char *filename, int line)
+{
+    int i;
+    word_t *video_mem = (word_t*)(video_initialized ? VIDEO_MEMORY : TEXT_VIDEO_MEMORY);
+    disable_ints();
+
+    uintptr_t call_stack[MAX_BACKTRACE];
+    int call_count = 0;
+    uintptr_t *frame_pointer;
+    asm volatile ("movl %%ebp, %0" : "=r"(frame_pointer) ::);
+
+    while (frame_pointer && call_count < MAX_BACKTRACE)
+    {
+        if (!get_physical_address(&frame_pointer[1])) break;
+        call_stack[call_count++] = frame_pointer[1];
+        if (!get_physical_address(&frame_pointer[0])) break;
+        frame_pointer = (uintptr_t*)frame_pointer[0];
+    }
+
+    for (i = 0; i < TEXT_HEIGHT; i++)
+    {
+        if (!screen_template[i]) continue;
+
+        switch (i)
+        {
+        case 8:
+            sprintf(&screen[i * TEXT_WIDTH], screen_template[i], message);
+            break;
+
+        case 9:
+            if (strlen(message) > 71) sprintf(&screen[i * TEXT_WIDTH], screen_template[i], &message[71]);
+            break;
+
+        case 10:
+            sprintf(&screen[i * TEXT_WIDTH], screen_template[i], filename, line);
+            break;
+
+        case 11:
+            {
+                int module_count = 0, j, k;
+                const char *module_list[call_count];
+                char modules[61] = "";
+
+                for (j = 0; j < call_count; j++)
+                {
+                    module_t *module = get_module_from_address((void*)call_stack[j]);
+                    if (!module) continue;
+
+                    bool_t found = FALSE;
+                    for (k = 0; k < module_count; k++)
+                    {
+                        if (strcmp(module_list[k], module->name) == 0)
+                        {
+                            found = TRUE;
+                            break;
+                        }
+                    }
+
+                    if (found) continue;
+                    module_list[module_count++] = module->name;
+                    if (module_count) strncat(modules, ", ", sizeof(modules) - strlen(modules) - 1);
+                    strncat(modules, module_list[j], sizeof(modules) - strlen(modules) - 1);
+                }
+
+                if (!strlen(modules)) sprintf(modules, "(none)");
+                sprintf(&screen[i * TEXT_WIDTH], screen_template[i], modules);
+            }
+            break;
+
+        default:
+            strcpy(&screen[i * TEXT_WIDTH], screen_template[i]);
+        }
+    }
+ 
+    for (i = 0; i < TEXT_WIDTH * TEXT_HEIGHT; i++) video_mem[i] = (CRASH_SCREEN_ATTRIBUTE << 8) | screen[i];
+
+    log_write(LOG_CRITICAL, "******************************\n");
+    log_write(LOG_CRITICAL, "*        ATTENTION!!!        *\n");
+    log_write(LOG_CRITICAL, "******************************\n");
+    log_write(LOG_CRITICAL, "The kernel crashed, specifying the following message:\n");
+    log_write(LOG_CRITICAL, "%s\n", message);
+    log_write(LOG_CRITICAL, "Crash requested in file %s line %u\n", filename, line);
+
+    thread_t *thread = get_current_thread();
+
+    if (thread)
+    {
+        log_write(LOG_CRITICAL, "Context: thread %u", thread->tid);
+
+        if (thread->owner_process)
+        {
+            log_write(LOG_CRITICAL, ", attached to process %u (%s).\n", thread->owner_process->pid, thread->owner_process->name);
+        }
+        else
+        {
+            log_write(LOG_CRITICAL, ", not attached to any process.\n");
+        }
+    }
+    else
+    {
+        log_write(LOG_CRITICAL, "No context available.\n");
+    }
+
+    if (regs)
+    {
+        const char *flag_names[32] = {
+            "CF", NULL, "PF", NULL, "AF", NULL, "ZF", "SF",
+            "TF", "IF", "DF", "OF", NULL, NULL, "NT", NULL,
+            "RF", "VM", "AC", "VIF", "VIP", "ID"
+        };
+
+        log_write(LOG_CRITICAL, "Machine state:\n");
+        log_write(LOG_CRITICAL, "EAX: 0x%08X\n", regs->eax);
+        log_write(LOG_CRITICAL, "ECX: 0x%08X\n", regs->ecx);
+        log_write(LOG_CRITICAL, "EDX: 0x%08X\n", regs->edx);
+        log_write(LOG_CRITICAL, "EBX: 0x%08X\n", regs->ebx);
+        log_write(LOG_CRITICAL, "ESP: 0x%08X\n", regs->esp);
+        log_write(LOG_CRITICAL, "EBP: 0x%08X\n", regs->ebp);
+        log_write(LOG_CRITICAL, "ESI: 0x%08X\n", regs->eax);
+        log_write(LOG_CRITICAL, "EDI: 0x%08X\n", regs->eax);
+        log_write(LOG_CRITICAL, "EIP: 0x%08X\n", regs->eip);
+        log_write(LOG_CRITICAL, "Code: 0x%04X\n", regs->cs);
+        log_write(LOG_CRITICAL, "Data: 0x%04X\n", regs->data_selector);
+        log_write(LOG_CRITICAL, "EFLAGS: %08X ( ", regs->eflags);
+
+        for (i = 0; i < 32; i++)
+        {
+            if (flag_names[i] && regs->eflags & (1 << i))
+            {
+                log_write(LOG_CRITICAL, "%s ", flag_names[i]);
+            }
+        }
+
+        log_write(LOG_CRITICAL, ")\n");
+
+        dword_t cr0, cr2, cr3;
+        asm volatile ("movl %%cr0, %0" : "=r"(cr0) ::);
+        asm volatile ("movl %%cr2, %0" : "=r"(cr2) ::);
+        asm volatile ("movl %%cr3, %0" : "=r"(cr3) ::);
+
+        log_write(LOG_CRITICAL, "CR0: 0x%08X\n", cr0);
+        log_write(LOG_CRITICAL, "CR2: 0x%08X\n", cr2);
+        log_write(LOG_CRITICAL, "CR3: 0x%08X\n", cr3);
+    }
+    else
+    {
+        log_write(LOG_CRITICAL, "No machine state available.\n");
+    }
+
+    log_write(LOG_CRITICAL, "Backtrace:\n");
+
+    for (i = 0; i < call_count; i++)
+    {
+        log_write(LOG_CRITICAL, "0x%08X", call_stack[i]);
+        module_t *module = get_module_from_address((void*)call_stack[i]);
+        extern int _end;
+
+        if (module)
+        {
+            log_write(LOG_CRITICAL, " in module %s", module->name);
+        }
+        else if (call_stack[i] >= KERNEL_AREA_START && call_stack[i] < (uintptr_t)&_end)
+        {
+            log_write(LOG_CRITICAL, " in the kernel");
+
+            const char *function_name = lookup_kernel_symbol_name(call_stack[i]);
+            if (function_name) log_write(LOG_CRITICAL, ", function %s", function_name);
+        }
+
+        log_write(LOG_CRITICAL, "\n");
+    }
+
+    halt();
+    for(;;);
+}

+ 2 - 58
kernel/src/device.c

@@ -310,70 +310,14 @@ dword_t device_delete_file(mounted_volume_t *volume, const char *path, bool_t pu
 
 dword_t device_read_file(file_instance_t *_file, void *buffer, qword_t offset, size_t length, size_t *bytes_read)
 {
-    dword_t ret = ERR_SUCCESS;
-    void *safe_buffer = NULL;
-    dword_t safe_bytes_read;
     device_file_t *file = CONTAINER_OF(_file->global, device_file_t, header);
-
-    if (get_previous_mode() == USER_MODE)
-    {
-        if (!check_usermode(buffer, length)) return ERR_BADPTR;
-        if (!check_usermode(bytes_read, sizeof(dword_t))) return ERR_BADPTR;
-
-        ret = pin_memory(buffer, &safe_buffer, length, FALSE);
-        if (ret != ERR_SUCCESS) return ret;
-    }
-    else
-    {
-        safe_buffer = buffer;
-    }
-
-    ret = device_read(file->device, safe_buffer, offset, length, &safe_bytes_read);
-
-    if (get_previous_mode() == USER_MODE)
-    {
-        EH_TRY *bytes_read = safe_bytes_read;
-        EH_CATCH ret = ERR_BADPTR;
-        EH_DONE;
-
-        if (safe_buffer) unmap_memory(safe_buffer);
-    }
-
-    return ret;
+    return device_read(file->device, buffer, offset, length, bytes_read);
 }
 
 dword_t device_write_file(file_instance_t *_file, const void *buffer, qword_t offset, size_t length, size_t *bytes_written)
 {
-    dword_t ret = ERR_SUCCESS;
-    void *safe_buffer = NULL;
-    dword_t safe_bytes_written;
     device_file_t *file = CONTAINER_OF(_file->global, device_file_t, header);
-
-    if (get_previous_mode() == USER_MODE)
-    {
-        if (!check_usermode(buffer, length)) return ERR_BADPTR;
-        if (!check_usermode(bytes_written, sizeof(dword_t))) return ERR_BADPTR;
-
-        ret = pin_memory(buffer, &safe_buffer, length, FALSE);
-        if (ret != ERR_SUCCESS) return ret;
-    }
-    else
-    {
-        safe_buffer = (void*)buffer;
-    }
-
-    ret = device_write(file->device, safe_buffer, offset, length, &safe_bytes_written);
-
-    if (get_previous_mode() == USER_MODE)
-    {
-        EH_TRY *bytes_written = safe_bytes_written;
-        EH_CATCH ret = ERR_BADPTR;
-        EH_DONE;
-
-        unmap_memory(safe_buffer);
-    }
-
-    return ret;
+    return device_write(file->device, buffer, offset, length, bytes_written);
 }
 
 dword_t device_list_dir(file_instance_t *directory, char *filename, bool_t continue_scan)

+ 1 - 66
kernel/src/exception.c

@@ -34,15 +34,6 @@ static const char *exception_names[] = {
     "Memory Access Fault",
 };
 
-static inline dword_t get_cr(int num)
-{
-    dword_t value;
-    if (num == 0) asm volatile ("movl %%cr0, %0" : "=r"(value));
-    else if (num == 2) asm volatile ("movl %%cr2, %0" : "=r"(value));
-    else if (num == 3) asm volatile ("movl %%cr3, %0" : "=r"(value));
-    return value;
-}
-
 static void raise_exception_internal(registers_t *regs, processor_mode_t mode, exception_info_t *info)
 {
     thread_t *thread = get_current_thread();
@@ -150,7 +141,7 @@ static void exception_handler(registers_t *regs, byte_t int_num)
         break;
 
     case CPU_EXCEPTION_PF:
-        faulting_address = (void*)get_cr(2);
+        asm volatile ("movl %%cr2, %0" : "=r"(faulting_address) ::);
         if (memory_fault_handler(faulting_address, regs)) return;
 
         info.number = EXCEPTION_MEMORY_ACCESS;
@@ -270,62 +261,6 @@ sysret_t syscall_restore_exception_handler(exception_handler_t *old_handler)
     return ERR_SUCCESS;
 }
 
-void __attribute__((noreturn)) kernel_crash(const char *message, registers_t *regs, const char *filename, int line)
-{
-    disable_ints();
-    thread_t *current_thread = get_current_thread();
-
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_STRONG);
-    printf("\n>>> KERNEL CRASH <<<\n\n");
-
-    if (current_thread)
-    {
-        printf("Process/Thread: ");
-        set_text_color(TEXT_COLOR_BLUE | TEXT_COLOR_GREEN | TEXT_COLOR_RED | TEXT_COLOR_STRONG);
-        printf("%s (PID %u, TID %u)\n\n",
-               current_thread->owner_process->name,
-               current_thread->owner_process->pid,
-               current_thread->tid);
-    }
-
-    if (regs != NULL)
-    {
-        set_text_color(TEXT_COLOR_BLUE | TEXT_COLOR_GREEN | TEXT_COLOR_RED | TEXT_COLOR_STRONG);
-        printf("\nEAX = %08X ECX = %08X EDX = %08X EBX = %08X\n",
-               regs->eax,
-               regs->ecx,
-               regs->edx,
-               regs->ebx);
-        printf("ESP = %08X EBP = %08X ESI = %08X EDI = %08X\n",
-               (regs->eflags & EFLAGS_VM) ? ((registers_ext_t*)regs)->esp3 : regs->esp,
-               regs->ebp,
-               regs->esi,
-               regs->edi);
-        printf("CS:EIP = %04X:%08X EFLAGS = %08X DS/ES/FS/GS = %04X SS = %04X\n",
-               regs->cs,
-               regs->eip,
-               regs->eflags,
-               regs->data_selector,
-               (regs->eflags & EFLAGS_VM) ? ((registers_ext_t*)regs)->ss : regs->data_selector);
-        printf("CR0 = 0x%08X CR2 = 0x%08X CR3 = 0x%08X\n\n",
-               get_cr(0),
-               get_cr(2),
-               get_cr(3));
-    }
-
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_STRONG);
-    printf("Error: ");
-    set_text_color(TEXT_COLOR_BLUE | TEXT_COLOR_GREEN | TEXT_COLOR_RED | TEXT_COLOR_STRONG);
-    printf("%s", message);
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_STRONG);
-    printf(" at ");
-    set_text_color(TEXT_COLOR_BLUE | TEXT_COLOR_GREEN | TEXT_COLOR_RED | TEXT_COLOR_STRONG);
-    printf("%s:%d", filename, line);
-
-    halt();
-    for(;;);
-}
-
 void exceptions_init()
 {
     byte_t i;

+ 5 - 6
kernel/src/exec/aout.c

@@ -22,7 +22,7 @@
 #include <heap.h>
 #include <syscalls.h>
 
-dword_t load_aout(handle_t file, process_params_t *parameters, thread_state_t *initial_state)
+dword_t load_aout(handle_t file, thread_state_t *initial_state)
 {
     aout_header_t header;
     size_t bytes_read;
@@ -51,9 +51,8 @@ dword_t load_aout(handle_t file, process_params_t *parameters, thread_state_t *i
     if (ret != ERR_SUCCESS) return ret;
 
     initial_state->regs.esp = (uintptr_t)address + 0x200000;
-    init_user_stack((uintptr_t*)&initial_state->regs.esp, parameters);
 
-    address = (void*)0x100000;
+    address = (void*)0x1000;
 
     switch (header.midmag & 0xFFFF)
     {
@@ -97,8 +96,8 @@ dword_t load_aout(handle_t file, process_params_t *parameters, thread_state_t *i
                       INVALID_HANDLE,
                       section,
                       &address,
-                      0ULL,
-                      PAGE_ALIGN_UP(header.text_size + sizeof(aout_header_t)),
+                      (qword_t)sizeof(aout_header_t),
+                      PAGE_ALIGN_UP(header.text_size),
                       MEMORY_BLOCK_ACCESSIBLE
                       | MEMORY_BLOCK_WRITABLE
                       | MEMORY_BLOCK_USERMODE
@@ -144,7 +143,7 @@ dword_t load_aout(handle_t file, process_params_t *parameters, thread_state_t *i
         }
 
         syscall(SYSCALL_CLOSE_OBJECT, section);
-        initial_state->regs.eip = (uintptr_t)address + header.entry_point + sizeof(aout_header_t);
+        initial_state->regs.eip = (uintptr_t)address + header.entry_point;
         break;
     }
 

+ 7 - 8
kernel/src/exec/elf.c

@@ -20,6 +20,7 @@
 #include <exec/elf.h>
 #include <process.h>
 #include <module.h>
+#include <log.h>
 
 extern void *get_kernel_symbol(const char *name);
 
@@ -36,7 +37,7 @@ static dword_t elf_hash(const byte_t *name)
     return hash;
 }
 
-dword_t load_elf(handle_t file, process_params_t *parameters, thread_state_t *initial_state)
+dword_t load_elf(handle_t file, thread_state_t *initial_state)
 {
     elf_ident_t ident;
     char filename[MAX_PATH];
@@ -116,8 +117,6 @@ dword_t load_elf(handle_t file, process_params_t *parameters, thread_state_t *in
     if (ret != ERR_SUCCESS) return ret;
 
     initial_state->regs.esp = (uintptr_t)stack_address + 0x200000;
-    init_user_stack((uintptr_t*)&initial_state->regs.esp, parameters);
-
     syscall(SYSCALL_CLOSE_OBJECT, section);
     return ret;
 }
@@ -183,27 +182,27 @@ dword_t load_module_elf(void *address, module_t *module)
         case ELF_R_386_PC32: *(dword_t*)location += symbol + rela->r_addend - (uintptr_t)location; break;
 
         case ELF_R_386_GOT32:
-            printf("missing support: GOT32\n");
+            log_write(LOG_WARNING, "missing support: GOT32\n");
             /* *(dword_t*)location = G + rela->r_addend */;
             break;
 
         case ELF_R_386_PLT32:
-            printf("missing support: PLT32\n");
+            log_write(LOG_WARNING, "missing support: PLT32\n");
             /* *(dword_t*)location = L + rela->r_addend - (uintptr_t)location; */ break;
 
         case ELF_R_386_RELATIVE: *(dword_t*)location += (uintptr_t)module->base_address + rela->r_addend; break;
 
         case ELF_R_386_GOTOFF:
-            printf("missing support: GOTOFF\n");
+            log_write(LOG_WARNING, "missing support: GOTOFF\n");
             /* *(dword_t*)location = symbol + rela->r_addend - GOT; */ break;
 
         case ELF_R_386_GOTPC:
-            printf("missing support: GOTPC\n");
+            log_write(LOG_WARNING, "missing support: GOTPC\n");
             /* *(dword_t*)location = GOT + rela->r_addend - (uintptr_t)location; */
             break;
 
         case ELF_R_386_32PLT:
-            printf("missing support: 32PLT\n");
+            log_write(LOG_WARNING, "missing support: 32PLT\n");
             /* *(dword_t*)location = L + rela->r_addend */;
             break;
 

+ 103 - 0
kernel/src/log.c

@@ -0,0 +1,103 @@
+/*
+ * log.c
+ *
+ * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <log.h>
+#include <device.h>
+#include <sync.h>
+#include <stdio.h>
+#include <timer.h>
+
+#define QUEUE_SIZE 4096
+
+typedef struct
+{
+    log_level_t level;
+    char message[MAX_LOG_MESSAGE_SIZE];
+} log_entry_t;
+
+static lock_t lock = 0;
+static log_entry_t queue[QUEUE_SIZE];
+static bool_t empty = TRUE;
+static dword_t start = 0, end = 0;
+
+char *debug_channel = NULL;
+#ifdef DEBUG
+log_level_t debug_min_level = LOG_DEBUG;
+#else
+log_level_t debug_min_level = LOG_NORMAL;
+#endif
+
+static void flush_queue(void)
+{
+    if (!debug_channel) return;
+    device_t *device = get_char_device(debug_channel);
+    if (!device) return;
+    acquire_lock(&lock);
+
+    while (!empty)
+    {
+        if (queue[start].level >= debug_min_level)
+        {
+            size_t written;
+            if (device_write(device, queue[start].message, 0ULL, strlen(queue[start].message), &written) != ERR_SUCCESS) break;
+        }
+
+        start++;
+        start %= QUEUE_SIZE;
+        if (start == end) empty = TRUE;
+    }
+
+    release_lock(&lock);
+}
+
+void append_log_entry(const char *source, log_level_t level, const char *message)
+{
+    size_t length = strlen(message);
+    if (length == 0) return;
+
+    bool_t too_big = FALSE;
+    size_t max_size = MAX_LOG_MESSAGE_SIZE - 4 - strlen(source);
+    if (length >= max_size)
+    {
+        length = max_size - 3;
+        too_big = TRUE;
+    }
+
+    char message_copy[length + 1];
+    strncpy(message_copy, message, length);
+    message_copy[length] = '\0';
+    if (too_big) strcat(message_copy, "...");
+
+    acquire_lock(&lock);
+    queue[end].level = level;
+    snprintf(queue[end].message, MAX_LOG_MESSAGE_SIZE, "[%s] %s\n", source, message_copy);
+
+    if (start == end && !empty)
+    {
+        start++;
+        start %= QUEUE_SIZE;
+    }
+
+    end++;
+    end %= QUEUE_SIZE;
+    empty = FALSE;
+
+    release_lock(&lock);
+    flush_queue();
+}

+ 14 - 11
kernel/src/memory/memory.c

@@ -18,6 +18,7 @@
  */
 
 #include <memory.h>
+#include <log.h>
 #include <exception.h>
 #include <process.h>
 #include <syscalls.h>
@@ -885,8 +886,10 @@ dword_t map_memory_in_address_space(memory_address_space_t *address_space,
 {
     dword_t ret;
     void *address = (void*)PAGE_ALIGN((uintptr_t)*virtual);
+    uintptr_t aligned_physical = PAGE_ALIGN((uintptr_t)physical);
+    if (*virtual != NULL && PAGE_OFFSET((uintptr_t)*virtual) != PAGE_OFFSET((uintptr_t)physical)) return ERR_INVALID;
 
-    size = PAGE_ALIGN_UP(size) >> 12;
+    size = (PAGE_ALIGN_UP((uintptr_t)physical + size - 1) - aligned_physical) >> 12;
     acquire_resource_exclusive(&address_space->resource);
 
     memory_block_t *block = find_free_block(address_space, address, size);
@@ -904,7 +907,7 @@ dword_t map_memory_in_address_space(memory_address_space_t *address_space,
     if (block_flags & MEMORY_BLOCK_WRITABLE) flags |= PAGE_WRITABLE;
     if (block_flags & MEMORY_BLOCK_USERMODE) flags |= PAGE_USERMODE;
 
-    ret = map_memory_internal(physical, (void*)real_address, size * PAGE_SIZE, flags);
+    ret = map_memory_internal((void*)aligned_physical, (void*)real_address, size * PAGE_SIZE, flags);
     if (ret != ERR_SUCCESS)
     {
         release_resource(&address_space->resource);
@@ -2594,8 +2597,8 @@ void memory_init(multiboot_tag_mmap_t *mmap, uintptr_t lowest_physical)
 
     fix_overlapping_sections(mmap);
 
-    puts("\nMemory map:\n\nBase\t\t\tLength\t\t\tType");
-    puts("------------------------------------------------------------");
+    log_write(LOG_NORMAL, "Memory map:\nBase\t\t\tLength\t\t\tType\n");
+    log_write(LOG_NORMAL, "------------------------------------------------------------\n");
 
     multiboot_mmap_entry_t *entry;
 
@@ -2603,12 +2606,12 @@ void memory_init(multiboot_tag_mmap_t *mmap, uintptr_t lowest_physical)
          (uintptr_t)entry < ((uintptr_t)mmap + mmap->size);
          entry = (multiboot_mmap_entry_t*)((uintptr_t)entry + mmap->entry_size))
     {
-        printf("0x%08X%08X\t0x%08X%08X\t%s\n",
-               entry->base_high,
-               entry->base_low,
-               entry->length_high,
-               entry->length_low,
-               (entry->type == 1) ? "Usable" : "Not Usable");
+        log_write(LOG_NORMAL, "0x%08X%08X\t0x%08X%08X\t%s\n",
+                  entry->base_high,
+                  entry->base_low,
+                  entry->length_high,
+                  entry->length_low,
+                  (entry->type == 1) ? "Usable" : "Not Usable");
 
         if (entry->type == 1
             && entry->base_high == 0
@@ -2654,7 +2657,7 @@ void memory_init(multiboot_tag_mmap_t *mmap, uintptr_t lowest_physical)
         }
     }
 
-    puts("------------------------------------------------------------");
+    log_write(LOG_NORMAL, "------------------------------------------------------------\n");
     total_physical_pages += num_free_pages;
     pages = (page_t*)(KERNEL_POOL_START - total_physical_pages * sizeof(page_t));
 

+ 20 - 0
kernel/src/module.c

@@ -25,8 +25,28 @@ extern dword_t load_module_elf(const void *address, module_t *module);
 
 typedef dword_t (*driver_load_proc_t)(const char *parameters);
 
+char driver_name[] = "kernel";
 static DECLARE_LIST(modules);
 
+module_t *get_module_from_address(void *address)
+{
+    uintptr_t addr = (uintptr_t)address;
+
+    list_entry_t *i, *j;
+    for (i = modules.next; i != &modules; i = i->next)
+    {
+        module_t *module = CONTAINER_OF(i, module_t, link);
+
+        for (j = module->segments.next; j != &module->segments; j = j->next)
+        {
+            module_segment_t *segment = CONTAINER_OF(j, module_segment_t, link);
+            if (addr >= (uintptr_t)segment->address && addr < ((uintptr_t)segment->address + segment->size)) return module;
+        }
+    }
+
+    return NULL;
+}
+
 dword_t module_load_from_physical(module_t *module, const char *parameters)
 {
     module->name = NULL;

+ 37 - 17
kernel/src/pci.c

@@ -18,6 +18,7 @@
  */
 
 #include <pci.h>
+#include <log.h>
 #include <heap.h>
 #include <irq.h>
 
@@ -47,8 +48,8 @@ static inline bool_t pci_device_exists(dword_t bus, dword_t slot, dword_t func)
         .slot = slot,
         .function = func
     };
-    dword_t reg0 = pci_read(&device, 0);
-    return ((reg0 & 0xFFFF) == 0xFFFF) ? FALSE : TRUE;
+
+    return PCI_READ_VALUE(&device, pci_header_t, vendor_id) != 0xFFFF;
 }
 
 dword_t pci_read(pci_device_t *device, dword_t reg)
@@ -80,25 +81,44 @@ list_entry_t *get_pci_device_list_head(void)
 
 void pci_init(void)
 {
-    int i, j, k;
+    byte_t buses[256] = {0};
+    size_t num_buses = 1;
 
-    for (i = 0; i < 256; i++) for (j = 0; j < 32; j++) for (k = 0; k < 8; k++)
+    int i, j, k;
+    for (i = 0; i < num_buses; i++)
     {
-        if (!pci_device_exists(i, j, k)) continue;
-        pci_device_t *device = (pci_device_t*)malloc(sizeof(pci_device_t));
-        if (device == NULL) continue;
+        for (j = 0; j < 32; j++) for (k = 0; k < 8; k++)
+        {
+            if (!pci_device_exists(buses[i], j, k)) continue;
+            pci_device_t *device = (pci_device_t*)malloc(sizeof(pci_device_t));
+            if (device == NULL) continue;
+
+            device->bus = buses[i];
+            device->slot = j;
+            device->function = k;
+
+            dword_t reg2 = pci_read(device, 2);
+            device->class = (reg2 >> 24) & 0xFF;
+            device->subclass = (reg2 >> 16) & 0xFF;
+            device->prog_if = (reg2 >> 8) & 0xFF;
+            device->in_use = FALSE;
 
-        device->bus = i;
-        device->slot = j;
-        device->function = k;
+            if (device->class == PCI_BRIDGE_DEVICE)
+            {
+                if (device->subclass == 0)
+                {
+                    if (device->function) buses[num_buses++] = device->function;
+                }
+                else if (device->subclass == 4 || device->subclass == 9)
+                {
+                    buses[num_buses++] = PCI_READ_VALUE(device, pci_bridge_header_t, secondary_bus_num);
+                }
+            }
 
-        dword_t data = pci_read(device, 2);
-        device->class = (data >> 24) & 0xFF;
-        device->subclass = (data >> 16) & 0xFF;
-        device->prog_if = (data >> 8) & 0xFF;
-        device->in_use = FALSE;
+            log_write(LOG_NORMAL, "PCI bus #%u, slot #%u, function #%u: %s\n", buses[i], j, k, pci_device_classes[device->class]);
+            list_append(&pci_device_list, &device->list);
 
-        printf("PCI bus #%u, slot #%u, function #%u: %s\n", i, j, k, pci_device_classes[device->class]);
-        list_append(&pci_device_list, &device->list);
+            if (k == 0 && !(PCI_READ_VALUE(device, pci_header_t, header_type) & 0x80)) break;
+        }
     }
 }

+ 12 - 5
kernel/src/power.c

@@ -21,6 +21,15 @@
 #include <syscalls.h>
 #include <user.h>
 
+static power_callbacks_t *power_callbacks = NULL;
+
+dword_t register_power_callbacks(power_callbacks_t *callbacks)
+{
+    if (callbacks && power_callbacks) return ERR_EXISTS;
+    power_callbacks = callbacks;
+    return ERR_SUCCESS;
+}
+
 sysret_t syscall_power_control(power_command_t command)
 {
     if (get_previous_mode() == USER_MODE && !check_privileges(PRIVILEGE_POWER_CONTROL))
@@ -30,6 +39,9 @@ sysret_t syscall_power_control(power_command_t command)
 
     switch (command)
     {
+    case POWER_COMMAND_SHUTDOWN:
+        if (power_callbacks) power_callbacks->set_state(POWER_STATE_OFF);
+
     case POWER_COMMAND_HALT:
         disable_ints();
         halt();
@@ -42,11 +54,6 @@ sysret_t syscall_power_control(power_command_t command)
         halt();
         break;
 
-    case POWER_COMMAND_SHUTDOWN:
-        // TODO: ACPI set to S5
-        halt();
-        break;
-
     default:
         return ERR_INVALID;
     }

+ 24 - 44
kernel/src/process.c

@@ -25,9 +25,10 @@
 #include <exec/aout.h>
 #include <cpu.h>
 
-dword_t load_elf(handle_t file, process_params_t *parameters, thread_state_t *initial_state);
+dword_t load_elf(handle_t file, thread_state_t *initial_state);
+dword_t load_aout(handle_t file, thread_state_t *initial_state);
 
-typedef dword_t (*loader_proc)(handle_t, process_params_t*, thread_state_t*);
+typedef dword_t (*loader_proc)(handle_t, thread_state_t*);
 
 static dword_t pid_alloc_bitmap[MAX_PROCESSES / 32];
 static lock_t pid_bitmap_lock = 0;
@@ -141,13 +142,13 @@ sysret_t syscall_open_process(dword_t pid, handle_t *handle)
     return ret;
 }
 
-dword_t load_executable(handle_t file, process_params_t *parameters, thread_state_t *initial_state)
+dword_t load_executable(handle_t file, thread_state_t *initial_state)
 {
     loader_proc *loader = loaders;
 
     while (*loader)
     {
-        dword_t ret = (*loader++)(file, parameters, initial_state);
+        dword_t ret = (*loader++)(file, initial_state);
         if (ret == ERR_INVALID) continue;
         return ret;
     }
@@ -157,52 +158,25 @@ dword_t load_executable(handle_t file, process_params_t *parameters, thread_stat
 
 void init_user_stack(uintptr_t *stack_pointer, process_params_t *parameters)
 {
-    static const byte_t program_end_code[] = {
-        /* push eax */
-        0x50,
-
-        /* push INVALID_HANDLE */
-        0x68,
-        INVALID_HANDLE & 0xFF,
-        (INVALID_HANDLE >> 8) & 0xFF,
-        (INVALID_HANDLE >> 16) & 0xFF,
-        (INVALID_HANDLE >> 24) & 0xFF,
-
-        /* mov eax, SYSCALL_TERMINATE */
-        0xB8,
-        SYSCALL_TERMINATE & 0xFF,
-        (SYSCALL_TERMINATE >> 8) & 0xFF,
-        (SYSCALL_TERMINATE >> 16) & 0xFF,
-        SYSCALL_TERMINATE >> 24,
-
-        /* mov edx, esp */
-        0x8B, 0xD4,
-
-        /* int SYSCALL_INTERRUPT */
-        0xCD, SYSCALL_INTERRUPT
-    };
-
     uintptr_t stack_top = *stack_pointer;
 
-    *stack_pointer -= (strlen(parameters->command_line) + 1 + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
-    strcpy((char*)*stack_pointer, parameters->command_line);
-    parameters->command_line = (char*)*stack_pointer;
+    if (parameters->command_line)
+    {
+        *stack_pointer -= (strlen(parameters->command_line) + 1 + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
+        strcpy((char*)*stack_pointer, parameters->command_line);
+        parameters->command_line = (char*)*stack_pointer;
+    }
 
     *stack_pointer -= (sizeof(process_params_t) + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
     *(process_params_t*)*stack_pointer = *parameters;
-    uintptr_t parameters_addr = *stack_pointer;
-
-    *stack_pointer -= (sizeof(program_end_code) + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
-    memcpy((void*)*stack_pointer, program_end_code, sizeof(program_end_code));
-    uintptr_t end_code_addr = *stack_pointer;
+    parameters = (process_params_t*)*stack_pointer;
 
     if ((stack_top - *stack_pointer) < MAX_PARAMETERS * sizeof(uintptr_t))
     {
         *stack_pointer = stack_top - MAX_PARAMETERS * sizeof(uintptr_t);
     }
 
-    push_to_stack(stack_pointer, parameters_addr);
-    push_to_stack(stack_pointer, end_code_addr);
+    init_thread_stack(stack_pointer, parameters);
 }
 
 sysret_t syscall_create_process(const char *path, dword_t flags, process_params_t *parameters, handle_t *process_handle, handle_t *thread_handle)
@@ -247,12 +221,18 @@ sysret_t syscall_create_process(const char *path, dword_t flags, process_params_
             }
 
             safe_params.command_line = cmdline;
+            parameters = &safe_params;
         }
     }
     else
     {
         safe_path = (char*)path;
-        if (parameters) safe_params = *parameters;
+
+        if (parameters)
+        {
+            safe_params = *parameters;
+            parameters = &safe_params;
+        }
     }
 
     if (safe_path)
@@ -341,7 +321,8 @@ sysret_t syscall_create_process(const char *path, dword_t flags, process_params_
     if (file != INVALID_HANDLE)
     {
         process_t *old_process = switch_process(proc);
-        ret = load_executable(file, parameters ? &safe_params : NULL, &initial_state);
+        ret = load_executable(file, &initial_state);
+        init_user_stack((uintptr_t*)&initial_state.regs.esp, parameters);
         switch_process(old_process);
         if (ret != ERR_SUCCESS) goto cleanup;
     }
@@ -407,9 +388,8 @@ cleanup:
             syscall(SYSCALL_TERMINATE, proc->pid, 1);
             if (safe_process_handle != INVALID_HANDLE) syscall_close_object(safe_process_handle);
             if (safe_thread_handle != INVALID_HANDLE) syscall_close_object(safe_thread_handle);
+            dereference(&proc->header);
         }
-
-        dereference(&proc->header);
     }
     else
     {
@@ -751,7 +731,7 @@ process_t *switch_process(process_t *new_process)
     return old_process;
 }
 
-void process_init(char *root_directory)
+void process_init(void)
 {
     memset(pid_alloc_bitmap, 0, sizeof(pid_alloc_bitmap));
 

+ 157 - 122
kernel/src/start.c

@@ -19,6 +19,7 @@
 
 #include <boot/multiboot.h>
 #include <common.h>
+#include <log.h>
 #include <cpu.h>
 #include <memory.h>
 #include <heap.h>
@@ -35,19 +36,53 @@
 #include <module.h>
 #include <exec/elf.h>
 
-#define MAX_CMDLINE_LENGTH 256
+#define DO_TASK(x, ...) x(__VA_ARGS__); advance_progress()
 
-extern bool_t video_initialized;
+#define MAX_CMDLINE_LENGTH 256
 
 static char cmdline[MAX_CMDLINE_LENGTH] = "";
 static uintptr_t lowest_physical = 0;
 static multiboot_tag_mmap_t *mmap = NULL;
 static multiboot_tag_sections_t *kernel_sections = NULL;
+static size_t tasks_completed = 0, num_tasks = 12;
+static const char *manager_path = "";
 
+bool_t video_initialized = FALSE;
 const elf32_symbol_t *kernel_symtab = NULL;
 dword_t kernel_symcount = 0;
 const char *kernel_strtab = NULL;
 
+void *get_kernel_symbol(const char *name)
+{
+    int i;
+
+    for (i = 0; i < kernel_symcount; i++)
+    {
+        if (strcmp(name, &kernel_strtab[kernel_symtab[i].st_name]) == 0)
+        {
+            return (void*)kernel_symtab[i].st_value;
+        }
+    }
+
+    return NULL;
+}
+
+const char *lookup_kernel_symbol_name(uintptr_t address)
+{
+    int i;
+
+    for (i = 0; i < kernel_symcount; i++)
+    {
+        if (address >= kernel_symtab[i].st_value && address < (kernel_symtab[i].st_value + kernel_symtab[i].st_size))
+        {
+            return &kernel_strtab[kernel_symtab[i].st_name];
+        }
+    }
+
+    return NULL;
+}
+
+
 static dword_t __attribute__((__noreturn__)) system_idle_thread(void *param)
 {
     UNUSED_PARAMETER(param);
@@ -85,6 +120,7 @@ static void scan_multiboot_info(multiboot_tag_t *mboot)
             {
                 multiboot_tag_module_t *module = (multiboot_tag_module_t*)tag;
                 if (module->mod_end > lowest_physical) lowest_physical = module->mod_end;
+                num_tasks++;
             }
             break;
 
@@ -145,117 +181,149 @@ static bool_t load_kernel_symbols()
     return TRUE;
 }
 
-void *get_kernel_symbol(const char *name)
+static void setup_memory_management(void)
 {
-    int i;
+    if (!mmap) KERNEL_CRASH("The bootloader failed to supply a memory map");
+    memory_init(mmap, PAGE_ALIGN_UP(lowest_physical));
+    heap_init();
 
-    for (i = 0; i < kernel_symcount; i++)
+    map_memory_internal((void*)TEXT_VIDEO_MEMORY,
+                        (void*)TEXT_VIDEO_MEMORY,
+                        TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t),
+                        PAGE_PRESENT | PAGE_WRITABLE);
+}
+
+static void parse_command_line(void)
+{
+    static char cmdline_copy[MAX_CMDLINE_LENGTH];
+    strcpy(cmdline_copy, cmdline);
+
+    char *token;
+    for (token = strtok(cmdline_copy, " "); token != NULL; token = strtok(NULL, " "))
     {
-        if (strcmp(name, &kernel_strtab[kernel_symtab[i].st_name]) == 0)
+        char *separator = strchr(token, ':');
+        if (separator == NULL) continue;
+
+        char *value = separator + 1;
+        *separator = '\0';
+
+        if (strcmp(token, "manager") == 0)
         {
-            return (void*)kernel_symtab[i].st_value;
+            manager_path = value;
         }
-    }
+        else if (strcmp(token, "debug") == 0)
+        {
+            char *ptr = strchr(value, ',');
 
-    return NULL;
+            if (ptr)
+            {
+                *ptr = '\0';
+                log_level_t min_level = *(ptr + 1) - '0';
+                if (min_level >= LOG_DEBUG || min_level <= LOG_CRITICAL) debug_min_level = min_level;
+            }
+
+            debug_channel = value;
+        }
+    }
 }
 
-void kernel_main(uintptr_t mboot_tags, size_t mboot_size)
+static handle_t start_system_manager(void)
 {
-    extern int _end;
+    char *root_disk = strdup(manager_path);
+    char *slash = strchr(root_disk, '/');
+    if (slash == NULL) KERNEL_CRASH("Invalid or missing system manager path");
+    *slash = 0;
 
-    int i = 0;
-    const char *manager_path = "";
+    log_write(LOG_NORMAL, "Mounting root disk: %s\n", root_disk);
+    dword_t ret = syscall_mount(root_disk, root_disk, NULL, MOUNT_FLAG_READONLY);
+    if (ret != ERR_SUCCESS) KERNEL_CRASH("Cannot mount root disk");
+    free(root_disk);
 
-    pre_initialization();
+    handle_t manager_process;
+    handle_t main_thread;
+
+    process_params_t parameters;
+    parameters.command_line = cmdline;
+    parameters.standard_input = INVALID_HANDLE;
+    parameters.standard_output = INVALID_HANDLE;
+    parameters.standard_error = INVALID_HANDLE;
 
-    clearscreen();
-    for (i = 0; i < 80; i++) putchar('-');
-    puts("The Monolithium Kernel 0.1 - By Alexander Andrejevic");
-    for (i = 0; i < 80; i++) putchar('-');
+    log_write(LOG_NORMAL, "Starting the system manager: %s\n", manager_path);
+    ret = syscall_create_process(manager_path, 0, &parameters, &manager_process, &main_thread);
+    if (ret != ERR_SUCCESS) KERNEL_CRASH("Cannot start system manager");
 
-    lowest_physical = PAGE_ALIGN_UP((uintptr_t)&_end) - 0x7FF00000;
-    if ((mboot_tags + mboot_size) > lowest_physical) lowest_physical = mboot_tags + mboot_size;
+    syscall_close_object(main_thread);
+    return manager_process;
+}
 
-    multiboot_tag_t *mboot = (multiboot_tag_t*)(PAGE_ALIGN_UP((uintptr_t)&_end) + PAGE_OFFSET(mboot_tags));
-    map_memory_internal((void*)mboot_tags, mboot, mboot_size, PAGE_PRESENT | PAGE_WRITABLE);
-    scan_multiboot_info(mboot);
+static void draw_progress_bar(void)
+{
+    static const char text[] = "The Monolithium kernel is loading, please wait...";
 
-    if (!mmap) KERNEL_CRASH("The bootloader failed to supply a memory map");
-    memory_init(mmap, PAGE_ALIGN_UP(lowest_physical));
-    heap_init();
+    word_t *video_mem = (word_t*)(video_initialized ? VIDEO_MEMORY : TEXT_VIDEO_MEMORY);
+    memset(video_mem, 0x00, TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t));
 
-    map_memory_internal((void*)TEXT_VIDEO_MEMORY,
-                        (void*)TEXT_VIDEO_MEMORY,
-                        TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t),
-                        PAGE_PRESENT | PAGE_WRITABLE);
+    int i;
+    size_t length = sizeof(text) - 1;
+    size_t text_start = 10 * TEXT_WIDTH + (TEXT_WIDTH - length) / 2;
+    for (i = 0; i < length; i++) video_mem[text_start + i] = text[i] | 0x0700;
 
-    if (kernel_sections) load_kernel_symbols();
+    video_mem[11 * TEXT_WIDTH + 14] = 0x07DA;
+    for (i = 15; i < TEXT_WIDTH - 15; i++) video_mem[11 * TEXT_WIDTH + i] = 0x07C4;
+    video_mem[12 * TEXT_WIDTH - 15] = 0x07BF;
 
-    printf("%-70s", "Initializing devices...");
-    device_init();
-    set_text_color(TEXT_COLOR_GREEN | TEXT_COLOR_STRONG);
-    puts("done");
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_GREEN | TEXT_COLOR_BLUE);
+    video_mem[12 * TEXT_WIDTH + 14] = video_mem[13 * TEXT_WIDTH - 15] = 0x07B3;
 
-    char *token;
-    for (token = strtok(cmdline, " "); token != NULL; token = strtok(NULL, " "))
-    {
-        char *separator = strchr(token, ':');
-        if (separator == NULL) continue;
+    video_mem[13 * TEXT_WIDTH + 14] = 0x07C0;
+    for (i = 15; i < TEXT_WIDTH - 15; i++) video_mem[13 * TEXT_WIDTH + i] = 0x07C4;
+    video_mem[14 * TEXT_WIDTH - 15] = 0x07D9;
+}
 
-        char *value = separator + 1;
-        *separator = '\0';
+static void advance_progress(void)
+{
+    word_t *video_mem = (word_t*)(video_initialized ? VIDEO_MEMORY : TEXT_VIDEO_MEMORY);
+    size_t old_status = tasks_completed * 50 / num_tasks;
+    size_t new_status = (tasks_completed + 1) * 50 / num_tasks;
 
-        if (strcmp(token, "manager") == 0) manager_path = value;
-    }
+    int i;
+    for (i = old_status; i < new_status; i++) video_mem[12 * TEXT_WIDTH + i + 15] = 0x7020;
+    tasks_completed++;
+}
 
-    printf("%-70s", "Initializing timer...");
-    timer_init();
-    set_text_color(TEXT_COLOR_GREEN | TEXT_COLOR_STRONG);
-    puts("done");
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_GREEN | TEXT_COLOR_BLUE);
-
-    printf("%-70s", "Initializing clock...");
-    clock_init();
-    set_text_color(TEXT_COLOR_GREEN | TEXT_COLOR_STRONG);
-    puts("done");
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_GREEN | TEXT_COLOR_BLUE);
-
-    printf("%-70s", "Initializing processes...");
-    process_init();
-    set_text_color(TEXT_COLOR_GREEN | TEXT_COLOR_STRONG);
-    puts("done");
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_GREEN | TEXT_COLOR_BLUE);
-
-    printf("%-70s", "Initializing threads...");
-    thread_init();
-    set_text_color(TEXT_COLOR_GREEN | TEXT_COLOR_STRONG);
-    puts("done");
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_GREEN | TEXT_COLOR_BLUE);
+void kernel_main(uintptr_t mboot_tags, size_t mboot_size)
+{
+    log_write(LOG_NORMAL, "Monolithium 0.1\n");
 
-    thread_t *idle;
-    ASSERT(create_system_thread(system_idle_thread, 0, THREAD_PRIORITY_IDLE, 0, NULL, &idle) == ERR_SUCCESS);
+    pre_initialization();
+    log_write(LOG_NORMAL, "Pre-initialization complete\n");
+
+    draw_progress_bar();
 
-    printf("%-70s", "Initializing users...");
-    user_init();
-    set_text_color(TEXT_COLOR_GREEN | TEXT_COLOR_STRONG);
-    puts("done");
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_GREEN | TEXT_COLOR_BLUE);
+    extern int _end;
+    lowest_physical = PAGE_ALIGN_UP((uintptr_t)&_end) - 0x7FF00000;
+    if ((mboot_tags + mboot_size) > lowest_physical) lowest_physical = mboot_tags + mboot_size;
 
-    printf("%s", "Scanning the PCI bus...\n");
-    pci_init();
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_GREEN | TEXT_COLOR_BLUE);
+    multiboot_tag_t *mboot = (multiboot_tag_t*)(PAGE_ALIGN_UP((uintptr_t)&_end) + PAGE_OFFSET(mboot_tags));
+    map_memory_internal((void*)mboot_tags, mboot, mboot_size, PAGE_PRESENT | PAGE_WRITABLE);
+    DO_TASK(scan_multiboot_info, mboot);
+    DO_TASK(parse_command_line);
+    DO_TASK(setup_memory_management);
+    if (kernel_sections) load_kernel_symbols();
+    DO_TASK(device_init);
+    DO_TASK(timer_init);
+    DO_TASK(clock_init);
+    DO_TASK(process_init);
+    DO_TASK(thread_init);
 
-    printf("%-70s", "Initializing video subsystem...");
-    video_init();
+    thread_t *idle;
+    ASSERT(create_system_thread(system_idle_thread, 0, THREAD_PRIORITY_IDLE, 0, NULL, &idle) == ERR_SUCCESS);
+
+    DO_TASK(user_init);
+    DO_TASK(pci_init);
+    DO_TASK(video_init);
     unmap_memory_internal((void*)TEXT_VIDEO_MEMORY, TEXT_HEIGHT * TEXT_WIDTH * sizeof(word_t));
     video_initialized = TRUE;
 
-    set_text_color(TEXT_COLOR_GREEN | TEXT_COLOR_STRONG);
-    puts("done");
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_GREEN | TEXT_COLOR_BLUE);
-
     multiboot_tag_t *tag;
     for (tag = mboot; tag->type != MULTIBOOT_INFO_END; tag = (multiboot_tag_t*)(((uintptr_t)tag + tag->size + 7) & ~7))
     {
@@ -269,54 +337,21 @@ void kernel_main(uintptr_t mboot_tags, size_t mboot_size)
             dword_t ret = module_load_from_physical(mod, module->string);
             if (ret == ERR_SUCCESS)
             {
-                printf("Loaded module %s at 0x%08X\n", mod->name, mod->base_address);
+                log_write(LOG_NORMAL, "Loaded module %s at 0x%08X\n", mod->name, mod->base_address);
             }
             else
             {
-                if (mod->name) printf("Cannot load module %s: %s\n", mod->name, get_error_string(ret));
-                else printf("Cannot load module from physical address 0x%08X: %s\n", module->mod_start, get_error_string(ret));
+                if (mod->name) log_write(LOG_ERROR, "Cannot load module %s: %s\n", mod->name, get_error_string(ret));
+                else log_write(LOG_ERROR, "Cannot load module from physical address 0x%08X: %s\n", module->mod_start, get_error_string(ret));
                 free(mod);
             }
 
+            advance_progress();
             // TODO: Reclaim pages
         }
     }
 
-    char *root_disk = strdup(manager_path);
-    char *slash = strchr(root_disk, '/');
-    if (slash == NULL) KERNEL_CRASH("Invalid or missing system manager path");
-    *slash = 0;
-
-    char message[256] = "Mounting root disk ";
-    strcat(message, root_disk);
-    strcat(message, "...");
-    printf("%-70s", message);
-
-    dword_t ret = syscall_mount(root_disk, root_disk, NULL, MOUNT_FLAG_READONLY);
-    if (ret != ERR_SUCCESS) KERNEL_CRASH("Cannot mount root disk");
-
-    free(root_disk);
-
-    set_text_color(TEXT_COLOR_GREEN | TEXT_COLOR_STRONG);
-    puts("done");
-    set_text_color(TEXT_COLOR_RED | TEXT_COLOR_GREEN | TEXT_COLOR_BLUE);
-
-    sprintf(message, "Starting system manager: %s", manager_path);
-    printf("%-70s", message);
-
-    handle_t manager_process;
-    handle_t main_thread;
-
-    process_params_t parameters;
-    parameters.command_line = "";
-    parameters.standard_input = INVALID_HANDLE;
-    parameters.standard_output = INVALID_HANDLE;
-    parameters.standard_error = INVALID_HANDLE;
-
-    ret = syscall_create_process(manager_path, 0, &parameters, &manager_process, &main_thread);
-    if (ret != ERR_SUCCESS) KERNEL_CRASH("Cannot start system manager");
-
-    syscall_close_object(main_thread);
+    handle_t manager_process = DO_TASK(start_system_manager);
     syscall_wait_process(manager_process, NO_TIMEOUT);
 
     KERNEL_CRASH("The system manager has stopped working");

+ 1 - 0
kernel/src/video.c

@@ -24,6 +24,7 @@
 #include <memory.h>
 #include <process.h>
 #include <syscalls.h>
+#include <stdio.h>
 
 static dword_t video_device_init(void);
 static dword_t video_device_cleanup(void);

+ 64 - 0
sdk/defs.h

@@ -77,4 +77,68 @@ typedef uint64_t qword_t;
 /* System call return value */
 typedef qword_t sysret_t;
 
+static inline void set_bit(dword_t *bitfield, dword_t bit)
+{
+    bitfield[bit >> 5] |= 1 << (bit & 0x1F);
+}
+
+static inline void clear_bit(dword_t *bitfield, dword_t bit)
+{
+    bitfield[bit >> 5] &= ~(1 << (bit & 0x1F));
+}
+
+static inline bool_t test_bit(dword_t *bitfield, dword_t bit)
+{
+    return (bitfield[bit >> 5] & (1 << (bit & 0x1F))) ? TRUE : FALSE;
+}
+
+static inline void push_to_stack(uintptr_t *stack, uintptr_t value)
+{
+    *stack -= sizeof(uintptr_t);
+    *((uintptr_t*)(*stack)) = value;
+}
+
+static inline uintptr_t pop_from_stack(uintptr_t *stack)
+{
+    uintptr_t value = *((uintptr_t*)(*stack));
+    *stack += sizeof(uintptr_t);
+    return value;
+}
+
+static inline const char *get_error_string(dword_t err_num)
+{
+    static const char *error_strings[] = {
+        "ERR_SUCCESS",
+        "ERR_NOTFOUND",
+        "ERR_FORBIDDEN",
+        "ERR_INVALID",
+        "ERR_EXISTS",
+        "ERR_NOMEMORY",
+        "ERR_HARDWARE",
+        "ERR_BUSY",
+        "ERR_NOMEDIA",
+        "ERR_NOTRESP",
+        "ERR_WRITEPROT",
+        "ERR_NOSYSCALL",
+        "ERR_TIMEOUT",
+        "ERR_BADPTR",
+        "ERR_CANCELED",
+        "ERR_ISDIR",
+        "ERR_ISNOTDIR",
+        "ERR_DISKFULL",
+        "ERR_MEDIACHG"
+    };
+
+    if (err_num == 0)
+    {
+        return error_strings[0];
+    }
+    else if (err_num >= 0xE0000000)
+    {
+        if (err_num < MAX_ERR) return error_strings[err_num - 0xE0000000];
+    }
+
+    return NULL;
+}
+
 #endif

+ 37 - 0
sdk/thread.h

@@ -24,6 +24,8 @@
 
 #include "defs.h"
 
+typedef dword_t (*thread_procedure_t)(void*);
+
 typedef qword_t affinity_t;
 
 typedef enum
@@ -51,6 +53,41 @@ typedef struct
     byte_t fpu_state[512];
 } thread_state_t;
 
+static inline void init_thread_stack(uintptr_t *stack_pointer, void *parameter)
+{
+    static const byte_t thread_end_code[] = {
+        /* push eax */
+        0x50,
+
+        /* push INVALID_HANDLE */
+        0x68,
+        INVALID_HANDLE & 0xFF,
+        (INVALID_HANDLE >> 8) & 0xFF,
+        (INVALID_HANDLE >> 16) & 0xFF,
+        (INVALID_HANDLE >> 24) & 0xFF,
+
+        /* mov eax, SYSCALL_TERMINATE_THREAD */
+        0xB8,
+        SYSCALL_TERMINATE_THREAD & 0xFF,
+        (SYSCALL_TERMINATE_THREAD >> 8) & 0xFF,
+        (SYSCALL_TERMINATE_THREAD >> 16) & 0xFF,
+        SYSCALL_TERMINATE_THREAD >> 24,
+
+        /* mov edx, esp */
+        0x8B, 0xD4,
+
+        /* int SYSCALL_INTERRUPT */
+        0xCD, SYSCALL_INTERRUPT
+    };
+
+    *stack_pointer -= (sizeof(thread_end_code) + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
+    __builtin_memcpy((void*)*stack_pointer, thread_end_code, sizeof(thread_end_code));
+
+    uintptr_t end_code_addr = *stack_pointer;
+    push_to_stack(stack_pointer, (uintptr_t)parameter);
+    push_to_stack(stack_pointer, end_code_addr);
+}
+
 sysret_t syscall_open_thread(dword_t tid, handle_t *handle);
 sysret_t syscall_create_thread(handle_t process, thread_state_t *initial_state, dword_t flags, priority_t priority, handle_t *new_thread);
 sysret_t syscall_terminate_thread(handle_t thread, dword_t return_value);