[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:
Justin C. Miller
2023-02-07 19:12:40 -08:00
parent 118ee73ff1
commit ada660deeb
10 changed files with 91 additions and 73 deletions

View File

@@ -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();

View File

@@ -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));
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -11,6 +11,14 @@ wait_queue::add_thread(obj::thread *t)
m_threads.push_back(t);
}
void
wait_queue::wait()
{
obj::thread &current = obj::thread::current();
add_thread(&current);
current.block();
}
void
wait_queue::pop_exited()
{

View File

@@ -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() {