ソースを参照

feat: build and link user space programs

greatbridf 2 年 前
コミット
e6dc019e17

+ 10 - 2
CMakeLists.txt

@@ -37,7 +37,7 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O")
 endif()
 
-include_directories(${PROJECT_SOURCE_DIR}/include)
+include_directories(${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/user-space-program/build)
 
 set(KERNEL_MAIN_SOURCES src/kernel_main.c
                         src/kernel/errno.c
@@ -94,11 +94,19 @@ add_custom_command(OUTPUT extracted_kernel_main
     COMMAND ${CMAKE_AR} xf ${PROJECT_BINARY_DIR}/libkernel_main.a --output=${EXTRACT_DIR}
 )
 
+add_custom_command(OUTPUT user_space_programs
+    COMMAND make -C ${CMAKE_SOURCE_DIR}/user-space-program all
+    COMMAND mkdir -p ${CMAKE_SOURCE_DIR}/user-space-program/build
+    COMMAND rm -f ${CMAKE_SOURCE_DIR}/user-space-program/build/*
+    COMMAND cp ${CMAKE_SOURCE_DIR}/user-space-program/*.res ${CMAKE_SOURCE_DIR}/user-space-program/build
+)
+
 add_custom_target(kernel.out
     DEPENDS extracted_bootloader
     DEPENDS extracted_kernel_main
+    DEPENDS user_space_programs
     DEPENDS ${CMAKE_SOURCE_DIR}/ldscript.ld
-    COMMAND ${CMAKE_LINKER} -T ${CMAKE_SOURCE_DIR}/ldscript.ld ${EXTRACT_DIR}/*.o
+    COMMAND ${CMAKE_LINKER} -T ${CMAKE_SOURCE_DIR}/ldscript.ld ${EXTRACT_DIR}/*.o ${CMAKE_SOURCE_DIR}/user-space-program/user.sym
     -melf_i386 -o ${CMAKE_BINARY_DIR}/kernel.out
 )
 

+ 1 - 1
src/asm/interrupt.s

@@ -210,7 +210,7 @@ syscall_stub:
     andl $0xfffffff0, %esp
     movl %eax, (%esp)
 
-    call *syscall_handlers(%ebx)
+    call *syscall_handlers(,%ebx,4)
 
     # restore stack
     popl %esp

+ 4 - 17
src/kernel/process.cpp

@@ -5,6 +5,8 @@
 #include <kernel/stdio.h>
 #include <kernel_main.h>
 #include <types/types.h>
+#include <hello-world.res>
+#include <interrupt-test.res>
 
 extern "C" void NORETURN go_user_space(void* eip);
 
@@ -87,25 +89,10 @@ void NORETURN init_scheduler()
     processes = types::kernel_allocator_new<types::list<process>>();
     ready_thds = types::kernel_allocator_new<types::list<thread*>>();
 
-    // movl $0x01919810, %eax
-    // movl $0x00114514, %ebx
-    // movl $0x00000001, %eax
-    // int $0x80
-    unsigned char instruction1[] = {
-        0xb8, 0x10, 0x98, 0x91, 0x01, 0xbb, 0x14, 0x45, 0x11, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0xcd, 0x80
-    };
-
-    // movl $0x19198100, %eax
-    // movl $0x11451400, %ebx
-    // jmp $.
-    uint8_t instruction2[] = {
-        0xb8, 0x00, 0x81, 0x19, 0x19, 0xbb, 0x00, 0x14, 0x45, 0x11, 0xeb, 0xfe
-    };
-
     void* user_space_start = reinterpret_cast<void*>(0x40000000U);
 
-    processes->emplace_back(user_space_start, instruction1, sizeof(instruction1), false);
-    processes->emplace_back(user_space_start, instruction2, sizeof(instruction2), false);
+    processes->emplace_back(user_space_start, hello_world_bin, hello_world_bin_len, false);
+    processes->emplace_back(user_space_start, interrupt_test_bin, interrupt_test_bin_len, false);
 
     // we need interrupts enabled for cow mapping
     asm_cli();

+ 16 - 2
src/kernel/syscall.cpp

@@ -1,4 +1,6 @@
+#include <asm/port_io.h>
 #include <kernel/syscall.hpp>
+#include <kernel/tty.h>
 
 syscall_handler syscall_handlers[8];
 
@@ -14,11 +16,23 @@ void _syscall_fork(syscall_stack_data* data)
     data->s_regs.edx = 0xfefefefe;
 }
 
+void _syscall_write(syscall_stack_data* data)
+{
+    tty_print(console, reinterpret_cast<const char*>(data->s_regs.edi));
+    data->s_regs.eax = 0;
+    data->s_regs.edx = 0;
+}
+
+void _syscall_sleep(syscall_stack_data* data)
+{
+    ++data->s_regs.ecx;
+}
+
 void init_syscall(void)
 {
     syscall_handlers[0] = _syscall_fork;
-    syscall_handlers[1] = _syscall_not_impl;
-    syscall_handlers[2] = _syscall_not_impl;
+    syscall_handlers[1] = _syscall_write;
+    syscall_handlers[2] = _syscall_sleep;
     syscall_handlers[3] = _syscall_not_impl;
     syscall_handlers[4] = _syscall_not_impl;
     syscall_handlers[5] = _syscall_not_impl;

+ 1 - 1
src/kernel_main.c

@@ -199,6 +199,6 @@ void NORETURN kernel_main(void)
     struct inode* init = vfs_open("/init");
     vfs_read(init, buf, 128, 1, 10);
 
-    printkf("switching execution to the scheduler...");
+    printkf("switching execution to the scheduler...\n");
     init_scheduler(&tss);
 }

+ 4 - 0
user-space-program/.gitignore

@@ -0,0 +1,4 @@
+*.o
+*.bin
+*.res
+user.sym

+ 29 - 0
user-space-program/Makefile.src

@@ -0,0 +1,29 @@
+CROSS_COMPILE=
+CC=$(CROSS_COMPILE)gcc
+LD=$(CROSS_COMPILE)ld
+XXD=xxd
+
+RES=hello-world.res interrupt-test.res
+OBJS=hello-world.o interrupt-test.o
+
+all: user.sym $(RES)
+	mkdir -p build
+	cp $(RES) build
+
+user.sym: $(OBJS) output_symbols.ld
+	$(LD) -r -T output_symbols.ld $(OBJS) -o user.sym
+
+%.o: %.s
+	$(CC) -c -g -m32 -o $@ $<
+
+%.bin: %.o output_code.ld
+	$(LD) -T output_code.ld $< -o $@
+
+%.res: %.bin
+	$(XXD) -i $< $@
+
+.PHONY: clean
+clean:
+	-rm $(OBJS)
+	-rm $(RES)
+	-rm user.sym

+ 8 - 0
user-space-program/hello-world.s

@@ -0,0 +1,8 @@
+.code32
+.section .text.user-space
+
+.globl user_hello_world
+user_hello_world:
+	movl $0xcbcbcbcb, %eax
+	movl $0xacacacac, %ebx
+	jmp .

+ 18 - 0
user-space-program/interrupt-test.s

@@ -0,0 +1,18 @@
+.code32
+.section .text.user-space
+
+.globl user_interrupt_test
+user_interrupt_test:
+# write
+	movl $1, %eax
+	movl $__user_interrupt_test_string, %edi
+	int $0x80
+# sleep
+	movl $2, %eax
+	movl $0xffffffff, %edi
+	int $0x80
+# noreturn
+	jmp .
+
+__user_interrupt_test_string:
+	.ascii "syscall 0x01 write: hello from user space\n\0"

+ 20 - 0
user-space-program/output_code.ld

@@ -0,0 +1,20 @@
+OUTPUT_FORMAT(binary)
+OUTPUT_ARCH(i386:i386)
+
+SECTIONS
+{
+    .text 0x40000000 : AT(0x00)
+    {
+        *(.text*)
+        *(.rodata*)
+        *(.data)
+        *(.data*)
+        *(.bss)
+        *(.bss*)
+    }
+
+    /DISCARD/ :
+    {
+        *(.note.gnu.property)
+    }
+}

+ 47 - 0
user-space-program/output_symbols.ld

@@ -0,0 +1,47 @@
+OUTPUT_FORMAT(elf32-i386)
+OUTPUT_ARCH(i386:i386)
+
+SECTIONS
+{
+    /DISCARD/ :
+    {
+        *(.text*)
+        *(.data)
+        *(.data*)
+        *(.note.gnu.property)
+    }
+
+    /* Stabs debugging sections.  */
+    .stab          0 : { *(.stab) }
+    .stabstr       0 : { *(.stabstr) }
+    .stab.excl     0 : { *(.stab.excl) }
+    .stab.exclstr  0 : { *(.stab.exclstr) }
+    .stab.index    0 : { *(.stab.index) }
+    .stab.indexstr 0 : { *(.stab.indexstr) }
+    .comment       0 : { *(.comment) }
+    /* DWARF debug sections.
+       Symbols in the DWARF debugging sections are relative to the beginning
+       of the section so we begin them at 0.  */
+    /* DWARF 1 */
+    .debug          0 : { *(.debug) }
+    .line           0 : { *(.line) }
+    /* GNU DWARF 1 extensions */
+    .debug_srcinfo  0 : { *(.debug_srcinfo) }
+    .debug_sfnames  0 : { *(.debug_sfnames) }
+    /* DWARF 1.1 and DWARF 2 */
+    .debug_aranges  0 : { *(.debug_aranges) }
+    .debug_pubnames 0 : { *(.debug_pubnames) }
+    /* DWARF 2 */
+    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+    .debug_abbrev   0 : { *(.debug_abbrev) }
+    .debug_line     0 : { *(.debug_line) }
+    .debug_frame    0 : { *(.debug_frame) }
+    .debug_str      0 : { *(.debug_str) }
+    .debug_loc      0 : { *(.debug_loc) }
+    .debug_macinfo  0 : { *(.debug_macinfo) }
+    /* SGI/MIPS DWARF 2 extensions */
+    .debug_weaknames 0 : { *(.debug_weaknames) }
+    .debug_funcnames 0 : { *(.debug_funcnames) }
+    .debug_typenames 0 : { *(.debug_typenames) }
+    .debug_varnames  0 : { *(.debug_varnames) }
+}