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 <[EMAIL PROTECTED]>

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 <[EMAIL PROTECTED]>
+ */
+
+#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" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to