diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp index 6187bffc97..970483382d 100644 --- a/Kernel/Arch/i386/CPU.cpp +++ b/Kernel/Arch/i386/CPU.cpp @@ -76,6 +76,7 @@ extern "C" void handle_interrupt(TrapFrame*); // clang-format off +#if ARCH(I386) #define EH_ENTRY(ec, title) \ extern "C" void title##_asm_entry(); \ extern "C" void title##_handler(TrapFrame*); \ @@ -127,6 +128,26 @@ extern "C" void handle_interrupt(TrapFrame*); " call " #title "_handler\n" \ " jmp common_trap_exit \n"); +#elif ARCH(X86_64) +#define EH_ENTRY(ec, title) \ + extern "C" void title##_asm_entry(); \ + extern "C" void title##_handler(TrapFrame*); \ + asm( \ + ".globl " #title "_asm_entry\n" \ + "" #title "_asm_entry: \n" \ + " cli;hlt;\n" \ +); + +#define EH_ENTRY_NO_CODE(ec, title) \ + extern "C" void title##_handler(TrapFrame*); \ + extern "C" void title##_asm_entry(); \ +asm( \ + ".globl " #title "_asm_entry\n" \ + "" #title "_asm_entry: \n" \ + " cli;hlt;\n" \ +); +#endif + // clang-format on static void dump(const RegisterState& regs) @@ -1593,6 +1614,7 @@ extern "C" u32 do_init_context(Thread* thread, u32 flags) extern "C" void do_assume_context(Thread* thread, u32 flags); +#if ARCH(I386) // clang-format off asm( ".global do_assume_context \n" @@ -1614,8 +1636,9 @@ asm( " jmp enter_thread_context \n" ); // clang-format on +#endif -void Processor::assume_context(Thread& thread, u32 flags) +void Processor::assume_context(Thread& thread, FlatPtr flags) { dbgln_if(CONTEXT_SWITCH_DEBUG, "Assume context for thread {} {}", VirtualAddress(&thread), thread); @@ -1624,7 +1647,12 @@ void Processor::assume_context(Thread& thread, u32 flags) // in_critical() should be 2 here. The critical section in Process::exec // and then the scheduler lock VERIFY(Processor::current().in_critical() == 2); +#if ARCH(I386) do_assume_context(&thread, flags); +#elif ARCH(X86_64) + (void)flags; + TODO(); +#endif VERIFY_NOT_REACHED(); } @@ -2315,12 +2343,14 @@ UNMAP_AFTER_INIT void Processor::gdt_init() : "memory"); set_fs(GDT_SELECTOR_PROC); +#if ARCH(I386) // Make sure CS points to the kernel code descriptor. // clang-format off asm volatile( "ljmpl $" __STRINGIFY(GDT_SELECTOR_CODE0) ", $sanity\n" "sanity:\n"); // clang-format on +#endif } void copy_kernel_registers_into_ptrace_registers(PtraceRegisters& ptrace_regs, const RegisterState& kernel_regs) diff --git a/Kernel/Arch/i386/CPU.h b/Kernel/Arch/i386/CPU.h index e343369a29..84ed4b05e5 100644 --- a/Kernel/Arch/i386/CPU.h +++ b/Kernel/Arch/i386/CPU.h @@ -1014,7 +1014,7 @@ public: [[noreturn]] void initialize_context_switching(Thread& initial_thread); void switch_context(Thread*& from_thread, Thread*& to_thread); - [[noreturn]] static void assume_context(Thread& thread, u32 flags); + [[noreturn]] static void assume_context(Thread& thread, FlatPtr flags); u32 init_context(Thread& thread, bool leave_crit); static Vector capture_stack_trace(Thread& thread, size_t max_frames = 0); diff --git a/Kernel/Arch/i386/Interrupts.h b/Kernel/Arch/i386/Interrupts.h index 7d4e4b69ba..cfa457da16 100644 --- a/Kernel/Arch/i386/Interrupts.h +++ b/Kernel/Arch/i386/Interrupts.h @@ -32,13 +32,15 @@ extern "C" void interrupt_common_asm_entry(); -#define GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(isr_number) \ - extern "C" void interrupt_##isr_number##_asm_entry(); \ - asm(".globl interrupt_" #isr_number "_asm_entry\n" \ - "interrupt_" #isr_number "_asm_entry:\n" \ - " pushw $" #isr_number "\n" \ - " pushw $0\n" \ - " jmp interrupt_common_asm_entry\n"); +#if ARCH(I386) + +# define GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(isr_number) \ + extern "C" void interrupt_##isr_number##_asm_entry(); \ + asm(".globl interrupt_" #isr_number "_asm_entry\n" \ + "interrupt_" #isr_number "_asm_entry:\n" \ + " pushw $" #isr_number "\n" \ + " pushw $0\n" \ + " jmp interrupt_common_asm_entry\n"); // clang-format off asm( @@ -83,3 +85,19 @@ asm( " iret\n" ); // clang-format on + +#elif ARCH(X86_64) + +# define GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(isr_number) \ + extern "C" void interrupt_##isr_number##_asm_entry(); \ + asm(".globl interrupt_" #isr_number "_asm_entry\n" \ + "interrupt_" #isr_number "_asm_entry:\n" \ + " cli\n" \ + " hlt\n"); + +asm( + ".globl common_trap_exit\n" + "common_trap_exit:\n" + " cli;hlt\n"); + +#endif diff --git a/Kernel/Arch/x86_64/Boot/boot.S b/Kernel/Arch/x86_64/Boot/boot.S new file mode 100644 index 0000000000..1ed1cd9207 --- /dev/null +++ b/Kernel/Arch/x86_64/Boot/boot.S @@ -0,0 +1,183 @@ +.set MULTIBOOT_MAGIC, 0x1badb002 +.set MULTIBOOT_PAGE_ALIGN, 0x1 +.set MULTIBOOT_MEMORY_INFO, 0x2 +.set MULTIBOOT_VIDEO_MODE, 0x4 +.set multiboot_flags, MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_MODE +.set multiboot_checksum, -(MULTIBOOT_MAGIC + multiboot_flags) + +.section .multiboot +.align 4 + +.long MULTIBOOT_MAGIC +.long multiboot_flags +.long multiboot_checksum + + +/* for MULTIBOOT_MEMORY_INFO */ +.long 0x00000000 /* header_addr */ +.long 0x00000000 /* load_addr */ +.long 0x00000000 /* load_end_addr */ +.long 0x00000000 /* bss_end_addr */ +.long 0x00000000 /* entry_addr */ + +/* for MULTIBOOT_VIDEO_MODE */ +.long 0x00000000 /* mode_type */ +.long 1280 /* width */ +.long 1024 /* height */ +.long 32 /* depth */ + +.section .stack, "aw", @nobits +stack_bottom: +.skip 32768 +stack_top: + +.global kernel_cmdline +kernel_cmdline: +.skip 4096 + +.section .page_tables, "aw", @nobits +.align 4096 +.global boot_pdpt +boot_pdpt: +.skip 4096 +.global boot_pd0 +boot_pd0: +.skip 4096 +.global boot_pd3 +boot_pd3: +.skip 4096 +.global boot_pd0_pt0 +boot_pd0_pt0: +.skip 4096 * 4 +.global boot_pd3_pts +boot_pd3_pts: +.skip 4096 * 8 +.global boot_pd3_pt1023 +boot_pd3_pt1023: +.skip 4096 + +.section .text + +.global start +.type start, @function + +.extern init +.type init, @function + +.extern multiboot_info_ptr +.type multiboot_info_ptr, @object + +start: + cli + cld + + /* We don't know where the bootloader might have put the command line. + * It might be at an inconvenient location that we're not about to map, + * so let's just copy it to a convenient location while we have the whole + * memory space identity-mapped anyway. :^) + */ + + movl %ebx, %esi + addl $16, %esi + movl (%esi), %esi + movl $1024, %ecx + movl $(kernel_cmdline - 0xc0000000), %edi + rep movsl + + call init + add $4, %esp + + cli +loop: + hlt + jmp loop + +.extern init_ap +.type init_ap, @function + +/* + The apic_ap_start function will be loaded to P0x00008000 where the APIC + will boot the AP from in real mode. This code also contains space for + special variables that *must* remain here. When initializing the APIC, + the code here gets copied to P0x00008000, the variables in here get + populated and then the the boot of the APs will be triggered. Having + the variables here allows us to access them from real mode. Also, the + code here avoids the need for relocation entries. + + Basically, the variables between apic_ap_start and end_apic_ap_start + *MUST* remain here and cannot be moved into a .bss or any other location. +*/ +.global apic_ap_start +.type apic_ap_start, @function +apic_ap_start: +.code16 + cli + jmp $0x800, $(1f - apic_ap_start) /* avoid relocation entries */ +1: + mov %cs, %ax + mov %ax, %ds + + xor %ax, %ax + mov %ax, %sp + + /* load the first temporary gdt */ + lgdt (ap_cpu_gdtr_initial - apic_ap_start) + + /* enable PM */ + movl %cr0, %eax + orl $1, %eax + movl %eax, %cr0 + + ljmpl $8, $(apic_ap_start32 - apic_ap_start + 0x8000) +apic_ap_start32: +.code32 + cli + hlt + +.align 4 +.global apic_ap_start_size +apic_ap_start_size: + .2byte end_apic_ap_start - apic_ap_start +.align 4 +ap_cpu_id: + .4byte 0x0 +ap_cpu_gdt: + /* null */ + .8byte 0x0 + /* code */ + .4byte 0x0000FFFF + .4byte 0x00cf9a00 + /* data */ + .4byte 0x0000FFFF + .4byte 0x00cf9200 +ap_cpu_gdt_end: +ap_cpu_gdtr_initial: + .2byte ap_cpu_gdt_end - ap_cpu_gdt - 1 + .4byte (ap_cpu_gdt - apic_ap_start) + 0x8000 +ap_cpu_gdtr_initial2: + .2byte ap_cpu_gdt_end - ap_cpu_gdt - 1 + .4byte (ap_cpu_gdt - apic_ap_start) + 0xc0008000 +.global ap_cpu_gdtr +ap_cpu_gdtr: + .4byte 0x0 /* will be set at runtime */ +.global ap_cpu_idtr +ap_cpu_idtr: + .4byte 0x0 /* will be set at runtime */ +.global ap_cpu_init_cr0 +ap_cpu_init_cr0: + .4byte 0x0 /* will be set at runtime */ +.global ap_cpu_init_cr3 +ap_cpu_init_cr3: + .4byte 0x0 /* will be set at runtime */ +.global ap_cpu_init_cr4 +ap_cpu_init_cr4: + .4byte 0x0 /* will be set at runtime */ +.global ap_cpu_init_processor_info_array +ap_cpu_init_processor_info_array: + .4byte 0x0 /* will be set at runtime */ +.global ap_cpu_init_stacks +ap_cpu_init_stacks: + /* array of allocated stack pointers */ + /* NOTE: ap_cpu_init_stacks must be the last variable before + end_apic_ap_start! */ +.set end_apic_ap_start, . diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 54037845b4..cd74fddb66 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -1,5 +1,11 @@ add_compile_options(-Os) +if ("${SERENITY_ARCH}" STREQUAL "i686") + set(KERNEL_ARCH i386) +elseif("${SERENITY_ARCH}" STREQUAL "x86_64") + set(KERNEL_ARCH x86_64) +endif() + set(KERNEL_HEAP_SOURCES Heap/SlabAllocator.cpp Heap/kmalloc.cpp @@ -285,6 +291,10 @@ if (NOT ${CMAKE_HOST_SYSTEM_NAME} MATCHES SerenityOS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib -nostdinc -nostdinc++") endif() +if ("${SERENITY_ARCH}" STREQUAL "x86_64") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcmodel=large -mno-red-zone") +endif() + # Kernel Undefined Behavior Sanitizer (KUBSAN) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") @@ -307,9 +317,9 @@ add_link_options(LINKER:-T ${CMAKE_CURRENT_BINARY_DIR}/linker.ld -nostdlib) # kernel won't re-link when boot.S changes without this. set_source_files_properties(init.cpp PROPERTIES - OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Arch/i386/Boot/boot.S + OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Arch/${KERNEL_ARCH}/Boot/boot.S ) -add_library(boot OBJECT Arch/i386/Boot/boot.S) +add_library(boot OBJECT Arch/${KERNEL_ARCH}/Boot/boot.S) add_library(kernel_heap STATIC ${KERNEL_HEAP_SOURCES}) file(GENERATE OUTPUT linker.ld INPUT linker.ld) diff --git a/Kernel/Devices/USB/UHCIController.cpp b/Kernel/Devices/USB/UHCIController.cpp index 852f389aa9..96488e6eef 100644 --- a/Kernel/Devices/USB/UHCIController.cpp +++ b/Kernel/Devices/USB/UHCIController.cpp @@ -25,15 +25,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include -#include -#include -#include -#include +#include -#define UHCI_ENABLED 1 +// FIXME: This should not be i386-specific. +#if ARCH(I386) + +# include +# include +# include +# include +# include +# include +# include + +# define UHCI_ENABLED 1 static constexpr u8 MAXIMUM_NUMBER_OF_TDS = 128; // Upper pool limit. This consumes the second page we have allocated static constexpr u8 MAXIMUM_NUMBER_OF_QHS = 64; @@ -88,9 +93,9 @@ UHCIController& UHCIController::the() UNMAP_AFTER_INIT void UHCIController::detect() { -#if !UHCI_ENABLED +# if !UHCI_ENABLED return; -#endif +# endif PCI::enumerate([&](const PCI::Address& address, PCI::ID id) { if (address.is_null()) return; @@ -195,9 +200,9 @@ UNMAP_AFTER_INIT void UHCIController::create_structures() transfer_descriptor->set_isochronous(); transfer_descriptor->link_queue_head(m_interrupt_transfer_queue->paddr()); -#if UHCI_VERBOSE_DEBUG +# if UHCI_VERBOSE_DEBUG transfer_descriptor->print(); -#endif +# endif } m_free_td_pool.resize(MAXIMUM_NUMBER_OF_TDS); @@ -211,17 +216,17 @@ UNMAP_AFTER_INIT void UHCIController::create_structures() // access the raw descriptor (that we later send to the controller) m_free_td_pool.at(i) = new (placement_addr) Kernel::USB::TransferDescriptor(paddr); -#if UHCI_VERBOSE_DEBUG +# if UHCI_VERBOSE_DEBUG auto transfer_descriptor = m_free_td_pool.at(i); transfer_descriptor->print(); -#endif +# endif } -#if UHCI_DEBUG +# if UHCI_DEBUG klog() << "UHCI: Pool information:"; klog() << "\tqh_pool: " << PhysicalAddress(m_qh_pool->physical_page(0)->paddr()) << ", length: " << m_qh_pool->range().size(); klog() << "\ttd_pool: " << PhysicalAddress(m_td_pool->physical_page(0)->paddr()) << ", length: " << m_td_pool->range().size(); -#endif +# endif } UNMAP_AFTER_INIT void UHCIController::setup_schedule() @@ -289,9 +294,9 @@ QueueHead* UHCIController::allocate_queue_head() const for (QueueHead* queue_head : m_free_qh_pool) { if (!queue_head->in_use()) { queue_head->set_in_use(true); -#if UHCI_DEBUG +# if UHCI_DEBUG klog() << "UHCI: Allocated a new Queue Head! Located @ " << VirtualAddress(queue_head) << "(" << PhysicalAddress(queue_head->paddr()) << ")"; -#endif +# endif return queue_head; } } @@ -305,9 +310,9 @@ TransferDescriptor* UHCIController::allocate_transfer_descriptor() const for (TransferDescriptor* transfer_descriptor : m_free_td_pool) { if (!transfer_descriptor->in_use()) { transfer_descriptor->set_in_use(true); -#if UHCI_DEBUG +# if UHCI_DEBUG klog() << "UHCI: Allocated a new Transfer Descriptor! Located @ " << VirtualAddress(transfer_descriptor) << "(" << PhysicalAddress(transfer_descriptor->paddr()) << ")"; -#endif +# endif return transfer_descriptor; } } @@ -464,3 +469,5 @@ void UHCIController::handle_irq(const RegisterState&) } } + +#endif diff --git a/Kernel/Devices/USB/UHCIController.h b/Kernel/Devices/USB/UHCIController.h index 8a79536240..02ab96f212 100644 --- a/Kernel/Devices/USB/UHCIController.h +++ b/Kernel/Devices/USB/UHCIController.h @@ -27,13 +27,18 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include +#include + +// FIXME: This should not be i386-specific. +#if ARCH(I386) + +# include +# include +# include +# include +# include +# include +# include namespace Kernel::USB { @@ -100,3 +105,4 @@ private: }; } +#endif diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index f4075153f4..e22ca91696 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -281,8 +281,10 @@ void signal_trampoline_dummy() "int 0x82\n" // sigreturn syscall "asm_signal_trampoline_end:\n" ".att_syntax" ::"i"(Syscall::SC_sigreturn)); -#else - // FIXME: Implement trampoline for other architectures. +#elif ARCH(X86_64) + asm("asm_signal_trampoline:\n" + "cli;hlt\n" + "asm_signal_trampoline_end:\n"); #endif } diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index fa7d5a23a1..04d2f2a774 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -37,6 +37,7 @@ extern "C" void syscall_handler(TrapFrame*); extern "C" void syscall_asm_entry(); // clang-format off +#if ARCH(I386) asm( ".globl syscall_asm_entry\n" "syscall_asm_entry:\n" @@ -64,6 +65,13 @@ asm( " call syscall_handler \n" " movl %ebx, 0(%esp) \n" // push pointer to TrapFrame " jmp common_trap_exit \n"); +#elif ARCH(X86_64) + asm( + ".globl syscall_asm_entry\n" + "syscall_asm_entry:\n" + " cli\n" + " hlt\n"); +#endif // clang-format on namespace Syscall { diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index bd50f16dc9..d19bcbd9b8 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -795,12 +795,12 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal) auto setup_stack = [&](RegisterState& state) { #if ARCH(I386) FlatPtr* stack = &state.userspace_esp; -#elif ARCH(X86_64) - FlatPtr* stack = &state.userspace_esp; -#endif FlatPtr old_esp = *stack; FlatPtr ret_eip = state.eip; FlatPtr ret_eflags = state.eflags; +#elif ARCH(X86_64) + FlatPtr* stack = &state.userspace_esp; +#endif #if SIGNAL_DEBUG klog() << "signal: setting up user stack to return to eip: " << String::format("%p", (void*)ret_eip) << " esp: " << String::format("%p", (void*)old_esp); diff --git a/Kernel/VM/AnonymousVMObject.cpp b/Kernel/VM/AnonymousVMObject.cpp index 06a3581378..ad14cf75b7 100644 --- a/Kernel/VM/AnonymousVMObject.cpp +++ b/Kernel/VM/AnonymousVMObject.cpp @@ -75,7 +75,7 @@ RefPtr AnonymousVMObject::create_with_size(size_t size, Alloc { if (commit == AllocationStrategy::Reserve || commit == AllocationStrategy::AllocateNow) { // We need to attempt to commit before actually creating the object - if (!MM.commit_user_physical_pages(ceil_div(size, PAGE_SIZE))) + if (!MM.commit_user_physical_pages(ceil_div(size, static_cast(PAGE_SIZE)))) return {}; } return adopt(*new AnonymousVMObject(size, commit)); diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp index ac7c7964ff..e57d2889e9 100644 --- a/Kernel/VM/MemoryManager.cpp +++ b/Kernel/VM/MemoryManager.cpp @@ -699,7 +699,7 @@ NonnullRefPtrVector MemoryManager::allocate_contiguous_supervisor_ { VERIFY(!(size % PAGE_SIZE)); ScopedSpinLock lock(s_mm_lock); - size_t count = ceil_div(size, PAGE_SIZE); + size_t count = ceil_div(size, static_cast(PAGE_SIZE)); NonnullRefPtrVector physical_pages; for (auto& region : m_super_physical_regions) { diff --git a/Kernel/VM/MemoryManager.h b/Kernel/VM/MemoryManager.h index be1fe34840..bc76efef34 100644 --- a/Kernel/VM/MemoryManager.h +++ b/Kernel/VM/MemoryManager.h @@ -57,12 +57,12 @@ constexpr FlatPtr page_round_down(FlatPtr x) return ((FlatPtr)(x)) & ~(PAGE_SIZE - 1); } -inline u32 low_physical_to_virtual(u32 physical) +inline FlatPtr low_physical_to_virtual(FlatPtr physical) { return physical + 0xc0000000; } -inline u32 virtual_to_low_physical(u32 physical) +inline FlatPtr virtual_to_low_physical(FlatPtr physical) { return physical - 0xc0000000; } diff --git a/Kernel/VM/VMObject.cpp b/Kernel/VM/VMObject.cpp index 71da13de1e..77c66e94f8 100644 --- a/Kernel/VM/VMObject.cpp +++ b/Kernel/VM/VMObject.cpp @@ -37,7 +37,7 @@ VMObject::VMObject(const VMObject& other) VMObject::VMObject(size_t size) { - m_physical_pages.resize(ceil_div(size, PAGE_SIZE)); + m_physical_pages.resize(ceil_div(size, static_cast(PAGE_SIZE))); MM.register_vmobject(*this); } diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 2dc3405779..8a9467c2ac 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -272,7 +272,11 @@ void init_stage2(void*) } } + // FIXME: This should not be i386-specific. +#if ARCH(I386) USB::UHCIController::detect(); +#endif + DMIExpose::initialize(); E1000NetworkAdapter::detect();