Working LAPIC timer

This commit is contained in:
Mark
2019-10-09 18:24:28 +03:00
parent c345c3db26
commit c3cc760b2c
22 changed files with 802 additions and 173 deletions
-147
View File
@@ -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
}
+31
View File
@@ -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
+47
View File
@@ -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);
+4
View File
@@ -0,0 +1,4 @@
#pragma once
#include "sys/amd64/hw/acpi.h"
void amd64_apic_init(struct acpi_madt *madt);
+37
View File
@@ -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);
+3
View File
@@ -0,0 +1,3 @@
#pragma once
void amd64_idt_init(void);
+34
View File
@@ -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);
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+68
View File
@@ -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);
}
+110
View File
@@ -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;
}
+96
View File
@@ -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
+46
View File
@@ -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);
}
+6
View File
@@ -0,0 +1,6 @@
.section .text
.global amd64_gdt_load
amd64_gdt_load:
lgdt (%rdi)
// Not sure if CS reload is needed
retq
+56
View File
@@ -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)");
}
+32
View File
@@ -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"
+16
View File
@@ -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");
}
}
+52
View File
@@ -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);
}
-14
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}