mirror of
https://github.com/justinian/jsix.git
synced 2025-12-09 16:04:32 -08:00
[kernel] Move log buffer to its own memory section
In prep for the coming change to keep log entries as a true ring buffer, move the log buffer from bss into its own memory section. Related changes in this commit: - New vm_area_ring, which maps a set of pages twice to allow easy linear reading of data from a ring buffer when it wraps around the end. - logger_init() went away, and the logger ctor is called from mem::initialize() - Instead of an event object, the logger just has a bare wait_queue - util::counted::from template type changed slightly to allow easy conversion from an intptr_t as well as a pointer - Previously added debugcon_logger code removed - this will be added in a separate file in a followup commit
This commit is contained in:
@@ -24,3 +24,6 @@
|
|||||||
|
|
||||||
- name: buffers
|
- name: buffers
|
||||||
size: 64G
|
size: 64G
|
||||||
|
|
||||||
|
- name: logs
|
||||||
|
size: 2G
|
||||||
|
|||||||
@@ -36,9 +36,8 @@ kernel_main(bootproto::args *args)
|
|||||||
panic::install(args->panic_handler, args->symbol_table);
|
panic::install(args->panic_handler, args->symbol_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger_init();
|
|
||||||
|
|
||||||
cpu_data *cpu = bsp_early_init();
|
cpu_data *cpu = bsp_early_init();
|
||||||
|
mem::initialize(*args);
|
||||||
|
|
||||||
kassert(args->magic == bootproto::args_magic,
|
kassert(args->magic == bootproto::args_magic,
|
||||||
"Bad kernel args magic number");
|
"Bad kernel args magic number");
|
||||||
@@ -51,7 +50,6 @@ kernel_main(bootproto::args *args)
|
|||||||
|
|
||||||
disable_legacy_pic();
|
disable_legacy_pic();
|
||||||
|
|
||||||
mem::initialize(*args);
|
|
||||||
|
|
||||||
bsp_late_init();
|
bsp_late_init();
|
||||||
|
|
||||||
|
|||||||
@@ -6,15 +6,9 @@
|
|||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "memory.h"
|
|
||||||
#include "objects/system.h"
|
#include "objects/system.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
|
|
||||||
static constexpr bool j6_debugcon_enable = false;
|
|
||||||
static constexpr uint16_t j6_debugcon_port = 0x6600;
|
|
||||||
|
|
||||||
static uint8_t log_buffer[log::logger::log_pages * arch::frame_size];
|
|
||||||
|
|
||||||
// The logger is initialized _before_ global constructors are called,
|
// The logger is initialized _before_ global constructors are called,
|
||||||
// so that we can start log output immediately. Keep its constructor
|
// so that we can start log output immediately. Keep its constructor
|
||||||
// from being called here so as to not overwrite the previous initialization.
|
// from being called here so as to not overwrite the previous initialization.
|
||||||
@@ -25,36 +19,16 @@ log::logger &g_logger = __g_logger_storage.value;
|
|||||||
namespace log {
|
namespace log {
|
||||||
|
|
||||||
logger *logger::s_log = nullptr;
|
logger *logger::s_log = nullptr;
|
||||||
const char *logger::s_level_names[] = {"", "fatal", "error", "warn", "info", "verbose", "spam"};
|
|
||||||
const char *logger::s_area_names[] = {
|
|
||||||
#define LOG(name, lvl) #name ,
|
|
||||||
#include <j6/tables/log_areas.inc>
|
|
||||||
#undef LOG
|
|
||||||
nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void
|
|
||||||
debug_out(const char *msg, size_t size)
|
|
||||||
{
|
|
||||||
asm ( "rep outsb;" :: "c"(size), "d"(j6_debugcon_port), "S"(msg) );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
debug_newline()
|
|
||||||
{
|
|
||||||
static const char *newline = "\r\n";
|
|
||||||
asm ( "rep outsb;" :: "c"(2), "d"(j6_debugcon_port), "S"(newline) );
|
|
||||||
}
|
|
||||||
|
|
||||||
logger::logger() :
|
logger::logger() :
|
||||||
m_buffer(nullptr, 0)
|
m_buffer {nullptr, 0}
|
||||||
{
|
{
|
||||||
memset(&m_levels, 0, sizeof(m_levels));
|
memset(&m_levels, 0, sizeof(m_levels));
|
||||||
s_log = this;
|
s_log = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger::logger(uint8_t *buffer, size_t size) :
|
logger::logger(util::buffer data) :
|
||||||
m_buffer(buffer, size)
|
m_buffer {data.pointer, data.count}
|
||||||
{
|
{
|
||||||
memset(&m_levels, 0, sizeof(m_levels));
|
memset(&m_levels, 0, sizeof(m_levels));
|
||||||
s_log = this;
|
s_log = this;
|
||||||
@@ -70,13 +44,6 @@ logger::output(level severity, logs area, const char *fmt, va_list args)
|
|||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
|
|
||||||
if constexpr (j6_debugcon_enable) {
|
|
||||||
size_t dlen = util::format({buffer, sizeof(buffer)}, "%7s %7s| ",
|
|
||||||
s_area_names[static_cast<uint8_t>(area)],
|
|
||||||
s_level_names[static_cast<uint8_t>(severity)]);
|
|
||||||
debug_out(buffer, dlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
entry *header = reinterpret_cast<entry *>(buffer);
|
entry *header = reinterpret_cast<entry *>(buffer);
|
||||||
header->bytes = sizeof(entry);
|
header->bytes = sizeof(entry);
|
||||||
header->area = area;
|
header->area = area;
|
||||||
@@ -86,11 +53,6 @@ logger::output(level severity, logs area, const char *fmt, va_list args)
|
|||||||
header->message[mlen] = 0;
|
header->message[mlen] = 0;
|
||||||
header->bytes += mlen + 1;
|
header->bytes += mlen + 1;
|
||||||
|
|
||||||
if constexpr (j6_debugcon_enable) {
|
|
||||||
debug_out(header->message, mlen);
|
|
||||||
debug_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
util::scoped_lock lock {m_lock};
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
uint8_t *out;
|
uint8_t *out;
|
||||||
@@ -103,7 +65,7 @@ logger::output(level severity, logs area, const char *fmt, va_list args)
|
|||||||
memcpy(out, buffer, n);
|
memcpy(out, buffer, n);
|
||||||
m_buffer.commit(n);
|
m_buffer.commit(n);
|
||||||
|
|
||||||
m_event.signal(1);
|
m_waiting.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
@@ -115,7 +77,7 @@ logger::get_entry(void *buffer, size_t size)
|
|||||||
size_t out_size = m_buffer.get_block(&out);
|
size_t out_size = m_buffer.get_block(&out);
|
||||||
if (out_size == 0 || out == 0) {
|
if (out_size == 0 || out == 0) {
|
||||||
lock.release();
|
lock.release();
|
||||||
m_event.wait();
|
m_waiting.wait();
|
||||||
lock.reacquire();
|
lock.reacquire();
|
||||||
out_size = m_buffer.get_block(&out);
|
out_size = m_buffer.get_block(&out);
|
||||||
|
|
||||||
@@ -168,9 +130,3 @@ void fatal(logs area, const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace log
|
} // namespace log
|
||||||
|
|
||||||
|
|
||||||
void logger_init()
|
|
||||||
{
|
|
||||||
new (&g_logger) log::logger(log_buffer, sizeof(log_buffer));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <util/bip_buffer.h>
|
#include <util/bip_buffer.h>
|
||||||
|
#include <util/counted.h>
|
||||||
#include <util/spinlock.h>
|
#include <util/spinlock.h>
|
||||||
|
|
||||||
#include "objects/event.h"
|
#include "objects/event.h"
|
||||||
@@ -19,6 +20,9 @@ enum class logs : uint8_t {
|
|||||||
|
|
||||||
namespace log {
|
namespace log {
|
||||||
|
|
||||||
|
/// Size of the log ring buffer
|
||||||
|
inline constexpr unsigned log_pages = 16;
|
||||||
|
|
||||||
enum class level : uint8_t {
|
enum class level : uint8_t {
|
||||||
silent, fatal, error, warn, info, verbose, spam, max
|
silent, fatal, error, warn, info, verbose, spam, max
|
||||||
};
|
};
|
||||||
@@ -29,26 +33,16 @@ constexpr unsigned areas_count =
|
|||||||
class logger
|
class logger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Size of the log ring buffer
|
|
||||||
static constexpr unsigned log_pages = 16;
|
|
||||||
|
|
||||||
/// Default constructor. Creates a logger without a backing store.
|
/// Default constructor. Creates a logger without a backing store.
|
||||||
logger();
|
logger();
|
||||||
|
|
||||||
/// Constructor. Logs are written to the given buffer.
|
/// Constructor. Logs are written to the given buffer.
|
||||||
/// \arg buffer Buffer to which logs are written
|
/// \arg buffer Buffer to which logs are written
|
||||||
/// \arg size Size of `buffer`, in bytes
|
logger(util::buffer buffer);
|
||||||
logger(uint8_t *buffer, size_t size);
|
|
||||||
|
|
||||||
/// Get the default logger.
|
/// Get the default logger.
|
||||||
inline logger & get() { return *s_log; }
|
inline logger & get() { return *s_log; }
|
||||||
|
|
||||||
/// Get the registered name for a given area
|
|
||||||
inline const char * area_name(logs area) const { return s_area_names[static_cast<unsigned>(area)]; }
|
|
||||||
|
|
||||||
/// Get the name of a level
|
|
||||||
inline const char * level_name(level l) const { return s_level_names[static_cast<unsigned>(l)]; }
|
|
||||||
|
|
||||||
/// Write to the log
|
/// Write to the log
|
||||||
/// \arg severity The severity of the message
|
/// \arg severity The severity of the message
|
||||||
/// \arg area The log area to write to
|
/// \arg area The log area to write to
|
||||||
@@ -100,7 +94,7 @@ private:
|
|||||||
return m_levels[static_cast<unsigned>(area)];
|
return m_levels[static_cast<unsigned>(area)];
|
||||||
}
|
}
|
||||||
|
|
||||||
obj::event m_event;
|
wait_queue m_waiting;
|
||||||
|
|
||||||
level m_levels[areas_count];
|
level m_levels[areas_count];
|
||||||
|
|
||||||
@@ -108,8 +102,6 @@ private:
|
|||||||
util::spinlock m_lock;
|
util::spinlock m_lock;
|
||||||
|
|
||||||
static logger *s_log;
|
static logger *s_log;
|
||||||
static const char *s_area_names[areas_count+1];
|
|
||||||
static const char *s_level_names[static_cast<unsigned>(level::max)];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void spam (logs area, const char *fmt, ...);
|
void spam (logs area, const char *fmt, ...);
|
||||||
@@ -119,8 +111,6 @@ void warn (logs area, const char *fmt, ...);
|
|||||||
void error (logs area, const char *fmt, ...);
|
void error (logs area, const char *fmt, ...);
|
||||||
void fatal (logs area, const char *fmt, ...);
|
void fatal (logs area, const char *fmt, ...);
|
||||||
|
|
||||||
extern log::logger &g_logger;
|
|
||||||
|
|
||||||
} // namespace log
|
} // namespace log
|
||||||
|
|
||||||
void logger_init();
|
extern log::logger &g_logger;
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ frame_allocator &g_frame_allocator = __g_frame_allocator_storage.value;
|
|||||||
static util::no_construct<obj::vm_area_untracked> __g_kernel_heap_area_storage;
|
static util::no_construct<obj::vm_area_untracked> __g_kernel_heap_area_storage;
|
||||||
obj::vm_area_untracked &g_kernel_heap_area = __g_kernel_heap_area_storage.value;
|
obj::vm_area_untracked &g_kernel_heap_area = __g_kernel_heap_area_storage.value;
|
||||||
|
|
||||||
|
static util::no_construct<obj::vm_area_ring> __g_kernel_log_area_storage;
|
||||||
|
obj::vm_area_ring &g_kernel_log_area = __g_kernel_log_area_storage.value;
|
||||||
|
|
||||||
static util::no_construct<obj::vm_area_untracked> __g_kernel_heapmap_area_storage;
|
static util::no_construct<obj::vm_area_untracked> __g_kernel_heapmap_area_storage;
|
||||||
obj::vm_area_untracked &g_kernel_heapmap_area = __g_kernel_heapmap_area_storage.value;
|
obj::vm_area_untracked &g_kernel_heapmap_area = __g_kernel_heapmap_area_storage.value;
|
||||||
|
|
||||||
@@ -78,7 +81,7 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
|
|||||||
|
|
||||||
page_table *kpml4 = static_cast<page_table*>(kargs.pml4);
|
page_table *kpml4 = static_cast<page_table*>(kargs.pml4);
|
||||||
|
|
||||||
|
// Initialize the frame allocator
|
||||||
frame_block *blocks = reinterpret_cast<frame_block*>(mem::bitmap_offset);
|
frame_block *blocks = reinterpret_cast<frame_block*>(mem::bitmap_offset);
|
||||||
new (&g_frame_allocator) frame_allocator {blocks, kargs.frame_blocks.count};
|
new (&g_frame_allocator) frame_allocator {blocks, kargs.frame_blocks.count};
|
||||||
|
|
||||||
@@ -91,10 +94,11 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
|
|||||||
reg = reg->next;
|
reg = reg->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the kernel "process" and vm_space
|
||||||
obj::process *kp = obj::process::create_kernel_process(kpml4);
|
obj::process *kp = obj::process::create_kernel_process(kpml4);
|
||||||
vm_space &vm = kp->space();
|
vm_space &vm = kp->space();
|
||||||
|
|
||||||
|
// Create the heap space and heap allocator
|
||||||
obj::vm_area *heap = new (&g_kernel_heap_area)
|
obj::vm_area *heap = new (&g_kernel_heap_area)
|
||||||
obj::vm_area_untracked(mem::heap_size, vm_flags::write);
|
obj::vm_area_untracked(mem::heap_size, vm_flags::write);
|
||||||
|
|
||||||
@@ -106,6 +110,16 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
|
|||||||
|
|
||||||
new (&g_kernel_heap) heap_allocator {mem::heap_offset, mem::heap_size, mem::heapmap_offset};
|
new (&g_kernel_heap) heap_allocator {mem::heap_offset, mem::heap_size, mem::heapmap_offset};
|
||||||
|
|
||||||
|
// Set up the log area and logger
|
||||||
|
size_t log_buffer_size = log::log_pages * arch::frame_size;
|
||||||
|
obj::vm_area *logs = new (&g_kernel_log_area)
|
||||||
|
obj::vm_area_ring(log_buffer_size, vm_flags::write);
|
||||||
|
vm.add(mem::logs_offset, logs);
|
||||||
|
|
||||||
|
new (&g_logger) log::logger(
|
||||||
|
util::buffer::from(mem::logs_offset, log_buffer_size));
|
||||||
|
|
||||||
|
// Set up the capability tables
|
||||||
obj::vm_area *caps = new (&g_cap_table_area)
|
obj::vm_area *caps = new (&g_cap_table_area)
|
||||||
obj::vm_area_untracked(mem::caps_size, vm_flags::write);
|
obj::vm_area_untracked(mem::caps_size, vm_flags::write);
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,11 @@ vm_area_open::get_page(uintptr_t offset, uintptr_t &phys)
|
|||||||
return page_tree::find_or_add(m_mapped, offset, phys);
|
return page_tree::find_or_add(m_mapped, offset, phys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vm_area_open::add_existing(uintptr_t offset, uintptr_t phys)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
vm_area_guarded::vm_area_guarded(uintptr_t start, size_t buf_pages, size_t size, vm_flags flags) :
|
vm_area_guarded::vm_area_guarded(uintptr_t start, size_t buf_pages, size_t size, vm_flags flags) :
|
||||||
m_pages {buf_pages + 1}, // Sections are N+1 pages for the leading guard page
|
m_pages {buf_pages + 1}, // Sections are N+1 pages for the leading guard page
|
||||||
@@ -179,4 +184,20 @@ vm_area_guarded::get_page(uintptr_t offset, uintptr_t &phys)
|
|||||||
return vm_area_open::get_page(offset, phys);
|
return vm_area_open::get_page(offset, phys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vm_area_ring::vm_area_ring(size_t size, vm_flags flags) :
|
||||||
|
vm_area_open {size * 2, flags},
|
||||||
|
m_bufsize {size}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
vm_area_ring::~vm_area_ring() {}
|
||||||
|
|
||||||
|
bool
|
||||||
|
vm_area_ring::get_page(uintptr_t offset, uintptr_t &phys)
|
||||||
|
{
|
||||||
|
if (offset > m_bufsize)
|
||||||
|
offset -= m_bufsize;
|
||||||
|
return vm_area_open::get_page(offset, phys);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace obj
|
} // namespace obj
|
||||||
|
|||||||
@@ -126,6 +126,10 @@ public:
|
|||||||
|
|
||||||
virtual bool get_page(uintptr_t offset, uintptr_t &phys) override;
|
virtual bool get_page(uintptr_t offset, uintptr_t &phys) override;
|
||||||
|
|
||||||
|
/// Tell this VMA about an existing mapping that did not originate
|
||||||
|
/// from get_page.
|
||||||
|
void add_existing(uintptr_t offset, uintptr_t phys);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
page_tree *m_mapped;
|
page_tree *m_mapped;
|
||||||
};
|
};
|
||||||
@@ -178,4 +182,25 @@ private:
|
|||||||
block_allocator m_stacks;
|
block_allocator m_stacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Area that maps its pages twice for use in ring buffers.
|
||||||
|
/// Cannot be resized.
|
||||||
|
class vm_area_ring :
|
||||||
|
public vm_area_open
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Constructor.
|
||||||
|
/// \arg size Virtual size of the ring buffer. Note that
|
||||||
|
/// the VMA size will be double this value.
|
||||||
|
/// \arg flags Flags for this memory area
|
||||||
|
vm_area_ring(size_t size, vm_flags flags);
|
||||||
|
virtual ~vm_area_ring();
|
||||||
|
|
||||||
|
virtual bool get_page(uintptr_t offset, uintptr_t &phys) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t m_bufsize;
|
||||||
|
page_tree *m_mapped;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace obj
|
} // namespace obj
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ wait_queue::add_thread(obj::thread *t)
|
|||||||
m_threads.push_back(t);
|
m_threads.push_back(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wait_queue::wait()
|
||||||
|
{
|
||||||
|
obj::thread ¤t = obj::thread::current();
|
||||||
|
add_thread(¤t);
|
||||||
|
current.block();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
wait_queue::pop_exited()
|
wait_queue::pop_exited()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ public:
|
|||||||
/// queue lock.
|
/// queue lock.
|
||||||
void add_thread(obj::thread *t);
|
void add_thread(obj::thread *t);
|
||||||
|
|
||||||
|
/// Block the current thread on the queue.
|
||||||
|
void wait();
|
||||||
|
|
||||||
/// Pops the next waiting thread off the queue.
|
/// Pops the next waiting thread off the queue.
|
||||||
/// Locks the queue lock.
|
/// Locks the queue lock.
|
||||||
inline obj::thread * pop_next() {
|
inline obj::thread * pop_next() {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ struct counted<const void>
|
|||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline counted<const void> from(T *p, size_t c) {
|
static inline counted<const void> from(T p, size_t c) {
|
||||||
return {reinterpret_cast<const void*>(p), c};
|
return {reinterpret_cast<const void*>(p), c};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ struct counted<void>
|
|||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline counted<void> from(T *p, size_t c) {
|
static inline counted<void> from(T p, size_t c) {
|
||||||
return {reinterpret_cast<void*>(p), c};
|
return {reinterpret_cast<void*>(p), c};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user