1
0
Fork 0
mirror of https://gitlab.com/sortix/sortix.git synced 2023-02-13 20:55:38 -05:00

Rename Sortix kernel directory to kernel.

This commit is contained in:
Jonas 'Sortie' Termansen 2013-12-20 01:24:47 +01:00
parent 18d2695439
commit 98a87fa1e5
228 changed files with 10 additions and 10 deletions

67
kernel/x64/base.s Normal file
View file

@ -0,0 +1,67 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/base.s
Bootstraps the kernel and passes over control from the boot-loader to the
kernel main function.
*******************************************************************************/
.section .text
.global beginkernel
.type beginkernel, @function
beginkernel:
movw $0x736, 0xB83E8
movw $0x734, 0xB83EA
movw $0x753, 0xB83EE
movw $0x74F, 0xB83F0
movw $0x752, 0xB83F2
movw $0x754, 0xB83F4
movw $0x749, 0xB83F6
movw $0x758, 0xB83F8
# Initialize the stack pointer.
movq $stack, %rsp
addq $65536, %rsp # 64 KiB, see kernel.cpp
# Reset EFLAGS.
# pushl $0
# popf
# Push the pointer to the Multiboot information structure.
mov %rbx, %rsi
# Push the magic value.
mov %rax, %rdi
call KernelInit
.size beginkernel, . - beginkernel
.global HaltKernel
HaltKernel:
cli
hlt
jmp HaltKernel
.size HaltKernel, . - HaltKernel
.global WaitForInterrupt
.type WaitForInterrupt, @function # void WaitForInterrupt();
WaitForInterrupt:
hlt
ret

197
kernel/x64/boot.s Normal file
View file

@ -0,0 +1,197 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/boot.s
Bootstraps the kernel and passes over control from the boot-loader to the
kernel main function. It also jumps into long mode!
*******************************************************************************/
.section .text
.text 0x100000
.global _start
.type _start, @function
.code32
_start:
jmp prepare_kernel_execution
# Align 32 bits boundary.
.align 4
# Multiboot header.
multiboot_header:
# Magic.
.long 0x1BADB002
# Flags.
.long 0x00000003
# Checksum.
.long -(0x1BADB002 + 0x00000003)
prepare_kernel_execution:
# We got our multiboot information in various registers. But we are going
# to need these registers. But where can we store them then? Oh hey, let's
# store then in the code already run!
# Store the pointer to the Multiboot information structure.
mov %ebx, 0x100000
# Store the magic value.
mov %eax, 0x100004
# Clear the first $0xE000 bytes following 0x21000.
movl $0x21000, %edi
mov %edi, %cr3
xorl %eax, %eax
movl $0xE000, %ecx
rep stosl
movl %cr3, %edi
# Set the initial page tables.
# Note that we OR with 0x7 here to allow user-space access, except in the
# first 2 MiB. We also do this with 0x200 to allow forking the page.
# Page-Map Level 4
movl $0x22207, (%edi)
addl $0x1000, %edi
# Page-Directory Pointer Table
movl $0x23207, (%edi)
addl $0x1000, %edi
# Page-Directory (no user-space access here)
movl $0x24003, (%edi) # (First 2 MiB)
movl $0x25003, 8(%edi) # (Second 2 MiB)
addl $0x1000, %edi
# Page-Table
# Memory map the first 4 MiB.
movl $0x3, %ebx
movl $1024, %ecx
SetEntry:
mov %ebx, (%edi)
add $0x1000, %ebx
add $8, %edi
loop SetEntry
# Enable PAE.
mov %cr4, %eax
orl $0x20, %eax
mov %eax, %cr4
# Enable long mode.
mov $0xC0000080, %ecx
rdmsr
orl $0x100, %eax
wrmsr
# Enable paging and enter long mode (still 32-bit)
mov %cr0, %eax
orl $0x80000000, %eax
mov %eax, %cr0
# Load the long mode GDT.
mov GDTPointer, %eax
lgdtl GDTPointer
# Now use the 64-bit code segment, and we are in full 64-bit mode.
ljmp $0x10, $Realm64
.code64
Realm64:
# Now, set up the other segment registers.
cli
mov $0x18, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
# Enable the floating point unit.
mov %cr0, %rax
and $0xFFFD, %ax
or $0x10, %ax
mov %rax, %cr0
fninit
# Enable Streaming SIMD Extensions.
mov %cr0, %rax
and $0xFFFB, %ax
or $0x2, %ax
mov %rax, %cr0
mov %cr4, %rax
or $0x600, %rax
mov %rax, %cr4
# Alright, that was the bootstrap code. Now begin preparing to run the
# actual 64-bit kernel.
jmp Main
.size _start, . - _start
.section .data
GDT64: # Global Descriptor Table (64-bit).
GDTNull: # The null descriptor.
.word 0 # Limit (low).
.word 0 # Base (low).
.byte 0 # Base (middle)
.byte 0 # Access.
.byte 0 # Granularity.
.byte 0 # Base (high).
GDTUnused: # The null descriptor.
.word 0 # Limit (low).
.word 0 # Base (low).
.byte 0 # Base (middle)
.byte 0 # Access.
.byte 0 # Granularity.
.byte 0 # Base (high).
GDTCode: # The code descriptor.
.word 0xFFFF # Limit (low).
.word 0 # Base (low).
.byte 0 # Base (middle)
.byte 0x9A # Access.
.byte 0xAF # Granularity.
.byte 0 # Base (high).
GDTData: # The data descriptor.
.word 0xFFFF # Limit (low).
.word 0 # Base (low).
.byte 0 # Base (middle)
.byte 0x92 # Access.
.byte 0x8F # Granularity.
.byte 0 # Base (high).
GDTPointer: # The GDT-pointer.
.word GDTPointer - GDT64 - 1 # Limit.
.long GDT64 # Base.
.long 0
Main:
# Copy the character B onto the screen so we know it works.
movq $0x242, %r15
movq %r15, %rax
movw %ax, 0xB8000
# Load the pointer to the Multiboot information structure.
mov 0x100000, %ebx
# Load the magic value.
mov 0x100004, %eax
jmp beginkernel
.size Main, . - Main

