diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..e88febc6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "files.associations": { + "array": "c", + "string_view": "c", + "initializer_list": "c", + "utility": "c", + "typeinfo": "c", + "compare": "c", + "functional": "c", + "tuple": "c", + "type_traits": "c", + "unistd.h": "c", + "assert.h": "c", + "kernel.h": "c", + "paging.h": "c", + "zone_allocator.h": "c", + "buddysystem.h": "c" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..f0b1a345 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,11 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Compile and Run in Debug", + "type": "shell", + "command":"cmake --build ${workspaceRoot}/build --target all filesystem qemu-gdb", + "isBackground": true + } + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e885d7dd..8b19ed3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,23 +76,23 @@ endif() # ASSEMBLY COMPILER # ============================================================================= -# Find the NASM compiler. -find_program(ASM_COMPILER NAMES nasm HINTS /usr/bin/ /usr/local/bin/) -# Mark the variable ASM_COMPILER as advanced. -mark_as_advanced(ASM_COMPILER) -# Check that we have found the compiler. -if(NOT ASM_COMPILER) - message(FATAL_ERROR "ASM compiler not found!") -endif(NOT ASM_COMPILER) -# Set the asm compiler. -set(CMAKE_ASM_COMPILER ${ASM_COMPILER}) +# Set the ASM compiler to GCC explicitly. +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) + # Set the assembly compiler flags. +# Adjust for debug and release builds. if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(CMAKE_ASM_COMPILE_OBJECT " -f elf -g -O0 -F dwarf -o ") + set(CMAKE_ASM_FLAGS "-m32 -g") else() - set(CMAKE_ASM_COMPILE_OBJECT " -f elf -g -O3 -o ") + set(CMAKE_ASM_FLAGS "-m32 -O3") endif() +# Ensure assembly files are compiled properly. +set(CMAKE_ASM_COMPILE_OBJECT "${CMAKE_ASM_COMPILER} ${CMAKE_ASM_FLAGS} -c -o ") + +# Enable assembly language in the project. +enable_language(ASM) + # ============================================================================= # GLOBAL COMPILATION FLAGS # ============================================================================= @@ -135,8 +135,6 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Release") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") endif(CMAKE_BUILD_TYPE STREQUAL "Debug") -# Set the assembly compiler flags. -set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -m32") # ============================================================================= # SUB-DIRECTORIES SETUP diff --git a/libc/src/crt0.S b/libc/src/crt0.S index 665b3522..198f4302 100644 --- a/libc/src/crt0.S +++ b/libc/src/crt0.S @@ -1,15 +1,19 @@ -extern main -extern __libc_start_main -global _start +# External functions +.extern main +.extern __libc_start_main -; ----------------------------------------------------------------------------- -; SECTION (text) -; ----------------------------------------------------------------------------- -section .text -_start: ; _start is the entry point known to the linker - mov ebp, 0 ; Set ebp to 0 as x86 programs require - push main ; Push the pointer to `main` to the stack. - call __libc_start_main ; Call the libc initialization function. - mov ebx, eax ; Move `main` return value to ebx. - mov eax, 1 ; Call the `exit` function by using `int 80` (i.e., a system call) - int 0x80 +# Global entry point +.global _start + +# ----------------------------------------------------------------------------- +# SECTION (text) +# ----------------------------------------------------------------------------- +.section .text + +_start: # _start is the entry point known to the linker + movl $0, %ebp # Set ebp to 0 as x86 programs require + pushl $main # Push the pointer to `main` onto the stack + call __libc_start_main # Call the libc initialization function + movl %eax, %ebx # Move `main` return value to ebx + movl $1, %eax # Exit system call number + int $0x80 # Perform system call diff --git a/mentos/CMakeLists.txt b/mentos/CMakeLists.txt index d1cfd67f..a0d5e7af 100644 --- a/mentos/CMakeLists.txt +++ b/mentos/CMakeLists.txt @@ -105,7 +105,7 @@ set(KERNEL_SOURCES ${CMAKE_SOURCE_DIR}/mentos/src/process/scheduler.c ${CMAKE_SOURCE_DIR}/mentos/src/process/process.c ${CMAKE_SOURCE_DIR}/mentos/src/process/wait.c - ${CMAKE_SOURCE_DIR}/mentos/src/process/user.S + ${CMAKE_SOURCE_DIR}/mentos/src/process/user.s ${CMAKE_SOURCE_DIR}/mentos/src/sys/utsname.c ${CMAKE_SOURCE_DIR}/mentos/src/sys/module.c ${CMAKE_SOURCE_DIR}/mentos/src/system/errno.c @@ -217,7 +217,7 @@ endif() add_library( ${BOOTLOADER_NAME} src/boot.c - src/boot.S + src/boot.s ) # Add the includes. target_include_directories( diff --git a/mentos/boot.lds b/mentos/boot.lds index ad47a4ae..1fd31f96 100644 --- a/mentos/boot.lds +++ b/mentos/boot.lds @@ -3,54 +3,39 @@ OUTPUT_FORMAT("elf32-i386") ENTRY(boot_entry) MEMORY { - BOOTLOADER_MEM : ORIGIN = 0x00000000, LENGTH = 128M + BOOTLOADER_MEM : ORIGIN = 0x00100000, LENGTH = 128M } SECTIONS { - . = 0x00100000; - _bootloader_start = .; - .multiboot . : AT(ADDR(.multiboot)) - { - . = ALIGN(4); - _multiboot_header_start = .; - *(.multiboot_header) - _multiboot_header_end = .; - } > BOOTLOADER_MEM - - /* Put the .text section. */ - .text . : AT(ADDR(.text)) - { - _text_start = .; + . = ORIGIN(BOOTLOADER_MEM); + + # Put a symbol end here, it tells us where all the kernel code/data starts. + _bootloader_start = .; + + .multiboot_header ALIGN(4) : AT(ORIGIN(BOOTLOADER_MEM)) { + _multiboot_header_start = .; + *(.multiboot_header) + _multiboot_header_end = .; + } > BOOTLOADER_MEM + + .text ALIGN(4) : { *(.text) - _text_end = .; } > BOOTLOADER_MEM - /* Read-only data. */ - .rodata ALIGN(4K) : AT(ADDR(.rodata)) - { - _rodata_start = .; + .rodata ALIGN(4) : { *(.rodata) - _rodata_end = .; + *(.rodata.*) } > BOOTLOADER_MEM - /* Read-write data (initialized) */ - .data ALIGN(4K) : AT(ADDR(.data)) - { - _data_start = .; + .data ALIGN(4) : { *(.data) - _data_end = .; } > BOOTLOADER_MEM - /* Read-write data (uninitialized) and stack */ - .bss ALIGN(4K) : AT(ADDR(.bss)) - { - _bss_start = .; - *(.bss*) - _bss_end = .; + .bss ALIGN(16) : { + *(.bss) } > BOOTLOADER_MEM - /* Put a symbol end here, it tells us where all the kernel code/data ends, - it means everything after 'end' can be used for something else. */ + # Put a symbol end here, it tells us where all the kernel code/data ends. _bootloader_end = .; } diff --git a/mentos/kernel.lds b/mentos/kernel.lds index 32b1d415..22826578 100644 --- a/mentos/kernel.lds +++ b/mentos/kernel.lds @@ -8,43 +8,25 @@ MEMORY { KERNEL_HIGHMEM : ORIGIN = 0xF8000000, LENGTH = 128M } - SECTIONS { . = 0xC0000000; - /* Put the .text section. */ - .text . : AT(ADDR(.text)) - { - _text_start = .; + + .text : AT(ORIGIN(KERNEL_LOWMEM)) { EXCLUDE_FILE(*boot.*.o) *(.text) - _text_end = .; } > KERNEL_LOWMEM - /* Read-only data. */ - .rodata ALIGN(4K) : AT(ADDR(.rodata)) - { - _rodata_start = .; + .rodata ALIGN(4K) : { EXCLUDE_FILE(*boot.*.o) *(.rodata) - _rodata_end = .; } > KERNEL_LOWMEM - /* Read-write data (initialized) */ - .data ALIGN(4K) : AT(ADDR(.data)) - { - _data_start = .; + .data ALIGN(4K) : { EXCLUDE_FILE(*boot.*.o) *(.data) - _data_end = .; } > KERNEL_LOWMEM - /* Read-write data (uninitialized) and stack */ - .bss ALIGN(4K) : AT(ADDR(.bss)) - { - _bss_start = .; + .bss ALIGN(4K) : { *(.bss*) - _bss_end = .; } > KERNEL_LOWMEM - /* Put a symbol end here, it tells us where all the kernel code/data ends, - it means everything after 'end' can be used for something else. */ _kernel_end = .; } diff --git a/mentos/src/boot.S b/mentos/src/boot.S deleted file mode 100644 index d48bf190..00000000 --- a/mentos/src/boot.S +++ /dev/null @@ -1,103 +0,0 @@ -; MentOS, The Mentoring Operating system project -; @file boot.asm -; @brief Kernel start location, multiboot header -; @copyright (c) 2014-2021 This file is distributed under the MIT License. -; See LICENSE.md for details. - -bits 32 ; All instructions should be 32-bit. -extern boot_main ; The start point of our C code - -; The magic field should contain this. -MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 -; This should be in %eax. -MULTIBOOT_BOOTLOADER_MAGIC equ 0x2BADB002 - -; = Specify what GRUB should PROVIDE ========================================= -; Align the kernel and kernel modules on i386 page (4KB) boundaries. -MULTIBOOT_PAGE_ALIGN equ 0x00000001 -; Provide the kernel with memory information. -MULTIBOOT_MEMORY_INFO equ 0x00000002 -; Must pass video information to OS. -MULTIBOOT_VIDEO_MODE equ 0x00000004 -; ----------------------------------------------------------------------------- - -; This is the flag combination that we prepare for Grub -; to read at kernel load time. -MULTIBOOT_HEADER_FLAGS equ (MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO) -; Grub reads this value to make sure it loads a kernel -; and not just garbage. -MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) - -LOAD_MEMORY_ADDRESS equ 0x00000000 -; reserve (1024*1024) for the stack on a doubleword boundary -KERNEL_STACK_SIZE equ 0x100000 - -; ----------------------------------------------------------------------------- -; SECTION (multiboot_header) -; ----------------------------------------------------------------------------- -section .multiboot_header -align 4 -; This is the GRUB Multiboot header. -multiboot_header: - ; magic - dd MULTIBOOT_HEADER_MAGIC - ; flags - dd MULTIBOOT_HEADER_FLAGS - ; checksum - dd MULTIBOOT_CHECKSUM - -; ----------------------------------------------------------------------------- -; SECTION (data) -; ----------------------------------------------------------------------------- -; section .data nobits -; align 4096 - -; ----------------------------------------------------------------------------- -; SECTION (text) -; ----------------------------------------------------------------------------- -section .text -global boot_entry -boot_entry: - ; Clear interrupt flag [IF = 0]; 0xFA - cli - ; To set up a stack, we simply set the esp register to point to the top of - ; our stack (as it grows downwards). - mov esp, stack_top - ; pass the initial ESP - push esp - ; pass Multiboot info structure - push ebx - ; pass Multiboot magic number - push eax - ; Call the boot_main() function inside boot.c - call boot_main - ; Set interrupt flag [IF = 1]; 0xFA - ; Clear interrupts and hang if we return from boot_main - cli -hang: - hlt - jmp hang - -global boot_kernel -boot_kernel: - mov edx, [esp + 4] ; stack_pointer - mov ebx, [esp + 8] ; entry - mov eax, [esp + 12] ; boot info - mov esp, edx ; set stack pointer - push eax ; push the boot info - call ebx ; call the kernel main - - -; ----------------------------------------------------------------------------- -; SECTION (bss) -; ----------------------------------------------------------------------------- -section .bss -align 16 - -global stack_bottom -stack_bottom: - resb KERNEL_STACK_SIZE - -global stack_top -stack_top: - ; the top of the stack is the bottom because the stack counts down diff --git a/mentos/src/boot.c b/mentos/src/boot.c index 102cd2e5..94b5c304 100644 --- a/mentos/src/boot.c +++ b/mentos/src/boot.c @@ -49,19 +49,41 @@ static inline void __outportb(uint16_t port, uint8_t data) __asm__ __volatile__("outb %%al, %%dx" ::"a"(data), "d"(port)); } -/// @brief Writes the given character on the debug port. -/// @param c the character to send to the debug port. +/// @brief Reads a byte from the given port. +/// @param port The input port. +/// @return The byte read from the port. +static inline uint8_t __inportb(uint16_t port) +{ + uint8_t result; + __asm__ __volatile__("inb %%dx, %%al" : "=a"(result) : "d"(port)); + return result; +} + +/// @brief Waits until the serial port is ready to transmit. +/// @param port The base port of the serial device. +static inline void __serial_wait(uint16_t port) +{ + while ((__inportb(port + 5) & 0x20) == 0); // Wait until Transmitter Holding Register is empty +} + +/// @brief Writes the given character to the debug port. +/// @param c The character to send to the debug port. static inline void __debug_putchar(char c) { + __serial_wait(SERIAL_COM1); + if (c == '\n') { + __outportb(SERIAL_COM1, '\r'); + __serial_wait(SERIAL_COM1); + } __outportb(SERIAL_COM1, c); } -/// @brief Writes the given string on the debug port. -/// @param s the string to send to the debug port. -static inline void __debug_puts(char *s) +/// @brief Writes the given string to the debug port. +/// @param s The string to send to the debug port. +static inline void __debug_puts(const char *s) { while ((*s) != 0) { - __outportb(SERIAL_COM1, *s++); + __debug_putchar(*s++); } } @@ -210,12 +232,27 @@ static inline void __relocate_kernel_image(elf_header_t *elf_hdr) } } +/// @brief Initializes the serial port. +/// Configures baud rate, parity, and stop bits for proper transmission. +static inline void __serial_init(uint16_t port) +{ + __outportb(port + 1, 0x00); // Disable all interrupts + __outportb(port + 3, 0x80); // Enable DLAB (set baud rate divisor) + __outportb(port + 0, 0x03); // Set divisor to 3 (low byte, 38400 baud) + __outportb(port + 1, 0x00); // (high byte) + __outportb(port + 3, 0x03); // 8 bits, no parity, one stop bit + __outportb(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + __outportb(port + 4, 0x0B); // IRQs enabled, RTS/DSR set +} + /// @brief Entry point of the bootloader. /// @param magic The magic number coming from the multiboot assembly code. /// @param header Multiboot header provided by the bootloader. /// @param esp The initial stack pointer. void boot_main(uint32_t magic, multiboot_info_t *header, uint32_t esp) { + __serial_init(SERIAL_COM1); + __debug_puts("\n[bootloader] Start...\n"); elf_header_t *elf_hdr = (elf_header_t *)LDVAR(kernel_bin); diff --git a/mentos/src/boot.s b/mentos/src/boot.s new file mode 100644 index 00000000..304d8c71 --- /dev/null +++ b/mentos/src/boot.s @@ -0,0 +1,65 @@ +# MentOS, The Mentoring Operating system project +# @file boot.s +# @brief Kernel start location, multiboot header +# GRUB-compatible multiboot header for kernel loading. +# Includes stack setup and handoff to `boot_main`. +# Copyright (c) 2014-2021 This file is distributed under the MIT License. +# See LICENSE.md for details. + +# ============================================================================= +# SECTION (multiboot_header) +# ============================================================================= +.section .multiboot_header, "a" +.align 4 +.global multiboot_header +multiboot_header: + .long 0x1BADB002 # Magic number + .long 0x00000003 # Flags + .long -(0x1BADB002 + 0x00000003) # Checksum + +# ============================================================================= +# SECTION (text) +# ============================================================================= +.section .text +.global boot_entry +boot_entry: + # Clear interrupt flag [IF = 0] + cli + # Set up the stack pointer + movl $stack_top, %esp + # Pass initial ESP + pushl %esp + # Pass Multiboot info structure + pushl %ebx + # Pass Multiboot magic number + pushl %eax + # Call the boot_main() function inside boot.c + call boot_main + # Clear interrupts and hang if we return from boot_main + cli +hang: + hlt + jmp hang + +.global boot_kernel +boot_kernel: + movl 4(%esp), %edx # Stack pointer + movl 8(%esp), %ebx # Entry + movl 12(%esp), %eax # Boot info + movl %edx, %esp # Set stack pointer + pushl %eax # Push the boot info + call *%ebx # Call the kernel main + +# ============================================================================= +# SECTION (bss) +# ============================================================================= +.section .bss +.align 16 + +.global stack_bottom +stack_bottom: + .skip 0x100000 + +.global stack_top +stack_top: + # The top of the stack is the bottom because the stack counts down. diff --git a/mentos/src/descriptor_tables/exception.S b/mentos/src/descriptor_tables/exception.S index 9ac39eb4..8452c196 100644 --- a/mentos/src/descriptor_tables/exception.S +++ b/mentos/src/descriptor_tables/exception.S @@ -1,38 +1,38 @@ -; MentOS, The Mentoring Operating system project -; @file exception.asm -; @brief -; @copyright (c) 2014-2021 This file is distributed under the MIT License. -; See LICENSE.md for details. +# MentOS, The Mentoring Operating system project +# @file exception.s +# @brief +# @copyright (c) 2014-2021 This file is distributed under the MIT License. +# See LICENSE.md for details. -extern isr_handler +.extern isr_handler -; Macro used to define a ISR which does not push an error code. -%macro ISR_NOERR 1 - global INT_%1 - INT_%1: - cli - ; A normal ISR stub that pops a dummy error code to keep a - ; uniform stack frame - push 0 - push %1 - jmp isr_common -%endmacro +# Macro used to define an ISR which does not push an error code. +.macro ISR_NOERR num +.global INT_\num +INT_\num: + cli + # A normal ISR stub that pops a dummy error code to keep a + # uniform stack frame + pushl $0 + pushl $\num + jmp isr_common +.endm -; Macro used to define a ISR which pushes an error code. -%macro ISR_ERR 1 - global INT_%1 - INT_%1: - cli - push %1 - jmp isr_common -%endmacro +# Macro used to define an ISR which pushes an error code. +.macro ISR_ERR num +.global INT_\num +INT_\num: + cli + pushl $\num + jmp isr_common +.endm -; ----------------------------------------------------------------------------- -; SECTION (text) -; ----------------------------------------------------------------------------- -section .text +# ----------------------------------------------------------------------------- +# SECTION (text) +# ----------------------------------------------------------------------------- +.section .text -; Standard X86 interrupt service routines +# Standard x86 interrupt service routines ISR_NOERR 0 ISR_NOERR 1 ISR_NOERR 2 @@ -69,48 +69,40 @@ ISR_NOERR 31 ISR_NOERR 80 isr_common: - ; Save all registers (eax, ecx, edx, ebx, esp, ebp, esi, edi) + # Save all registers (eax, ecx, edx, ebx, esp, ebp, esi, edi) pusha - ; Save segment registers - push ds - push es - push fs - push gs + # Save segment registers + pushl %ds + pushl %es + pushl %fs + pushl %gs - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - ; CLD - Azzera la flag di Direzione - ; Questa istruzione forza semplicemente a zero la flag di Direzione. - ; Quando la flag di direzione vale 0 tutte le istruzioni per la - ; manipolazione delle stringhe agiscono in avanti, cioè dagli indirizzi più - ; bassi a quelli più alti. - ; L'istruzione agisce dunque sui puntatori SI e DI producendo su essi un - ; autoincremento proporzionale alla dimensione degli operandi trattati. - ; Le sue caratteristiche sono riassunte nella seguente tabella (leggi le - ; istruzioni Legenda della Tabella): + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + # CLD - Clear Direction Flag cld - ; Call the interrupt handler. - push esp - call isr_handler - add esp, 0x4 + # Call the interrupt handler. + pushl %esp + call isr_handler + addl $0x4, %esp - ; Restore segment registers. - pop gs - pop fs - pop es - pop ds + # Restore segment registers. + popl %gs + popl %fs + popl %es + popl %ds - ; Restore all registers (eax, ecx, edx, ebx, esp, ebp, esi, edi). + # Restore all registers (eax, ecx, edx, ebx, esp, ebp, esi, edi). popa - ; Cleanup error code and IRQ # - add esp, 0x8 - + # Cleanup error code and IRQ # + addl $0x8, %esp - iret ; pops 5 things at once: - ; CS, EIP, EFLAGS, SS, and ESP + iret # Pops 5 things at once: + # CS, EIP, EFLAGS, SS, and ESP diff --git a/mentos/src/descriptor_tables/gdt.S b/mentos/src/descriptor_tables/gdt.S index ea5c6def..2ffa9365 100644 --- a/mentos/src/descriptor_tables/gdt.S +++ b/mentos/src/descriptor_tables/gdt.S @@ -1,30 +1,29 @@ -; MentOS, The Mentoring Operating system project -; @file gdt.asm -; @brief -; @copyright (c) 2014-2021 This file is distributed under the MIT License. -; See LICENSE.md for details. +# MentOS, The Mentoring Operating system project +# @file gdt.s +# @brief +# @copyright (c) 2014-2021 This file is distributed under the MIT License. +# See LICENSE.md for details. -global gdt_flush ; Allows the C code to call gdt_flush(). +.global gdt_flush # Allows the C code to call gdt_flush(). -; ----------------------------------------------------------------------------- -; SECTION (text) -; ----------------------------------------------------------------------------- -section .text +# ----------------------------------------------------------------------------- +# SECTION (text) +# ----------------------------------------------------------------------------- +.section .text gdt_flush: - mov eax, [esp+4] ; Get the pointer to the GDT, passed as a parameter. - lgdt [eax] ; Load the new GDT pointer + movl 4(%esp), %eax # Get the pointer to the GDT, passed as a parameter. + lgdt (%eax) # Load the new GDT pointer. - ; The data segments selectors (registers), can be easily modified using - ; simple mov instruction, but the cs can't be used with mov, so you use: - jmp 0x08:flush - ; to load the segment configurations into the the code segment selector. + # The data segments selectors (registers) can be modified using + # simple mov instructions, but cs can't be directly set with mov, so we use: + ljmp $0x08, $flush # to load the segment configurations into the code selector. flush: - mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment - mov ds, ax ; Load all data segment selectors - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax + movw $0x10, %ax # 0x10 is the offset in the GDT to our data segment. + movw %ax, %ds # Load all data segment selectors. + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss ret \ No newline at end of file diff --git a/mentos/src/descriptor_tables/idt.S b/mentos/src/descriptor_tables/idt.S index 3c4db2f5..9b02638b 100644 --- a/mentos/src/descriptor_tables/idt.S +++ b/mentos/src/descriptor_tables/idt.S @@ -1,17 +1,17 @@ -; MentOS, The Mentoring Operating system project -; @file idt.asm -; @brief -; @copyright (c) 2014-2021 This file is distributed under the MIT License. -; See LICENSE.md for details. +# MentOS, The Mentoring Operating system project +# @file idt.s +# @brief +# @copyright (c) 2014-2021 This file is distributed under the MIT License. +# See LICENSE.md for details. -global idt_flush ; Allows the C code to call idt_flush(). +.global idt_flush # Allows the C code to call idt_flush(). -; ----------------------------------------------------------------------------- -; SECTION (text) -; ----------------------------------------------------------------------------- -section .text +# ----------------------------------------------------------------------------- +# SECTION (text) +# ----------------------------------------------------------------------------- +.section .text idt_flush: - mov eax, [esp+4] ; Get the pointer to the IDT, passed as a parameter. - lidt [eax] ; Load the IDT pointer. - ret \ No newline at end of file + movl 4(%esp), %eax # Get the pointer to the IDT, passed as a parameter. + lidt (%eax) # Load the IDT pointer. + ret diff --git a/mentos/src/descriptor_tables/interrupt.S b/mentos/src/descriptor_tables/interrupt.S index 00970839..915e414c 100644 --- a/mentos/src/descriptor_tables/interrupt.S +++ b/mentos/src/descriptor_tables/interrupt.S @@ -1,28 +1,29 @@ -; MentOS, The Mentoring Operating system project -; @file interrupt.asm -; @brief -; @copyright (c) 2014-2021 This file is distributed under the MIT License. -; See LICENSE.md for details. +# MentOS, The Mentoring Operating system project +# @file interrupt.s +# @brief +# @copyright (c) 2014-2021 This file is distributed under the MIT License. +# See LICENSE.md for details. -extern irq_handler +.extern irq_handler -%macro IRQ 2 - global IRQ_%1 - IRQ_%1: - cli ; disable interrupt line - ; A normal ISR stub that pops a dummy error code to keep a - ; uniform stack frame - push 0 - push %2 ; irq number - jmp irq_common -%endmacro +# Define a macro to create IRQ handlers. +.macro IRQ irq_num, irq_vector +.global IRQ_\irq_num +IRQ_\irq_num: + cli # Disable interrupt line + # A normal ISR stub that pops a dummy error code to keep a + # uniform stack frame + pushl $0 # Push dummy error code + pushl $\irq_vector # Push IRQ number + jmp irq_common # Jump to common IRQ handler +.endm -; ----------------------------------------------------------------------------- -; SECTION (text) -; ----------------------------------------------------------------------------- -section .text +# ----------------------------------------------------------------------------- +# SECTION (text) +# ----------------------------------------------------------------------------- +.section .text -; 32 is the first irq, 47 is the last one. DO NOT CHANGE THESE NUMBERS. +# 32 is the first IRQ, 47 is the last one. DO NOT CHANGE THESE NUMBERS. IRQ 0, 32 IRQ 1, 33 IRQ 2, 34 @@ -41,51 +42,51 @@ IRQ 14, 46 IRQ 15, 47 irq_common: - ;==== Save CPU registers =================================================== - ; when an irq occurs, the following registers are already pushed on stack: - ; eip, cs, eflags, useresp, ss + #==== Save CPU registers =================================================== + # When an IRQ occurs, the following registers are already pushed on stack: + # EIP, CS, EFLAGS, USERESP, SS - ; Save registers: eax, ecx, edx, ebx, esp, ebp, esi, edi + # Save general-purpose registers pusha - ; Save segment registers - push ds - push es - push fs - push gs - ;--------------------------------------------------------------------------- + # Save segment registers + pushl %ds + pushl %es + pushl %fs + pushl %gs + #---------------------------------------------------------------------------- - ;==== ensure we are using kernel data segment ============================== - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax + #==== Ensure we are using kernel data segment =============================== + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs cld - ;--------------------------------------------------------------------------- + #---------------------------------------------------------------------------- - ;==== Call the interrupt handler =========================================== - ; The argument passed is a pointer to an Interrupt_State struct, - ; which describes the stack layout for all interrupts. - push esp - call irq_handler - add esp, $4 ; remove esp from stack - ;--------------------------------------------------------------------------- + #==== Call the interrupt handler ============================================ + # The argument passed is a pointer to an Interrupt_State struct, + # which describes the stack layout for all interrupts. + pushl %esp + call irq_handler + addl $4, %esp # Remove ESP from stack + #---------------------------------------------------------------------------- - ;==== Restore registers ==================================================== - ; restore segment registers - pop gs - pop fs - pop es - pop ds + #==== Restore registers ===================================================== + # Restore segment registers + popl %gs + popl %fs + popl %es + popl %ds - ; restore registers: eax, ecx, edx, ebx, esp, ebp, esi, edi + # Restore general-purpose registers popa - ;--------------------------------------------------------------------------- + #---------------------------------------------------------------------------- - ; Cleanup error code and IRQ # - add esp, $8 + # Cleanup error code and IRQ # + addl $8, %esp - ; return to process - iret ; pops 5 things at once: - ; CS, EIP, EFLAGS, SS, and ESP + # Return to process + iret # Pops 5 things at once: + # CS, EIP, EFLAGS, SS, and ESP diff --git a/mentos/src/descriptor_tables/tss.S b/mentos/src/descriptor_tables/tss.S index df9fdd04..99544573 100644 --- a/mentos/src/descriptor_tables/tss.S +++ b/mentos/src/descriptor_tables/tss.S @@ -1,17 +1,17 @@ -; MentOS, The Mentoring Operating system project -; @file tss.asm -; @brief -; @copyright (c) 2014-2021 This file is distributed under the MIT License. -; See LICENSE.md for details. +# MentOS, The Mentoring Operating system project +# @file tss.s +# @brief +# @copyright (c) 2014-2021 This file is distributed under the MIT License. +# See LICENSE.md for details. -global tss_flush +.global tss_flush -; ----------------------------------------------------------------------------- -; SECTION (text) -; ----------------------------------------------------------------------------- -section .text +# ----------------------------------------------------------------------------- +# SECTION (text) +# ----------------------------------------------------------------------------- +.section .text tss_flush: - mov ax, 0x28 - ltr ax - ret + movw $0x28, %ax # Load 0x28 into AX + ltr %ax # Load the task register + ret # Return diff --git a/mentos/src/kernel.c b/mentos/src/kernel.c index 043a0c8e..45e33ea8 100644 --- a/mentos/src/kernel.c +++ b/mentos/src/kernel.c @@ -46,35 +46,6 @@ char *module_start[MAX_MODULES]; /// Describe end address of grub multiboot modules. char *module_end[MAX_MODULES]; -// Everything is defined in kernel.ld. - -/// Points at the multiheader grub info, starting address. -extern uint32_t _multiboot_header_start; -/// Points at the multiheader grub info, ending address. -extern uint32_t _multiboot_header_end; -/// Points at the kernel code, starting address. -extern uint32_t _text_start; -/// Points at the kernel code, ending address. -extern uint32_t _text_end; -/// Points at the read-only kernel data, starting address. -extern uint32_t _rodata_start; -/// Points at the read-only kernel data, ending address. -extern uint32_t _rodata_end; -/// Points at the read-write kernel data initialized, starting address. -extern uint32_t _data_start; -/// Points at the read-write kernel data initialized, ending address. -extern uint32_t _data_end; -/// Points at the read-write kernel data uninitialized an kernel stack, starting address. -extern uint32_t _bss_start; -/// Points at the read-write kernel data uninitialized an kernel stack, ending address. -extern uint32_t _bss_end; -/// Points at the top of the kernel stack. -extern uint32_t stack_top; -/// Points at the bottom of the kernel stack. -extern uint32_t stack_bottom; -/// Points at the end of kernel code/data. -extern uint32_t end; - /// Initial ESP. uintptr_t initial_esp = 0; /// The boot info. @@ -123,7 +94,7 @@ int kmain(boot_info_t *boot_informations) //========================================================================== pr_notice("Initialize the video...\n"); - vga_initialize(); + // vga_initialize(); video_init(); //========================================================================== @@ -454,7 +425,7 @@ int kmain(boot_info_t *boot_informations) print_ok(); // We have completed the booting procedure. - pr_notice("Booting done, jumping into init process.\n"); + pr_notice("Booting done, jumping into init process (0x%p).\n", init_p->thread.regs.eip); // Switch to the page directory of init. paging_switch_directory_va(init_p->mm->pgd); // Jump into init process. diff --git a/mentos/src/process/user.S b/mentos/src/process/user.S deleted file mode 100644 index 044fb0a6..00000000 --- a/mentos/src/process/user.S +++ /dev/null @@ -1,87 +0,0 @@ -; MentOS, The Mentoring Operating system project -; @file user.asm -; @brief -; @copyright (c) 2014-2021 This file is distributed under the MIT License. -; See LICENSE.md for details. - -; Enter userspace (ring3) (from Ring 0, namely Kernel) -; Usage: enter_userspace(uintptr_t location, uintptr_t stack); -; On stack -; | stack | [ebp + 0x0C] ARG1 -; | location | [ebp + 0x08] ARG0 -; | return address | [ebp + 0x04] -; | EBP | [ebp + 0x00] -; | SS | -; | ESP | -; | EFLAGS | -; | CS | -; | EIP | - -; We can use the following macros to access the arguments ONLY AFTER 0x23 is -; pushed onto the stack, in fact, the first argument is after 0x08 because -; we just pushed first `ebp` and then `0x23`. -%define ARG0 [ebp + 0x08] ; Argument 0 -%define ARG1 [ebp + 0x0C] ; Argument 1 -%define ARG2 [ebp + 0x10] ; Argument 2 -%define ARG3 [ebp + 0x14] ; Argument 3 -%define ARG4 [ebp + 0x18] ; Argument 4 - -; ----------------------------------------------------------------------------- -; SECTION (text) -; ----------------------------------------------------------------------------- -section .text - -global enter_userspace ; Allows the C code to call enter_userspace(...). - -enter_userspace: - - push ebp ; Save current ebp - mov ebp, esp ; open a new stack frame - - ;==== Segment selector ===================================================== - mov ax, 0x23 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - ; we don't need to worry about SS. it's handled by iret - ;--------------------------------------------------------------------------- - - ; We have to prepare the following stack before executing iret - ; SS --> Segment selector - ; ESP --> Stack address - ; EFLAGS --> CPU state flgas - ; CS --> Code segment - ; EIP --> Entry point - ; - - ;==== User data segmenet with bottom 2 bits set for ring3 ?================= - push 0x23 ; push SS on Kernel's stack - ;--------------------------------------------------------------------------- - - ;==== (ESP) Stack address ================================================== - mov eax, ARG1 ; get uintptr_t stack - push eax ; push process's stack address on Kernel's stack - ;--------------------------------------------------------------------------- - - ;==== (EFLAGS) ============================================================= - pushf ; push EFLAGS into Kernel's stack - pop eax ; pop EFLAGS into eax - or eax, 0x200 ; enable interrupt - push eax ; push new EFLAGS on Kernel's stack - ;--------------------------------------------------------------------------- - - ;==== (CS) Code Segment ==================================================== - push 0x1b ; - ;--------------------------------------------------------------------------- - - ;==== (EIP) Entry point ==================================================== - mov eax, ARG0 ; get uintptr_t location - push eax ; push uintptr_t location on Kernel's stack - ;--------------------------------------------------------------------------- - - iret ; interrupt return - pop ebp - ret - - ; WE SHOULD NOT STILL BE HERE! :(p \ No newline at end of file diff --git a/mentos/src/process/user.s b/mentos/src/process/user.s new file mode 100644 index 00000000..6b563f42 --- /dev/null +++ b/mentos/src/process/user.s @@ -0,0 +1,65 @@ +# MentOS, The Mentoring Operating system project +# @file user.s +# @brief +# Enter userspace (Ring 3) from Ring 0 (Kernel mode). +# Usage: enter_userspace(uintptr_t location, uintptr_t stack) +# Copyright (c) 2014-2021 This file is distributed under the MIT License. +# See LICENSE.md for details. + +.global enter_userspace + +# ----------------------------------------------------------------------------- +# SECTION (text) +# ----------------------------------------------------------------------------- +.section .text + +enter_userspace: + pushl %ebp # Save current EBP + movl %esp, %ebp # Open a new stack frame + + #==== Segment Selector ===================================================== + movw $0x23, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + # We don't need to worry about SS; it's handled by `iret`. + #---------------------------------------------------------------------------- + + #==== Prepare the Stack for `iret` ========================================= + # Required stack structure before `iret`: + # SS --> Segment selector + # ESP --> Stack address + # EFLAGS --> CPU state flags + # CS --> Code segment + # EIP --> Entry point + + #==== User Data Segment with Bottom 2 Bits Set for Ring 3 ================== + pushl $0x23 # Push SS onto the Kernel's stack + #---------------------------------------------------------------------------- + + #==== ESP: Stack Address =================================================== + movl 8(%ebp), %eax # ARG1: uintptr_t stack (offset 0x08 from EBP) + pushl %eax # Push process's stack address onto Kernel's stack + #---------------------------------------------------------------------------- + + #==== EFLAGS: CPU State Flags ============================================== + pushf # Push EFLAGS onto the Kernel's stack + popl %eax # Pop EFLAGS into EAX + orl $0x200, %eax # Enable interrupts (set IF bit in EFLAGS) + pushl %eax # Push updated EFLAGS onto the Kernel's stack + #---------------------------------------------------------------------------- + + #==== CS: Code Segment ===================================================== + pushl $0x1b # Push Code Segment (Ring 3 CS selector) onto the stack + #---------------------------------------------------------------------------- + + #==== EIP: Entry Point ===================================================== + movl 4(%ebp), %eax # ARG0: uintptr_t location (offset 0x04 from EBP) + pushl %eax # Push uintptr_t location onto the Kernel's stack + #---------------------------------------------------------------------------- + + iret # Interrupt return: switch to Ring 3 (userspace) + popl %ebp # Restore EBP (if we somehow get here, which we shouldn't) + ret # Return (should never reach here) + # We should NOT still be here! diff --git a/programs/shell.c b/programs/shell.c index 110f0379..31a16e6f 100644 --- a/programs/shell.c +++ b/programs/shell.c @@ -1138,9 +1138,7 @@ static inline void __free_argv(int argc, char **argv) } // Free each argument in the argv array. for (int i = 0; i < argc; ++i) { - if (argv[i] != NULL) { - free(argv[i]); - } + free(argv[i]); } // Free the argv array itself. free(argv); @@ -1338,7 +1336,7 @@ static void __interactive_mode(void) if (stat(".shellrc", &buf) == 0) { int ret = __execute_file(".shellrc"); if (ret < 0) { - printf("%s: .shellrc: %s\n", strerror(-ret)); + printf(".shellrc: %s\n", strerror(-ret)); } } #pragma clang diagnostic push @@ -1406,7 +1404,7 @@ int main(int argc, char *argv[]) memset(&action, 0, sizeof(action)); action.sa_handler = wait_for_child; if (sigaction(SIGCHLD, &action, NULL) == -1) { - printf("Failed to set signal handler (%s).\n", SIGCHLD, strerror(errno)); + printf("Failed to set signal handler (%s).\n", strerror(errno)); return 1; }