Implement serial logging. Finish modularizing power management.
[monolithium.git] / kernel / src / exec / aout.c
index 4c76ad3c8ea5572f6bf6722518cd9a9afa4d8c38..6d071962b88a9987e458b0a3a519c101e0cb335d 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * aout.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
 
 #include <exec/aout.h>
 #include <memory.h>
+#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;
     char filename[MAX_PATH];
     qword_t filesize;
+    uintptr_t i;
 
     dword_t ret = syscall(SYSCALL_QUERY_FILE, file, FILE_INFO_NAME, filename, sizeof(filename));
     if (ret != ERR_SUCCESS) return ret;
@@ -38,6 +40,8 @@ dword_t load_aout(handle_t file, process_params_t *parameters, thread_state_t *i
     if (ret != ERR_SUCCESS) return ret;
 
     void *address = (void*)0x7FE00000;
+    void *data_address;
+    void *bss_address;
 
     ret = syscall(SYSCALL_ALLOC_MEMORY,
                   INVALID_HANDLE,
@@ -45,17 +49,18 @@ dword_t load_aout(handle_t file, process_params_t *parameters, thread_state_t *i
                   0x200000,
                   MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_WRITABLE | MEMORY_BLOCK_USERMODE | MEMORY_BLOCK_EVICTABLE);
     if (ret != ERR_SUCCESS) return ret;
-    initial_state->regs.esp = (uintptr_t)address + 0x200000 - (MAX_PARAMETERS * sizeof(uintptr_t)) - sizeof(process_params_t);
 
-    *(process_params_t*)initial_state->regs.esp = *parameters;
-    push_to_stack(&initial_state->regs.esp, initial_state->regs.esp);
+    initial_state->regs.esp = (uintptr_t)address + 0x200000;
 
-    address = (void*)0x100000;
+    address = (void*)0x1000;
 
     switch (header.midmag & 0xFFFF)
     {
     case OMAGIC:
     {
+        data_address = (void*)((uintptr_t)address + header.text_size + sizeof(aout_header_t));
+        bss_address = (void*)((uintptr_t)address + header.text_size + header.data_size + sizeof(aout_header_t));
+
         ret = syscall(SYSCALL_ALLOC_MEMORY,
                       INVALID_HANDLE,
                       &address,
@@ -81,8 +86,8 @@ dword_t load_aout(handle_t file, process_params_t *parameters, thread_state_t *i
     case ZMAGIC:
     {
         handle_t section;
-        void *data_address = (void*)((uintptr_t)address + PAGE_ALIGN_UP(header.text_size));
-        void *bss_address = (void*)((uintptr_t)address + PAGE_ALIGN_UP(header.text_size) + PAGE_ALIGN_UP(header.data_size));
+        data_address = (void*)((uintptr_t)address + PAGE_ALIGN_UP(header.text_size));
+        bss_address = (void*)((uintptr_t)address + PAGE_ALIGN_UP(header.text_size) + PAGE_ALIGN_UP(header.data_size));
 
         ret = syscall(SYSCALL_CREATE_MEMORY_SECTION, filename, file, (size_t)filesize, MEMORY_SECTION_WRITABLE, &section);
         if (ret != ERR_SUCCESS) return ret;
@@ -91,9 +96,13 @@ 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)),
-                      MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_USERMODE | MEMORY_BLOCK_EXECUTABLE | MEMORY_BLOCK_EVICTABLE);
+                      (qword_t)sizeof(aout_header_t),
+                      PAGE_ALIGN_UP(header.text_size),
+                      MEMORY_BLOCK_ACCESSIBLE
+                      | MEMORY_BLOCK_WRITABLE
+                      | MEMORY_BLOCK_USERMODE
+                      | MEMORY_BLOCK_EXECUTABLE
+                      | MEMORY_BLOCK_EVICTABLE);
         if (ret != ERR_SUCCESS)
         {
             syscall(SYSCALL_CLOSE_OBJECT, section);
@@ -134,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;
     }
 
@@ -142,6 +151,166 @@ dword_t load_aout(handle_t file, process_params_t *parameters, thread_state_t *i
         return ERR_INVALID;
     }
 
-    // TODO: relocations
-    return ERR_SUCCESS; // TODO
+    uintptr_t num_text_relocs = header.text_reloc_size / sizeof(aout_reloc_t);
+    uintptr_t num_data_relocs = header.data_reloc_size / sizeof(aout_reloc_t);
+    uintptr_t num_symbols = header.sym_size / sizeof(aout_symbol_t);
+    aout_reloc_t *text_relocs = NULL;
+    aout_reloc_t *data_relocs = NULL;
+    aout_symbol_t *symbols = NULL;
+    uintptr_t string_table_size = 0;
+    char *string_table = NULL;
+
+    if (header.text_reloc_size)
+    {
+        text_relocs = (aout_reloc_t*)malloc(header.text_reloc_size);
+        if (text_relocs == NULL) return ERR_NOMEMORY;
+
+        ret = syscall(SYSCALL_READ_FILE,
+                      file,
+                      text_relocs,
+                      (qword_t)(sizeof(aout_header_t) + header.text_size + header.data_size),
+                      header.text_reloc_size,
+                      &bytes_read);
+        if (ret != ERR_SUCCESS) goto cleanup;
+    }
+
+    if (header.data_reloc_size)
+    {
+        data_relocs = (aout_reloc_t*)malloc(header.data_reloc_size);
+        if (data_relocs == NULL) return ERR_NOMEMORY;
+
+        ret = syscall(SYSCALL_READ_FILE,
+                      file,
+                      data_relocs,
+                      (qword_t)(sizeof(aout_header_t)
+                                + header.text_size
+                                + header.data_size
+                                + header.text_reloc_size),
+                      header.data_reloc_size,
+                      &bytes_read);
+        if (ret != ERR_SUCCESS) goto cleanup;
+    }
+
+    if (header.sym_size)
+    {
+        symbols = (aout_symbol_t*)malloc(header.sym_size);
+        if (symbols == NULL) return ERR_NOMEMORY;
+
+        ret = syscall(SYSCALL_READ_FILE,
+                      file,
+                      symbols,
+                      (qword_t)(sizeof(aout_header_t)
+                                + header.text_size
+                                + header.data_size
+                                + header.text_reloc_size
+                                + header.data_reloc_size),
+                      header.sym_size,
+                      &bytes_read);
+        if (ret != ERR_SUCCESS) goto cleanup;
+    }
+
+    ret = syscall(SYSCALL_READ_FILE,
+                  file,
+                  &string_table_size,
+                  (qword_t)(sizeof(aout_header_t)
+                            + header.text_size
+                            + header.data_size
+                            + header.sym_size
+                            + header.text_reloc_size
+                            + header.data_reloc_size),
+                  sizeof(string_table_size),
+                  &bytes_read);
+    if (ret != ERR_SUCCESS) goto cleanup;
+
+    string_table = malloc(string_table_size);
+    if (string_table == NULL)
+    {
+        ret = ERR_NOMEMORY;
+        goto cleanup;
+    }
+
+    ret = syscall(SYSCALL_READ_FILE,
+                  file,
+                  string_table,
+                  (qword_t)(sizeof(aout_header_t)
+                            + header.text_size
+                            + header.data_size
+                            + header.sym_size
+                            + header.text_reloc_size
+                            + header.data_reloc_size),
+                  string_table_size,
+                  &bytes_read);
+    if (ret != ERR_SUCCESS) goto cleanup;
+
+    for (i = 0; i < num_symbols; i++)
+    {
+        symbols[i].name = (char*)((uintptr_t)string_table + symbols[i].name_offset);
+
+        switch (AOUT_TYPE_FIELD(symbols[i].type))
+        {
+        case AOUT_SYM_UNDEFINED:
+            // TODO: Resolve symbol
+            break;
+
+        case AOUT_SYM_TEXT:
+            symbols[i].value += (uintptr_t)address + sizeof(aout_header_t);
+            break;
+
+        case AOUT_SYM_DATA:
+            symbols[i].value += (uintptr_t)data_address;
+            break;
+
+        case AOUT_SYM_BSS:
+            symbols[i].value += (uintptr_t)bss_address;
+            break;
+        }
+    }
+
+    for (i = 0; i < num_text_relocs + num_data_relocs; i++)
+    {
+        aout_reloc_t *reloc = (i < num_text_relocs) ? &text_relocs[i] : &data_relocs[i];
+        uintptr_t base_address = (i < num_text_relocs) ? ((uintptr_t)address + sizeof(aout_header_t)) : (uintptr_t)data_address;
+        dword_t offset;
+
+        if (!reloc->external)
+        {
+            offset = (uintptr_t)address + sizeof(aout_header_t);
+        }
+        else
+        {
+            if (reloc->symbol_num >= num_symbols)
+            {
+                ret = ERR_INVALID;
+                goto cleanup;
+            }
+
+            offset = symbols[reloc->symbol_num].value;
+        }
+
+        switch (reloc->length)
+        {
+        case 0:
+            *(byte_t*)(base_address + reloc->address) += offset;
+            break;
+        case 1:
+            *(word_t*)(base_address + reloc->address) += offset;
+            break;
+        case 2:
+            *(dword_t*)(base_address + reloc->address) += offset;
+            break;
+        }
+    }
+
+    if ((header.midmag & 0xFFFF) == ZMAGIC)
+    {
+        syscall(SYSCALL_SET_MEMORY_FLAGS,
+                INVALID_HANDLE,
+                address,
+                MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_USERMODE | MEMORY_BLOCK_EXECUTABLE | MEMORY_BLOCK_EVICTABLE);
+    }
+
+cleanup:
+    if (symbols) free(symbols);
+    if (string_table) free(string_table);
+    return ret;
 }