57
kernel/x64/calltrace.s Normal file
View file

@ -0,0 +1,57 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/calltrace.s
Attempts to unwind the stack and prints the code locations where functions
were called. This greatly aids debugging.
*******************************************************************************/
.section .text
.global calltrace
.type calltrace, @function
calltrace:
push %rbp
push %rbx
movq %rsp, %rbp
push %rbx
movq %rdi, %rbx
testq %rbx, %rbx
jnz 1f
movq %rbp, %rbx
1:
xorl %edi, %edi
calltrace_unwind:
testq %rbx, %rbx
jz calltrace_done
movq 8(%rbx), %rsi # Previous RIP
movq 0(%rbx), %rbx # Previous RBP
pushq %rdi
call calltrace_print_function
popq %rdi
incq %rdi
jmp calltrace_unwind
calltrace_done:
popq %rbx
popq %rbp
retq
.size calltrace, . - calltrace

39
kernel/x64/crti.s Normal file
View file

@ -0,0 +1,39 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/crti.s
Provides the header of the _init and _fini functions.
*******************************************************************************/
.section .init
.global _init
.type _init, @function
_init:
push %rbp
movq %rsp, %rbp
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
.section .fini
.global _fini
.type _fini, @function
_fini:
push %rbp
movq %rsp, %rbp
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */

33
kernel/x64/crtn.s Normal file
View file

@ -0,0 +1,33 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/crtn.s
Provides the tail of the _init and _fini functions.
*******************************************************************************/
.section .init
/* gcc will nicely put the contents of crtend.o's .init section here. */
popq %rbp
ret
.section .fini
/* gcc will nicely put the contents of crtend.o's .fini section here. */
popq %rbp
ret

512
kernel/x64/interrupt.s Normal file
View file

@ -0,0 +1,512 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/interrupt.s
Transfers control to interrupt handlers when interrupts happen.
*******************************************************************************/
.section .text
.global isr0
.type isr0, @function
isr0:
cli
pushq $0 # err_code
pushq $0 # int_no
jmp interrupt_handler_prepare
.global isr1
.type isr1, @function
isr1:
cli
pushq $0 # err_code
pushq $1 # int_no
jmp interrupt_handler_prepare
.global isr2
.type isr2, @function
isr2:
cli
pushq $0 # err_code
pushq $2 # int_no
jmp interrupt_handler_prepare
.global isr3
.type isr3, @function
isr3:
cli
pushq $0 # err_code
pushq $3 # int_no
jmp interrupt_handler_prepare
.global isr4
.type isr4, @function
isr4:
cli
pushq $0 # err_code
pushq $4 # int_no
jmp interrupt_handler_prepare
.global isr5
.type isr5, @function
isr5:
cli
pushq $0 # err_code
pushq $5 # int_no
jmp interrupt_handler_prepare
.global isr6
.type isr6, @function
isr6:
cli
pushq $0 # err_code
pushq $6 # int_no
jmp interrupt_handler_prepare
.global isr7
.type isr7, @function
isr7:
cli
pushq $0 # err_code
pushq $7 # int_no
jmp interrupt_handler_prepare
.global isr8
.type isr8, @function
isr8:
cli
# pushq $0 # err_code pushed by CPU
pushq $8 # int_no
jmp interrupt_handler_prepare
.global isr9
.type isr9, @function
isr9:
cli
pushq $0 # err_code
pushq $9 # int_no
jmp interrupt_handler_prepare
.global isr10
.type isr10, @function
isr10:
cli
# pushq $0 # err_code pushed by CPU
pushq $10 # int_no
jmp interrupt_handler_prepare
.global isr11
.type isr11, @function
isr11:
cli
# pushq $0 # err_code pushed by CPU
pushq $11 # int_no
jmp interrupt_handler_prepare
.global isr12
.type isr12, @function
isr12:
cli
# pushq $0 # err_code pushed by CPU
pushq $12 # int_no
jmp interrupt_handler_prepare
.global isr13
.type isr13, @function
isr13:
cli
# pushq $0 # err_code pushed by CPU
pushq $13 # int_no
jmp interrupt_handler_prepare
.global isr14
.type isr14, @function
isr14:
cli
# pushq $0 # err_code pushed by CPU
pushq $14 # int_no
jmp interrupt_handler_prepare
.global isr15
.type isr15, @function
isr15:
cli
pushq $0 # err_code
pushq $15 # int_no
jmp interrupt_handler_prepare
.global isr16
.type isr16, @function
isr16:
cli
pushq $0 # err_code
pushq $16 # int_no
jmp interrupt_handler_prepare
.global isr17
.type isr17, @function
isr17:
cli
pushq $0 # err_code
pushq $17 # int_no
jmp interrupt_handler_prepare
.global isr18
.type isr18, @function
isr18:
cli
pushq $0 # err_code
pushq $18 # int_no
jmp interrupt_handler_prepare
.global isr19
.type isr19, @function
isr19:
cli
pushq $0 # err_code
pushq $19 # int_no
jmp interrupt_handler_prepare
.global isr20
.type isr20, @function
isr20:
cli
pushq $0 # err_code
pushq $20 # int_no
jmp interrupt_handler_prepare
.global isr21
.type isr21, @function
isr21:
cli
pushq $0 # err_code
pushq $21 # int_no
jmp interrupt_handler_prepare
.global isr22
.type isr22, @function
isr22:
cli
pushq $0 # err_code
pushq $22 # int_no
jmp interrupt_handler_prepare
.global isr23
.type isr23, @function
isr23:
cli
pushq $0 # err_code
pushq $23 # int_no
jmp interrupt_handler_prepare
.global isr24
.type isr24, @function
isr24:
cli
pushq $0 # err_code
pushq $24 # int_no
jmp interrupt_handler_prepare
.global isr25
.type isr25, @function
isr25:
cli
pushq $0 # err_code
pushq $25 # int_no
jmp interrupt_handler_prepare
.global isr26
.type isr26, @function
isr26:
cli
pushq $0 # err_code
pushq $26 # int_no
jmp interrupt_handler_prepare
.global isr27
.type isr27, @function
isr27:
cli
pushq $0 # err_code
pushq $27 # int_no
jmp interrupt_handler_prepare
.global isr28
.type isr28, @function
isr28:
cli
pushq $0 # err_code
pushq $28 # int_no
jmp interrupt_handler_prepare
.global isr29
.type isr29, @function
isr29:
cli
pushq $0 # err_code
pushq $29 # int_no
jmp interrupt_handler_prepare
.global isr30
.type isr30, @function
isr30:
cli
pushq $0 # err_code
pushq $30 # int_no
jmp interrupt_handler_prepare
.global isr31
.type isr31, @function
isr31:
cli
pushq $0 # err_code
pushq $31 # int_no
jmp interrupt_handler_prepare
.global isr128
.type isr128, @function
isr128:
cli
pushq $0 # err_code
pushq $128 # int_no
jmp interrupt_handler_prepare
.global isr130
.type isr130, @function
isr130:
cli
pushq $0 # err_code
pushq $130 # int_no
jmp interrupt_handler_prepare
.global isr131
.type isr131, @function
isr131:
cli
pushq $0 # err_code
pushq $131 # int_no
jmp interrupt_handler_prepare
.global irq0
.type irq0, @function
irq0:
cli
pushq $0 # err_code
pushq $32 # int_no
jmp interrupt_handler_prepare
.global irq1
.type irq1, @function
irq1:
cli
pushq $0 # err_code
pushq $33 # int_no
jmp interrupt_handler_prepare
.global irq2
.type irq2, @function
irq2:
cli
pushq $0 # err_code
pushq $34 # int_no
jmp interrupt_handler_prepare
.global irq3
.type irq3, @function
irq3:
cli
pushq $0 # err_code
pushq $35 # int_no
jmp interrupt_handler_prepare
.global irq4
.type irq4, @function
irq4:
cli
pushq $0 # err_code
pushq $36 # int_no
jmp interrupt_handler_prepare
.global irq5
.type irq5, @function
irq5:
cli
pushq $0 # err_code
pushq $37 # int_no
jmp interrupt_handler_prepare
.global irq6
.type irq6, @function
irq6:
cli
pushq $0 # err_code
pushq $38 # int_no
jmp interrupt_handler_prepare
.global irq7
.type irq7, @function
irq7:
cli
pushq $0 # err_code
pushq $39 # int_no
jmp interrupt_handler_prepare
.global irq8
.type irq8, @function
irq8:
cli
pushq $0 # err_code
pushq $40 # int_no
jmp interrupt_handler_prepare
.global irq9
.type irq9, @function
irq9:
cli
pushq $0 # err_code
pushq $41 # int_no
jmp interrupt_handler_prepare
.global irq10
.type irq10, @function
irq10:
cli
pushq $0 # err_code
pushq $42 # int_no
jmp interrupt_handler_prepare
.global irq11
.type irq11, @function
irq11:
cli
pushq $0 # err_code
pushq $43 # int_no
jmp interrupt_handler_prepare
.global irq12
.type irq12, @function
irq12:
cli
pushq $0 # err_code
pushq $44 # int_no
jmp interrupt_handler_prepare
.global irq13
.type irq13, @function
irq13:
cli
pushq $0 # err_code
pushq $45 # int_no
jmp interrupt_handler_prepare
.global irq14
.type irq14, @function
irq14:
cli
pushq $0 # err_code
pushq $46 # int_no
jmp interrupt_handler_prepare
.global irq15
.type irq15, @function
irq15:
cli
pushq $0 # err_code
pushq $47 # int_no
jmp interrupt_handler_prepare
.global yield_cpu_handler
.type yield_cpu_handler, @function
yield_cpu_handler:
cli
pushq $0 # err_code
pushq $129 # int_no
jmp interrupt_handler_prepare
.global thread_exit_handler
.type thread_exit_handler, @function
thread_exit_handler:
cli
pushq $0 # err_code
pushq $132 # int_no
jmp interrupt_handler_prepare
interrupt_handler_prepare:
movq $1, asm_is_cpu_interrupted
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %r11
pushq %r10
pushq %r9
pushq %r8
pushq %rax
pushq %rcx
pushq %rdx
pushq %rbx
pushq %rsp
pushq %rbp
pushq %rsi
pushq %rdi
# Push the user-space data segment.
movl %ds, %ebp
pushq %rbp
# Load the kernel data segment.
movw $0x10, %bp
movl %ebp, %ds
movl %ebp, %es
movl %ebp, %fs
movl %ebp, %gs
# Push CR2 in case of page faults
movq %cr2, %rbp
pushq %rbp
# Push the current kernel errno value.
movl global_errno, %ebp
pushq %rbp
# Push whether a signal is pending.
movq asm_signal_is_pending, %rbp
pushq %rbp
# Now call the interrupt handler.
movq %rsp, %rdi
call interrupt_handler
load_interrupted_registers:
# Restore whether signals are pending.
popq %rbp
movq %rbp, asm_signal_is_pending
# Restore the previous kernel errno.
popq %rbp
movl %ebp, global_errno
# Remove CR2 from the stack.
addq $8, %rsp
# Restore the user-space data segment.
popq %rbp
movl %ebp, %ds
movl %ebp, %es
movl %ebp, %fs
movl %ebp, %gs
popq %rdi
popq %rsi
popq %rbp
addq $8, %rsp # Don't pop %rsp, may not be defined.
popq %rbx
popq %rdx
popq %rcx
popq %rax
popq %r8
popq %r9
popq %r10
popq %r11
popq %r12
popq %r13
popq %r14
popq %r15
# Remove int_no and err_code
addq $16, %rsp
movq $0, asm_is_cpu_interrupted
# Return to where we came from.
iretq
.size interrupt_handler_prepare, . - interrupt_handler_prepare
.global interrupt_handler_null
.type interrupt_handler_null, @function
interrupt_handler_null:
iretq
.size interrupt_handler_null, . - interrupt_handler_null
.global asm_interrupts_are_enabled
.type asm_interrupts_are_enabled, @function
asm_interrupts_are_enabled:
pushfq
popq %rax
andq $0x000200, %rax # FLAGS_INTERRUPT
retq
.size asm_interrupts_are_enabled, . - asm_interrupts_are_enabled
.global load_registers
.type load_registers, @function
load_registers:
# Let the register struct become our temporary stack
movq %rdi, %rsp
jmp load_interrupted_registers
.size load_registers, . - load_registers

