[PATCH 1 of 4] Consilidate libcflat for x86 to single lib for all archs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



8 files changed, 453 insertions(+)
user/test/lib/libcflat.h |   37 +++++++++
user/test/lib/panic.c    |   13 +++
user/test/lib/printf.c   |  179 ++++++++++++++++++++++++++++++++++++++++++++++
user/test/lib/string.c   |   21 +++++
user/test/lib/x86/apic.h |   14 +++
user/test/lib/x86/io.c   |   23 +++++
user/test/lib/x86/smp.c  |  150 ++++++++++++++++++++++++++++++++++++++
user/test/lib/x86/smp.h  |   16 ++++


This patch lays the ground work for a sinlge libcflat library that can be used for x86. But this allows for other archs to share common code, and build a single archive for tests to use libcflat functions.

Signed-off-by: Jerone Young <jyoung5@.us.com>

diff --git a/user/test/lib/libcflat.h b/user/test/lib/libcflat.h
new file mode 100644
--- /dev/null
+++ b/user/test/lib/libcflat.h
@@ -0,0 +1,37 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@xxxxxxxxxx>
+ */
+
+#ifndef __LIBCFLAT_H
+#define __LIBCFLAT_H
+
+#include <stdarg.h>
+
+extern int main(void);
+extern void exit(int code);
+extern void panic(char *fmt, ...);
+
+extern unsigned long strlen(const char *buf);
+extern char *strcat(char *dest, const char *src);
+
+extern int printf(const char *fmt, ...);
+extern int vsnprintf(char *buf, int size, const char *fmt, va_list va);
+
+extern void puts(const char *s);
+
+#endif
diff --git a/user/test/lib/panic.c b/user/test/lib/panic.c
new file mode 100644
--- /dev/null
+++ b/user/test/lib/panic.c
@@ -0,0 +1,13 @@
+#include "libcflat.h"
+
+void panic(char *fmt, ...)
+{
+	va_list va;
+	char buf[2000];
+
+	va_start(va, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, va);
+	va_end(va);
+	puts(buf);
+	exit(-1);
+}
diff --git a/user/test/lib/printf.c b/user/test/lib/printf.c
new file mode 100644
--- /dev/null
+++ b/user/test/lib/printf.c
@@ -0,0 +1,179 @@
+#include "libcflat.h"
+
+typedef struct pstream {
+    char *buffer;
+    int remain;
+    int added;
+} pstream_t;
+
+static void addchar(pstream_t *p, char c)
+{
+    if (p->remain) {
+	*p->buffer++ = c;
+	--p->remain;
+    }
+    ++p->added;
+}
+
+void print_str(pstream_t *p, const char *s)
+{
+    while (*s)
+	addchar(p, *s++);
+}
+
+static char digits[16] = "0123456789abcdef";
+
+void print_int(pstream_t *ps, long long n, int base)
+{
+    char buf[sizeof(long) * 3 + 2], *p = buf;
+    int s = 0, i;
+    
+    if (n < 0) {
+	n = -n;
+	s = 1;
+    }
+
+    while (n) {
+	*p++ = digits[n % base];
+	n /= base;
+    }
+    
+    if (s)
+	*p++ = '-';
+
+    if (p == buf)
+	*p++ = '0';
+    
+    for (i = 0; i < (p - buf) / 2; ++i) {
+	char tmp;
+
+	tmp = buf[i];
+	buf[i] = p[-1-i];
+	p[-1-i] = tmp;
+    }
+
+    *p = 0;
+
+    print_str(ps, buf);
+}
+
+void print_unsigned(pstream_t *ps, unsigned long long n, int base)
+{
+    char buf[sizeof(long) * 3 + 1], *p = buf;
+    int i;
+    
+    while (n) {
+	*p++ = digits[n % base];
+	n /= base;
+    }
+    
+    if (p == buf)
+	*p++ = '0';
+    
+    for (i = 0; i < (p - buf) / 2; ++i) {
+	char tmp;
+
+	tmp = buf[i];
+	buf[i] = p[-1-i];
+	p[-1-i] = tmp;
+    }
+
+    *p = 0;
+
+    print_str(ps, buf);
+}
+
+int vsnprintf(char *buf, int size, const char *fmt, va_list va)
+{
+    pstream_t s;
+
+    s.buffer = buf;
+    s.remain = size - 1;
+    s.added = 0;
+    while (*fmt) {
+	char f = *fmt++;
+	int nlong = 0;
+
+	if (f != '%') {
+	    addchar(&s, f);
+	    continue;
+	}
+    morefmt:
+	f = *fmt++;
+	switch (f) {
+	case '%':
+	    addchar(&s, '%');
+	    break;
+	case '\0':
+	    --fmt;
+	    break;
+	case 'l':
+	    ++nlong;
+	    goto morefmt;
+	case 'd':
+	    switch (nlong) {
+	    case 0:
+		print_int(&s, va_arg(va, int), 10);
+		break;
+	    case 1:
+		print_int(&s, va_arg(va, long), 10);
+		break;
+	    default:
+		print_int(&s, va_arg(va, long long), 10);
+		break;
+	    }
+	    break;
+	case 'x':
+	    switch (nlong) {
+	    case 0:
+		print_unsigned(&s, va_arg(va, unsigned), 16);
+		break;
+	    case 1:
+		print_unsigned(&s, va_arg(va, unsigned long), 16);
+		break;
+	    default:
+		print_unsigned(&s, va_arg(va, unsigned long long), 16);
+		break;
+	    }
+	    break;
+	case 'p':
+	    print_str(&s, "0x");
+	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16);
+	    break;
+	case 's':
+	    print_str(&s, va_arg(va, const char *));
+	    break;
+	default:
+	    addchar(&s, f);
+	    break;
+	}
+    }
+    *s.buffer = 0;
+    ++s.added;
+    return s.added;
+}
+
+
+int snprintf(char *buf, int size, const char *fmt, ...)
+{
+    va_list va;
+    int r;
+
+    va_start(va, fmt);
+    r = vsnprintf(buf, size, fmt, va);
+    va_end(va);
+    return r;
+}
+
+int printf(const char *fmt, ...)
+{
+    va_list va;
+    char buf[2000];
+    int r;
+
+    va_start(va, fmt);
+    r = vsnprintf(buf, sizeof buf, fmt, va);
+    va_end(va);
+    puts(buf);
+    return r;
+}
diff --git a/user/test/lib/string.c b/user/test/lib/string.c
new file mode 100644
--- /dev/null
+++ b/user/test/lib/string.c
@@ -0,0 +1,21 @@
+#include "libcflat.h"
+
+unsigned long strlen(const char *buf)
+{
+    unsigned long len = 0;
+
+    while (*buf++)
+	++len;
+    return len;
+}
+
+char *strcat(char *dest, const char *src)
+{
+    char *p = dest;
+
+    while (*p)
+	++p;
+    while ((*p++ = *src++) != 0)
+	;
+    return dest;
+}
diff --git a/user/test/lib/x86/apic.h b/user/test/lib/x86/apic.h
new file mode 100644
--- /dev/null
+++ b/user/test/lib/x86/apic.h
@@ -0,0 +1,14 @@
+#ifndef SILLY_APIC_H
+#define SILLY_APIC_H
+
+#define APIC_BASE 0x1000
+#define APIC_SIZE 0x100
+
+#define APIC_REG_NCPU        0x00
+#define APIC_REG_ID          0x04
+#define APIC_REG_SIPI_ADDR   0x08
+#define APIC_REG_SEND_SIPI   0x0c
+#define APIC_REG_IPI_VECTOR  0x10
+#define APIC_REG_SEND_IPI    0x14
+
+#endif
diff --git a/user/test/lib/x86/io.c b/user/test/lib/x86/io.c
new file mode 100644
--- /dev/null
+++ b/user/test/lib/x86/io.c
@@ -0,0 +1,23 @@
+#include <libcflat.h>
+#include "smp.h"
+
+static struct spinlock lock;
+
+static void print_serial(const char *buf)
+{
+	unsigned long len = strlen(buf);
+
+	asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
+}
+
+void puts(const char *s)
+{
+	spin_lock(&lock);
+	print_serial(s);
+	spin_unlock(&lock);
+}
+
+void exit(int code)
+{
+        asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4));
+}
diff --git a/user/test/lib/x86/smp.c b/user/test/lib/x86/smp.c
new file mode 100644
--- /dev/null
+++ b/user/test/lib/x86/smp.c
@@ -0,0 +1,150 @@
+
+#include <libcflat.h>
+#include "smp.h"
+#include "apic.h"
+
+#define IPI_VECTOR 0x20
+
+static int apic_read(int reg)
+{
+    unsigned short port = APIC_BASE + reg;
+    unsigned v;
+
+    asm volatile ("in %1, %0" : "=a"(v) : "d"(port));
+    return v;
+}
+
+static void apic_write(int reg, unsigned v)
+{
+    unsigned short port = APIC_BASE + reg;
+
+    asm volatile ("out %0, %1" : : "a"(v), "d"(port));
+}
+
+static int apic_get_cpu_count()
+{
+    return apic_read(APIC_REG_NCPU);
+}
+
+static int apic_get_id()
+{
+    return apic_read(APIC_REG_ID);
+}
+
+static void apic_set_ipi_vector(int vector)
+{
+    apic_write(APIC_REG_IPI_VECTOR, vector);
+}
+
+static void apic_send_ipi(int cpu)
+{
+    apic_write(APIC_REG_SEND_IPI, cpu);
+}
+
+static struct spinlock ipi_lock;
+static void (*ipi_function)(void *data);
+static void *ipi_data;
+static volatile int ipi_done;
+
+static __attribute__((used)) void ipi()
+{
+    ipi_function(ipi_data);
+    ipi_done = 1;
+}
+
+asm (
+     "ipi_entry: \n"
+     "   call ipi \n"
+#ifndef __x86_64__
+     "   iret"
+#else
+     "   iretq"
+#endif
+     );
+
+
+static void set_ipi_descriptor(void (*ipi_entry)(void))
+{
+    unsigned short *desc = (void *)(IPI_VECTOR * sizeof(long) * 2);
+    unsigned short cs;
+    unsigned long ipi = (unsigned long)ipi_entry;
+
+    asm ("mov %%cs, %0" : "=r"(cs));
+    desc[0] = ipi;
+    desc[1] = cs;
+    desc[2] = 0x8e00;
+    desc[3] = ipi >> 16;
+#ifdef __x86_64__
+    desc[4] = ipi >> 32;
+    desc[5] = ipi >> 48;
+    desc[6] = 0;
+    desc[7] = 0;
+#endif
+}
+
+void spin_lock(struct spinlock *lock)
+{
+    int v = 1;
+
+    do {
+	asm volatile ("xchg %1, %0" : "+m"(lock->v), "+r"(v));
+    } while (v);
+    asm volatile ("" : : : "memory");
+}
+
+void spin_unlock(struct spinlock *lock)
+{
+    asm volatile ("" : : : "memory");
+    lock->v = 0;
+}
+
+int cpu_count(void)
+{
+    return apic_get_cpu_count();
+}
+
+int smp_id(void)
+{
+    return apic_get_id();
+}
+
+void on_cpu(int cpu, void (*function)(void *data), void *data)
+{
+    spin_lock(&ipi_lock);
+    if (cpu == apic_get_id())
+	function(data);
+    else {
+	ipi_function = function;
+	ipi_data = data;
+	apic_send_ipi(cpu);
+	while (!ipi_done)
+	    ;
+	ipi_done = 0;
+    }
+    spin_unlock(&ipi_lock);
+}
+
+static void (*smp_main_func)(void);
+static volatile int smp_main_running;
+
+asm ("smp_init_entry: \n"
+     "incl smp_main_running \n"
+     "sti \n"
+     "call *smp_main_func");
+
+void smp_init(void (*smp_main)(void))
+{
+    int i;
+    void smp_init_entry(void);
+    void ipi_entry(void);
+
+    apic_set_ipi_vector(IPI_VECTOR);
+    set_ipi_descriptor(smp_init_entry);
+    smp_main_func = smp_main;
+    for (i = 1; i < cpu_count(); ++i) {
+	apic_send_ipi(i);
+	while (smp_main_running < i)
+	    ;
+    }
+    set_ipi_descriptor(ipi_entry);
+}
diff --git a/user/test/lib/x86/smp.h b/user/test/lib/x86/smp.h
new file mode 100644
--- /dev/null
+++ b/user/test/lib/x86/smp.h
@@ -0,0 +1,16 @@
+#ifndef __SMP_H
+#define __SMP_H
+
+struct spinlock {
+    int v;
+};
+
+void smp_init(void (*smp_main)(void));
+
+int cpu_count(void);
+int smp_id(void);
+void on_cpu(int cpu, void (*function)(void *data), void *data);
+void spin_lock(struct spinlock *lock);
+void spin_unlock(struct spinlock *lock);
+
+#endif
--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [KVM Development]     [KVM ARM]     [KVM ia64]     [Linux Virtualization]     [Linux USB Devel]     [Linux Video]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux