Initialize the GDT in the bootstrap assembly.
This commit is contained in:
parent
cf55531aae
commit
a422c394b8
|
@ -31,14 +31,14 @@ BOOTOBJS:=
|
||||||
ifeq ($(CPU),x86)
|
ifeq ($(CPU),x86)
|
||||||
X86FAMILY:=1
|
X86FAMILY:=1
|
||||||
CPUDIR:=$(CPU)
|
CPUDIR:=$(CPU)
|
||||||
CPUOBJS:=$(CPUDIR)/boot.o $(CPUDIR)/base.o
|
CPUOBJS:=$(CPUDIR)/boot.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(CPU),x64)
|
ifeq ($(CPU),x64)
|
||||||
X86FAMILY:=1
|
X86FAMILY:=1
|
||||||
CPUDIR:=$(CPU)
|
CPUDIR:=$(CPU)
|
||||||
CXXFLAGS:=$(CXXFLAGS) -mno-red-zone -mno-mmx -mno-sse -mno-sse2
|
CXXFLAGS:=$(CXXFLAGS) -mno-red-zone -mno-mmx -mno-sse -mno-sse2
|
||||||
CPUOBJS:=$(CPUDIR)/boot.o $(CPUDIR)/base.o
|
CPUOBJS:=$(CPUDIR)/boot.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef CPUDIR
|
ifndef CPUDIR
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2013, 2014.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2013, 2014, 2015.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -30,7 +30,6 @@ namespace Sortix {
|
||||||
extern "C" __attribute__((noreturn)) void HaltKernel();
|
extern "C" __attribute__((noreturn)) void HaltKernel();
|
||||||
extern "C" __attribute__((noreturn)) void Panic(const char* error);
|
extern "C" __attribute__((noreturn)) void Panic(const char* error);
|
||||||
extern "C" __attribute__((noreturn, format(printf, 1, 2))) void PanicF(const char* format, ...);
|
extern "C" __attribute__((noreturn, format(printf, 1, 2))) void PanicF(const char* format, ...);
|
||||||
extern "C" void WaitForInterrupt();
|
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,8 @@ const uint32_t UCS = 0x18;
|
||||||
const uint32_t UDS = 0x20;
|
const uint32_t UDS = 0x20;
|
||||||
const uint32_t URPL = 0x3;
|
const uint32_t URPL = 0x3;
|
||||||
const uint32_t RPLMASK = 0x3;
|
const uint32_t RPLMASK = 0x3;
|
||||||
|
#define GDT_FS_ENTRY 6
|
||||||
|
#define GDT_GS_ENTRY 7
|
||||||
|
|
||||||
struct interrupt_context
|
struct interrupt_context
|
||||||
{
|
{
|
||||||
|
|
|
@ -93,7 +93,7 @@
|
||||||
#include "x86-family/gdt.h"
|
#include "x86-family/gdt.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Keep the stack size aligned with $CPU/base.s
|
// Keep the stack size aligned with $CPU/boot.s
|
||||||
const size_t STACK_SIZE = 64*1024;
|
const size_t STACK_SIZE = 64*1024;
|
||||||
extern "C" { __attribute__((aligned(16))) size_t stack[STACK_SIZE / sizeof(size_t)]; }
|
extern "C" { __attribute__((aligned(16))) size_t stack[STACK_SIZE / sizeof(size_t)]; }
|
||||||
|
|
||||||
|
@ -276,10 +276,6 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
// Initialize paging and virtual memory.
|
// Initialize paging and virtual memory.
|
||||||
Memory::Init(bootinfo);
|
Memory::Init(bootinfo);
|
||||||
|
|
||||||
// Initialize the GDT and TSS structures.
|
|
||||||
GDT::Init();
|
|
||||||
GDT::SetKernelStack((uintptr_t) stack + STACK_SIZE);
|
|
||||||
|
|
||||||
// Initialize the interrupt handler table and enable interrupts.
|
// Initialize the interrupt handler table and enable interrupts.
|
||||||
Interrupt::Init();
|
Interrupt::Init();
|
||||||
|
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
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
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014, 2015.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -26,6 +26,12 @@
|
||||||
.section .text
|
.section .text
|
||||||
.text 0x100000
|
.text 0x100000
|
||||||
|
|
||||||
|
# Multiboot header.
|
||||||
|
.align 4
|
||||||
|
.long 0x1BADB002 # Magic.
|
||||||
|
.long 0x00000003 # Flags.
|
||||||
|
.long -(0x1BADB002 + 0x00000003) # Checksum
|
||||||
|
|
||||||
.global _start
|
.global _start
|
||||||
.global __start
|
.global __start
|
||||||
.type _start, @function
|
.type _start, @function
|
||||||
|
@ -33,34 +39,31 @@
|
||||||
.code32
|
.code32
|
||||||
_start:
|
_start:
|
||||||
__start:
|
__start:
|
||||||
jmp prepare_kernel_execution
|
# Initialize the stack pointer. The magic value is from kernel.cpp.
|
||||||
|
movl $(stack + 65536), %esp # 64 KiB, see kernel.cpp (See below also)
|
||||||
|
|
||||||
# Align 32 bits boundary.
|
# Finish installing the kernel stack into the Task Switch Segment.
|
||||||
.align 4
|
movl %esp, tss + 4
|
||||||
|
movl $0, tss + 8
|
||||||
|
|
||||||
# Multiboot header.
|
# Finish installing the Task Switch Segment into the Global Descriptor Table.
|
||||||
multiboot_header:
|
movl $tss, %ecx
|
||||||
# Magic.
|
movw %cx, gdt + 0x28 + 2
|
||||||
.long 0x1BADB002
|
shrl $16, %ecx
|
||||||
# Flags.
|
movb %cl, gdt + 0x28 + 4
|
||||||
.long 0x00000003
|
shrl $8, %ecx
|
||||||
# Checksum.
|
movb %cl, gdt + 0x28 + 7
|
||||||
.long -(0x1BADB002 + 0x00000003)
|
movl $0, gdt + 0x28 + 8
|
||||||
|
|
||||||
prepare_kernel_execution:
|
# We got our multiboot information in various registers.
|
||||||
# We got our multiboot information in various registers. But we are going
|
pushl $0
|
||||||
# to need these registers. But where can we store them then? Oh hey, let's
|
pushl %eax # Multiboot magic value.
|
||||||
# store then in the code already run!
|
pushl $0
|
||||||
|
pushl %ebx # Multiboot information structure pointer.
|
||||||
# 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.
|
# Clear the first $0xE000 bytes following 0x21000.
|
||||||
movl $0x21000, %edi
|
movl $0x21000, %edi
|
||||||
mov %edi, %cr3
|
movl %edi, %cr3
|
||||||
xorl %eax, %eax
|
xorl %eax, %eax
|
||||||
movl $0xE000, %ecx
|
movl $0xE000, %ecx
|
||||||
rep stosl
|
rep stosl
|
||||||
|
@ -88,45 +91,56 @@ prepare_kernel_execution:
|
||||||
movl $0x3, %ebx
|
movl $0x3, %ebx
|
||||||
movl $1024, %ecx
|
movl $1024, %ecx
|
||||||
|
|
||||||
SetEntry:
|
1:
|
||||||
mov %ebx, (%edi)
|
movl %ebx, (%edi)
|
||||||
add $0x1000, %ebx
|
addl $0x1000, %ebx
|
||||||
add $8, %edi
|
addl $8, %edi
|
||||||
loop SetEntry
|
loop 1b
|
||||||
|
|
||||||
# Enable PAE.
|
# Enable PAE.
|
||||||
mov %cr4, %eax
|
movl %cr4, %eax
|
||||||
orl $0x20, %eax
|
orl $0x20, %eax
|
||||||
mov %eax, %cr4
|
movl %eax, %cr4
|
||||||
|
|
||||||
# Enable long mode.
|
# Enable long mode.
|
||||||
mov $0xC0000080, %ecx
|
movl $0xC0000080, %ecx
|
||||||
rdmsr
|
rdmsr
|
||||||
orl $0x100, %eax
|
orl $0x100, %eax
|
||||||
wrmsr
|
wrmsr
|
||||||
|
|
||||||
# Enable paging and enter long mode (still 32-bit)
|
# Enable paging and enter long mode (still 32-bit)
|
||||||
mov %cr0, %eax
|
movl %cr0, %eax
|
||||||
orl $0x80000000, %eax
|
orl $0x80000000, %eax
|
||||||
mov %eax, %cr0
|
movl %eax, %cr0
|
||||||
|
|
||||||
# Load the long mode GDT.
|
# Load the Global Descriptor Table pointer register.
|
||||||
mov GDTPointer, %eax
|
subl $6, %esp
|
||||||
lgdtl GDTPointer
|
movw gdt_size_minus_one, %cx
|
||||||
|
movw %cx, 0(%esp)
|
||||||
|
movl $gdt, %ecx
|
||||||
|
movl %ecx, 2(%esp)
|
||||||
|
lgdt 0(%esp)
|
||||||
|
addl $6, %esp
|
||||||
|
|
||||||
# Now use the 64-bit code segment, and we are in full 64-bit mode.
|
# Now use the 64-bit code segment, and we are in full 64-bit mode.
|
||||||
ljmp $0x10, $Realm64
|
ljmp $0x08, $2f
|
||||||
|
|
||||||
.code64
|
.code64
|
||||||
Realm64:
|
2:
|
||||||
|
# Switch ds, es, fs, gs, ss to the kernel data segment (0x10).
|
||||||
|
movw $0x10, %cx
|
||||||
|
movw %cx, %ds
|
||||||
|
movw %cx, %es
|
||||||
|
movw %cx, %ss
|
||||||
|
|
||||||
# Now, set up the other segment registers.
|
# Switch the task switch segment register to the task switch segment (0x28).
|
||||||
cli
|
movw $(0x28 /* TSS */ | 0x3 /* RPL */), %cx
|
||||||
mov $0x18, %ax
|
ltr %cx
|
||||||
mov %ax, %ds
|
|
||||||
mov %ax, %es
|
# Switch to the thread local fs and gs segments.
|
||||||
mov %ax, %fs
|
movw $(0x20 /* DS */ | 0x3 /* RPL */), %cx
|
||||||
mov %ax, %gs
|
movw %cx, %fs
|
||||||
|
movw %cx, %gs
|
||||||
|
|
||||||
# Enable the floating point unit.
|
# Enable the floating point unit.
|
||||||
mov %cr0, %rax
|
mov %cr0, %rax
|
||||||
|
@ -147,58 +161,18 @@ Realm64:
|
||||||
# Store a copy of the initialial floating point registers.
|
# Store a copy of the initialial floating point registers.
|
||||||
fxsave fpu_initialized_regs
|
fxsave fpu_initialized_regs
|
||||||
|
|
||||||
# Alright, that was the bootstrap code. Now begin preparing to run the
|
# Enter the high-level kernel proper.
|
||||||
# actual 64-bit kernel.
|
pop %rsi # Multiboot information structure pointer.
|
||||||
jmp Main
|
pop %rdi # Multiboot magic value.
|
||||||
|
call KernelInit
|
||||||
|
|
||||||
|
jmp HaltKernel
|
||||||
.size _start, . - _start
|
.size _start, . - _start
|
||||||
.size __start, . - __start
|
.size __start, . - __start
|
||||||
|
.global HaltKernel
|
||||||
.section .data
|
.type HaltKernel, @function
|
||||||
GDT64: # Global Descriptor Table (64-bit).
|
HaltKernel:
|
||||||
GDTNull: # The null descriptor.
|
cli
|
||||||
.word 0 # Limit (low).
|
hlt
|
||||||
.word 0 # Base (low).
|
jmp HaltKernel
|
||||||
.byte 0 # Base (middle)
|
.size HaltKernel, . - HaltKernel
|
||||||
.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
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
x86-family/gdt.cpp
|
x86-family/gdt.cpp
|
||||||
Initializes and handles the GDT and TSS.
|
GDT and TSS.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ struct gdt_entry
|
||||||
uint8_t base_high;
|
uint8_t base_high;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
struct gdt_entry64
|
struct gdt_entry64
|
||||||
{
|
{
|
||||||
uint16_t limit_low;
|
uint16_t limit_low;
|
||||||
|
@ -55,25 +56,15 @@ struct gdt_entry64
|
||||||
uint32_t base_highest;
|
uint32_t base_highest;
|
||||||
uint32_t reserved0;
|
uint32_t reserved0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Do this in another way that doesn't require a silly structure .
|
|
||||||
struct gdt_ptr
|
|
||||||
{
|
|
||||||
uint16_t limit;
|
|
||||||
#if defined(__i386__)
|
|
||||||
uint32_t base;
|
|
||||||
#else
|
|
||||||
uint64_t base;
|
|
||||||
#endif
|
#endif
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
struct tss_entry
|
struct tss_entry
|
||||||
{
|
{
|
||||||
uint32_t prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list.
|
uint32_t prev_tss;
|
||||||
uint32_t esp0; // The stack pointer to load when we change to kernel mode.
|
uint32_t esp0;
|
||||||
uint32_t ss0; // The stack segment to load when we change to kernel mode.
|
uint32_t ss0;
|
||||||
uint32_t esp1; // Unused...
|
uint32_t esp1;
|
||||||
uint32_t ss1;
|
uint32_t ss1;
|
||||||
uint32_t esp2;
|
uint32_t esp2;
|
||||||
uint32_t ss2;
|
uint32_t ss2;
|
||||||
|
@ -88,13 +79,13 @@ struct tss_entry
|
||||||
uint32_t ebp;
|
uint32_t ebp;
|
||||||
uint32_t esi;
|
uint32_t esi;
|
||||||
uint32_t edi;
|
uint32_t edi;
|
||||||
uint32_t es; // The value to load into ES when we change to kernel mode.
|
uint32_t es;
|
||||||
uint32_t cs; // The value to load into CS when we change to kernel mode.
|
uint32_t cs;
|
||||||
uint32_t ss; // The value to load into SS when we change to kernel mode.
|
uint32_t ss;
|
||||||
uint32_t ds; // The value to load into DS when we change to kernel mode.
|
uint32_t ds;
|
||||||
uint32_t fs; // The value to load into FS when we change to kernel mode.
|
uint32_t fs;
|
||||||
uint32_t gs; // The value to load into GS when we change to kernel mode.
|
uint32_t gs;
|
||||||
uint32_t ldt; // Unused...
|
uint32_t ldt;
|
||||||
uint16_t trap;
|
uint16_t trap;
|
||||||
uint16_t iomap_base;
|
uint16_t iomap_base;
|
||||||
};
|
};
|
||||||
|
@ -105,164 +96,148 @@ struct tss_entry
|
||||||
uint64_t stack0; /* This is not naturally aligned, so packed is needed. */
|
uint64_t stack0; /* This is not naturally aligned, so packed is needed. */
|
||||||
uint64_t stack1;
|
uint64_t stack1;
|
||||||
uint64_t stack2;
|
uint64_t stack2;
|
||||||
uint64_t reserved2;
|
uint64_t reserved1;
|
||||||
uint64_t ist[7];
|
uint64_t ist[7];
|
||||||
uint64_t reserved3;
|
uint64_t reserved2;
|
||||||
uint16_t reserved4;
|
uint16_t reserved3;
|
||||||
uint16_t iomap_base;
|
uint16_t iomap_base;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__i386__)
|
extern "C" {
|
||||||
const size_t GDT_NUM_ENTRIES = 9;
|
|
||||||
const size_t GDT_FS_ENTRY = 7;
|
|
||||||
const size_t GDT_GS_ENTRY = 8;
|
|
||||||
#else
|
|
||||||
const size_t GDT_NUM_ENTRIES = 7;
|
|
||||||
#endif
|
|
||||||
static struct gdt_entry gdt_entries[GDT_NUM_ENTRIES];
|
|
||||||
|
|
||||||
static struct tss_entry tss_entry;
|
const size_t STACK_SIZE = 64*1024;
|
||||||
|
extern size_t stack[STACK_SIZE / sizeof(size_t)];
|
||||||
|
|
||||||
const uint8_t GRAN_64_BIT_MODE = 1 << 5;
|
struct tss_entry tss =
|
||||||
const uint8_t GRAN_32_BIT_MODE = 1 << 6;
|
|
||||||
const uint8_t GRAN_4KIB_BLOCKS = 1 << 7;
|
|
||||||
|
|
||||||
void SetGate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
|
|
||||||
{
|
{
|
||||||
struct gdt_entry* entry = (struct gdt_entry*) &gdt_entries[num];
|
#if defined(__i386__)
|
||||||
|
.prev_tss = 0, /* c++ */
|
||||||
|
.esp0 = 0 /*(uintptr_t) stack + sizeof(stack)*/,
|
||||||
|
.ss0 = 0x10 /* Kernel Data Segment */,
|
||||||
|
.esp1 = 0, /* c++ */
|
||||||
|
.ss1 = 0, /* c++ */
|
||||||
|
.esp2 = 0, /* c++ */
|
||||||
|
.ss2 = 0, /* c++ */
|
||||||
|
.cr3 = 0, /* c++ */
|
||||||
|
.eip = 0, /* c++ */
|
||||||
|
.eflags = 0, /* c++ */
|
||||||
|
.eax = 0, /* c++ */
|
||||||
|
.ecx = 0, /* c++ */
|
||||||
|
.edx = 0, /* c++ */
|
||||||
|
.ebx = 0, /* c++ */
|
||||||
|
.esp = 0, /* c++ */
|
||||||
|
.ebp = 0, /* c++ */
|
||||||
|
.esi = 0, /* c++ */
|
||||||
|
.edi = 0, /* c++ */
|
||||||
|
.es = 0x13 /* Kernel Data Segment */,
|
||||||
|
.cs = 0x0B /* Kernel Code Segment */,
|
||||||
|
.ss = 0, /* c++ */
|
||||||
|
.ds = 0x13 /* Kernel Data Segment */,
|
||||||
|
.fs = 0x13 /* Kernel Data Segment */,
|
||||||
|
.gs = 0x13 /* Kernel Data Segment */,
|
||||||
|
.ldt = 0, /* c++ */
|
||||||
|
.trap = 0, /* c++ */
|
||||||
|
.iomap_base = 0, /* c++ */
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
.reserved0 = 0, /* c++ */
|
||||||
|
.stack0 = 0 /*(uintptr_t) stack + sizeof(stack)*/,
|
||||||
|
.stack1 = 0, /* c++ */
|
||||||
|
.stack2 = 0, /* c++ */
|
||||||
|
.reserved1 = 0, /* c++ */
|
||||||
|
.ist = { 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
.reserved2 = 0,
|
||||||
|
.reserved3 = 0,
|
||||||
|
.iomap_base = 0,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
entry->base_low = base >> 0 & 0xFFFF;
|
} // extern "C"
|
||||||
entry->base_middle = base >> 16 & 0xFF;
|
|
||||||
entry->base_high = base >> 24 & 0xFF;
|
|
||||||
|
|
||||||
entry->limit_low = limit & 0xFFFF;
|
#define GRAN_64_BIT_MODE (1 << 5)
|
||||||
entry->granularity = (limit >> 16 & 0x0F) | (gran & 0xF0);
|
#define GRAN_32_BIT_MODE (1 << 6)
|
||||||
|
#define GRAN_4KIB_BLOCKS (1 << 7)
|
||||||
|
|
||||||
entry->access = access;
|
#define GDT_ENTRY(base, limit, access, granularity) \
|
||||||
}
|
{ (limit) & 0xFFFF, /* limit_low */ \
|
||||||
|
(uint16_t) ((base) >> 0 & 0xFFFF), /* base_low */ \
|
||||||
|
(uint8_t) ((base) >> 16 & 0xFF), /* base_middle */ \
|
||||||
|
(access) & 0xFF, /* access */ \
|
||||||
|
((limit) >> 16 & 0x0F) | ((granularity) & 0xF0), /* granularity */ \
|
||||||
|
(uint8_t) ((base) >> 24 & 0xFF), /* base_high */ }
|
||||||
|
|
||||||
void SetGate64(int32_t num, uint64_t base, uint32_t limit, uint8_t access, uint8_t gran)
|
#if defined(__x86_64__)
|
||||||
{
|
#define GDT_ENTRY64(base, limit, access, granularity) \
|
||||||
struct gdt_entry64* entry = (struct gdt_entry64*) &gdt_entries[num];
|
{ (limit) & 0xFFFF, /* limit_low */ \
|
||||||
|
(uint16_t) ((base) >> 0 & 0xFFFF), /* base_low */ \
|
||||||
entry->base_low = base >> 0 & 0xFFFF;
|
(uint8_t) ((base) >> 16 & 0xFF), /* base_middle */ \
|
||||||
entry->base_middle = base >> 16 & 0xFF;
|
(access) & 0xFF, /* access */ \
|
||||||
entry->base_high = base >> 24 & 0xFF;
|
((limit) >> 16 & 0x0F) | ((granularity) & 0xF0), /* granularity */ \
|
||||||
entry->base_highest = base >> 32;
|
(uint8_t) ((base) >> 24 & 0xFF), /* base_high */ }, \
|
||||||
|
{ (uint16_t) ((base) >> 32 & 0xFFFF), /* base_highest */ \
|
||||||
entry->limit_low = limit & 0xFFFF;
|
(uint16_t) ((base) >> 48 & 0xFFFF), /* base_highest */ \
|
||||||
entry->granularity = (limit >> 16 & 0x0F) | (gran & 0xF0);
|
0, /* reserved0 */ \
|
||||||
|
0, /* reserved0 */ \
|
||||||
entry->access = access;
|
0, /* reserved0 */ \
|
||||||
entry->reserved0 = 0;
|
0, /* reserved0 */ }
|
||||||
}
|
#endif
|
||||||
|
|
||||||
void Init()
|
extern "C" {
|
||||||
|
|
||||||
|
struct gdt_entry gdt[] =
|
||||||
{
|
{
|
||||||
|
/* 0x00: Null segment */
|
||||||
|
GDT_ENTRY(0, 0, 0, 0),
|
||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
const uint8_t gran = GRAN_4KIB_BLOCKS | GRAN_32_BIT_MODE;
|
/* 0x08: Kernel Code Segment. */
|
||||||
|
GDT_ENTRY(0, 0xFFFFFFFF, 0x9A, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
|
||||||
|
|
||||||
|
/* 0x10: Kernel Data Segment. */
|
||||||
|
GDT_ENTRY(0, 0xFFFFFFFF, 0x92, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
|
||||||
|
|
||||||
|
/* 0x18: User Code Segment. */
|
||||||
|
GDT_ENTRY(0, 0xFFFFFFFF, 0xFA, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
|
||||||
|
|
||||||
|
/* 0x20: User Data Segment. */
|
||||||
|
GDT_ENTRY(0, 0xFFFFFFFF, 0xF2, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
|
||||||
|
|
||||||
|
/* 0x28: Task Switch Segment. */
|
||||||
|
GDT_ENTRY(0 /*((uintptr_t) &tss)*/, sizeof(tss) - 1, 0xE9, 0x00),
|
||||||
|
|
||||||
|
/* 0x30: F Segment. */
|
||||||
|
GDT_ENTRY(0, 0xFFFFFFFF, 0xF2, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
|
||||||
|
|
||||||
|
/* 0x38: G Segment. */
|
||||||
|
GDT_ENTRY(0, 0xFFFFFFFF, 0xF2, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
const uint8_t gran = GRAN_4KIB_BLOCKS | GRAN_64_BIT_MODE;
|
/* 0x08: Kernel Code Segment. */
|
||||||
|
GDT_ENTRY(0, 0xFFFFFFFF, 0x9A, GRAN_64_BIT_MODE | GRAN_4KIB_BLOCKS),
|
||||||
|
|
||||||
|
/* 0x10: Kernel Data Segment. */
|
||||||
|
GDT_ENTRY(0, 0xFFFFFFFF, 0x92, GRAN_64_BIT_MODE | GRAN_4KIB_BLOCKS),
|
||||||
|
|
||||||
|
/* 0x18: User Code Segment. */
|
||||||
|
GDT_ENTRY(0, 0xFFFFFFFF, 0xFA, GRAN_64_BIT_MODE | GRAN_4KIB_BLOCKS),
|
||||||
|
|
||||||
|
/* 0x20: User Data Segment. */
|
||||||
|
GDT_ENTRY(0, 0xFFFFFFFF, 0xF2, GRAN_64_BIT_MODE | GRAN_4KIB_BLOCKS),
|
||||||
|
|
||||||
|
/* 0x28: Task Switch Segment. */
|
||||||
|
GDT_ENTRY64((uint64_t) 0 /*((uintptr_t) &tss)*/, sizeof(tss) - 1, 0xE9, 0x00),
|
||||||
#endif
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
SetGate(0, 0, 0, 0, 0); // Null segment
|
uint16_t gdt_size_minus_one = sizeof(gdt) - 1;
|
||||||
SetGate(1, 0, 0xFFFFFFFF, 0x9A, gran); // Code segment
|
|
||||||
SetGate(2, 0, 0xFFFFFFFF, 0x92, gran); // Data segment
|
|
||||||
SetGate(3, 0, 0xFFFFFFFF, 0xFA, gran); // User mode code segment
|
|
||||||
SetGate(4, 0, 0xFFFFFFFF, 0xF2, gran); // User mode data segment
|
|
||||||
|
|
||||||
WriteTSS(5, 0x10, 0x0);
|
} // extern "C"
|
||||||
|
|
||||||
#if defined(__i386__)
|
|
||||||
SetGate(GDT_FS_ENTRY, 0, 0xFFFFFFFF, 0xF2, gran);
|
|
||||||
SetGate(GDT_GS_ENTRY, 0, 0xFFFFFFFF, 0xF2, gran);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Reload the Global Descriptor Table.
|
|
||||||
volatile struct gdt_ptr gdt_ptr;
|
|
||||||
gdt_ptr.limit = (sizeof(struct gdt_entry) * GDT_NUM_ENTRIES) - 1;
|
|
||||||
gdt_ptr.base = (uintptr_t) &gdt_entries;
|
|
||||||
asm volatile ("lgdt (%0)" : : "r"(&gdt_ptr));
|
|
||||||
|
|
||||||
// Switch the current data segment.
|
|
||||||
asm volatile ("mov %0, %%ds\n"
|
|
||||||
"mov %0, %%es\n"
|
|
||||||
"mov %0, %%ss\n" : :
|
|
||||||
"r"(KDS));
|
|
||||||
|
|
||||||
#if defined(__i386__)
|
|
||||||
asm volatile ("mov %0, %%fs" : : "r"(GDT_FS_ENTRY << 3 | URPL));
|
|
||||||
asm volatile ("mov %0, %%gs" : : "r"(GDT_GS_ENTRY << 3 | URPL));
|
|
||||||
#elif defined(__x86_64__)
|
|
||||||
asm volatile ("mov %0, %%fs" : : "r"(UDS | URPL));
|
|
||||||
asm volatile ("mov %0, %%gs" : : "r"(UDS | URPL));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Switch the current code segment.
|
|
||||||
#if defined(__i386__)
|
|
||||||
asm volatile ("push %0\n"
|
|
||||||
"push $1f\n"
|
|
||||||
"retf\n"
|
|
||||||
"1:\n" : :
|
|
||||||
"r"(KCS));
|
|
||||||
#elif defined(__x86_64__)
|
|
||||||
asm volatile ("push %0\n"
|
|
||||||
"push $1f\n"
|
|
||||||
"retfq\n"
|
|
||||||
"1:\n" : :
|
|
||||||
"r"(KCS));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Load the task state register - The index is 0x28, as it is the 5th
|
|
||||||
// selector and each is 8 bytes long, but we set the bottom two bits (making
|
|
||||||
// 0x2B) so that it has an RPL of 3, not zero.
|
|
||||||
asm volatile ("ltr %%ax" : : "a"(0x2B));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialise our task state segment structure.
|
|
||||||
void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0)
|
|
||||||
{
|
|
||||||
// First, let's compute the base and limit of our entry in the GDT.
|
|
||||||
uintptr_t base = (uintptr_t) &tss_entry;
|
|
||||||
uint32_t limit = sizeof(tss_entry) - 1;
|
|
||||||
|
|
||||||
// Now, add our TSS descriptor's address to the GDT.
|
|
||||||
#if defined(__i386__)
|
|
||||||
SetGate(num, base, limit, 0xE9, 0x00);
|
|
||||||
#elif defined(__x86_64__)
|
|
||||||
SetGate64(num, base, limit, 0xE9, 0x00);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Ensure the descriptor is initially zero.
|
|
||||||
memset(&tss_entry, 0, sizeof(tss_entry));
|
|
||||||
|
|
||||||
#if defined(__i386__)
|
|
||||||
tss_entry.ss0 = ss0; // Set the kernel stack segment.
|
|
||||||
tss_entry.esp0 = stack0; // Set the kernel stack pointer.
|
|
||||||
|
|
||||||
// Here we set the cs, ss, ds, es, fs and gs entries in the TSS.
|
|
||||||
// These specify what segments should be loaded when the processor
|
|
||||||
// switches to kernel mode. Therefore they are just our normal
|
|
||||||
// kernel code/data segments - 0x08 and 0x10 respectively, but with
|
|
||||||
// the last two bits set, making 0x0b and 0x13. The setting of these
|
|
||||||
// bits sets the RPL (requested privilege level) to 3, meaning that
|
|
||||||
// this TSS can be used to switch to kernel mode from ring 3.
|
|
||||||
tss_entry.cs = KCS | 0x3;
|
|
||||||
tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = KDS | 0x3;
|
|
||||||
#elif defined(__x86_64__)
|
|
||||||
(void) ss0;
|
|
||||||
tss_entry.stack0 = stack0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t GetKernelStack()
|
uintptr_t GetKernelStack()
|
||||||
{
|
{
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
return tss_entry.esp0;
|
return tss.esp0;
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
return tss_entry.stack0;
|
return tss.stack0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,16 +245,16 @@ void SetKernelStack(uintptr_t stack_pointer)
|
||||||
{
|
{
|
||||||
assert((stack_pointer & 0xF) == 0);
|
assert((stack_pointer & 0xF) == 0);
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
tss_entry.esp0 = (uint32_t) stack_pointer;
|
tss.esp0 = (uint32_t) stack_pointer;
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
tss_entry.stack0 = (uint64_t) stack_pointer;
|
tss.stack0 = (uint64_t) stack_pointer;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
uint32_t GetFSBase()
|
uint32_t GetFSBase()
|
||||||
{
|
{
|
||||||
struct gdt_entry* entry = gdt_entries + GDT_FS_ENTRY;
|
struct gdt_entry* entry = gdt + GDT_FS_ENTRY;
|
||||||
return (uint32_t) entry->base_low << 0 |
|
return (uint32_t) entry->base_low << 0 |
|
||||||
(uint32_t) entry->base_middle << 16 |
|
(uint32_t) entry->base_middle << 16 |
|
||||||
(uint32_t) entry->base_high << 24;
|
(uint32_t) entry->base_high << 24;
|
||||||
|
@ -287,7 +262,7 @@ uint32_t GetFSBase()
|
||||||
|
|
||||||
uint32_t GetGSBase()
|
uint32_t GetGSBase()
|
||||||
{
|
{
|
||||||
struct gdt_entry* entry = gdt_entries + GDT_GS_ENTRY;
|
struct gdt_entry* entry = gdt + GDT_GS_ENTRY;
|
||||||
return (uint32_t) entry->base_low << 0 |
|
return (uint32_t) entry->base_low << 0 |
|
||||||
(uint32_t) entry->base_middle << 16 |
|
(uint32_t) entry->base_middle << 16 |
|
||||||
(uint32_t) entry->base_high << 24;
|
(uint32_t) entry->base_high << 24;
|
||||||
|
@ -295,7 +270,7 @@ uint32_t GetGSBase()
|
||||||
|
|
||||||
void SetFSBase(uint32_t fsbase)
|
void SetFSBase(uint32_t fsbase)
|
||||||
{
|
{
|
||||||
struct gdt_entry* entry = gdt_entries + GDT_FS_ENTRY;
|
struct gdt_entry* entry = gdt + GDT_FS_ENTRY;
|
||||||
entry->base_low = fsbase >> 0 & 0xFFFF;
|
entry->base_low = fsbase >> 0 & 0xFFFF;
|
||||||
entry->base_middle = fsbase >> 16 & 0xFF;
|
entry->base_middle = fsbase >> 16 & 0xFF;
|
||||||
entry->base_high = fsbase >> 24 & 0xFF;
|
entry->base_high = fsbase >> 24 & 0xFF;
|
||||||
|
@ -304,7 +279,7 @@ void SetFSBase(uint32_t fsbase)
|
||||||
|
|
||||||
void SetGSBase(uint32_t gsbase)
|
void SetGSBase(uint32_t gsbase)
|
||||||
{
|
{
|
||||||
struct gdt_entry* entry = gdt_entries + GDT_GS_ENTRY;
|
struct gdt_entry* entry = gdt + GDT_GS_ENTRY;
|
||||||
entry->base_low = gsbase >> 0 & 0xFFFF;
|
entry->base_low = gsbase >> 0 & 0xFFFF;
|
||||||
entry->base_middle = gsbase >> 16 & 0xFF;
|
entry->base_middle = gsbase >> 16 & 0xFF;
|
||||||
entry->base_high = gsbase >> 24 & 0xFF;
|
entry->base_high = gsbase >> 24 & 0xFF;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
x86-family/gdt.h
|
x86-family/gdt.h
|
||||||
Initializes and handles the GDT and TSS.
|
GDT and TSS.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
@ -31,7 +31,6 @@ namespace Sortix {
|
||||||
namespace GDT {
|
namespace GDT {
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0);
|
|
||||||
uintptr_t GetKernelStack();
|
uintptr_t GetKernelStack();
|
||||||
void SetKernelStack(uintptr_t stack_pointer);
|
void SetKernelStack(uintptr_t stack_pointer);
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
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/>.
|
|
||||||
|
|
||||||
x86/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:
|
|
||||||
# Initialize the stack pointer. The magic value is from kernel.cpp.
|
|
||||||
movl $stack, %esp
|
|
||||||
addl $65536, %esp # 64 KiB, see kernel.cpp
|
|
||||||
|
|
||||||
# Reset EFLAGS.
|
|
||||||
# pushl $0
|
|
||||||
# popf
|
|
||||||
|
|
||||||
# Push the pointer to the Multiboot information structure.
|
|
||||||
push %ebx
|
|
||||||
# Push the magic value.
|
|
||||||
push %eax
|
|
||||||
|
|
||||||
## Disable interrupts.
|
|
||||||
cli
|
|
||||||
|
|
||||||
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
|
|
||||||
.size WaitForInterrupt, . - WaitForInterrupt
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014, 2015.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -26,48 +26,96 @@
|
||||||
.section .text
|
.section .text
|
||||||
.text 0x100000
|
.text 0x100000
|
||||||
|
|
||||||
|
# Multiboot header.
|
||||||
|
.align 4
|
||||||
|
.long 0x1BADB002 # Magic.
|
||||||
|
.long 0x00000003 # Flags.
|
||||||
|
.long -(0x1BADB002 + 0x00000003) # Checksum.
|
||||||
|
|
||||||
.global _start
|
.global _start
|
||||||
.global __start
|
.global __start
|
||||||
.type _start, @function
|
.type _start, @function
|
||||||
.type __start, @function
|
.type __start, @function
|
||||||
_start:
|
_start:
|
||||||
__start:
|
__start:
|
||||||
jmp prepare_kernel_execution
|
# Initialize the stack pointer. The magic value is from kernel.cpp.
|
||||||
|
movl $(stack + 65536), %esp # 64 KiB, see kernel.cpp
|
||||||
|
|
||||||
# Align 32 bits boundary.
|
# Finish installing the kernel stack into the Task Switch Segment.
|
||||||
.align 4
|
movl %esp, tss + 4
|
||||||
|
|
||||||
# Multiboot header.
|
# Finish installing the Task Switch Segment into the Global Descriptor Table.
|
||||||
multiboot_header:
|
movl $tss, %ecx
|
||||||
# Magic.
|
movw %cx, gdt + 0x28 + 2
|
||||||
.long 0x1BADB002
|
shrl $16, %ecx
|
||||||
# Flags.
|
movb %cl, gdt + 0x28 + 4
|
||||||
.long 0x00000003
|
shrl $8, %ecx
|
||||||
# Checksum.
|
movb %cl, gdt + 0x28 + 7
|
||||||
.long -(0x1BADB002 + 0x00000003)
|
|
||||||
|
# Load the Global Descriptor Table pointer register.
|
||||||
|
subl $6, %esp
|
||||||
|
movw gdt_size_minus_one, %cx
|
||||||
|
movw %cx, 0(%esp)
|
||||||
|
movl $gdt, %ecx
|
||||||
|
movl %ecx, 2(%esp)
|
||||||
|
lgdt 0(%esp)
|
||||||
|
addl $6, %esp
|
||||||
|
|
||||||
|
# Switch cs to the kernel code segment (0x08).
|
||||||
|
push $0x08
|
||||||
|
push $2f
|
||||||
|
retf
|
||||||
|
|
||||||
|
2:
|
||||||
|
# Switch ds, es, fs, gs, ss to the kernel data segment (0x10).
|
||||||
|
movw $0x10, %cx
|
||||||
|
movw %cx, %ds
|
||||||
|
movw %cx, %es
|
||||||
|
movw %cx, %ss
|
||||||
|
|
||||||
|
# Switch the task switch segment register to the task switch segment (0x28).
|
||||||
|
movw $(0x28 /* TSS */ | 0x3 /* RPL */), %cx
|
||||||
|
ltr %cx
|
||||||
|
|
||||||
|
# Switch to the thread local fs and gs segments.
|
||||||
|
movw $(0x30 /* FS */ | 0x3 /* RPL */), %cx
|
||||||
|
movw %cx, %fs
|
||||||
|
movw $(0x38 /* GS */ | 0x3 /* RPL */), %cx
|
||||||
|
movw %cx, %gs
|
||||||
|
|
||||||
prepare_kernel_execution:
|
|
||||||
# Enable the floating point unit.
|
# Enable the floating point unit.
|
||||||
mov %eax, 0x100000
|
mov %cr0, %ecx
|
||||||
mov %cr0, %eax
|
and $0xFFFD, %cx
|
||||||
and $0xFFFD, %ax
|
or $0x10, %cx
|
||||||
or $0x10, %ax
|
mov %ecx, %cr0
|
||||||
mov %eax, %cr0
|
|
||||||
fninit
|
fninit
|
||||||
|
|
||||||
# Enable Streaming SIMD Extensions.
|
# Enable Streaming SIMD Extensions.
|
||||||
mov %cr0, %eax
|
mov %cr0, %ecx
|
||||||
and $0xFFFB, %ax
|
and $0xFFFB, %cx
|
||||||
or $0x2, %ax
|
or $0x2, %cx
|
||||||
mov %eax, %cr0
|
mov %ecx, %cr0
|
||||||
mov %cr4, %eax
|
mov %cr4, %ecx
|
||||||
or $0x600, %eax
|
or $0x600, %ecx
|
||||||
mov %eax, %cr4
|
mov %ecx, %cr4
|
||||||
mov 0x100000, %eax
|
|
||||||
|
|
||||||
# Store a copy of the initialial floating point registers.
|
# Store a copy of the initialial floating point registers.
|
||||||
fxsave fpu_initialized_regs
|
fxsave fpu_initialized_regs
|
||||||
|
|
||||||
jmp beginkernel
|
# Enter the high-level kernel proper.
|
||||||
|
subl $8, %esp # 16-byte align at call time.
|
||||||
|
push %ebx # Multiboot information structure pointer.
|
||||||
|
push %eax # Multiboot magic value.
|
||||||
|
call KernelInit
|
||||||
|
|
||||||
|
jmp HaltKernel
|
||||||
.size _start, . - _start
|
.size _start, . - _start
|
||||||
.size __start, . - __start
|
.size __start, . - __start
|
||||||
|
|
||||||
|
.global HaltKernel
|
||||||
|
.type HaltKernel, @function
|
||||||
|
HaltKernel:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
jmp HaltKernel
|
||||||
|
.size HaltKernel, . - HaltKernel
|
||||||
|
|
Loading…
Reference in New Issue