89
kernel/x64/kthread.s Normal file
View file

@ -0,0 +1,89 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/kthread.s
Utilities and synchronization mechanisms for x64 kernel threads.
*******************************************************************************/
.section .text
.global kthread_mutex_trylock
.type kthread_mutex_trylock, @function
kthread_mutex_trylock:
pushq %rbp
movq %rsp, %rbp
movl $-1, %eax
xchgl (%rdi), %eax
not %eax
leaveq
retq
.size kthread_mutex_trylock, . - kthread_mutex_trylock
.global kthread_mutex_lock
.type kthread_mutex_lock, @function
kthread_mutex_lock:
pushq %rbp
movq %rsp, %rbp
kthread_mutex_lock_retry:
movl $-1, %eax
xchgl (%rdi), %eax
testl %eax, %eax
jnz kthread_mutex_lock_failed
leaveq
retq
kthread_mutex_lock_failed:
int $0x81 # Yield the CPU.
jmp kthread_mutex_lock_retry
.size kthread_mutex_lock, . - kthread_mutex_lock
.global kthread_mutex_lock_signal
.type kthread_mutex_lock_signal, @function
kthread_mutex_lock_signal:
pushq %rbp
movq %rsp, %rbp
kthread_mutex_lock_signal_retry:
movq asm_signal_is_pending, %rax
testq %rax, %rax
jnz kthread_mutex_lock_signal_pending
movl $-1, %eax
xchgl (%rdi), %eax
testl %eax, %eax
jnz kthread_mutex_lock_signal_failed
inc %eax
kthread_mutex_lock_signal_out:
leaveq
retq
kthread_mutex_lock_signal_failed:
int $0x81 # Yield the CPU.
jmp kthread_mutex_lock_signal_retry
kthread_mutex_lock_signal_pending:
xorl %eax, %eax
jmp kthread_mutex_lock_signal_out
.size kthread_mutex_lock_signal, . - kthread_mutex_lock_signal
.global kthread_mutex_unlock
.type kthread_mutex_unlock, @function
kthread_mutex_unlock:
pushq %rbp
movq %rsp, %rbp
movl $0, (%rdi)
leaveq
retq
.size kthread_mutex_unlock, . - kthread_mutex_unlock

