mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 10:53:16 +01:00
Initial commit
This commit is contained in:
12
src/lib/SConscript
Normal file
12
src/lib/SConscript
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
# Inherit global environment
|
||||
Import('env')
|
||||
Import('config_symbols')
|
||||
# The set of source files associated with this SConscript file.
|
||||
src_local = ['printk.c', 'putc.c', 'string.c', 'bit.c', 'wait.c', 'mutex.c', 'idpool.c', 'memcache.c']
|
||||
if "ARCH_TEST" not in config_symbols:
|
||||
obj = env.Object(src_local)
|
||||
else:
|
||||
obj = []
|
||||
Return('obj')
|
||||
52
src/lib/bit.c
Normal file
52
src/lib/bit.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Bit manipulation functions.
|
||||
*
|
||||
* Copyright (C) 2007 Bahadir Balban
|
||||
*/
|
||||
#include <l4/lib/bit.h>
|
||||
#include INC_GLUE(memory.h)
|
||||
|
||||
/* Emulation of ARM's CLZ (count leading zeroes) instruction */
|
||||
unsigned int __clz(unsigned int bitvector)
|
||||
{
|
||||
unsigned int x = 0;
|
||||
while((!(bitvector & ((unsigned)1 << 31))) && (x < 32)) {
|
||||
bitvector <<= 1;
|
||||
x++;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int find_and_set_first_free_bit(u32 *word, unsigned int limit)
|
||||
{
|
||||
int success = 0;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < limit; i++) {
|
||||
/* Find first unset bit */
|
||||
if (!(word[BITWISE_GETWORD(i)] & BITWISE_GETBIT(i))) {
|
||||
/* Set it */
|
||||
word[BITWISE_GETWORD(i)] |= BITWISE_GETBIT(i);
|
||||
success = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Return bit just set */
|
||||
if (success)
|
||||
return i;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int check_and_clear_bit(u32 *word, int bit)
|
||||
{
|
||||
/* Check that bit was set */
|
||||
if (word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit)) {
|
||||
word[BITWISE_GETWORD(bit)] &= ~BITWISE_GETBIT(bit);
|
||||
return 0;
|
||||
} else {
|
||||
//printf("Trying to clear already clear bit\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
35
src/lib/idpool.c
Normal file
35
src/lib/idpool.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Used for thread and space ids.
|
||||
*
|
||||
* Copyright (C) 2007 Bahadir Balban
|
||||
*/
|
||||
#include <l4/lib/printk.h>
|
||||
#include <l4/lib/idpool.h>
|
||||
#include <l4/generic/kmalloc.h>
|
||||
#include INC_GLUE(memory.h)
|
||||
|
||||
struct id_pool *id_pool_new_init(int totalbits)
|
||||
{
|
||||
int nwords = BITWISE_GETWORD(totalbits);
|
||||
struct id_pool *new = kzalloc((nwords * SZ_WORD)
|
||||
+ sizeof(struct id_pool));
|
||||
new->nwords = nwords;
|
||||
return new;
|
||||
}
|
||||
|
||||
int id_new(struct id_pool *pool)
|
||||
{
|
||||
int id = find_and_set_first_free_bit(pool->bitmap,
|
||||
pool->nwords * WORD_BITS);
|
||||
BUG_ON(id < 0);
|
||||
return id;
|
||||
}
|
||||
|
||||
int id_del(struct id_pool *pool, int id)
|
||||
{
|
||||
int ret = check_and_clear_bit(pool->bitmap, id);
|
||||
|
||||
BUG_ON(ret < 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
170
src/lib/memcache.c
Normal file
170
src/lib/memcache.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Bitmap-based linked-listable fixed-size memory cache.
|
||||
*
|
||||
* Copyright (C) 2007 Bahadir Balban
|
||||
*/
|
||||
#include <l4/lib/memcache.h>
|
||||
#include <l4/lib/string.h>
|
||||
#include <l4/lib/printk.h>
|
||||
#include INC_GLUE(memory.h)
|
||||
#include <l4/lib/bit.h>
|
||||
|
||||
/* Allocate, clear and return element */
|
||||
void *mem_cache_zalloc(struct mem_cache *cache)
|
||||
{
|
||||
void *elem = mem_cache_alloc(cache);
|
||||
memset(elem, 0, cache->struct_size);
|
||||
return elem;
|
||||
}
|
||||
|
||||
/* Allocate another element from given @cache. Returns 0 when full. */
|
||||
void *mem_cache_alloc(struct mem_cache *cache)
|
||||
{
|
||||
int bit;
|
||||
if (cache->free > 0) {
|
||||
mutex_lock(&cache->mutex);
|
||||
cache->free--;
|
||||
if ((bit = find_and_set_first_free_bit(cache->bitmap,
|
||||
cache->total)) < 0) {
|
||||
printk("Error: Anomaly in cache occupied state.\n"
|
||||
"Bitmap full although cache->free > 0\n");
|
||||
BUG();
|
||||
}
|
||||
mutex_unlock(&cache->mutex);
|
||||
return (void *)(cache->start + (cache->struct_size * bit));
|
||||
} else {
|
||||
/* Cache full */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free element at @addr in @cache. Return negative on error. */
|
||||
int mem_cache_free(struct mem_cache *cache, void *addr)
|
||||
{
|
||||
unsigned int struct_addr = (unsigned int)addr;
|
||||
unsigned int bit;
|
||||
int err = 0;
|
||||
|
||||
/* Check boundary */
|
||||
if (struct_addr < cache->start || struct_addr > cache->end)
|
||||
return -1; /* Address doesn't belong to cache */
|
||||
|
||||
bit = ((struct_addr - cache->start) / cache->struct_size);
|
||||
|
||||
/*
|
||||
* Check alignment:
|
||||
* Find out if there was a lost remainder in last division.
|
||||
* There shouldn't have been, because addresses are allocated at
|
||||
* struct_size offsets from cache->start.
|
||||
*/
|
||||
if (((bit * cache->struct_size) + cache->start) != struct_addr) {
|
||||
printk("Error: This address is not aligned on a predefined "
|
||||
"structure address in this cache.\n");
|
||||
err = -1;
|
||||
return err;
|
||||
}
|
||||
|
||||
mutex_lock(&cache->mutex);
|
||||
/* Check free/occupied state */
|
||||
if (check_and_clear_bit(cache->bitmap, bit) < 0) {
|
||||
printk("Error: Anomaly in cache occupied state:\n"
|
||||
"Trying to free already free structure.\n");
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
cache->free++;
|
||||
if (cache->free > cache->total) {
|
||||
printk("Error: Anomaly in cache occupied state:\n"
|
||||
"More free elements than total.\n");
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&cache->mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct mem_cache *mem_cache_init(void *start,
|
||||
int cache_size,
|
||||
int struct_size,
|
||||
unsigned int aligned)
|
||||
{
|
||||
struct mem_cache *cache = start;
|
||||
unsigned int area_start;
|
||||
unsigned int *bitmap;
|
||||
int bwords_in_structs;
|
||||
int bwords;
|
||||
int total;
|
||||
int bsize;
|
||||
|
||||
if ((struct_size < 0) || (cache_size < 0) ||
|
||||
((unsigned long)start == ~(0))) {
|
||||
printk("Invalid parameters.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The cache definition itself is at the beginning.
|
||||
* Skipping it to get to start of free memory. i.e. the cache.
|
||||
*/
|
||||
area_start = (unsigned long)start + sizeof(struct mem_cache);
|
||||
cache_size -= sizeof(struct mem_cache);
|
||||
|
||||
if (cache_size < struct_size) {
|
||||
printk("Cache too small for given struct_size\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get how much bitmap words occupy */
|
||||
total = cache_size / struct_size;
|
||||
bwords = total >> 5; /* Divide by 32 */
|
||||
if (total & 0x1F) { /* Remainder? */
|
||||
bwords++; /* Add one more word for remainder */
|
||||
}
|
||||
bsize = bwords * 4;
|
||||
|
||||
/* This many structures will be chucked from cache for bitmap space */
|
||||
bwords_in_structs = ((bsize) / struct_size) + 1;
|
||||
|
||||
/* Total structs left after deducing bitmaps */
|
||||
total = total - bwords_in_structs;
|
||||
cache_size -= bsize;
|
||||
|
||||
/* This should always catch too small caches */
|
||||
if (total <= 0) {
|
||||
printk("Cache too small for given struct_size\n");
|
||||
return 0;
|
||||
}
|
||||
if (cache_size <= 0) {
|
||||
printk("Cache too small for given struct_size\n");
|
||||
return 0;
|
||||
}
|
||||
bitmap = (unsigned int *)area_start;
|
||||
area_start = (unsigned int)(bitmap + bwords);
|
||||
if (aligned) {
|
||||
unsigned int addr = area_start;
|
||||
unsigned int addr_aligned = align_up(area_start, struct_size);
|
||||
unsigned int diff = addr_aligned - addr;
|
||||
|
||||
BUG_ON(diff >= struct_size);
|
||||
if (diff)
|
||||
total--;
|
||||
cache_size -= diff;
|
||||
area_start = addr_aligned;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&cache->list);
|
||||
cache->start = area_start;
|
||||
cache->end = area_start + cache_size;
|
||||
cache->total = total;
|
||||
cache->free = cache->total;
|
||||
cache->struct_size = struct_size;
|
||||
cache->bitmap = bitmap;
|
||||
|
||||
mutex_init(&cache->mutex);
|
||||
memset(cache->bitmap, 0, bwords*SZ_WORD);
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
149
src/lib/mutex.c
Normal file
149
src/lib/mutex.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Mutex/Semaphore implementations.
|
||||
*
|
||||
* Copyright (c) 2007 Bahadir Balban
|
||||
*/
|
||||
#include <l4/lib/mutex.h>
|
||||
#include <l4/generic/scheduler.h>
|
||||
#include <l4/generic/tcb.h>
|
||||
|
||||
/*
|
||||
* Semaphore usage:
|
||||
*
|
||||
* Producer locks/produces/unlocks data.
|
||||
* Producer does semaphore up.
|
||||
* --
|
||||
* Consumer does semaphore down.
|
||||
* Consumer locks/consumes/unlocks data.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Semaphore *up* for multiple producers. If any consumer is waiting, wake them
|
||||
* up, otherwise, sleep. Effectively producers and consumers use the same
|
||||
* waitqueue and there's only one kind in the queue at any one time.
|
||||
*/
|
||||
void sem_up(struct mutex *mutex)
|
||||
{
|
||||
int cnt;
|
||||
|
||||
spin_lock(&mutex->slock);
|
||||
if ((cnt = mutex_inc(&mutex->lock)) <= 0) {
|
||||
struct waitqueue *wq;
|
||||
struct ktcb *sleeper;
|
||||
|
||||
/* Each producer wakes one consumer in queue. */
|
||||
mutex->sleepers--;
|
||||
BUG_ON(list_empty(&mutex->wq.task_list));
|
||||
list_for_each_entry(wq, &mutex->wq.task_list, task_list) {
|
||||
list_del_init(&wq->task_list);
|
||||
spin_unlock(&mutex->slock);
|
||||
sleeper = wq->task;
|
||||
printk("(%d) Waking up consumer (%d)\n", current->tid,
|
||||
sleeper->tid);
|
||||
sched_resume_task(sleeper);
|
||||
return; /* Don't iterate, wake only one task. */
|
||||
}
|
||||
} else if (cnt > 0) {
|
||||
DECLARE_WAITQUEUE(wq, current);
|
||||
INIT_LIST_HEAD(&wq.task_list);
|
||||
list_add_tail(&wq.task_list, &mutex->wq.task_list);
|
||||
mutex->sleepers++;
|
||||
sched_notify_sleep(current);
|
||||
need_resched = 1;
|
||||
printk("(%d) produced, now sleeping...\n", current->tid);
|
||||
spin_unlock(&mutex->slock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Semaphore *down* for multiple consumers. If any producer is sleeping, wake them
|
||||
* up, otherwise, sleep. Effectively producers and consumers use the same
|
||||
* waitqueue and there's only one kind in the queue at any one time.
|
||||
*/
|
||||
void sem_down(struct mutex *mutex)
|
||||
{
|
||||
int cnt;
|
||||
|
||||
spin_lock(&mutex->slock);
|
||||
if ((cnt = mutex_dec(&mutex->lock)) >= 0) {
|
||||
struct waitqueue *wq;
|
||||
struct ktcb *sleeper;
|
||||
|
||||
/* Each consumer wakes one producer in queue. */
|
||||
mutex->sleepers--;
|
||||
BUG_ON(list_empty(&mutex->wq.task_list));
|
||||
list_for_each_entry(wq, &mutex->wq.task_list, task_list) {
|
||||
list_del_init(&wq->task_list);
|
||||
spin_unlock(&mutex->slock);
|
||||
sleeper = wq->task;
|
||||
printk("(%d) Waking up producer (%d)\n", current->tid,
|
||||
sleeper->tid);
|
||||
sched_resume_task(sleeper);
|
||||
return; /* Don't iterate, wake only one task. */
|
||||
}
|
||||
} else if (cnt < 0) {
|
||||
DECLARE_WAITQUEUE(wq, current);
|
||||
INIT_LIST_HEAD(&wq.task_list);
|
||||
list_add_tail(&wq.task_list, &mutex->wq.task_list);
|
||||
mutex->sleepers++;
|
||||
sched_notify_sleep(current);
|
||||
need_resched = 1;
|
||||
printk("(%d) Waiting to consume, now sleeping...\n", current->tid);
|
||||
spin_unlock(&mutex->slock);
|
||||
}
|
||||
}
|
||||
|
||||
void mutex_lock(struct mutex *mutex)
|
||||
{
|
||||
/* NOTE:
|
||||
* Everytime we're woken up we retry acquiring the mutex. It is
|
||||
* undeterministic as to how many retries will result in success.
|
||||
*/
|
||||
for (;;) {
|
||||
spin_lock(&mutex->slock);
|
||||
if (!__mutex_lock(&mutex->lock)) { /* Could not lock, sleep. */
|
||||
DECLARE_WAITQUEUE(wq, current);
|
||||
INIT_LIST_HEAD(&wq.task_list);
|
||||
list_add_tail(&wq.task_list, &mutex->wq.task_list);
|
||||
mutex->sleepers++;
|
||||
sched_notify_sleep(current);
|
||||
printk("(%d) sleeping...\n", current->tid);
|
||||
spin_unlock(&mutex->slock);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
spin_unlock(&mutex->slock);
|
||||
}
|
||||
|
||||
void mutex_unlock(struct mutex *mutex)
|
||||
{
|
||||
spin_lock(&mutex->slock);
|
||||
__mutex_unlock(&mutex->lock);
|
||||
BUG_ON(mutex->sleepers < 0);
|
||||
if (mutex->sleepers > 0) {
|
||||
struct waitqueue *wq;
|
||||
struct ktcb *sleeper;
|
||||
|
||||
/* Each unlocker wakes one other sleeper in queue. */
|
||||
mutex->sleepers--;
|
||||
BUG_ON(list_empty(&mutex->wq.task_list));
|
||||
list_for_each_entry(wq, &mutex->wq.task_list, task_list) {
|
||||
list_del_init(&wq->task_list);
|
||||
spin_unlock(&mutex->slock);
|
||||
/*
|
||||
* Here, someone else may get the lock, well before we
|
||||
* wake up the sleeper that we *hope* would get it. This
|
||||
* is fine as the sleeper would retry and re-sleep. BUT,
|
||||
* this may potentially starve the sleeper causing
|
||||
* non-determinisim.
|
||||
*/
|
||||
sleeper = wq->task;
|
||||
printk("(%d) Waking up (%d)\n", current->tid,
|
||||
sleeper->tid);
|
||||
sched_resume_task(sleeper);
|
||||
return; /* Don't iterate, wake only one task. */
|
||||
}
|
||||
}
|
||||
spin_unlock(&mutex->slock);
|
||||
}
|
||||
|
||||
445
src/lib/printk.c
Normal file
445
src/lib/printk.c
Normal file
@@ -0,0 +1,445 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* Copyright (C) 2002-2004 Karlsruhe University
|
||||
*
|
||||
* File path: generic/printk.cc
|
||||
* Description: Implementation of printf
|
||||
*
|
||||
* 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 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 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 <stdarg.h> /* for va_list, ... comes with gcc */
|
||||
#include <l4/lib/printk.h>
|
||||
/* FIXME: LICENSE LICENCE */
|
||||
typedef unsigned int word_t;
|
||||
|
||||
extern void putc(const char c);
|
||||
extern int print_tid (word_t val, word_t width, word_t precision, int adjleft);
|
||||
|
||||
|
||||
/* convert nibble to lowercase hex char */
|
||||
#define hexchars(x) (((x) < 10) ? ('0' + (x)) : ('a' + ((x) - 10)))
|
||||
|
||||
/**
|
||||
* Print hexadecimal value
|
||||
*
|
||||
* @param val value to print
|
||||
* @param width width in caracters
|
||||
* @param precision minimum number of digits to apprear
|
||||
* @param adjleft left adjust the value
|
||||
* @param nullpad pad with leading zeros (when right padding)
|
||||
*
|
||||
* Prints a hexadecimal value with leading zeroes of given width
|
||||
* using putc(), or if adjleft argument is given, print
|
||||
* hexadecimal value with space padding to the right.
|
||||
*
|
||||
* @returns the number of charaters printed (should be same as width).
|
||||
*/
|
||||
int print_hex64(u64 val, int width, int precision, int adjleft, int nullpad)
|
||||
{
|
||||
int i, n = 0;
|
||||
int nwidth = 0;
|
||||
u32 high, low;
|
||||
|
||||
high = val >> 32;
|
||||
low = (u32)val;
|
||||
|
||||
// Find width of hexnumber
|
||||
if (high) {
|
||||
while ((high >> (4 * nwidth)) && ((unsigned) nwidth < 2 * sizeof (u32)))
|
||||
nwidth++;
|
||||
nwidth += 32;
|
||||
} else {
|
||||
while ((low >> (4 * nwidth)) && ((unsigned) nwidth < 2 * sizeof (u32)))
|
||||
nwidth++;
|
||||
}
|
||||
|
||||
if (nwidth == 0)
|
||||
nwidth = 1;
|
||||
|
||||
// May need to increase number of printed digits
|
||||
if (precision > nwidth)
|
||||
nwidth = precision;
|
||||
|
||||
// May need to increase number of printed characters
|
||||
if (width == 0 && width < nwidth)
|
||||
width = nwidth;
|
||||
|
||||
// Print number with padding
|
||||
if (high)
|
||||
{
|
||||
if (!adjleft)
|
||||
for (i = width - nwidth; i > 0; i--, n++)
|
||||
putc (nullpad ? '0' : ' ');
|
||||
for (i = 4 * (nwidth - 33); i >= 0; i -= 4, n++)
|
||||
putc (hexchars ((high >> i) & 0xF));
|
||||
if (adjleft)
|
||||
for (i = width - nwidth; i > 0; i--, n++)
|
||||
putc (' ');
|
||||
width -= 32;
|
||||
nwidth -= 32;
|
||||
nullpad = 1;
|
||||
}
|
||||
if (! adjleft)
|
||||
for (i = width - nwidth; i > 0; i--, n++)
|
||||
putc (nullpad ? '0' : ' ');
|
||||
for (i = 4 * (nwidth - 1); i >= 0; i -= 4, n++)
|
||||
putc (hexchars ((low >> i) & 0xF));
|
||||
if (adjleft)
|
||||
for (i = width - nwidth; i > 0; i--, n++)
|
||||
putc (' ');
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int print_hex_3arg(const word_t val, int width, int precision)
|
||||
{
|
||||
long i, n = 0;
|
||||
long nwidth = 0;
|
||||
int adjleft = 0;
|
||||
int nullpad = 0;
|
||||
|
||||
// Find width of hexnumber
|
||||
while ((val >> (4 * nwidth)) && (word_t) nwidth < 2 * sizeof (word_t))
|
||||
nwidth++;
|
||||
|
||||
if (nwidth == 0)
|
||||
nwidth = 1;
|
||||
|
||||
// May need to increase number of printed digits
|
||||
if (precision > nwidth)
|
||||
nwidth = precision;
|
||||
|
||||
// May need to increase number of printed characters
|
||||
if (width == 0 && width < nwidth)
|
||||
width = nwidth;
|
||||
|
||||
// Print number with padding
|
||||
if (! adjleft)
|
||||
for (i = width - nwidth; i > 0; i--, n++)
|
||||
putc (nullpad ? '0' : ' ');
|
||||
for (i = 4 * (nwidth - 1); i >= 0; i -= 4, n++)
|
||||
putc (hexchars ((val >> i) & 0xF));
|
||||
if (adjleft)
|
||||
for (i = width - nwidth; i > 0; i--, n++)
|
||||
putc (' ');
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int print_hex_5arg(const word_t val, int width,
|
||||
int precision, int adjleft, int nullpad)
|
||||
{
|
||||
long i, n = 0;
|
||||
long nwidth = 0;
|
||||
|
||||
// Find width of hexnumber
|
||||
while ((val >> (4 * nwidth)) && (word_t) nwidth < 2 * sizeof (word_t))
|
||||
nwidth++;
|
||||
|
||||
if (nwidth == 0)
|
||||
nwidth = 1;
|
||||
|
||||
// May need to increase number of printed digits
|
||||
if (precision > nwidth)
|
||||
nwidth = precision;
|
||||
|
||||
// May need to increase number of printed characters
|
||||
if (width == 0 && width < nwidth)
|
||||
width = nwidth;
|
||||
|
||||
// Print number with padding
|
||||
if (! adjleft)
|
||||
for (i = width - nwidth; i > 0; i--, n++)
|
||||
putc (nullpad ? '0' : ' ');
|
||||
for (i = 4 * (nwidth - 1); i >= 0; i -= 4, n++)
|
||||
putc (hexchars ((val >> i) & 0xF));
|
||||
if (adjleft)
|
||||
for (i = width - nwidth; i > 0; i--, n++)
|
||||
putc (' ');
|
||||
|
||||
return n;
|
||||
}
|
||||
/**
|
||||
* Print a string
|
||||
*
|
||||
* @param s zero-terminated string to print
|
||||
* @param width minimum width of printed string
|
||||
*
|
||||
* Prints the zero-terminated string using putc(). The printed
|
||||
* string will be right padded with space to so that it will be
|
||||
* at least WIDTH characters wide.
|
||||
*
|
||||
* @returns the number of charaters printed.
|
||||
*/
|
||||
int print_string_3arg(const char * s, const int width, const int precision)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (*s == 0)
|
||||
break;
|
||||
|
||||
putc(*s++);
|
||||
n++;
|
||||
if (precision && n >= precision)
|
||||
break;
|
||||
}
|
||||
|
||||
while (n < width) { putc(' '); n++; }
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int print_string_1arg(const char * s)
|
||||
{
|
||||
int n = 0;
|
||||
int width = 0;
|
||||
int precision = 0;
|
||||
|
||||
for (;;) {
|
||||
if (*s == 0)
|
||||
break;
|
||||
|
||||
putc(*s++);
|
||||
n++;
|
||||
if (precision && n >= precision)
|
||||
break;
|
||||
}
|
||||
|
||||
while (n < width) {
|
||||
putc(' ');
|
||||
n++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Print hexadecimal value with a separator
|
||||
*
|
||||
* @param val value to print
|
||||
* @param bits number of lower-most bits before which to
|
||||
* place the separator
|
||||
* @param sep the separator to print
|
||||
*
|
||||
* @returns the number of charaters printed.
|
||||
*/
|
||||
int print_hex_sep(const word_t val, const int bits, const char *sep)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
n = print_hex_3arg(val >> bits, 0, 0);
|
||||
n += print_string_1arg(sep);
|
||||
n += print_hex_3arg(val & ((1 << bits) - 1), 0, 0);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Print decimal value
|
||||
*
|
||||
* @param val value to print
|
||||
* @param width width of field
|
||||
* @param pad character used for padding value up to width
|
||||
*
|
||||
* Prints a value as a decimal in the given WIDTH with leading
|
||||
* whitespaces.
|
||||
*
|
||||
* @returns the number of characters printed (may be more than WIDTH)
|
||||
*/
|
||||
int print_dec(const word_t val, int width)
|
||||
{
|
||||
word_t divisor;
|
||||
int digits;
|
||||
/* estimate number of spaces and digits */
|
||||
for (divisor = 1, digits = 1; val/divisor >= 10; divisor *= 10, digits++);
|
||||
|
||||
/* print spaces */
|
||||
for ( ; digits < width; digits++ )
|
||||
putc(' ');
|
||||
|
||||
/* print digits */
|
||||
do {
|
||||
putc(((val/divisor) % 10) + '0');
|
||||
} while (divisor /= 10);
|
||||
|
||||
/* report number of digits printed */
|
||||
return digits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the real printk work
|
||||
*
|
||||
* @param format_p pointer to format string
|
||||
* @param args list of arguments, variable length
|
||||
*
|
||||
* Prints the given arguments as specified by the format string.
|
||||
* Implements a subset of the well-known printf plus some L4-specifics.
|
||||
*
|
||||
* @returns the number of characters printed
|
||||
*/
|
||||
int do_printk(char* format_p, va_list args)
|
||||
{
|
||||
const char* format = format_p;
|
||||
int n = 0;
|
||||
int i = 0;
|
||||
int width = 8;
|
||||
int precision = 0;
|
||||
int adjleft = 0, nullpad = 0;
|
||||
|
||||
#define arg(x) va_arg(args, x)
|
||||
|
||||
/* sanity check */
|
||||
if (format == '\0')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*format)
|
||||
{
|
||||
switch (*(format))
|
||||
{
|
||||
case '%':
|
||||
width = precision = 0;
|
||||
adjleft = nullpad = 0;
|
||||
reentry:
|
||||
switch (*(++format))
|
||||
{
|
||||
/* modifiers */
|
||||
case '.':
|
||||
for (format++; *format >= '0' && *format <= '9'; format++)
|
||||
precision = precision * 10 + (*format) - '0';
|
||||
if (*format == 'w')
|
||||
{
|
||||
// Set precision to printsize of a hex word
|
||||
precision = sizeof (word_t) * 2;
|
||||
format++;
|
||||
}
|
||||
format--;
|
||||
goto reentry;
|
||||
case '0':
|
||||
nullpad = (width == 0);
|
||||
case '1'...'9':
|
||||
width = width*10 + (*format)-'0';
|
||||
goto reentry;
|
||||
case 'w':
|
||||
// Set width to printsize of a hex word
|
||||
width = sizeof (word_t) * 2;
|
||||
goto reentry;
|
||||
case '-':
|
||||
adjleft = 0;
|
||||
goto reentry;
|
||||
case 'l':
|
||||
goto reentry;
|
||||
break;
|
||||
case 'c':
|
||||
putc(arg(int));
|
||||
n++;
|
||||
break;
|
||||
case 'm': /* microseconds */
|
||||
{
|
||||
n += print_hex64(arg(u64), width, precision,
|
||||
adjleft, nullpad);
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
{
|
||||
long val = arg(long);
|
||||
if (val < 0)
|
||||
{
|
||||
putc('-');
|
||||
val = -val;
|
||||
}
|
||||
n += print_dec(val, width);
|
||||
break;
|
||||
}
|
||||
case 'u':
|
||||
n += print_dec(arg(long), width);
|
||||
break;
|
||||
case 'p':
|
||||
precision = sizeof (word_t) * 2;
|
||||
case 'x':
|
||||
n += print_hex_5arg(arg(long), width, precision, adjleft, nullpad);
|
||||
break;
|
||||
case 's':
|
||||
{
|
||||
char* s = arg(char*);
|
||||
if (s)
|
||||
n += print_string_3arg(s, width, precision);
|
||||
else
|
||||
n += print_string_3arg("(null)", width, precision);
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
case 'T':
|
||||
// Do nothing for now.
|
||||
//n += print_tid (arg (word_t), width, precision, adjleft);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
putc('%');
|
||||
n++;
|
||||
format++;
|
||||
continue;
|
||||
default:
|
||||
n += print_string_1arg("?");
|
||||
break;
|
||||
};
|
||||
i++;
|
||||
break;
|
||||
default:
|
||||
putc(*format);
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flexible print function
|
||||
*
|
||||
* @param format string containing formatting and parameter type
|
||||
* information
|
||||
* @param ... variable list of parameters
|
||||
*
|
||||
* @returns the number of characters printed
|
||||
*/
|
||||
int printk(char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
va_start(args, format);
|
||||
i = do_printk(format, args);
|
||||
va_end(args);
|
||||
return i;
|
||||
};
|
||||
|
||||
|
||||
14
src/lib/putc.c
Normal file
14
src/lib/putc.c
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Generic putc implementation that ties with platform-specific uart driver.
|
||||
*
|
||||
* Copyright (C) 2007 Bahadir Balban
|
||||
*/
|
||||
|
||||
#include INC_PLAT(uart.h)
|
||||
|
||||
void putc(char c)
|
||||
{
|
||||
if (c == '\n')
|
||||
uart_putc('\r');
|
||||
uart_putc(c);
|
||||
}
|
||||
69
src/lib/string.c
Normal file
69
src/lib/string.c
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
|
||||
void *memset(void *p, int c, int size)
|
||||
{
|
||||
char ch;
|
||||
char *pp;
|
||||
|
||||
pp = (char *)p;
|
||||
ch = (char)c;
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
*pp++ = ch;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *memcpy(void *d, void *s, int size)
|
||||
{
|
||||
char *dst = (char *)d;
|
||||
char *src = (char *)s;
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
*dst = *src;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
int strcmp(const char *s1, const char *s2)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
int d;
|
||||
|
||||
while(1) {
|
||||
d = (unsigned char)s1[i] - (unsigned char)s2[i];
|
||||
if (d != 0 || s1[i] == '\0')
|
||||
return d;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* LICENCE: Taken from linux for now BB.
|
||||
* strncpy - Copy a length-limited, %NUL-terminated string
|
||||
* @dest: Where to copy the string to
|
||||
* @src: Where to copy the string from
|
||||
* @count: The maximum number of bytes to copy
|
||||
*
|
||||
* The result is not %NUL-terminated if the source exceeds
|
||||
* @count bytes.
|
||||
*
|
||||
* In the case where the length of @src is less than that of
|
||||
* count, the remainder of @dest will be padded with %NUL.
|
||||
*
|
||||
*/
|
||||
char *strncpy(char *dest, const char *src, int count)
|
||||
{
|
||||
char *tmp = dest;
|
||||
|
||||
while (count) {
|
||||
if ((*tmp = *src) != 0)
|
||||
src++;
|
||||
tmp++;
|
||||
count--;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
60
src/lib/wait.c
Normal file
60
src/lib/wait.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Implementation of wakeup/wait for processes.
|
||||
*
|
||||
* Copyright (C) 2007 Bahadir Balban
|
||||
*/
|
||||
#include <l4/generic/scheduler.h>
|
||||
#include <l4/lib/wait.h>
|
||||
#include <l4/lib/spinlock.h>
|
||||
|
||||
/* Sleep if the given condition isn't true. */
|
||||
#define wait_event(wqh, condition) \
|
||||
do { \
|
||||
for (;;) { \
|
||||
if (condition) \
|
||||
break; \
|
||||
DECLARE_WAITQUEUE(wq, current); \
|
||||
spin_lock(&wqh->slock); \
|
||||
wqh->sleepers++; \
|
||||
list_add_tail(&wq.task_list, &wqh->task_list); \
|
||||
sched_tell(current, SCHED_FL_SLEEP); \
|
||||
need_resched = 1; \
|
||||
printk("(%d) waiting...\n", current->tid); \
|
||||
spin_unlock(&wqh->slock); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
/* Sleep without any condition */
|
||||
#define wait_on(wqh) \
|
||||
do { \
|
||||
DECLARE_WAITQUEUE(wq, current); \
|
||||
spin_lock(&wqh->slock); \
|
||||
wqh->sleepers++; \
|
||||
list_add_tail(&wq.task_list, &wqh->task_list); \
|
||||
sched_tell(current, SCHED_FL_SLEEP); \
|
||||
need_resched = 1; \
|
||||
printk("(%d) waiting...\n", current->tid); \
|
||||
spin_unlock(&wqh->slock); \
|
||||
} while(0);
|
||||
|
||||
/* Wake up single waiter */
|
||||
void wake_up(struct waitqueue_head *wqh)
|
||||
{
|
||||
BUG_ON(wqh->sleepers < 0);
|
||||
spin_lock(&wqh->slock);
|
||||
if (wqh->sleepers > 0) {
|
||||
struct waitqueue *wq = list_entry(wqh->task_list.next,
|
||||
struct waitqueue,
|
||||
task_list);
|
||||
struct ktcb *sleeper = wq->task;
|
||||
list_del_init(&wq->task_list);
|
||||
wqh->sleepers--;
|
||||
BUG_ON(list_empty(&wqh->task_list));
|
||||
printk("(%d) Waking up (%d)\n", current->tid, sleeper->tid);
|
||||
sched_notify_resume(sleeper);
|
||||
spin_unlock(&wqh->slock);
|
||||
return;
|
||||
}
|
||||
spin_unlock(&wqh->slock);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user