Compare commits

...

11 Commits

Author SHA1 Message Date
wash bd6872d672 x86_64: thread: ensure cs and ss are initialised properly in cloned thread context 2026-06-07 13:46:16 +01:00
wash 2ca7a34a22 ds: ringbuf: fix uninitialised variables 2026-06-07 13:45:50 +01:00
wash c425d6e389 kernel: implement support for magenta_debug over serial 2026-06-06 17:51:44 +01:00
wash eb15d2ffa3 x86_64: update serial driver to support kernel debugging 2026-06-06 17:51:01 +01:00
wash 249ac7a8cf ds: add a ringbuffer data structure 2026-06-06 17:50:23 +01:00
wash 44bcc8c805 vm: remove unused variables 2026-06-06 17:49:38 +01:00
wash 4f0d3c1071 libmagenta: add new status codes 2026-06-06 17:49:13 +01:00
wash 4d30949a4d meta: add debugging library
the debug library can be used by both server (the kernel) and client
(the debugger) applications. the library implements the protocol
that is used for communication between the kernel and debugger, as
well as handling for any requests supported by the protocol.
2026-06-06 17:25:00 +01:00
wash c90ee285cc cmake: fix release build detection 2026-05-28 18:12:13 +01:00
wash 6f178f1a60 build: add real version numbering 2026-04-30 20:53:24 +01:00
wash 5e9a165578 meta: update readme 2026-04-30 20:37:21 +01:00
30 changed files with 1264 additions and 59 deletions
+30 -1
View File
@@ -16,6 +16,23 @@ set(generic_src_dirs ds init kernel libc sched util vm syscall)
set(kernel_sources "")
set(kernel_headers "")
set(version_args --arch ${CMAKE_SYSTEM_PROCESSOR})
if (CMAKE_BUILD_TYPE)
if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(version_args ${version_args} "--release")
endif ()
endif()
execute_process(
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tools/magenta.buildid
${version_args}
OUTPUT_VARIABLE kernel_version
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "Magenta kernel version: ${kernel_version}")
foreach (dir ${generic_src_dirs})
file(GLOB_RECURSE dir_sources ${dir}/*.c)
file(GLOB_RECURSE dir_headers ${dir}/*.h)
@@ -52,7 +69,19 @@ add_custom_command(
COMMAND ${CMAKE_STRIP} -g $<TARGET_FILE:${kernel_exe_name}>)
target_link_libraries(${kernel_exe_name} -nostdlib -ffreestanding -lgcc)
target_compile_definitions(${kernel_exe_name} PRIVATE BUILD_ID="0")
target_compile_definitions(${kernel_exe_name} PRIVATE
KERNEL_NAME="${kernel_name}"
KERNEL_VERSION="${kernel_version}"
KERNEL_ARCH="${kernel_arch}")
include(arch/${kernel_arch}/config.cmake)
include(arch/${kernel_arch}/targets.cmake)
add_subdirectory(debug)
target_link_libraries(${kernel_exe_name} magenta_debug)
target_compile_definitions(magenta_debug PRIVATE KERNEL_VERSION="${kernel_version}")
target_include_directories(magenta_debug PRIVATE
include
libc/include
libmagenta/include
arch/${kernel_arch}/include)
+1 -1
View File
@@ -1,4 +1,4 @@
Magenta
=====
=======
It's a kernel!
+13
View File
@@ -0,0 +1,13 @@
#include <arch/serial.h>
#include <kernel/machine/debug.h>
#include <magenta/status.h>
kern_status_t debug_read(void *buf, size_t max, size_t *nr_read)
{
return serial_read(COM1, buf, max, nr_read);
}
kern_status_t debug_write(const void *buf, size_t max, size_t *nr_written)
{
return serial_write(COM1, buf, max, nr_written);
}
+23 -5
View File
@@ -1,14 +1,21 @@
#ifndef ARCH_SERIAL_H_
#define ARCH_SERIAL_H_
#include <magenta/types.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SERIAL_PORT_A 0x3F8
#define SERIAL_PORT_B 0x2F8
#define SERIAL_PORT_C 0x3E8
#define SERIAL_PORT_D 0x2E8
#define COM(x) (x)
#define COM1 COM(1)
#define COM2 COM(2)
#define COM3 COM(3)
#define COM4 COM(4)
extern void serial_init(int baud);
extern void serial_putchar(int port, char ch);
@@ -18,7 +25,18 @@ extern char serial_recv_byte(int device);
extern int serial_rcvd(int device);
extern void early_serialcon_init(int baud);
extern kern_status_t serial_read(
int device,
void *buf,
size_t max,
size_t *nr_read);
extern kern_status_t serial_write(
int device,
const void *buf,
size_t count,
size_t *nr_written);
extern void early_serialcon_init(void);
#ifdef __cplusplus
}
@@ -0,0 +1,10 @@
#ifndef KERNEL_X86_64_DEBUG_H_
#define KERNEL_X86_64_DEBUG_H_
#include <magenta/types.h>
#include <stddef.h>
extern kern_status_t debug_read(void *buf, size_t max, size_t *nr_read);
extern kern_status_t debug_write(const void *buf, size_t max, size_t *nr_read);
#endif
+11 -4
View File
@@ -7,6 +7,7 @@
#include <kernel/clock.h>
#include <kernel/console.h>
#include <kernel/cpu.h>
#include <kernel/debug.h>
#include <kernel/init.h>
#include <kernel/libc/stdio.h>
#include <kernel/machine/cpu.h>
@@ -19,6 +20,7 @@
#include <kernel/types.h>
#include <kernel/util.h>
#include <kernel/vm.h>
#include <magenta/debug/packet.h>
#define HARDWARE_RNG
@@ -69,7 +71,8 @@ static void early_vm_init(uintptr_t reserve_end)
void early_console_init(void)
{
const char *dest = arg_value("kernel.early-console");
if (!dest) {
bool debug = arg_is_set("kernel.enable-debugger");
if (!dest || debug) {
dest = "tty0";
}
@@ -78,7 +81,7 @@ void early_console_init(void)
vgacon_init();
} else if (!strcmp(dest, "ttyS0")) {
/* write log messages to serial port */
early_serialcon_init(115200);
early_serialcon_init();
}
}
@@ -92,8 +95,6 @@ static void find_bsp(multiboot_info_t *mb, struct boot_module *out)
{
memset(out, 0x0, sizeof *out);
printk("modules=%u: %llx", mb->mods_count, mb->mods_addr);
multiboot_module_t *mods = PTR32(mb->mods_addr);
size_t nr_mods = mb->mods_count;
@@ -111,6 +112,7 @@ int ml_init(uintptr_t arg)
parse_cmdline(PTR32(mb->cmdline));
serial_init(115200);
early_console_init();
bootstrap_cpu_init();
@@ -187,5 +189,10 @@ int ml_init(uintptr_t arg)
pit_start(500);
ml_int_enable();
if (arg_is_set("kernel.enable-debugger")) {
debug_await();
debug_create_task();
}
return 0;
}
+145 -42
View File
@@ -3,50 +3,78 @@
#include <arch/serial.h>
#include <kernel/libc/stdio.h>
#include <kernel/printk.h>
#include <kernel/ringbuf.h>
#define COM1 0x3F8
#define COM2 0x2F8
#define COM3 0x3E8
#define COM4 0x2E8
#define SERIAL_BUFFER_SIZE 1024
static int transmit_empty(int device)
RINGBUF_DECLARE(com1_queue, SERIAL_BUFFER_SIZE);
RINGBUF_DECLARE(com2_queue, SERIAL_BUFFER_SIZE);
RINGBUF_DECLARE(com3_queue, SERIAL_BUFFER_SIZE);
RINGBUF_DECLARE(com4_queue, SERIAL_BUFFER_SIZE);
static const uint16_t port_addresses[] = {
[COM1] = 0x3F8,
[COM2] = 0x2F8,
[COM3] = 0x3E8,
[COM4] = 0x2E8,
};
static int port_active[] = {
[COM1] = 0,
[COM2] = 0,
[COM3] = 0,
[COM4] = 0,
};
static struct ringbuf *port_buffer[] = {
[COM1] = &com1_queue,
[COM2] = &com2_queue,
[COM3] = &com3_queue,
[COM4] = &com4_queue,
};
static int transmit_empty(int port)
{
return inportb(device + 5) & 0x20;
return inportb(port_addresses[port] + 5) & 0x20;
}
static int serial_received(int device)
static int serial_received(int port)
{
return inportb(device + 5) & 0x1;
return inportb(port_addresses[port] + 5) & 0x1;
}
void serial_send_byte(int device, char out)
void serial_send_byte(int port, char out)
{
uint16_t address = port_addresses[port];
volatile unsigned int _count = 0;
while (!transmit_empty(device)) {
while (!transmit_empty(port)) {
_count++;
}
(void)_count;
outportb(device, out);
outportb(address, out);
if (device == COM1) {
if (port == COM1) {
outportb(0xe9, out);
}
while (!transmit_empty(device)) {
while (!transmit_empty(port)) {
_count++;
}
}
char serial_recv_byte(int device)
char serial_recv_byte(int port)
{
uint16_t address = port_addresses[port];
volatile unsigned int _count = 0;
while (!serial_received(device)) {
while (!serial_received(port)) {
_count++;
}
(void)_count;
char c = inportb(device);
char c = inportb(address);
outportb(device + 5, inportb(device + 5) & ~0x1);
outportb(address + 5, inportb(address + 5) & ~0x1);
return c;
}
@@ -100,37 +128,75 @@ static int get_baud_divisor(int baud)
static void init_serial_port(int port, int baud)
{
uint16_t address = port_addresses[port];
int baud_div = get_baud_divisor(baud);
outportb(port + 1, 0x00); // Disable all interrupts
outportb(port + 3, 0x80); // Enable DLAB (set baud rate divisor)
outportb(port + 0, baud_div); // Set divisor
outportb(port + 1, 0x00);
outportb(port + 3, 0x03); // 8 bits, no parity, one stop bit
outportb(address + 1, 0x00); // Disable all interrupts
outportb(address + 3, 0x80); // Enable DLAB (set baud rate divisor)
outportb(address + 0, baud_div); // Set divisor
outportb(address + 1, 0x00);
outportb(address + 3, 0x03); // 8 bits, no parity, one stop bit
outportb(
port + 2,
address + 2,
0xC7); // Enable FIFO, clear them, with 14-byte threshold
outportb(port + 4, 0x0B); // IRQs enabled, RTS/DSR set
outportb(address + 4, 0x0B); // IRQs enabled, RTS/DSR set
outportb(
port + 4,
address + 4,
0x1E); // Set in loopback mode, test the serial chip
outportb(port + 0, 0xAE); // Test serial chip (send byte 0xAE and
// check if serial returns same byte)
outportb(address + 0, 0xAE); // Test serial chip (send byte 0xAE and
// check if serial returns same byte)
volatile unsigned int q = 0;
while (!serial_received(port)) {
q++;
}
(void)q;
// Check if serial is faulty (i.e: not same byte as sent)
if (inportb(port + 0) != 0xAE) {
if (inportb(address + 0) != 0xAE) {
printk("serial: COM%d is faulty", port);
return;
}
// If serial is not faulty set it in normal operation mode
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
outportb(port + 1, 0x01);
outportb(port + 4, 0x0F);
printk("serial: port %x initialised", port);
outportb(address + 1, 0x01);
outportb(address + 4, 0x0F);
port_active[port] = 1;
printk("serial: COM%d initialised", port);
}
kern_status_t serial_read(int device, void *buf, size_t max, size_t *nr_read)
{
struct ringbuf *src = port_buffer[device];
unsigned long flags;
ringbuf_lock(src, &flags);
kern_status_t status = ringbuf_read(src, buf, max, nr_read, &flags);
ringbuf_unlock(src, flags);
return status;
}
kern_status_t serial_write(
int device,
const void *buf,
size_t count,
size_t *nr_written)
{
if (!port_active[device]) {
return KERN_BAD_STATE;
}
const unsigned char *p = buf;
size_t w = 0;
for (size_t i = 0; i < count; i++) {
serial_send_byte(device, p[i]);
w++;
}
*nr_written = w;
return KERN_OK;
}
static struct console serialcon = {
@@ -140,30 +206,67 @@ static struct console serialcon = {
.c_lock = SPIN_LOCK_INIT,
};
static int serial_irq1(void)
static int serial_irq_com1_com3(void)
{
#if 0
if (serial_received(COM1)) {
unsigned long flags;
if (port_active[COM1] && serial_received(COM1)) {
unsigned char c = serial_recv_byte(COM1);
printk("serial: COM1 received %c", c);
ringbuf_lock(&com1_queue, &flags);
ringbuf_write(&com1_queue, &c, 1, NULL, &flags);
ringbuf_unlock(&com1_queue, flags);
}
if (serial_received(COM3)) {
if (port_active[COM3] && serial_received(COM3)) {
unsigned char c = serial_recv_byte(COM3);
printk("serial: COM3 received %c", c);
ringbuf_lock(&com3_queue, &flags);
ringbuf_write(&com3_queue, &c, 1, NULL, &flags);
ringbuf_unlock(&com3_queue, flags);
}
#endif
return 0;
}
static struct irq_hook irq1_hook = {
.irq_callback = serial_irq1,
static int serial_irq_com2_com4(void)
{
unsigned long flags;
if (port_active[COM2] && serial_received(COM2)) {
unsigned char c = serial_recv_byte(COM2);
ringbuf_lock(&com2_queue, &flags);
ringbuf_write(&com2_queue, &c, 1, NULL, &flags);
ringbuf_unlock(&com2_queue, flags);
}
if (port_active[COM4] && serial_received(COM4)) {
unsigned char c = serial_recv_byte(COM4);
ringbuf_lock(&com4_queue, &flags);
ringbuf_write(&com4_queue, &c, 1, NULL, &flags);
ringbuf_unlock(&com4_queue, flags);
}
return 0;
}
static struct irq_hook irq_hook_com1_com3 = {
.irq_callback = serial_irq_com1_com3,
};
void early_serialcon_init(int baud)
static struct irq_hook irq_hook_com2_com4 = {
.irq_callback = serial_irq_com2_com4,
};
void serial_init(int baud)
{
hook_irq(IRQ4, &irq1_hook);
hook_irq(IRQ4, &irq_hook_com1_com3);
hook_irq(IRQ3, &irq_hook_com2_com4);
init_serial_port(COM1, baud);
init_serial_port(COM2, baud);
init_serial_port(COM3, baud);
init_serial_port(COM4, baud);
}
void early_serialcon_init(void)
{
console_register(&serialcon);
}
+2
View File
@@ -93,6 +93,8 @@ kern_status_t ml_thread_clone_user_context(
memcpy(regs, src_regs, sizeof *regs);
regs->rax = return_value;
regs->ss = 0x1b;
regs->cs = 0x23;
dest_ml->tr_fsbase = src_ml->tr_fsbase;
dest_ml->tr_gsbase = src_ml->tr_gsbase;
+4
View File
@@ -0,0 +1,4 @@
file(GLOB sources *.c *.h include/magenta/debug/*.h)
add_library(magenta_debug STATIC ${sources})
target_include_directories(magenta_debug PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+29
View File
@@ -0,0 +1,29 @@
#include <magenta/debug/event.h>
const char *mxdbg_event_type_get_description(enum mxdbg_event_type type)
{
switch (type) {
case MXDBG_EVENT_TASK_CREATED:
return "task-create";
case MXDBG_EVENT_TASK_STARTED:
return "task-start";
case MXDBG_EVENT_TASK_STOPPED:
return "task-stop";
case MXDBG_EVENT_TASK_DESTROYED:
return "task-destroy";
case MXDBG_EVENT_THREAD_CREATED:
return "thread-create";
case MXDBG_EVENT_THREAD_STARTED:
return "thread-start";
case MXDBG_EVENT_THREAD_STOPPED:
return "thread-stop";
case MXDBG_EVENT_THREAD_DESTROYED:
return "thread-destroy";
case MXDBG_EVENT_THREAD_FAULT:
return "thread-fault";
case MXDBG_EVENT_PANIC:
return "panic";
default:
return "<unknown>";
}
}
+110
View File
@@ -0,0 +1,110 @@
#include "magenta/debug/util.h"
#include <magenta/debug/host.h>
#include <magenta/debug/packet.h>
#include <magenta/debug/request.h>
enum mxdbg_status mxdbg_host_handle_request(struct mxdbg_host *host)
{
struct mxdbg_packet packet = {0};
enum mxdbg_status status = mxdbg_host_recv(host, &packet);
if (status != MXDBG_SUCCESS) {
debug_printf("debug: failed to read packet");
return status;
}
if (packet.pkt_magic != MXDBG_PACKET_MAGIC) {
debug_printf(
"debug: packet is malformed (magic=%08x)",
packet.pkt_magic);
return MXDBG_ERR_BAD_FORMAT;
}
return mxdbg_handle_request(host, &packet);
}
enum mxdbg_status mxdbg_host_recv(
struct mxdbg_host *host,
struct mxdbg_packet *packet)
{
size_t r;
if (host->read_remote) {
return host->read_remote(host, packet, sizeof *packet, &r);
}
return MXDBG_ERR_NOT_SUPPORTED;
}
enum mxdbg_status mxdbg_host_recv_packet_data(
struct mxdbg_host *host,
struct mxdbg_packet *packet)
{
if (packet->pkt_magic != MXDBG_PACKET_MAGIC) {
return MXDBG_ERR_INVALID_ARGUMENT;
}
if (!packet->pkt_length) {
return MXDBG_SUCCESS;
}
size_t r;
void *dest = packet + 1;
if (host->read_remote) {
return host->read_remote(
host,
dest,
packet->pkt_length - sizeof *packet,
&r);
}
return MXDBG_ERR_NOT_SUPPORTED;
}
enum mxdbg_status mxdbg_host_send(
struct mxdbg_host *host,
const struct mxdbg_packet *packet)
{
size_t w;
if (host->write_remote) {
return host->write_remote(host, packet, packet->pkt_length, &w);
}
return MXDBG_ERR_NOT_SUPPORTED;
}
enum mxdbg_status mxdbg_host_identify(
struct mxdbg_host *host,
enum mxdbg_identity_key key,
void *out,
size_t max)
{
if (host->identify) {
return host->identify(host, key, out, max);
}
return MXDBG_ERR_NOT_SUPPORTED;
}
enum mxdbg_status mxdbg_host_identify_task(
struct mxdbg_host *host,
unsigned int tid,
enum mxdbg_identity_key key,
void *out,
size_t max)
{
if (host->identify_task) {
return host->identify_task(host, tid, key, out, max);
}
return MXDBG_ERR_NOT_SUPPORTED;
}
enum mxdbg_status mxdbg_host_resume(struct mxdbg_host *host)
{
if (host->resume) {
return host->resume(host);
}
return MXDBG_ERR_NOT_SUPPORTED;
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef MAGENTA_DEBUG_EVENT_H_
#define MAGENTA_DEBUG_EVENT_H_
enum mxdbg_event_type {
MXDBG_EVENT_NONE = 0,
MXDBG_EVENT_TASK_CREATED,
MXDBG_EVENT_TASK_STARTED,
MXDBG_EVENT_TASK_STOPPED,
MXDBG_EVENT_TASK_DESTROYED,
MXDBG_EVENT_THREAD_CREATED,
MXDBG_EVENT_THREAD_STARTED,
MXDBG_EVENT_THREAD_STOPPED,
MXDBG_EVENT_THREAD_DESTROYED,
MXDBG_EVENT_THREAD_FAULT,
MXDBG_EVENT_PANIC,
};
extern const char *mxdbg_event_type_get_description(enum mxdbg_event_type type);
#endif
+61
View File
@@ -0,0 +1,61 @@
#ifndef MAGENTA_DEBUG_HOST_H_
#define MAGENTA_DEBUG_HOST_H_
#include <magenta/debug/identity.h>
#include <magenta/debug/status.h>
#include <stddef.h>
#include <stdint.h>
struct mxdbg_packet;
struct mxdbg_packet_event;
struct mxdbg_host {
enum mxdbg_status (
*read_remote)(struct mxdbg_host *, void *, size_t, size_t *);
enum mxdbg_status (*write_remote)(
struct mxdbg_host *,
const void *,
size_t,
size_t *);
enum mxdbg_status (*identify)(
struct mxdbg_host *,
enum mxdbg_identity_key,
void *,
size_t);
enum mxdbg_status (*identify_task)(
struct mxdbg_host *,
unsigned int,
enum mxdbg_identity_key,
void *,
size_t);
enum mxdbg_status (*resume)(struct mxdbg_host *);
};
extern enum mxdbg_status mxdbg_host_handle_request(struct mxdbg_host *host);
extern enum mxdbg_status mxdbg_host_recv(
struct mxdbg_host *host,
struct mxdbg_packet *packet);
extern enum mxdbg_status mxdbg_host_recv_packet_data(
struct mxdbg_host *host,
struct mxdbg_packet *packet);
extern enum mxdbg_status mxdbg_host_send(
struct mxdbg_host *host,
const struct mxdbg_packet *packet);
extern enum mxdbg_status mxdbg_host_identify(
struct mxdbg_host *host,
enum mxdbg_identity_key key,
void *out,
size_t max);
extern enum mxdbg_status mxdbg_host_identify_task(
struct mxdbg_host *host,
unsigned int task,
enum mxdbg_identity_key key,
void *out,
size_t max);
extern enum mxdbg_status mxdbg_host_resume(struct mxdbg_host *host);
extern enum mxdbg_status mxdbg_host_send_event(
struct mxdbg_host *host,
struct mxdbg_packet_event *ev);
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef MAGENTA_DEBUG_IDENTITY_H_
#define MAGENTA_DEBUG_IDENTITY_H_
enum mxdbg_identity_key {
MXDBG_IDENTITY_NONE = 0,
MXDBG_IDENTITY_KERNEL_NAME,
MXDBG_IDENTITY_KERNEL_VERSION,
MXDBG_IDENTITY_KERNEL_ARCH,
/* identify_task keys */
MXDBG_IDENTITY_TASK_NAME,
MXDBG_IDENTITY_TASK_PARENT,
MXDBG_IDENTITY_TASK_NR_THREADS,
};
#endif
+66
View File
@@ -0,0 +1,66 @@
#ifndef MAGENTA_DEBUG_PACKET_H_
#define MAGENTA_DEBUG_PACKET_H_
#include <magenta/debug/event.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define MXDBG_PACKET_MAGIC 0xdecafbaf
enum mxdbg_packet_type {
MXDBG_PACKET_NONE = 0,
MXDBG_PACKET_IDENTIFY_KERNEL,
MXDBG_PACKET_IDENTIFY_TASK,
MXDBG_PACKET_LIST_TASK,
MXDBG_PACKET_RESUME,
MXDBG_PACKET_STOP,
MXDBG_PACKET_EVENT,
};
enum mxdbg_packet_flags {
MXDBG_PACKET_F_NONE = 0,
MXDBG_PACKET_F_RESPONSE = 0x01u,
};
struct mxdbg_packet {
uint32_t pkt_magic;
uint16_t pkt_length;
uint8_t pkt_type;
uint8_t pkt_flags;
};
struct mxdbg_packet_identify_kernel {
struct mxdbg_packet id_base;
char id_kernel_name[32];
char id_kernel_version[32];
char id_kernel_arch[16];
};
struct mxdbg_packet_list_task {
struct mxdbg_packet l_base;
uint16_t l_task_count;
};
struct mxdbg_packet_identify_task {
struct mxdbg_packet id_base;
uint16_t id_task, id_parent;
uint16_t id_thread_count;
char id_task_name[64];
};
struct mxdbg_packet_event {
struct mxdbg_packet ev_base;
uint16_t ev_type;
uint16_t ev_task, ev_thread;
uint32_t ev_code;
};
extern void mxdbg_packet_init(
struct mxdbg_packet *packet,
size_t size,
enum mxdbg_packet_type type,
enum mxdbg_packet_flags flags);
extern bool mxdbg_packet_validate(const struct mxdbg_packet *packet);
#endif
+11
View File
@@ -0,0 +1,11 @@
#ifndef MAGENTA_DEBUG_REQUEST_H_
#define MAGENTA_DEBUG_REQUEST_H_
struct mxdbg_host;
struct mxdbg_packet;
extern enum mxdbg_status mxdbg_handle_request(
struct mxdbg_host *host,
const struct mxdbg_packet *req);
#endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef MAGENTA_DEBUG_STATUS_H_
#define MAGENTA_DEBUG_STATUS_H_
enum mxdbg_status {
MXDBG_SUCCESS = 0,
MXDBG_ERR_INVALID_ARGUMENT,
MXDBG_ERR_NOT_SUPPORTED,
MXDBG_ERR_BAD_FORMAT,
MXDBG_ERR_IO_FAILURE,
};
#endif
+14
View File
@@ -0,0 +1,14 @@
#ifndef MAGENTA_DEBUG_UTIL_H_
#define MAGENTA_DEBUG_UTIL_H_
#if defined(KERNEL_VERSION)
#include <kernel/libc/string.h>
#include <kernel/printk.h>
#define debug_printf(...) printk(__VA_ARGS__)
#else
#include <stdio.h>
#include <string.h>
#define debug_printf(...) printf(__VA_ARGS__)
#endif
#endif
+20
View File
@@ -0,0 +1,20 @@
#include <magenta/debug/packet.h>
#include <magenta/debug/util.h>
void mxdbg_packet_init(
struct mxdbg_packet *packet,
size_t size,
enum mxdbg_packet_type type,
enum mxdbg_packet_flags flags)
{
memset(packet, 0x0, sizeof *packet);
packet->pkt_magic = MXDBG_PACKET_MAGIC;
packet->pkt_length = size;
packet->pkt_type = type;
packet->pkt_flags = flags;
}
bool mxdbg_packet_validate(const struct mxdbg_packet *packet)
{
return packet->pkt_magic == MXDBG_PACKET_MAGIC;
}
+106
View File
@@ -0,0 +1,106 @@
#include <magenta/debug/host.h>
#include <magenta/debug/packet.h>
#include <magenta/debug/util.h>
static enum mxdbg_status identify_kernel(
struct mxdbg_host *host,
const struct mxdbg_packet *req)
{
struct mxdbg_packet_identify_kernel id = {0};
mxdbg_packet_init(
&id.id_base,
sizeof id,
MXDBG_PACKET_IDENTIFY_KERNEL,
MXDBG_PACKET_F_RESPONSE);
mxdbg_host_identify(
host,
MXDBG_IDENTITY_KERNEL_NAME,
id.id_kernel_name,
sizeof id.id_kernel_name);
mxdbg_host_identify(
host,
MXDBG_IDENTITY_KERNEL_VERSION,
id.id_kernel_version,
sizeof id.id_kernel_version);
mxdbg_host_identify(
host,
MXDBG_IDENTITY_KERNEL_ARCH,
id.id_kernel_arch,
sizeof id.id_kernel_arch);
mxdbg_host_send(host, &id.id_base);
return MXDBG_SUCCESS;
}
static enum mxdbg_status identify_task(
struct mxdbg_host *host,
const struct mxdbg_packet *packet)
{
struct mxdbg_packet_identify_task *req
= (struct mxdbg_packet_identify_task *)packet;
struct mxdbg_packet_identify_task id = {0};
id.id_base = *packet;
mxdbg_host_recv_packet_data(host, &id.id_base);
unsigned int tid = id.id_task;
mxdbg_packet_init(
&id.id_base,
sizeof id,
MXDBG_PACKET_IDENTIFY_TASK,
MXDBG_PACKET_F_RESPONSE);
mxdbg_host_identify_task(
host,
tid,
MXDBG_IDENTITY_TASK_NAME,
id.id_task_name,
sizeof id.id_task_name);
mxdbg_host_identify_task(
host,
tid,
MXDBG_IDENTITY_TASK_PARENT,
&id.id_parent,
sizeof id.id_parent);
mxdbg_host_identify_task(
host,
tid,
MXDBG_IDENTITY_TASK_NR_THREADS,
&id.id_thread_count,
sizeof id.id_thread_count);
size_t w;
mxdbg_host_send(host, &id.id_base);
debug_printf("debug: identify_task response sent");
return MXDBG_SUCCESS;
}
static enum mxdbg_status resume(
struct mxdbg_host *host,
const struct mxdbg_packet *req)
{
return mxdbg_host_resume(host);
}
enum mxdbg_status mxdbg_handle_request(
struct mxdbg_host *host,
const struct mxdbg_packet *req)
{
switch (req->pkt_type) {
case MXDBG_PACKET_IDENTIFY_KERNEL:
return identify_kernel(host, req);
case MXDBG_PACKET_IDENTIFY_TASK:
return identify_task(host, req);
case MXDBG_PACKET_RESUME:
return resume(host, req);
default:
debug_printf(
"debug: unrecognised packet 0x%02x",
req->pkt_type);
return MXDBG_ERR_NOT_SUPPORTED;
}
return MXDBG_SUCCESS;
}
+323
View File
@@ -0,0 +1,323 @@
#include <kernel/ringbuf.h>
#include <kernel/sched.h>
#include <kernel/thread.h>
#include <kernel/wait.h>
#include <magenta/status.h>
#define BUF_LOCKED(buf) \
(((buf)->buf_flags & (RINGBUF_READ_LOCKED | RINGBUF_WRITE_LOCKED)) != 0)
enum ringbuf_flags {
RINGBUF_READ_LOCKED = 0x01u,
RINGBUF_WRITE_LOCKED = 0x02u,
};
kern_status_t ringbuf_lock(struct ringbuf *buf, unsigned long *flags)
{
spin_lock_irqsave(&buf->buf_lock, flags);
return KERN_OK;
}
kern_status_t ringbuf_unlock(struct ringbuf *buf, unsigned long flags)
{
spin_unlock_irqrestore(&buf->buf_lock, flags);
return KERN_OK;
}
static kern_status_t ringbuf_clear(struct ringbuf *buf)
{
buf->buf_read = buf->buf_write = 0;
return KERN_OK;
}
static size_t ringbuf_write_capacity_remaining(const struct ringbuf *buf)
{
if (buf->buf_read > buf->buf_write) {
return buf->buf_read - buf->buf_write - 1;
} else {
return buf->buf_capacity - buf->buf_write + buf->buf_read - 1;
}
}
static size_t ringbuf_available_data_remaining(const struct ringbuf *buf)
{
if (buf->buf_read < buf->buf_write) {
return buf->buf_write - buf->buf_read;
} else if (buf->buf_read > buf->buf_write) {
return buf->buf_capacity - buf->buf_read + buf->buf_write;
} else {
return 0;
}
}
static kern_status_t ringbuf_open_read_buffer(
struct ringbuf *buf,
const void **ptr,
size_t *length)
{
if (BUF_LOCKED(buf)) {
return KERN_BUSY;
}
size_t contiguous_capacity = 0;
if (buf->buf_read > buf->buf_write) {
contiguous_capacity = buf->buf_capacity - buf->buf_read;
} else {
contiguous_capacity = buf->buf_write - buf->buf_read;
}
if (contiguous_capacity == 0) {
return KERN_NO_DATA;
}
buf->buf_opened_ptr = (unsigned char *)buf->buf_ptr + buf->buf_read;
buf->buf_opened_capacity = contiguous_capacity;
buf->buf_flags |= RINGBUF_READ_LOCKED;
*ptr = buf->buf_opened_ptr;
*length = contiguous_capacity;
return KERN_OK;
}
static kern_status_t ringbuf_close_read_buffer(
struct ringbuf *buf,
const void **ptr,
size_t nbuf_read)
{
if (!(buf->buf_flags & RINGBUF_READ_LOCKED)) {
return KERN_BAD_STATE;
}
if (*ptr != buf->buf_opened_ptr) {
return KERN_INVALID_ARGUMENT;
}
if (nbuf_read > buf->buf_opened_capacity) {
return KERN_INVALID_ARGUMENT;
}
buf->buf_read += nbuf_read;
if (buf->buf_read >= buf->buf_capacity) {
buf->buf_read = 0;
}
if (buf->buf_read == buf->buf_write) {
/* the ringbuf is now empty. set both pointers to 0.
* this ensures that the whole buffer will be available
* contiguously to the next call to open_write_buffer */
buf->buf_read = 0;
buf->buf_write = 0;
}
buf->buf_opened_ptr = NULL;
buf->buf_opened_capacity = 0;
buf->buf_flags &= ~RINGBUF_READ_LOCKED;
return KERN_OK;
}
static kern_status_t ringbuf_open_write_buffer(
struct ringbuf *buf,
void **ptr,
size_t *capacity)
{
if (BUF_LOCKED(buf)) {
return KERN_BUSY;
}
size_t contiguous_capacity = 0;
if (buf->buf_write >= buf->buf_read) {
contiguous_capacity = buf->buf_capacity - buf->buf_write - 1;
if (buf->buf_read > 0) {
contiguous_capacity++;
}
} else {
contiguous_capacity = buf->buf_read - buf->buf_write - 1;
}
if (contiguous_capacity == 0) {
return KERN_NO_SPACE;
}
buf->buf_opened_ptr = (unsigned char *)buf->buf_ptr + buf->buf_write;
buf->buf_opened_capacity = contiguous_capacity;
buf->buf_flags |= RINGBUF_WRITE_LOCKED;
*ptr = buf->buf_opened_ptr;
*capacity = contiguous_capacity;
return KERN_OK;
}
static kern_status_t ringbuf_close_write_buffer(
struct ringbuf *buf,
void **ptr,
size_t nbuf_written)
{
if (!(buf->buf_flags & RINGBUF_WRITE_LOCKED)) {
return KERN_BAD_STATE;
}
if (*ptr != buf->buf_opened_ptr) {
return KERN_INVALID_ARGUMENT;
}
if (nbuf_written > buf->buf_opened_capacity) {
return KERN_INVALID_ARGUMENT;
}
buf->buf_write += nbuf_written;
if (buf->buf_write >= buf->buf_capacity) {
buf->buf_write = 0;
}
buf->buf_opened_ptr = NULL;
buf->buf_opened_capacity = 0;
buf->buf_flags &= ~RINGBUF_WRITE_LOCKED;
return KERN_OK;
}
static void wait_for_data(struct ringbuf *buf, unsigned long *flags)
{
struct thread *self = get_current_thread();
struct wait_item waiter;
wait_item_init(&waiter, self);
for (;;) {
thread_wait_begin(&waiter, &buf->buf_read_queue);
if (ringbuf_available_data_remaining(buf) > 0) {
break;
}
ringbuf_unlock(buf, *flags);
schedule(SCHED_NORMAL);
ringbuf_lock(buf, flags);
}
thread_wait_end(&waiter, &buf->buf_read_queue);
put_current_thread(self);
}
static void wait_for_capacity(struct ringbuf *buf, unsigned long *flags)
{
struct thread *self = get_current_thread();
struct wait_item waiter;
wait_item_init(&waiter, self);
for (;;) {
thread_wait_begin(&waiter, &buf->buf_write_queue);
if (ringbuf_write_capacity_remaining(buf) > 0) {
break;
}
ringbuf_unlock(buf, *flags);
schedule(SCHED_NORMAL);
ringbuf_lock(buf, flags);
}
thread_wait_end(&waiter, &buf->buf_write_queue);
put_current_thread(self);
}
kern_status_t ringbuf_read(
struct ringbuf *buf,
void *p,
size_t count,
size_t *nbuf_read,
unsigned long *irq_flags)
{
if (BUF_LOCKED(buf)) {
return KERN_BUSY;
}
size_t r = 0;
unsigned char *dest = p;
size_t remaining = count;
kern_status_t status = KERN_OK;
while (remaining > 0) {
const void *src;
size_t available;
wait_for_data(buf, irq_flags);
status = ringbuf_open_read_buffer(buf, &src, &available);
if (status != KERN_OK) {
break;
}
size_t to_copy = remaining;
if (to_copy > available) {
to_copy = available;
}
memcpy(dest, src, to_copy);
remaining -= to_copy;
dest += to_copy;
r += to_copy;
ringbuf_close_read_buffer(buf, &src, to_copy);
}
wakeup_queue(&buf->buf_write_queue);
if (nbuf_read) {
*nbuf_read = r;
}
if (status == KERN_NO_DATA && r > 0) {
status = KERN_OK;
}
return KERN_OK;
}
kern_status_t ringbuf_write(
struct ringbuf *buf,
const void *p,
size_t count,
size_t *nbuf_written,
unsigned long *irq_flags)
{
if (BUF_LOCKED(buf)) {
return KERN_BUSY;
}
size_t w = 0;
const unsigned char *src = p;
size_t remaining = count;
kern_status_t status = KERN_OK;
while (remaining > 0) {
void *dest = NULL;
size_t available = 0;
wait_for_capacity(buf, irq_flags);
status = ringbuf_open_write_buffer(buf, &dest, &available);
if (status == KERN_NO_SPACE) {
break;
}
size_t to_copy = remaining;
if (to_copy > available) {
to_copy = available;
}
memcpy(dest, src, to_copy);
remaining -= to_copy;
src += to_copy;
w += to_copy;
ringbuf_close_write_buffer(buf, &dest, to_copy);
}
wakeup_queue(&buf->buf_read_queue);
if (nbuf_written) {
*nbuf_written = w;
}
if (status == KERN_NO_SPACE && w > 0) {
status = KERN_OK;
}
return status;
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef KERNEL_DEBUG_H_
#define KERNEL_DEBUG_H_
#include <magenta/status.h>
#include <magenta/types.h>
extern kern_status_t debug_await(void);
extern kern_status_t debug_create_task(void);
extern kern_status_t debug_event_task_created(tid_t id);
extern kern_status_t debug_event_task_started(void);
extern kern_status_t debug_event_task_stopped(void);
extern kern_status_t debug_event_task_destroyed(void);
#endif
+45
View File
@@ -0,0 +1,45 @@
#ifndef KERNEL_RINGBUF_H_
#define KERNEL_RINGBUF_H_
#include <kernel/wait.h>
#include <magenta/types.h>
struct ringbuf {
unsigned int buf_read;
unsigned int buf_write;
unsigned int buf_capacity;
unsigned int buf_flags;
unsigned char *buf_ptr;
struct waitqueue buf_read_queue;
struct waitqueue buf_write_queue;
spin_lock_t buf_lock;
unsigned char *buf_opened_ptr;
unsigned int buf_opened_capacity;
};
#define RINGBUF_DECLARE(name, size) \
static unsigned char __buf_##name[size] = {0}; \
static struct ringbuf name = { \
.buf_ptr = __buf_##name, \
.buf_capacity = size, \
}
extern kern_status_t ringbuf_lock(struct ringbuf *buf, unsigned long *flags);
extern kern_status_t ringbuf_unlock(struct ringbuf *buf, unsigned long flags);
extern kern_status_t ringbuf_read(
struct ringbuf *buf,
void *out,
size_t count,
size_t *nr_read,
unsigned long *irq_flags);
extern kern_status_t ringbuf_write(
struct ringbuf *buf,
const void *out,
size_t count,
size_t *nr_written,
unsigned long *irq_flags);
#endif
+1 -1
View File
@@ -23,7 +23,7 @@ extern char __pstart[], __pend[];
void print_kernel_banner(void)
{
printk("Magenta kernel version " BUILD_ID);
printk(KERNEL_NAME " version " KERNEL_VERSION);
}
static void hang(void)
+165
View File
@@ -0,0 +1,165 @@
#include "kernel/panic.h"
#include <kernel/debug.h>
#include <kernel/libc/stdio.h>
#include <kernel/machine/cpu.h>
#include <kernel/machine/debug.h>
#include <kernel/printk.h>
#include <kernel/sched.h>
#include <kernel/task.h>
#include <kernel/thread.h>
#include <magenta/debug/host.h>
#include <magenta/debug/packet.h>
static volatile bool initial_continue = false;
static volatile bool debug_enabled = false;
static spin_lock_t debug_io_lock = SPIN_LOCK_INIT;
static enum mxdbg_status read_remote(
struct mxdbg_host *host,
void *buf,
size_t count,
size_t *nr_read)
{
debug_read(buf, count, nr_read);
return MXDBG_SUCCESS;
}
static enum mxdbg_status write_remote(
struct mxdbg_host *host,
const void *buf,
size_t count,
size_t *nr_written)
{
spin_lock(&debug_io_lock);
debug_write(buf, count, nr_written);
spin_unlock(&debug_io_lock);
return MXDBG_SUCCESS;
}
static enum mxdbg_status identify(
struct mxdbg_host *host,
enum mxdbg_identity_key key,
void *out,
size_t max)
{
switch (key) {
case MXDBG_IDENTITY_KERNEL_NAME:
snprintf(out, max, "%s", KERNEL_NAME);
break;
case MXDBG_IDENTITY_KERNEL_VERSION:
snprintf(out, max, "%s", KERNEL_VERSION);
break;
case MXDBG_IDENTITY_KERNEL_ARCH:
snprintf(out, max, "%s", KERNEL_ARCH);
break;
default:
return MXDBG_ERR_INVALID_ARGUMENT;
}
return MXDBG_SUCCESS;
}
static enum mxdbg_status identify_task(
struct mxdbg_host *host,
tid_t tid,
enum mxdbg_identity_key key,
void *out,
size_t max)
{
struct task *task = task_from_tid(tid);
if (!task) {
return MXDBG_ERR_INVALID_ARGUMENT;
}
switch (key) {
case MXDBG_IDENTITY_TASK_NAME:
snprintf(out, max, "%s", task->t_name);
break;
case MXDBG_IDENTITY_TASK_PARENT:
*(uint16_t *)out = task->t_parent ? task->t_parent->t_id : -1;
break;
case MXDBG_IDENTITY_TASK_NR_THREADS:
*(uint16_t *)out = queue_length(&task->t_threads);
break;
default:
return MXDBG_ERR_INVALID_ARGUMENT;
}
return MXDBG_SUCCESS;
}
static enum mxdbg_status resume(struct mxdbg_host *host)
{
initial_continue = true;
return MXDBG_SUCCESS;
}
static struct mxdbg_host dbg_host = {
.read_remote = read_remote,
.write_remote = write_remote,
.identify = identify,
.identify_task = identify_task,
.resume = resume,
};
static void debugger(void)
{
ml_int_enable();
while (1) {
mxdbg_host_handle_request(&dbg_host);
}
}
kern_status_t debug_await(void)
{
debug_enabled = true;
printk("debug: waiting for connection...");
while (!initial_continue) {
mxdbg_host_handle_request(&dbg_host);
}
return KERN_OK;
}
kern_status_t debug_create_task(void)
{
struct task *kernel_task = get_current_task();
struct thread *debug_thread = task_create_thread(kernel_task);
thread_init_kernel(debug_thread, (virt_addr_t)debugger);
schedule_thread_on_cpu(debug_thread);
put_current_task(kernel_task);
return KERN_OK;
}
kern_status_t debug_event_task_created(tid_t id)
{
if (!debug_enabled) {
return KERN_OK;
}
struct mxdbg_packet_event ev = {0};
mxdbg_packet_init(&ev.ev_base, sizeof ev, MXDBG_PACKET_EVENT, 0);
ev.ev_type = MXDBG_EVENT_TASK_CREATED;
ev.ev_task = id;
size_t w;
write_remote(&dbg_host, &ev, sizeof ev, &w);
return KERN_OK;
}
kern_status_t debug_event_task_started(void)
{
return KERN_OK;
}
kern_status_t debug_event_task_stopped(void)
{
return KERN_OK;
}
kern_status_t debug_event_task_destroyed(void)
{
return KERN_OK;
}
+1 -1
View File
@@ -17,7 +17,7 @@ void panic_irq(struct ml_cpu_context *ctx, const char *fmt, ...)
va_end(args);
printk("---[ kernel panic: %s", buf);
printk("kernel: " BUILD_ID ", compiler version: " __VERSION__);
printk("kernel: " KERNEL_VERSION ", compiler version: " __VERSION__);
struct task *task = get_current_task();
struct thread *thr = get_current_thread();
+2
View File
@@ -17,5 +17,7 @@
#define KERN_BAD_STATE (13)
#define KERN_MEMORY_FAULT (14)
#define KERN_ACCESS_DENIED (15)
#define KERN_NO_DATA (16)
#define KERN_NO_SPACE (17)
#endif
+3
View File
@@ -2,6 +2,7 @@
#include <kernel/channel.h>
#include <kernel/clock.h>
#include <kernel/cpu.h>
#include <kernel/debug.h>
#include <kernel/handle.h>
#include <kernel/libc/stdio.h>
#include <kernel/locks.h>
@@ -223,6 +224,8 @@ struct task *task_create(
task_list_insert(&task_list, task);
spin_unlock_irqrestore(&task_list_lock, flags);
debug_event_task_created(task->t_id);
return task;
}
+2 -2
View File
@@ -33,7 +33,7 @@ if is_arg_set('release'):
build_type = 'release'
current_tag = subprocess.check_output(['git', 'describe', '--tags', '--abbrev=0']).decode('utf-8').strip()
current_tag = current_tag[1:]
revision = subprocess.check_output(['git', 'rev-list', '{}..HEAD'.format(current_tag), '--count']).decode('utf-8').strip()
build_id = '{}/{}_{}'.format(current_tag, build_type, arch)
build_id = '{}~{}/{}_{}'.format(current_tag[1:], revision, build_type, arch)
print('{}'.format(build_id.upper()))
-2
View File
@@ -105,11 +105,9 @@ static size_t zone_free_bytes(struct vm_zone *z)
for (enum vm_page_order i = VM_PAGE_MIN_ORDER; i <= VM_PAGE_MAX_ORDER;
i++) {
size_t page_bytes = vm_page_order_to_bytes(i);
size_t nr_pages = 0;
queue_foreach(struct vm_page, pg, &z->z_free_pages[i], p_list)
{
free_bytes += page_bytes;
nr_pages++;
}
}