View file

@ -0,0 +1,211 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/memorymanagement.cpp
Handles memory for the x64 architecture.
*******************************************************************************/
#include <string.h>
#include <sortix/kernel/interrupt.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/memorymanagement.h>
#include "multiboot.h"
#include "x86-family/memorymanagement.h"
namespace Sortix
{
namespace Page
{
extern size_t stackused;
extern size_t stacklength;
void ExtendStack();
}
namespace Memory
{
extern addr_t currentdir;
void InitCPU()
{
// The x64 boot code already set up virtual memory and identity
// mapped the first 2 MiB. This code finishes the job such that
// virtual memory is fully usable and manageable.
// boot.s already initialized everything from 0x1000UL to 0xE000UL
// to zeroes. Since these structures are already used, doing it here
// will be very dangerous.
PML* const BOOTPML4 = (PML* const) 0x21000UL;
PML* const BOOTPML3 = (PML* const) 0x26000UL;
PML* const BOOTPML2 = (PML* const) 0x27000UL;
PML* const BOOTPML1 = (PML* const) 0x28000UL;
// First order of business is to map the virtual memory structures
// to the pre-defined locations in the virtual address space.
addr_t flags = PML_PRESENT | PML_WRITABLE;
// Fractal map the PML1s.
BOOTPML4->entry[511] = (addr_t) BOOTPML4 | flags;
// Fractal map the PML2s.
BOOTPML4->entry[510] = (addr_t) BOOTPML3 | flags | PML_FORK;
BOOTPML3->entry[511] = (addr_t) BOOTPML4 | flags;
// Fractal map the PML3s.
BOOTPML3->entry[510] = (addr_t) BOOTPML2 | flags | PML_FORK;
BOOTPML2->entry[511] = (addr_t) BOOTPML4 | flags;
// Fractal map the PML4s.
BOOTPML2->entry[510] = (addr_t) BOOTPML1 | flags | PML_FORK;
BOOTPML1->entry[511] = (addr_t) BOOTPML4 | flags;
// Add some predefined room for forking address spaces.
PML* const FORKPML2 = (PML* const) 0x29000UL;
PML* const FORKPML1 = (PML* const) 0x2A000UL;
BOOTPML3->entry[0] = (addr_t) FORKPML2 | flags | PML_FORK;
BOOTPML2->entry[0] = (addr_t) FORKPML1 | flags | PML_FORK;
currentdir = (addr_t) BOOTPML4;
// The virtual memory structures are now available on the predefined
// locations. This means the virtual memory code is bootstrapped. Of
// course, we still have no physical page allocator, so that's the
// next step.
PML* const PHYSPML3 = (PML* const) 0x2B000UL;
PML* const PHYSPML2 = (PML* const) 0x2C000UL;
PML* const PHYSPML1 = (PML* const) 0x2D000UL;
PML* const PHYSPML0 = (PML* const) 0x2E000UL;
BOOTPML4->entry[509] = (addr_t) PHYSPML3 | flags;
PHYSPML3->entry[0] = (addr_t) PHYSPML2 | flags;
PHYSPML2->entry[0] = (addr_t) PHYSPML1 | flags;
PHYSPML1->entry[0] = (addr_t) PHYSPML0 | flags;
Page::stackused = 0;
Page::stacklength = 4096UL / sizeof(addr_t);
// The physical memory allocator should now be ready for use. Next
// up, the calling function will fill up the physical allocator with
// plenty of nice physical pages. (see Page::InitPushRegion)
}
// Please note that even if this function exists, you should still clean
// up the address space of a process _before_ calling
// DestroyAddressSpace. This is just a hack because it currently is
// impossible to clean up PLM1's using the MM api!
// ---
// TODO: This function is duplicated in {x86,x64}/memorymanagement.cpp!
// ---
void RecursiveFreeUserspacePages(size_t level, size_t offset)
{
PML* pml = PMLS[level] + offset;
for ( size_t i = 0; i < ENTRIES; i++ )
{
addr_t entry = pml->entry[i];
if ( !(entry & PML_PRESENT) ) { continue; }
if ( !(entry & PML_USERSPACE) ) { continue; }
if ( !(entry & PML_FORK) ) { continue; }
if ( level > 1 ) { RecursiveFreeUserspacePages(level-1, offset * ENTRIES + i); }
addr_t addr = pml->entry[i] & PML_ADDRESS;
// No need to unmap the page, we just need to mark it as unused.
Page::PutUnlocked(addr);
}
}
void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* user)
{
// Look up the last few entries used for the fractal mapping. These
// cannot be unmapped as that would destroy the world. Instead, we
// will remember them, switch to another adress space, and safely
// mark them as unused. Also handling the forking related pages.
addr_t fractal3 = (PMLS[4] + 0)->entry[510UL];
addr_t fork2 = (PMLS[3] + 510UL)->entry[0];
addr_t fractal2 = (PMLS[3] + 510UL)->entry[510];
addr_t fork1 = (PMLS[2] + 510UL * 512UL + 510UL)->entry[0];
addr_t fractal1 = (PMLS[2] + 510UL * 512UL + 510UL)->entry[510];
addr_t dir = currentdir;
// We want to free the pages, but we are still using them ourselves,
// so lock the page allocation structure until we are done.
Page::Lock();
// In case any pages wasn't cleaned at this point.
// TODO: Page::Put calls may internally Page::Get and then reusing pages we are not done with just yet
RecursiveFreeUserspacePages(TOPPMLLEVEL, 0);
// Switch to the address space from when the world was originally
// created. It should contain the kernel, the whole kernel, and
// nothing but the kernel.
PML* const BOOTPML4 = (PML* const) 0x21000UL;
if ( !fallback )
fallback = (addr_t) BOOTPML4;
if ( func )
func(fallback, user);
else
SwitchAddressSpace(fallback);
// Ok, now we got marked everything left behind as unused, we can
// now safely let another thread use the pages.
Page::Unlock();
// These are safe to free since we switched address space.
Page::Put(fractal3 & PML_ADDRESS);
Page::Put(fractal2 & PML_ADDRESS);
Page::Put(fractal1 & PML_ADDRESS);
Page::Put(fork2 & PML_ADDRESS);
Page::Put(fork1 & PML_ADDRESS);
Page::Put(dir & PML_ADDRESS);
}
const size_t KERNEL_STACK_SIZE = 256UL * 1024UL;
const addr_t KERNEL_STACK_END = 0xFFFF800000001000UL;
const addr_t KERNEL_STACK_START = KERNEL_STACK_END + KERNEL_STACK_SIZE;
const addr_t VIRTUAL_AREA_LOWER = KERNEL_STACK_START;
const addr_t VIRTUAL_AREA_UPPER = 0xFFFFFE8000000000UL;
void GetKernelVirtualArea(addr_t* from, size_t* size)
{
*from = KERNEL_STACK_END;
*size = VIRTUAL_AREA_UPPER - VIRTUAL_AREA_LOWER;
}
void GetUserVirtualArea(uintptr_t* from, size_t* size)
{
*from = 0x400000; // 4 MiB.
*size = 0x800000000000 - *from; // 128 TiB - 4 MiB.
}
addr_t GetKernelStack()
{
return KERNEL_STACK_START;
}
size_t GetKernelStackSize()
{
return KERNEL_STACK_SIZE;
}
}
}

