From: Antti Kantee Date: Tue, 21 Apr 2015 12:23:42 +0000 (+0000) Subject: Rename librumprun_core to libbmk_core. X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=303f48bb47d98c383c4c4463bf5ab7e14b28455e;p=people%2Fliuw%2Frumprun.git Rename librumprun_core to libbmk_core. It doesn't have anything to do with rumprun, but is at a lower layer of abstraction, so let's just match the header namespace here. --- diff --git a/lib/libbmk_core/Makefile b/lib/libbmk_core/Makefile new file mode 100644 index 0000000..3e8c8c7 --- /dev/null +++ b/lib/libbmk_core/Makefile @@ -0,0 +1,10 @@ +LIB= bmk_core +LIBISPRIVATE= # defined + +SRCS= init.c bmk_string.c memalloc.c sched.c subr_prf.c + +CPPFLAGS+= -I${.CURDIR}/../../include + +.include "${.CURDIR}/arch/${MACHINE}/Makefile.inc" + +.include diff --git a/lib/libbmk_core/arch/amd64/Makefile.inc b/lib/libbmk_core/arch/amd64/Makefile.inc new file mode 100644 index 0000000..80b2d56 --- /dev/null +++ b/lib/libbmk_core/arch/amd64/Makefile.inc @@ -0,0 +1,6 @@ +MYDIR:= ${.PARSEDIR} +.PATH: ${MYDIR} + +SRCS+= cpu_sched_switch.S + +.include "${MYDIR}/../x86/Makefile.inc" diff --git a/lib/libbmk_core/arch/amd64/cpu_sched_switch.S b/lib/libbmk_core/arch/amd64/cpu_sched_switch.S new file mode 100644 index 0000000..4747652 --- /dev/null +++ b/lib/libbmk_core/arch/amd64/cpu_sched_switch.S @@ -0,0 +1,70 @@ +/*- + **************************************************************************** + * (C) 2005 - Grzegorz Milos - Intel Research Cambridge + **************************************************************************** + * + * File: sched.c + * Author: Grzegorz Milos + * Changes: Robert Kaiser + * + * Date: Aug 2005 + * + * Environment: Xen Minimal OS + * Description: simple scheduler for Mini-Os + * + * The scheduler is non-preemptive (cooperative), and schedules according + * to Round Robin algorithm. + * + **************************************************************************** + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include + +ENTRY(bmk_cpu_sched_bouncer) + popq %rdi + popq %rbx + pushq $0 /* correct stack alignment for SSE */ + pushq $0 + xorq %rbp,%rbp + call *%rbx + call bmk_sched_exit +END(bmk_cpu_sched_bouncer) + +ENTRY(bmk__cpu_switch) + pushq %rbp + pushq %rbx + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + movq %rsp, (%rdi) /* save ESP */ + movq (%rsi), %rsp /* restore ESP */ + movq $1f, 8(%rdi) /* save EIP */ + pushq 8(%rsi) /* restore EIP */ + ret +1: + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbx + popq %rbp + ret +END(bmk__cpu_switch) diff --git a/lib/libbmk_core/arch/i386/Makefile.inc b/lib/libbmk_core/arch/i386/Makefile.inc new file mode 100644 index 0000000..80b2d56 --- /dev/null +++ b/lib/libbmk_core/arch/i386/Makefile.inc @@ -0,0 +1,6 @@ +MYDIR:= ${.PARSEDIR} +.PATH: ${MYDIR} + +SRCS+= cpu_sched_switch.S + +.include "${MYDIR}/../x86/Makefile.inc" diff --git a/lib/libbmk_core/arch/i386/cpu_sched_switch.S b/lib/libbmk_core/arch/i386/cpu_sched_switch.S new file mode 100644 index 0000000..cc9ec7d --- /dev/null +++ b/lib/libbmk_core/arch/i386/cpu_sched_switch.S @@ -0,0 +1,73 @@ +/*- + **************************************************************************** + * (C) 2005 - Grzegorz Milos - Intel Research Cambridge + **************************************************************************** + * + * File: sched.c + * Author: Grzegorz Milos + * Changes: Robert Kaiser + * + * Date: Aug 2005 + * + * Environment: Xen Minimal OS + * Description: simple scheduler for Mini-Os + * + * The scheduler is non-preemptive (cooperative), and schedules according + * to Round Robin algorithm. + * + **************************************************************************** + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include + +ENTRY(bmk_cpu_sched_bouncer) + popl %eax + popl %ebx + pushl $0 + xorl %ebp,%ebp + pushl %eax + call *%ebx + call bmk_sched_exit +END(bmk_cpu_sched_bouncer) + +ENTRY(bmk__cpu_switch) + movl 4(%esp), %ecx /* prev */ + movl 8(%esp), %edx /* next */ + + /* reload tls for new thread */ + movl $0x18, %eax + movl %eax, %gs + + pushl %ebp + pushl %ebx + pushl %esi + pushl %edi + movl %esp, (%ecx) /* save ESP */ + movl (%edx), %esp /* restore ESP */ + movl $1f, 4(%ecx) /* save EIP */ + pushl 4(%edx) /* restore EIP */ + ret +1: + popl %edi + popl %esi + popl %ebx + popl %ebp + ret +END(bmk__cpu_switch) diff --git a/lib/libbmk_core/arch/x86/Makefile.inc b/lib/libbmk_core/arch/x86/Makefile.inc new file mode 100644 index 0000000..757c137 --- /dev/null +++ b/lib/libbmk_core/arch/x86/Makefile.inc @@ -0,0 +1,4 @@ +X86DIR:=${.PARSEDIR} +.PATH: ${X86DIR} + +SRCS+= cpu_sched.c diff --git a/lib/libbmk_core/arch/x86/cpu_sched.c b/lib/libbmk_core/arch/x86/cpu_sched.c new file mode 100644 index 0000000..f9c945d --- /dev/null +++ b/lib/libbmk_core/arch/x86/cpu_sched.c @@ -0,0 +1,76 @@ +/* + **************************************************************************** + * (C) 2005 - Grzegorz Milos - Intel Research Cambridge + **************************************************************************** + * + * File: sched.c + * Author: Grzegorz Milos + * Changes: Robert Kaiser + * + * Date: Aug 2005 + * + * Environment: Xen Minimal OS + * Description: simple scheduler for Mini-Os + * + * The scheduler is non-preemptive (cooperative), and schedules according + * to Round Robin algorithm. + * + **************************************************************************** + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +static void +stack_push(void **stackp, unsigned long value) +{ + unsigned long *stack = *stackp; + + stack--; + *stack = value; + *stackp = stack; +} + +void +bmk_cpu_sched_create(struct bmk_thread *thread, struct bmk_tcb *tcb, + void (*f)(void *), void *arg, + void *stack_base, unsigned long stack_size) +{ + void *stack_top = (char *)stack_base + stack_size; + + /* Save pointer to the thread on the stack, used by current macro */ + *(unsigned long *)stack_base = (unsigned long)thread; + + /* these values are used by bmk_cpu_sched_bouncer() */ + stack_push(&stack_top, (unsigned long)f); + stack_push(&stack_top, (unsigned long)arg); + + tcb->btcb_sp = (unsigned long)stack_top; + tcb->btcb_ip = (unsigned long)bmk_cpu_sched_bouncer; +} + +struct bmk_thread * +bmk_cpu_sched_current(void) +{ + struct bmk_thread **current; + + current = (void *)((unsigned long)¤t & ~(bmk_stacksize-1)); + return *current; +}; diff --git a/lib/libbmk_core/bmk_string.c b/lib/libbmk_core/bmk_string.c new file mode 100644 index 0000000..fb53980 --- /dev/null +++ b/lib/libbmk_core/bmk_string.c @@ -0,0 +1,135 @@ +/*- + * Copyright (c) 2014 Antti Kantee. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * The assumption is that these won't be used very often, + * only for the very low-level routines. + * + * Some code from public domain implementations. + */ + +#include +#include + +unsigned long +bmk_strlen(const char *str) +{ + unsigned long rv = 0; + + while (*str++) + rv++; + return rv; +} + +int +bmk_strcmp(const char *a, const char *b) +{ + + while (*a && *a++ == *b++) { + continue; + } + if (*a) { + a--; + b--; + } + return *a - *b; +} + +int +bmk_strncmp(const char *a, const char *b, unsigned long n) +{ + unsigned char u1, u2; + + while (n-- > 0) { + u1 = (unsigned char)*a++; + u2 = (unsigned char)*b++; + if (u1 != u2) + return u1 - u2; + if (u1 == '\0') + return 0; + } + return 0; +} + +char * +bmk_strcpy(char *d, const char *s) +{ + char *orig = d; + + while ((*d++ = *s++) != '\0') + continue; + return orig; +} + +char * +bmk_strncpy(char *d, const char *s, unsigned long n) +{ + char *orig = d; + + while ((*d++ = *s++) && n--) + continue; + while (n--) + *d++ = '\0'; + return orig; +} + +void * +bmk_memset(void *b, int c, unsigned long n) +{ + unsigned char *v = b; + + while (n--) + *v++ = (unsigned char)c; + + return b; +} + +void * +bmk_memcpy(void *d, const void *src, unsigned long n) +{ + unsigned char *dp; + const unsigned char *sp; + + dp = d; + sp = src; + + while (n--) + *dp++ = *sp++; + + return d; +} + +void * +bmk_memchr(const void *d, int c, unsigned long n) +{ + const unsigned char *p = d; + + while (n--) { + if (*p == (unsigned char)c) + return (void *)(unsigned long)p; + p++; + } + return NULL; +} diff --git a/lib/libbmk_core/init.c b/lib/libbmk_core/init.c new file mode 100644 index 0000000..215b59e --- /dev/null +++ b/lib/libbmk_core/init.c @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2015 Antti Kantee. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +unsigned long bmk_stackpageorder; +unsigned long bmk_stacksize; +unsigned long bmk_pagesize; + +int +bmk_core_init(unsigned long stackpageorder, unsigned long pagesize) +{ + + bmk_stackpageorder = stackpageorder; + bmk_stacksize = (1< + +#include +#if defined(RCHECK) +#include +#endif +#if defined(RCHECK) || defined(MSTATS) +#include +#endif +#include +#include +#include + +#else + +#include +#include +#include +#include + +#define NULL (void *)0 +#define ASSERT(x) + +#endif + + +/* + * The overhead on a block is at least 4 bytes. When free, this space + * contains a pointer to the next free block, and the bottom two bits must + * be zero. When in use, the first byte is set to MAGIC, and the second + * byte is the size index. The remaining bytes are for alignment. + * If range checking is enabled then a second word holds the size of the + * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC). + * The order of elements is critical: ov_magic must overlay the low order + * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern. + */ +union overhead { + union overhead *ov_next; /* when free */ + struct { + unsigned long ovu_alignpad; /* padding for alignment */ + unsigned char ovu_magic; /* magic number */ + unsigned char ovu_index; /* bucket # */ +#ifdef RCHECK + unsigned short ovu_rmagic; /* range magic number */ + unsigned long ovu_size; /* actual block size */ +#endif + } ovu; +#define ov_alignpad ovu.ovu_alignpad +#define ov_magic ovu.ovu_magic +#define ov_index ovu.ovu_index +#define ov_rmagic ovu.ovu_rmagic +#define ov_size ovu.ovu_size +}; + +#define MAGIC 0xef /* magic # on accounting info */ +#define UNMAGIC 0x12 /* magic # != MAGIC */ +#define UNMAGIC2 0x24 /* magic # != MAGIC/UNMAGIC */ +#ifdef RCHECK +#define RMAGIC 0x5555 /* magic # on range info */ +#endif + +#ifdef RCHECK +#define RSLOP sizeof (unsigned short) +#else +#define RSLOP 0 +#endif + +/* + * nextf[i] is the pointer to the next free block of size 2^(i+MINSHIFT). The + * smallest allocatable block is 1< + +static void botch(const char *); + +/* + * NOTE: since this may be called while malloc_mutex is locked, stdio must not + * be used in this function. + */ +static void +botch(const char *s) +{ + struct iovec iov[3]; + + iov[0].iov_base = "\nassertion botched: "; + iov[0].iov_len = 20; + iov[1].iov_base = (void *)s; + iov[1].iov_len = strlen(s); + iov[2].iov_base = "\n"; + iov[2].iov_len = 1; + + /* + * This place deserves a word of warning: a cancellation point will + * occur when executing writev(), and we might be still owning + * malloc_mutex. At this point we need to disable cancellation + * until `after' abort() because i) establishing a cancellation handler + * might, depending on the implementation, result in another malloc() + * to be executed, and ii) it is really not desirable to let execution + * continue. `Fix me.' + * + * Note that holding mutex_lock during abort() is safe. + */ + + (void)writev(STDERR_FILENO, iov, 3); + abort(); +} +#endif + +void * +bmk_memalloc(unsigned long nbytes, unsigned long align) +{ + union overhead *op; + void *rv; + unsigned long allocbytes; + int bucket; + unsigned amt; + unsigned long alignpad; + + malloc_lock(); + + if (pagesz == 0) { + pagesz = bmk_pagesize; + ASSERT(pagesz > 0); + +#if 0 + op = (union overhead *)(void *)sbrk(0); + n = n - sizeof (*op) - ((long)op & (n - 1)); + if (n < 0) + n += pagesz; + if (n) { + if (sbrk((int)n) == (void *)-1) { + malloc_unlock(); + return (NULL); + } + } +#endif + + bucket = 0; + amt = 1< amt) { + amt <<= 1; + bucket++; + } + pagebucket = bucket; + } + + if (align & (align-1)) + return NULL; + if (align < MINALIGN) + align = MINALIGN; + + /* need at least this many bytes plus header to satisfy alignment */ + allocbytes = nbytes + ((sizeof(*op) + (align-1)) & ~(align-1)); + + /* + * Convert amount of memory requested into closest block size + * stored in hash buckets which satisfies request. + * Account for space used per block for accounting. + */ + if (allocbytes <= pagesz - RSLOP) { +#ifndef RCHECK + amt = 1< amt) { + amt <<= 1; + if (amt == 0) + return (NULL); + bucket++; + } + /* + * If nothing in hash bucket right now, + * request more memory from the system. + */ + if ((op = nextf[bucket]) == NULL) { + morecore(bucket); + if ((op = nextf[bucket]) == NULL) { + malloc_unlock(); + return (NULL); + } + } + /* remove from linked list */ + nextf[bucket] = op->ov_next; + + /* align op before returned memory */ + rv = (void *)(((unsigned long)(op+1) + align - 1) & ~(align - 1)); + alignpad = (unsigned long)rv - (unsigned long)op; + +#ifdef MEMALLOC_TESTING + memset(op, MAGIC, alignpad); +#endif + + op = ((union overhead *)rv)-1; + op->ov_magic = MAGIC; + op->ov_index = bucket; + op->ov_alignpad = alignpad; +#ifdef MSTATS + nmalloc[bucket]++; +#endif + malloc_unlock(); +#ifdef RCHECK + /* + * Record allocated size of block and + * bound space with magic numbers. + */ + op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1); + op->ov_rmagic = RMAGIC; + *(unsigned short *)((char *)(op + 1) + op->ov_size) = RMAGIC; +#endif + + return rv; +} + +void * +bmk_xmalloc(unsigned long howmuch) +{ + void *rv; + + rv = bmk_memalloc(howmuch, 0); + if (rv == NULL) + bmk_platform_halt("xmalloc failed"); + return rv; +} + +void * +bmk_memcalloc(unsigned long n, unsigned long size) +{ + void *v; + unsigned long tot = n * size; + + if (size != 0 && tot / size != n) + return NULL; + + if ((v = bmk_memalloc(tot, MINALIGN)) != NULL) { + bmk_memset(v, 0, tot); + } + return v; +} + +static void * +corealloc(int shift) +{ + void *v; + +#ifdef MEMALLOC_TESTING + v = malloc((1< 0) { + op->ov_next = + (union overhead *)(void *)((char *)(void *)op+(unsigned long)sz); + op = op->ov_next; + } + op->ov_next = NULL; +} + +void +bmk_memfree(void *cp) +{ + long size; + union overhead *op; + unsigned long alignpad; + void *origp; + + if (cp == NULL) + return; + op = ((union overhead *)cp)-1; + if (op->ov_magic != MAGIC) { +#ifdef MEMALLOC_TESTING + ASSERT(0); +#endif + return; /* sanity */ + } + +#ifdef RCHECK + ASSERT(op->ov_rmagic == RMAGIC); + ASSERT(*(unsigned short *)((char *)(op + 1) + op->ov_size) == RMAGIC); +#endif + size = op->ov_index; + alignpad = op->ov_alignpad; + ASSERT(size < NBUCKETS); + + malloc_lock(); + origp = (unsigned char *)cp - alignpad; + +#ifdef MEMALLOC_TESTING + { + unsigned long i; + + for (i = 0; + (unsigned char *)origp + i < (unsigned char *)op; + i++) { + ASSERT(*((unsigned char *)origp + i) == MAGIC); + + } + } +#endif + + op = (void *)origp; + op->ov_next = nextf[(unsigned int)size];/* also clobbers ov_magic */ + nextf[(unsigned int)size] = op; +#ifdef MSTATS + nmalloc[(unsigned long)size]--; +#endif + + malloc_unlock(); +} + +/* + * don't do any of "storage compaction" nonsense, "just" the three modes: + * + cp == NULL ==> malloc + * + nbytes == 0 ==> free + * + else ==> realloc + */ +void * +bmk_memrealloc(void *cp, unsigned long nbytes) +{ + union overhead *op; + unsigned long size; + unsigned long alignpad; + void *np; + + if (cp == NULL) + return bmk_memalloc(nbytes, MINALIGN); + + if (nbytes == 0) { + bmk_memfree(cp); + return NULL; + } + + op = ((union overhead *)cp)-1; + size = op->ov_index; + alignpad = op->ov_alignpad; + + /* don't bother "compacting". don't like it? don't use realloc! */ + if (((1<<(size+MINSHIFT)) - alignpad) >= nbytes) + return cp; + + /* we're gonna need a bigger bucket */ + np = bmk_memalloc(nbytes, 8); + if (np == NULL) + return NULL; + + bmk_memcpy(np, cp, (1<<(size+MINSHIFT)) - alignpad); + bmk_memfree(cp); + return np; +} + +#ifdef MSTATS +/* + * mstats - print out statistics about malloc + * + * Prints two lines of numbers, one showing the length of the free list + * for each size category, the second showing the number of mallocs - + * frees for each size category. + */ +void +mstats(const char *s) +{ + int i, j; + union overhead *p; + int totfree = 0, + totused = 0; + + fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s); + for (i = 0; i < NBUCKETS; i++) { + for (j = 0, p = nextf[i]; p; p = p->ov_next, j++) + ; + fprintf(stderr, " %d", j); + totfree += j * (1 << (i + 3)); + } + fprintf(stderr, "\nused:\t"); + for (i = 0; i < NBUCKETS; i++) { + fprintf(stderr, " %d", nmalloc[i]); + totused += nmalloc[i] * (1 << (i + 3)); + } + fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n", + totused, totfree); +} +#endif + +#ifdef MEMALLOC_TESTING + +#define TEST_MINALLOC 0 +#define TEST_MAXALLOC 64*1024 + +#define TEST_MINALIGN 1 +#define TEST_MAXALIGN 16 + +#define NALLOC 1024 +#define NRING 16 + +static void * +testalloc(void) +{ + void *v, *nv; + size_t size1, size2, align; + + /* doesn't give an even bucket distribution, but ... */ + size1 = random() % ((TEST_MAXALLOC-TEST_MINALLOC)+1) + TEST_MINALLOC; + align = random() % ((TEST_MAXALIGN-TEST_MINALIGN)+1) + TEST_MINALIGN; + + v = bmk_memalloc(size1, 1< +#include +#include +#include +#include +#include +#include + +#define TLS_COUNT 2 +#define NAME_MAXLEN 16 + +#define THREAD_RUNNABLE 0x01 +#define THREAD_MUSTJOIN 0x02 +#define THREAD_JOINED 0x04 +#define THREAD_EXTSTACK 0x08 +#define THREAD_TIMEDOUT 0x10 + +struct bmk_thread { + char bt_name[NAME_MAXLEN]; + + void *bt_tls[TLS_COUNT]; + + bmk_time_t bt_wakeup_time; + + int bt_flags; + int bt_errno; + + void *bt_stackbase; + + void *bt_cookie; + + /* MD thread control block */ + struct bmk_tcb bt_tcb; + + TAILQ_ENTRY(bmk_thread) bt_entries; +}; + +static TAILQ_HEAD(, bmk_thread) zombies = TAILQ_HEAD_INITIALIZER(zombies); +static TAILQ_HEAD(, bmk_thread) threads = TAILQ_HEAD_INITIALIZER(threads); + +static void (*scheduler_hook)(void *, void *); + +static int +is_runnable(struct bmk_thread *thread) +{ + + return thread->bt_flags & THREAD_RUNNABLE; +} + +static void +set_runnable(struct bmk_thread *thread) +{ + + thread->bt_flags |= THREAD_RUNNABLE; +} + +static void +clear_runnable(struct bmk_thread *thread) +{ + + thread->bt_flags &= ~THREAD_RUNNABLE; +} + +static void +stackalloc(void **stack, unsigned long *ss) +{ + + *stack = bmk_platform_allocpg2(bmk_stackpageorder); + *ss = bmk_stacksize; +} + +static void +stackfree(struct bmk_thread *thread) +{ + + bmk_platform_freepg2(thread->bt_stackbase, bmk_stackpageorder); +} + +static void +print_threadinfo(struct bmk_thread *thread) +{ + + bmk_printf("thread \"%s\" at %p, flags 0x%x\n", + thread->bt_name, thread, thread->bt_flags); +} + +static void +sched_switch(struct bmk_thread *prev, struct bmk_thread *next) +{ + + if (scheduler_hook) + scheduler_hook(prev->bt_cookie, next->bt_cookie); + bmk_platform_cpu_sched_switch(&prev->bt_tcb, &next->bt_tcb); +} + +struct bmk_thread * +bmk_sched_current(void) +{ + + return bmk_cpu_sched_current(); +} + +void +bmk_sched_dumpqueue(void) +{ + struct bmk_thread *thr; + + bmk_printf("BEGIN schedqueue dump\n"); + TAILQ_FOREACH(thr, &threads, bt_entries) { + print_threadinfo(thr); + } + bmk_printf("END schedqueue dump\n"); +} + +void +bmk_sched(void) +{ + struct bmk_thread *prev, *next, *thread, *tmp; + unsigned long flags; + + prev = bmk_sched_current(); + flags = bmk_platform_splhigh(); + +#if 0 + /* XXX */ + if (_minios_in_hypervisor_callback) { + minios_printk("Must not call schedule() from a callback\n"); + BUG(); + } +#endif + + if (flags) { + bmk_platform_halt("Must not call sched() with IRQs disabled\n"); + } + + /* could do time management a bit better here */ + do { + bmk_time_t tm, wakeup; + + /* block domain for max 1s */ + tm = bmk_clock_monotonic(); + wakeup = tm + 1*1000*1000*1000ULL; + + next = NULL; + TAILQ_FOREACH_SAFE(thread, &threads, bt_entries, tmp) { + if (!is_runnable(thread) + && thread->bt_wakeup_time >= 0) { + if (thread->bt_wakeup_time <= tm) { + thread->bt_flags |= THREAD_TIMEDOUT; + bmk_sched_wake(thread); + } else if (thread->bt_wakeup_time < wakeup) + wakeup = thread->bt_wakeup_time; + } + if (is_runnable(thread)) { + next = thread; + /* Put this thread on the end of the list */ + TAILQ_REMOVE(&threads, thread, bt_entries); + TAILQ_INSERT_TAIL(&threads, thread, bt_entries); + break; + } + } + if (next) + break; + + /* sleep for a while */ + bmk_platform_block(wakeup); + } while (1); + + bmk_platform_splx(flags); + + if (prev != next) { + sched_switch(prev, next); + } + + /* reaper */ + TAILQ_FOREACH_SAFE(thread, &zombies, bt_entries, tmp) { + if (thread != prev) { + TAILQ_REMOVE(&zombies, thread, bt_entries); + if ((thread->bt_flags & THREAD_EXTSTACK) == 0) + stackfree(thread); + bmk_memfree(thread); + } + } +} + +/* + * Allocate tls and initialize it. + * + * XXX: this needs to change in the future so that + * we put the tcb in the same space instead of having multiple + * random copies flying around. + */ +extern const char _tdata_start[], _tdata_end[]; +extern const char _tbss_start[], _tbss_end[]; +static int +allocothertls(struct bmk_thread *thread) +{ + const unsigned long tdatasize = _tdata_end - _tdata_start; + const unsigned long tbsssize = _tbss_end - _tbss_start; + struct bmk_tcb *tcb = &thread->bt_tcb; + char *tlsmem; + + tlsmem = bmk_memalloc(tdatasize + tbsssize, 0); + + bmk_memcpy(tlsmem, _tdata_start, tdatasize); + bmk_memset(tlsmem + tdatasize, 0, tbsssize); + + tcb->btcb_tp = (unsigned long)(tlsmem + tdatasize + tbsssize); + tcb->btcb_tpsize = tdatasize + tbsssize; + + return 0; +} + +static void +freeothertls(struct bmk_thread *thread) +{ + void *mem; + + mem = (void *)(thread->bt_tcb.btcb_tp-thread->bt_tcb.btcb_tpsize); + bmk_memfree(mem); +} + +struct bmk_thread * +bmk_sched_create(const char *name, void *cookie, int joinable, + void (*f)(void *), void *data, + void *stack_base, unsigned long stack_size) +{ + struct bmk_thread *thread; + unsigned long flags; + + thread = bmk_xmalloc(sizeof(*thread)); + bmk_memset(thread, 0, sizeof(*thread)); + bmk_strncpy(thread->bt_name, name, sizeof(thread->bt_name)-1); + + if (!stack_base) { + bmk_assert(stack_size == 0); + stackalloc(&stack_base, &stack_size); + } else { + thread->bt_flags = THREAD_EXTSTACK; + } + thread->bt_stackbase = stack_base; + if (joinable) + thread->bt_flags |= THREAD_MUSTJOIN; + + bmk_cpu_sched_create(thread, &thread->bt_tcb, f, data, + stack_base, stack_size); + + thread->bt_cookie = cookie; + + thread->bt_wakeup_time = -1; + + flags = bmk_platform_splhigh(); + TAILQ_INSERT_TAIL(&threads, thread, bt_entries); + bmk_platform_splx(flags); + + allocothertls(thread); + set_runnable(thread); + + return thread; +} + +struct join_waiter { + struct bmk_thread *jw_thread; + struct bmk_thread *jw_wanted; + TAILQ_ENTRY(join_waiter) jw_entries; +}; +static TAILQ_HEAD(, join_waiter) joinwq = TAILQ_HEAD_INITIALIZER(joinwq); + +void +bmk_sched_exit(void) +{ + struct bmk_thread *thread = bmk_sched_current(); + struct join_waiter *jw_iter; + unsigned long flags; + + /* if joinable, gate until we are allowed to exit */ + flags = bmk_platform_splhigh(); + while (thread->bt_flags & THREAD_MUSTJOIN) { + thread->bt_flags |= THREAD_JOINED; + bmk_platform_splx(flags); + + /* see if the joiner is already there */ + TAILQ_FOREACH(jw_iter, &joinwq, jw_entries) { + if (jw_iter->jw_wanted == thread) { + bmk_sched_wake(jw_iter->jw_thread); + break; + } + } + bmk_sched_block(thread); + bmk_sched(); + flags = bmk_platform_splhigh(); + } + freeothertls(thread); + + /* Remove from the thread list */ + TAILQ_REMOVE(&threads, thread, bt_entries); + clear_runnable(thread); + /* Put onto exited list */ + TAILQ_INSERT_HEAD(&zombies, thread, bt_entries); + bmk_platform_splx(flags); + + /* bye */ + bmk_sched(); + bmk_platform_halt("schedule() returned for a dead thread!\n"); +} + +void +bmk_sched_join(struct bmk_thread *joinable) +{ + struct join_waiter jw; + struct bmk_thread *thread = bmk_sched_current(); + unsigned long flags; + + bmk_assert(joinable->bt_flags & THREAD_MUSTJOIN); + + flags = bmk_platform_splhigh(); + /* wait for exiting thread to hit thread_exit() */ + while ((joinable->bt_flags & THREAD_JOINED) == 0) { + bmk_platform_splx(flags); + + jw.jw_thread = thread; + jw.jw_wanted = joinable; + TAILQ_INSERT_TAIL(&joinwq, &jw, jw_entries); + bmk_sched_block(thread); + bmk_sched(); + TAILQ_REMOVE(&joinwq, &jw, jw_entries); + + flags = bmk_platform_splhigh(); + } + + /* signal exiting thread that we have seen it and it may now exit */ + bmk_assert(joinable->bt_flags & THREAD_JOINED); + joinable->bt_flags &= ~THREAD_MUSTJOIN; + bmk_platform_splx(flags); + + bmk_sched_wake(joinable); +} + +void +bmk_sched_block_timeout(struct bmk_thread *thread, bmk_time_t deadline) +{ + + thread->bt_wakeup_time = deadline; + clear_runnable(thread); +} + +void +bmk_sched_block(struct bmk_thread *thread) +{ + + bmk_sched_block_timeout(thread, -1); +} + +int +bmk_sched_nanosleep_abstime(bmk_time_t nsec) +{ + struct bmk_thread *thread = bmk_sched_current(); + int rv; + + thread->bt_flags &= ~THREAD_TIMEDOUT; + thread->bt_wakeup_time = nsec; + clear_runnable(thread); + bmk_sched(); + + rv = !!(thread->bt_flags & THREAD_TIMEDOUT); + thread->bt_flags &= ~THREAD_TIMEDOUT; + return rv; +} + +int +bmk_sched_nanosleep(bmk_time_t nsec) +{ + + return bmk_sched_nanosleep_abstime(nsec + bmk_clock_monotonic()); +} + +void +bmk_sched_wake(struct bmk_thread *thread) +{ + + thread->bt_wakeup_time = -1; + set_runnable(thread); +} + +void +bmk_sched_init(void (*mainfun)(void *), void *arg) +{ + struct bmk_thread *mainthread; + struct bmk_thread initthread; + + mainthread = bmk_sched_create("main", NULL, 0, mainfun, arg, NULL, 0); + if (mainthread == NULL) + bmk_platform_halt("failed to create main thread"); + + bmk_memset(&initthread, 0, sizeof(initthread)); + bmk_strcpy(initthread.bt_name, "init"); + sched_switch(&initthread, mainthread); + + bmk_platform_halt("bmk_sched_init unreachable"); +} + +void +bmk_sched_set_hook(void (*f)(void *, void *)) +{ + + scheduler_hook = f; +} + +struct bmk_thread * +bmk_sched_init_mainlwp(void *cookie) +{ + struct bmk_thread *current = bmk_sched_current(); + + current->bt_cookie = cookie; + allocothertls(current); + return current; +} + +const char * +bmk_sched_threadname(struct bmk_thread *thread) +{ + + return thread->bt_name; +} + +int * +bmk_sched_geterrno(void) +{ + struct bmk_thread *thread = bmk_sched_current(); + + return &thread->bt_errno; +} + +void +bmk_sched_settls(struct bmk_thread *thread, unsigned int which, void *value) +{ + + if (which >= TLS_COUNT) { + bmk_platform_halt("out of bmk sched tls space"); + } + thread->bt_tls[which] = value; +} + +void * +bmk_sched_gettls(struct bmk_thread *thread, unsigned int which) +{ + + if (which >= TLS_COUNT) { + bmk_platform_halt("out of bmk sched tls space"); + } + return thread->bt_tls[which]; +} + +void +bmk_sched_yield(void) +{ + struct bmk_thread *current = bmk_sched_current(); + + TAILQ_REMOVE(&threads, current, bt_entries); + TAILQ_INSERT_TAIL(&threads, current, bt_entries); + bmk_sched(); +} diff --git a/lib/libbmk_core/subr_prf.c b/lib/libbmk_core/subr_prf.c new file mode 100644 index 0000000..415c62b --- /dev/null +++ b/lib/libbmk_core/subr_prf.c @@ -0,0 +1,638 @@ +/* $NetBSD: subr_prf.c,v 1.157 2015/02/04 07:10:47 msaitoh Exp $ */ + +/*- + * Copyright (c) 1986, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)subr_prf.c 8.4 (Berkeley) 5/4/95 + */ + +/* + * This is the NetBSD kernel printf code heavily stripped. Format support + * is the same, but the wrappers for calling printf have been reduced + * down to: + * + printf + * + snprintf + * + vnsprintf + */ + +#define _BMK_PRINTF_VA +#include +#include +#include + +#define TOBUFONLY 0x01 +#define TOCONS 0x02 + +#define __UNCONST(x) ((void *)(unsigned long)(x)) +#define KPRINTF_BUFSIZE (sizeof(long long)*8/3 + 2) + +/* + * local prototypes + */ + +static void cons_putchar(int, int); +static int kprintf(const char *, int, void *, char *, va_list); + +/* + * globals + */ + +static void +nullfun(void) +{ + + return; +} + +static void (*v_flush)(void); +static void (*v_putc)(int); + +void +bmk_printf_init(void (*putc)(int), void (*flush)(void)) +{ + + v_putc = putc; + if (flush == NULL) + flush = nullfun; + v_flush = flush; +} + +static const char hexdigits[] = "0123456789abcdef"; +static const char HEXDIGITS[] = "0123456789ABCDEF"; + +/* + * functions + */ + +/* dmesg ring buffer */ +#ifndef BMK_DMESG_SIZE +#define BMK_DMESG_SIZE (16*1024) +#endif +static char bmk_dmesg[BMK_DMESG_SIZE]; +static int bmk_dmesgoff; + +/* + * putchar: print a single character on console or user terminal. + * + * => if console, then the last MSGBUFS chars are saved in msgbuf + * for inspection later (e.g. dmesg/syslog) + * => we must already be in the mutex! + */ +static void +cons_putchar(int c, int flags) +{ + + bmk_dmesg[bmk_dmesgoff] = c; + if (++bmk_dmesgoff == sizeof(bmk_dmesg)-1) + bmk_dmesgoff = 0; + (*v_putc)(c); +} + +static void +kprintf_lock(void) +{ + + /* XXX */ +} + +static void +kprintf_unlock(void) +{ + + /* XXX */ +} + +/* + * bmk_printf: print a message to the console + */ +void +bmk_printf(const char *fmt, ...) +{ + va_list ap; + + kprintf_lock(); + + va_start(ap, fmt); + kprintf(fmt, TOCONS, NULL, NULL, ap); + va_end(ap); + + kprintf_unlock(); +} + +/* + * bmk_vprintf: print a message to the console [already have + * va_list] + */ +void +bmk_vprintf(const char *fmt, va_list ap) +{ + kprintf_lock(); + + kprintf(fmt, TOCONS, NULL, NULL, ap); + + kprintf_unlock(); +} + +/* + * bmk_snprintf: print a message to a buffer + */ +int +bmk_snprintf(char *bf, unsigned long size, const char *fmt, ...) +{ + int retval; + va_list ap; + + va_start(ap, fmt); + retval = bmk_vsnprintf(bf, size, fmt, ap); + va_end(ap); + + return retval; +} + +/* + * bmk_vsnprintf: print a message to a buffer [already have va_list] + */ +int +bmk_vsnprintf(char *bf, unsigned long size, const char *fmt, va_list ap) +{ + int retval; + char *p; + + p = bf + size; + retval = kprintf(fmt, TOBUFONLY, &p, bf, ap); + if (bf && size > 0) { + /* nul terminate */ + if (size <= (unsigned long)retval) + bf[size - 1] = '\0'; + else + bf[retval] = '\0'; + } + return retval; +} + +/* + * kprintf: scaled down version of printf(3). + * + * this version based on vfprintf() from libc which was derived from + * software contributed to Berkeley by Chris Torek. + * + * NOTE: The kprintf mutex must be held if we're going TOBUF or TOCONS! + */ + +/* + * macros for converting digits to letters and vice versa + */ +#define to_digit(c) ((c) - '0') +#define is_digit(c) ((unsigned)to_digit(c) <= 9) +#define to_char(n) ((n) + '0') + +/* + * flags used during conversion. + */ +#define ALT 0x001 /* alternate form */ +#define HEXPREFIX 0x002 /* add 0x or 0X prefix */ +#define LADJUST 0x004 /* left adjustment */ +#define LONGDBL 0x008 /* long double; unimplemented */ +#define LONGINT 0x010 /* long integer */ +#define QUADINT 0x020 /* quad integer */ +#define SHORTINT 0x040 /* short integer */ +#define MAXINT 0x080 /* intmax_t */ +#define PTRINT 0x100 /* intptr_t */ +#define SIZEINT 0x200 /* size_t */ +#define ZEROPAD 0x400 /* zero (as opposed to blank) pad */ +#define FPT 0x800 /* Floating point number */ + + /* + * To extend shorts properly, we need both signed and unsigned + * argument extraction methods. + */ +#define SARG() \ + (flags&MAXINT ? va_arg(ap, long long) : \ + flags&PTRINT ? va_arg(ap, long) : \ + flags&SIZEINT ? va_arg(ap, long) : /* XXX */ \ + flags&QUADINT ? va_arg(ap, long long) : \ + flags&LONGINT ? va_arg(ap, long) : \ + flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ + (long)va_arg(ap, int)) +#define UARG() \ + (flags&MAXINT ? va_arg(ap, unsigned long long) : \ + flags&PTRINT ? va_arg(ap, unsigned long) : \ + flags&SIZEINT ? va_arg(ap, unsigned long) : \ + flags&QUADINT ? va_arg(ap, unsigned long long) : \ + flags&LONGINT ? va_arg(ap, unsigned long) : \ + flags&SHORTINT ? (unsigned long)(unsigned long)va_arg(ap, int) : \ + (unsigned long)va_arg(ap, unsigned int)) + +#define KPRINTF_PUTCHAR(C) { \ + if (oflags == TOBUFONLY) { \ + if (sbuf && ((vp == NULL) || (sbuf < tailp))) \ + *sbuf++ = (C); \ + } else { \ + cons_putchar((C), oflags); \ + } \ +} + +/* + * Guts of kernel printf. Note, we already expect to be in a mutex! + */ +static int +kprintf(const char *fmt0, int oflags, void *vp, char *sbuf, va_list ap) +{ + int ret = 0; /* return value accumulator */ + const char *fmt; /* format string */ + int ch; /* character from fmt */ + int n; /* handy integer (short term usage) */ + char *cp; /* handy char pointer (short term usage) */ + int flags; /* flags as above */ + int width; /* width from format (%8d), or 0 */ + int prec; /* precision from format (%.3d), or -1 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ + + unsigned long long _uquad; /* integer arguments %[diouxX] */ + enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ + int dprec; /* a copy of prec if [diouxX], 0 otherwise */ + int realsz; /* field size expanded by dprec */ + int size; /* size of converted field or string */ + const char *xdigs; /* digits for [xX] conversion */ + char bf[KPRINTF_BUFSIZE]; /* space for %c, %[diouxX] */ + char *tailp; /* tail pointer for snprintf */ + + if (oflags == TOBUFONLY && (vp != NULL)) + tailp = *(char **)vp; + else + tailp = NULL; + + cp = NULL; /* XXX: shutup gcc */ + size = 0; /* XXX: shutup gcc */ + + fmt = fmt0; + ret = 0; + + xdigs = NULL; /* XXX: shut up gcc warning */ + + /* + * Scan the format for conversions (`%' character). + */ + for (;;) { + for (; *fmt != '%' && *fmt; fmt++) { + ret++; + KPRINTF_PUTCHAR(*fmt); + } + if (*fmt == 0) + goto done; + + fmt++; /* skip over '%' */ + + flags = 0; + dprec = 0; + width = 0; + prec = -1; + sign = '\0'; + +rflag: ch = *fmt++; +reswitch: switch (ch) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if ((width = va_arg(ap, int)) >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if ((ch = *fmt++) == '*') { + n = va_arg(ap, int); + prec = n < 0 ? -1 : n; + goto rflag; + } + n = 0; + while (is_digit(ch)) { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } + prec = n < 0 ? -1 : n; + goto reswitch; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } while (is_digit(ch)); + width = n; + goto reswitch; + case 'h': + flags |= SHORTINT; + goto rflag; + case 'j': + flags |= MAXINT; + goto rflag; + case 'l': + if (*fmt == 'l') { + fmt++; + flags |= QUADINT; + } else { + flags |= LONGINT; + } + goto rflag; + case 'q': + flags |= QUADINT; + goto rflag; + case 't': + flags |= PTRINT; + goto rflag; + case 'z': + flags |= SIZEINT; + goto rflag; + case 'c': + *(cp = bf) = va_arg(ap, int); + size = 1; + sign = '\0'; + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + _uquad = SARG(); + if ((long long)_uquad < 0) { + _uquad = -_uquad; + sign = '-'; + } + base = DEC; + goto number; + case 'n': + if (flags & MAXINT) + *va_arg(ap, long long *) = ret; + else if (flags & PTRINT) + *va_arg(ap, long *) = ret; + else if (flags & SIZEINT) + *va_arg(ap, long *) = ret; + else if (flags & QUADINT) + *va_arg(ap, long long *) = ret; + else if (flags & LONGINT) + *va_arg(ap, long *) = ret; + else if (flags & SHORTINT) + *va_arg(ap, short *) = ret; + else + *va_arg(ap, int *) = ret; + continue; /* no output */ + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + _uquad = UARG(); + base = OCT; + goto nosign; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + /* NOSTRICT */ + _uquad = (unsigned long)va_arg(ap, void *); + base = HEX; + xdigs = hexdigits; + flags |= HEXPREFIX; + ch = 'x'; + goto nosign; + case 's': + if ((cp = va_arg(ap, char *)) == NULL) + /*XXXUNCONST*/ + cp = __UNCONST("(null)"); + if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen() will go further. + */ + char *p = bmk_memchr(cp, 0, prec); + + if (p != NULL) { + size = p - cp; + if (size > prec) + size = prec; + } else + size = prec; + } else + size = bmk_strlen(cp); + sign = '\0'; + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + _uquad = UARG(); + base = DEC; + goto nosign; + case 'X': + xdigs = HEXDIGITS; + goto hex; + case 'x': + xdigs = hexdigits; +hex: _uquad = UARG(); + base = HEX; + /* leading 0x/X only if non-zero */ + if (flags & ALT && _uquad != 0) + flags |= HEXPREFIX; + + /* unsigned conversions */ +nosign: sign = '\0'; + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ +number: if ((dprec = prec) >= 0) + flags &= ~ZEROPAD; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + cp = bf + KPRINTF_BUFSIZE; + if (_uquad != 0 || prec != 0) { + /* + * Unsigned mod is hard, and unsigned mod + * by a constant is easier than that by + * a variable; hence this switch. + */ + switch (base) { + case OCT: + do { + *--cp = to_char(_uquad & 7); + _uquad >>= 3; + } while (_uquad); + /* handle octal leading 0 */ + if (flags & ALT && *cp != '0') + *--cp = '0'; + break; + + case DEC: + /* many numbers are 1 digit */ + while (_uquad >= 10) { + *--cp = to_char(_uquad % 10); + _uquad /= 10; + } + *--cp = to_char(_uquad); + break; + + case HEX: + do { + *--cp = xdigs[_uquad & 15]; + _uquad >>= 4; + } while (_uquad); + break; + + default: + /*XXXUNCONST*/ + cp = __UNCONST("bug in kprintf: bad base"); + size = bmk_strlen(cp); + goto skipsize; + } + } + size = bf + KPRINTF_BUFSIZE - cp; + skipsize: + break; + default: /* "%?" prints ?, unless ? is NUL */ + if (ch == '\0') + goto done; + /* pretend it was %c with argument ch */ + cp = bf; + *cp = ch; + size = 1; + sign = '\0'; + break; + } + + /* + * All reasonable formats wind up here. At this point, `cp' + * points to a string which (if not flags&LADJUST) should be + * padded out to `width' places. If flags&ZEROPAD, it should + * first be prefixed by any sign or other prefix; otherwise, + * it should be blank padded before the prefix is emitted. + * After any left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print the + * string proper, then emit zeroes required by any leftover + * floating precision; finally, if LADJUST, pad with blanks. + * + * Compute actual size, so we know how much to pad. + * size excludes decimal prec; realsz includes it. + */ + realsz = dprec > size ? dprec : size; + if (sign) + realsz++; + else if (flags & HEXPREFIX) + realsz+= 2; + + /* adjust ret */ + ret += width > realsz ? width : realsz; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0) { + n = width - realsz; + while (n-- > 0) + KPRINTF_PUTCHAR(' '); + } + + /* prefix */ + if (sign) { + KPRINTF_PUTCHAR(sign); + } else if (flags & HEXPREFIX) { + KPRINTF_PUTCHAR('0'); + KPRINTF_PUTCHAR(ch); + } + + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) { + n = width - realsz; + while (n-- > 0) + KPRINTF_PUTCHAR('0'); + } + + /* leading zeroes from decimal precision */ + n = dprec - size; + while (n-- > 0) + KPRINTF_PUTCHAR('0'); + + /* the string or number proper */ + for (; size--; cp++) + KPRINTF_PUTCHAR(*cp); + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) { + n = width - realsz; + while (n-- > 0) + KPRINTF_PUTCHAR(' '); + } + } + +done: + if ((oflags == TOBUFONLY) && (vp != NULL)) + *(char **)vp = sbuf; + (*v_flush)(); + + return ret; +} diff --git a/lib/librumprun_core/Makefile b/lib/librumprun_core/Makefile deleted file mode 100644 index 9984df3..0000000 --- a/lib/librumprun_core/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -LIB= rumprun_core -LIBISPRIVATE= # defined - -SRCS= init.c bmk_string.c memalloc.c sched.c subr_prf.c - -CPPFLAGS+= -I${.CURDIR}/../../include - -.include "${.CURDIR}/arch/${MACHINE}/Makefile.inc" - -.include diff --git a/lib/librumprun_core/arch/amd64/Makefile.inc b/lib/librumprun_core/arch/amd64/Makefile.inc deleted file mode 100644 index 80b2d56..0000000 --- a/lib/librumprun_core/arch/amd64/Makefile.inc +++ /dev/null @@ -1,6 +0,0 @@ -MYDIR:= ${.PARSEDIR} -.PATH: ${MYDIR} - -SRCS+= cpu_sched_switch.S - -.include "${MYDIR}/../x86/Makefile.inc" diff --git a/lib/librumprun_core/arch/amd64/cpu_sched_switch.S b/lib/librumprun_core/arch/amd64/cpu_sched_switch.S deleted file mode 100644 index 4747652..0000000 --- a/lib/librumprun_core/arch/amd64/cpu_sched_switch.S +++ /dev/null @@ -1,70 +0,0 @@ -/*- - **************************************************************************** - * (C) 2005 - Grzegorz Milos - Intel Research Cambridge - **************************************************************************** - * - * File: sched.c - * Author: Grzegorz Milos - * Changes: Robert Kaiser - * - * Date: Aug 2005 - * - * Environment: Xen Minimal OS - * Description: simple scheduler for Mini-Os - * - * The scheduler is non-preemptive (cooperative), and schedules according - * to Round Robin algorithm. - * - **************************************************************************** - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include - -ENTRY(bmk_cpu_sched_bouncer) - popq %rdi - popq %rbx - pushq $0 /* correct stack alignment for SSE */ - pushq $0 - xorq %rbp,%rbp - call *%rbx - call bmk_sched_exit -END(bmk_cpu_sched_bouncer) - -ENTRY(bmk__cpu_switch) - pushq %rbp - pushq %rbx - pushq %r12 - pushq %r13 - pushq %r14 - pushq %r15 - movq %rsp, (%rdi) /* save ESP */ - movq (%rsi), %rsp /* restore ESP */ - movq $1f, 8(%rdi) /* save EIP */ - pushq 8(%rsi) /* restore EIP */ - ret -1: - popq %r15 - popq %r14 - popq %r13 - popq %r12 - popq %rbx - popq %rbp - ret -END(bmk__cpu_switch) diff --git a/lib/librumprun_core/arch/i386/Makefile.inc b/lib/librumprun_core/arch/i386/Makefile.inc deleted file mode 100644 index 80b2d56..0000000 --- a/lib/librumprun_core/arch/i386/Makefile.inc +++ /dev/null @@ -1,6 +0,0 @@ -MYDIR:= ${.PARSEDIR} -.PATH: ${MYDIR} - -SRCS+= cpu_sched_switch.S - -.include "${MYDIR}/../x86/Makefile.inc" diff --git a/lib/librumprun_core/arch/i386/cpu_sched_switch.S b/lib/librumprun_core/arch/i386/cpu_sched_switch.S deleted file mode 100644 index cc9ec7d..0000000 --- a/lib/librumprun_core/arch/i386/cpu_sched_switch.S +++ /dev/null @@ -1,73 +0,0 @@ -/*- - **************************************************************************** - * (C) 2005 - Grzegorz Milos - Intel Research Cambridge - **************************************************************************** - * - * File: sched.c - * Author: Grzegorz Milos - * Changes: Robert Kaiser - * - * Date: Aug 2005 - * - * Environment: Xen Minimal OS - * Description: simple scheduler for Mini-Os - * - * The scheduler is non-preemptive (cooperative), and schedules according - * to Round Robin algorithm. - * - **************************************************************************** - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include - -ENTRY(bmk_cpu_sched_bouncer) - popl %eax - popl %ebx - pushl $0 - xorl %ebp,%ebp - pushl %eax - call *%ebx - call bmk_sched_exit -END(bmk_cpu_sched_bouncer) - -ENTRY(bmk__cpu_switch) - movl 4(%esp), %ecx /* prev */ - movl 8(%esp), %edx /* next */ - - /* reload tls for new thread */ - movl $0x18, %eax - movl %eax, %gs - - pushl %ebp - pushl %ebx - pushl %esi - pushl %edi - movl %esp, (%ecx) /* save ESP */ - movl (%edx), %esp /* restore ESP */ - movl $1f, 4(%ecx) /* save EIP */ - pushl 4(%edx) /* restore EIP */ - ret -1: - popl %edi - popl %esi - popl %ebx - popl %ebp - ret -END(bmk__cpu_switch) diff --git a/lib/librumprun_core/arch/x86/Makefile.inc b/lib/librumprun_core/arch/x86/Makefile.inc deleted file mode 100644 index 757c137..0000000 --- a/lib/librumprun_core/arch/x86/Makefile.inc +++ /dev/null @@ -1,4 +0,0 @@ -X86DIR:=${.PARSEDIR} -.PATH: ${X86DIR} - -SRCS+= cpu_sched.c diff --git a/lib/librumprun_core/arch/x86/cpu_sched.c b/lib/librumprun_core/arch/x86/cpu_sched.c deleted file mode 100644 index f9c945d..0000000 --- a/lib/librumprun_core/arch/x86/cpu_sched.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - **************************************************************************** - * (C) 2005 - Grzegorz Milos - Intel Research Cambridge - **************************************************************************** - * - * File: sched.c - * Author: Grzegorz Milos - * Changes: Robert Kaiser - * - * Date: Aug 2005 - * - * Environment: Xen Minimal OS - * Description: simple scheduler for Mini-Os - * - * The scheduler is non-preemptive (cooperative), and schedules according - * to Round Robin algorithm. - * - **************************************************************************** - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -static void -stack_push(void **stackp, unsigned long value) -{ - unsigned long *stack = *stackp; - - stack--; - *stack = value; - *stackp = stack; -} - -void -bmk_cpu_sched_create(struct bmk_thread *thread, struct bmk_tcb *tcb, - void (*f)(void *), void *arg, - void *stack_base, unsigned long stack_size) -{ - void *stack_top = (char *)stack_base + stack_size; - - /* Save pointer to the thread on the stack, used by current macro */ - *(unsigned long *)stack_base = (unsigned long)thread; - - /* these values are used by bmk_cpu_sched_bouncer() */ - stack_push(&stack_top, (unsigned long)f); - stack_push(&stack_top, (unsigned long)arg); - - tcb->btcb_sp = (unsigned long)stack_top; - tcb->btcb_ip = (unsigned long)bmk_cpu_sched_bouncer; -} - -struct bmk_thread * -bmk_cpu_sched_current(void) -{ - struct bmk_thread **current; - - current = (void *)((unsigned long)¤t & ~(bmk_stacksize-1)); - return *current; -}; diff --git a/lib/librumprun_core/bmk_string.c b/lib/librumprun_core/bmk_string.c deleted file mode 100644 index fb53980..0000000 --- a/lib/librumprun_core/bmk_string.c +++ /dev/null @@ -1,135 +0,0 @@ -/*- - * Copyright (c) 2014 Antti Kantee. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * The assumption is that these won't be used very often, - * only for the very low-level routines. - * - * Some code from public domain implementations. - */ - -#include -#include - -unsigned long -bmk_strlen(const char *str) -{ - unsigned long rv = 0; - - while (*str++) - rv++; - return rv; -} - -int -bmk_strcmp(const char *a, const char *b) -{ - - while (*a && *a++ == *b++) { - continue; - } - if (*a) { - a--; - b--; - } - return *a - *b; -} - -int -bmk_strncmp(const char *a, const char *b, unsigned long n) -{ - unsigned char u1, u2; - - while (n-- > 0) { - u1 = (unsigned char)*a++; - u2 = (unsigned char)*b++; - if (u1 != u2) - return u1 - u2; - if (u1 == '\0') - return 0; - } - return 0; -} - -char * -bmk_strcpy(char *d, const char *s) -{ - char *orig = d; - - while ((*d++ = *s++) != '\0') - continue; - return orig; -} - -char * -bmk_strncpy(char *d, const char *s, unsigned long n) -{ - char *orig = d; - - while ((*d++ = *s++) && n--) - continue; - while (n--) - *d++ = '\0'; - return orig; -} - -void * -bmk_memset(void *b, int c, unsigned long n) -{ - unsigned char *v = b; - - while (n--) - *v++ = (unsigned char)c; - - return b; -} - -void * -bmk_memcpy(void *d, const void *src, unsigned long n) -{ - unsigned char *dp; - const unsigned char *sp; - - dp = d; - sp = src; - - while (n--) - *dp++ = *sp++; - - return d; -} - -void * -bmk_memchr(const void *d, int c, unsigned long n) -{ - const unsigned char *p = d; - - while (n--) { - if (*p == (unsigned char)c) - return (void *)(unsigned long)p; - p++; - } - return NULL; -} diff --git a/lib/librumprun_core/init.c b/lib/librumprun_core/init.c deleted file mode 100644 index 215b59e..0000000 --- a/lib/librumprun_core/init.c +++ /dev/null @@ -1,41 +0,0 @@ -/*- - * Copyright (c) 2015 Antti Kantee. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -unsigned long bmk_stackpageorder; -unsigned long bmk_stacksize; -unsigned long bmk_pagesize; - -int -bmk_core_init(unsigned long stackpageorder, unsigned long pagesize) -{ - - bmk_stackpageorder = stackpageorder; - bmk_stacksize = (1< - -#include -#if defined(RCHECK) -#include -#endif -#if defined(RCHECK) || defined(MSTATS) -#include -#endif -#include -#include -#include - -#else - -#include -#include -#include -#include - -#define NULL (void *)0 -#define ASSERT(x) - -#endif - - -/* - * The overhead on a block is at least 4 bytes. When free, this space - * contains a pointer to the next free block, and the bottom two bits must - * be zero. When in use, the first byte is set to MAGIC, and the second - * byte is the size index. The remaining bytes are for alignment. - * If range checking is enabled then a second word holds the size of the - * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC). - * The order of elements is critical: ov_magic must overlay the low order - * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern. - */ -union overhead { - union overhead *ov_next; /* when free */ - struct { - unsigned long ovu_alignpad; /* padding for alignment */ - unsigned char ovu_magic; /* magic number */ - unsigned char ovu_index; /* bucket # */ -#ifdef RCHECK - unsigned short ovu_rmagic; /* range magic number */ - unsigned long ovu_size; /* actual block size */ -#endif - } ovu; -#define ov_alignpad ovu.ovu_alignpad -#define ov_magic ovu.ovu_magic -#define ov_index ovu.ovu_index -#define ov_rmagic ovu.ovu_rmagic -#define ov_size ovu.ovu_size -}; - -#define MAGIC 0xef /* magic # on accounting info */ -#define UNMAGIC 0x12 /* magic # != MAGIC */ -#define UNMAGIC2 0x24 /* magic # != MAGIC/UNMAGIC */ -#ifdef RCHECK -#define RMAGIC 0x5555 /* magic # on range info */ -#endif - -#ifdef RCHECK -#define RSLOP sizeof (unsigned short) -#else -#define RSLOP 0 -#endif - -/* - * nextf[i] is the pointer to the next free block of size 2^(i+MINSHIFT). The - * smallest allocatable block is 1< - -static void botch(const char *); - -/* - * NOTE: since this may be called while malloc_mutex is locked, stdio must not - * be used in this function. - */ -static void -botch(const char *s) -{ - struct iovec iov[3]; - - iov[0].iov_base = "\nassertion botched: "; - iov[0].iov_len = 20; - iov[1].iov_base = (void *)s; - iov[1].iov_len = strlen(s); - iov[2].iov_base = "\n"; - iov[2].iov_len = 1; - - /* - * This place deserves a word of warning: a cancellation point will - * occur when executing writev(), and we might be still owning - * malloc_mutex. At this point we need to disable cancellation - * until `after' abort() because i) establishing a cancellation handler - * might, depending on the implementation, result in another malloc() - * to be executed, and ii) it is really not desirable to let execution - * continue. `Fix me.' - * - * Note that holding mutex_lock during abort() is safe. - */ - - (void)writev(STDERR_FILENO, iov, 3); - abort(); -} -#endif - -void * -bmk_memalloc(unsigned long nbytes, unsigned long align) -{ - union overhead *op; - void *rv; - unsigned long allocbytes; - int bucket; - unsigned amt; - unsigned long alignpad; - - malloc_lock(); - - if (pagesz == 0) { - pagesz = bmk_pagesize; - ASSERT(pagesz > 0); - -#if 0 - op = (union overhead *)(void *)sbrk(0); - n = n - sizeof (*op) - ((long)op & (n - 1)); - if (n < 0) - n += pagesz; - if (n) { - if (sbrk((int)n) == (void *)-1) { - malloc_unlock(); - return (NULL); - } - } -#endif - - bucket = 0; - amt = 1< amt) { - amt <<= 1; - bucket++; - } - pagebucket = bucket; - } - - if (align & (align-1)) - return NULL; - if (align < MINALIGN) - align = MINALIGN; - - /* need at least this many bytes plus header to satisfy alignment */ - allocbytes = nbytes + ((sizeof(*op) + (align-1)) & ~(align-1)); - - /* - * Convert amount of memory requested into closest block size - * stored in hash buckets which satisfies request. - * Account for space used per block for accounting. - */ - if (allocbytes <= pagesz - RSLOP) { -#ifndef RCHECK - amt = 1< amt) { - amt <<= 1; - if (amt == 0) - return (NULL); - bucket++; - } - /* - * If nothing in hash bucket right now, - * request more memory from the system. - */ - if ((op = nextf[bucket]) == NULL) { - morecore(bucket); - if ((op = nextf[bucket]) == NULL) { - malloc_unlock(); - return (NULL); - } - } - /* remove from linked list */ - nextf[bucket] = op->ov_next; - - /* align op before returned memory */ - rv = (void *)(((unsigned long)(op+1) + align - 1) & ~(align - 1)); - alignpad = (unsigned long)rv - (unsigned long)op; - -#ifdef MEMALLOC_TESTING - memset(op, MAGIC, alignpad); -#endif - - op = ((union overhead *)rv)-1; - op->ov_magic = MAGIC; - op->ov_index = bucket; - op->ov_alignpad = alignpad; -#ifdef MSTATS - nmalloc[bucket]++; -#endif - malloc_unlock(); -#ifdef RCHECK - /* - * Record allocated size of block and - * bound space with magic numbers. - */ - op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1); - op->ov_rmagic = RMAGIC; - *(unsigned short *)((char *)(op + 1) + op->ov_size) = RMAGIC; -#endif - - return rv; -} - -void * -bmk_xmalloc(unsigned long howmuch) -{ - void *rv; - - rv = bmk_memalloc(howmuch, 0); - if (rv == NULL) - bmk_platform_halt("xmalloc failed"); - return rv; -} - -void * -bmk_memcalloc(unsigned long n, unsigned long size) -{ - void *v; - unsigned long tot = n * size; - - if (size != 0 && tot / size != n) - return NULL; - - if ((v = bmk_memalloc(tot, MINALIGN)) != NULL) { - bmk_memset(v, 0, tot); - } - return v; -} - -static void * -corealloc(int shift) -{ - void *v; - -#ifdef MEMALLOC_TESTING - v = malloc((1< 0) { - op->ov_next = - (union overhead *)(void *)((char *)(void *)op+(unsigned long)sz); - op = op->ov_next; - } - op->ov_next = NULL; -} - -void -bmk_memfree(void *cp) -{ - long size; - union overhead *op; - unsigned long alignpad; - void *origp; - - if (cp == NULL) - return; - op = ((union overhead *)cp)-1; - if (op->ov_magic != MAGIC) { -#ifdef MEMALLOC_TESTING - ASSERT(0); -#endif - return; /* sanity */ - } - -#ifdef RCHECK - ASSERT(op->ov_rmagic == RMAGIC); - ASSERT(*(unsigned short *)((char *)(op + 1) + op->ov_size) == RMAGIC); -#endif - size = op->ov_index; - alignpad = op->ov_alignpad; - ASSERT(size < NBUCKETS); - - malloc_lock(); - origp = (unsigned char *)cp - alignpad; - -#ifdef MEMALLOC_TESTING - { - unsigned long i; - - for (i = 0; - (unsigned char *)origp + i < (unsigned char *)op; - i++) { - ASSERT(*((unsigned char *)origp + i) == MAGIC); - - } - } -#endif - - op = (void *)origp; - op->ov_next = nextf[(unsigned int)size];/* also clobbers ov_magic */ - nextf[(unsigned int)size] = op; -#ifdef MSTATS - nmalloc[(unsigned long)size]--; -#endif - - malloc_unlock(); -} - -/* - * don't do any of "storage compaction" nonsense, "just" the three modes: - * + cp == NULL ==> malloc - * + nbytes == 0 ==> free - * + else ==> realloc - */ -void * -bmk_memrealloc(void *cp, unsigned long nbytes) -{ - union overhead *op; - unsigned long size; - unsigned long alignpad; - void *np; - - if (cp == NULL) - return bmk_memalloc(nbytes, MINALIGN); - - if (nbytes == 0) { - bmk_memfree(cp); - return NULL; - } - - op = ((union overhead *)cp)-1; - size = op->ov_index; - alignpad = op->ov_alignpad; - - /* don't bother "compacting". don't like it? don't use realloc! */ - if (((1<<(size+MINSHIFT)) - alignpad) >= nbytes) - return cp; - - /* we're gonna need a bigger bucket */ - np = bmk_memalloc(nbytes, 8); - if (np == NULL) - return NULL; - - bmk_memcpy(np, cp, (1<<(size+MINSHIFT)) - alignpad); - bmk_memfree(cp); - return np; -} - -#ifdef MSTATS -/* - * mstats - print out statistics about malloc - * - * Prints two lines of numbers, one showing the length of the free list - * for each size category, the second showing the number of mallocs - - * frees for each size category. - */ -void -mstats(const char *s) -{ - int i, j; - union overhead *p; - int totfree = 0, - totused = 0; - - fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s); - for (i = 0; i < NBUCKETS; i++) { - for (j = 0, p = nextf[i]; p; p = p->ov_next, j++) - ; - fprintf(stderr, " %d", j); - totfree += j * (1 << (i + 3)); - } - fprintf(stderr, "\nused:\t"); - for (i = 0; i < NBUCKETS; i++) { - fprintf(stderr, " %d", nmalloc[i]); - totused += nmalloc[i] * (1 << (i + 3)); - } - fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n", - totused, totfree); -} -#endif - -#ifdef MEMALLOC_TESTING - -#define TEST_MINALLOC 0 -#define TEST_MAXALLOC 64*1024 - -#define TEST_MINALIGN 1 -#define TEST_MAXALIGN 16 - -#define NALLOC 1024 -#define NRING 16 - -static void * -testalloc(void) -{ - void *v, *nv; - size_t size1, size2, align; - - /* doesn't give an even bucket distribution, but ... */ - size1 = random() % ((TEST_MAXALLOC-TEST_MINALLOC)+1) + TEST_MINALLOC; - align = random() % ((TEST_MAXALIGN-TEST_MINALIGN)+1) + TEST_MINALIGN; - - v = bmk_memalloc(size1, 1< -#include -#include -#include -#include -#include -#include - -#define TLS_COUNT 2 -#define NAME_MAXLEN 16 - -#define THREAD_RUNNABLE 0x01 -#define THREAD_MUSTJOIN 0x02 -#define THREAD_JOINED 0x04 -#define THREAD_EXTSTACK 0x08 -#define THREAD_TIMEDOUT 0x10 - -struct bmk_thread { - char bt_name[NAME_MAXLEN]; - - void *bt_tls[TLS_COUNT]; - - bmk_time_t bt_wakeup_time; - - int bt_flags; - int bt_errno; - - void *bt_stackbase; - - void *bt_cookie; - - /* MD thread control block */ - struct bmk_tcb bt_tcb; - - TAILQ_ENTRY(bmk_thread) bt_entries; -}; - -static TAILQ_HEAD(, bmk_thread) zombies = TAILQ_HEAD_INITIALIZER(zombies); -static TAILQ_HEAD(, bmk_thread) threads = TAILQ_HEAD_INITIALIZER(threads); - -static void (*scheduler_hook)(void *, void *); - -static int -is_runnable(struct bmk_thread *thread) -{ - - return thread->bt_flags & THREAD_RUNNABLE; -} - -static void -set_runnable(struct bmk_thread *thread) -{ - - thread->bt_flags |= THREAD_RUNNABLE; -} - -static void -clear_runnable(struct bmk_thread *thread) -{ - - thread->bt_flags &= ~THREAD_RUNNABLE; -} - -static void -stackalloc(void **stack, unsigned long *ss) -{ - - *stack = bmk_platform_allocpg2(bmk_stackpageorder); - *ss = bmk_stacksize; -} - -static void -stackfree(struct bmk_thread *thread) -{ - - bmk_platform_freepg2(thread->bt_stackbase, bmk_stackpageorder); -} - -static void -print_threadinfo(struct bmk_thread *thread) -{ - - bmk_printf("thread \"%s\" at %p, flags 0x%x\n", - thread->bt_name, thread, thread->bt_flags); -} - -static void -sched_switch(struct bmk_thread *prev, struct bmk_thread *next) -{ - - if (scheduler_hook) - scheduler_hook(prev->bt_cookie, next->bt_cookie); - bmk_platform_cpu_sched_switch(&prev->bt_tcb, &next->bt_tcb); -} - -struct bmk_thread * -bmk_sched_current(void) -{ - - return bmk_cpu_sched_current(); -} - -void -bmk_sched_dumpqueue(void) -{ - struct bmk_thread *thr; - - bmk_printf("BEGIN schedqueue dump\n"); - TAILQ_FOREACH(thr, &threads, bt_entries) { - print_threadinfo(thr); - } - bmk_printf("END schedqueue dump\n"); -} - -void -bmk_sched(void) -{ - struct bmk_thread *prev, *next, *thread, *tmp; - unsigned long flags; - - prev = bmk_sched_current(); - flags = bmk_platform_splhigh(); - -#if 0 - /* XXX */ - if (_minios_in_hypervisor_callback) { - minios_printk("Must not call schedule() from a callback\n"); - BUG(); - } -#endif - - if (flags) { - bmk_platform_halt("Must not call sched() with IRQs disabled\n"); - } - - /* could do time management a bit better here */ - do { - bmk_time_t tm, wakeup; - - /* block domain for max 1s */ - tm = bmk_clock_monotonic(); - wakeup = tm + 1*1000*1000*1000ULL; - - next = NULL; - TAILQ_FOREACH_SAFE(thread, &threads, bt_entries, tmp) { - if (!is_runnable(thread) - && thread->bt_wakeup_time >= 0) { - if (thread->bt_wakeup_time <= tm) { - thread->bt_flags |= THREAD_TIMEDOUT; - bmk_sched_wake(thread); - } else if (thread->bt_wakeup_time < wakeup) - wakeup = thread->bt_wakeup_time; - } - if (is_runnable(thread)) { - next = thread; - /* Put this thread on the end of the list */ - TAILQ_REMOVE(&threads, thread, bt_entries); - TAILQ_INSERT_TAIL(&threads, thread, bt_entries); - break; - } - } - if (next) - break; - - /* sleep for a while */ - bmk_platform_block(wakeup); - } while (1); - - bmk_platform_splx(flags); - - if (prev != next) { - sched_switch(prev, next); - } - - /* reaper */ - TAILQ_FOREACH_SAFE(thread, &zombies, bt_entries, tmp) { - if (thread != prev) { - TAILQ_REMOVE(&zombies, thread, bt_entries); - if ((thread->bt_flags & THREAD_EXTSTACK) == 0) - stackfree(thread); - bmk_memfree(thread); - } - } -} - -/* - * Allocate tls and initialize it. - * - * XXX: this needs to change in the future so that - * we put the tcb in the same space instead of having multiple - * random copies flying around. - */ -extern const char _tdata_start[], _tdata_end[]; -extern const char _tbss_start[], _tbss_end[]; -static int -allocothertls(struct bmk_thread *thread) -{ - const unsigned long tdatasize = _tdata_end - _tdata_start; - const unsigned long tbsssize = _tbss_end - _tbss_start; - struct bmk_tcb *tcb = &thread->bt_tcb; - char *tlsmem; - - tlsmem = bmk_memalloc(tdatasize + tbsssize, 0); - - bmk_memcpy(tlsmem, _tdata_start, tdatasize); - bmk_memset(tlsmem + tdatasize, 0, tbsssize); - - tcb->btcb_tp = (unsigned long)(tlsmem + tdatasize + tbsssize); - tcb->btcb_tpsize = tdatasize + tbsssize; - - return 0; -} - -static void -freeothertls(struct bmk_thread *thread) -{ - void *mem; - - mem = (void *)(thread->bt_tcb.btcb_tp-thread->bt_tcb.btcb_tpsize); - bmk_memfree(mem); -} - -struct bmk_thread * -bmk_sched_create(const char *name, void *cookie, int joinable, - void (*f)(void *), void *data, - void *stack_base, unsigned long stack_size) -{ - struct bmk_thread *thread; - unsigned long flags; - - thread = bmk_xmalloc(sizeof(*thread)); - bmk_memset(thread, 0, sizeof(*thread)); - bmk_strncpy(thread->bt_name, name, sizeof(thread->bt_name)-1); - - if (!stack_base) { - bmk_assert(stack_size == 0); - stackalloc(&stack_base, &stack_size); - } else { - thread->bt_flags = THREAD_EXTSTACK; - } - thread->bt_stackbase = stack_base; - if (joinable) - thread->bt_flags |= THREAD_MUSTJOIN; - - bmk_cpu_sched_create(thread, &thread->bt_tcb, f, data, - stack_base, stack_size); - - thread->bt_cookie = cookie; - - thread->bt_wakeup_time = -1; - - flags = bmk_platform_splhigh(); - TAILQ_INSERT_TAIL(&threads, thread, bt_entries); - bmk_platform_splx(flags); - - allocothertls(thread); - set_runnable(thread); - - return thread; -} - -struct join_waiter { - struct bmk_thread *jw_thread; - struct bmk_thread *jw_wanted; - TAILQ_ENTRY(join_waiter) jw_entries; -}; -static TAILQ_HEAD(, join_waiter) joinwq = TAILQ_HEAD_INITIALIZER(joinwq); - -void -bmk_sched_exit(void) -{ - struct bmk_thread *thread = bmk_sched_current(); - struct join_waiter *jw_iter; - unsigned long flags; - - /* if joinable, gate until we are allowed to exit */ - flags = bmk_platform_splhigh(); - while (thread->bt_flags & THREAD_MUSTJOIN) { - thread->bt_flags |= THREAD_JOINED; - bmk_platform_splx(flags); - - /* see if the joiner is already there */ - TAILQ_FOREACH(jw_iter, &joinwq, jw_entries) { - if (jw_iter->jw_wanted == thread) { - bmk_sched_wake(jw_iter->jw_thread); - break; - } - } - bmk_sched_block(thread); - bmk_sched(); - flags = bmk_platform_splhigh(); - } - freeothertls(thread); - - /* Remove from the thread list */ - TAILQ_REMOVE(&threads, thread, bt_entries); - clear_runnable(thread); - /* Put onto exited list */ - TAILQ_INSERT_HEAD(&zombies, thread, bt_entries); - bmk_platform_splx(flags); - - /* bye */ - bmk_sched(); - bmk_platform_halt("schedule() returned for a dead thread!\n"); -} - -void -bmk_sched_join(struct bmk_thread *joinable) -{ - struct join_waiter jw; - struct bmk_thread *thread = bmk_sched_current(); - unsigned long flags; - - bmk_assert(joinable->bt_flags & THREAD_MUSTJOIN); - - flags = bmk_platform_splhigh(); - /* wait for exiting thread to hit thread_exit() */ - while ((joinable->bt_flags & THREAD_JOINED) == 0) { - bmk_platform_splx(flags); - - jw.jw_thread = thread; - jw.jw_wanted = joinable; - TAILQ_INSERT_TAIL(&joinwq, &jw, jw_entries); - bmk_sched_block(thread); - bmk_sched(); - TAILQ_REMOVE(&joinwq, &jw, jw_entries); - - flags = bmk_platform_splhigh(); - } - - /* signal exiting thread that we have seen it and it may now exit */ - bmk_assert(joinable->bt_flags & THREAD_JOINED); - joinable->bt_flags &= ~THREAD_MUSTJOIN; - bmk_platform_splx(flags); - - bmk_sched_wake(joinable); -} - -void -bmk_sched_block_timeout(struct bmk_thread *thread, bmk_time_t deadline) -{ - - thread->bt_wakeup_time = deadline; - clear_runnable(thread); -} - -void -bmk_sched_block(struct bmk_thread *thread) -{ - - bmk_sched_block_timeout(thread, -1); -} - -int -bmk_sched_nanosleep_abstime(bmk_time_t nsec) -{ - struct bmk_thread *thread = bmk_sched_current(); - int rv; - - thread->bt_flags &= ~THREAD_TIMEDOUT; - thread->bt_wakeup_time = nsec; - clear_runnable(thread); - bmk_sched(); - - rv = !!(thread->bt_flags & THREAD_TIMEDOUT); - thread->bt_flags &= ~THREAD_TIMEDOUT; - return rv; -} - -int -bmk_sched_nanosleep(bmk_time_t nsec) -{ - - return bmk_sched_nanosleep_abstime(nsec + bmk_clock_monotonic()); -} - -void -bmk_sched_wake(struct bmk_thread *thread) -{ - - thread->bt_wakeup_time = -1; - set_runnable(thread); -} - -void -bmk_sched_init(void (*mainfun)(void *), void *arg) -{ - struct bmk_thread *mainthread; - struct bmk_thread initthread; - - mainthread = bmk_sched_create("main", NULL, 0, mainfun, arg, NULL, 0); - if (mainthread == NULL) - bmk_platform_halt("failed to create main thread"); - - bmk_memset(&initthread, 0, sizeof(initthread)); - bmk_strcpy(initthread.bt_name, "init"); - sched_switch(&initthread, mainthread); - - bmk_platform_halt("bmk_sched_init unreachable"); -} - -void -bmk_sched_set_hook(void (*f)(void *, void *)) -{ - - scheduler_hook = f; -} - -struct bmk_thread * -bmk_sched_init_mainlwp(void *cookie) -{ - struct bmk_thread *current = bmk_sched_current(); - - current->bt_cookie = cookie; - allocothertls(current); - return current; -} - -const char * -bmk_sched_threadname(struct bmk_thread *thread) -{ - - return thread->bt_name; -} - -int * -bmk_sched_geterrno(void) -{ - struct bmk_thread *thread = bmk_sched_current(); - - return &thread->bt_errno; -} - -void -bmk_sched_settls(struct bmk_thread *thread, unsigned int which, void *value) -{ - - if (which >= TLS_COUNT) { - bmk_platform_halt("out of bmk sched tls space"); - } - thread->bt_tls[which] = value; -} - -void * -bmk_sched_gettls(struct bmk_thread *thread, unsigned int which) -{ - - if (which >= TLS_COUNT) { - bmk_platform_halt("out of bmk sched tls space"); - } - return thread->bt_tls[which]; -} - -void -bmk_sched_yield(void) -{ - struct bmk_thread *current = bmk_sched_current(); - - TAILQ_REMOVE(&threads, current, bt_entries); - TAILQ_INSERT_TAIL(&threads, current, bt_entries); - bmk_sched(); -} diff --git a/lib/librumprun_core/subr_prf.c b/lib/librumprun_core/subr_prf.c deleted file mode 100644 index 415c62b..0000000 --- a/lib/librumprun_core/subr_prf.c +++ /dev/null @@ -1,638 +0,0 @@ -/* $NetBSD: subr_prf.c,v 1.157 2015/02/04 07:10:47 msaitoh Exp $ */ - -/*- - * Copyright (c) 1986, 1988, 1991, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)subr_prf.c 8.4 (Berkeley) 5/4/95 - */ - -/* - * This is the NetBSD kernel printf code heavily stripped. Format support - * is the same, but the wrappers for calling printf have been reduced - * down to: - * + printf - * + snprintf - * + vnsprintf - */ - -#define _BMK_PRINTF_VA -#include -#include -#include - -#define TOBUFONLY 0x01 -#define TOCONS 0x02 - -#define __UNCONST(x) ((void *)(unsigned long)(x)) -#define KPRINTF_BUFSIZE (sizeof(long long)*8/3 + 2) - -/* - * local prototypes - */ - -static void cons_putchar(int, int); -static int kprintf(const char *, int, void *, char *, va_list); - -/* - * globals - */ - -static void -nullfun(void) -{ - - return; -} - -static void (*v_flush)(void); -static void (*v_putc)(int); - -void -bmk_printf_init(void (*putc)(int), void (*flush)(void)) -{ - - v_putc = putc; - if (flush == NULL) - flush = nullfun; - v_flush = flush; -} - -static const char hexdigits[] = "0123456789abcdef"; -static const char HEXDIGITS[] = "0123456789ABCDEF"; - -/* - * functions - */ - -/* dmesg ring buffer */ -#ifndef BMK_DMESG_SIZE -#define BMK_DMESG_SIZE (16*1024) -#endif -static char bmk_dmesg[BMK_DMESG_SIZE]; -static int bmk_dmesgoff; - -/* - * putchar: print a single character on console or user terminal. - * - * => if console, then the last MSGBUFS chars are saved in msgbuf - * for inspection later (e.g. dmesg/syslog) - * => we must already be in the mutex! - */ -static void -cons_putchar(int c, int flags) -{ - - bmk_dmesg[bmk_dmesgoff] = c; - if (++bmk_dmesgoff == sizeof(bmk_dmesg)-1) - bmk_dmesgoff = 0; - (*v_putc)(c); -} - -static void -kprintf_lock(void) -{ - - /* XXX */ -} - -static void -kprintf_unlock(void) -{ - - /* XXX */ -} - -/* - * bmk_printf: print a message to the console - */ -void -bmk_printf(const char *fmt, ...) -{ - va_list ap; - - kprintf_lock(); - - va_start(ap, fmt); - kprintf(fmt, TOCONS, NULL, NULL, ap); - va_end(ap); - - kprintf_unlock(); -} - -/* - * bmk_vprintf: print a message to the console [already have - * va_list] - */ -void -bmk_vprintf(const char *fmt, va_list ap) -{ - kprintf_lock(); - - kprintf(fmt, TOCONS, NULL, NULL, ap); - - kprintf_unlock(); -} - -/* - * bmk_snprintf: print a message to a buffer - */ -int -bmk_snprintf(char *bf, unsigned long size, const char *fmt, ...) -{ - int retval; - va_list ap; - - va_start(ap, fmt); - retval = bmk_vsnprintf(bf, size, fmt, ap); - va_end(ap); - - return retval; -} - -/* - * bmk_vsnprintf: print a message to a buffer [already have va_list] - */ -int -bmk_vsnprintf(char *bf, unsigned long size, const char *fmt, va_list ap) -{ - int retval; - char *p; - - p = bf + size; - retval = kprintf(fmt, TOBUFONLY, &p, bf, ap); - if (bf && size > 0) { - /* nul terminate */ - if (size <= (unsigned long)retval) - bf[size - 1] = '\0'; - else - bf[retval] = '\0'; - } - return retval; -} - -/* - * kprintf: scaled down version of printf(3). - * - * this version based on vfprintf() from libc which was derived from - * software contributed to Berkeley by Chris Torek. - * - * NOTE: The kprintf mutex must be held if we're going TOBUF or TOCONS! - */ - -/* - * macros for converting digits to letters and vice versa - */ -#define to_digit(c) ((c) - '0') -#define is_digit(c) ((unsigned)to_digit(c) <= 9) -#define to_char(n) ((n) + '0') - -/* - * flags used during conversion. - */ -#define ALT 0x001 /* alternate form */ -#define HEXPREFIX 0x002 /* add 0x or 0X prefix */ -#define LADJUST 0x004 /* left adjustment */ -#define LONGDBL 0x008 /* long double; unimplemented */ -#define LONGINT 0x010 /* long integer */ -#define QUADINT 0x020 /* quad integer */ -#define SHORTINT 0x040 /* short integer */ -#define MAXINT 0x080 /* intmax_t */ -#define PTRINT 0x100 /* intptr_t */ -#define SIZEINT 0x200 /* size_t */ -#define ZEROPAD 0x400 /* zero (as opposed to blank) pad */ -#define FPT 0x800 /* Floating point number */ - - /* - * To extend shorts properly, we need both signed and unsigned - * argument extraction methods. - */ -#define SARG() \ - (flags&MAXINT ? va_arg(ap, long long) : \ - flags&PTRINT ? va_arg(ap, long) : \ - flags&SIZEINT ? va_arg(ap, long) : /* XXX */ \ - flags&QUADINT ? va_arg(ap, long long) : \ - flags&LONGINT ? va_arg(ap, long) : \ - flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ - (long)va_arg(ap, int)) -#define UARG() \ - (flags&MAXINT ? va_arg(ap, unsigned long long) : \ - flags&PTRINT ? va_arg(ap, unsigned long) : \ - flags&SIZEINT ? va_arg(ap, unsigned long) : \ - flags&QUADINT ? va_arg(ap, unsigned long long) : \ - flags&LONGINT ? va_arg(ap, unsigned long) : \ - flags&SHORTINT ? (unsigned long)(unsigned long)va_arg(ap, int) : \ - (unsigned long)va_arg(ap, unsigned int)) - -#define KPRINTF_PUTCHAR(C) { \ - if (oflags == TOBUFONLY) { \ - if (sbuf && ((vp == NULL) || (sbuf < tailp))) \ - *sbuf++ = (C); \ - } else { \ - cons_putchar((C), oflags); \ - } \ -} - -/* - * Guts of kernel printf. Note, we already expect to be in a mutex! - */ -static int -kprintf(const char *fmt0, int oflags, void *vp, char *sbuf, va_list ap) -{ - int ret = 0; /* return value accumulator */ - const char *fmt; /* format string */ - int ch; /* character from fmt */ - int n; /* handy integer (short term usage) */ - char *cp; /* handy char pointer (short term usage) */ - int flags; /* flags as above */ - int width; /* width from format (%8d), or 0 */ - int prec; /* precision from format (%.3d), or -1 */ - char sign; /* sign prefix (' ', '+', '-', or \0) */ - - unsigned long long _uquad; /* integer arguments %[diouxX] */ - enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ - int dprec; /* a copy of prec if [diouxX], 0 otherwise */ - int realsz; /* field size expanded by dprec */ - int size; /* size of converted field or string */ - const char *xdigs; /* digits for [xX] conversion */ - char bf[KPRINTF_BUFSIZE]; /* space for %c, %[diouxX] */ - char *tailp; /* tail pointer for snprintf */ - - if (oflags == TOBUFONLY && (vp != NULL)) - tailp = *(char **)vp; - else - tailp = NULL; - - cp = NULL; /* XXX: shutup gcc */ - size = 0; /* XXX: shutup gcc */ - - fmt = fmt0; - ret = 0; - - xdigs = NULL; /* XXX: shut up gcc warning */ - - /* - * Scan the format for conversions (`%' character). - */ - for (;;) { - for (; *fmt != '%' && *fmt; fmt++) { - ret++; - KPRINTF_PUTCHAR(*fmt); - } - if (*fmt == 0) - goto done; - - fmt++; /* skip over '%' */ - - flags = 0; - dprec = 0; - width = 0; - prec = -1; - sign = '\0'; - -rflag: ch = *fmt++; -reswitch: switch (ch) { - case ' ': - /* - * ``If the space and + flags both appear, the space - * flag will be ignored.'' - * -- ANSI X3J11 - */ - if (!sign) - sign = ' '; - goto rflag; - case '#': - flags |= ALT; - goto rflag; - case '*': - /* - * ``A negative field width argument is taken as a - * - flag followed by a positive field width.'' - * -- ANSI X3J11 - * They don't exclude field widths read from args. - */ - if ((width = va_arg(ap, int)) >= 0) - goto rflag; - width = -width; - /* FALLTHROUGH */ - case '-': - flags |= LADJUST; - goto rflag; - case '+': - sign = '+'; - goto rflag; - case '.': - if ((ch = *fmt++) == '*') { - n = va_arg(ap, int); - prec = n < 0 ? -1 : n; - goto rflag; - } - n = 0; - while (is_digit(ch)) { - n = 10 * n + to_digit(ch); - ch = *fmt++; - } - prec = n < 0 ? -1 : n; - goto reswitch; - case '0': - /* - * ``Note that 0 is taken as a flag, not as the - * beginning of a field width.'' - * -- ANSI X3J11 - */ - flags |= ZEROPAD; - goto rflag; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - n = 0; - do { - n = 10 * n + to_digit(ch); - ch = *fmt++; - } while (is_digit(ch)); - width = n; - goto reswitch; - case 'h': - flags |= SHORTINT; - goto rflag; - case 'j': - flags |= MAXINT; - goto rflag; - case 'l': - if (*fmt == 'l') { - fmt++; - flags |= QUADINT; - } else { - flags |= LONGINT; - } - goto rflag; - case 'q': - flags |= QUADINT; - goto rflag; - case 't': - flags |= PTRINT; - goto rflag; - case 'z': - flags |= SIZEINT; - goto rflag; - case 'c': - *(cp = bf) = va_arg(ap, int); - size = 1; - sign = '\0'; - break; - case 'D': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'd': - case 'i': - _uquad = SARG(); - if ((long long)_uquad < 0) { - _uquad = -_uquad; - sign = '-'; - } - base = DEC; - goto number; - case 'n': - if (flags & MAXINT) - *va_arg(ap, long long *) = ret; - else if (flags & PTRINT) - *va_arg(ap, long *) = ret; - else if (flags & SIZEINT) - *va_arg(ap, long *) = ret; - else if (flags & QUADINT) - *va_arg(ap, long long *) = ret; - else if (flags & LONGINT) - *va_arg(ap, long *) = ret; - else if (flags & SHORTINT) - *va_arg(ap, short *) = ret; - else - *va_arg(ap, int *) = ret; - continue; /* no output */ - case 'O': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'o': - _uquad = UARG(); - base = OCT; - goto nosign; - case 'p': - /* - * ``The argument shall be a pointer to void. The - * value of the pointer is converted to a sequence - * of printable characters, in an implementation- - * defined manner.'' - * -- ANSI X3J11 - */ - /* NOSTRICT */ - _uquad = (unsigned long)va_arg(ap, void *); - base = HEX; - xdigs = hexdigits; - flags |= HEXPREFIX; - ch = 'x'; - goto nosign; - case 's': - if ((cp = va_arg(ap, char *)) == NULL) - /*XXXUNCONST*/ - cp = __UNCONST("(null)"); - if (prec >= 0) { - /* - * can't use strlen; can only look for the - * NUL in the first `prec' characters, and - * strlen() will go further. - */ - char *p = bmk_memchr(cp, 0, prec); - - if (p != NULL) { - size = p - cp; - if (size > prec) - size = prec; - } else - size = prec; - } else - size = bmk_strlen(cp); - sign = '\0'; - break; - case 'U': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'u': - _uquad = UARG(); - base = DEC; - goto nosign; - case 'X': - xdigs = HEXDIGITS; - goto hex; - case 'x': - xdigs = hexdigits; -hex: _uquad = UARG(); - base = HEX; - /* leading 0x/X only if non-zero */ - if (flags & ALT && _uquad != 0) - flags |= HEXPREFIX; - - /* unsigned conversions */ -nosign: sign = '\0'; - /* - * ``... diouXx conversions ... if a precision is - * specified, the 0 flag will be ignored.'' - * -- ANSI X3J11 - */ -number: if ((dprec = prec) >= 0) - flags &= ~ZEROPAD; - - /* - * ``The result of converting a zero value with an - * explicit precision of zero is no characters.'' - * -- ANSI X3J11 - */ - cp = bf + KPRINTF_BUFSIZE; - if (_uquad != 0 || prec != 0) { - /* - * Unsigned mod is hard, and unsigned mod - * by a constant is easier than that by - * a variable; hence this switch. - */ - switch (base) { - case OCT: - do { - *--cp = to_char(_uquad & 7); - _uquad >>= 3; - } while (_uquad); - /* handle octal leading 0 */ - if (flags & ALT && *cp != '0') - *--cp = '0'; - break; - - case DEC: - /* many numbers are 1 digit */ - while (_uquad >= 10) { - *--cp = to_char(_uquad % 10); - _uquad /= 10; - } - *--cp = to_char(_uquad); - break; - - case HEX: - do { - *--cp = xdigs[_uquad & 15]; - _uquad >>= 4; - } while (_uquad); - break; - - default: - /*XXXUNCONST*/ - cp = __UNCONST("bug in kprintf: bad base"); - size = bmk_strlen(cp); - goto skipsize; - } - } - size = bf + KPRINTF_BUFSIZE - cp; - skipsize: - break; - default: /* "%?" prints ?, unless ? is NUL */ - if (ch == '\0') - goto done; - /* pretend it was %c with argument ch */ - cp = bf; - *cp = ch; - size = 1; - sign = '\0'; - break; - } - - /* - * All reasonable formats wind up here. At this point, `cp' - * points to a string which (if not flags&LADJUST) should be - * padded out to `width' places. If flags&ZEROPAD, it should - * first be prefixed by any sign or other prefix; otherwise, - * it should be blank padded before the prefix is emitted. - * After any left-hand padding and prefixing, emit zeroes - * required by a decimal [diouxX] precision, then print the - * string proper, then emit zeroes required by any leftover - * floating precision; finally, if LADJUST, pad with blanks. - * - * Compute actual size, so we know how much to pad. - * size excludes decimal prec; realsz includes it. - */ - realsz = dprec > size ? dprec : size; - if (sign) - realsz++; - else if (flags & HEXPREFIX) - realsz+= 2; - - /* adjust ret */ - ret += width > realsz ? width : realsz; - - /* right-adjusting blank padding */ - if ((flags & (LADJUST|ZEROPAD)) == 0) { - n = width - realsz; - while (n-- > 0) - KPRINTF_PUTCHAR(' '); - } - - /* prefix */ - if (sign) { - KPRINTF_PUTCHAR(sign); - } else if (flags & HEXPREFIX) { - KPRINTF_PUTCHAR('0'); - KPRINTF_PUTCHAR(ch); - } - - /* right-adjusting zero padding */ - if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) { - n = width - realsz; - while (n-- > 0) - KPRINTF_PUTCHAR('0'); - } - - /* leading zeroes from decimal precision */ - n = dprec - size; - while (n-- > 0) - KPRINTF_PUTCHAR('0'); - - /* the string or number proper */ - for (; size--; cp++) - KPRINTF_PUTCHAR(*cp); - /* left-adjusting padding (always blank) */ - if (flags & LADJUST) { - n = width - realsz; - while (n-- > 0) - KPRINTF_PUTCHAR(' '); - } - } - -done: - if ((oflags == TOBUFONLY) && (vp != NULL)) - *(char **)vp = sbuf; - (*v_flush)(); - - return ret; -} diff --git a/platform/baremetal/Makefile b/platform/baremetal/Makefile index 639ffa3..0d895be 100644 --- a/platform/baremetal/Makefile +++ b/platform/baremetal/Makefile @@ -73,12 +73,12 @@ RUMPKERN_LIB= ${LIBS_VIO_NET} \ ${LIBS_SYSPROXY} \ -lrumpdev -lrumpvfs -lrump -COREDIR:= $(shell pwd)/../../lib/librumprun_core +COREDIR:= $(shell pwd)/../../lib/libbmk_core BASEDIR:= $(shell pwd)/../../lib/librumprun_base RUMPUSERDIR:= $(shell pwd)/../../lib/librumprun_rumpuser OBJS_BMK+= init.o -LIBS_USER= -L${BASEDIR}/baremetal -L${COREDIR}/baremetal -L${RUMPUSERDIR}/baremetal -lrumprun_rumpuser --start-group -lrumprun_base -lpthread -lc --end-group -lrumprun_core +LIBS_USER= -L${BASEDIR}/baremetal -L${COREDIR}/baremetal -L${RUMPUSERDIR}/baremetal -lrumprun_rumpuser --start-group -lrumprun_base -lpthread -lc --end-group -lbmk_core RUMP_LDLIBS= --whole-archive ${RUMPKERN_LIB} --no-whole-archive ${LIBS_USER} OBJS= ${OBJS_BMK} ${OBJS_APP} @@ -102,7 +102,7 @@ ${BASEDIR}/baremetal/librumprun_base.a: && ${RUMPMAKE} MAKEOBJDIR=baremetal obj \ && ${RUMPMAKE} MAKEOBJDIR=baremetal dependall ) -${COREDIR}/baremetal/librumprun_core.a: +${COREDIR}/baremetal/libbmk_core.a: ( cd ${COREDIR} \ && ${RUMPMAKE} MAKEOBJDIR=baremetal obj \ && ${RUMPMAKE} MAKEOBJDIR=baremetal dependall ) @@ -112,7 +112,7 @@ ${RUMPUSERDIR}/baremetal/librumprun_rumpuser.a: && ${RUMPMAKE} MAKEOBJDIR=baremetal obj \ && ${RUMPMAKE} MAKEOBJDIR=baremetal dependall ) -rumprun.o: ${OBJS} ${BASEDIR}/baremetal/librumprun_base.a ${COREDIR}/baremetal/librumprun_core.a ${RUMPUSERDIR}/baremetal/librumprun_rumpuser.a +rumprun.o: ${OBJS} ${BASEDIR}/baremetal/librumprun_base.a ${COREDIR}/baremetal/libbmk_core.a ${RUMPUSERDIR}/baremetal/librumprun_rumpuser.a ${CC} -nostdlib ${CFLAGS} -Wl,-r ${OBJS_BMK} -o $@ tests: rumprun.o app-tools diff --git a/platform/xen/Makefile b/platform/xen/Makefile index 8284f1d..ec2cc51 100644 --- a/platform/xen/Makefile +++ b/platform/xen/Makefile @@ -32,7 +32,7 @@ ifeq ($(TARGET_ARCH),x86_64) CFLAGS += -mno-red-zone -fno-reorder-blocks -fno-asynchronous-unwind-tables endif -COREDIR:= $(shell pwd)/../../lib/librumprun_core +COREDIR:= $(shell pwd)/../../lib/libbmk_core BASEDIR:= $(shell pwd)/../../lib/librumprun_base RUMPUSERDIR:= $(shell pwd)/../../lib/librumprun_rumpuser @@ -47,7 +47,7 @@ RUMP_LIBS_NET+= -lrumpnet_local -lrumpnet_net -lrumpxen_xendev -lrumpnet # Define some default flags for linking. RUMP_LDLIBS = --whole-archive ${RUMP_LIBS_FS} ${RUMP_LIBS_NET} ${RUMP_LIBS_PCI} ${RUMP_LIBS_SYSPROXY} -lrumpxen_tc -lrump --no-whole-archive -RUMP_LDLIBS := ${RUMP_LDLIBS} -L${BASEDIR}/xen -L${COREDIR}/xen -L${RUMPUSERDIR}/xen -lrumprun_rumpuser --start-group -lrumprun_base -lpthread -lc --end-group -lrumprun_core +RUMP_LDLIBS := ${RUMP_LDLIBS} -L${BASEDIR}/xen -L${COREDIR}/xen -L${RUMPUSERDIR}/xen -lrumprun_rumpuser --start-group -lrumprun_base -lpthread -lc --end-group -lbmk_core LDFLAGS := -L$(abspath rump/lib) @@ -81,7 +81,7 @@ ${BASEDIR}/xen/librumprun_base.a: && ${RUMPMAKE} MAKEOBJDIR=xen obj \ && ${RUMPMAKE} MAKEOBJDIR=xen dependall ) -${COREDIR}/xen/librumprun_core.a: +${COREDIR}/xen/libbmk_core.a: ( cd ${COREDIR} \ && ${RUMPMAKE} MAKEOBJDIR=xen obj \ && ${RUMPMAKE} MAKEOBJDIR=xen dependall ) @@ -94,7 +94,7 @@ ${RUMPUSERDIR}/xen/librumprun_rumpuser.a: .PHONY: rumprun rumprun: $(OBJ_DIR)/rumprun.o -$(OBJ_DIR)/rumprun.o: $(RUMP_OBJS) ${BASEDIR}/xen/librumprun_base.a ${COREDIR}/xen/librumprun_core.a ${RUMPUSERDIR}/xen/librumprun_rumpuser.a +$(OBJ_DIR)/rumprun.o: $(RUMP_OBJS) ${BASEDIR}/xen/librumprun_base.a ${COREDIR}/xen/libbmk_core.a ${RUMPUSERDIR}/xen/librumprun_rumpuser.a $(CC) -Wl,-r $(CFLAGS) $(LDFLAGS) $(RUMP_OBJS) -nostdlib -o $@ APP_TOOLS_TARGETARCH= $(TARGET_ARCH)