Add kernel logging task
- Enable creating kernel tasks - Create kernel task that disables immediate-mode logging and prints logs to the console forever
This commit is contained in:
@@ -3,6 +3,8 @@
|
|||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
cpu_data bsp_cpu_data;
|
||||||
|
|
||||||
inline static void
|
inline static void
|
||||||
__cpuid(
|
__cpuid(
|
||||||
uint32_t leaf,
|
uint32_t leaf,
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ struct cpu_state
|
|||||||
uint64_t rip, cs, rflags, user_rsp, ss;
|
uint64_t rip, cs, rflags, user_rsp, ss;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cpu_data
|
||||||
|
{
|
||||||
|
uintptr_t rsp0;
|
||||||
|
uintptr_t rsp3;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern cpu_data bsp_cpu_data;
|
||||||
|
|
||||||
class cpu_id
|
class cpu_id
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -4,10 +4,6 @@
|
|||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "page_manager.h"
|
#include "page_manager.h"
|
||||||
|
|
||||||
#define print_regL(name, value) cons->printf(" %s: %016lx", name, (value));
|
|
||||||
#define print_regM(name, value) cons->printf(" %s: %016lx", name, (value));
|
|
||||||
#define print_regR(name, value) cons->printf(" %s: %016lx\n", name, (value));
|
|
||||||
|
|
||||||
size_t __counter_syscall_enter = 0;
|
size_t __counter_syscall_enter = 0;
|
||||||
size_t __counter_syscall_sysret = 0;
|
size_t __counter_syscall_sysret = 0;
|
||||||
|
|
||||||
@@ -36,7 +32,7 @@ print_regs(const cpu_state ®s)
|
|||||||
cons->puts("\n\n");
|
cons->puts("\n\n");
|
||||||
print_regL("rbp", regs.rbp);
|
print_regL("rbp", regs.rbp);
|
||||||
print_regM("rsp", regs.user_rsp);
|
print_regM("rsp", regs.user_rsp);
|
||||||
print_regR("sp0", tss_get_stack(0));
|
print_regR("sp0", bsp_cpu_data.rsp0);
|
||||||
|
|
||||||
print_regL("rip", regs.rip);
|
print_regL("rip", regs.rip);
|
||||||
print_regM("cr3", page_manager::get()->get_pml4());
|
print_regM("cr3", page_manager::get()->get_pml4());
|
||||||
|
|||||||
@@ -18,5 +18,7 @@ void print_regs(const cpu_state ®s);
|
|||||||
void print_stack(const cpu_state ®s);
|
void print_stack(const cpu_state ®s);
|
||||||
void print_stacktrace(int skip);
|
void print_stacktrace(int skip);
|
||||||
|
|
||||||
#define print_reg(name, value) cons->printf(" %s: %016lx\n", name, (value));
|
#define print_regL(name, value) cons->printf(" %s: %016lx", name, (value));
|
||||||
|
#define print_regM(name, value) cons->printf(" %s: %016lx", name, (value));
|
||||||
|
#define print_regR(name, value) cons->printf(" %s: %016lx\n", name, (value));
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,38 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs)
|
|||||||
|
|
||||||
switch (static_cast<isr>(regs->interrupt & 0xff)) {
|
switch (static_cast<isr>(regs->interrupt & 0xff)) {
|
||||||
|
|
||||||
|
case isr::isrDebug: {
|
||||||
|
cons->set_color(11);
|
||||||
|
cons->puts("\nDebug Exception:\n");
|
||||||
|
cons->set_color();
|
||||||
|
|
||||||
|
uint64_t dr = 0;
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("mov %%dr0, %0" : "=r"(dr));
|
||||||
|
print_regL("dr0", dr);
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("mov %%dr1, %0" : "=r"(dr));
|
||||||
|
print_regM("dr1", dr);
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("mov %%dr2, %0" : "=r"(dr));
|
||||||
|
print_regM("dr2", dr);
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("mov %%dr3, %0" : "=r"(dr));
|
||||||
|
print_regR("dr3", dr);
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("mov %%dr6, %0" : "=r"(dr));
|
||||||
|
print_regL("dr6", dr);
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("mov %%dr7, %0" : "=r"(dr));
|
||||||
|
print_regR("dr7", dr);
|
||||||
|
|
||||||
|
print_regL("rip", regs->rip);
|
||||||
|
print_regM("rsp", regs->user_rsp);
|
||||||
|
print_regM("fla", regs->rflags);
|
||||||
|
_halt();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case isr::isrGPFault: {
|
case isr::isrGPFault: {
|
||||||
cons->set_color(9);
|
cons->set_color(9);
|
||||||
cons->puts("\nGeneral Protection Fault:\n");
|
cons->puts("\nGeneral Protection Fault:\n");
|
||||||
@@ -145,7 +177,6 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs)
|
|||||||
print_stacktrace(2);
|
print_stacktrace(2);
|
||||||
print_stack(*regs);
|
print_stack(*regs);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
_halt();
|
_halt();
|
||||||
break;
|
break;
|
||||||
@@ -165,12 +196,9 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs)
|
|||||||
|
|
||||||
uint64_t cr2 = 0;
|
uint64_t cr2 = 0;
|
||||||
__asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2));
|
__asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2));
|
||||||
print_reg("cr2", cr2);
|
print_regL("cr2", cr2);
|
||||||
|
print_regM("rsp", regs->user_rsp);
|
||||||
print_reg("rsp", regs->user_rsp);
|
print_regR("rip", regs->rip);
|
||||||
print_reg("rip", regs->rip);
|
|
||||||
|
|
||||||
cons->puts("\n");
|
|
||||||
//print_stacktrace(2);
|
//print_stacktrace(2);
|
||||||
}
|
}
|
||||||
_halt();
|
_halt();
|
||||||
@@ -242,7 +270,7 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs)
|
|||||||
regs->interrupt, regs->errorcode);
|
regs->interrupt, regs->errorcode);
|
||||||
|
|
||||||
print_regs(*regs);
|
print_regs(*regs);
|
||||||
//print_stacktrace(2);
|
print_stacktrace(2);
|
||||||
_halt();
|
_halt();
|
||||||
}
|
}
|
||||||
*reinterpret_cast<uint32_t *>(0xffffff80fee000b0) = 0;
|
*reinterpret_cast<uint32_t *>(0xffffff80fee000b0) = 0;
|
||||||
|
|||||||
@@ -28,6 +28,31 @@ output_log(log::area_t area, log::level severity, const char *message)
|
|||||||
cons->set_color();
|
cons->set_color();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logger_task()
|
||||||
|
{
|
||||||
|
uint8_t buffer[257];
|
||||||
|
auto *ent = reinterpret_cast<log::logger::entry *>(buffer);
|
||||||
|
auto *cons = console::get();
|
||||||
|
|
||||||
|
g_logger.set_immediate(nullptr);
|
||||||
|
log::info(logs::task, "Starting kernel logger task");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
__asm__ ("cli");
|
||||||
|
if(g_logger.get_entry(buffer, sizeof(buffer))) {
|
||||||
|
buffer[ent->bytes] = 0;
|
||||||
|
cons->set_color(level_colors[static_cast<int>(ent->severity)]);
|
||||||
|
cons->printf("%9s %8s: %s\n",
|
||||||
|
g_logger.area_name(ent->area),
|
||||||
|
g_logger.level_name(ent->severity),
|
||||||
|
ent->message);
|
||||||
|
cons->set_color();
|
||||||
|
}
|
||||||
|
__asm__ ("sti");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
new (&g_logger) log::logger(log_buffer, sizeof(log_buffer));
|
new (&g_logger) log::logger(log_buffer, sizeof(log_buffer));
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace logs {
|
|||||||
#undef LOG
|
#undef LOG
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
void logger_task();
|
||||||
|
|
||||||
} // namespace logs
|
} // namespace logs
|
||||||
|
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ kernel_main(kernel_args *header)
|
|||||||
syscall_enable();
|
syscall_enable();
|
||||||
scheduler *sched = new (&scheduler::get()) scheduler(devices->get_lapic());
|
scheduler *sched = new (&scheduler::get()) scheduler(devices->get_lapic());
|
||||||
|
|
||||||
|
sched->create_kernel_task(-1, logs::logger_task);
|
||||||
|
|
||||||
for (auto &f : ird.files()) {
|
for (auto &f : ird.files()) {
|
||||||
if (f.executable())
|
if (f.executable())
|
||||||
sched->load_process(f.name(), f.data(), f.size());
|
sched->load_process(f.name(), f.data(), f.size());
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ public:
|
|||||||
/// \returns A pointer to the system page manager
|
/// \returns A pointer to the system page manager
|
||||||
static page_manager * get();
|
static page_manager * get();
|
||||||
|
|
||||||
|
/// Get a pointer to the kernel's PML4
|
||||||
|
inline page_table * get_kernel_pml4() { return m_kernel_pml4; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Copy a physical page
|
/// Copy a physical page
|
||||||
/// \arg orig Physical address of the page to copy
|
/// \arg orig Physical address of the page to copy
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "kutil/linked_list.h"
|
#include "kutil/linked_list.h"
|
||||||
#include "page_manager.h"
|
#include "page_manager.h"
|
||||||
|
|
||||||
typedef uint32_t pid_t;
|
typedef int32_t pid_t;
|
||||||
|
|
||||||
|
|
||||||
enum class process_flags : uint32_t
|
enum class process_flags : uint32_t
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
%macro push_all 0
|
%macro push_all 0
|
||||||
sub rsp, 0x78
|
sub rsp, 0x78
|
||||||
|
|
||||||
|
; ss3 rsp + 0xa8
|
||||||
|
; rsp3 rsp + 0xa0
|
||||||
|
; flags3 rsp + 0x98
|
||||||
|
; cs3 rsp + 0x90
|
||||||
|
; rip3 rsp + 0x88
|
||||||
|
; error rsp + 0x80
|
||||||
|
; vector rsp + 0x78
|
||||||
|
|
||||||
mov [rsp + 0x70], rax
|
mov [rsp + 0x70], rax
|
||||||
mov [rsp + 0x68], rcx
|
mov [rsp + 0x68], rcx
|
||||||
mov [rsp + 0x60], rdx
|
mov [rsp + 0x60], rdx
|
||||||
|
|||||||
@@ -27,14 +27,6 @@ extern "C" {
|
|||||||
void load_process(const void *image_start, size_t bytes, process *proc, cpu_state *state);
|
void load_process(const void *image_start, size_t bytes, process *proc, cpu_state *state);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cpu_data
|
|
||||||
{
|
|
||||||
uintptr_t rsp0;
|
|
||||||
uintptr_t rsp3;
|
|
||||||
};
|
|
||||||
|
|
||||||
static cpu_data bsp_cpu_data;
|
|
||||||
|
|
||||||
scheduler::scheduler(lapic *apic) :
|
scheduler::scheduler(lapic *apic) :
|
||||||
m_apic(apic),
|
m_apic(apic),
|
||||||
m_next_pid(1)
|
m_next_pid(1)
|
||||||
@@ -118,10 +110,12 @@ load_process(const void *image_start, size_t bytes, process *proc, cpu_state *st
|
|||||||
}
|
}
|
||||||
|
|
||||||
process_node *
|
process_node *
|
||||||
scheduler::create_process()
|
scheduler::create_process(pid_t pid)
|
||||||
{
|
{
|
||||||
|
kassert(pid <= 0, "Cannot specify a positive pid in create_process");
|
||||||
|
|
||||||
auto *proc = m_process_allocator.pop();
|
auto *proc = m_process_allocator.pop();
|
||||||
proc->pid = m_next_pid++;
|
proc->pid = pid ? pid : m_next_pid++;
|
||||||
proc->priority = default_priority;
|
proc->priority = default_priority;
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
@@ -189,6 +183,44 @@ scheduler::load_process(const char *name, const void *data, size_t size)
|
|||||||
log::debug(logs::task, " PML4 %016lx", pml4);
|
log::debug(logs::task, " PML4 %016lx", pml4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
scheduler::create_kernel_task(pid_t pid, void (*task)())
|
||||||
|
{
|
||||||
|
auto *proc = create_process(pid);
|
||||||
|
|
||||||
|
uint16_t kcs = (1 << 3) | 0; // Kernel CS is GDT entry 1, ring 0
|
||||||
|
uint16_t kss = (2 << 3) | 0; // Kernel SS is GDT entry 2, ring 0
|
||||||
|
|
||||||
|
// Create a one-page kernel stack space
|
||||||
|
void *stack0 = proc->setup_kernel_stack(stack_size, 0);
|
||||||
|
|
||||||
|
// Stack grows down, point to the end, resere space for initial null frame
|
||||||
|
static const size_t null_frame = sizeof(uint64_t);
|
||||||
|
void *sp0 = kutil::offset_pointer(stack0, stack_size - null_frame);
|
||||||
|
|
||||||
|
cpu_state *state = reinterpret_cast<cpu_state *>(sp0) - 1;
|
||||||
|
|
||||||
|
// Highest state in the stack is the process' kernel stack for the loader
|
||||||
|
// to iret to:
|
||||||
|
state->ss = kss;
|
||||||
|
state->cs = kcs;
|
||||||
|
state->rflags = rflags_int;
|
||||||
|
state->rip = reinterpret_cast<uint64_t>(task);
|
||||||
|
state->user_rsp = reinterpret_cast<uint64_t>(state);
|
||||||
|
|
||||||
|
proc->rsp = reinterpret_cast<uintptr_t>(state);
|
||||||
|
proc->pml4 = page_manager::get()->get_kernel_pml4();
|
||||||
|
proc->quanta = process_quanta;
|
||||||
|
proc->flags =
|
||||||
|
process_flags::running |
|
||||||
|
process_flags::ready;
|
||||||
|
|
||||||
|
m_runlists[default_priority].push_back(proc);
|
||||||
|
|
||||||
|
log::debug(logs::task, "Creating kernel task: pid %d pri %d", proc->pid, proc->priority);
|
||||||
|
log::debug(logs::task, " RSP0 %016lx", state);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
scheduler::start()
|
scheduler::start()
|
||||||
{
|
{
|
||||||
@@ -276,7 +308,6 @@ scheduler::schedule(uintptr_t rsp0)
|
|||||||
tss_set_stack(0, rsp0 + sizeof(cpu_state));
|
tss_set_stack(0, rsp0 + sizeof(cpu_state));
|
||||||
bsp_cpu_data.rsp0 = rsp0;
|
bsp_cpu_data.rsp0 = rsp0;
|
||||||
|
|
||||||
|
|
||||||
// Swap page tables
|
// Swap page tables
|
||||||
page_table *pml4 = m_current->pml4;
|
page_table *pml4 = m_current->pml4;
|
||||||
page_manager::set_pml4(pml4);
|
page_manager::set_pml4(pml4);
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ public:
|
|||||||
static const uint8_t default_priority = num_priorities / 2;
|
static const uint8_t default_priority = num_priorities / 2;
|
||||||
|
|
||||||
/// How long the timer quantum is
|
/// How long the timer quantum is
|
||||||
static const uint64_t quantum_micros = 100000;
|
static const uint64_t quantum_micros = 1000;
|
||||||
|
|
||||||
/// How many quantums a process gets before being rescheduled
|
/// How many quantums a process gets before being rescheduled
|
||||||
static const uint16_t process_quanta = 10;
|
static const uint16_t process_quanta = 100;
|
||||||
|
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
/// \arg apic Pointer to the local APIC object
|
/// \arg apic Pointer to the local APIC object
|
||||||
@@ -36,6 +36,11 @@ public:
|
|||||||
/// \arg size Size of the program image, in bytes
|
/// \arg size Size of the program image, in bytes
|
||||||
void load_process(const char *name, const void *data, size_t size);
|
void load_process(const char *name, const void *data, size_t size);
|
||||||
|
|
||||||
|
/// Create a new kernel task
|
||||||
|
/// \arg pid Pid to use for this task, must be negative
|
||||||
|
/// \arg proc Function to run as a kernel task
|
||||||
|
void create_kernel_task(pid_t pid, void (*task)());
|
||||||
|
|
||||||
/// Start the scheduler working. This may involve starting
|
/// Start the scheduler working. This may involve starting
|
||||||
/// timer interrupts or other preemption methods.
|
/// timer interrupts or other preemption methods.
|
||||||
void start();
|
void start();
|
||||||
@@ -65,8 +70,9 @@ private:
|
|||||||
|
|
||||||
/// Create a new process object. This process will have its pid
|
/// Create a new process object. This process will have its pid
|
||||||
/// set but nothing else.
|
/// set but nothing else.
|
||||||
|
/// \arg pid The pid to give the process (0 for automatic)
|
||||||
/// \returns The new process object
|
/// \returns The new process object
|
||||||
process_node * create_process();
|
process_node * create_process(pid_t pid = 0);
|
||||||
|
|
||||||
/// Handle a timer tick
|
/// Handle a timer tick
|
||||||
/// \arg rsp0 The stack pointer of the current interrupt handler
|
/// \arg rsp0 The stack pointer of the current interrupt handler
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ logger::get_entry(void *buffer, size_t size)
|
|||||||
void *out;
|
void *out;
|
||||||
size_t out_size = m_buffer.get_block(&out);
|
size_t out_size = m_buffer.get_block(&out);
|
||||||
entry *ent = reinterpret_cast<entry *>(out);
|
entry *ent = reinterpret_cast<entry *>(out);
|
||||||
if (out_size == 0)
|
if (out_size == 0 || out == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
kassert(out_size >= sizeof(entry), "Couldn't read a full entry");
|
kassert(out_size >= sizeof(entry), "Couldn't read a full entry");
|
||||||
|
|||||||
Reference in New Issue
Block a user