View file

@ -0,0 +1,56 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/memorymanagement.h
Handles memory for the x64 architecture.
*******************************************************************************/
#ifndef SORTIX_X64_MEMORYMANAGEMENT_H
#define SORTIX_X64_MEMORYMANAGEMENT_H
namespace Sortix
{
namespace Memory
{
const size_t TOPPMLLEVEL = 4;
const size_t ENTRIES = 4096UL / sizeof(addr_t);
const size_t TRANSBITS = 9;
PML* const PMLS[TOPPMLLEVEL + 1] =
{
(PML* const) 0x0,
(PML* const) 0xFFFFFF8000000000UL,
(PML* const) 0xFFFFFF7FC0000000UL,
(PML* const) 0XFFFFFF7FBFE00000UL,
(PML* const) 0xFFFFFF7FBFDFF000UL,
};
PML* const FORKPML = (PML* const) 0xFFFFFF0000000000UL;
}
namespace Page
{
addr_t* const STACK = (addr_t* const) 0xFFFFFE8000000000UL;
const size_t MAXSTACKSIZE = (512UL*1024UL*1024UL*1024UL);
const size_t MAXSTACKLENGTH = MAXSTACKSIZE / sizeof(addr_t);
}
}
#endif

84
kernel/x64/process.cpp Normal file
View file

