Working LAPIC timer
This commit is contained in:
@@ -1,147 +0,0 @@
|
||||
# Generated by YCM Generator at 2019-09-16 12:39:32.163870
|
||||
|
||||
# This file is NOT licensed under the GPLv3, which is the license for the rest
|
||||
# of YouCompleteMe.
|
||||
#
|
||||
# Here's the license text for this file:
|
||||
#
|
||||
# This is free and unencumbered software released into the public domain.
|
||||
#
|
||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
# distribute this software, either in source code form or as a compiled
|
||||
# binary, for any purpose, commercial or non-commercial, and by any
|
||||
# means.
|
||||
#
|
||||
# In jurisdictions that recognize copyright laws, the author or authors
|
||||
# of this software dedicate any and all copyright interest in the
|
||||
# software to the public domain. We make this dedication for the benefit
|
||||
# of the public at large and to the detriment of our heirs and
|
||||
# successors. We intend this dedication to be an overt act of
|
||||
# relinquishment in perpetuity of all present and future rights to this
|
||||
# software under copyright law.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
import os
|
||||
import ycm_core
|
||||
|
||||
flags = [
|
||||
'-x',
|
||||
'c',
|
||||
'-DARCH_AMD64',
|
||||
'-I.',
|
||||
'-Iinclude',
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
'-Wextra',
|
||||
'-Wno-unused-parameter',
|
||||
'-Wpedantic',
|
||||
'-m64',
|
||||
'-nostdlib',
|
||||
]
|
||||
|
||||
|
||||
# Set this to the absolute path to the folder (NOT the file!) containing the
|
||||
# compile_commands.json file to use that instead of 'flags'. See here for
|
||||
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
|
||||
#
|
||||
# You can get CMake to generate this file for you by adding:
|
||||
# set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
|
||||
# to your CMakeLists.txt file.
|
||||
#
|
||||
# Most projects will NOT need to set this to anything; you can just change the
|
||||
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
|
||||
compilation_database_folder = ''
|
||||
|
||||
if os.path.exists( compilation_database_folder ):
|
||||
database = ycm_core.CompilationDatabase( compilation_database_folder )
|
||||
else:
|
||||
database = None
|
||||
|
||||
SOURCE_EXTENSIONS = [ '.C', '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
|
||||
|
||||
def DirectoryOfThisScript():
|
||||
return os.path.dirname( os.path.abspath( __file__ ) )
|
||||
|
||||
|
||||
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
|
||||
if not working_directory:
|
||||
return list( flags )
|
||||
new_flags = []
|
||||
make_next_absolute = False
|
||||
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
|
||||
for flag in flags:
|
||||
new_flag = flag
|
||||
|
||||
if make_next_absolute:
|
||||
make_next_absolute = False
|
||||
if not flag.startswith( '/' ):
|
||||
new_flag = os.path.join( working_directory, flag )
|
||||
|
||||
for path_flag in path_flags:
|
||||
if flag == path_flag:
|
||||
make_next_absolute = True
|
||||
break
|
||||
|
||||
if flag.startswith( path_flag ):
|
||||
path = flag[ len( path_flag ): ]
|
||||
new_flag = path_flag + os.path.join( working_directory, path )
|
||||
break
|
||||
|
||||
if new_flag:
|
||||
new_flags.append( new_flag )
|
||||
return new_flags
|
||||
|
||||
|
||||
def IsHeaderFile( filename ):
|
||||
extension = os.path.splitext( filename )[ 1 ]
|
||||
return extension in [ '.H', '.h', '.hxx', '.hpp', '.hh' ]
|
||||
|
||||
|
||||
def GetCompilationInfoForFile( filename ):
|
||||
# The compilation_commands.json file generated by CMake does not have entries
|
||||
# for header files. So we do our best by asking the db for flags for a
|
||||
# corresponding source file, if any. If one exists, the flags for that file
|
||||
# should be good enough.
|
||||
if IsHeaderFile( filename ):
|
||||
basename = os.path.splitext( filename )[ 0 ]
|
||||
for extension in SOURCE_EXTENSIONS:
|
||||
replacement_file = basename + extension
|
||||
if os.path.exists( replacement_file ):
|
||||
compilation_info = database.GetCompilationInfoForFile(
|
||||
replacement_file )
|
||||
if compilation_info.compiler_flags_:
|
||||
return compilation_info
|
||||
return None
|
||||
return database.GetCompilationInfoForFile( filename )
|
||||
|
||||
|
||||
def FlagsForFile( filename, **kwargs ):
|
||||
if database:
|
||||
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
|
||||
# python list, but a "list-like" StringVec object
|
||||
compilation_info = GetCompilationInfoForFile( filename )
|
||||
if not compilation_info:
|
||||
return None
|
||||
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute(
|
||||
compilation_info.compiler_flags_,
|
||||
compilation_info.compiler_working_dir_ )
|
||||
|
||||
else:
|
||||
relative_to = DirectoryOfThisScript()
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
|
||||
|
||||
return {
|
||||
'flags': final_flags,
|
||||
'do_cache': True
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
Local APIC
|
||||
==========
|
||||
|
||||
LAPIC Base MSR
|
||||
--------------
|
||||
|
||||
`IA32_LAPIC_BASE = 0x1B` model-specific register stores information about Local APIC
|
||||
status and its base address.
|
||||
|
||||
Notable LAPIC registers
|
||||
-----------------------
|
||||
|
||||
| Base offset | Name | Description |
|
||||
|------------:|---------------------|-------------------------------------------|
|
||||
| 0x20 | IA32_LAPIC_REG_ID | Local APIC ID register |
|
||||
| 0x80 | IA32_LAPIC_REG_TPR | Task Priority Register |
|
||||
| 0xB0 | IA32_LAPIC_REG_EOI | End of interrupt register |
|
||||
| 0xF0 | IA32_LAPIC_REG_SVR | Spurious Interrupt Vector Register |
|
||||
| 0x300 | IA32_LAPIC_REG_ICR0 | Interrupt Control Register, 31 .. 0 |
|
||||
| 0x310 | IA32_LAPIC_REG_ICR1 | Interrupt Control Register, 63 .. 32 |
|
||||
|-------------|---------------------|-------------------------------------------|
|
||||
|
||||
Local APIC configuration sequence
|
||||
---------------------------------
|
||||
|
||||
1. Mask all the interrupts in i8259
|
||||
2. Remap all of them properly so spurious interrupts don't generate exceptions
|
||||
3. Setup `LINTx` registers for LAPIC-originated (internal) interrupts
|
||||
4. Set the IRQ number spurious interrupts should be mapped to and soft-enable the
|
||||
LAPIC by writing `IA32_LAPIC_REG_SVR`
|
||||
5. Set the `IA32_LAPIC_REG_TPR` so that lower-priority interrupts don't get postponed
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
|
||||
struct acpi_rsdp {
|
||||
char signature[8];
|
||||
uint8_t checksum;
|
||||
char oemid[6];
|
||||
uint8_t rev;
|
||||
uint32_t rsdt_address;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct acpi_rsdp_ext {
|
||||
struct acpi_rsdp rsdp;
|
||||
|
||||
uint32_t length;
|
||||
uint64_t xsdt_address;
|
||||
uint8_t ext_checksum;
|
||||
uint8_t reserved[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct acpi_header {
|
||||
char signature[4];
|
||||
uint32_t length;
|
||||
uint8_t rev;
|
||||
uint8_t checksum;
|
||||
char oemid[6];
|
||||
char oem_table_id[8];
|
||||
uint32_t oem_rev;
|
||||
char asl_id[4];
|
||||
uint32_t asl_rev;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct acpi_rsdt {
|
||||
struct acpi_header hdr;
|
||||
|
||||
uint32_t entry[];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct acpi_madt {
|
||||
struct acpi_header hdr;
|
||||
|
||||
uint32_t local_apic_addr;
|
||||
uint32_t flags;
|
||||
char entry[];
|
||||
} __attribute__((packed));
|
||||
|
||||
void amd64_acpi_init(void);
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include "sys/amd64/hw/acpi.h"
|
||||
|
||||
void amd64_apic_init(struct acpi_madt *madt);
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t limit_lo;
|
||||
uint16_t base_lo;
|
||||
uint8_t base_mi;
|
||||
uint8_t access;
|
||||
uint8_t flags;
|
||||
uint8_t base_hi;
|
||||
} amd64_gdt_entry_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t __res0;
|
||||
uint64_t rsp0;
|
||||
uint64_t rsp1;
|
||||
uint64_t rsp2;
|
||||
uint64_t __res1;
|
||||
uint64_t ist1;
|
||||
uint64_t ist2;
|
||||
uint64_t ist3;
|
||||
uint64_t ist4;
|
||||
uint64_t ist5;
|
||||
uint64_t ist6;
|
||||
uint64_t ist7;
|
||||
uint64_t __res2;
|
||||
uint16_t __res3;
|
||||
uint16_t iopb_base;
|
||||
}__attribute__((packed)) amd64_tss_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t size;
|
||||
uintptr_t offset;
|
||||
} __attribute__((packed)) amd64_gdt_ptr_t;
|
||||
|
||||
void amd64_gdt_init(void);
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void amd64_idt_init(void);
|
||||
@@ -0,0 +1,34 @@
|
||||
/* vim: set ft=cpp.doxygen : */
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "sys/amd64/loader/data.h"
|
||||
|
||||
/// The place where the kernel pages are virtually mapped to
|
||||
#define KERNEL_VIRT_BASE 0xFFFFFF0000000000
|
||||
|
||||
/// amd64 standard states that addresses' upper bits are copies of the 47th bit, so these need to be
|
||||
/// stripped down to only 48 bits
|
||||
#define AMD64_MM_STRIPSX(a) ((uintptr_t) (a) & 0xFFFFFFFFFFFF)
|
||||
#define AMD64_MM_ADDRSX(a) (((uintptr_t) (a) & (1ULL << 47)) ? \
|
||||
(0xFFFFFF0000000000 | ((uintptr_t) (a))) : \
|
||||
((uintptr_t) (a)))
|
||||
|
||||
#define MM_VIRTUALIZE(a) ((uintptr_t) (a) + 0xFFFFFF0000000000)
|
||||
#define MM_PHYS(a) ((uintptr_t) (a) - 0xFFFFFF0000000000)
|
||||
|
||||
/// Page map level 4
|
||||
typedef uint64_t *mm_pml4_t;
|
||||
/// Page directory pointer table
|
||||
typedef uint64_t *mm_pdpt_t;
|
||||
/// Page directory
|
||||
typedef uint64_t *mm_pagedir_t;
|
||||
/// Page table
|
||||
typedef uint64_t *mm_pagetab_t;
|
||||
|
||||
/// Virtual memory space
|
||||
typedef mm_pml4_t mm_space_t;
|
||||
|
||||
/// Kernel memory space
|
||||
extern mm_space_t mm_kernel;
|
||||
|
||||
void amd64_mm_init(struct amd64_loader_data *data);
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
void *memcpy(void *restrict dst, const void *restrict src, size_t cnt);
|
||||
void *memmove(void *dst, const void *src, size_t cnt);
|
||||
void *memset(void *dst, int v, size_t count);
|
||||
|
||||
size_t strlen(const char *s);
|
||||
int strncmp(const char *a, const char *b, size_t lim);
|
||||
|
||||
+15
-3
@@ -4,7 +4,15 @@ all:
|
||||
### Kernel build
|
||||
DEFINES+=-DARCH_AMD64
|
||||
OBJS+=$(O)/sys/amd64/hw/rs232.o \
|
||||
$(O)/sys/amd64/string.o
|
||||
$(O)/sys/amd64/kernel.o \
|
||||
$(O)/sys/amd64/hw/gdt.o \
|
||||
$(O)/sys/amd64/hw/gdt_s.o \
|
||||
$(O)/sys/amd64/hw/acpi.o \
|
||||
$(O)/sys/amd64/mm/mm.o \
|
||||
$(O)/sys/amd64/hw/apic.o \
|
||||
$(O)/sys/amd64/hw/idt.o \
|
||||
$(O)/sys/amd64/hw/exc_s.o \
|
||||
$(O)/sys/amd64/hw/irq0.o
|
||||
kernel_OBJS=$(O)/sys/amd64/entry.o \
|
||||
$(OBJS)
|
||||
kernel_LINKER=sys/amd64/link.ld
|
||||
@@ -33,7 +41,8 @@ kernel_CFLAGS=-ffreestanding \
|
||||
-mno-sse2 \
|
||||
-z max-page-size=0x1000
|
||||
DIRS+=$(O)/sys/amd64/image/boot/grub \
|
||||
$(O)/sys/amd64/hw
|
||||
$(O)/sys/amd64/hw \
|
||||
$(O)/sys/amd64/mm
|
||||
|
||||
# add .inc includes for asm
|
||||
HEADERS+=$(shell find include -name "*.inc")
|
||||
@@ -94,7 +103,10 @@ $(O)/sys/amd64/initrd.img: amd64_mkstage
|
||||
### Debugging and emulation
|
||||
QEMU_BIN?=qemu-system-x86_64
|
||||
QEMU_OPTS?=-serial mon:stdio \
|
||||
-m 512
|
||||
-m 512 \
|
||||
--accel tcg,thread=multi \
|
||||
-cpu core2duo \
|
||||
-smp 2
|
||||
|
||||
$(O)/sys/amd64/image.iso: $(O)/sys/amd64/kernel.elf \
|
||||
$(O)/sys/amd64/loader.elf \
|
||||
|
||||
+2
-8
@@ -4,21 +4,15 @@
|
||||
.global _start
|
||||
_start:
|
||||
cli
|
||||
movabsq $kernel_stack_top, %rsp
|
||||
leaq kernel_stack_top(%rip), %rsp
|
||||
|
||||
leaq _msg_entry(%rip), %rsi
|
||||
xorq %rdi, %rdi
|
||||
call debugf
|
||||
call kernel_main
|
||||
|
||||
1:
|
||||
cli
|
||||
hlt
|
||||
jmp 1b
|
||||
|
||||
.section .rodata
|
||||
_msg_entry:
|
||||
.string "Entered kernel\n"
|
||||
|
||||
.section .bss
|
||||
kernel_stack_bottom:
|
||||
.skip 65536
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "sys/amd64/hw/acpi.h"
|
||||
#include "sys/amd64/hw/apic.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/debug.h"
|
||||
|
||||
static uint8_t checksum(const void *ptr, size_t size) {
|
||||
uint8_t v = 0;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
v += ((const uint8_t *) ptr)[i];
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void amd64_acpi_init(void) {
|
||||
struct acpi_rsdp_ext *rsdp = NULL;
|
||||
struct acpi_madt *madt = NULL;
|
||||
struct acpi_rsdt *rsdt;
|
||||
|
||||
for (size_t i = 0xFFFFFF0000000000 + 0x000E0000; i < 0xFFFFFF0000000000 + 0x000FFFFF - 8; ++i) {
|
||||
if (!strncmp((const char *) i, "RSD PTR ", 8)) {
|
||||
rsdp = (struct acpi_rsdp_ext *) i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rsdp) {
|
||||
kdebug("Failed to find rsdp\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
kdebug("Found RSDP: %p\n", rsdp);
|
||||
|
||||
if (checksum(rsdp, sizeof(struct acpi_rsdp)) != 0) {
|
||||
kdebug("RSDP is invalid\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
kdebug("RSDP revision %d\n", rsdp->rsdp.rev);
|
||||
rsdt = (struct acpi_rsdt *) (0xFFFFFF0000000000 + rsdp->rsdp.rsdt_address);
|
||||
kdebug("RSDT: %p\n", rsdt);
|
||||
|
||||
if (checksum(rsdt, rsdt->hdr.length) != 0) {
|
||||
kdebug("RSDT is invalid\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (rsdt->hdr.length - sizeof(struct acpi_header)) / sizeof(uint32_t); ++i) {
|
||||
uintptr_t entry_addr = 0xFFFFFF0000000000 + rsdt->entry[i];
|
||||
struct acpi_header *hdr = (struct acpi_header *) entry_addr;
|
||||
|
||||
if (!strncmp((const char *) hdr, "APIC", 4)) {
|
||||
kdebug("Found MADT = %p\n", entry_addr);
|
||||
if (checksum(hdr, hdr->length) != 0) {
|
||||
kdebug("Entry is invalid\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
madt = (struct acpi_madt *) hdr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!madt) {
|
||||
kdebug("No MADT\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
amd64_apic_init(madt);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "sys/amd64/hw/apic.h"
|
||||
#include "sys/debug.h"
|
||||
|
||||
#define IA32_APIC_BASE_MSR 0x1B
|
||||
#define IA32_APIC_BASE_MSR_BSP 0x100
|
||||
#define IA32_APIC_BASE_MSR_ENABLE 0x800
|
||||
|
||||
#define IA32_LAPIC_REG_ID 0x20
|
||||
#define IA32_LAPIC_REG_TPR 0x80
|
||||
#define IA32_LAPIC_REG_EOI 0xB0
|
||||
#define IA32_LAPIC_REG_SVR 0xF0
|
||||
|
||||
#define IA32_LAPIC_REG_LVTT 0x320
|
||||
|
||||
#define IA32_LAPIC_REG_TMRINITCNT 0x380
|
||||
#define IA32_LAPIC_REG_TMRCURRCNT 0x390
|
||||
#define IA32_LAPIC_REG_TMRDIV 0x3E0
|
||||
|
||||
#define IA32_LAPIC_REG_CMD0 0x300
|
||||
#define IA32_LAPIC_REG_CMD1 0x310
|
||||
|
||||
/////
|
||||
|
||||
static uint64_t rdmsr(uint32_t addr) {
|
||||
uint64_t v;
|
||||
asm volatile ("rdmsr":"=A"(v):"c"(addr));
|
||||
return v;
|
||||
}
|
||||
|
||||
// static void wrmsr(uint32_t addr, uint64_t v) {
|
||||
// uint32_t low = v & 0xFFFFFFFF;
|
||||
// uint32_t high = v >> 32;
|
||||
// asm volatile ("wrmsr"::"c"(addr),"d"(high),"a"(low));
|
||||
// }
|
||||
|
||||
/////
|
||||
|
||||
struct acpi_apic_field_type {
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct acpi_lapic_entry {
|
||||
struct acpi_apic_field_type hdr;
|
||||
|
||||
uint8_t processor_id;
|
||||
uint8_t apic_id;
|
||||
uint32_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct acpi_ioapic_entry {
|
||||
struct acpi_apic_field_type hdr;
|
||||
|
||||
uint8_t ioapic_id;
|
||||
uint8_t res;
|
||||
uint32_t ioapic_addr;
|
||||
uint32_t gsi_base;
|
||||
} __attribute__((packed));
|
||||
|
||||
/////
|
||||
|
||||
// LAPIC ID of the BSP CPU
|
||||
static uint32_t bsp_lapic_id;
|
||||
// Local APIC base for every processor
|
||||
// (mapped to per-CPU LAPICs, while the address is the same)
|
||||
static uintptr_t lapic_base;
|
||||
|
||||
/////
|
||||
|
||||
static uintptr_t amd64_apic_base(void) {
|
||||
uint64_t addr = rdmsr(IA32_APIC_BASE_MSR);
|
||||
return addr & 0xFFFFFF000;
|
||||
}
|
||||
|
||||
static int amd64_apic_status(void) {
|
||||
uintptr_t v = rdmsr(IA32_APIC_BASE_MSR);
|
||||
return v & IA32_APIC_BASE_MSR_ENABLE;
|
||||
}
|
||||
|
||||
static void amd64_pic8259_disable(void) {
|
||||
// Mask everything
|
||||
asm volatile (
|
||||
"mov $0xFF, %al \n"
|
||||
"outb %al, $0xA1 \n"
|
||||
"outb %al, $0x21"
|
||||
);
|
||||
}
|
||||
|
||||
void amd64_apic_init(struct acpi_madt *madt) {
|
||||
// Get LAPIC base
|
||||
lapic_base = amd64_apic_base() + 0xFFFFFF0000000000;
|
||||
kdebug("APIC base is %p\n", lapic_base);
|
||||
kdebug("APIC is %s\n", (amd64_apic_status() ? "enabled" : "disabled"));
|
||||
|
||||
kdebug("Disabling i8259 PIC\n");
|
||||
amd64_pic8259_disable();
|
||||
|
||||
// Determine the BSP LAPIC ID
|
||||
bsp_lapic_id = *(uint32_t *) (lapic_base + IA32_LAPIC_REG_ID);
|
||||
kdebug("BSP Local APIC ID: %d\n", bsp_lapic_id);
|
||||
|
||||
// Enable LAPIC.SVR.SoftwareEnable bit
|
||||
// And set spurious interrupt mapping to 0xFF
|
||||
*(uint32_t *) (lapic_base + IA32_LAPIC_REG_SVR) |= (1 << 8) | (0xFF);
|
||||
|
||||
// Enable LAPIC timer
|
||||
*(uint32_t *) (lapic_base + IA32_LAPIC_REG_LVTT) = 32 | 0x20000;
|
||||
*(uint32_t *) (lapic_base + IA32_LAPIC_REG_TMRDIV) = 0x3;
|
||||
*(uint32_t *) (lapic_base + IA32_LAPIC_REG_TMRINITCNT) = 100000;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
.macro amd64_isr_nerr, n
|
||||
amd64_exc_isr_\n:
|
||||
cli
|
||||
pushq $0
|
||||
pushq $\n
|
||||
jmp amd64_exc_generic
|
||||
.endm
|
||||
|
||||
.macro amd64_isr_yerr, n
|
||||
amd64_exc_isr_\n:
|
||||
cli
|
||||
pushq $\n
|
||||
jmp amd64_exc_generic
|
||||
.endm
|
||||
|
||||
.section .text
|
||||
amd64_exc_generic:
|
||||
// TODO: exception handling
|
||||
leaq _amd64_exc_str(%rip), %rsi
|
||||
xorq %rdi, %rdi
|
||||
call debugs
|
||||
1:
|
||||
cli
|
||||
hlt
|
||||
jmp 1b
|
||||
_amd64_exc_str:
|
||||
.string "Error: unhandled exception\n"
|
||||
|
||||
amd64_isr_nerr 0
|
||||
amd64_isr_nerr 1
|
||||
amd64_isr_nerr 2
|
||||
amd64_isr_nerr 3
|
||||
amd64_isr_nerr 4
|
||||
amd64_isr_nerr 5
|
||||
amd64_isr_nerr 6
|
||||
amd64_isr_nerr 7
|
||||
amd64_isr_yerr 8
|
||||
amd64_isr_nerr 9
|
||||
amd64_isr_yerr 10
|
||||
amd64_isr_yerr 11
|
||||
amd64_isr_yerr 12
|
||||
amd64_isr_yerr 13
|
||||
amd64_isr_yerr 14
|
||||
amd64_isr_nerr 15
|
||||
amd64_isr_nerr 16
|
||||
amd64_isr_yerr 17
|
||||
amd64_isr_nerr 18
|
||||
amd64_isr_nerr 19
|
||||
amd64_isr_nerr 20
|
||||
amd64_isr_nerr 21
|
||||
amd64_isr_nerr 22
|
||||
amd64_isr_nerr 23
|
||||
amd64_isr_nerr 24
|
||||
amd64_isr_nerr 25
|
||||
amd64_isr_nerr 26
|
||||
amd64_isr_nerr 27
|
||||
amd64_isr_nerr 28
|
||||
amd64_isr_nerr 29
|
||||
amd64_isr_yerr 30
|
||||
amd64_isr_nerr 31
|
||||
|
||||
.section .rodata
|
||||
.global amd64_exception_vectors
|
||||
amd64_exception_vectors:
|
||||
.quad amd64_exc_isr_0
|
||||
.quad amd64_exc_isr_1
|
||||
.quad amd64_exc_isr_2
|
||||
.quad amd64_exc_isr_3
|
||||
.quad amd64_exc_isr_4
|
||||
.quad amd64_exc_isr_5
|
||||
.quad amd64_exc_isr_6
|
||||
.quad amd64_exc_isr_7
|
||||
.quad amd64_exc_isr_8
|
||||
.quad amd64_exc_isr_9
|
||||
.quad amd64_exc_isr_10
|
||||
.quad amd64_exc_isr_11
|
||||
.quad amd64_exc_isr_12
|
||||
.quad amd64_exc_isr_13
|
||||
.quad amd64_exc_isr_14
|
||||
.quad amd64_exc_isr_15
|
||||
.quad amd64_exc_isr_16
|
||||
.quad amd64_exc_isr_17
|
||||
.quad amd64_exc_isr_18
|
||||
.quad amd64_exc_isr_19
|
||||
.quad amd64_exc_isr_20
|
||||
.quad amd64_exc_isr_21
|
||||
.quad amd64_exc_isr_22
|
||||
.quad amd64_exc_isr_23
|
||||
.quad amd64_exc_isr_24
|
||||
.quad amd64_exc_isr_25
|
||||
.quad amd64_exc_isr_26
|
||||
.quad amd64_exc_isr_27
|
||||
.quad amd64_exc_isr_28
|
||||
.quad amd64_exc_isr_29
|
||||
.quad amd64_exc_isr_30
|
||||
.quad amd64_exc_isr_31
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "sys/amd64/hw/gdt.h"
|
||||
#define GDT_SIZE 3
|
||||
|
||||
extern void amd64_gdt_load(void *p);
|
||||
|
||||
static amd64_gdt_entry_t gdt[GDT_SIZE] = { 0 };
|
||||
static amd64_gdt_ptr_t gdtr = {
|
||||
sizeof(gdt) - 1,
|
||||
(uintptr_t) gdt
|
||||
};
|
||||
|
||||
#define GDT_ACC_AC (1 << 0)
|
||||
#define GDT_ACC_RW (1 << 1)
|
||||
#define GDT_ACC_DC (1 << 2)
|
||||
#define GDT_ACC_EX (1 << 3)
|
||||
#define GDT_ACC_S (1 << 4)
|
||||
#define GDT_ACC_R0 (0 << 5)
|
||||
#define GDT_ACC_R1 (1 << 5)
|
||||
#define GDT_ACC_R2 (2 << 5)
|
||||
#define GDT_ACC_R3 (3 << 5)
|
||||
#define GDT_ACC_PR (1 << 7)
|
||||
|
||||
#define GDT_FLG_LONG (1 << 5)
|
||||
#define GDT_FLG_SZ (1 << 6)
|
||||
#define GDT_FLG_GR (1 << 7)
|
||||
|
||||
static void amd64_gdt_set(int idx, uint32_t base, uint32_t limit, uint8_t flags, uint8_t access) {
|
||||
gdt[idx].base_lo = base & 0xFFFF;
|
||||
gdt[idx].base_mi = (base >> 16) & 0xFF;
|
||||
gdt[idx].base_hi = (base >> 24) & 0xFF;
|
||||
gdt[idx].access = access;
|
||||
gdt[idx].flags = (flags & 0xF0) | ((limit >> 16) & 0xF);
|
||||
gdt[idx].limit_lo = limit & 0xFFFF;
|
||||
}
|
||||
|
||||
void amd64_gdt_init(void) {
|
||||
amd64_gdt_set(0, 0, 0, 0, 0);
|
||||
amd64_gdt_set(1, 0, 0,
|
||||
GDT_FLG_LONG,
|
||||
GDT_ACC_PR | GDT_ACC_S | GDT_ACC_EX);
|
||||
amd64_gdt_set(2, 0, 0,
|
||||
0,
|
||||
GDT_ACC_PR | GDT_ACC_S | GDT_ACC_RW);
|
||||
|
||||
amd64_gdt_load(&gdtr);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
.section .text
|
||||
.global amd64_gdt_load
|
||||
amd64_gdt_load:
|
||||
lgdt (%rdi)
|
||||
// Not sure if CS reload is needed
|
||||
retq
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "sys/amd64/hw/idt.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/types.h"
|
||||
|
||||
#define IDT_FLG_TASK32 0x5
|
||||
#define IDT_FLG_INT16 0x6
|
||||
#define IDT_FLG_TRAP16 0x7
|
||||
#define IDT_FLG_INT32 0xE
|
||||
#define IDT_FLG_TRAP32 0xF
|
||||
#define IDT_FLG_SS (1 << 4)
|
||||
#define IDT_FLG_R0 (0 << 5)
|
||||
#define IDT_FLG_R1 (1 << 5)
|
||||
#define IDT_FLG_R2 (2 << 5)
|
||||
#define IDT_FLG_R3 (3 << 5)
|
||||
#define IDT_FLG_P (1 << 7)
|
||||
|
||||
extern uintptr_t amd64_exception_vectors[32];
|
||||
extern void amd64_irq0(void);
|
||||
|
||||
static struct amd64_idt_entry {
|
||||
uint16_t base_lo;
|
||||
uint16_t selector;
|
||||
uint8_t zero;
|
||||
uint8_t flags;
|
||||
uint16_t base_hi;
|
||||
uint32_t base_ex;
|
||||
uint32_t zero1;
|
||||
} __attribute__((packed)) idt[256] __attribute__((aligned(0x10)));
|
||||
|
||||
static const struct {
|
||||
uint16_t size;
|
||||
uintptr_t offset;
|
||||
} __attribute__((packed)) idtr __attribute__((aligned(0x10))) = {
|
||||
.size = sizeof(idt) - 1,
|
||||
.offset = (uintptr_t) idt
|
||||
};
|
||||
|
||||
static void amd64_idt_set(int idx, uintptr_t base, uint16_t selector, uint8_t flags) {
|
||||
idt[idx].base_lo = base & 0xFFFF;
|
||||
idt[idx].base_hi = (base >> 16) & 0xFFFF;
|
||||
idt[idx].base_ex = (base >> 32) & 0xFFFFFFFF;
|
||||
idt[idx].selector = selector;
|
||||
idt[idx].flags = flags;
|
||||
idt[idx].zero = 0;
|
||||
}
|
||||
|
||||
void amd64_idt_init(void) {
|
||||
memset(idt, 0, sizeof(idt));
|
||||
// Exception vectors
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
amd64_idt_set(i, amd64_exception_vectors[i], 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
}
|
||||
amd64_idt_set(32, (uintptr_t) amd64_irq0, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
|
||||
|
||||
asm volatile ("lidt idtr(%rip)");
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
.section .text
|
||||
.global amd64_irq0
|
||||
amd64_irq0:
|
||||
pushq %rax
|
||||
movq $0xFFFFFF00FEE000B0, %rax
|
||||
movl $0, (%rax)
|
||||
popq %rax
|
||||
|
||||
pushq %rax
|
||||
pushq %rcx
|
||||
pushq %rdx
|
||||
pushq %rbx
|
||||
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
|
||||
xorq %rdi, %rdi
|
||||
leaq _tmr_msg(%rip), %rsi
|
||||
call debugs
|
||||
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
|
||||
popq %rbx
|
||||
popq %rdx
|
||||
popq %rcx
|
||||
popq %rax
|
||||
|
||||
iretq
|
||||
|
||||
_tmr_msg:
|
||||
.string "T!\n"
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "sys/debug.h"
|
||||
#include "sys/amd64/hw/gdt.h"
|
||||
#include "sys/amd64/hw/idt.h"
|
||||
#include "sys/amd64/mm/mm.h"
|
||||
#include "sys/amd64/hw/acpi.h"
|
||||
|
||||
void kernel_main(struct amd64_loader_data *data) {
|
||||
amd64_gdt_init();
|
||||
amd64_idt_init();
|
||||
amd64_mm_init(NULL);
|
||||
amd64_acpi_init();
|
||||
|
||||
while (1) {
|
||||
asm ("sti; hlt");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// #include "sys/vmalloc.h"
|
||||
// #include "sys/assert.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/amd64/mm/mm.h"
|
||||
// #include "sys/panic.h"
|
||||
// #include "sys/heap.h"
|
||||
// #include "sys/mem.h"
|
||||
// #include "sys/mm.h"
|
||||
|
||||
mm_space_t mm_kernel;
|
||||
|
||||
extern int _kernel_end;
|
||||
|
||||
void amd64_mm_init(struct amd64_loader_data *data) {
|
||||
kdebug("Memory manager init\n");
|
||||
|
||||
// Physical memory at this point:
|
||||
// 0x000000 - 0x400000 - Used by kernel and info passed from the loader
|
||||
// Virtual memory:
|
||||
// Lower 1GiB mapped to itself for loader access
|
||||
// 0xFFFFFF0000000000 (1GiB) is mapped to 0 for kernel access
|
||||
|
||||
// XXX: assuming nothing important is there
|
||||
uint64_t *pml4 = (uint64_t *) (0x200000 - 0x1000);
|
||||
uint64_t *pdpt = (uint64_t *) (0x200000 - 0x2000);
|
||||
|
||||
memset((void *) (0x200000 - 2 * 0x1000), 0, 0x1000 * 2);
|
||||
|
||||
// 0xFFFFFF0000000000 -> 0 (512GiB) mapping
|
||||
pml4[AMD64_MM_STRIPSX(KERNEL_VIRT_BASE) >> 39] = ((uintptr_t) pdpt) | 1 | 2 | 4;
|
||||
for (uint64_t i = 0; i < 4; ++i) {
|
||||
kdebug("Mapping %p -> %p\n", KERNEL_VIRT_BASE | (i << 30), i << 30);
|
||||
pdpt[((AMD64_MM_STRIPSX(KERNEL_VIRT_BASE) >> 30) + i) & 0x1FF] = (i << 30) | 1 | 2 | 4 | (1 << 7);
|
||||
}
|
||||
|
||||
// Load the new table
|
||||
asm volatile ("mov %0, %%cr3"::"a"(pml4):"memory");
|
||||
|
||||
// Create a pool located right after kernel image
|
||||
// amd64_mm_pool_init((uintptr_t) &_kernel_end, MM_POOL_SIZE);
|
||||
|
||||
// mm_kernel = (mm_space_t) (MM_VIRTUALIZE(pml4));
|
||||
|
||||
// // Allocate some pages for kernel heap (base size: 16MiB)
|
||||
// uintptr_t heap_base_phys = amd64_phys_alloc_contiguous(KERNEL_HEAP >> 12);
|
||||
// assert(heap_base_phys != MM_NADDR, "Could not allocate %S of memory for kernel heap\n", KERNEL_HEAP);
|
||||
// kdebug("Setting up kernel heap of %S @ %p\n", KERNEL_HEAP, heap_base_phys);
|
||||
// amd64_heap_init(heap_global, heap_base_phys, KERNEL_HEAP);
|
||||
|
||||
// amd64_heap_dump(heap_global);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
.section .text
|
||||
.global strlen
|
||||
strlen:
|
||||
// %rdi - str
|
||||
xorq %rax, %rax
|
||||
1:
|
||||
cmpq $0, (%rdi)
|
||||
je 1f
|
||||
incq %rax
|
||||
incq %rdi
|
||||
jmp 1b
|
||||
1:
|
||||
|
||||
ret
|
||||
+2
-1
@@ -42,4 +42,5 @@ endif
|
||||
# $(O)/sys/tty.o \
|
||||
# $(O)/sys/chr.o
|
||||
|
||||
OBJS+=$(O)/sys/debug.o
|
||||
OBJS+=$(O)/sys/debug.o \
|
||||
$(O)/sys/string.o
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
#include "sys/string.h"
|
||||
|
||||
size_t strlen(const char *a) {
|
||||
size_t s = 0;
|
||||
while (*a++) {
|
||||
++s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int strncmp(const char *a, const char *b, size_t n) {
|
||||
size_t c = 0;
|
||||
for (; c < n && (*a || *b); ++c, ++a, ++b) {
|
||||
if (*a != *b) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strcmp(const char *a, const char *b) {
|
||||
if (a == b) {
|
||||
return 0;
|
||||
}
|
||||
if (a == NULL || b == NULL) {
|
||||
return -1;
|
||||
}
|
||||
for (; *a || *b; ++a, ++b) {
|
||||
if (*a != *b) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *strcpy(char *dst, const char *src) {
|
||||
size_t i;
|
||||
for (i = 0; src[i]; ++i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
dst[i] = 0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strncpy(char *dst, const char *src, size_t lim) {
|
||||
size_t i = 0;
|
||||
while (i < lim) {
|
||||
if (!src[i]) {
|
||||
dst[i] = 0;
|
||||
return dst;
|
||||
}
|
||||
dst[i] = src[i];
|
||||
++i;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strchr(const char *s, int c) {
|
||||
while (*s) {
|
||||
if (*s == (char) c) {
|
||||
return (char *) s;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strrchr(const char *s, int c) {
|
||||
ssize_t l = (ssize_t) strlen(s);
|
||||
if (!l) {
|
||||
return NULL;
|
||||
}
|
||||
while (l >= 0) {
|
||||
if (s[l] == (char) c) {
|
||||
return (char *) &s[l];
|
||||
}
|
||||
--l;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n) {
|
||||
char *d = dest;
|
||||
const char *s = src;
|
||||
|
||||
if (d == s) {
|
||||
return d;
|
||||
}
|
||||
|
||||
if ((s + n) <= d || (d + n) <= s) {
|
||||
return memcpy(d, s, n);
|
||||
}
|
||||
|
||||
if (d < s) {
|
||||
if (((uintptr_t) s) % sizeof(size_t) == ((uintptr_t) d) % sizeof(size_t)) {
|
||||
while (((uintptr_t) d) % sizeof(size_t)) {
|
||||
if (!n--) {
|
||||
return dest;
|
||||
}
|
||||
*d++ = *s++;
|
||||
}
|
||||
for (; n >= sizeof(size_t); n -= sizeof(size_t), d += sizeof(size_t), s += sizeof(size_t)) {
|
||||
*((size_t *) d) = *((size_t *) s);
|
||||
}
|
||||
}
|
||||
for (; n; n--) {
|
||||
*d++ = *s++;
|
||||
}
|
||||
} else {
|
||||
if (((uintptr_t) s) % sizeof(size_t) == ((uintptr_t) d) % sizeof(size_t)) {
|
||||
while (((uintptr_t) (d + n)) % sizeof(size_t)) {
|
||||
if (!n--) {
|
||||
return dest;
|
||||
}
|
||||
d[n] = s[n];
|
||||
}
|
||||
while (n >= sizeof(size_t)) {
|
||||
n -= sizeof(size_t);
|
||||
*((size_t *) (d + n)) = *((size_t *) (s + n));
|
||||
}
|
||||
}
|
||||
while (n) {
|
||||
n--;
|
||||
d[n] = s[n];
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *blk, int v, size_t sz) {
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
((char *) blk)[i] = v;
|
||||
}
|
||||
return blk;
|
||||
}
|
||||
|
||||
void *memcpy(void *dst, const void *src, size_t sz) {
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
((char *) dst)[i] = ((const char *) src)[i];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user