[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:
@@ -36,9 +36,8 @@ kernel_main(bootproto::args *args)
|
||||
panic::install(args->panic_handler, args->symbol_table);
|
||||
}
|
||||
|
||||
logger_init();
|
||||
|
||||
cpu_data *cpu = bsp_early_init();
|
||||
mem::initialize(*args);
|
||||
|
||||
kassert(args->magic == bootproto::args_magic,
|
||||
"Bad kernel args magic number");
|
||||
@@ -51,7 +50,6 @@ kernel_main(bootproto::args *args)
|
||||
|
||||
disable_legacy_pic();
|
||||
|
||||
mem::initialize(*args);
|
||||
|
||||
bsp_late_init();
|
||||
|
||||
|
||||
@@ -6,15 +6,9 @@
|
||||
|
||||
#include "assert.h"
|
||||
#include "logger.h"
|
||||
#include "memory.h"
|
||||
#include "objects/system.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,
|
||||
// so that we can start log output immediately. Keep its constructor
|
||||
// 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 {
|
||||
|
||||
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() :
|
||||
m_buffer(nullptr, 0)
|
||||
m_buffer {nullptr, 0}
|
||||
{
|
||||
memset(&m_levels, 0, sizeof(m_levels));
|
||||
s_log = this;
|
||||
}
|
||||
|
||||
logger::logger(uint8_t *buffer, size_t size) :
|
||||
m_buffer(buffer, size)
|
||||
logger::logger(util::buffer data) :
|
||||
m_buffer {data.pointer, data.count}
|
||||
{
|
||||
memset(&m_levels, 0, sizeof(m_levels));
|
||||
s_log = this;
|
||||
@@ -70,13 +44,6 @@ logger::output(level severity, logs area, const char *fmt, va_list args)
|
||||
{
|
||||
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);
|
||||
header->bytes = sizeof(entry);
|
||||
header->area = area;
|
||||
@@ -86,11 +53,6 @@ logger::output(level severity, logs area, const char *fmt, va_list args)
|
||||
header->message[mlen] = 0;
|
||||
header->bytes += mlen + 1;
|
||||
|
||||
if constexpr (j6_debugcon_enable) {
|
||||
debug_out(header->message, mlen);
|
||||
debug_newline();
|
||||
}
|
||||
|
||||
util::scoped_lock lock {m_lock};
|
||||
|
||||
uint8_t *out;
|
||||
@@ -103,7 +65,7 @@ logger::output(level severity, logs area, const char *fmt, va_list args)
|
||||
memcpy(out, buffer, n);
|
||||
m_buffer.commit(n);
|
||||
|
||||
m_event.signal(1);
|
||||
m_waiting.clear();
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -115,7 +77,7 @@ logger::get_entry(void *buffer, size_t size)
|
||||
size_t out_size = m_buffer.get_block(&out);
|
||||
if (out_size == 0 || out == 0) {
|
||||
lock.release();
|
||||
m_event.wait();
|
||||
m_waiting.wait();
|
||||
lock.reacquire();
|
||||
out_size = m_buffer.get_block(&out);
|
||||
|
||||
@@ -168,9 +130,3 @@ void fatal(logs area, const char *fmt, ...)
|
||||
}
|
||||
|
||||
} // namespace log
|
||||
|
||||
|
||||
void logger_init()
|
||||
{
|
||||
new (&g_logger) log::logger(log_buffer, sizeof(log_buffer));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <util/bip_buffer.h>
|
||||
#include <util/counted.h>
|
||||
#include <util/spinlock.h>
|
||||
|
||||
#include "objects/event.h"
|
||||
@@ -19,6 +20,9 @@ enum class logs : uint8_t {
|
||||
|
||||
namespace log {
|
||||
|
||||
/// Size of the log ring buffer
|
||||
inline constexpr unsigned log_pages = 16;
|
||||
|
||||
enum class level : uint8_t {
|
||||
silent, fatal, error, warn, info, verbose, spam, max
|
||||
};
|
||||
@@ -29,26 +33,16 @@ constexpr unsigned areas_count =
|
||||
class logger
|
||||
{
|
||||
public:
|
||||
/// Size of the log ring buffer
|
||||
static constexpr unsigned log_pages = 16;
|
||||
|
||||
/// Default constructor. Creates a logger without a backing store.
|
||||
logger();
|
||||
|
||||
/// Constructor. Logs are written to the given buffer.
|
||||
/// \arg buffer Buffer to which logs are written
|
||||
/// \arg size Size of `buffer`, in bytes
|
||||
logger(uint8_t *buffer, size_t size);
|
||||
logger(util::buffer buffer);
|
||||
|
||||
/// Get the default logger.
|
||||
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
|
||||
/// \arg severity The severity of the message
|
||||
/// \arg area The log area to write to
|
||||
@@ -100,7 +94,7 @@ private:
|
||||
return m_levels[static_cast<unsigned>(area)];
|
||||
}
|
||||
|
||||
obj::event m_event;
|
||||
wait_queue m_waiting;
|
||||
|
||||
level m_levels[areas_count];
|
||||
|
||||
@@ -108,8 +102,6 @@ private:
|
||||
util::spinlock m_lock;
|
||||
|
||||
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, ...);
|
||||
@@ -119,8 +111,6 @@ void warn (logs area, const char *fmt, ...);
|
||||
void error (logs area, const char *fmt, ...);
|
||||
void fatal (logs area, const char *fmt, ...);
|
||||
|
||||
extern log::logger &g_logger;
|
||||
|
||||
} // 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;
|
||||
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;
|
||||
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);
|
||||
|
||||
|
||||
// Initialize the frame allocator
|
||||
frame_block *blocks = reinterpret_cast<frame_block*>(mem::bitmap_offset);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// Initialize the kernel "process" and vm_space
|
||||
obj::process *kp = obj::process::create_kernel_process(kpml4);
|
||||
vm_space &vm = kp->space();
|
||||
|
||||
// Create the heap space and heap allocator
|
||||
obj::vm_area *heap = new (&g_kernel_heap_area)
|
||||
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};
|
||||
|
||||
// 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_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);
|
||||
}
|
||||
|
||||
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) :
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -126,6 +126,10 @@ public:
|
||||
|
||||
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:
|
||||
page_tree *m_mapped;
|
||||
};
|
||||
@@ -178,4 +182,25 @@ private:
|
||||
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
|
||||
|
||||
@@ -11,6 +11,14 @@ wait_queue::add_thread(obj::thread *t)
|
||||
m_threads.push_back(t);
|
||||
}
|
||||
|
||||
void
|
||||
wait_queue::wait()
|
||||
{
|
||||
obj::thread ¤t = obj::thread::current();
|
||||
add_thread(¤t);
|
||||
current.block();
|
||||
}
|
||||
|
||||
void
|
||||
wait_queue::pop_exited()
|
||||
{
|
||||
|
||||
@@ -19,6 +19,9 @@ public:
|
||||
/// queue lock.
|
||||
void add_thread(obj::thread *t);
|
||||
|
||||
/// Block the current thread on the queue.
|
||||
void wait();
|
||||
|
||||
/// Pops the next waiting thread off the queue.
|
||||
/// Locks the queue lock.
|
||||
inline obj::thread * pop_next() {
|
||||
|
||||
@@ -70,7 +70,7 @@ struct counted<const void>
|
||||
size_t count = 0;
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ struct counted<void>
|
||||
size_t count = 0;
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user