summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Levy <alevy@redhat.com>2011-03-30 19:09:51 +0200
committerAlon Levy <alevy@redhat.com>2011-04-07 19:01:48 +0300
commitffd639fa3b720c8060608f620c278d54b48ae73b (patch)
treec56885cf57c73363ca283db571028e7466e19366
parentdac50beb630bb06d0c677f0f034d758397084942 (diff)
miniport: add QXL_IO_LOG
Until now logging for miniport and display went in different paths, display knew how to use the QXL_IO_LOG port to allow basically seeing the debug messages on the host with the rest of the qemu monitor output. But miniport always went through VideoPortDbg, which made it harder to pretend there is nothing like DebugView/WinDBG and use printf's to debug some stuff. The main reason for this is that snprintf is not provided by the minimal API you can use in the miniport. So to code around this this patch adds a minimal snprintf and vsnprintf implementation, and if guestdebug is not 0 then it uses that. The only missing bit is a semaphore to make sure the driver and miniport don't overwrite one another's logs, but that wasn't seen in practice.
-rw-r--r--miniport/minimal_snprintf.c150
-rw-r--r--miniport/qxl.c55
-rw-r--r--miniport/qxl.h3
-rw-r--r--miniport/sources1
4 files changed, 206 insertions, 3 deletions
diff --git a/miniport/minimal_snprintf.c b/miniport/minimal_snprintf.c
new file mode 100644
index 0000000..133b84e
--- /dev/null
+++ b/miniport/minimal_snprintf.c
@@ -0,0 +1,150 @@
+#include "minimal_snprintf.h"
+
+static char lower_digits[] = "0123456789abcdef";
+static char upper_digits[] = "0123456789abcdef";
+
+char *print_unsigned(char *str, size_t *size, long long val, int base,
+ const char *digits)
+{
+ int n = 0;
+ char *strout;
+ long long temp = val;
+
+ if (*size == 0) {
+ return str;
+ }
+ if (base < 0 || base > 16) {
+ base = 10;
+ }
+ while (temp != 0) {
+ temp /= base;
+ n++;
+ }
+ if (n > 0) {
+ n--;
+ }
+ while (n >= (int)*size) {
+ val /= base;
+ n--;
+ }
+ strout = str + n + 1;
+ while (n >= 0 && *size) {
+ (*size)--;
+ *(str + n) = digits[(val % base)];
+ val /= base;
+ n--;
+ }
+ return strout;
+}
+
+char *print_signed(char *str, size_t *size, long long val, int base,
+ const char *digits)
+{
+ if (*size == 0) {
+ return str;
+ }
+ if (val < 0) {
+ val = -val;
+ *(str++) = '-';
+ (*size)--;
+ }
+ return print_unsigned(str, size, val, base, digits);
+}
+
+char *print_number(char *str, size_t *size, long long val, int base,
+ const char *digits, int is_signed)
+{
+ if (is_signed) {
+ return print_signed(str, size, val, base, digits);
+ }
+ return print_unsigned(str, size, val, base, digits);
+}
+
+char *print_string(char *str, size_t *size, char *arg)
+{
+ for(; *arg && *size; ++arg, ++str, --(*size)) {
+ *str = *arg;
+ }
+ return str;
+}
+
+int minimal_vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+ char *str_arg;
+ int signed_arg;
+ unsigned unsigned_arg;
+ int orig_size = size;
+ int is_long;
+ int is_signed;
+ int base;
+ long long val;
+
+ while (*format && size) {
+ switch (*format) {
+ case '%':
+ is_signed = 1;
+ is_long = 0;
+repeat:
+ format++;
+ switch (*format) {
+ case 'l':
+ is_long = 1;
+ goto repeat;
+ break;
+ case 'd':
+ case 'x':
+ case 'u':
+ switch (*format) {
+ case 'u':
+ is_signed = 0;
+ case 'd':
+ base = 10;
+ break;
+ case 'x':
+ is_signed = 0;
+ base = 16;
+ break;
+ }
+ if (is_long) {
+ if (is_signed) {
+ val = (long long)va_arg(ap, long int);
+ } else {
+ val = (long long)va_arg(ap, long unsigned);
+ }
+ } else {
+ if (is_signed) {
+ val = (long long)va_arg(ap, int);
+ } else {
+ val = (long long)va_arg(ap, unsigned);
+ }
+ }
+ str = print_number(str, &size, val, base, lower_digits, is_signed);
+ break;
+ case 's':
+ str = print_string(str, &size, va_arg(ap, char*));
+ break;
+ default:
+ /* unrecognized type, ignored (this *is* minimal) */
+ break;
+ }
+ format++;
+ break;
+ default:
+ *(str++) = *(format++); size--;
+ break;
+ }
+ }
+ *str = '\0';
+ return orig_size - size;
+}
+
+int minimal_snprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = minimal_vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/miniport/qxl.c b/miniport/qxl.c
index 855b08b..3eb71a9 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -19,11 +19,15 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
+#include "stddef.h"
+#include <stdlib.h>
+#include "miniport.h"
#include "os_dep.h"
#include "qxl.h"
#if (WINVER < 0x0501)
#include "wdmhelper.h"
#endif
+#include "minimal_snprintf.h"
VP_STATUS FindAdapter(PVOID dev_extension,
PVOID reserved,
@@ -91,6 +95,53 @@ typedef struct QXLExtension {
#define QXL_ALLOC_TAG '_lxq'
+static char *g_log_buf = NULL;
+static PUCHAR g_log_port = 0;
+static UINT32 *g_log_level = NULL;
+
+#define DBG_LEVEL 0
+
+#define QXL_MINIPORT_DEBUG_PREFIX "qxlmp: "
+
+void my_memcpy(char *dest, const char *src, unsigned n)
+{
+ while (n-- > 0) {
+ *(dest++) = *(src++);
+ }
+}
+
+void DebugPrintV(char *log_buf, PUCHAR log_port, const char *message, const char *func, va_list ap)
+{
+ int n, n_strlen;
+
+ if (log_buf && log_port && g_log_level && *g_log_level > 0) {
+ /*
+ * TODO: use a shared semaphore with display code.
+ * In practice this is not a problem, since miniport runs either on ioctls (sync)
+ * or before display is brought up or when it is brought down.
+ * Also the worst that can happen is overwriting a message (not seen in practice).
+ */
+ minimal_snprintf(log_buf, QXL_LOG_BUF_SIZE, QXL_MINIPORT_DEBUG_PREFIX);
+ minimal_vsnprintf(log_buf + strlen(QXL_MINIPORT_DEBUG_PREFIX),
+ QXL_LOG_BUF_SIZE - strlen(QXL_MINIPORT_DEBUG_PREFIX),
+ message, ap);
+ VideoPortWritePortUchar(log_port, 0);
+ } else {
+ VideoDebugPrint((0, (PCHAR)message, ap));
+ }
+}
+
+void DebugPrint(UINT32 level, const char *message, const char *func, ...)
+{
+ va_list ap;
+
+ if (level > (g_log_level ? *g_log_level : DBG_LEVEL)) {
+ return;
+ }
+ va_start(ap, message);
+ DebugPrintV(g_log_buf, g_log_port, message, func, ap);
+ va_end(ap);
+}
ULONG DriverEntry(PVOID context1, PVOID context2)
{
@@ -153,7 +204,8 @@ VP_STATUS InitIO(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
dev->io_base = io_base;
dev->io_port = (PUCHAR)range->RangeStart.LowPart;
-
+ g_log_port = dev->io_port + QXL_IO_LOG;
+ g_log_level = &dev->rom->log_level;
DEBUG_PRINT((0, "%s: OK, io 0x%x size %lu\n", __FUNCTION__,
(ULONG)range->RangeStart.LowPart, range->RangeLength));
@@ -259,6 +311,7 @@ VP_STATUS InitRam(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
dev->ram_start = ram;
dev->ram_header = ram_header;
dev->ram_size = range->RangeLength;
+ g_log_buf = dev->ram_header->log_buf;
DEBUG_PRINT((0, "%s OK: ram 0x%lx size %lu\n",
__FUNCTION__, (ULONG)range->RangeStart.QuadPart, range->RangeLength));
return NO_ERROR;
diff --git a/miniport/qxl.h b/miniport/qxl.h
index a65d590..c7df4b1 100644
--- a/miniport/qxl.h
+++ b/miniport/qxl.h
@@ -35,8 +35,7 @@ enum {
#define PAGE_SIZE (1 << PAGE_SHIFT)
#if DBG
-#define DEBUG_PRINT(arg) VideoDebugPrint(arg)
+#define DEBUG_PRINT(arg) DebugPrint arg
#else
#define DEBUG_PRINT(arg)
#endif
-
diff --git a/miniport/sources b/miniport/sources
index 15b1c76..9391cbf 100644
--- a/miniport/sources
+++ b/miniport/sources
@@ -22,6 +22,7 @@ MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /WX
INCLUDES=$(SPICE_COMMON_DIR); ..\include
SOURCES=qxl.c \
+ minimal_snprintf.c \
wdmhelper.c \
qxl.rc