@ -0,0 +1,84 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/process.cpp
CPU-specific process code.
*******************************************************************************/
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <sortix/fork.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/process.h>
namespace Sortix
{
void Process::ExecuteCPU(int argc, char** argv, int envc, char** envp,
addr_t stackpos, addr_t entry,
CPU::InterruptRegisters* regs)
{
const uint64_t CS = 0x18;
const uint64_t DS = 0x20;
const uint64_t RPL = 0x3;
regs->rdi = argc;
regs->rsi = (size_t) argv;
regs->rdx = envc;
regs->rcx = (size_t) envp;
regs->rip = entry;
regs->userrsp = stackpos & ~(15UL);
regs->rbp = regs->userrsp;
regs->cs = CS | RPL;
regs->ds = DS | RPL;
regs->ss = DS | RPL;
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
}
void InitializeThreadRegisters(CPU::InterruptRegisters* regs,
const tforkregs_t* requested)
{
memset(regs, 0, sizeof(*regs));
regs->rip = requested->rip;
regs->userrsp = requested->rsp;
regs->rax = requested->rax;
regs->rbx = requested->rbx;
regs->rcx = requested->rcx;
regs->rdx = requested->rdx;
regs->rdi = requested->rdi;
regs->rsi = requested->rsi;
regs->rbp = requested->rbp;
regs->r8 = requested->r8;
regs->r9 = requested->r9;
regs->r10 = requested->r10;
regs->r11 = requested->r11;
regs->r12 = requested->r12;
regs->r13 = requested->r13;
regs->r14 = requested->r14;
regs->r15 = requested->r15;
regs->cs = 0x18 | 0x3;
regs->ds = 0x20 | 0x3;
regs->ss = 0x20 | 0x3;
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
}
}

83
kernel/x64/syscall.s Normal file
View file

@ -0,0 +1,83 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/syscall.s
An assembly stub that acts as glue for system calls.
*******************************************************************************/
.global syscall_handler
.section .text
.type syscall_handler, @function
syscall_handler:
# The processor disabled interrupts during the int $0x80 instruction,
# however Sortix system calls runs with interrupts enabled such that they
# can be pre-empted.
sti
movl $0, global_errno # Reset errno
pushq %rbp
movq %rsp, %rbp
# Make sure the requested system call is valid, if not, then fix it.
cmp SYSCALL_MAX, %rax
jae fix_syscall
valid_syscall:
# Read a system call function pointer.
xorq %r11, %r11
movq syscall_list(%r11,%rax,8), %rax
# Oh how nice, user-space put the parameters in: rdi, rsi, rdx, rcx, r8, r9
# Call the system call.
callq *%rax
# Return to user-space, system call result in %rax:%rdx, errno in %ecx.
popq %rbp
movl global_errno, %ecx
# If any signals are pending, fire them now.
movq asm_signal_is_pending, %rdi
testq %rdi, %rdi
jnz call_signal_dispatcher
iretq
fix_syscall:
# Call the null system call instead.
xorq %rax, %rax
jmp valid_syscall
call_signal_dispatcher:
# We can't return to this location after the signal, since if any system
# call is made this stack will get reused and all our nice temporaries wil
# be garbage. We therefore pass the kernel the state to return to and it'll
# handle it for us when the signal is over.
movq 0(%rsp), %rdi # userspace rip
movq 16(%rsp), %rsi # userspace rflags
movq 24(%rsp), %r8 # userspace rsp, note %rcx is used for errno
int $130 # Deliver pending signals.
# If we end up here, it means that the signal didn't override anything and
# that we should just go ahead and return to userspace ourselves.
iretq
.size syscall_handler, .-syscall_handler

155
kernel/x64/thread.cpp Normal file
View file

