1/*
2 * Copyright 2016-2022 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "debug.h"
8
9#include <string.h>
10
11#include <boot/platform.h>
12#include <boot/stage2.h>
13#include <boot/stdio.h>
14#include <util/ring_buffer.h>
15
16#include "efi_platform.h"
17#include "serial.h"
18
19
20static char sBuffer[16384];
21static uint32 sBufferPosition;
22
23static ring_buffer* sDebugSyslogBuffer = NULL;
24
25
26static void
27syslog_write(const char* buffer, size_t length)
28{
29	if (sDebugSyslogBuffer != NULL) {
30		ring_buffer_write(sDebugSyslogBuffer, (const uint8*)buffer, length);
31	} else if (sBufferPosition + length < sizeof(sBuffer)) {
32		memcpy(sBuffer + sBufferPosition, buffer, length);
33		sBufferPosition += length;
34	}
35}
36
37
38static void
39dprintf_args(const char *format, va_list args)
40{
41	char buffer[512];
42	int length = vsnprintf(buffer, sizeof(buffer), format, args);
43	if (length == 0)
44		return;
45
46	if (length >= (int)sizeof(buffer))
47		length = sizeof(buffer) - 1;
48
49	syslog_write(buffer, length);
50	serial_puts(buffer, length);
51}
52
53
54extern "C" void
55dprintf(const char *format, ...)
56{
57	va_list args;
58
59	va_start(args, format);
60	dprintf_args(format, args);
61	va_end(args);
62}
63
64
65extern "C" void
66panic(const char *format, ...)
67{
68	va_list args;
69
70	platform_switch_to_text_mode();
71
72	puts("*** PANIC ***");
73
74	va_start(args, format);
75	vprintf(format, args);
76	va_end(args);
77
78	while (true)
79		kBootServices->Stall(1000000);
80}
81
82
83static void
84allocate_ring_buffer(void)
85{
86	// allocate 1 MB memory
87	void* buffer = NULL;
88	size_t size = 1024 * 1024;
89
90	if (platform_allocate_region(&buffer, size, 0, false) != B_OK)
91		return;
92
93	sDebugSyslogBuffer = create_ring_buffer_etc(buffer, size, 0);
94
95	gKernelArgs.debug_output = sDebugSyslogBuffer;
96	gKernelArgs.debug_size = sDebugSyslogBuffer->size;
97}
98
99
100void
101debug_cleanup(void)
102{
103	allocate_ring_buffer();
104
105	if (sDebugSyslogBuffer != NULL) {
106		if (gKernelArgs.keep_debug_output_buffer) {
107			// copy the output gathered so far into the ring buffer
108			ring_buffer_clear(sDebugSyslogBuffer);
109			ring_buffer_write(sDebugSyslogBuffer, (uint8*)sBuffer,
110				sBufferPosition);
111		}
112	} else {
113		gKernelArgs.keep_debug_output_buffer = false;
114	}
115
116	if (!gKernelArgs.keep_debug_output_buffer) {
117		gKernelArgs.debug_output = kernel_args_malloc(sBufferPosition);
118		if (gKernelArgs.debug_output != NULL) {
119			memcpy(gKernelArgs.debug_output, sBuffer, sBufferPosition);
120			gKernelArgs.debug_size = sBufferPosition;
121		}
122	}
123}
124
125
126char*
127platform_debug_get_log_buffer(size_t *_size)
128{
129	if (_size != NULL)
130		*_size = sizeof(sBuffer);
131
132	return sBuffer;
133}
134