@ -0,0 +1,155 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/thread.cpp
x64 specific parts of thread.cpp.
*******************************************************************************/
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/thread.h>
namespace Sortix
{
void Thread::SaveRegisters(const CPU::InterruptRegisters* src)
{
registers.rip = src->rip;
registers.userrsp = src->userrsp;
registers.rax = src->rax;
registers.rbx = src->rbx;
registers.rcx = src->rcx;
registers.rdx = src->rdx;
registers.rdi = src->rdi;
registers.rsi = src->rsi;
registers.rbp = src->rbp;
registers.r8 = src->r8;
registers.r9 = src->r9;
registers.r10 = src->r10;
registers.r11 = src->r11;
registers.r12 = src->r12;
registers.r13 = src->r13;
registers.r14 = src->r14;
registers.r15 = src->r15;
registers.cs = src->cs;
registers.ds = src->ds;
registers.ss = src->ss;
registers.rflags = src->rflags;
registers.kerrno = src->kerrno;
registers.signal_pending = src->signal_pending;
}
void Thread::LoadRegisters(CPU::InterruptRegisters* dest)
{
dest->rip = registers.rip;
dest->userrsp = registers.userrsp;
dest->rax = registers.rax;
dest->rbx = registers.rbx;
dest->rcx = registers.rcx;
dest->rdx = registers.rdx;
dest->rdi = registers.rdi;
dest->rsi = registers.rsi;
dest->rbp = registers.rbp;
dest->r8 = registers.r8;
dest->r9 = registers.r9;
dest->r10 = registers.r10;
dest->r11 = registers.r11;
dest->r12 = registers.r12;
dest->r13 = registers.r13;
dest->r14 = registers.r14;
dest->r15 = registers.r15;
dest->cs = registers.cs;
dest->ds = registers.ds;
dest->ss = registers.ss;
dest->rflags = registers.rflags;
dest->kerrno = registers.kerrno;
dest->signal_pending = registers.signal_pending;
}
void SetupKernelThreadRegs(CPU::InterruptRegisters* regs, ThreadEntry entry,
void* user, addr_t stack, size_t stacksize)
{
// Instead of directly calling the desired entry point, we call a small
// stub that calls it for us and then destroys the kernel thread if
// the entry function returns. Note that since we use a register based
// calling convention, we call BootstrapKernelThread directly.
regs->rip = (addr_t) BootstrapKernelThread;
regs->userrsp = stack + stacksize - sizeof(size_t);
*((size_t*) regs->userrsp) = 0; /* back tracing stops at NULL rip */
regs->rax = 0;
regs->rbx = 0;
regs->rcx = 0;
regs->rdx = 0;
regs->rdi = (addr_t) user;
regs->rsi = (addr_t) entry;
regs->rbp = 0;
regs->r8 = 0;
regs->r9 = 0;
regs->r10 = 0;
regs->r11 = 0;
regs->r12 = 0;
regs->r13 = 0;
regs->r14 = 0;
regs->r15 = 0;
regs->cs = KCS | KRPL;
regs->ds = KDS | KRPL;
regs->ss = KDS | KRPL;
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
regs->kerrno = 0;
regs->signal_pending = 0;
}
void Thread::HandleSignalFixupRegsCPU(CPU::InterruptRegisters* regs)
{
if ( regs->InUserspace() )
return;
regs->rip = regs->rdi;
regs->rflags = regs->rsi;
regs->userrsp = regs->r8;
regs->cs = UCS | URPL;
regs->ds = UDS | URPL;
regs->ss = UDS | URPL;
}
void Thread::HandleSignalCPU(CPU::InterruptRegisters* regs)
{
const size_t STACK_ALIGNMENT = 16UL;
const size_t RED_ZONE_SIZE = 128UL;
regs->userrsp -= RED_ZONE_SIZE;
regs->userrsp &= ~(STACK_ALIGNMENT-1UL);
regs->rbp = regs->userrsp;
regs->rdi = currentsignal;
regs->rip = (size_t) sighandler;
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
regs->kerrno = 0;
regs->signal_pending = 0;
}
void Thread::GotoOnSigKill(CPU::InterruptRegisters* regs)
{
regs->rip = (unsigned long) Thread__OnSigKill;
regs->rdi = (unsigned long) this;
regs->userrsp = regs->rbp = kernelstackpos + kernelstacksize;
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
regs->cs = KCS | KRPL;
regs->ds = KDS | KRPL;
regs->ss = KDS | KRPL;
regs->kerrno = 0;
regs->signal_pending = 0;
}
}

49
kernel/x64/x64.cpp Normal file
View file

@ -0,0 +1,49 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix 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 General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x64/x64.cpp
CPU stuff for the x64 platform.
*******************************************************************************/
#include <sortix/kernel/cpu.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/log.h>
namespace Sortix
{
namespace X64
{
void InterruptRegisters::LogRegisters() const
{
Log::PrintF("[cr2=0x%zx,ds=0x%zx,rdi=0x%zx,rsi=0x%zx,rbp=0x%zx,"
"rsp=0x%zx,rbx=0x%zx,rdx=0x%zx,rcx=0x%zx,rax=0x%zx,"
"r8=0x%zx,r9=0x%zx,r10=0x%zx,r11=0x%zx,r12=0x%zx,"
"r13=0x%zx,r14=0x%zx,r15=0x%zx,int_no=0x%zx,"
"err_code=0x%zx,rip=0x%zx,cs=0x%zx,rflags=0x%zx,"
"userrsp=0x%zx,ss=0x%zx]",
cr2, ds, rdi, rsi, rbp,
rsp, rbx, rdx, rcx, rax,
r8, r9, r10, r11, r12,
r13, r14, r15, int_no,
err_code, rip, cs, rflags,
userrsp, ss);
}
}
}