Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev HEAD → Rev 2201

/branches/arm/kernel/generic/include/udebug/udebug_ipc.h
File deleted
/branches/arm/kernel/generic/include/udebug/udebug.h
File deleted
/branches/arm/kernel/generic/include/udebug/udebug_ops.h
File deleted
/branches/arm/kernel/generic/include/string.h
File deleted
/branches/arm/kernel/generic/include/print.h
1,3 → 1,4
#include "../../arch/arm32/src/aux_print/printf.h"
/*
* Copyright (c) 2001-2004 Jakub Jermar
* All rights reserved.
26,7 → 27,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
40,15 → 41,18
#include <arch/arg.h>
 
/* We need this address in spinlock to avoid deadlock in deadlock detection */
SPINLOCK_EXTERN(printf_lock);
SPINLOCK_EXTERN(printflock);
 
#define EOF (-1)
 
extern int puts(const char *s);
extern int printf(const char *fmt, ...);
//extern int printf(const char *fmt, ...);
#define printf(xx...) aux_printf(xx)
extern int sprintf(char *str, const char *fmt, ...);
extern int snprintf(char *str, size_t size, const char *fmt, ...);
 
extern int vprintf(const char *fmt, va_list ap);
extern int vsprintf(char *str, const char *fmt, va_list ap);
extern int vsnprintf(char *str, size_t size, const char *fmt, va_list ap);
 
#endif
/branches/arm/kernel/generic/include/lib/elf.h
114,8 → 114,7
#define EE_MEMORY 2 /* Cannot allocate address space */
#define EE_INCOMPATIBLE 3 /* ELF image is not compatible with current architecture */
#define EE_UNSUPPORTED 4 /* Non-supported ELF (e.g. dynamic ELFs) */
#define EE_LOADER 5 /* The image is actually a program loader */
#define EE_IRRECOVERABLE 6
#define EE_IRRECOVERABLE 5
 
/**
* ELF section types
145,7 → 144,6
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
#define SHF_EXECINSTR 0x4
#define SHF_TLS 0x400
#define SHF_MASKPROC 0xf0000000
 
/**
337,12 → 335,8
typedef struct elf64_symbol elf_symbol_t;
#endif
 
extern char *elf_error(unsigned int rc);
extern char *elf_error(int rc);
 
/* Interpreter string used to recognize the program loader */
#define ELF_INTERP_ZSTR "kernel"
#define ELF_INTERP_ZLEN sizeof(ELF_INTERP_ZSTR)
 
#endif
 
/** @}
/branches/arm/kernel/generic/include/lib/objc.h
0,0 → 1,50
/*
* Copyright (c) 2007 Martin Decky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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 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.
*/
 
/** @addtogroup generic
* @{
*/
/** @file
*/
 
#ifndef KERN_OBJC_H_
#define KERN_OBJC_H_
 
extern id class_create_instance(Class _class);
extern id object_dispose(id object);
 
@interface base_t {
Class isa;
}
 
+ (id) new;
- (id) free;
 
@end
 
#endif
/branches/arm/kernel/generic/include/lib/objc_ext.h
0,0 → 1,64
/*
* Copyright (c) 2007 Martin Decky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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 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.
*/
 
/** @addtogroup generic
* @{
*/
/** @file
*/
 
#ifndef KERN_OBJC_EXT_H_
#define KERN_OBJC_EXT_H_
 
#include <arch/types.h>
#include <arch/arg.h>
 
extern void *stderr;
 
extern void __assert_fail(const char *assertion, const char *file, unsigned int line, const char *function);
extern void abort(void);
 
extern void *fopen(const char *path, const char *mode);
extern size_t fread(void *ptr, size_t size, size_t nmemb, void *stream);
extern size_t fwrite(const void *ptr, size_t size, size_t nmemb, void *stream);
extern int fflush(void *stream);
extern int feof(void *stream);
extern int fclose(void *stream);
 
extern int vfprintf(void *stream, const char *format, va_list ap);
extern int sscanf(const char *str, const char *format, ...);
extern const unsigned short **__ctype_b_loc(void);
extern long int __strtol_internal(const char *__nptr, char **__endptr, int __base, int __group);
 
extern void *memset(void *s, int c, size_t n);
extern void *calloc(size_t nmemb, size_t size);
 
#endif
 
/** @}
*/
/branches/arm/kernel/generic/include/lib/rd.h
40,7 → 40,7
/**
* RAM disk version
*/
#define RD_VERSION 1
#define RD_VERSION 0
 
/**
* RAM disk magic number
66,18 → 66,16
#define RE_UNSUPPORTED 2 /* Non-supported image (e.g. wrong version) */
 
/** RAM disk header */
struct rd_header {
typedef struct {
uint8_t magic[RD_MAGIC_SIZE];
uint8_t version;
uint8_t data_type;
uint32_t header_size;
uint64_t data_size;
} __attribute__ ((packed));
} rd_header;
 
typedef struct rd_header rd_header_t;
extern int init_rd(rd_header * addr, size_t size);
 
extern int init_rd(rd_header_t *addr, size_t size);
 
#endif
 
/** @}
/branches/arm/kernel/generic/include/mm/as.h
53,6 → 53,10
#include <adt/btree.h>
#include <lib/elf.h>
 
#ifdef __OBJC__
#include <lib/objc.h>
#endif
 
/**
* Defined to be true if user address space and kernel address space shadow each
* other.
80,6 → 84,45
/** The page fault was caused by memcpy_from_uspace() or memcpy_to_uspace(). */
#define AS_PF_DEFER 2
 
#ifdef __OBJC__
@interface as_t : base_t {
@public
/** Protected by asidlock. */
link_t inactive_as_with_asid_link;
mutex_t lock;
/** Number of references (i.e tasks that reference this as). */
count_t refcount;
/** Number of processors on wich is this address space active. */
count_t cpu_refcount;
/** B+tree of address space areas. */
btree_t as_area_btree;
/**
* Address space identifier.
* Constant on architectures that do not support ASIDs.
*/
asid_t asid;
/** Non-generic content. */
as_genarch_t genarch;
/** Architecture specific content. */
as_arch_t arch;
}
 
+ (pte_t *) page_table_create: (int) flags;
+ (void) page_table_destroy: (pte_t *) page_table;
- (void) page_table_lock: (bool) _lock;
- (void) page_table_unlock: (bool) unlock;
 
@end
 
#else
 
/** Address space structure.
*
* as_t contains the list of as_areas of userspace accessible
90,26 → 133,24
typedef struct as {
/** Protected by asidlock. */
link_t inactive_as_with_asid_link;
/**
* Number of processors on wich is this address space active.
* Protected by asidlock.
*/
size_t cpu_refcount;
/**
* Address space identifier.
* Constant on architectures that do not support ASIDs.
* Protected by asidlock.
*/
asid_t asid;
 
mutex_t lock;
 
/** Number of references (i.e tasks that reference this as). */
atomic_t refcount;
count_t refcount;
 
mutex_t lock;
/** Number of processors on wich is this address space active. */
count_t cpu_refcount;
 
/** B+tree of address space areas. */
btree_t as_area_btree;
/**
* Address space identifier.
* Constant on architectures that do not support ASIDs.
*/
asid_t asid;
/** Non-generic content. */
as_genarch_t genarch;
 
123,6 → 164,7
void (* page_table_lock)(as_t *as, bool lock);
void (* page_table_unlock)(as_t *as, bool unlock);
} as_operations_t;
#endif
 
/**
* This structure contains information associated with the shared address space
132,7 → 174,7
/** This lock must be acquired only when the as_area lock is held. */
mutex_t lock;
/** This structure can be deallocated if refcount drops to 0. */
size_t refcount;
count_t refcount;
/**
* B+tree containing complete map of anonymous pages of the shared area.
*/
156,7 → 198,7
};
struct { /**< phys_backend members */
uintptr_t base;
size_t frames;
count_t frames;
};
} mem_backend_data_t;
 
163,6 → 205,7
/** Address space area structure.
*
* Each as_area_t structure describes one contiguous area of virtual memory.
* In the future, it should not be difficult to support shared areas.
*/
typedef struct {
mutex_t lock;
175,7 → 218,7
/** Attributes related to the address space area itself. */
int attributes;
/** Size of this area in multiples of PAGE_SIZE. */
size_t pages;
count_t pages;
/** Base address of this area. */
uintptr_t base;
/** Map of used space. */
203,7 → 246,11
 
extern as_t *AS_KERNEL;
 
#ifndef __OBJC__
extern as_operations_t *as_operations;
#endif
 
SPINLOCK_EXTERN(inactive_as_with_asid_lock);
extern link_t inactive_as_with_asid_head;
 
extern void as_init(void);
220,13 → 267,12
extern int as_area_resize(as_t *as, uintptr_t address, size_t size, int flags);
int as_area_share(as_t *src_as, uintptr_t src_base, size_t acc_size,
as_t *dst_as, uintptr_t dst_base, int dst_flags_mask);
extern int as_area_change_flags(as_t *as, int flags, uintptr_t address);
 
extern int as_area_get_flags(as_area_t *area);
extern bool as_area_check_access(as_area_t *area, pf_access_t access);
extern size_t as_area_get_size(uintptr_t base);
extern int used_space_insert(as_area_t *a, uintptr_t page, size_t count);
extern int used_space_remove(as_area_t *a, uintptr_t page, size_t count);
extern size_t as_get_size(uintptr_t base);
extern int used_space_insert(as_area_t *a, uintptr_t page, count_t count);
extern int used_space_remove(as_area_t *a, uintptr_t page, count_t count);
 
 
/* Interface to be implemented by architectures. */
251,19 → 297,11
extern mem_backend_t elf_backend;
extern mem_backend_t phys_backend;
 
/**
* This flags is passed when running the loader, otherwise elf_load()
* would return with a EE_LOADER error code.
*/
#define ELD_F_NONE 0
#define ELD_F_LOADER 1
extern int elf_load(elf_header_t *header, as_t *as);
 
extern unsigned int elf_load(elf_header_t *header, as_t *as, int flags);
 
/* Address space area related syscalls. */
extern unative_t sys_as_area_create(uintptr_t address, size_t size, int flags);
extern unative_t sys_as_area_resize(uintptr_t address, size_t size, int flags);
extern unative_t sys_as_area_change_flags(uintptr_t address, int flags);
extern unative_t sys_as_area_destroy(uintptr_t address);
 
/* Introspection functions. */
/branches/arm/kernel/generic/include/mm/slab.h
41,40 → 41,39
#include <mm/frame.h>
 
/** Minimum size to be allocated by malloc */
#define SLAB_MIN_MALLOC_W 4
#define SLAB_MIN_MALLOC_W 4
 
/** Maximum size to be allocated by malloc */
#define SLAB_MAX_MALLOC_W 22
#define SLAB_MAX_MALLOC_W 18
 
/** Initial Magazine size (TODO: dynamically growing magazines) */
#define SLAB_MAG_SIZE 4
 
/** If object size is less, store control structure inside SLAB */
#define SLAB_INSIDE_SIZE (PAGE_SIZE >> 3)
#define SLAB_INSIDE_SIZE (PAGE_SIZE >> 3)
 
/** Maximum wasted space we allow for cache */
#define SLAB_MAX_BADNESS(cache) \
(((unsigned int) PAGE_SIZE << (cache)->order) >> 2)
#define SLAB_MAX_BADNESS(cache) ((PAGE_SIZE << (cache)->order) >> 2)
 
/* slab_reclaim constants */
 
/** Reclaim all possible memory, because we are in memory stress */
#define SLAB_RECLAIM_ALL 0x01
#define SLAB_RECLAIM_ALL 0x1
 
/* cache_create flags */
 
/** Do not use per-cpu cache */
#define SLAB_CACHE_NOMAGAZINE 0x01
#define SLAB_CACHE_NOMAGAZINE 0x1
/** Have control structure inside SLAB */
#define SLAB_CACHE_SLINSIDE 0x02
#define SLAB_CACHE_SLINSIDE 0x2
/** We add magazine cache later, if we have this flag */
#define SLAB_CACHE_MAGDEFERRED (0x04 | SLAB_CACHE_NOMAGAZINE)
#define SLAB_CACHE_MAGDEFERRED (0x4 | SLAB_CACHE_NOMAGAZINE)
 
typedef struct {
link_t link;
size_t busy; /**< Count of full slots in magazine */
size_t size; /**< Number of slots in magazine */
void *objs[]; /**< Slots in magazine */
count_t busy; /**< Count of full slots in magazine */
count_t size; /**< Number of slots in magazine */
void *objs[0]; /**< Slots in magazine */
} slab_magazine_t;
 
typedef struct {
86,23 → 85,23
 
typedef struct {
char *name;
 
link_t link;
 
/* Configuration */
/** Size of slab position - align_up(sizeof(obj)) */
size_t size;
 
int (*constructor)(void *obj, int kmflag);
int (*destructor)(void *obj);
 
/** Flags changing behaviour of cache */
int flags;
 
/* Computed values */
uint8_t order; /**< Order of frames to be allocated */
unsigned int objects; /**< Number of objects that fit in */
uint8_t order; /**< Order of frames to be allocated */
int objects; /**< Number of objects that fit in */
 
/* Statistics */
atomic_t allocated_slabs;
atomic_t allocated_objs;
109,26 → 108,27
atomic_t cached_objs;
/** How many magazines in magazines list */
atomic_t magazine_counter;
 
/* Slabs */
link_t full_slabs; /**< List of full slabs */
link_t partial_slabs; /**< List of partial slabs */
link_t full_slabs; /**< List of full slabs */
link_t partial_slabs; /**< List of partial slabs */
SPINLOCK_DECLARE(slablock);
/* Magazines */
link_t magazines; /**< List o full magazines */
/* Magazines */
link_t magazines; /**< List o full magazines */
SPINLOCK_DECLARE(maglock);
 
/** CPU cache */
slab_mag_cache_t *mag_cache;
} slab_cache_t;
 
extern slab_cache_t *slab_cache_create(char *, size_t, size_t,
int (*)(void *, int), int (*)(void *), int);
extern void slab_cache_destroy(slab_cache_t *);
extern slab_cache_t * slab_cache_create(char *name, size_t size, size_t align,
int (*constructor)(void *obj, int kmflag), int (*destructor)(void *obj),
int flags);
extern void slab_cache_destroy(slab_cache_t *cache);
 
extern void * slab_alloc(slab_cache_t *, int);
extern void slab_free(slab_cache_t *, void *);
extern size_t slab_reclaim(int);
extern void * slab_alloc(slab_cache_t *cache, int flags);
extern void slab_free(slab_cache_t *cache, void *obj);
extern count_t slab_reclaim(int flags);
 
/* slab subsytem initialization */
extern void slab_cache_init(void);
138,10 → 138,9
extern void slab_print_list(void);
 
/* malloc support */
extern void *malloc(unsigned int, int);
extern void *realloc(void *, unsigned int, int);
extern void free(void *);
 
extern void * malloc(unsigned int size, int flags);
extern void * realloc(void *ptr, unsigned int size, int flags);
extern void free(void *ptr);
#endif
 
/** @}
/branches/arm/kernel/generic/include/mm/frame.h
38,82 → 38,33
 
#include <arch/types.h>
#include <adt/list.h>
#include <synch/spinlock.h>
#include <mm/buddy.h>
#include <synch/spinlock.h>
#include <arch/mm/page.h>
#include <arch/mm/frame.h>
 
#define ONE_FRAME 0
#define TWO_FRAMES 1
#define FOUR_FRAMES 2
#define ONE_FRAME 0
#define TWO_FRAMES 1
 
 
#ifdef ARCH_STACK_FRAMES
#define STACK_FRAMES ARCH_STACK_FRAMES
#define STACK_FRAMES ARCH_STACK_FRAMES
#else
#define STACK_FRAMES ONE_FRAME
#define STACK_FRAMES ONE_FRAME
#endif
 
/** Maximum number of zones in the system. */
#define ZONES_MAX 32
/** Maximum number of zones in system. */
#define ZONES_MAX 16
 
typedef uint8_t frame_flags_t;
/** If possible, merge with neighbouring zones. */
#define ZONE_JOIN 0x1
 
/** Convert the frame address to kernel VA. */
#define FRAME_KA 0x01
/** Convert the frame address to kernel va. */
#define FRAME_KA 0x1
/** Do not panic and do not sleep on failure. */
#define FRAME_ATOMIC 0x02
#define FRAME_ATOMIC 0x2
/** Do not start reclaiming when no free memory. */
#define FRAME_NO_RECLAIM 0x04
#define FRAME_NO_RECLAIM 0x4
 
typedef uint8_t zone_flags_t;
 
/** Available zone (free for allocation) */
#define ZONE_AVAILABLE 0x00
/** Zone is reserved (not available for allocation) */
#define ZONE_RESERVED 0x08
/** Zone is used by firmware (not available for allocation) */
#define ZONE_FIRMWARE 0x10
 
/** Currently there is no equivalent zone flags
for frame flags */
#define FRAME_TO_ZONE_FLAGS(frame_flags) 0
 
typedef struct {
size_t refcount; /**< Tracking of shared frames */
uint8_t buddy_order; /**< Buddy system block order */
link_t buddy_link; /**< Link to the next free block inside
one order */
void *parent; /**< If allocated by slab, this points there */
} frame_t;
 
typedef struct {
pfn_t base; /**< Frame_no of the first frame
in the frames array */
size_t count; /**< Size of zone */
size_t free_count; /**< Number of free frame_t
structures */
size_t busy_count; /**< Number of busy frame_t
structures */
zone_flags_t flags; /**< Type of the zone */
frame_t *frames; /**< Array of frame_t structures
in this zone */
buddy_system_t *buddy_system; /**< Buddy system for the zone */
} zone_t;
 
/*
* The zoneinfo.lock must be locked when accessing zoneinfo structure.
* Some of the attributes in zone_t structures are 'read-only'
*/
typedef struct {
SPINLOCK_DECLARE(lock);
size_t count;
zone_t info[ZONES_MAX];
} zones_t;
 
extern zones_t zones;
 
static inline uintptr_t PFN2ADDR(pfn_t frame)
{
return (uintptr_t) (frame << FRAME_WIDTH);
124,57 → 75,45
return (pfn_t) (addr >> FRAME_WIDTH);
}
 
static inline size_t SIZE2FRAMES(size_t size)
static inline count_t SIZE2FRAMES(size_t size)
{
if (!size)
return 0;
return (size_t) ((size - 1) >> FRAME_WIDTH) + 1;
return (count_t) ((size - 1) >> FRAME_WIDTH) + 1;
}
 
static inline size_t FRAMES2SIZE(size_t frames)
{
return (size_t) (frames << FRAME_WIDTH);
}
#define IS_BUDDY_ORDER_OK(index, order) \
((~(((unative_t) -1) << (order)) & (index)) == 0)
#define IS_BUDDY_LEFT_BLOCK(zone, frame) \
(((frame_index((zone), (frame)) >> (frame)->buddy_order) & 0x1) == 0)
#define IS_BUDDY_RIGHT_BLOCK(zone, frame) \
(((frame_index((zone), (frame)) >> (frame)->buddy_order) & 0x1) == 1)
#define IS_BUDDY_LEFT_BLOCK_ABS(zone, frame) \
(((frame_index_abs((zone), (frame)) >> (frame)->buddy_order) & 0x1) == 0)
#define IS_BUDDY_RIGHT_BLOCK_ABS(zone, frame) \
(((frame_index_abs((zone), (frame)) >> (frame)->buddy_order) & 0x1) == 1)
 
static inline bool zone_flags_available(zone_flags_t flags)
{
return ((flags & (ZONE_RESERVED | ZONE_FIRMWARE)) == 0);
}
#define frame_alloc(order, flags) \
frame_alloc_generic(order, flags, NULL)
 
#define IS_BUDDY_ORDER_OK(index, order) \
((~(((unative_t) -1) << (order)) & (index)) == 0)
#define IS_BUDDY_LEFT_BLOCK(zone, frame) \
(((frame_index((zone), (frame)) >> (frame)->buddy_order) & 0x01) == 0)
#define IS_BUDDY_RIGHT_BLOCK(zone, frame) \
(((frame_index((zone), (frame)) >> (frame)->buddy_order) & 0x01) == 1)
#define IS_BUDDY_LEFT_BLOCK_ABS(zone, frame) \
(((frame_index_abs((zone), (frame)) >> (frame)->buddy_order) & 0x01) == 0)
#define IS_BUDDY_RIGHT_BLOCK_ABS(zone, frame) \
(((frame_index_abs((zone), (frame)) >> (frame)->buddy_order) & 0x01) == 1)
 
#define frame_alloc(order, flags) \
frame_alloc_generic(order, flags, NULL)
 
extern void frame_init(void);
extern void *frame_alloc_generic(uint8_t, frame_flags_t, size_t *);
extern void frame_free(uintptr_t);
extern void frame_reference_add(pfn_t);
extern void *frame_alloc_generic(uint8_t order, int flags, unsigned int *pzone);
extern void frame_free(uintptr_t frame);
extern void frame_reference_add(pfn_t pfn);
 
extern size_t find_zone(pfn_t frame, size_t count, size_t hint);
extern size_t zone_create(pfn_t, size_t, pfn_t, zone_flags_t);
extern void *frame_get_parent(pfn_t, size_t);
extern void frame_set_parent(pfn_t, void *, size_t);
extern void frame_mark_unavailable(pfn_t, size_t);
extern uintptr_t zone_conf_size(size_t);
extern bool zone_merge(size_t, size_t);
extern void zone_merge_all(void);
extern uint64_t zone_total_size(void);
extern int zone_create(pfn_t start, count_t count, pfn_t confframe, int flags);
void *frame_get_parent(pfn_t frame, unsigned int hint);
void frame_set_parent(pfn_t frame, void *data, unsigned int hint);
void frame_mark_unavailable(pfn_t start, count_t count);
uintptr_t zone_conf_size(count_t count);
void zone_merge(unsigned int z1, unsigned int z2);
void zone_merge_all(void);
 
/*
* Console functions
*/
extern void zone_print_list(void);
extern void zone_print_one(size_t);
void zone_print_one(unsigned int znum);
 
#endif
 
/branches/arm/kernel/generic/include/mm/page.h
39,10 → 39,15
#include <mm/as.h>
#include <memstr.h>
 
/**
* Macro for computing page color.
*/
#define PAGE_COLOR(va) (((va) >> PAGE_WIDTH) & ((1 << PAGE_COLOR_BITS) - 1))
 
/** Operations to manipulate page mappings. */
typedef struct {
void (* mapping_insert)(as_t *as, uintptr_t page, uintptr_t frame,
int flags);
int flags);
void (* mapping_remove)(as_t *as, uintptr_t page);
pte_t *(* mapping_find)(as_t *as, uintptr_t page);
} page_mapping_operations_t;
59,7 → 64,6
extern pte_t *page_table_create(int flags);
extern void page_table_destroy(pte_t *page_table);
extern void map_structure(uintptr_t s, size_t size);
 
extern uintptr_t hw_map(uintptr_t physaddr, size_t size);
 
#endif
/branches/arm/kernel/generic/include/mm/tlb.h
61,7 → 61,7
tlb_invalidate_type_t type; /**< Message type. */
asid_t asid; /**< Address space identifier. */
uintptr_t page; /**< Page address. */
size_t count; /**< Number of pages to invalidate. */
count_t count; /**< Number of pages to invalidate. */
} tlb_shootdown_msg_t;
 
extern void tlb_init(void);
68,7 → 68,7
 
#ifdef CONFIG_SMP
extern void tlb_shootdown_start(tlb_invalidate_type_t type, asid_t asid,
uintptr_t page, size_t count);
uintptr_t page, count_t count);
extern void tlb_shootdown_finalize(void);
extern void tlb_shootdown_ipi_recv(void);
#else
84,7 → 84,7
 
extern void tlb_invalidate_all(void);
extern void tlb_invalidate_asid(asid_t asid);
extern void tlb_invalidate_pages(asid_t asid, uintptr_t page, size_t cnt);
extern void tlb_invalidate_pages(asid_t asid, uintptr_t page, count_t cnt);
#endif
 
/** @}
/branches/arm/kernel/generic/include/mm/buddy.h
66,6 → 66,7
void (*mark_available)(struct buddy_system *, link_t *);
/** Find parent of block that has given order */
link_t *(* find_block)(struct buddy_system *, link_t *, uint8_t);
void (* print_id)(struct buddy_system *, link_t *);
} buddy_system_operations_t;
 
typedef struct buddy_system {
77,13 → 78,14
void *data;
} buddy_system_t;
 
extern void buddy_system_create(buddy_system_t *, uint8_t,
buddy_system_operations_t *, void *);
extern link_t *buddy_system_alloc(buddy_system_t *, uint8_t);
extern bool buddy_system_can_alloc(buddy_system_t *, uint8_t);
extern void buddy_system_free(buddy_system_t *, link_t *);
extern size_t buddy_conf_size(size_t);
extern link_t *buddy_system_alloc_block(buddy_system_t *, link_t *);
extern void buddy_system_create(buddy_system_t *b, uint8_t max_order,
buddy_system_operations_t *op, void *data);
extern link_t *buddy_system_alloc(buddy_system_t *b, uint8_t i);
extern bool buddy_system_can_alloc(buddy_system_t *b, uint8_t order);
extern void buddy_system_free(buddy_system_t *b, link_t *block);
extern void buddy_system_structure_print(buddy_system_t *b, size_t elem_size);
extern size_t buddy_conf_size(int max_order);
extern link_t *buddy_system_alloc_block(buddy_system_t *b, link_t *block);
 
#endif
 
/branches/arm/kernel/generic/include/memstr.h
42,9 → 42,9
* Architecture independent variants.
*/
extern void *_memcpy(void *dst, const void *src, size_t cnt);
extern void _memsetb(void *dst, size_t cnt, uint8_t x);
extern void _memsetw(void *dst, size_t cnt, uint16_t x);
extern void *memmove(void *dst, const void *src, size_t cnt);
extern void _memsetb(uintptr_t dst, size_t cnt, uint8_t x);
extern void _memsetw(uintptr_t dst, size_t cnt, uint16_t x);
extern char *strcpy(char *dest, const char *src);
 
#endif
 
/branches/arm/kernel/generic/include/syscall/syscall.h
36,55 → 36,35
#define KERN_SYSCALL_H_
 
typedef enum {
SYS_KLOG = 0,
SYS_TLS_SET = 1, /* Hardcoded in AMD64, IA32 uspace - fibril.S */
SYS_IO = 0,
SYS_TLS_SET = 1, /* Hardcoded in AMD64, IA32 uspace - psthread.S */
SYS_THREAD_CREATE,
SYS_THREAD_EXIT,
SYS_THREAD_GET_ID,
SYS_TASK_GET_ID,
SYS_TASK_SET_NAME,
SYS_PROGRAM_SPAWN_LOADER,
SYS_FUTEX_SLEEP,
SYS_FUTEX_WAKEUP,
SYS_SMC_COHERENCE,
SYS_AS_AREA_CREATE,
SYS_AS_AREA_RESIZE,
SYS_AS_AREA_CHANGE_FLAGS,
SYS_AS_AREA_DESTROY,
SYS_IPC_CALL_SYNC_FAST,
SYS_IPC_CALL_SYNC_SLOW,
SYS_IPC_CALL_SYNC,
SYS_IPC_CALL_ASYNC_FAST,
SYS_IPC_CALL_ASYNC_SLOW,
SYS_IPC_CALL_ASYNC,
SYS_IPC_ANSWER_FAST,
SYS_IPC_ANSWER_SLOW,
SYS_IPC_ANSWER,
SYS_IPC_FORWARD_FAST,
SYS_IPC_FORWARD_SLOW,
SYS_IPC_WAIT,
SYS_IPC_HANGUP,
SYS_IPC_REGISTER_IRQ,
SYS_IPC_UNREGISTER_IRQ,
 
SYS_EVENT_SUBSCRIBE,
SYS_CAP_GRANT,
SYS_CAP_REVOKE,
SYS_DEVICE_ASSIGN_DEVNO,
SYS_PHYSMEM_MAP,
SYS_IOSPACE_ENABLE,
SYS_PREEMPT_CONTROL,
SYS_SYSINFO_VALID,
SYS_SYSINFO_VALUE,
SYS_DEBUG_ENABLE_CONSOLE,
SYS_DEBUG_DISABLE_CONSOLE,
SYS_IPC_CONNECT_KBOX,
SYSCALL_END
} syscall_t;
 
92,13 → 72,12
 
#include <arch/types.h>
 
typedef unative_t (*syshandler_t)(unative_t, unative_t, unative_t, unative_t,
unative_t, unative_t);
typedef unative_t (*syshandler_t)(unative_t, unative_t, unative_t, unative_t);
 
extern syshandler_t syscall_table[SYSCALL_END];
extern unative_t syscall_handler(unative_t, unative_t, unative_t, unative_t,
unative_t, unative_t, unative_t);
extern unative_t sys_tls_set(unative_t);
extern unative_t syscall_handler(unative_t a1, unative_t a2, unative_t a3,
unative_t a4, unative_t id);
extern unative_t sys_tls_set(unative_t addr);
 
#endif
 
/branches/arm/kernel/generic/include/proc/program.h
File deleted
/branches/arm/kernel/generic/include/proc/tasklet.h
File deleted
/branches/arm/kernel/generic/include/proc/thread.h
1,5 → 1,5
/*
* Copyright (c) 2001-2007 Jakub Jermar
* Copyright (c) 2001-2004 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
40,13 → 40,11
#include <time/timeout.h>
#include <cpu.h>
#include <synch/rwlock.h>
#include <synch/spinlock.h>
#include <adt/avl.h>
#include <adt/btree.h>
#include <mm/slab.h>
#include <arch/cpu.h>
#include <mm/tlb.h>
#include <proc/uarg.h>
#include <udebug/udebug.h>
 
#define THREAD_STACK_SIZE STACK_SIZE
#define THREAD_NAME_BUFLEN 20
55,18 → 53,12
 
/* Thread flags */
 
/** Thread cannot be migrated to another CPU.
*
* When using this flag, the caller must set cpu in the thread_t
* structure manually before calling thread_ready (even on uniprocessor).
*/
/** Thread cannot be migrated to another CPU. */
#define THREAD_FLAG_WIRED (1 << 0)
/** Thread was migrated to another CPU and has not run yet. */
#define THREAD_FLAG_STOLEN (1 << 1)
/** Thread executes in userspace. */
#define THREAD_FLAG_USPACE (1 << 2)
/** Thread will be attached by the caller. */
#define THREAD_FLAG_NOATTACH (1 << 3)
 
/** Thread states. */
typedef enum {
82,18 → 74,22
Entering,
/** After a thread calls thread_exit(), it is put into Exiting state. */
Exiting,
/** Threads that were not detached but exited are Lingering. */
Lingering
/** Threads that were not detached but exited are in the Undead state. */
Undead
} state_t;
 
/** Join types. */
typedef enum {
None,
TaskClnp, /**< The thread will be joined by ktaskclnp thread. */
TaskGC /**< The thread will be joined by ktaskgc thread. */
} thread_join_type_t;
 
/** Thread structure. There is one per thread. */
typedef struct thread {
link_t rq_link; /**< Run queue link. */
link_t wq_link; /**< Wait queue link. */
link_t th_link; /**< Links to threads within containing task. */
 
/** Threads linkage to the threads_tree. */
avltree_node_t threads_tree_node;
/** Lock protecting thread structure.
*
150,12 → 146,12
*/
bool interrupted;
/** Who joinins the thread. */
thread_join_type_t join_type;
/** If true, thread_join_timeout() cannot be used on this thread. */
bool detached;
/** Waitq for thread_join_timeout(). */
waitq_t join_wq;
/** Link used in the joiner_head list. */
link_t joiner_link;
 
fpu_context_t *saved_fpu_context;
int fpu_context_exists;
197,7 → 193,7
/** Thread's priority. Implemented as index to CPU->rq */
int priority;
/** Thread ID. */
thread_id_t tid;
uint32_t tid;
/** Architecture-specific data. */
thread_arch_t arch;
204,29 → 200,22
 
/** Thread's kernel stack. */
uint8_t *kstack;
 
#ifdef CONFIG_UDEBUG
/** Debugging stuff */
udebug_thread_t udebug;
#endif
 
} thread_t;
 
/** Thread list lock.
*
* This lock protects the threads_tree.
* This lock protects all link_t structures chained in threads_head.
* Must be acquired before T.lock for each T of type thread_t.
*
*/
SPINLOCK_EXTERN(threads_lock);
 
/** AVL tree containing all threads. */
extern avltree_t threads_tree;
/** B+tree containing all threads. */
extern btree_t threads_btree;
 
extern void thread_init(void);
extern thread_t *thread_create(void (* func)(void *), void *arg, task_t *task,
int flags, char *name, bool uncounted);
extern void thread_attach(thread_t *t, task_t *task);
extern void thread_ready(thread_t *t);
extern void thread_exit(void) __attribute__((noreturn));
 
259,10 → 248,8
extern slab_cache_t *fpu_context_slab;
 
/* Thread syscall prototypes. */
extern unative_t sys_thread_create(uspace_arg_t *uspace_uarg,
char *uspace_name, size_t name_len, thread_id_t *uspace_thread_id);
extern unative_t sys_thread_exit(int uspace_status);
extern unative_t sys_thread_get_id(thread_id_t *uspace_thread_id);
unative_t sys_thread_create(uspace_arg_t *uspace_uarg, char *uspace_name);
unative_t sys_thread_exit(int uspace_status);
 
#endif
 
/branches/arm/kernel/generic/include/proc/task.h
41,7 → 41,6
#include <synch/mutex.h>
#include <synch/rwlock.h>
#include <synch/futex.h>
#include <adt/avl.h>
#include <adt/btree.h>
#include <adt/list.h>
#include <security/cap.h>
52,18 → 51,11
#include <arch/cpu.h>
#include <mm/tlb.h>
#include <proc/scheduler.h>
#include <udebug/udebug.h>
#include <ipc/kbox.h>
 
#define TASK_NAME_BUFLEN 20
 
struct thread;
 
/** Task structure. */
typedef struct task {
/** Task's linkage for the tasks_tree AVL tree. */
avltree_node_t tasks_tree_node;
/** Task lock.
*
* Must be acquired before threads_lock and thread lock of any of its
70,8 → 62,10
* threads.
*/
SPINLOCK_DECLARE(lock);
 
char name[TASK_NAME_BUFLEN];
char *name;
/** Pointer to the main thread. */
struct thread *main_thread;
/** List of threads contained in this task. */
link_t th_head;
/** Address space. */
81,10 → 75,10
/** Task security context. */
context_id_t context;
 
/** If this is true, new threads can become part of the task. */
bool accept_new_threads;
/** Number of references (i.e. threads). */
atomic_t refcount;
/** Number of threads that haven't exited yet. */
atomic_t lifecount;
count_t refcount;
 
/** Task capabilities. */
cap_t capabilities;
96,18 → 90,10
* Active asynchronous messages. It is used for limiting uspace to
* certain extent.
*/
atomic_t active_calls;
 
#ifdef CONFIG_UDEBUG
/** Debugging stuff. */
udebug_task_t udebug;
 
/** Kernel answerbox. */
kbox_t kb;
#endif
 
atomic_t active_calls;
/** Architecture specific task data. */
task_arch_t arch;
task_arch_t arch;
/**
* Serializes access to the B+tree of task's futexes. This mutex is
122,12 → 108,12
} task_t;
 
SPINLOCK_EXTERN(tasks_lock);
extern avltree_t tasks_tree;
extern btree_t tasks_btree;
 
extern void task_init(void);
extern void task_done(void);
extern task_t *task_create(as_t *as, char *name);
extern void task_destroy(task_t *t);
extern task_t *task_run_program(void *program_addr, char *name);
extern task_t *task_find_by_id(task_id_t id);
extern int task_kill(task_id_t id);
extern uint64_t task_get_accounting(task_t *t);
135,6 → 121,7
extern void cap_set(task_t *t, cap_t caps);
extern cap_t cap_get(task_t *t);
 
 
#ifndef task_create_arch
extern void task_create_arch(task_t *t);
#endif
144,7 → 131,6
#endif
 
extern unative_t sys_task_get_id(task_id_t *uspace_task_id);
extern unative_t sys_task_set_name(const char *uspace_name, size_t name_len);
 
#endif
 
/branches/arm/kernel/generic/include/proc/scheduler.h
47,7 → 47,7
typedef struct {
SPINLOCK_DECLARE(lock);
link_t rq_head; /**< List of ready threads. */
size_t n; /**< Number of threads in rq_ready. */
count_t n; /**< Number of threads in rq_ready. */
} runq_t;
 
extern atomic_t nrdy;
/branches/arm/kernel/generic/include/synch/smc.h
File deleted
/branches/arm/kernel/generic/include/synch/waitq.h
40,10 → 40,8
#include <synch/synch.h>
#include <adt/list.h>
 
typedef enum {
WAKEUP_FIRST = 0,
WAKEUP_ALL
} wakeup_mode_t;
#define WAKEUP_FIRST 0
#define WAKEUP_ALL 1
 
/** Wait queue structure. */
typedef struct {
72,8 → 70,8
extern ipl_t waitq_sleep_prepare(waitq_t *wq);
extern int waitq_sleep_timeout_unsafe(waitq_t *wq, uint32_t usec, int flags);
extern void waitq_sleep_finish(waitq_t *wq, int rc, ipl_t ipl);
extern void waitq_wakeup(waitq_t *wq, wakeup_mode_t mode);
extern void _waitq_wakeup_unsafe(waitq_t *wq, wakeup_mode_t mode);
extern void waitq_wakeup(waitq_t *wq, bool all);
extern void _waitq_wakeup_unsafe(waitq_t *wq, bool all);
extern void waitq_interrupt_sleep(struct thread *t);
 
#endif
/branches/arm/kernel/generic/include/synch/futex.h
49,7 → 49,7
/** Futex hash table link. */
link_t ht_link;
/** Number of tasks that reference this futex. */
size_t refcount;
count_t refcount;
} futex_t;
 
extern void futex_init(void);
/branches/arm/kernel/generic/include/synch/rwlock.h
53,7 → 53,7
*/
mutex_t exclusive;
/** Number of readers in critical section. */
size_t readers_in;
count_t readers_in;
} rwlock_t;
 
#define rwlock_write_lock(rwl) \
/branches/arm/kernel/generic/include/synch/spinlock.h
36,7 → 36,6
#define KERN_SPINLOCK_H_
 
#include <arch/types.h>
#include <arch/barrier.h>
#include <preemption.h>
#include <atomic.h>
#include <debug.h>
102,26 → 101,8
preemption_enable();
}
 
#ifdef CONFIG_DEBUG_SPINLOCK
 
extern int printf(const char *, ...);
 
#define DEADLOCK_THRESHOLD 100000000
#define DEADLOCK_PROBE_INIT(pname) size_t pname = 0
#define DEADLOCK_PROBE(pname, value) \
if ((pname)++ > (value)) { \
(pname) = 0; \
printf("Deadlock probe %s: exceeded threshold %u\n", \
"cpu%u: function=%s, line=%u\n", \
#pname, (value), CPU->id, __func__, __LINE__); \
}
#else
#define DEADLOCK_PROBE_INIT(pname)
#define DEADLOCK_PROBE(pname, value)
#endif
 
#else
 
/* On UP systems, spinlocks are effectively left out. */
#define SPINLOCK_DECLARE(name)
#define SPINLOCK_EXTERN(name)
132,9 → 113,6
#define spinlock_trylock(x) (preemption_disable(), 1)
#define spinlock_unlock(x) preemption_enable()
 
#define DEADLOCK_PROBE_INIT(pname)
#define DEADLOCK_PROBE(pname, value)
 
#endif
 
#endif
/branches/arm/kernel/generic/include/synch/mutex.h
39,26 → 39,22
#include <synch/semaphore.h>
#include <synch/synch.h>
 
typedef enum {
MUTEX_PASSIVE,
MUTEX_ACTIVE
} mutex_type_t;
 
typedef struct {
mutex_type_t type;
semaphore_t sem;
} mutex_t;
 
#define mutex_lock(mtx) \
_mutex_lock_timeout((mtx), SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE)
#define mutex_trylock(mtx) \
_mutex_lock_timeout((mtx), SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NON_BLOCKING)
#define mutex_lock_timeout(mtx, usec) \
_mutex_lock_timeout((mtx), (usec), SYNCH_FLAGS_NON_BLOCKING)
#define mutex_lock(mtx) \
_mutex_lock_timeout((mtx),SYNCH_NO_TIMEOUT,SYNCH_FLAGS_NONE)
#define mutex_trylock(mtx) \
_mutex_lock_timeout((mtx),SYNCH_NO_TIMEOUT,SYNCH_FLAGS_NON_BLOCKING)
#define mutex_lock_timeout(mtx,usec) \
_mutex_lock_timeout((mtx),(usec),SYNCH_FLAGS_NON_BLOCKING)
#define mutex_lock_active(mtx) \
while (mutex_trylock((mtx)) != ESYNCH_OK_ATOMIC)
 
extern void mutex_initialize(mutex_t *, mutex_type_t);
extern int _mutex_lock_timeout(mutex_t *, uint32_t, int);
extern void mutex_unlock(mutex_t *);
extern void mutex_initialize(mutex_t *mtx);
extern int _mutex_lock_timeout(mutex_t *mtx, uint32_t usec, int flags);
extern void mutex_unlock(mutex_t *mtx);
 
#endif
 
/branches/arm/kernel/generic/include/ddi/irq.h
36,16 → 36,18
#define KERN_IRQ_H_
 
typedef enum {
CMD_PIO_READ_8 = 1,
CMD_PIO_READ_16,
CMD_PIO_READ_32,
CMD_PIO_WRITE_8,
CMD_PIO_WRITE_16,
CMD_PIO_WRITE_32,
CMD_BTEST,
CMD_PREDICATE,
CMD_ACCEPT,
CMD_DECLINE,
CMD_MEM_READ_1 = 0,
CMD_MEM_READ_2,
CMD_MEM_READ_4,
CMD_MEM_READ_8,
CMD_MEM_WRITE_1,
CMD_MEM_WRITE_2,
CMD_MEM_WRITE_4,
CMD_MEM_WRITE_8,
CMD_PORT_READ_1,
CMD_PORT_WRITE_1,
CMD_IA64_GETCHAR,
CMD_PPC32_GETCHAR,
CMD_LAST
} irq_cmd_type;
 
52,9 → 54,8
typedef struct {
irq_cmd_type cmd;
void *addr;
unsigned long long value;
unsigned int srcarg;
unsigned int dstarg;
unsigned long long value;
int dstarg;
} irq_cmd_t;
 
typedef struct {
66,10 → 67,8
 
#include <arch/types.h>
#include <adt/list.h>
#include <adt/hash_table.h>
#include <synch/spinlock.h>
#include <proc/task.h>
#include <ipc/ipc.h>
 
typedef enum {
IRQ_DECLINE, /**< Decline to service. */
82,11 → 81,8
} irq_trigger_t;
 
struct irq;
typedef void (* irq_handler_t)(struct irq *);
typedef void (* irq_handler_t)(struct irq *irq, void *arg, ...);
 
/** Type for function used to clear the interrupt. */
typedef void (* cir_t)(void *, inr_t);
 
/** IPC notification config structure.
*
* Primarily, this structure is encapsulated in the irq_t structure.
99,12 → 95,10
answerbox_t *answerbox;
/** Method to be used for the notification. */
unative_t method;
/** Arguments that will be sent if the IRQ is claimed. */
unative_t scratch[IPC_CALL_LEN];
/** Top-half pseudocode. */
irq_code_t *code;
/** Counter. */
size_t counter;
count_t counter;
/**
* Link between IRQs that are notifying the same answerbox. The list is
* protected by the answerbox irq_lock.
127,14 → 121,6
* this lock must not be taken first.
*/
SPINLOCK_DECLARE(lock);
/** Send EOI before processing the interrupt.
* This is essential for timer interrupt which
* has to be acknowledged before doing preemption
* to make sure another timer interrupt will
* be eventually generated.
*/
bool preack;
 
/** Unique device number. -1 if not yet assigned. */
devno_t devno;
141,32 → 127,25
 
/** Actual IRQ number. -1 if not yet assigned. */
inr_t inr;
/** Trigger level of the IRQ. */
/** Trigger level of the IRQ.*/
irq_trigger_t trigger;
/** Claim ownership of the IRQ. */
irq_ownership_t (* claim)(struct irq *);
irq_ownership_t (* claim)(void);
/** Handler for this IRQ and device. */
irq_handler_t handler;
/** Instance argument for the handler and the claim function. */
void *instance;
/** Argument for the handler. */
void *arg;
 
/** Clear interrupt routine. */
cir_t cir;
/** First argument to the clear interrupt routine. */
void *cir_arg;
 
/** Notification configuration structure. */
ipc_notif_cfg_t notif_cfg;
} irq_t;
 
SPINLOCK_EXTERN(irq_uspace_hash_table_lock);
extern hash_table_t irq_uspace_hash_table;
extern void irq_init(count_t inrs, count_t chains);
extern void irq_initialize(irq_t *irq);
extern void irq_register(irq_t *irq);
extern irq_t *irq_dispatch_and_lock(inr_t inr);
extern irq_t *irq_find_and_lock(inr_t inr, devno_t devno);
 
extern void irq_init(size_t, size_t);
extern void irq_initialize(irq_t *);
extern void irq_register(irq_t *);
extern irq_t *irq_dispatch_and_lock(inr_t);
 
#endif
 
#endif
/branches/arm/kernel/generic/include/ddi/device.h
35,11 → 35,7
#ifndef KERN_DEVICE_H_
#define KERN_DEVICE_H_
 
#include <arch/types.h>
#include <typedefs.h>
 
extern devno_t device_assign_devno(void);
extern unative_t sys_device_assign_devno(void);
 
#endif
 
/branches/arm/kernel/generic/include/ddi/ddi.h
38,14 → 38,13
#include <ddi/ddi_arg.h>
#include <arch/types.h>
#include <proc/task.h>
#include <adt/list.h>
 
/** Structure representing contiguous physical memory area. */
typedef struct {
uintptr_t pbase; /**< Physical base of the area. */
pfn_t frames; /**< Number of frames in the area. */
link_t link; /**< Linked list link */
uintptr_t pbase; /**< Physical base of the area. */
uintptr_t vbase; /**< Virtual base of the area. */
count_t frames; /**< Number of frames in the area. */
bool cacheable; /**< Cacheability. */
} parea_t;
 
extern void ddi_init(void);
/branches/arm/kernel/generic/include/time/clock.h
35,19 → 35,8
#ifndef KERN_CLOCK_H_
#define KERN_CLOCK_H_
 
#include <arch/types.h>
 
#define HZ 100
 
/** Uptime structure */
typedef struct {
unative_t seconds1;
unative_t useconds;
unative_t seconds2;
} uptime_t;
 
extern uptime_t *uptime;
 
extern void clock(void);
extern void clock_counter_init(void);
 
/branches/arm/kernel/generic/include/console/chardev.h
39,63 → 39,41
#include <synch/waitq.h>
#include <synch/spinlock.h>
 
#define INDEV_BUFLEN 512
#define CHARDEV_BUFLEN 512
 
struct indev;
struct chardev;
 
/* Input character device operations interface. */
/* Character device operations interface. */
typedef struct {
/** Suspend pushing characters. */
void (* suspend)(struct chardev *);
/** Resume pushing characters. */
void (* resume)(struct chardev *);
/** Write character to stream. */
void (* write)(struct chardev *, char c);
/** Read character directly from device, assume interrupts disabled. */
wchar_t (* poll)(struct indev *);
} indev_operations_t;
char (* read)(struct chardev *);
} chardev_operations_t;
 
/** Character input device. */
typedef struct indev {
typedef struct chardev {
char *name;
waitq_t wq;
/** Protects everything below. */
SPINLOCK_DECLARE(lock);
wchar_t buffer[INDEV_BUFLEN];
size_t counter;
/** Implementation of indev operations. */
indev_operations_t *op;
size_t index;
SPINLOCK_DECLARE(lock);
uint8_t buffer[CHARDEV_BUFLEN];
count_t counter;
/** Implementation of chardev operations. */
chardev_operations_t *op;
index_t index;
void *data;
} indev_t;
} chardev_t;
 
extern void chardev_initialize(char *name, chardev_t *chardev,
chardev_operations_t *op);
extern void chardev_push_character(chardev_t *chardev, uint8_t ch);
 
struct outdev;
 
/* Output character device operations interface. */
typedef struct {
/** Write character to output. */
void (* write)(struct outdev *, wchar_t, bool);
} outdev_operations_t;
 
/** Character input device. */
typedef struct outdev {
char *name;
/** Protects everything below. */
SPINLOCK_DECLARE(lock);
/** Implementation of outdev operations. */
outdev_operations_t *op;
void *data;
} outdev_t;
 
extern void indev_initialize(char *name, indev_t *indev,
indev_operations_t *op);
extern void indev_push_character(indev_t *indev, wchar_t ch);
extern wchar_t indev_pop_character(indev_t *indev);
 
extern void outdev_initialize(char *name, outdev_t *outdev,
outdev_operations_t *op);
 
extern bool check_poll(indev_t *indev);
 
#endif /* KERN_CHARDEV_H_ */
 
/** @}
/branches/arm/kernel/generic/include/console/kconsole.h
37,10 → 37,9
 
#include <adt/list.h>
#include <synch/spinlock.h>
#include <ipc/irq.h>
 
#define MAX_CMDLINE 256
#define KCONSOLE_HISTORY 10
#define MAX_CMDLINE 256
#define KCONSOLE_HISTORY 10
 
typedef enum {
ARG_TYPE_INVALID = 0,
47,7 → 46,7
ARG_TYPE_INT,
ARG_TYPE_STRING,
/** Variable type - either symbol or string. */
ARG_TYPE_VAR
ARG_TYPE_VAR
} cmd_arg_type_t;
 
/** Structure representing one argument of kconsole command line. */
77,7 → 76,7
/** Function implementing the command. */
int (* func)(cmd_arg_t *);
/** Number of arguments. */
size_t argc;
count_t argc;
/** Argument vector. */
cmd_arg_t *argv;
/** Function for printing detailed help. */
84,19 → 83,13
void (* help)(void);
} cmd_info_t;
 
extern bool kconsole_notify;
extern irq_t kconsole_irq;
 
SPINLOCK_EXTERN(cmd_lock);
extern link_t cmd_head;
 
extern void kconsole_init(void);
extern void kconsole_notify_init(void);
extern bool kconsole_check_poll(void);
extern void kconsole(char *prompt, char *msg, bool kcon);
extern void kconsole_thread(void *data);
extern void kconsole(void *prompt);
 
extern bool cmd_register(cmd_info_t *cmd);
extern int cmd_register(cmd_info_t *cmd);
 
#endif
 
/branches/arm/kernel/generic/include/console/console.h
38,26 → 38,14
#include <arch/types.h>
#include <console/chardev.h>
 
extern indev_t *stdin;
extern outdev_t *stdout;
extern bool silent;
extern chardev_t *stdin;
extern chardev_t *stdout;
 
extern indev_t *stdin_wire(void);
extern void console_init(void);
extern uint8_t getc(chardev_t *chardev);
uint8_t _getc(chardev_t *chardev);
extern count_t gets(chardev_t *chardev, char *buf, size_t buflen);
extern void putchar(char c);
 
extern void klog_init(void);
extern void klog_update(void);
 
extern wchar_t getc(indev_t *indev);
extern size_t gets(indev_t *indev, char *buf, size_t buflen);
extern unative_t sys_klog(int fd, const void *buf, size_t size);
 
extern void grab_console(void);
extern void release_console(void);
 
extern unative_t sys_debug_enable_console(void);
extern unative_t sys_debug_disable_console(void);
 
extern void arch_grab_console(void);
extern void arch_release_console(void);
 
/branches/arm/kernel/generic/include/console/klog.h
0,0 → 1,44
/*
* Copyright (c) 2006 Ondrej Palkovsky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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 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.
*/
 
/** @addtogroup genericklog
* @{
*/
/** @file
*/
 
#ifndef KERN_KLOG_H_
#define KERN_KLOG_H_
 
void klog_init(void);
void klog_printf(const char *fmt, ...);
 
#endif
 
/** @}
*/
/branches/arm/kernel/generic/include/adt/avl.h
File deleted
/branches/arm/kernel/generic/include/adt/hash_table.h
47,7 → 47,7
*
* @return Index into hash table.
*/
size_t (* hash)(unative_t key[]);
index_t (* hash)(unative_t key[]);
/** Hash table item comparison function.
*
56,7 → 56,7
*
* @return true if the keys match, false otherwise.
*/
bool (*compare)(unative_t key[], size_t keys, link_t *item);
bool (*compare)(unative_t key[], count_t keys, link_t *item);
 
/** Hash table item removal callback.
*
68,8 → 68,8
/** Hash table structure. */
typedef struct {
link_t *entry;
size_t entries;
size_t max_keys;
count_t entries;
count_t max_keys;
hash_table_operations_t *op;
} hash_table_t;
 
76,11 → 76,11
#define hash_table_get_instance(item, type, member) \
list_get_instance((item), type, member)
 
extern void hash_table_create(hash_table_t *h, size_t m, size_t max_keys,
extern void hash_table_create(hash_table_t *h, count_t m, count_t max_keys,
hash_table_operations_t *op);
extern void hash_table_insert(hash_table_t *h, unative_t key[], link_t *item);
extern link_t *hash_table_find(hash_table_t *h, unative_t key[]);
extern void hash_table_remove(hash_table_t *h, unative_t key[], size_t keys);
extern void hash_table_remove(hash_table_t *h, unative_t key[], count_t keys);
 
#endif
 
/branches/arm/kernel/generic/include/adt/list.h
36,7 → 36,6
#define KERN_LIST_H_
 
#include <arch/types.h>
#include <typedefs.h>
 
/** Doubly linked list head and link type. */
typedef struct link {
181,7 → 180,7
headless_list_split_or_concat(part1, part2);
}
 
#define list_get_instance(link, type, member) \
#define list_get_instance(link,type,member) \
((type *)(((uint8_t *)(link)) - ((uint8_t *)&(((type *)NULL)->member))))
 
extern bool list_member(const link_t *link, const link_t *head);
/branches/arm/kernel/generic/include/adt/btree.h
46,7 → 46,7
/** B-tree node structure. */
typedef struct btree_node {
/** Number of keys. */
size_t keys;
count_t keys;
 
/**
* Keys. We currently support only single keys. Additional room for one
/branches/arm/kernel/generic/include/adt/fifo.h
59,9 → 59,9
#define FIFO_INITIALIZE_STATIC(name, t, itms) \
struct { \
t fifo[(itms)]; \
size_t items; \
size_t head; \
size_t tail; \
count_t items; \
index_t head; \
index_t tail; \
} name = { \
.items = (itms), \
.head = 0, \
80,9 → 80,9
#define FIFO_INITIALIZE_DYNAMIC(name, t, itms) \
struct { \
t *fifo; \
size_t items; \
size_t head; \
size_t tail; \
count_t items; \
index_t head; \
index_t tail; \
} name = { \
.fifo = NULL, \
.items = (itms), \
/branches/arm/kernel/generic/include/adt/bitmap.h
41,23 → 41,14
 
typedef struct {
uint8_t *map;
size_t bits;
count_t bits;
} bitmap_t;
 
extern void bitmap_initialize(bitmap_t *bitmap, uint8_t *map, size_t bits);
extern void bitmap_set_range(bitmap_t *bitmap, size_t start, size_t bits);
extern void bitmap_clear_range(bitmap_t *bitmap, size_t start, size_t bits);
extern void bitmap_copy(bitmap_t *dst, bitmap_t *src, size_t bits);
extern void bitmap_initialize(bitmap_t *bitmap, uint8_t *map, count_t bits);
extern void bitmap_set_range(bitmap_t *bitmap, index_t start, count_t bits);
extern void bitmap_clear_range(bitmap_t *bitmap, index_t start, count_t bits);
extern void bitmap_copy(bitmap_t *dst, bitmap_t *src, count_t bits);
 
static inline int bitmap_get(bitmap_t *bitmap, size_t bit)
{
if(bit >= bitmap->bits)
return 0;
return !! ((bitmap->map)[bit/8] & (1 << (bit & 7)));
}
 
 
#endif
 
/** @}
/branches/arm/kernel/generic/include/ipc/event.h
File deleted
Property changes:
Deleted: svn:mergeinfo
/branches/arm/kernel/generic/include/ipc/event_types.h
File deleted
Property changes:
Deleted: svn:mergeinfo
/branches/arm/kernel/generic/include/ipc/kbox.h
File deleted
/branches/arm/kernel/generic/include/ipc/sysipc.h
40,26 → 40,23
#include <arch/types.h>
 
unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method,
unative_t arg1, unative_t arg2, unative_t arg3, ipc_data_t *data);
unative_t sys_ipc_call_sync_slow(unative_t phoneid, ipc_data_t *question,
unative_t arg1, ipc_data_t *data);
unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question,
ipc_data_t *reply);
unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method,
unative_t arg1, unative_t arg2, unative_t arg3, unative_t arg4);
unative_t sys_ipc_call_async_slow(unative_t phoneid, ipc_data_t *data);
unative_t arg1, unative_t arg2);
unative_t sys_ipc_call_async(unative_t phoneid, ipc_data_t *data);
unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval,
unative_t arg1, unative_t arg2, unative_t arg3, unative_t arg4);
unative_t sys_ipc_answer_slow(unative_t callid, ipc_data_t *data);
unative_t arg1, unative_t arg2);
unative_t sys_ipc_answer(unative_t callid, ipc_data_t *data);
unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec,
int nonblocking);
unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid,
unative_t method, unative_t arg1, unative_t arg2, int mode);
unative_t sys_ipc_forward_slow(unative_t callid, unative_t phoneid,
ipc_data_t *data, int mode);
unative_t method, unative_t arg1);
unative_t sys_ipc_hangup(int phoneid);
unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method,
irq_code_t *ucode);
unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno);
unative_t sys_ipc_connect_kbox(sysarg64_t *task_id);
 
#endif
 
/branches/arm/kernel/generic/include/ipc/ipc.h
37,13 → 37,13
 
/* Length of data being transfered with IPC call */
/* - the uspace may not be able to utilize full length */
#define IPC_CALL_LEN 6
#define IPC_CALL_LEN 4
 
/** Maximum active async calls per thread */
#ifdef CONFIG_DEBUG
#define IPC_MAX_ASYNC_CALLS 4
# define IPC_MAX_ASYNC_CALLS 4
#else
#define IPC_MAX_ASYNC_CALLS 4000
# define IPC_MAX_ASYNC_CALLS 4000
#endif
 
/* Flags for calls */
61,17 → 61,15
/** Interrupt notification */
#define IPC_CALL_NOTIF (1 << 5)
 
/*
* Bits used in call hashes.
* The addresses are aligned at least to 4 that is why we can use the 2 least
* significant bits of the call address.
/* Flags of callid (the addresses are aligned at least to 4,
* that is why we can use bottom 2 bits of the call address
*/
/** Type of this call is 'answer' */
/** Type of this msg is 'answer' */
#define IPC_CALLID_ANSWERED 1
/** Type of this call is 'notification' */
/** Type of this msg is 'notification' */
#define IPC_CALLID_NOTIFICATION 2
 
/* Return values from sys_ipc_call_async(). */
/* Return values from IPC_ASYNC */
#define IPC_CALLRET_FATAL -1
#define IPC_CALLRET_TEMPORARY -2
 
82,8 → 80,6
#define IPC_SET_ARG1(data, val) ((data).args[1] = (val))
#define IPC_SET_ARG2(data, val) ((data).args[2] = (val))
#define IPC_SET_ARG3(data, val) ((data).args[3] = (val))
#define IPC_SET_ARG4(data, val) ((data).args[4] = (val))
#define IPC_SET_ARG5(data, val) ((data).args[5] = (val))
 
#define IPC_GET_METHOD(data) ((data).args[0])
#define IPC_GET_RETVAL(data) ((data).args[0])
91,45 → 87,13
#define IPC_GET_ARG1(data) ((data).args[1])
#define IPC_GET_ARG2(data) ((data).args[2])
#define IPC_GET_ARG3(data) ((data).args[3])
#define IPC_GET_ARG4(data) ((data).args[4])
#define IPC_GET_ARG5(data) ((data).args[5])
 
/* Well known phone descriptors */
#define PHONE_NS 0
 
/* Forwarding flags. */
#define IPC_FF_NONE 0
/**
* The call will be routed as though it was initially sent via the phone used to
* forward it. This feature is intended to support the situation in which the
* forwarded call needs to be handled by the same connection fibril as any other
* calls that were initially sent by the forwarder to the same destination. This
* flag has no imapct on routing replies.
*/
#define IPC_FF_ROUTE_FROM_ME (1 << 0)
 
/* System-specific methods - only through special syscalls
* These methods have special behaviour
*/
/** Clone connection.
*
* The calling task clones one of its phones for the callee.
*
* - ARG1 - The caller sets ARG1 to the phone of the cloned connection.
* - The callee gets the new phone from ARG1.
* - on answer, the callee acknowledges the new connection by sending EOK back
* or the kernel closes it
*/
#define IPC_M_CONNECTION_CLONE 1
/** Protocol for CONNECT - ME
*
* Through this call, the recipient learns about the new cloned connection.
*
* - ARG5 - the kernel sets ARG5 to contain the hash of the used phone
* - on asnwer, the callee acknowledges the new connection by sending EOK back
* or the kernel closes it
*/
#define IPC_M_CONNECT_ME 2
/** Protocol for CONNECT - TO - ME
*
* Calling process asks the callee to create a callback connection,
136,8 → 100,8
* so that it can start initiating new messages.
*
* The protocol for negotiating is:
* - sys_connect_to_me - sends a message IPC_M_CONNECT_TO_ME
* - recipient - upon receipt tries to allocate new phone
* - sys_connect_to_me - sends a message IPC_M_CONNECTTOME
* - sys_wait_for_call - upon receipt tries to allocate new phone
* - if it fails, responds with ELIMIT
* - passes call to userspace. If userspace
* responds with error, phone is deallocated and
144,9 → 108,10
* error is sent back to caller. Otherwise
* the call is accepted and the response is sent back.
* - the allocated phoneid is passed to userspace
* (on the receiving side) as ARG5 of the call.
* (on the receiving sid) as ARG3 of the call.
* - the caller obtains taskid of the called thread
*/
#define IPC_M_CONNECT_TO_ME 3
#define IPC_M_CONNECT_TO_ME 1
/** Protocol for CONNECT - ME - TO
*
* Calling process asks the callee to create for him a new connection.
156,82 → 121,54
* - sys_connect_me_to - send a synchronous message to name server
* indicating that it wants to be connected to some
* service
* - arg1/2/3 are user specified, arg5 contains
* - arg1/2 are user specified, arg3 contains
* address of the phone that should be connected
* (TODO: it leaks to userspace)
* - recipient - if ipc_answer == 0, then accept connection
* recipient - if ipc_answer == 0, then accept connection
* - otherwise connection refused
* - recepient may forward message.
* - recepient may forward message. Forwarding
* system message
*
*/
#define IPC_M_CONNECT_ME_TO 4
#define IPC_M_CONNECT_ME_TO 2
/** This message is sent to answerbox when the phone
* is hung up
*/
#define IPC_M_PHONE_HUNGUP 5
#define IPC_M_PHONE_HUNGUP 3
 
/** Send as_area over IPC.
* - ARG1 - source as_area base address
* - ARG2 - size of source as_area (filled automatically by kernel)
/** Send as_area over IPC
* - ARG1 - src as_area base address
* - ARG2 - size of src as_area (filled automatically by kernel)
* - ARG3 - flags of the as_area being sent
*
* on answer, the recipient must set:
* on answer:
* - ARG1 - dst as_area base adress
*/
#define IPC_M_SHARE_OUT 6
#define IPC_M_AS_AREA_SEND 5
 
/** Receive as_area over IPC.
* - ARG1 - destination as_area base address
* - ARG2 - destination as_area size
/** Get as_area over IPC
* - ARG1 - dst as_area base address
* - ARG2 - dst as_area size
* - ARG3 - user defined argument
*
* on answer, the recipient must set:
* on answer, the server must set:
*
* - ARG1 - source as_area base address
* - ARG1 - src as_area base address
* - ARG2 - flags that will be used for sharing
*/
#define IPC_M_SHARE_IN 7
#define IPC_M_AS_AREA_RECV 6
 
/** Send data to another address space over IPC.
* - ARG1 - source address space virtual address
* - ARG2 - size of data to be copied, may be overriden by the recipient
*
* on answer, the recipient must set:
*
* - ARG1 - final destination address space virtual address
* - ARG2 - final size of data to be copied
*/
#define IPC_M_DATA_WRITE 8
 
/** Receive data from another address space over IPC.
* - ARG1 - destination virtual address in the source address space
* - ARG2 - size of data to be received, may be cropped by the recipient
*
* on answer, the recipient must set:
*
* - ARG1 - source virtual address in the destination address space
* - ARG2 - final size of data to be copied
*/
#define IPC_M_DATA_READ 9
 
/** Debug the recipient.
* - ARG1 - specifies the debug method (from udebug_method_t)
* - other arguments are specific to the debug method
*/
#define IPC_M_DEBUG_ALL 10
 
/* Well-known methods */
#define IPC_M_LAST_SYSTEM 511
#define IPC_M_PING 512
#define IPC_M_LAST_SYSTEM 511
#define IPC_M_PING 512
/* User methods */
#define IPC_FIRST_USER_METHOD 1024
#define FIRST_USER_METHOD 1024
 
#ifdef KERNEL
 
#define IPC_MAX_PHONES 16
 
#include <synch/spinlock.h>
#include <synch/mutex.h>
#include <synch/waitq.h>
 
struct answerbox;
252,7 → 189,7
 
/** Structure identifying phone (in TASK structure) */
typedef struct {
mutex_t lock;
SPINLOCK_DECLARE(lock);
link_t link;
struct answerbox *callee;
ipc_phone_state_t state;
266,17 → 203,17
 
waitq_t wq;
 
/** Phones connected to this answerbox. */
/** Phones connected to this answerbox */
link_t connected_phones;
/** Received calls. */
/** Received calls */
link_t calls;
link_t dispatched_calls; /* Should be hash table in the future */
 
/** Answered calls. */
/** Answered calls */
link_t answers;
 
SPINLOCK_DECLARE(irq_lock);
/** Notifications from IRQ handlers. */
/** Notifications from IRQ handlers */
link_t irq_notifs;
/** IRQs with notifications to this answerbox. */
link_t irq_head;
292,48 → 229,37
 
int flags;
 
/** Identification of the caller. */
/* Identification of the caller */
struct task *sender;
/** The caller box is different from sender->answerbox for synchronous
* calls. */
/* The caller box is different from sender->answerbox
* for synchronous calls
*/
answerbox_t *callerbox;
 
/** Private data to internal IPC. */
/** Private data to internal IPC */
unative_t priv;
 
/** Data passed from/to userspace. */
/** Data passed from/to userspace */
ipc_data_t data;
 
/** Buffer for IPC_M_DATA_WRITE and IPC_M_DATA_READ. */
uint8_t *buffer;
 
/*
* The forward operation can masquerade the caller phone. For those
* cases, we must keep it aside so that the answer is processed
* correctly.
*/
phone_t *caller_phone;
} call_t;
 
extern void ipc_init(void);
extern call_t * ipc_wait_for_call(answerbox_t *, uint32_t, int);
extern void ipc_answer(answerbox_t *, call_t *);
extern int ipc_call(phone_t *, call_t *);
extern int ipc_call_sync(phone_t *, call_t *);
extern void ipc_phone_init(phone_t *);
extern void ipc_phone_connect(phone_t *, answerbox_t *);
extern void ipc_call_free(call_t *);
extern call_t * ipc_call_alloc(int);
extern void ipc_answerbox_init(answerbox_t *, struct task *);
extern void ipc_call_static_init(call_t *);
extern call_t * ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags);
extern void ipc_answer(answerbox_t *box, call_t *request);
extern int ipc_call(phone_t *phone, call_t *call);
extern void ipc_call_sync(phone_t *phone, call_t *request);
extern void ipc_phone_init(phone_t *phone);
extern void ipc_phone_connect(phone_t *phone, answerbox_t *box);
extern void ipc_call_free(call_t *call);
extern call_t * ipc_call_alloc(int flags);
extern void ipc_answerbox_init(answerbox_t *box);
extern void ipc_call_static_init(call_t *call);
extern void task_print_list(void);
extern int ipc_forward(call_t *, phone_t *, answerbox_t *, int);
extern void ipc_cleanup(void);
extern int ipc_phone_hangup(phone_t *);
extern void ipc_backsend_err(phone_t *, call_t *, unative_t);
extern void ipc_print_task(task_id_t);
extern void ipc_answerbox_slam_phones(answerbox_t *, bool);
extern void ipc_cleanup_call_list(link_t *);
extern int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox);
void ipc_cleanup(void);
int ipc_phone_hangup(phone_t *phone);
extern void ipc_backsend_err(phone_t *phone, call_t *call, unative_t err);
extern void ipc_print_task(task_id_t taskid);
 
extern answerbox_t *ipc_phone_0;
 
/branches/arm/kernel/generic/include/ipc/irq.h
36,7 → 36,7
#define KERN_IPC_IRQ_H_
 
/** Maximum length of IPC IRQ program */
#define IRQ_MAX_PROG_SIZE 20
#define IRQ_MAX_PROG_SIZE 10
 
#include <ipc/ipc.h>
#include <ddi/irq.h>
43,35 → 43,13
#include <arch/types.h>
#include <adt/list.h>
 
extern int ipc_irq_register(answerbox_t *, inr_t, devno_t, unative_t,
irq_code_t *);
extern int ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno,
unative_t method, irq_code_t *ucode);
extern void ipc_irq_send_notif(irq_t *irq);
extern void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3);
extern void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno);
extern void ipc_irq_cleanup(answerbox_t *box);
 
extern irq_ownership_t ipc_irq_top_half_claim(irq_t *);
extern void ipc_irq_top_half_handler(irq_t *);
 
extern int ipc_irq_unregister(answerbox_t *, inr_t, devno_t);
extern void ipc_irq_cleanup(answerbox_t *);
 
/*
* User friendly wrappers for ipc_irq_send_msg(). They are in the form
* ipc_irq_send_msg_m(), where m is the number of payload arguments.
*/
#define ipc_irq_send_msg_0(irq) \
ipc_irq_send_msg((irq), 0, 0, 0, 0, 0)
#define ipc_irq_send_msg_1(irq, a1) \
ipc_irq_send_msg((irq), (a1), 0, 0, 0, 0)
#define ipc_irq_send_msg_2(irq, a1, a2) \
ipc_irq_send_msg((irq), (a1), (a2), 0, 0, 0)
#define ipc_irq_send_msg_3(irq, a1, a2, a3) \
ipc_irq_send_msg((irq), (a1), (a2), (a3), 0, 0)
#define ipc_irq_send_msg_4(irq, a1, a2, a3, a4) \
ipc_irq_send_msg((irq), (a1), (a2), (a3), (a4), 0)
#define ipc_irq_send_msg_5(irq, a1, a2, a3, a4, a5) \
ipc_irq_send_msg((irq), (a1), (a2), (a3), (a4), (a5))
 
extern void ipc_irq_send_msg(irq_t *, unative_t, unative_t, unative_t, unative_t,
unative_t);
 
#endif
 
/** @}
/branches/arm/kernel/generic/include/ipc/ipcrsc.h
35,14 → 35,11
#ifndef KERN_IPCRSC_H_
#define KERN_IPCRSC_H_
 
#include <proc/task.h>
#include <ipc/ipc.h>
call_t * get_call(unative_t callid);
int phone_alloc(void);
void phone_connect(int phoneid, answerbox_t *box);
void phone_dealloc(int phoneid);
 
extern call_t * get_call(unative_t callid);
extern int phone_alloc(task_t *t);
extern void phone_connect(int phoneid, answerbox_t *box);
extern void phone_dealloc(int phoneid);
 
#endif
 
/** @}
/branches/arm/kernel/generic/include/arch.h
56,7 → 56,7
* the base address of the stack.
*/
typedef struct {
size_t preemption_disabled; /**< Preemption disabled counter. */
count_t preemption_disabled; /**< Preemption disabled counter. */
thread_t *thread; /**< Current thread. */
task_t *task; /**< Current task. */
cpu_t *cpu; /**< Executing cpu. */
63,23 → 63,19
as_t *as; /**< Current address space. */
} the_t;
 
#define THE ((the_t * )(get_stack_base()))
#define THE ((the_t *)(get_stack_base()))
 
extern void the_initialize(the_t *the);
extern void the_copy(the_t *src, the_t *dst);
 
extern void arch_pre_main(void);
extern void arch_pre_mm_init(void);
extern void arch_post_mm_init(void);
extern void arch_post_cpu_init(void);
extern void arch_pre_smp_init(void);
extern void arch_post_smp_init(void);
 
extern void calibrate_delay_loop(void);
 
extern void reboot(void);
extern void arch_reboot(void);
extern void *arch_construct_function(fncptr_t *fptr, void *addr, void *caller);
 
#endif
 
/** @}
/branches/arm/kernel/generic/include/cpu.h
51,18 → 51,18
SPINLOCK_DECLARE(lock);
 
tlb_shootdown_msg_t tlb_messages[TLB_MESSAGE_QUEUE_LEN];
size_t tlb_messages_count;
count_t tlb_messages_count;
context_t saved_context;
 
atomic_t nrdy;
runq_t rq[RQ_COUNT];
volatile size_t needs_relink;
volatile count_t needs_relink;
 
SPINLOCK_DECLARE(timeoutlock);
link_t timeout_active_head;
 
size_t missed_clock_ticks; /**< When system clock loses a tick, it is recorded here
count_t missed_clock_ticks; /**< When system clock loses a tick, it is recorded here
so that clock() can react. This variable is
CPU-local and can be only accessed when interrupts
are disabled. */
/branches/arm/kernel/generic/include/func.h
41,6 → 41,11
extern atomic_t haltstate;
 
extern void halt(void);
 
extern size_t strlen(const char *str);
extern int strcmp(const char *src, const char *dst);
extern int strncmp(const char *src, const char *dst, size_t len);
extern void strncpy(char *dest, const char *src, size_t len);
extern unative_t atoi(const char *text);
extern void order(const uint64_t val, uint64_t *rv, char *suffix);
 
/branches/arm/kernel/generic/include/fpu_context.h
37,6 → 37,10
 
#include <arch/fpu_context.h>
 
#if defined(CONFIG_FPU_LAZY) && !defined(ARCH_HAS_FPU)
# error "CONFIG_FPU_LAZY defined, but no ARCH_HAS_FPU"
#endif
 
extern void fpu_context_save(fpu_context_t *);
extern void fpu_context_restore(fpu_context_t *);
extern void fpu_init(void);
/branches/arm/kernel/generic/include/config.h
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
38,19 → 38,19
#include <arch/types.h>
#include <arch/mm/page.h>
 
#define STACK_SIZE PAGE_SIZE
#define STACK_SIZE PAGE_SIZE
 
#define CONFIG_INIT_TASKS 32
#define CONFIG_TASK_NAME_BUFLEN 32
#define CONFIG_MEMORY_SIZE (8 * 1024 * 1024)
 
#define CONFIG_INIT_TASKS 32
 
typedef struct {
uintptr_t addr;
size_t size;
char name[CONFIG_TASK_NAME_BUFLEN];
} init_task_t;
 
typedef struct {
size_t cnt;
count_t cnt;
init_task_t tasks[CONFIG_INIT_TASKS];
} init_t;
 
65,14 → 65,15
} ballocs_t;
 
typedef struct {
size_t cpu_count; /**< Number of processors detected. */
volatile size_t cpu_active; /**< Number of processors that are up and running. */
count_t cpu_count; /**< Number of processors detected. */
volatile count_t cpu_active; /**< Number of processors that are up and running. */
 
uintptr_t base;
size_t kernel_size; /**< Size of memory in bytes taken by kernel and stack */
size_t memory_size; /**< Size of detected memory in bytes. */
size_t kernel_size; /**< Size of memory in bytes taken by kernel and stack */
uintptr_t stack_base; /**< Base adddress of initial stack */
size_t stack_size; /**< Size of initial stack */
uintptr_t stack_base; /**< Base adddress of initial stack */
size_t stack_size; /**< Size of initial stack */
} config_t;
 
extern config_t config;
/branches/arm/kernel/generic/include/debug.h
38,11 → 38,11
#include <panic.h>
#include <arch/debug.h>
 
#define CALLER ((uintptr_t) __builtin_return_address(0))
#define CALLER ((uintptr_t)__builtin_return_address(0))
 
#ifndef HERE
/** Current Instruction Pointer address */
# define HERE ((uintptr_t *) 0)
# define HERE ((uintptr_t *) 0)
#endif
 
/** Debugging ASSERT macro
55,51 → 55,12
*
*/
#ifdef CONFIG_DEBUG
# define ASSERT(expr) \
if (!(expr)) { \
panic("Assertion failed (%s), caller=%p.", #expr, CALLER); \
}
# define ASSERT(expr) if (!(expr)) { panic("assertion failed (%s), caller=%.*p\n", #expr, sizeof(uintptr_t) * 2, CALLER); }
#else
# define ASSERT(expr)
#endif
 
/** Extensive logging output macro
*
* If CONFIG_LOG is set, the LOG() macro
* will print whatever message is indicated plus
* an information about the location.
*
*/
 
#ifdef CONFIG_LOG
# define LOG(format, ...) \
printf("%s() at %s:%u: " format "\n", __func__, __FILE__, \
__LINE__, ##__VA_ARGS__);
#else
# define LOG(format, ...)
#endif
 
/** Extensive logging execute macro
*
* If CONFIG_LOG is set, the LOG_EXEC() macro
* will print an information about calling a given
* function and call it.
*
*/
 
#ifdef CONFIG_LOG
# define LOG_EXEC(fnc) \
{ \
printf("%s() at %s:%u: " #fnc "\n", __func__, __FILE__, \
__LINE__); \
fnc; \
}
#else
# define LOG_EXEC(fnc) fnc
#endif
 
 
#endif
 
/** @}
*/
/branches/arm/kernel/generic/include/interrupt.h
40,17 → 40,17
#include <proc/task.h>
#include <proc/thread.h>
#include <arch.h>
#include <console/klog.h>
#include <ddi/irq.h>
 
typedef void (* iroutine)(int n, istate_t *istate);
 
#define fault_if_from_uspace(istate, fmt, ...) \
#define fault_if_from_uspace(istate, cmd, ...) \
{ \
if (istate_from_uspace(istate)) { \
task_t *task = TASK; \
printf("Task %s (%" PRIu64 ") killed due to an exception at %p: ", task->name, task->taskid, istate_get_pc(istate)); \
printf(fmt "\n", ##__VA_ARGS__); \
task_kill(task->taskid); \
klog_printf("Task %lld killed due to an exception at %p.", TASK->taskid, istate_get_pc(istate)); \
klog_printf(" " cmd, ##__VA_ARGS__); \
task_kill(TASK->taskid); \
thread_exit(); \
} \
}
/branches/arm/kernel/generic/include/main/main.h
35,13 → 35,8
#ifndef KERN_MAIN_H_
#define KERN_MAIN_H_
 
#include <arch/types.h>
 
extern uintptr_t stack_safe;
 
extern void main_bsp(void);
extern void main_ap(void);
 
#endif
 
/** @}
/branches/arm/kernel/generic/include/printf/printf_core.h
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
35,23 → 35,20
#ifndef KERN_PRINTF_CORE_H_
#define KERN_PRINTF_CORE_H_
 
#include <typedefs.h>
#include <arch/types.h>
#include <arch/arg.h>
 
/** Structure for specifying output methods for different printf clones. */
typedef struct {
/* String output function, returns number of printed characters or EOF */
int (*str_write)(const char *, size_t, void *);
/* Wide string output function, returns number of printed characters or EOF */
int (*wstr_write)(const wchar_t *, size_t, void *);
/* User data - output stream specification, state, locks, etc. */
struct printf_spec {
/* Output function, returns count of printed characters or EOF */
int (*write)(void *, size_t, void *);
/* Support data - output stream specification, its state, locks,... */
void *data;
} printf_spec_t;
 
int printf_core(const char *fmt, printf_spec_t *ps, va_list ap);
};
 
int printf_core(const char *fmt, struct printf_spec *ps ,va_list ap);
 
#endif
 
/** @}
/branches/arm/kernel/generic/include/typedefs.h
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
35,28 → 35,8
#ifndef KERN_TYPEDEFS_H_
#define KERN_TYPEDEFS_H_
 
#include <arch/types.h>
 
#define NULL 0
#define false 0
#define true 1
 
typedef void (* function)();
 
typedef uint8_t bool;
typedef uint64_t thread_id_t;
typedef uint64_t task_id_t;
typedef uint32_t context_id_t;
 
typedef int32_t inr_t;
typedef int32_t devno_t;
 
typedef int32_t wchar_t;
 
typedef volatile uint8_t ioport8_t;
typedef volatile uint16_t ioport16_t;
typedef volatile uint32_t ioport32_t;
 
#endif
 
/** @}
/branches/arm/kernel/generic/include/macros.h
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
35,15 → 35,24
#ifndef KERN_MACROS_H_
#define KERN_MACROS_H_
 
#ifndef __ASM__
 
#include <arch/types.h>
 
/** Return true if the intervals overlap.
#define is_digit(d) (((d) >= '0') && ((d) <= '9'))
#define is_lower(c) (((c) >= 'a') && ((c) <= 'z'))
#define is_upper(c) (((c) >= 'A') && ((c) <= 'Z'))
#define is_alpha(c) (is_lower(c) || is_upper(c))
#define is_alphanum(c) (is_alpha(c) || is_digit(c))
#define is_white(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || \
((c) == '\r'))
 
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
 
/** Return true if the interlvals overlap.
*
* @param s1 Start address of the first interval.
* @param s1 Start address of the first interval.
* @param sz1 Size of the first interval.
* @param s2 Start address of the second interval.
* @param s2 Start address of the second interval.
* @param sz2 Size of the second interval.
*/
static inline int overlaps(uintptr_t s1, size_t sz1, uintptr_t s2, size_t sz2)
50,58 → 59,15
{
uintptr_t e1 = s1 + sz1;
uintptr_t e2 = s2 + sz2;
return ((s1 < e2) && (s2 < e1));
 
return (s1 < e2) && (s2 < e1);
}
 
#endif /* __ASM__ */
 
#define isdigit(d) (((d) >= '0') && ((d) <= '9'))
#define islower(c) (((c) >= 'a') && ((c) <= 'z'))
#define isupper(c) (((c) >= 'A') && ((c) <= 'Z'))
#define isalpha(c) (is_lower((c)) || is_upper((c)))
#define isalphanum(c) (is_alpha((c)) || is_digit((c)))
#define isspace(c) \
(((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
 
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
 
#define min3(a, b, c) ((a) < (b) ? (min(a, c)) : (min(b, c)))
#define max3(a, b, c) ((a) > (b) ? (max(a, c)) : (max(b, c)))
 
/* Compute overlapping of physical addresses */
#define PA_overlaps(x, szx, y, szy) \
overlaps(KA2PA((x)), (szx), KA2PA((y)), (szy))
#define PA_overlaps(x, szx, y, szy) overlaps(KA2PA(x), szx, KA2PA(y), szy)
 
#define SIZE2KB(size) ((size) >> 10)
#define SIZE2MB(size) ((size) >> 20)
#define STRING(arg) STRING_ARG(arg)
#define STRING_ARG(arg) #arg
 
#define KB2SIZE(kb) ((kb) << 10)
#define MB2SIZE(mb) ((mb) << 20)
 
#define STRING(arg) STRING_ARG(arg)
#define STRING_ARG(arg) #arg
 
#define LOWER32(arg) ((arg) & 0xffffffff)
#define UPPER32(arg) (((arg) >> 32) & 0xffffffff)
 
#define MERGE_LOUP32(lo, up) \
((((uint64_t) (lo)) & 0xffffffff) \
| ((((uint64_t) (up)) & 0xffffffff) << 32))
 
/** Pseudorandom generator
*
* A pretty standard linear congruential pseudorandom
* number generator (m = 2^32 or 2^64 depending on architecture).
*
*/
#define RANDI(seed) \
({ \
(seed) = 1103515245 * (seed) + 12345; \
(seed); \
})
 
#endif
 
/** @}
/branches/arm/kernel/generic/include/context.h
45,7 → 45,7
(c)->sp = ((uintptr_t) (stack)) + (size) - SP_DELTA;
#endif /* context_set */
 
extern int context_save_arch(context_t *c) __attribute__ ((returns_twice));
extern int context_save_arch(context_t *c);
extern void context_restore_arch(context_t *c) __attribute__ ((noreturn));
 
/** Save register context.
76,6 → 76,10
* corresponding call to context_save(), the only
* difference being return value.
*
* Note that content of any local variable defined by
* the caller of context_save() is undefined after
* context_restore().
*
* @param c Context structure.
*/
static inline void context_restore(context_t *c)
/branches/arm/kernel/generic/include/align.h
26,13 → 26,13
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @ingroup others
* @{
*/
/**
* @file
* @brief Macros for making values and addresses aligned.
* @brief Macros for making values and addresses aligned.
*/
 
#ifndef KERN_ALIGN_H_
43,7 → 43,7
* @param s Address or size to be aligned.
* @param a Size of alignment, must be power of 2.
*/
#define ALIGN_DOWN(s, a) ((s) & ~((a) - 1))
#define ALIGN_DOWN(s, a) ((s) & ~((a) - 1))
 
 
/** Align to the nearest higher address.
51,7 → 51,7
* @param s Address or size to be aligned.
* @param a Size of alignment, must be power of 2.
*/
#define ALIGN_UP(s, a) (((s) + ((a) - 1)) & ~((a) - 1))
#define ALIGN_UP(s, a) (((s) + ((a) - 1)) & ~((a) - 1))
 
#endif
 
/branches/arm/kernel/generic/include/stackarg.h
52,9 → 52,9
(ap).last = (uint8_t *) &(lst)
 
#define va_arg(ap, type) \
(*((type *)((ap).last + ((ap).pos += sizeof(type)) - sizeof(type))))
(*((type *)((ap).last + ((ap).pos += sizeof(type) ) - sizeof(type))))
 
#define va_copy(dst, src) dst = src
#define va_copy(dst,src) dst=src
#define va_end(ap)
 
 
/branches/arm/kernel/generic/include/byteorder.h
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
35,76 → 35,26
#ifndef KERN_BYTEORDER_H_
#define KERN_BYTEORDER_H_
 
#include <arch/types.h>
 
#if !(defined(__BE__) ^ defined(__LE__))
#error The architecture must be either big-endian or little-endian.
#endif
 
#ifdef __BE__
 
#define uint16_t_le2host(n) (uint16_t_byteorder_swap(n))
#define uint32_t_le2host(n) (uint32_t_byteorder_swap(n))
#define uint64_t_le2host(n) (uint64_t_byteorder_swap(n))
 
#define uint16_t_be2host(n) (n)
#define uint32_t_be2host(n) (n)
#define uint64_t_be2host(n) (n)
 
#define host2uint16_t_le(n) (uint16_t_byteorder_swap(n))
#define host2uint32_t_le(n) (uint32_t_byteorder_swap(n))
#define host2uint64_t_le(n) (uint64_t_byteorder_swap(n))
 
#define host2uint16_t_be(n) (n)
#define host2uint32_t_be(n) (n)
#define host2uint64_t_be(n) (n)
 
#else
 
#define uint16_t_le2host(n) (n)
#define uint32_t_le2host(n) (n)
#define uint64_t_le2host(n) (n)
 
#define uint16_t_be2host(n) (uint16_t_byteorder_swap(n))
#define uint32_t_be2host(n) (uint32_t_byteorder_swap(n))
#define uint64_t_be2host(n) (uint64_t_byteorder_swap(n))
 
#define host2uint16_t_le(n) (n)
#define host2uint32_t_le(n) (n)
#define host2uint64_t_le(n) (n)
 
#define host2uint16_t_be(n) (uint16_t_byteorder_swap(n))
#define host2uint32_t_be(n) (uint32_t_byteorder_swap(n))
#define host2uint64_t_be(n) (uint64_t_byteorder_swap(n))
 
#endif
 
static inline uint64_t uint64_t_byteorder_swap(uint64_t n)
{
return ((n & 0xff) << 56) |
((n & 0xff00) << 40) |
((n & 0xff0000) << 24) |
((n & 0xff000000LL) << 8) |
((n & 0xff00000000LL) >> 8) |
((n & 0xff0000000000LL) >> 24) |
((n & 0xff000000000000LL) >> 40) |
((n & 0xff00000000000000LL) >> 56);
((n & 0xff00) << 40) |
((n & 0xff0000) << 24) |
((n & 0xff000000LL) << 8) |
((n & 0xff00000000LL) >> 8) |
((n & 0xff0000000000LL) >> 24) |
((n & 0xff000000000000LL) >> 40) |
((n & 0xff00000000000000LL) >> 56);
}
 
static inline uint32_t uint32_t_byteorder_swap(uint32_t n)
{
return ((n & 0xff) << 24) |
((n & 0xff00) << 8) |
((n & 0xff0000) >> 8) |
((n & 0xff000000) >> 24);
((n & 0xff00) << 8) |
((n & 0xff0000) >> 8) |
((n & 0xff000000) >> 24);
}
 
static inline uint16_t uint16_t_byteorder_swap(uint16_t n)
{
return ((n & 0xff) << 8) |
((n & 0xff00) >> 8);
}
 
#endif
 
/** @}
/branches/arm/kernel/generic/include/symtab.h
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
44,20 → 44,15
char symbol_name[MAX_SYMBOL_NAME];
};
 
extern int symtab_name_lookup(unative_t addr, char **name);
extern char *symtab_fmt_name_lookup(unative_t addr);
extern int symtab_addr_lookup(const char *name, uintptr_t *addr);
extern char * get_symtab_entry(unative_t addr);
extern uintptr_t get_symbol_addr(const char *name);
extern void symtab_print_search(const char *name);
extern int symtab_compl(char *input, size_t size);
extern int symtab_compl(char *name);
 
#ifdef CONFIG_SYMTAB
 
/* Symtable linked together by build process */
extern struct symtab_entry symbol_table[];
 
#endif
 
#endif
 
/** @}
*/
/branches/arm/kernel/generic/include/sysinfo/sysinfo.h
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
36,7 → 36,6
#define KERN_SYSINFO_H_
 
#include <arch/types.h>
#include <string.h>
 
typedef union sysinfo_item_val {
unative_t val;
60,13 → 59,13
int subinfo_type;
} sysinfo_item_t;
 
#define SYSINFO_VAL_VAL 0
#define SYSINFO_VAL_FUNCTION 1
#define SYSINFO_VAL_UNDEFINED U_SPECIAL
#define SYSINFO_VAL_VAL 0
#define SYSINFO_VAL_FUNCTION 1
#define SYSINFO_VAL_UNDEFINED '?'
 
#define SYSINFO_SUBINFO_NONE 0
#define SYSINFO_SUBINFO_TABLE 1
#define SYSINFO_SUBINFO_FUNCTION 2
#define SYSINFO_SUBINFO_NONE 0
#define SYSINFO_SUBINFO_TABLE 1
#define SYSINFO_SUBINFO_FUNCTION 2
 
typedef unative_t (*sysinfo_val_fn_t)(sysinfo_item_t *root);
typedef unative_t (*sysinfo_subinfo_fn_t)(const char *subname);
/branches/arm/kernel/generic/include/panic.h
36,15 → 36,12
#define KERN_PANIC_H_
 
#ifdef CONFIG_DEBUG
# define panic(format, ...) \
panic_printf("Kernel panic in %s() at %s:%u: " format "\n", \
__func__, __FILE__, __LINE__, ##__VA_ARGS__);
# define panic(format, ...) panic_printf("Kernel panic in %s() at %s on line %d: " format, __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__);
#else
# define panic(format, ...) \
panic_printf("Kernel panic: " format "\n", ##__VA_ARGS__);
# define panic(format, ...) panic_printf("Kernel panic: " format, ##__VA_ARGS__);
#endif
 
extern void panic_printf(char *fmt, ...) __attribute__((noreturn));
extern void panic_printf(char *fmt, ...) __attribute__((noreturn)) ;
 
#endif
 
/branches/arm/kernel/generic/include/putchar.h
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
35,7 → 35,7
#ifndef KERN_PUTCHAR_H_
#define KERN_PUTCHAR_H_
 
extern void putchar(const wchar_t ch);
extern void putchar(const char ch);
 
#endif
 
/branches/arm/kernel/generic/include/stdarg.h
45,7 → 45,7
#define va_start(ap, last) __builtin_va_start(ap, last)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_end(ap) __builtin_va_end(ap)
#define va_copy(dst, src) __builtin_va_copy(dst, src)
#define va_copy(dst,src) __builtin_va_copy(dst,src)
 
#endif
 
/branches/arm/kernel/generic/include/errno.h
37,7 → 37,6
 
/* 1-255 are kernel error codes, 256-512 are user error codes */
 
#define EOK 0 /* No error */
#define ENOENT -1 /* No such entry */
#define ENOMEM -2 /* Not enough memory */
#define ELIMIT -3 /* Limit exceeded */
44,22 → 43,16
#define EREFUSED -4 /* Connection refused */
#define EFORWARD -5 /* Forward error */
#define EPERM -6 /* Permission denied */
#define EHANGUP -7 /* Answerbox closed connection, call
* sys_ipc_hangup() to close the connection.
* Used by answerbox to close the connection.
*/
#define EPARTY -8 /* The other party encountered an error when
* receiving the call.
*/
#define EEXISTS -9 /* Entry already exists */
#define EBADMEM -10 /* Bad memory pointer */
#define ENOTSUP -11 /* Not supported */
#define EADDRNOTAVAIL -12 /* Address not available. */
#define ETIMEOUT -13 /* Timeout expired */
#define EINVAL -14 /* Invalid value */
#define EBUSY -15 /* Resource is busy */
#define EOVERFLOW -16 /* The result does not fit its size. */
#define EINTR -17 /* Operation was interrupted. */
#define EHANGUP -7 /* Answerbox closed connection, call sys_ipc_hangup
* to close the connection. Used by answerbox
* to close the connection. */
#define EEXISTS -8 /* Entry already exists */
#define EBADMEM -9 /* Bad memory pointer */
#define ENOTSUP -10 /* Not supported */
#define EADDRNOTAVAIL -11 /* Address not available. */
#define ETIMEOUT -12 /* Timeout expired */
#define EINVAL -13 /* Invalid value */
#define EBUSY -14 /* Resource is busy */
 
#endif
 
/branches/arm/kernel/generic/include/sort.h
40,8 → 40,8
/*
* sorting routines
*/
extern void bubblesort(void * data, size_t n, size_t e_size, int (* cmp) (void * a, void * b));
extern void qsort(void * data, size_t n, size_t e_size, int (* cmp) (void * a, void * b));
extern void bubblesort(void * data, count_t n, size_t e_size, int (* cmp) (void * a, void * b));
extern void qsort(void * data, count_t n, size_t e_size, int (* cmp) (void * a, void * b));
 
/*
* default sorting comparators
/branches/arm/kernel/generic/src/udebug/udebug_ipc.c
File deleted
/branches/arm/kernel/generic/src/udebug/udebug.c
File deleted
/branches/arm/kernel/generic/src/udebug/udebug_ops.c
File deleted
/branches/arm/kernel/generic/src/printf/printf.c
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
33,18 → 33,19
*/
 
#include <print.h>
int XXprintf(const char *fmt, ...);
 
int printf(const char *fmt, ...)
int XXprintf(const char *fmt, ...)
{
int ret;
va_list args;
 
va_start(args, fmt);
 
ret = vprintf(fmt, args);
va_end(args);
 
return ret;
}
 
/branches/arm/kernel/generic/src/printf/vprintf.c
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
35,72 → 35,28
#include <print.h>
#include <printf/printf_core.h>
#include <putchar.h>
#include <synch/spinlock.h>
#include <arch/asm.h>
#include <arch/types.h>
#include <typedefs.h>
#include <string.h>
 
SPINLOCK_INITIALIZE(printf_lock); /**< vprintf spinlock */
 
static int vprintf_str_write(const char *str, size_t size, void *data)
static int vprintf_write(const char *str, size_t count, void *unused)
{
size_t offset = 0;
size_t chars = 0;
while (offset < size) {
putchar(str_decode(str, &offset, size));
chars++;
}
return chars;
size_t i;
for (i = 0; i < count; i++)
putchar(str[i]);
return i;
}
 
static int vprintf_wstr_write(const wchar_t *str, size_t size, void *data)
int puts(const char *s)
{
size_t offset = 0;
size_t chars = 0;
while (offset < size) {
putchar(str[chars]);
chars++;
offset += sizeof(wchar_t);
}
return chars;
size_t i;
for (i = 0; s[i] != 0; i++)
putchar(s[i]);
return i;
}
 
int puts(const char *str)
int vprintf(const char *fmt, va_list ap)
{
size_t offset = 0;
size_t chars = 0;
wchar_t uc;
while ((uc = str_decode(str, &offset, STR_NO_LIMIT)) != 0) {
putchar(uc);
chars++;
}
return chars;
}
struct printf_spec ps = {(int(*)(void *, size_t, void *)) vprintf_write, NULL};
return printf_core(fmt, &ps, ap);
 
int vprintf(const char *fmt, va_list ap)
{
printf_spec_t ps = {
vprintf_str_write,
vprintf_wstr_write,
NULL
};
ipl_t ipl = interrupts_disable();
spinlock_lock(&printf_lock);
int ret = printf_core(fmt, &ps, ap);
spinlock_unlock(&printf_lock);
interrupts_restore(ipl);
return ret;
}
 
/** @}
/branches/arm/kernel/generic/src/printf/snprintf.c
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
42,11 → 42,12
va_start(args, fmt);
ret = vsnprintf(str, size, fmt, args);
 
va_end(args);
 
return ret;
}
 
/** @}
*/
 
/branches/arm/kernel/generic/src/printf/sprintf.c
0,0 → 1,51
/*
* Copyright (c) 2006 Josef Cejka
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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 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.
*/
 
/** @addtogroup generic
* @{
*/
/** @file
*/
 
#include <print.h>
 
int sprintf(char *str, const char *fmt, ...)
{
int ret;
va_list args;
va_start(args, fmt);
ret = vsprintf(str, fmt, args);
 
va_end(args);
 
return ret;
}
 
/** @}
*/
/branches/arm/kernel/generic/src/printf/vsnprintf.c
26,7 → 26,7
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/** @file
34,146 → 34,64
 
#include <print.h>
#include <printf/printf_core.h>
#include <string.h>
#include <memstr.h>
#include <errno.h>
 
typedef struct {
size_t size; /* Total size of the buffer (in bytes) */
size_t len; /* Number of already used bytes */
char *dst; /* Destination */
} vsnprintf_data_t;
struct vsnprintf_data {
size_t size; /* total space for string */
size_t len; /* count of currently used characters */
char *string; /* destination string */
};
 
int vsnprintf_write(const char *str, size_t count, struct vsnprintf_data *data);
 
/** Write string to given buffer.
*
* Write at most data->size plain characters including trailing zero.
* According to C99, snprintf() has to return number of characters that
* would have been written if enough space had been available. Hence
* the return value is not the number of actually printed characters
* but size of the input string.
*
* @param str Source string to print.
* @param size Number of plain characters in str.
* @param data Structure describing destination string, counter
* of used space and total string size.
*
* @return Number of characters to print (not characters actually
* printed).
*
* Write at most data->size characters including trailing zero. According to C99, snprintf() has to return number
* of characters that would have been written if enough space had been available. Hence the return value is not
* number of really printed characters but size of the input string. Number of really used characters
* is stored in data->len.
* @param str source string to print
* @param count size of source string
* @param data structure with destination string, counter of used space and total string size.
* @return number of characters to print (not characters really printed!)
*/
static int vsnprintf_str_write(const char *str, size_t size, vsnprintf_data_t *data)
int vsnprintf_write(const char *str, size_t count, struct vsnprintf_data *data)
{
size_t left = data->size - data->len;
size_t i;
i = data->size - data->len;
 
if (i == 0) {
return count;
}
if (left == 0)
return ((int) size);
if (left == 1) {
/* We have only one free byte left in buffer
* -> store trailing zero
*/
data->dst[data->size - 1] = 0;
if (i == 1) {
/* We have only one free byte left in buffer => write there trailing zero */
data->string[data->size - 1] = 0;
data->len = data->size;
return ((int) size);
return count;
}
if (left <= size) {
/* We do not have enough space for the whole string
* with the trailing zero => print only a part
* of string
*/
size_t index = 0;
while (index < size) {
wchar_t uc = str_decode(str, &index, size);
if (chr_encode(uc, data->dst, &data->len, data->size - 1) != EOK)
break;
}
/* Put trailing zero at end, but not count it
* into data->len so it could be rewritten next time
*/
data->dst[data->len] = 0;
return ((int) size);
if (i <= count) {
/* We have not enought space for whole string with the trailing zero => print only a part of string */
memcpy((void *)(data->string + data->len), (void *)str, i - 1);
data->string[data->size - 1] = 0;
data->len = data->size;
return count;
}
/* Buffer is big enought to print the whole string */
memcpy((void *)(data->dst + data->len), (void *) str, size);
data->len += size;
/* Put trailing zero at end, but not count it
* into data->len so it could be rewritten next time
*/
data->dst[data->len] = 0;
return ((int) size);
}
/* Buffer is big enought to print whole string */
memcpy((void *)(data->string + data->len), (void *)str, count);
data->len += count;
/* Put trailing zero at end, but not count it into data->len so it could be rewritten next time */
data->string[data->len] = 0;
 
/** Write wide string to given buffer.
*
* Write at most data->size plain characters including trailing zero.
* According to C99, snprintf() has to return number of characters that
* would have been written if enough space had been available. Hence
* the return value is not the number of actually printed characters
* but size of the input string.
*
* @param str Source wide string to print.
* @param size Number of bytes in str.
* @param data Structure describing destination string, counter
* of used space and total string size.
*
* @return Number of wide characters to print (not characters actually
* printed).
*
*/
static int vsnprintf_wstr_write(const wchar_t *str, size_t size, vsnprintf_data_t *data)
{
size_t index = 0;
while (index < (size / sizeof(wchar_t))) {
size_t left = data->size - data->len;
if (left == 0)
return ((int) size);
if (left == 1) {
/* We have only one free byte left in buffer
* -> store trailing zero
*/
data->dst[data->size - 1] = 0;
data->len = data->size;
return ((int) size);
}
if (chr_encode(str[index], data->dst, &data->len, data->size - 1) != EOK)
break;
index++;
}
/* Put trailing zero at end, but not count it
* into data->len so it could be rewritten next time
*/
data->dst[data->len] = 0;
return ((int) size);
return count;
}
 
int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
{
vsnprintf_data_t data = {
size,
0,
str
};
printf_spec_t ps = {
(int(*) (const char *, size_t, void *)) vsnprintf_str_write,
(int(*) (const wchar_t *, size_t, void *)) vsnprintf_wstr_write,
&data
};
struct vsnprintf_data data = {size, 0, str};
struct printf_spec ps = {(int(*)(void *, size_t, void *))vsnprintf_write, &data};
 
/* Print 0 at end of string - fix the case that nothing will be printed */
if (size > 0)
str[0] = 0;
/branches/arm/kernel/generic/src/printf/printf_core.c
1,7 → 1,6
/*
* Copyright (c) 2001-2004 Jakub Jermar
* Copyright (c) 2006 Josef Cejka
* Copyright (c) 2009 Martin Decky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
28,45 → 27,39
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup generic
/** @addtogroup generic
* @{
*/
/**
* @file
* @brief Printing functions.
* @brief Printing functions.
*/
 
#include <printf/printf_core.h>
#include <putchar.h>
#include <print.h>
#include <synch/spinlock.h>
#include <arch/arg.h>
#include <macros.h>
#include <string.h>
#include <arch/asm.h>
 
#include <arch.h>
 
/** show prefixes 0x or 0 */
#define __PRINTF_FLAG_PREFIX 0x00000001
/** signed / unsigned number */
#define __PRINTF_FLAG_SIGNED 0x00000002
/** print leading zeroes */
#define __PRINTF_FLAG_ZEROPADDED 0x00000004
/** align to left */
#define __PRINTF_FLAG_LEFTALIGNED 0x00000010
/** always show + sign */
#define __PRINTF_FLAG_SHOWPLUS 0x00000020
/** print space instead of plus */
#define __PRINTF_FLAG_SPACESIGN 0x00000040
/** show big characters */
#define __PRINTF_FLAG_BIGCHARS 0x00000080
/** number has - sign */
#define __PRINTF_FLAG_NEGATIVE 0x00000100
SPINLOCK_INITIALIZE(printflock); /**< printf spinlock */
 
/**
* Buffer big enough for 64-bit number printed in base 2, sign, prefix and 0
* to terminate string... (last one is only for better testing end of buffer by
* zero-filling subroutine)
*/
#define PRINT_NUMBER_BUFFER_SIZE (64 + 5)
#define __PRINTF_FLAG_PREFIX 0x00000001 /**< show prefixes 0x or 0*/
#define __PRINTF_FLAG_SIGNED 0x00000002 /**< signed / unsigned number */
#define __PRINTF_FLAG_ZEROPADDED 0x00000004 /**< print leading zeroes */
#define __PRINTF_FLAG_LEFTALIGNED 0x00000010 /**< align to left */
#define __PRINTF_FLAG_SHOWPLUS 0x00000020 /**< always show + sign */
#define __PRINTF_FLAG_SPACESIGN 0x00000040 /**< print space instead of plus */
#define __PRINTF_FLAG_BIGCHARS 0x00000080 /**< show big characters */
#define __PRINTF_FLAG_NEGATIVE 0x00000100 /**< number has - sign */
 
#define PRINT_NUMBER_BUFFER_SIZE (64+5) /**< Buffer big enought for 64 bit number
* printed in base 2, sign, prefix and
* 0 to terminate string.. (last one is only for better testing
* end of buffer by zero-filling subroutine)*/
 
/** Enumeration of possible arguments types.
*/
typedef enum {
75,296 → 68,190
PrintfQualifierInt,
PrintfQualifierLong,
PrintfQualifierLongLong,
PrintfQualifierNative,
PrintfQualifierPointer
} qualifier_t;
 
static char nullstr[] = "(NULL)";
static char digits_small[] = "0123456789abcdef";
static char digits_big[] = "0123456789ABCDEF";
static char invalch = U_SPECIAL;
static char digits_small[] = "0123456789abcdef"; /**< Small hexadecimal characters */
static char digits_big[] = "0123456789ABCDEF"; /**< Big hexadecimal characters */
 
/** Print one or more characters without adding newline.
*
* @param buf Buffer holding characters with size of
* at least size bytes. NULL is not allowed!
* @param size Size of the buffer in bytes.
* @param ps Output method and its data.
*
* @return Number of characters printed.
*
/** Checks c for a digit.
* @param c One character.
* @return nonzero if c is from interval '0 to '9'.
*/
static int printf_putnchars(const char *buf, size_t size,
printf_spec_t *ps)
static inline int isdigit(int c)
{
return ps->str_write((void *) buf, size, ps->data);
return ((c >= '0' )&&( c <= '9'));
}
 
/** Print one or more wide characters without adding newline.
*
* @param buf Buffer holding wide characters with size of
* at least size bytes. NULL is not allowed!
* @param size Size of the buffer in bytes.
* @param ps Output method and its data.
*
* @return Number of wide characters printed.
*
/** Compute length of given zero terminated string.
* @param str Pointer to valid string.
* @return string length without trailing zero.
*/
static int printf_wputnchars(const wchar_t *buf, size_t size,
printf_spec_t *ps)
static unative_t strlen(const char *str)
{
return ps->wstr_write((void *) buf, size, ps->data);
unative_t counter = 0;
 
while (str[counter] != 0) {
counter++;
}
 
return counter;
}
 
/** Print string without adding a newline.
*
* @param str String to print.
* @param ps Write function specification and support data.
*
* @return Number of characters printed.
*
/** Print count chars from buffer without adding newline
* @param buf Buffer with size at least count bytes - NULL pointer NOT allowed!
* @param count
* @param ps output method and its data
* @return number of printed characters
*/
static int printf_putstr(const char *str, printf_spec_t *ps)
static int printf_putnchars(const char * buf, size_t count, struct printf_spec *ps)
{
if (str == NULL)
return printf_putnchars(nullstr, str_size(nullstr), ps);
return ps->str_write((void *) str, str_size(str), ps->data);
return ps->write((void *)buf, count, ps->data);
}
 
/** Print one ASCII character.
*
* @param c ASCII character to be printed.
* @param ps Output method.
*
* @return Number of characters printed.
*
/** Print string without added newline
* @param str string to print
* @param ps write function specification and support data
* @return number of printed characters
*/
static int printf_putchar(const char ch, printf_spec_t *ps)
static int printf_putstr(const char * str, struct printf_spec *ps)
{
if (!ascii_check(ch))
return ps->str_write((void *) &invalch, 1, ps->data);
size_t count;
return ps->str_write(&ch, 1, ps->data);
if (str == NULL) {
return printf_putnchars("(NULL)", 6, ps);
}
 
count = strlen(str);
 
return ps->write((void *) str, count, ps->data);
}
 
/** Print one wide character.
*
* @param c Wide character to be printed.
* @param ps Output method.
*
* @return Number of characters printed.
*
/** Print one character to output
* @param c one character
* @param ps output method
* @return number of printed characters
*/
static int printf_putwchar(const wchar_t ch, printf_spec_t *ps)
static int printf_putchar(int c, struct printf_spec *ps)
{
if (!chr_check(ch))
return ps->str_write((void *) &invalch, 1, ps->data);
unsigned char ch = c;
return ps->wstr_write(&ch, sizeof(wchar_t), ps->data);
return ps->write((void *) &ch, 1, ps->data);
}
 
/** Print one formatted ASCII character.
*
* @param ch Character to print.
* @param width Width modifier.
* @param flags Flags that change the way the character is printed.
*
* @return Number of characters printed, negative value on failure.
*
/** Print one formatted character
* @param c character to print
* @param width
* @param flags
* @return number of printed characters, negative value on fail
*/
static int print_char(const char ch, int width, uint32_t flags, printf_spec_t *ps)
static int print_char(char c, int width, uint64_t flags, struct printf_spec *ps)
{
size_t counter = 0;
int counter = 0;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (--width > 0) {
/*
* One space is consumed by the character itself, hence
* the predecrement.
*/
if (printf_putchar(' ', ps) > 0)
counter++;
while (--width > 0) { /* one space is consumed by character itself hence predecrement */
if (printf_putchar(' ', ps) > 0)
++counter;
}
}
if (printf_putchar(ch, ps) > 0)
if (printf_putchar(c, ps) > 0)
counter++;
while (--width > 0) {
/*
* One space is consumed by the character itself, hence
* the predecrement.
*/
 
while (--width > 0) { /* one space is consumed by character itself hence predecrement */
if (printf_putchar(' ', ps) > 0)
counter++;
++counter;
}
return (int) (counter + 1);
return ++counter;
}
 
/** Print one formatted wide character.
*
* @param ch Character to print.
* @param width Width modifier.
* @param flags Flags that change the way the character is printed.
*
* @return Number of characters printed, negative value on failure.
*
/** Print one string
* @param s string
* @param width
* @param precision
* @param flags
* @return number of printed characters or negative value on fail
*/
static int print_wchar(const wchar_t ch, int width, uint32_t flags, printf_spec_t *ps)
static int print_string(char *s, int width, int precision, uint64_t flags, struct printf_spec *ps)
{
size_t counter = 0;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (--width > 0) {
/*
* One space is consumed by the character itself, hence
* the predecrement.
*/
if (printf_putchar(' ', ps) > 0)
counter++;
}
int counter = 0;
size_t size;
int retval;
 
if (s == NULL) {
return printf_putstr("(NULL)", ps);
}
if (printf_putwchar(ch, ps) > 0)
counter++;
while (--width > 0) {
/*
* One space is consumed by the character itself, hence
* the predecrement.
*/
if (printf_putchar(' ', ps) > 0)
counter++;
}
return (int) (counter + 1);
}
size = strlen(s);
 
/** Print string.
*
* @param str String to be printed.
* @param width Width modifier.
* @param precision Precision modifier.
* @param flags Flags that modify the way the string is printed.
*
* @return Number of characters printed, negative value on failure.
*/
static int print_str(char *str, int width, unsigned int precision,
uint32_t flags, printf_spec_t *ps)
{
if (str == NULL)
return printf_putstr(nullstr, ps);
/* print leading spaces */
 
/* Print leading spaces. */
size_t strw = str_length(str);
if (precision == 0)
precision = strw;
if (precision == 0)
precision = size;
 
/* Left padding */
size_t counter = 0;
width -= precision;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
}
 
/* Part of @a str fitting into the alloted space. */
int retval;
size_t size = str_lsize(str, precision);
if ((retval = printf_putnchars(str, size, ps)) < 0)
while (precision > size) {
precision--;
if (printf_putchar(' ', ps) == 1)
++counter;
}
if ((retval = printf_putnchars(s, precision, ps)) < 0) {
return -counter;
}
counter += retval;
 
counter += retval;
 
/* Right padding */
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
if (printf_putchar(' ', ps) == 1)
++counter;
}
return counter;
}
 
return ((int) counter);
 
}
 
/** Print wide string.
/** Print number in given base
*
* @param str Wide string to be printed.
* @param width Width modifier.
* @param precision Precision modifier.
* @param flags Flags that modify the way the string is printed.
* Print significant digits of a number in given
* base.
*
* @return Number of wide characters printed, negative value on failure.
* @param num Number to print.
* @param width
* @param precision
* @param base Base to print the number in (should
* be in range 2 .. 16).
* @param flags output modifiers
* @return number of written characters or EOF
*
*/
static int print_wstr(wchar_t *str, int width, unsigned int precision,
uint32_t flags, printf_spec_t *ps)
static int print_number(uint64_t num, int width, int precision, int base , uint64_t flags, struct printf_spec *ps)
{
if (str == NULL)
return printf_putstr(nullstr, ps);
/* Print leading spaces. */
size_t strw = wstr_length(str);
if (precision == 0)
precision = strw;
/* Left padding */
size_t counter = 0;
width -= precision;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
}
/* Part of @a wstr fitting into the alloted space. */
char *digits = digits_small;
char d[PRINT_NUMBER_BUFFER_SIZE]; /* this is good enough even for base == 2, prefix and sign */
char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
int size = 0; /* size of number with all prefixes and signs */
int number_size; /* size of plain number */
char sgn;
int retval;
size_t size = wstr_lsize(str, precision);
if ((retval = printf_wputnchars(str, size, ps)) < 0)
return -counter;
int counter = 0;
counter += retval;
if (flags & __PRINTF_FLAG_BIGCHARS)
digits = digits_big;
/* Right padding */
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
*ptr-- = 0; /* Put zero at end of string */
 
return ((int) counter);
}
 
/** Print a number in a given base.
*
* Print significant digits of a number in given base.
*
* @param num Number to print.
* @param width Width modifier.
* @param precision Precision modifier.
* @param base Base to print the number in (must be between 2 and 16).
* @param flags Flags that modify the way the number is printed.
*
* @return Number of characters printed.
*
*/
static int print_number(uint64_t num, int width, int precision, int base,
uint32_t flags, printf_spec_t *ps)
{
char *digits;
if (flags & __PRINTF_FLAG_BIGCHARS)
digits = digits_big;
else
digits = digits_small;
char data[PRINT_NUMBER_BUFFER_SIZE];
char *ptr = &data[PRINT_NUMBER_BUFFER_SIZE - 1];
/* Size of number with all prefixes and signs */
int size = 0;
/* Put zero at end of string */
*ptr-- = 0;
if (num == 0) {
*ptr-- = '0';
size++;
375,17 → 262,12
} while (num /= base);
}
/* Size of plain number */
int number_size = size;
/*
* Collect the sum of all prefixes/signs/etc. to calculate padding and
* leading zeroes.
*/
number_size = size;
 
/* Collect sum of all prefixes/signs/... to calculate padding and leading zeroes */
if (flags & __PRINTF_FLAG_PREFIX) {
switch(base) {
case 2:
/* Binary formating is not standard, but usefull */
case 2: /* Binary formating is not standard, but usefull */
size += 2;
break;
case 8:
396,60 → 278,57
break;
}
}
char sgn = 0;
 
sgn = 0;
if (flags & __PRINTF_FLAG_SIGNED) {
if (flags & __PRINTF_FLAG_NEGATIVE) {
sgn = '-';
size++;
} else if (flags & __PRINTF_FLAG_SHOWPLUS) {
sgn = '+';
size++;
} else if (flags & __PRINTF_FLAG_SPACESIGN) {
sgn = ' ';
size++;
}
sgn = '+';
size++;
} else if (flags & __PRINTF_FLAG_SPACESIGN) {
sgn = ' ';
size++;
}
}
if (flags & __PRINTF_FLAG_LEFTALIGNED)
 
if (flags & __PRINTF_FLAG_LEFTALIGNED) {
flags &= ~__PRINTF_FLAG_ZEROPADDED;
/*
* If the number is left-aligned or precision is specified then
* padding with zeros is ignored.
*/
}
 
/* if number is leftaligned or precision is specified then zeropadding is ignored */
if (flags & __PRINTF_FLAG_ZEROPADDED) {
if ((precision == 0) && (width > size))
if ((precision == 0) && (width > size)) {
precision = width - size + number_size;
}
}
/* Print leading spaces */
if (number_size > precision) {
/* Print the whole number, not only a part */
 
/* print leading spaces */
if (number_size > precision) /* We must print whole number not only a part */
precision = number_size;
}
 
width -= precision + size - number_size;
size_t counter = 0;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
}
/* Print sign */
/* print sign */
if (sgn) {
if (printf_putchar(sgn, ps) == 1)
counter++;
}
/* Print prefix */
/* print prefix */
if (flags & __PRINTF_FLAG_PREFIX) {
switch(base) {
case 2:
/* Binary formating is not standard, but usefull */
case 2: /* Binary formating is not standard, but usefull */
if (printf_putchar('0', ps) == 1)
counter++;
if (flags & __PRINTF_FLAG_BIGCHARS) {
477,309 → 356,258
break;
}
}
/* Print leading zeroes */
 
/* print leading zeroes */
precision -= number_size;
while (precision-- > 0) {
while (precision-- > 0) {
if (printf_putchar('0', ps) == 1)
counter++;
}
 
/* Print the number itself */
int retval;
if ((retval = printf_putstr(++ptr, ps)) > 0)
/* print number itself */
 
if ((retval = printf_putstr(++ptr, ps)) > 0) {
counter += retval;
}
/* Print tailing spaces */
/* print ending spaces */
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
return ((int) counter);
 
return counter;
}
 
 
/** Print formatted string.
*
* Print string formatted according to the fmt parameter and variadic arguments.
* Each formatting directive must have the following form:
* Print string formatted according to the fmt parameter
* and variadic arguments. Each formatting directive
* must have the following form:
*
* \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
*
* \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
*
* FLAGS:@n
* - "#" Force to print prefix. For \%o conversion, the prefix is 0, for
* \%x and \%X prefixes are 0x and 0X and for conversion \%b the
* prefix is 0b.
* - "#" Force to print prefix.
* For conversion \%o the prefix is 0, for \%x and \%X prefixes are 0x and 0X
* and for conversion \%b the prefix is 0b.
*
* - "-" Align to left.
* - "-" Align to left.
*
* - "+" Print positive sign just as negative.
* - "+" Print positive sign just as negative.
*
* - " " If the printed number is positive and "+" flag is not set,
* print space in place of sign.
* - " " If the printed number is positive and "+" flag is not set, print space in
* place of sign.
*
* - "0" Print 0 as padding instead of spaces. Zeroes are placed between
* sign and the rest of the number. This flag is ignored if "-"
* flag is specified.
*
* - "0" Print 0 as padding instead of spaces. Zeroes are placed between sign and the
* rest of the number. This flag is ignored if "-" flag is specified.
*
* WIDTH:@n
* - Specify the minimal width of a printed argument. If it is bigger,
* width is ignored. If width is specified with a "*" character instead of
* number, width is taken from parameter list. And integer parameter is
* expected before parameter for processed conversion specification. If
* this value is negative its absolute value is taken and the "-" flag is
* set.
* - Specify minimal width of printed argument. If it is bigger, width is ignored.
* If width is specified with a "*" character instead of number, width is taken from
* parameter list. And integer parameter is expected before parameter for processed
* conversion specification. If this value is negative its absolute value is taken
* and the "-" flag is set.
*
* PRECISION:@n
* - Value precision. For numbers it specifies minimum valid numbers.
* Smaller numbers are printed with leading zeroes. Bigger numbers are not
* affected. Strings with more than precision characters are cut off. Just
* as with width, an "*" can be used used instead of a number. An integer
* value is then expected in parameters. When both width and precision are
* specified using "*", the first parameter is used for width and the
* second one for precision.
*
* - Value precision. For numbers it specifies minimum valid numbers.
* Smaller numbers are printed with leading zeroes. Bigger numbers are not affected.
* Strings with more than precision characters are cut off.
* Just as with width, an "*" can be used used instead of a number.
* An integer value is then expected in parameters. When both width and precision
* are specified using "*", the first parameter is used for width and the second one
* for precision.
*
* TYPE:@n
* - "hh" Signed or unsigned char.@n
* - "h" Signed or unsigned short.@n
* - "" Signed or unsigned int (default value).@n
* - "l" Signed or unsigned long int.@n
* If conversion is "c", the character is wchar_t (wide character).@n
* If conversion is "s", the string is wchar_t * (wide string).@n
* - "ll" Signed or unsigned long long int.@n
*
* - "hh" Signed or unsigned char.@n
* - "h" Signed or usigned short.@n
* - "" Signed or usigned int (default value).@n
* - "l" Signed or usigned long int.@n
* - "ll" Signed or usigned long long int.@n
* - "z" unative_t (non-standard extension).@n
*
*
* CONVERSION:@n
* - % Print percentile character itself.
* - % Print percentile character itself.
*
* - c Print single character. The character is expected to be plain
* ASCII (e.g. only values 0 .. 127 are valid).@n
* If type is "l", then the character is expected to be wide character
* (e.g. values 0 .. 0x10ffff are valid).
* - c Print single character.
*
* - s Print zero terminated string. If a NULL value is passed as
* value, "(NULL)" is printed instead.@n
* If type is "l", then the string is expected to be wide string.
* - s Print zero terminated string. If a NULL value is passed as value, "(NULL)" is printed instead.
*
* - P, p Print value of a pointer. Void * value is expected and it is printed in hexadecimal notation with prefix
* (as with \%#X or \%#x for 32bit or \%#X / \%#x for 64bit long pointers).
*
* - P, p Print value of a pointer. Void * value is expected and it is
* printed in hexadecimal notation with prefix (as with \%#X / \%#x
* for 32-bit or \%#X / \%#x for 64-bit long pointers).
* - b Print value as unsigned binary number. Prefix is not printed by default. (Nonstandard extension.)
*
* - o Print value as unsigned octal number. Prefix is not printed by default.
*
* - b Print value as unsigned binary number. Prefix is not printed by
* default. (Nonstandard extension.)
* - d,i Print signed decimal number. There is no difference between d and i conversion.
*
* - o Print value as unsigned octal number. Prefix is not printed by
* default.
* - u Print unsigned decimal number.
*
* - d, i Print signed decimal number. There is no difference between d
* and i conversion.
* - X, x Print hexadecimal number with upper- or lower-case. Prefix is not printed by default.
*
* All other characters from fmt except the formatting directives
* are printed in verbatim.
*
* - u Print unsigned decimal number.
*
* - X, x Print hexadecimal number with upper- or lower-case. Prefix is
* not printed by default.
*
* All other characters from fmt except the formatting directives are printed
* verbatim.
*
* @param fmt Format NULL-terminated string.
*
* @return Number of characters printed, negative value on failure.
*
* @param fmt Formatting NULL terminated string.
* @return Number of printed characters or negative value on failure.
*/
int printf_core(const char *fmt, printf_spec_t *ps, va_list ap)
int printf_core(const char *fmt, struct printf_spec *ps, va_list ap)
{
size_t i; /* Index of the currently processed character from fmt */
size_t nxt = 0; /* Index of the next character from fmt */
size_t j = 0; /* Index to the first not printed nonformating character */
int irqpri;
int i = 0, j = 0; /**< i is index of currently processed char from fmt, j is index to the first not printed nonformating character */
int end;
int counter; /**< counter of printed characters */
int retval; /**< used to store return values from called functions */
char c;
qualifier_t qualifier; /* type of argument */
int base; /**< base in which will be parameter (numbers only) printed */
uint64_t number; /**< argument value */
size_t size; /**< byte size of integer parameter */
int width, precision;
uint64_t flags;
size_t counter = 0; /* Number of characters printed */
int retval; /* Return values from nested functions */
counter = 0;
while (true) {
i = nxt;
wchar_t uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (uc == 0)
break;
/* Control character */
if (uc == '%') {
/* Print common characters if any processed */
irqpri = interrupts_disable();
spinlock_lock(&printflock);
 
while ((c = fmt[i])) {
/* control character */
if (c == '%' ) {
/* print common characters if any processed */
if (i > j) {
if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
/* Error */
if ((retval = printf_putnchars(&fmt[j], (size_t)(i - j), ps)) < 0) { /* error */
counter = -counter;
goto out;
}
counter += retval;
}
j = i;
/* parse modifiers */
flags = 0;
end = 0;
/* Parse modifiers */
uint32_t flags = 0;
bool end = false;
do {
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
switch (uc) {
case '#':
flags |= __PRINTF_FLAG_PREFIX;
break;
case '-':
flags |= __PRINTF_FLAG_LEFTALIGNED;
break;
case '+':
flags |= __PRINTF_FLAG_SHOWPLUS;
break;
case ' ':
flags |= __PRINTF_FLAG_SPACESIGN;
break;
case '0':
flags |= __PRINTF_FLAG_ZEROPADDED;
break;
default:
end = true;
};
} while (!end);
++i;
switch (c = fmt[i]) {
case '#': flags |= __PRINTF_FLAG_PREFIX; break;
case '-': flags |= __PRINTF_FLAG_LEFTALIGNED; break;
case '+': flags |= __PRINTF_FLAG_SHOWPLUS; break;
case ' ': flags |= __PRINTF_FLAG_SPACESIGN; break;
case '0': flags |= __PRINTF_FLAG_ZEROPADDED; break;
default: end = 1;
};
} while (end == 0);
/* Width & '*' operator */
int width = 0;
if (isdigit(uc)) {
while (true) {
/* width & '*' operator */
width = 0;
if (isdigit(fmt[i])) {
while (isdigit(fmt[i])) {
width *= 10;
width += uc - '0';
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (uc == 0)
break;
if (!isdigit(uc))
break;
width += fmt[i++] - '0';
}
} else if (uc == '*') {
/* Get width value from argument list */
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
width = (int) va_arg(ap, int);
} else if (fmt[i] == '*') {
/* get width value from argument list*/
i++;
width = (int)va_arg(ap, int);
if (width < 0) {
/* Negative width sets '-' flag */
/* negative width means to set '-' flag */
width *= -1;
flags |= __PRINTF_FLAG_LEFTALIGNED;
}
}
/* Precision and '*' operator */
int precision = 0;
if (uc == '.') {
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (isdigit(uc)) {
while (true) {
/* precision and '*' operator */
precision = 0;
if (fmt[i] == '.') {
++i;
if (isdigit(fmt[i])) {
while (isdigit(fmt[i])) {
precision *= 10;
precision += uc - '0';
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (uc == 0)
break;
if (!isdigit(uc))
break;
precision += fmt[i++] - '0';
}
} else if (uc == '*') {
/* Get precision value from the argument list */
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
precision = (int) va_arg(ap, int);
} else if (fmt[i] == '*') {
/* get precision value from argument list*/
i++;
precision = (int)va_arg(ap, int);
if (precision < 0) {
/* Ignore negative precision */
/* negative precision means to ignore it */
precision = 0;
}
}
}
qualifier_t qualifier;
switch (uc) {
/** @todo Unimplemented qualifiers:
* t ptrdiff_t - ISO C 99
 
switch (fmt[i++]) {
/** TODO: unimplemented qualifiers:
* t ptrdiff_t - ISO C 99
*/
case 'h':
/* Char or short */
case 'h': /* char or short */
qualifier = PrintfQualifierShort;
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (uc == 'h') {
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (fmt[i] == 'h') {
i++;
qualifier = PrintfQualifierByte;
}
break;
case 'l':
/* Long or long long */
case 'l': /* long or long long*/
qualifier = PrintfQualifierLong;
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (uc == 'l') {
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (fmt[i] == 'l') {
i++;
qualifier = PrintfQualifierLongLong;
}
break;
case 'z': /* unative_t */
qualifier = PrintfQualifierNative;
break;
default:
/* Default type */
qualifier = PrintfQualifierInt;
}
qualifier = PrintfQualifierInt; /* default type */
--i;
}
unsigned int base = 10;
switch (uc) {
base = 10;
 
switch (c = fmt[i]) {
 
/*
* String and character conversions.
*/
* String and character conversions.
*/
case 's':
if (qualifier == PrintfQualifierLong)
retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps);
else
retval = print_str(va_arg(ap, char *), width, precision, flags, ps);
if (retval < 0) {
if ((retval = print_string(va_arg(ap, char*), width, precision, flags, ps)) < 0) {
counter = -counter;
goto out;
}
};
 
counter += retval;
j = nxt;
j = i + 1;
goto next_char;
case 'c':
if (qualifier == PrintfQualifierLong)
retval = print_wchar(va_arg(ap, wchar_t), width, flags, ps);
else
retval = print_char(va_arg(ap, unsigned int), width, flags, ps);
if (retval < 0) {
c = va_arg(ap, unsigned int);
if ((retval = print_char(c, width, flags, ps)) < 0) {
counter = -counter;
goto out;
};
counter += retval;
j = nxt;
j = i + 1;
goto next_char;
/*
 
/*
* Integer values
*/
case 'P':
/* Pointer */
flags |= __PRINTF_FLAG_BIGCHARS;
case 'P': /* pointer */
flags |= __PRINTF_FLAG_BIGCHARS;
case 'p':
flags |= __PRINTF_FLAG_PREFIX;
base = 16;
qualifier = PrintfQualifierPointer;
break;
case 'b':
break;
case 'b':
base = 2;
break;
case 'o':
787,7 → 615,7
break;
case 'd':
case 'i':
flags |= __PRINTF_FLAG_SIGNED;
flags |= __PRINTF_FLAG_SIGNED;
case 'u':
break;
case 'X':
795,97 → 623,99
case 'x':
base = 16;
break;
/* Percentile itself */
case '%':
/* percentile itself */
case '%':
j = i;
goto next_char;
/*
* Bad formatting.
*/
default:
/*
* Unknown format. Now, j is the index of '%'
* so we will print whole bad format sequence.
/* Unknown format
* now, j is index of '%' so we will
* print whole bad format sequence
*/
goto next_char;
goto next_char;
}
/* Print integers */
size_t size;
uint64_t number;
/* Print integers */
/* print number */
switch (qualifier) {
case PrintfQualifierByte:
size = sizeof(unsigned char);
number = (uint64_t) va_arg(ap, unsigned int);
number = (uint64_t)va_arg(ap, unsigned int);
break;
case PrintfQualifierShort:
size = sizeof(unsigned short);
number = (uint64_t) va_arg(ap, unsigned int);
number = (uint64_t)va_arg(ap, unsigned int);
break;
case PrintfQualifierInt:
size = sizeof(unsigned int);
number = (uint64_t) va_arg(ap, unsigned int);
number = (uint64_t)va_arg(ap, unsigned int);
break;
case PrintfQualifierLong:
size = sizeof(unsigned long);
number = (uint64_t) va_arg(ap, unsigned long);
number = (uint64_t)va_arg(ap, unsigned long);
break;
case PrintfQualifierLongLong:
size = sizeof(unsigned long long);
number = (uint64_t) va_arg(ap, unsigned long long);
number = (uint64_t)va_arg(ap, unsigned long long);
break;
case PrintfQualifierPointer:
size = sizeof(void *);
number = (uint64_t) (unsigned long) va_arg(ap, void *);
number = (uint64_t)(unsigned long)va_arg(ap, void *);
break;
default:
/* Unknown qualifier */
case PrintfQualifierNative:
size = sizeof(unative_t);
number = (uint64_t)va_arg(ap, unative_t);
break;
default: /* Unknown qualifier */
counter = -counter;
goto out;
}
if (flags & __PRINTF_FLAG_SIGNED) {
if (number & (0x1 << (size * 8 - 1))) {
if (number & (0x1 << (size*8 - 1))) {
flags |= __PRINTF_FLAG_NEGATIVE;
if (size == sizeof(uint64_t)) {
number = -((int64_t) number);
number = -((int64_t)number);
} else {
number = ~number;
number &=
~(0xFFFFFFFFFFFFFFFFll <<
(size * 8));
number &= (~((0xFFFFFFFFFFFFFFFFll) << (size * 8)));
number++;
}
}
}
if ((retval = print_number(number, width, precision,
base, flags, ps)) < 0) {
 
if ((retval = print_number(number, width, precision, base, flags, ps)) < 0) {
counter = -counter;
goto out;
}
};
 
counter += retval;
j = nxt;
}
j = i + 1;
}
next_char:
;
++i;
}
if (i > j) {
if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
/* Error */
if ((retval = printf_putnchars(&fmt[j], (unative_t)(i - j), ps)) < 0) { /* error */
counter = -counter;
goto out;
}
counter += retval;
}
 
out:
spinlock_unlock(&printflock);
interrupts_restore(irqpri);
out:
return ((int) counter);
return counter;
}
 
/** @}
/branches/arm/kernel/generic/src/printf/vsprintf.c
0,0 → 1,43
/*
* Copyright (c) 2006 Josef Cejka
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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 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.
*/
 
/** @addtogroup generic
* @{
*/
/** @file
*/
 
#include <print.h>
 
int vsprintf(char *str, const char *fmt, va_list ap)
{
return vsnprintf(str, (size_t)-1, fmt, ap);
}
 
/** @}
*/
/branches/arm/kernel/generic/src/mm/frame.c
1,7 → 1,6
/*
* Copyright (c) 2001-2005 Jakub Jermar
* Copyright (c) 2005 Sergey Bondari
* Copyright (c) 2009 Martin Decky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
34,7 → 33,7
 
/**
* @file
* @brief Physical frame allocator.
* @brief Physical frame allocator.
*
* This file contains the physical frame allocator and memory zone management.
* The frame allocator is built on top of the buddy allocator.
42,6 → 41,16
* @see buddy.c
*/
 
/*
* Locking order
*
* In order to access particular zone, the process must first lock
* the zones.lock, then lock the zone and then unlock the zones.lock.
* This insures, that we can fiddle with the zones in runtime without
* affecting the processes.
*
*/
 
#include <arch/types.h>
#include <mm/frame.h>
#include <mm/as.h>
48,8 → 57,7
#include <panic.h>
#include <debug.h>
#include <adt/list.h>
#include <synch/mutex.h>
#include <synch/condvar.h>
#include <synch/spinlock.h>
#include <arch/asm.h>
#include <arch.h>
#include <print.h>
59,45 → 67,66
#include <macros.h>
#include <config.h>
 
zones_t zones;
typedef struct {
count_t refcount; /**< tracking of shared frames */
uint8_t buddy_order; /**< buddy system block order */
link_t buddy_link; /**< link to the next free block inside one order */
void *parent; /**< If allocated by slab, this points there */
} frame_t;
 
typedef struct {
SPINLOCK_DECLARE(lock); /**< this lock protects everything below */
pfn_t base; /**< frame_no of the first frame in the frames array */
count_t count; /**< Size of zone */
 
frame_t *frames; /**< array of frame_t structures in this zone */
count_t free_count; /**< number of free frame_t structures */
count_t busy_count; /**< number of busy frame_t structures */
buddy_system_t *buddy_system; /**< buddy system for the zone */
int flags;
} zone_t;
 
/*
* Synchronization primitives used to sleep when there is no memory
* available.
* The zoneinfo.lock must be locked when accessing zoneinfo structure.
* Some of the attributes in zone_t structures are 'read-only'
*/
mutex_t mem_avail_mtx;
condvar_t mem_avail_cv;
size_t mem_avail_req = 0; /**< Number of frames requested. */
size_t mem_avail_gen = 0; /**< Generation counter. */
 
/********************/
typedef struct {
SPINLOCK_DECLARE(lock);
unsigned int count;
zone_t *info[ZONES_MAX];
} zones_t;
 
static zones_t zones;
 
 
/*********************************/
/* Helper functions */
/********************/
 
static inline size_t frame_index(zone_t *zone, frame_t *frame)
static inline index_t frame_index(zone_t *zone, frame_t *frame)
{
return (size_t) (frame - zone->frames);
return (index_t)(frame - zone->frames);
}
 
static inline size_t frame_index_abs(zone_t *zone, frame_t *frame)
static inline index_t frame_index_abs(zone_t *zone, frame_t *frame)
{
return (size_t) (frame - zone->frames) + zone->base;
return (index_t)(frame - zone->frames) + zone->base;
}
 
static inline bool frame_index_valid(zone_t *zone, size_t index)
static inline int frame_index_valid(zone_t *zone, index_t index)
{
return (index < zone->count);
return index >= 0 && index < zone->count;
}
 
static inline size_t make_frame_index(zone_t *zone, frame_t *frame)
/** Compute pfn_t from frame_t pointer & zone pointer */
static index_t make_frame_index(zone_t *zone, frame_t *frame)
{
return (frame - zone->frames);
return frame - zone->frames;
}
 
/** Initialize frame structure.
/** Initialize frame structure
*
* Initialize frame structure.
*
* @param frame Frame structure to be initialized.
*
*/
static void frame_initialize(frame_t *frame)
{
105,145 → 134,131
frame->buddy_order = 0;
}
 
/*******************/
/* Zones functions */
/*******************/
/*************************************/
/* Zoneinfo functions */
 
/** Insert-sort zone into zones list.
/**
* Insert-sort zone into zones list
*
* Assume interrupts are disabled and zones lock is
* locked.
*
* @param base Base frame of the newly inserted zone.
* @param count Number of frames of the newly inserted zone.
*
* @return Zone number on success, -1 on error.
*
* @param newzone New zone to be inserted into zone list
* @return zone number on success, -1 on error
*/
static size_t zones_insert_zone(pfn_t base, size_t count)
static int zones_add_zone(zone_t *newzone)
{
if (zones.count + 1 == ZONES_MAX) {
printf("Maximum zone count %u exceeded!\n", ZONES_MAX);
return (size_t) -1;
}
size_t i;
unsigned int i, j;
ipl_t ipl;
zone_t *z;
 
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
/* Try to merge */
if (zones.count + 1 == ZONES_MAX)
panic("Maximum zone(%d) count exceeded.", ZONES_MAX);
for (i = 0; i < zones.count; i++) {
/* Check for overlap */
if (overlaps(base, count,
zones.info[i].base, zones.info[i].count)) {
/* Check for overflow */
z = zones.info[i];
if (overlaps(newzone->base,newzone->count,
z->base, z->count)) {
printf("Zones overlap!\n");
return (size_t) -1;
return -1;
}
if (base < zones.info[i].base)
if (newzone->base < z->base)
break;
}
/* Move other zones up */
size_t j;
for (j = zones.count; j > i; j--) {
zones.info[j] = zones.info[j - 1];
zones.info[j].buddy_system->data =
(void *) &zones.info[j - 1];
}
for (j = i;j < zones.count; j++)
zones.info[j + 1] = zones.info[j];
zones.info[i] = newzone;
zones.count++;
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
 
return i;
}
 
/** Get total available frames.
*
* Assume interrupts are disabled and zones lock is
* locked.
*
* @return Total number of available frames.
*
/**
* Try to find a zone where can we find the frame
* Assume interrupts are disabled.
* @param frame Frame number contained in zone
* @param pzone If not null, it is used as zone hint. Zone index
* is filled into the variable on success.
* @return Pointer to locked zone containing frame
*/
#ifdef CONFIG_DEBUG
static size_t total_frames_free(void)
static zone_t * find_zone_and_lock(pfn_t frame, unsigned int *pzone)
{
size_t total = 0;
size_t i;
for (i = 0; i < zones.count; i++)
total += zones.info[i].free_count;
unsigned int i;
unsigned int hint = pzone ? *pzone : 0;
zone_t *z;
return total;
}
#endif
spinlock_lock(&zones.lock);
 
/** Find a zone with a given frames.
*
* Assume interrupts are disabled and zones lock is
* locked.
*
* @param frame Frame number contained in zone.
* @param count Number of frames to look for.
* @param hint Used as zone hint.
*
* @return Zone index or -1 if not found.
*
*/
size_t find_zone(pfn_t frame, size_t count, size_t hint)
{
if (hint >= zones.count)
if (hint >= zones.count || hint < 0)
hint = 0;
size_t i = hint;
i = hint;
do {
if ((zones.info[i].base <= frame)
&& (zones.info[i].base + zones.info[i].count >= frame + count))
return i;
z = zones.info[i];
spinlock_lock(&z->lock);
if (z->base <= frame && z->base + z->count > frame) {
spinlock_unlock(&zones.lock); /* Unlock the global lock */
if (pzone)
*pzone = i;
return z;
}
spinlock_unlock(&z->lock);
 
i++;
if (i >= zones.count)
i = 0;
} while (i != hint);
return (size_t) -1;
} while(i != hint);
 
spinlock_unlock(&zones.lock);
return NULL;
}
 
/** @return True if zone can allocate specified order */
static bool zone_can_alloc(zone_t *zone, uint8_t order)
static int zone_can_alloc(zone_t *z, uint8_t order)
{
return (zone_flags_available(zone->flags)
&& buddy_system_can_alloc(zone->buddy_system, order));
return buddy_system_can_alloc(z->buddy_system, order);
}
 
/** Find a zone that can allocate order frames.
/** Find and lock zone that can allocate order frames.
*
* Assume interrupts are disabled and zones lock is
* locked.
* Assume interrupts are disabled.
*
* @param order Size (2^order) of free space we are trying to find.
* @param flags Required flags of the target zone.
* @param hind Preferred zone.
*
* @param order Size (2^order) of free space we are trying to find
* @param pzone Pointer to preferred zone or NULL, on return contains zone number
*/
static size_t find_free_zone(uint8_t order, zone_flags_t flags, size_t hint)
static zone_t * find_free_zone_and_lock(uint8_t order, unsigned int *pzone)
{
unsigned int i;
zone_t *z;
unsigned int hint = pzone ? *pzone : 0;
spinlock_lock(&zones.lock);
if (hint >= zones.count)
hint = 0;
size_t i = hint;
i = hint;
do {
/*
* Check whether the zone meets the search criteria.
*/
if ((zones.info[i].flags & flags) == flags) {
/*
* Check if the zone has 2^order frames area available.
*/
if (zone_can_alloc(&zones.info[i], order))
return i;
z = zones.info[i];
spinlock_lock(&z->lock);
 
/* Check if the zone has 2^order frames area available */
if (zone_can_alloc(z, order)) {
spinlock_unlock(&zones.lock);
if (pzone)
*pzone = i;
return z;
}
i++;
if (i >= zones.count)
spinlock_unlock(&z->lock);
if (++i >= zones.count)
i = 0;
} while (i != hint);
return (size_t) -1;
} while(i != hint);
spinlock_unlock(&zones.lock);
return NULL;
}
 
/**************************/
250,146 → 265,165
/* Buddy system functions */
/**************************/
 
/** Buddy system find_block implementation.
/** Buddy system find_block implementation
*
* Find block that is parent of current list.
* That means go to lower addresses, until such block is found
*
* @param order Order of parent must be different then this
* parameter!!
*
* @param order - Order of parent must be different then this parameter!!
*/
static link_t *zone_buddy_find_block(buddy_system_t *buddy, link_t *child,
uint8_t order)
static link_t *zone_buddy_find_block(buddy_system_t *b, link_t *child,
uint8_t order)
{
frame_t *frame = list_get_instance(child, frame_t, buddy_link);
zone_t *zone = (zone_t *) buddy->data;
frame_t * frame;
zone_t * zone;
index_t index;
size_t index = frame_index(zone, frame);
frame = list_get_instance(child, frame_t, buddy_link);
zone = (zone_t *) b->data;
 
index = frame_index(zone, frame);
do {
if (zone->frames[index].buddy_order != order)
if (zone->frames[index].buddy_order != order) {
return &zone->frames[index].buddy_link;
} while (index-- > 0);
}
} while(index-- > 0);
return NULL;
}
 
/** Buddy system find_buddy implementation.
static void zone_buddy_print_id(buddy_system_t *b, link_t *block)
{
frame_t * frame;
zone_t * zone;
index_t index;
 
frame = list_get_instance(block, frame_t, buddy_link);
zone = (zone_t *) b->data;
index = frame_index(zone, frame);
printf("%zd", index);
}
 
/** Buddy system find_buddy implementation
*
* @param buddy Buddy system.
* @param block Block for which buddy should be found.
* @param b Buddy system.
* @param block Block for which buddy should be found
*
* @return Buddy for given block if found.
*
* @return Buddy for given block if found
*/
static link_t *zone_buddy_find_buddy(buddy_system_t *buddy, link_t *block)
static link_t * zone_buddy_find_buddy(buddy_system_t *b, link_t * block)
{
frame_t *frame = list_get_instance(block, frame_t, buddy_link);
zone_t *zone = (zone_t *) buddy->data;
ASSERT(IS_BUDDY_ORDER_OK(frame_index_abs(zone, frame),
frame->buddy_order));
frame_t * frame;
zone_t * zone;
index_t index;
bool is_left, is_right;
 
frame = list_get_instance(block, frame_t, buddy_link);
zone = (zone_t *) b->data;
ASSERT(IS_BUDDY_ORDER_OK(frame_index_abs(zone, frame), frame->buddy_order));
bool is_left = IS_BUDDY_LEFT_BLOCK_ABS(zone, frame);
size_t index;
is_left = IS_BUDDY_LEFT_BLOCK_ABS(zone, frame);
is_right = IS_BUDDY_RIGHT_BLOCK_ABS(zone, frame);
 
ASSERT(is_left ^ is_right);
if (is_left) {
index = (frame_index(zone, frame)) +
(1 << frame->buddy_order);
} else { /* is_right */
index = (frame_index(zone, frame)) -
(1 << frame->buddy_order);
index = (frame_index(zone, frame)) + (1 << frame->buddy_order);
} else { /* if (is_right) */
index = (frame_index(zone, frame)) - (1 << frame->buddy_order);
}
if (frame_index_valid(zone, index)) {
if ((zone->frames[index].buddy_order == frame->buddy_order) &&
(zone->frames[index].refcount == 0)) {
if (zone->frames[index].buddy_order == frame->buddy_order &&
zone->frames[index].refcount == 0) {
return &zone->frames[index].buddy_link;
}
}
return NULL;
 
return NULL;
}
 
/** Buddy system bisect implementation.
/** Buddy system bisect implementation
*
* @param buddy Buddy system.
* @param block Block to bisect.
* @param b Buddy system.
* @param block Block to bisect
*
* @return Right block.
*
* @return right block
*/
static link_t *zone_buddy_bisect(buddy_system_t *buddy, link_t *block)
{
frame_t *frame_l = list_get_instance(block, frame_t, buddy_link);
frame_t *frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
static link_t * zone_buddy_bisect(buddy_system_t *b, link_t * block) {
frame_t * frame_l, * frame_r;
 
frame_l = list_get_instance(block, frame_t, buddy_link);
frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
return &frame_r->buddy_link;
}
 
/** Buddy system coalesce implementation.
/** Buddy system coalesce implementation
*
* @param buddy Buddy system.
* @param block_1 First block.
* @param block_2 First block's buddy.
* @param b Buddy system.
* @param block_1 First block
* @param block_2 First block's buddy
*
* @return Coalesced block (actually block that represents lower
* address).
*
* @return Coalesced block (actually block that represents lower address)
*/
static link_t *zone_buddy_coalesce(buddy_system_t *buddy, link_t *block_1,
link_t *block_2)
static link_t * zone_buddy_coalesce(buddy_system_t *b, link_t * block_1,
link_t * block_2)
{
frame_t *frame1 = list_get_instance(block_1, frame_t, buddy_link);
frame_t *frame2 = list_get_instance(block_2, frame_t, buddy_link);
frame_t *frame1, *frame2;
return ((frame1 < frame2) ? block_1 : block_2);
frame1 = list_get_instance(block_1, frame_t, buddy_link);
frame2 = list_get_instance(block_2, frame_t, buddy_link);
return frame1 < frame2 ? block_1 : block_2;
}
 
/** Buddy system set_order implementation.
/** Buddy system set_order implementation
*
* @param buddy Buddy system.
* @param block Buddy system block.
* @param order Order to set.
*
* @param b Buddy system.
* @param block Buddy system block
* @param order Order to set
*/
static void zone_buddy_set_order(buddy_system_t *buddy, link_t *block,
uint8_t order)
{
list_get_instance(block, frame_t, buddy_link)->buddy_order = order;
static void zone_buddy_set_order(buddy_system_t *b, link_t * block, uint8_t order) {
frame_t * frame;
frame = list_get_instance(block, frame_t, buddy_link);
frame->buddy_order = order;
}
 
/** Buddy system get_order implementation.
/** Buddy system get_order implementation
*
* @param buddy Buddy system.
* @param block Buddy system block.
* @param b Buddy system.
* @param block Buddy system block
*
* @return Order of block.
*
* @return Order of block
*/
static uint8_t zone_buddy_get_order(buddy_system_t *buddy, link_t *block)
{
return list_get_instance(block, frame_t, buddy_link)->buddy_order;
static uint8_t zone_buddy_get_order(buddy_system_t *b, link_t * block) {
frame_t * frame;
frame = list_get_instance(block, frame_t, buddy_link);
return frame->buddy_order;
}
 
/** Buddy system mark_busy implementation.
/** Buddy system mark_busy implementation
*
* @param buddy Buddy system.
* @param block Buddy system block.
* @param b Buddy system
* @param block Buddy system block
*
*/
static void zone_buddy_mark_busy(buddy_system_t *buddy, link_t * block)
{
list_get_instance(block, frame_t, buddy_link)->refcount = 1;
static void zone_buddy_mark_busy(buddy_system_t *b, link_t * block) {
frame_t * frame;
 
frame = list_get_instance(block, frame_t, buddy_link);
frame->refcount = 1;
}
 
/** Buddy system mark_available implementation.
/** Buddy system mark_available implementation
*
* @param buddy Buddy system.
* @param block Buddy system block.
* @param b Buddy system
* @param block Buddy system block
*
*/
static void zone_buddy_mark_available(buddy_system_t *buddy, link_t *block)
{
list_get_instance(block, frame_t, buddy_link)->refcount = 0;
static void zone_buddy_mark_available(buddy_system_t *b, link_t * block) {
frame_t * frame;
frame = list_get_instance(block, frame_t, buddy_link);
frame->refcount = 0;
}
 
static buddy_system_operations_t zone_buddy_system_operations = {
400,7 → 434,8
.get_order = zone_buddy_get_order,
.mark_busy = zone_buddy_mark_busy,
.mark_available = zone_buddy_mark_available,
.find_block = zone_buddy_find_block
.find_block = zone_buddy_find_block,
.print_id = zone_buddy_print_id
};
 
/******************/
407,59 → 442,62
/* Zone functions */
/******************/
 
/** Allocate frame in particular zone.
/** Allocate frame in particular zone
*
* Assume zone is locked and is available for allocation.
* Assume zone is locked
* Panics if allocation is impossible.
*
* @param zone Zone to allocate from.
* @param order Allocate exactly 2^order frames.
*
* @return Frame index in zone.
* @return Frame index in zone
*
*/
static pfn_t zone_frame_alloc(zone_t *zone, uint8_t order)
{
ASSERT(zone_flags_available(zone->flags));
pfn_t v;
link_t *tmp;
frame_t *frame;
 
/* Allocate frames from zone buddy system */
link_t *link = buddy_system_alloc(zone->buddy_system, order);
tmp = buddy_system_alloc(zone->buddy_system, order);
ASSERT(link);
ASSERT(tmp);
/* Update zone information. */
zone->free_count -= (1 << order);
zone->busy_count += (1 << order);
 
/* Frame will be actually a first frame of the block. */
frame_t *frame = list_get_instance(link, frame_t, buddy_link);
frame = list_get_instance(tmp, frame_t, buddy_link);
/* Get frame address */
return make_frame_index(zone, frame);
/* get frame address */
v = make_frame_index(zone, frame);
return v;
}
 
/** Free frame from zone.
/** Free frame from zone
*
* Assume zone is locked and is available for deallocation.
* Assume zone is locked
*
* @param zone Pointer to zone from which the frame is to be freed.
* @param frame_idx Frame index relative to zone.
*
* @param zone Pointer to zone from which the frame is to be freed
* @param frame_idx Frame index relative to zone
*/
static void zone_frame_free(zone_t *zone, size_t frame_idx)
static void zone_frame_free(zone_t *zone, index_t frame_idx)
{
ASSERT(zone_flags_available(zone->flags));
frame_t *frame;
uint8_t order;
 
frame = &zone->frames[frame_idx];
frame_t *frame = &zone->frames[frame_idx];
/* Remember frame order */
uint8_t order = frame->buddy_order;
/* remember frame order */
order = frame->buddy_order;
 
ASSERT(frame->refcount);
 
if (!--frame->refcount) {
buddy_system_free(zone->buddy_system, &frame->buddy_link);
/* Update zone information. */
zone->free_count += (1 << order);
zone->busy_count -= (1 << order);
466,656 → 504,515
}
}
 
/** Return frame from zone. */
static frame_t *zone_get_frame(zone_t *zone, size_t frame_idx)
/** Return frame from zone */
static frame_t * zone_get_frame(zone_t *zone, index_t frame_idx)
{
ASSERT(frame_idx < zone->count);
return &zone->frames[frame_idx];
}
 
/** Mark frame in zone unavailable to allocation. */
static void zone_mark_unavailable(zone_t *zone, size_t frame_idx)
/** Mark frame in zone unavailable to allocation */
static void zone_mark_unavailable(zone_t *zone, index_t frame_idx)
{
ASSERT(zone_flags_available(zone->flags));
frame_t *frame = zone_get_frame(zone, frame_idx);
frame_t *frame;
link_t *link;
 
frame = zone_get_frame(zone, frame_idx);
if (frame->refcount)
return;
link_t *link __attribute__ ((unused));
link = buddy_system_alloc_block(zone->buddy_system,
&frame->buddy_link);
link = buddy_system_alloc_block(zone->buddy_system,
&frame->buddy_link);
ASSERT(link);
zone->free_count--;
}
 
/** Merge two zones.
/**
* Join 2 zones
*
* Expect buddy to point to space at least zone_conf_size large.
* Assume z1 & z2 are locked and compatible and zones lock is
* locked.
* Expect zone_t *z to point to space at least zone_conf_size large
*
* @param z1 First zone to merge.
* @param z2 Second zone to merge.
* @param old_z1 Original date of the first zone.
* @param buddy Merged zone buddy.
* Assume z1 & z2 are locked
*
* @param z Target zone structure pointer
* @param z1 Zone to merge
* @param z2 Zone to merge
*/
static void zone_merge_internal(size_t z1, size_t z2, zone_t *old_z1, buddy_system_t *buddy)
static void _zone_merge(zone_t *z, zone_t *z1, zone_t *z2)
{
ASSERT(zone_flags_available(zones.info[z1].flags));
ASSERT(zone_flags_available(zones.info[z2].flags));
ASSERT(zones.info[z1].flags == zones.info[z2].flags);
ASSERT(zones.info[z1].base < zones.info[z2].base);
ASSERT(!overlaps(zones.info[z1].base, zones.info[z1].count,
zones.info[z2].base, zones.info[z2].count));
uint8_t max_order;
unsigned int i;
int z2idx;
pfn_t frame_idx;
frame_t *frame;
 
ASSERT(!overlaps(z1->base,z1->count,z2->base,z2->count));
ASSERT(z1->base < z2->base);
 
spinlock_initialize(&z->lock, "zone_lock");
z->base = z1->base;
z->count = z2->base+z2->count - z1->base;
z->flags = z1->flags & z2->flags;
 
z->free_count = z1->free_count + z2->free_count;
z->busy_count = z1->busy_count + z2->busy_count;
/* Difference between zone bases */
pfn_t base_diff = zones.info[z2].base - zones.info[z1].base;
zones.info[z1].count = base_diff + zones.info[z2].count;
zones.info[z1].free_count += zones.info[z2].free_count;
zones.info[z1].busy_count += zones.info[z2].busy_count;
zones.info[z1].buddy_system = buddy;
uint8_t order = fnzb(zones.info[z1].count);
buddy_system_create(zones.info[z1].buddy_system, order,
&zone_buddy_system_operations, (void *) &zones.info[z1]);
zones.info[z1].frames =
(frame_t *) ((uint8_t *) zones.info[z1].buddy_system
+ buddy_conf_size(order));
/* This marks all frames busy */
size_t i;
for (i = 0; i < zones.info[z1].count; i++)
frame_initialize(&zones.info[z1].frames[i]);
max_order = fnzb(z->count);
 
z->buddy_system = (buddy_system_t *)&z[1];
buddy_system_create(z->buddy_system, max_order,
&zone_buddy_system_operations,
(void *) z);
 
z->frames = (frame_t *)((uint8_t *) z->buddy_system + buddy_conf_size(max_order));
for (i = 0; i < z->count; i++) {
/* This marks all frames busy */
frame_initialize(&z->frames[i]);
}
/* Copy frames from both zones to preserve full frame orders,
* parents etc. Set all free frames with refcount = 0 to 1, because
* we add all free frames to buddy allocator later again, clearing
* order to 0. Don't set busy frames with refcount = 0, as they
* parents etc. Set all free frames with refcount=0 to 1, because
* we add all free frames to buddy allocator later again, clear
* order to 0. Don't set busy frames with refcount=0, as they
* will not be reallocated during merge and it would make later
* problems with allocation/free.
*/
for (i = 0; i < old_z1->count; i++)
zones.info[z1].frames[i] = old_z1->frames[i];
for (i = 0; i < zones.info[z2].count; i++)
zones.info[z1].frames[base_diff + i]
= zones.info[z2].frames[i];
for (i = 0; i < z1->count; i++)
z->frames[i] = z1->frames[i];
for (i = 0; i < z2->count; i++) {
z2idx = i + (z2->base - z1->base);
z->frames[z2idx] = z2->frames[i];
}
i = 0;
while (i < zones.info[z1].count) {
if (zones.info[z1].frames[i].refcount) {
/* Skip busy frames */
i += 1 << zones.info[z1].frames[i].buddy_order;
} else {
/* Free frames, set refcount = 1
* (all free frames have refcount == 0, we need not
* to check the order)
*/
zones.info[z1].frames[i].refcount = 1;
zones.info[z1].frames[i].buddy_order = 0;
while (i < z->count) {
if (z->frames[i].refcount) {
/* skip busy frames */
i += 1 << z->frames[i].buddy_order;
} else { /* Free frames, set refcount=1 */
/* All free frames have refcount=0, we need not
* to check the order */
z->frames[i].refcount = 1;
z->frames[i].buddy_order = 0;
i++;
}
}
/* Add free blocks from the original zone z1 */
while (zone_can_alloc(old_z1, 0)) {
/* Allocate from the original zone */
pfn_t frame_idx = zone_frame_alloc(old_z1, 0);
/* Free the frame from the merged zone */
frame_t *frame = &zones.info[z1].frames[frame_idx];
/* Add free blocks from the 2 original zones */
while (zone_can_alloc(z1, 0)) {
frame_idx = zone_frame_alloc(z1, 0);
frame = &z->frames[frame_idx];
frame->refcount = 0;
buddy_system_free(zones.info[z1].buddy_system, &frame->buddy_link);
buddy_system_free(z->buddy_system, &frame->buddy_link);
}
/* Add free blocks from the original zone z2 */
while (zone_can_alloc(&zones.info[z2], 0)) {
/* Allocate from the original zone */
pfn_t frame_idx = zone_frame_alloc(&zones.info[z2], 0);
/* Free the frame from the merged zone */
frame_t *frame = &zones.info[z1].frames[base_diff + frame_idx];
while (zone_can_alloc(z2, 0)) {
frame_idx = zone_frame_alloc(z2, 0);
frame = &z->frames[frame_idx + (z2->base-z1->base)];
frame->refcount = 0;
buddy_system_free(zones.info[z1].buddy_system, &frame->buddy_link);
buddy_system_free(z->buddy_system, &frame->buddy_link);
}
}
 
/** Return old configuration frames into the zone.
/** Return old configuration frames into the zone
*
* We have two cases:
* - The configuration data is outside the zone
* -> do nothing (perhaps call frame_free?)
* - The configuration data was created by zone_create
* or updated by reduce_region -> free every frame
* We have several cases
* - the conf. data is outside of zone -> exit, shall we call frame_free??
* - the conf. data was created by zone_create or
* updated with reduce_region -> free every frame
*
* @param znum The actual zone where freeing should occur.
* @param pfn Old zone configuration frame.
* @param count Old zone frame count.
*
* @param newzone The actual zone where freeing should occur
* @param oldzone Pointer to old zone configuration data that should
* be freed from new zone
*/
static void return_config_frames(size_t znum, pfn_t pfn, size_t count)
static void return_config_frames(zone_t *newzone, zone_t *oldzone)
{
ASSERT(zone_flags_available(zones.info[znum].flags));
pfn_t pfn;
frame_t *frame;
count_t cframes;
unsigned int i;
 
pfn = ADDR2PFN((uintptr_t)KA2PA(oldzone));
cframes = SIZE2FRAMES(zone_conf_size(oldzone->count));
size_t cframes = SIZE2FRAMES(zone_conf_size(count));
if ((pfn < zones.info[znum].base)
|| (pfn >= zones.info[znum].base + zones.info[znum].count))
if (pfn < newzone->base || pfn >= newzone->base + newzone->count)
return;
frame_t *frame __attribute__ ((unused));
 
frame = &zones.info[znum].frames[pfn - zones.info[znum].base];
frame = &newzone->frames[pfn - newzone->base];
ASSERT(!frame->buddy_order);
size_t i;
 
for (i = 0; i < cframes; i++) {
zones.info[znum].busy_count++;
zone_frame_free(&zones.info[znum],
pfn - zones.info[znum].base + i);
newzone->busy_count++;
zone_frame_free(newzone, pfn+i-newzone->base);
}
}
 
/** Reduce allocated block to count of order 0 frames.
/** Reduce allocated block to count of order 0 frames
*
* The allocated block needs 2^order frames. Reduce all frames
* in the block to order 0 and free the unneeded frames. This means that
* when freeing the previously allocated block starting with frame_idx,
* The allocated block need 2^order frames of space. Reduce all frames
* in block to order 0 and free the unneeded frames. This means, that
* when freeing the previously allocated block starting with frame_idx,
* you have to free every frame.
*
* @param znum Zone.
* @param frame_idx Index the first frame of the block.
* @param count Allocated frames in block.
*
* @param zone
* @param frame_idx Index to block
* @param count Allocated space in block
*/
static void zone_reduce_region(size_t znum, pfn_t frame_idx, size_t count)
static void zone_reduce_region(zone_t *zone, pfn_t frame_idx, count_t count)
{
ASSERT(zone_flags_available(zones.info[znum].flags));
ASSERT(frame_idx + count < zones.info[znum].count);
count_t i;
uint8_t order;
frame_t *frame;
uint8_t order = zones.info[znum].frames[frame_idx].buddy_order;
ASSERT((size_t) (1 << order) >= count);
ASSERT(frame_idx + count < zone->count);
 
order = zone->frames[frame_idx].buddy_order;
ASSERT((count_t) (1 << order) >= count);
 
/* Reduce all blocks to order 0 */
size_t i;
for (i = 0; i < (size_t) (1 << order); i++) {
frame_t *frame = &zones.info[znum].frames[i + frame_idx];
for (i = 0; i < (count_t) (1 << order); i++) {
frame = &zone->frames[i + frame_idx];
frame->buddy_order = 0;
if (!frame->refcount)
if (! frame->refcount)
frame->refcount = 1;
ASSERT(frame->refcount == 1);
}
/* Free unneeded frames */
for (i = count; i < (size_t) (1 << order); i++)
zone_frame_free(&zones.info[znum], i + frame_idx);
for (i = count; i < (count_t) (1 << order); i++) {
zone_frame_free(zone, i + frame_idx);
}
}
 
/** Merge zones z1 and z2.
/** Merge zones z1 and z2
*
* The merged zones must be 2 zones with no zone existing in between
* (which means that z2 = z1 + 1). Both zones must be available zones
* with the same flags.
* - the zones must be 2 zones with no zone existing in between,
* which means that z2 = z1+1
*
* When you create a new zone, the frame allocator configuration does
* not to be 2^order size. Once the allocator is running it is no longer
* possible, merged configuration data occupies more space :-/
*
* The function uses
*
* - When you create a new zone, the frame allocator configuration does
* not to be 2^order size. Once the allocator is running it is no longer
* possible, merged configuration data occupies more space :-/
*/
bool zone_merge(size_t z1, size_t z2)
void zone_merge(unsigned int z1, unsigned int z2)
{
ipl_t ipl = interrupts_disable();
ipl_t ipl;
zone_t *zone1, *zone2, *newzone;
unsigned int cframes;
uint8_t order;
unsigned int i;
pfn_t pfn;
 
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
bool ret = true;
/* We can join only 2 zones with none existing inbetween,
* the zones have to be available and with the same
* set of flags
*/
if ((z1 >= zones.count) || (z2 >= zones.count)
|| (z2 - z1 != 1)
|| (!zone_flags_available(zones.info[z1].flags))
|| (!zone_flags_available(zones.info[z2].flags))
|| (zones.info[z1].flags != zones.info[z2].flags)) {
ret = false;
 
if (z1 < 0 || z1 >= zones.count || z2 < 0 || z2 >= zones.count)
goto errout;
}
pfn_t cframes = SIZE2FRAMES(zone_conf_size(
zones.info[z2].base - zones.info[z1].base
+ zones.info[z2].count));
uint8_t order;
/* We can join only 2 zones with none existing inbetween */
if (z2-z1 != 1)
goto errout;
 
zone1 = zones.info[z1];
zone2 = zones.info[z2];
spinlock_lock(&zone1->lock);
spinlock_lock(&zone2->lock);
 
cframes = SIZE2FRAMES(zone_conf_size(zone2->base+zone2->count-zone1->base));
if (cframes == 1)
order = 0;
else
order = fnzb(cframes - 1) + 1;
 
/* Allocate zonedata inside one of the zones */
if (zone_can_alloc(zone1, order))
pfn = zone1->base + zone_frame_alloc(zone1, order);
else if (zone_can_alloc(zone2, order))
pfn = zone2->base + zone_frame_alloc(zone2, order);
else
order = fnzb(cframes - 1) + 1;
/* Allocate merged zone data inside one of the zones */
pfn_t pfn;
if (zone_can_alloc(&zones.info[z1], order)) {
pfn = zones.info[z1].base + zone_frame_alloc(&zones.info[z1], order);
} else if (zone_can_alloc(&zones.info[z2], order)) {
pfn = zones.info[z2].base + zone_frame_alloc(&zones.info[z2], order);
} else {
ret = false;
goto errout;
}
/* Preserve original data from z1 */
zone_t old_z1 = zones.info[z1];
old_z1.buddy_system->data = (void *) &old_z1;
/* Do zone merging */
buddy_system_t *buddy = (buddy_system_t *) PA2KA(PFN2ADDR(pfn));
zone_merge_internal(z1, z2, &old_z1, buddy);
goto errout2;
 
newzone = (zone_t *) PA2KA(PFN2ADDR(pfn));
 
_zone_merge(newzone, zone1, zone2);
 
/* Free unneeded config frames */
zone_reduce_region(z1, pfn - zones.info[z1].base, cframes);
zone_reduce_region(newzone, pfn - newzone->base, cframes);
/* Subtract zone information from busy frames */
zones.info[z1].busy_count -= cframes;
/* Free old zone information */
return_config_frames(z1,
ADDR2PFN(KA2PA((uintptr_t) old_z1.frames)), old_z1.count);
return_config_frames(z1,
ADDR2PFN(KA2PA((uintptr_t) zones.info[z2].frames)),
zones.info[z2].count);
/* Move zones down */
size_t i;
for (i = z2 + 1; i < zones.count; i++) {
newzone->busy_count -= cframes;
 
/* Replace existing zones in zoneinfo list */
zones.info[z1] = newzone;
for (i = z2 + 1; i < zones.count; i++)
zones.info[i - 1] = zones.info[i];
zones.info[i - 1].buddy_system->data =
(void *) &zones.info[i - 1];
}
zones.count--;
 
/* Free old zone information */
return_config_frames(newzone, zone1);
return_config_frames(newzone, zone2);
errout2:
/* Nobody is allowed to enter to zone, so we are safe
* to touch the spinlocks last time */
spinlock_unlock(&zone1->lock);
spinlock_unlock(&zone2->lock);
errout:
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return ret;
}
 
/** Merge all mergeable zones into one big zone.
/**
* Merge all zones into one big zone
*
* It is reasonable to do this on systems where
* BIOS reports parts in chunks, so that we could
* have 1 zone (it's faster).
*
* It is reasonable to do this on systems whose bios reports parts in chunks,
* so that we could have 1 zone (it's faster).
*/
void zone_merge_all(void)
{
size_t i = 0;
while (i < zones.count) {
if (!zone_merge(i, i + 1))
i++;
int count = zones.count;
 
while (zones.count > 1 && --count) {
zone_merge(0,1);
break;
}
}
 
/** Create new frame zone.
/** Create frame zone
*
* @param zone Zone to construct.
* @param buddy Address of buddy system configuration information.
* Create new frame zone.
*
* @param start Physical address of the first frame within the zone.
* @param count Count of frames in zone.
* @param count Count of frames in zone
* @param z Address of configuration information of zone
* @param flags Zone flags.
*
* @return Initialized zone.
*
*/
static void zone_construct(zone_t *zone, buddy_system_t *buddy, pfn_t start, size_t count, zone_flags_t flags)
static void zone_construct(pfn_t start, count_t count, zone_t *z, int flags)
{
zone->base = start;
zone->count = count;
zone->flags = flags;
zone->free_count = count;
zone->busy_count = 0;
zone->buddy_system = buddy;
unsigned int i;
uint8_t max_order;
 
spinlock_initialize(&z->lock, "zone_lock");
z->base = start;
z->count = count;
z->flags = flags;
z->free_count = count;
z->busy_count = 0;
 
/*
* Compute order for buddy system, initialize
*/
max_order = fnzb(count);
z->buddy_system = (buddy_system_t *)&z[1];
if (zone_flags_available(flags)) {
/*
* Compute order for buddy system and initialize
*/
uint8_t order = fnzb(count);
buddy_system_create(zone->buddy_system, order,
&zone_buddy_system_operations, (void *) zone);
/* Allocate frames _after_ the confframe */
/* Check sizes */
zone->frames = (frame_t *) ((uint8_t *) zone->buddy_system +
buddy_conf_size(order));
size_t i;
for (i = 0; i < count; i++)
frame_initialize(&zone->frames[i]);
/* Stuffing frames */
for (i = 0; i < count; i++) {
zone->frames[i].refcount = 0;
buddy_system_free(zone->buddy_system, &zone->frames[i].buddy_link);
}
} else
zone->frames = NULL;
buddy_system_create(z->buddy_system, max_order,
&zone_buddy_system_operations,
(void *) z);
/* Allocate frames _after_ the conframe */
/* Check sizes */
z->frames = (frame_t *)((uint8_t *) z->buddy_system + buddy_conf_size(max_order));
for (i = 0; i < count; i++) {
frame_initialize(&z->frames[i]);
}
/* Stuffing frames */
for (i = 0; i < count; i++) {
z->frames[i].refcount = 0;
buddy_system_free(z->buddy_system, &z->frames[i].buddy_link);
}
}
 
/** Compute configuration data size for zone.
/** Compute configuration data size for zone
*
* @param count Size of zone in frames.
*
* @return Size of zone configuration info (in bytes).
*
* @param count Size of zone in frames
* @return Size of zone configuration info (in bytes)
*/
uintptr_t zone_conf_size(size_t count)
uintptr_t zone_conf_size(count_t count)
{
return (count * sizeof(frame_t) + buddy_conf_size(fnzb(count)));
int size = sizeof(zone_t) + count*sizeof(frame_t);
int max_order;
 
max_order = fnzb(count);
size += buddy_conf_size(max_order);
return size;
}
 
/** Create and add zone to system.
/** Create and add zone to system
*
* @param start First frame number (absolute).
* @param count Size of zone in frames.
* @param start First frame number (absolute)
* @param count Size of zone in frames
* @param confframe Where configuration frames are supposed to be.
* Automatically checks, that we will not disturb the
* kernel and possibly init. If confframe is given
* _outside_ this zone, it is expected, that the area is
* already marked BUSY and big enough to contain
* zone_conf_size() amount of data. If the confframe is
* inside the area, the zone free frame information is
* modified not to include it.
* Automatically checks, that we will not disturb the
* kernel and possibly init.
* If confframe is given _outside_ this zone, it is expected,
* that the area is already marked BUSY and big enough
* to contain zone_conf_size() amount of data.
* If the confframe is inside the area, the zone free frame
* information is modified not to include it.
*
* @return Zone number or -1 on error.
*
* @return Zone number or -1 on error
*/
size_t zone_create(pfn_t start, size_t count, pfn_t confframe, zone_flags_t flags)
int zone_create(pfn_t start, count_t count, pfn_t confframe, int flags)
{
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
if (zone_flags_available(flags)) { /* Create available zone */
/* Theoretically we could have NULL here, practically make sure
* nobody tries to do that. If some platform requires, remove
* the assert
*/
ASSERT(confframe != NULL);
/* If confframe is supposed to be inside our zone, then make sure
* it does not span kernel & init
*/
size_t confcount = SIZE2FRAMES(zone_conf_size(count));
if ((confframe >= start) && (confframe < start + count)) {
for (; confframe < start + count; confframe++) {
uintptr_t addr = PFN2ADDR(confframe);
if (overlaps(addr, PFN2ADDR(confcount),
KA2PA(config.base), config.kernel_size))
continue;
if (overlaps(addr, PFN2ADDR(confcount),
KA2PA(config.stack_base), config.stack_size))
continue;
bool overlap = false;
size_t i;
for (i = 0; i < init.cnt; i++)
if (overlaps(addr, PFN2ADDR(confcount),
KA2PA(init.tasks[i].addr),
init.tasks[i].size)) {
overlap = true;
break;
}
if (overlap)
continue;
break;
}
zone_t *z;
uintptr_t addr;
count_t confcount;
unsigned int i;
int znum;
 
/* Theoretically we could have here 0, practically make sure
* nobody tries to do that. If some platform requires, remove
* the assert
*/
ASSERT(confframe);
/* If conframe is supposed to be inside our zone, then make sure
* it does not span kernel & init
*/
confcount = SIZE2FRAMES(zone_conf_size(count));
if (confframe >= start && confframe < start+count) {
for (;confframe < start + count; confframe++) {
addr = PFN2ADDR(confframe);
if (overlaps(addr, PFN2ADDR(confcount), KA2PA(config.base), config.kernel_size))
continue;
if (confframe >= start + count)
panic("Cannot find configuration data for zone.");
if (overlaps(addr, PFN2ADDR(confcount), KA2PA(config.stack_base), config.stack_size))
continue;
bool overlap = false;
count_t i;
for (i = 0; i < init.cnt; i++)
if (overlaps(addr, PFN2ADDR(confcount), KA2PA(init.tasks[i].addr), init.tasks[i].size)) {
overlap = true;
break;
}
if (overlap)
continue;
break;
}
size_t znum = zones_insert_zone(start, count);
if (znum == (size_t) -1) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return (size_t) -1;
if (confframe >= start + count)
panic("Cannot find configuration data for zone.");
}
 
z = (zone_t *)PA2KA(PFN2ADDR(confframe));
zone_construct(start, count, z, flags);
znum = zones_add_zone(z);
if (znum == -1)
return -1;
 
/* If confdata in zone, mark as unavailable */
if (confframe >= start && confframe < start + count)
for (i = confframe; i < confframe + confcount; i++) {
zone_mark_unavailable(z, i - z->base);
}
buddy_system_t *buddy = (buddy_system_t *) PA2KA(PFN2ADDR(confframe));
zone_construct(&zones.info[znum], buddy, start, count, flags);
/* If confdata in zone, mark as unavailable */
if ((confframe >= start) && (confframe < start + count)) {
size_t i;
for (i = confframe; i < confframe + confcount; i++)
zone_mark_unavailable(&zones.info[znum],
i - zones.info[znum].base);
}
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return znum;
}
/* Non-available zone */
size_t znum = zones_insert_zone(start, count);
if (znum == (size_t) -1) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return (size_t) -1;
}
zone_construct(&zones.info[znum], NULL, start, count, flags);
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return znum;
}
 
/*******************/
/***************************************/
/* Frame functions */
/*******************/
 
/** Set parent of frame. */
void frame_set_parent(pfn_t pfn, void *data, size_t hint)
/** Set parent of frame */
void frame_set_parent(pfn_t pfn, void *data, unsigned int hint)
{
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
size_t znum = find_zone(pfn, 1, hint);
ASSERT(znum != (size_t) -1);
zone_get_frame(&zones.info[znum],
pfn - zones.info[znum].base)->parent = data;
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
zone_t *zone = find_zone_and_lock(pfn, &hint);
 
ASSERT(zone);
 
zone_get_frame(zone, pfn-zone->base)->parent = data;
spinlock_unlock(&zone->lock);
}
 
void *frame_get_parent(pfn_t pfn, size_t hint)
void * frame_get_parent(pfn_t pfn, unsigned int hint)
{
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
zone_t *zone = find_zone_and_lock(pfn, &hint);
void *res;
 
ASSERT(zone);
res = zone_get_frame(zone, pfn - zone->base)->parent;
size_t znum = find_zone(pfn, 1, hint);
ASSERT(znum != (size_t) -1);
void *res = zone_get_frame(&zones.info[znum],
pfn - zones.info[znum].base)->parent;
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
spinlock_unlock(&zone->lock);
return res;
}
 
/** Allocate power-of-two frames of physical memory.
*
* @param order Allocate exactly 2^order frames.
* @param flags Flags for host zone selection and address processing.
* @param pzone Preferred zone.
* @param order Allocate exactly 2^order frames.
* @param flags Flags for host zone selection and address processing.
* @param pzone Preferred zone
*
* @return Physical address of the allocated frame.
*
*/
void *frame_alloc_generic(uint8_t order, frame_flags_t flags, size_t *pzone)
void * frame_alloc_generic(uint8_t order, int flags, unsigned int *pzone)
{
size_t size = ((size_t) 1) << order;
ipl_t ipl;
size_t hint = pzone ? (*pzone) : 0;
int freed;
pfn_t v;
zone_t *zone;
loop:
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
/*
* First, find suitable frame zone.
*/
size_t znum = find_free_zone(order,
FRAME_TO_ZONE_FLAGS(flags), hint);
zone = find_free_zone_and_lock(order, pzone);
/* If no memory, reclaim some slab memory,
if it does not help, reclaim all */
if ((znum == (size_t) -1) && (!(flags & FRAME_NO_RECLAIM))) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
size_t freed = slab_reclaim(0);
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
if (freed > 0)
znum = find_free_zone(order,
FRAME_TO_ZONE_FLAGS(flags), hint);
if (znum == (size_t) -1) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
if (!zone && !(flags & FRAME_NO_RECLAIM)) {
freed = slab_reclaim(0);
if (freed)
zone = find_free_zone_and_lock(order, pzone);
if (!zone) {
freed = slab_reclaim(SLAB_RECLAIM_ALL);
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
if (freed > 0)
znum = find_free_zone(order,
FRAME_TO_ZONE_FLAGS(flags), hint);
if (freed)
zone = find_free_zone_and_lock(order, pzone);
}
}
if (znum == (size_t) -1) {
if (flags & FRAME_ATOMIC) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return NULL;
}
#ifdef CONFIG_DEBUG
size_t avail = total_frames_free();
#endif
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
if (!zone) {
/*
* Sleep until some frames are available again.
* TODO: Sleep until frames are available again.
*/
interrupts_restore(ipl);
 
if (flags & FRAME_ATOMIC)
return 0;
#ifdef CONFIG_DEBUG
printf("Thread %" PRIu64 " waiting for %" PRIs " frames, "
"%" PRIs " available.\n", THREAD->tid, size, avail);
#endif
mutex_lock(&mem_avail_mtx);
if (mem_avail_req > 0)
mem_avail_req = min(mem_avail_req, size);
else
mem_avail_req = size;
size_t gen = mem_avail_gen;
while (gen == mem_avail_gen)
condvar_wait(&mem_avail_cv, &mem_avail_mtx);
mutex_unlock(&mem_avail_mtx);
#ifdef CONFIG_DEBUG
printf("Thread %" PRIu64 " woken up.\n", THREAD->tid);
#endif
panic("Sleep not implemented.\n");
goto loop;
}
pfn_t pfn = zone_frame_alloc(&zones.info[znum], order)
+ zones.info[znum].base;
spinlock_unlock(&zones.lock);
v = zone_frame_alloc(zone, order);
v += zone->base;
 
spinlock_unlock(&zone->lock);
interrupts_restore(ipl);
if (pzone)
*pzone = znum;
 
if (flags & FRAME_KA)
return (void *) PA2KA(PFN2ADDR(pfn));
return (void *) PFN2ADDR(pfn);
return (void *)PA2KA(PFN2ADDR(v));
return (void *)PFN2ADDR(v);
}
 
/** Free a frame.
*
* Find respective frame structure for supplied physical frame address.
* Decrement frame reference count. If it drops to zero, move the frame
* structure to free list.
* Decrement frame reference count.
* If it drops to zero, move the frame structure to free list.
*
* @param frame Physical Address of of the frame to be freed.
*
* @param Frame Physical Address of of the frame to be freed.
*/
void frame_free(uintptr_t frame)
{
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
ipl_t ipl;
zone_t *zone;
pfn_t pfn = ADDR2PFN(frame);
 
ipl = interrupts_disable();
/*
* First, find host frame zone for addr.
*/
pfn_t pfn = ADDR2PFN(frame);
size_t znum = find_zone(pfn, 1, NULL);
zone = find_zone_and_lock(pfn,NULL);
ASSERT(zone);
ASSERT(znum != (size_t) -1);
zone_frame_free(zone, pfn-zone->base);
zone_frame_free(&zones.info[znum], pfn - zones.info[znum].base);
spinlock_unlock(&zones.lock);
spinlock_unlock(&zone->lock);
interrupts_restore(ipl);
/*
* Signal that some memory has been freed.
*/
mutex_lock(&mem_avail_mtx);
if (mem_avail_req > 0)
mem_avail_req--;
if (mem_avail_req == 0) {
mem_avail_gen++;
condvar_broadcast(&mem_avail_cv);
}
mutex_unlock(&mem_avail_mtx);
}
 
/** Add reference to frame.
1124,220 → 1021,133
* increment frame reference count.
*
* @param pfn Frame number of the frame to be freed.
*
*/
void frame_reference_add(pfn_t pfn)
{
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
ipl_t ipl;
zone_t *zone;
frame_t *frame;
 
ipl = interrupts_disable();
/*
* First, find host frame zone for addr.
*/
size_t znum = find_zone(pfn, 1, NULL);
zone = find_zone_and_lock(pfn,NULL);
ASSERT(zone);
ASSERT(znum != (size_t) -1);
frame = &zone->frames[pfn-zone->base];
frame->refcount++;
zones.info[znum].frames[pfn - zones.info[znum].base].refcount++;
spinlock_unlock(&zones.lock);
spinlock_unlock(&zone->lock);
interrupts_restore(ipl);
}
 
/** Mark given range unavailable in frame zones. */
void frame_mark_unavailable(pfn_t start, size_t count)
/** Mark given range unavailable in frame zones */
void frame_mark_unavailable(pfn_t start, count_t count)
{
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
unsigned int i;
zone_t *zone;
unsigned int prefzone = 0;
size_t i;
for (i = 0; i < count; i++) {
size_t znum = find_zone(start + i, 1, 0);
if (znum == (size_t) -1) /* PFN not found */
zone = find_zone_and_lock(start + i, &prefzone);
if (!zone) /* PFN not found */
continue;
zone_mark_unavailable(&zones.info[znum],
start + i - zones.info[znum].base);
zone_mark_unavailable(zone, start + i - zone->base);
 
spinlock_unlock(&zone->lock);
}
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
}
 
/** Initialize physical memory management. */
/** Initialize physical memory management
*
* Initialize physical memory managemnt.
*/
void frame_init(void)
{
if (config.cpu_active == 1) {
zones.count = 0;
spinlock_initialize(&zones.lock, "zones.lock");
mutex_initialize(&mem_avail_mtx, MUTEX_ACTIVE);
condvar_initialize(&mem_avail_cv);
}
/* Tell the architecture to create some memory */
frame_arch_init();
if (config.cpu_active == 1) {
frame_mark_unavailable(ADDR2PFN(KA2PA(config.base)),
SIZE2FRAMES(config.kernel_size));
frame_mark_unavailable(ADDR2PFN(KA2PA(config.stack_base)),
SIZE2FRAMES(config.stack_size));
frame_mark_unavailable(ADDR2PFN(KA2PA(config.base)), SIZE2FRAMES(config.kernel_size));
frame_mark_unavailable(ADDR2PFN(KA2PA(config.stack_base)), SIZE2FRAMES(config.stack_size));
size_t i;
for (i = 0; i < init.cnt; i++) {
pfn_t pfn = ADDR2PFN(KA2PA(init.tasks[i].addr));
frame_mark_unavailable(pfn,
SIZE2FRAMES(init.tasks[i].size));
}
count_t i;
for (i = 0; i < init.cnt; i++)
frame_mark_unavailable(ADDR2PFN(KA2PA(init.tasks[i].addr)), SIZE2FRAMES(init.tasks[i].size));
 
if (ballocs.size)
frame_mark_unavailable(ADDR2PFN(KA2PA(ballocs.base)),
SIZE2FRAMES(ballocs.size));
frame_mark_unavailable(ADDR2PFN(KA2PA(ballocs.base)), SIZE2FRAMES(ballocs.size));
 
/* Black list first frame, as allocating NULL would
* fail in some places
*/
* fail in some places */
frame_mark_unavailable(0, 1);
}
}
 
/** Return total size of all zones. */
uint64_t zone_total_size(void)
{
ipl_t ipl = interrupts_disable();
 
 
/** Prints list of zones
*
*/
void zone_print_list(void) {
zone_t *zone = NULL;
unsigned int i;
ipl_t ipl;
 
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
uint64_t total = 0;
size_t i;
for (i = 0; i < zones.count; i++)
total += (uint64_t) FRAMES2SIZE(zones.info[i].count);
printf("# base address free frames busy frames\n");
printf("-- ------------ ------------ ------------\n");
for (i = 0; i < zones.count; i++) {
zone = zones.info[i];
spinlock_lock(&zone->lock);
printf("%-2d %12p %12zd %12zd\n", i, PFN2ADDR(zone->base), zone->free_count, zone->busy_count);
spinlock_unlock(&zone->lock);
}
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return total;
}
 
/** Prints list of zones. */
void zone_print_list(void)
{
#ifdef __32_BITS__
printf("# base address frames flags free frames busy frames\n");
printf("-- ------------ ------------ -------- ------------ ------------\n");
#endif
 
#ifdef __64_BITS__
printf("# base address frames flags free frames busy frames\n");
printf("-- -------------------- ------------ -------- ------------ ------------\n");
#endif
/*
* Because printing may require allocation of memory, we may not hold
* the frame allocator locks when printing zone statistics. Therefore,
* we simply gather the statistics under the protection of the locks and
* print the statistics when the locks have been released.
*
* When someone adds/removes zones while we are printing the statistics,
* we may end up with inaccurate output (e.g. a zone being skipped from
* the listing).
*/
size_t i;
for (i = 0;; i++) {
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
if (i >= zones.count) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
break;
}
uintptr_t base = PFN2ADDR(zones.info[i].base);
size_t count = zones.info[i].count;
zone_flags_t flags = zones.info[i].flags;
size_t free_count = zones.info[i].free_count;
size_t busy_count = zones.info[i].busy_count;
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
bool available = zone_flags_available(flags);
printf("%-2" PRIs, i);
#ifdef __32_BITS__
printf(" %10p", base);
#endif
#ifdef __64_BITS__
printf(" %18p", base);
#endif
printf(" %12" PRIs " %c%c%c ", count,
available ? 'A' : ' ',
(flags & ZONE_RESERVED) ? 'R' : ' ',
(flags & ZONE_FIRMWARE) ? 'F' : ' ');
if (available)
printf("%12" PRIs " %12" PRIs,
free_count, busy_count);
printf("\n");
}
}
 
/** Prints zone details.
*
* @param num Zone base address or zone number.
*
*/
void zone_print_one(size_t num)
{
ipl_t ipl = interrupts_disable();
void zone_print_one(unsigned int num) {
zone_t *zone = NULL;
ipl_t ipl;
unsigned int i;
 
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
size_t znum = (size_t) -1;
size_t i;
 
for (i = 0; i < zones.count; i++) {
if ((i == num) || (PFN2ADDR(zones.info[i].base) == num)) {
znum = i;
if (i == num || PFN2ADDR(zones.info[i]->base) == num) {
zone = zones.info[i];
break;
}
}
if (znum == (size_t) -1) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
if (!zone) {
printf("Zone not found.\n");
return;
goto out;
}
uintptr_t base = PFN2ADDR(zones.info[i].base);
zone_flags_t flags = zones.info[i].flags;
size_t count = zones.info[i].count;
size_t free_count = zones.info[i].free_count;
size_t busy_count = zones.info[i].busy_count;
spinlock_lock(&zone->lock);
printf("Memory zone information\n");
printf("Zone base address: %#.*p\n", sizeof(uintptr_t) * 2, PFN2ADDR(zone->base));
printf("Zone size: %zd frames (%zdK)\n", zone->count, ((zone->count) * FRAME_SIZE) >> 10);
printf("Allocated space: %zd frames (%zdK)\n", zone->busy_count, (zone->busy_count * FRAME_SIZE) >> 10);
printf("Available space: %zd frames (%zdK)\n", zone->free_count, (zone->free_count * FRAME_SIZE) >> 10);
buddy_system_structure_print(zone->buddy_system, FRAME_SIZE);
spinlock_unlock(&zone->lock);
out:
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
bool available = zone_flags_available(flags);
printf("Zone number: %" PRIs "\n", znum);
printf("Zone base address: %p\n", base);
printf("Zone size: %" PRIs " frames (%" PRIs " KiB)\n", count,
SIZE2KB(FRAMES2SIZE(count)));
printf("Zone flags: %c%c%c\n",
available ? 'A' : ' ',
(flags & ZONE_RESERVED) ? 'R' : ' ',
(flags & ZONE_FIRMWARE) ? 'F' : ' ');
if (available) {
printf("Allocated space: %" PRIs " frames (%" PRIs " KiB)\n",
busy_count, SIZE2KB(FRAMES2SIZE(busy_count)));
printf("Available space: %" PRIs " frames (%" PRIs " KiB)\n",
free_count, SIZE2KB(FRAMES2SIZE(free_count)));
}
}
 
/** @}
/branches/arm/kernel/generic/src/mm/as.c
57,7 → 57,6
#include <genarch/mm/page_ht.h>
#include <mm/asid.h>
#include <arch/mm/asid.h>
#include <preemption.h>
#include <synch/spinlock.h>
#include <synch/mutex.h>
#include <adt/list.h>
82,6 → 81,7
#include <arch/mm/cache.h>
#endif /* CONFIG_VIRT_IDX_DCACHE */
 
#ifndef __OBJC__
/**
* Each architecture decides what functions will be used to carry out
* address space operations such as creating or locking page tables.
92,15 → 92,13
* Slab for as_t objects.
*/
static slab_cache_t *as_slab;
#endif
 
/**
* This lock serializes access to the ASID subsystem.
* It protects:
* - inactive_as_with_asid_head list
* - as->asid for each as of the as_t type
* - asids_allocated counter
* This lock protects inactive_as_with_asid_head list. It must be acquired
* before as_t mutex.
*/
SPINLOCK_INITIALIZE(asidlock);
SPINLOCK_INITIALIZE(inactive_as_with_asid_lock);
 
/**
* This list contains address spaces that are not active on any
111,11 → 109,13
/** Kernel address space. */
as_t *AS_KERNEL = NULL;
 
static int area_flags_to_page_flags(int);
static as_area_t *find_area_and_lock(as_t *, uintptr_t);
static bool check_area_conflicts(as_t *, uintptr_t, size_t, as_area_t *);
static void sh_info_remove_reference(share_info_t *);
static int area_flags_to_page_flags(int aflags);
static as_area_t *find_area_and_lock(as_t *as, uintptr_t va);
static bool check_area_conflicts(as_t *as, uintptr_t va, size_t size,
as_area_t *avoid_area);
static void sh_info_remove_reference(share_info_t *sh_info);
 
#ifndef __OBJC__
static int as_constructor(void *obj, int flags)
{
as_t *as = (as_t *) obj;
122,7 → 122,7
int rc;
 
link_initialize(&as->inactive_as_with_asid_link);
mutex_initialize(&as->lock, MUTEX_PASSIVE);
mutex_initialize(&as->lock);
rc = as_constructor_arch(as, flags);
135,6 → 135,7
 
return as_destructor_arch(as);
}
#endif
 
/** Initialize address space subsystem. */
void as_init(void)
141,29 → 142,33
{
as_arch_init();
 
#ifndef __OBJC__
as_slab = slab_cache_create("as_slab", sizeof(as_t), 0,
as_constructor, as_destructor, SLAB_CACHE_MAGDEFERRED);
#endif
AS_KERNEL = as_create(FLAG_AS_KERNEL);
if (!AS_KERNEL)
panic("Cannot create kernel address space.");
panic("can't create kernel address space\n");
/* Make sure the kernel address space
* reference count never drops to zero.
*/
atomic_set(&AS_KERNEL->refcount, 1);
}
 
/** Create address space.
*
* @param flags Flags that influence the way in wich the address space
* is created.
* @param flags Flags that influence way in wich the address space is created.
*/
as_t *as_create(int flags)
{
as_t *as;
 
#ifdef __OBJC__
as = [as_t new];
link_initialize(&as->inactive_as_with_asid_link);
mutex_initialize(&as->lock);
(void) as_constructor_arch(as, flags);
#else
as = (as_t *) slab_alloc(as_slab, 0);
#endif
(void) as_create_arch(as, 0);
btree_create(&as->as_area_btree);
173,7 → 178,7
else
as->asid = ASID_INVALID;
atomic_set(&as->refcount, 0);
as->refcount = 0;
as->cpu_refcount = 0;
#ifdef AS_PAGE_TABLE
as->genarch.page_table = page_table_create(flags);
180,7 → 185,7
#else
page_table_create(flags);
#endif
 
return as;
}
 
188,47 → 193,26
*
* When there are no tasks referencing this address space (i.e. its refcount is
* zero), the address space can be destroyed.
*
* We know that we don't hold any spinlock.
*
* @param as Address space to be destroyed.
*/
void as_destroy(as_t *as)
{
ipl_t ipl;
bool cond;
DEADLOCK_PROBE_INIT(p_asidlock);
 
ASSERT(atomic_get(&as->refcount) == 0);
ASSERT(as->refcount == 0);
/*
* Since there is no reference to this area,
* it is safe not to lock its mutex.
*/
 
/*
* We need to avoid deadlock between TLB shootdown and asidlock.
* We therefore try to take asid conditionally and if we don't succeed,
* we enable interrupts and try again. This is done while preemption is
* disabled to prevent nested context switches. We also depend on the
* fact that so far no spinlocks are held.
*/
preemption_disable();
ipl = interrupts_read();
retry:
interrupts_disable();
if (!spinlock_trylock(&asidlock)) {
interrupts_enable();
DEADLOCK_PROBE(p_asidlock, DEADLOCK_THRESHOLD);
goto retry;
}
preemption_enable(); /* Interrupts disabled, enable preemption */
ipl = interrupts_disable();
spinlock_lock(&inactive_as_with_asid_lock);
if (as->asid != ASID_INVALID && as != AS_KERNEL) {
if (as != AS && as->cpu_refcount == 0)
list_remove(&as->inactive_as_with_asid_link);
asid_put(as->asid);
}
spinlock_unlock(&asidlock);
spinlock_unlock(&inactive_as_with_asid_lock);
 
/*
* Destroy address space areas of the address space.
256,7 → 240,11
 
interrupts_restore(ipl);
 
#ifdef __OBJC__
[as free];
#else
slab_free(as_slab, as);
#endif
}
 
/** Create address space area of common attributes.
263,19 → 251,19
*
* The created address space area is added to the target address space.
*
* @param as Target address space.
* @param flags Flags of the area memory.
* @param size Size of area.
* @param base Base address of area.
* @param attrs Attributes of the area.
* @param backend Address space area backend. NULL if no backend is used.
* @param backend_data NULL or a pointer to an array holding two void *.
* @param as Target address space.
* @param flags Flags of the area memory.
* @param size Size of area.
* @param base Base address of area.
* @param attrs Attributes of the area.
* @param backend Address space area backend. NULL if no backend is used.
* @param backend_data NULL or a pointer to an array holding two void *.
*
* @return Address space area on success or NULL on failure.
* @return Address space area on success or NULL on failure.
*/
as_area_t *
as_area_create(as_t *as, int flags, size_t size, uintptr_t base, int attrs,
mem_backend_t *backend, mem_backend_data_t *backend_data)
mem_backend_t *backend, mem_backend_data_t *backend_data)
{
ipl_t ipl;
as_area_t *a;
301,7 → 289,7
a = (as_area_t *) malloc(sizeof(as_area_t), 0);
 
mutex_initialize(&a->lock, MUTEX_PASSIVE);
mutex_initialize(&a->lock);
a->as = as;
a->flags = flags;
313,7 → 301,8
if (backend_data)
a->backend_data = *backend_data;
else
memsetb(&a->backend_data, sizeof(a->backend_data), 0);
memsetb((uintptr_t) &a->backend_data, sizeof(a->backend_data),
0);
 
btree_create(&a->used_space);
327,14 → 316,13
 
/** Find address space area and change it.
*
* @param as Address space.
* @param address Virtual address belonging to the area to be changed.
* Must be page-aligned.
* @param size New size of the virtual memory block starting at
* address.
* @param flags Flags influencing the remap operation. Currently unused.
* @param as Address space.
* @param address Virtual address belonging to the area to be changed. Must be
* page-aligned.
* @param size New size of the virtual memory block starting at address.
* @param flags Flags influencing the remap operation. Currently unused.
*
* @return Zero on success or a value from @ref errno.h otherwise.
* @return Zero on success or a value from @ref errno.h otherwise.
*/
int as_area_resize(as_t *as, uintptr_t address, size_t size, int flags)
{
389,7 → 377,7
if (pages < area->pages) {
bool cond;
uintptr_t start_free = area->base + pages * PAGE_SIZE;
uintptr_t start_free = area->base + pages*PAGE_SIZE;
 
/*
* Shrinking the area.
399,7 → 387,7
/*
* Start TLB shootdown sequence.
*/
tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base +
tlb_shootdown_start(TLB_INVL_PAGES, AS->asid, area->base +
pages * PAGE_SIZE, area->pages - pages);
 
/*
418,12 → 406,12
btree_node_t, leaf_link);
if ((cond = (bool) node->keys)) {
uintptr_t b = node->key[node->keys - 1];
size_t c =
(size_t) node->value[node->keys - 1];
unsigned int i = 0;
count_t c =
(count_t) node->value[node->keys - 1];
int i = 0;
if (overlaps(b, c * PAGE_SIZE, area->base,
pages * PAGE_SIZE)) {
pages*PAGE_SIZE)) {
if (b + c * PAGE_SIZE <= start_free) {
/*
444,8 → 432,8
i = (start_free - b) >> PAGE_WIDTH;
if (!used_space_remove(area, start_free,
c - i))
panic("Cannot remove used "
"space.");
panic("Could not remove used "
"space.\n");
} else {
/*
* The interval of used space can be
452,8 → 440,8
* completely removed.
*/
if (!used_space_remove(area, b, c))
panic("Cannot remove used "
"space.");
panic("Could not remove used "
"space.\n");
}
for (; i < c; i++) {
480,16 → 468,15
/*
* Finish TLB shootdown sequence.
*/
 
tlb_invalidate_pages(as->asid, area->base + pages * PAGE_SIZE,
area->pages - pages);
tlb_shootdown_finalize();
/*
* Invalidate software translation caches (e.g. TSB on sparc64).
*/
as_invalidate_translation_cache(as, area->base +
pages * PAGE_SIZE, area->pages - pages);
tlb_shootdown_finalize();
} else {
/*
* Growing the area.
515,10 → 502,10
 
/** Destroy address space area.
*
* @param as Address space.
* @param address Address within the area to be deleted.
* @param as Address space.
* @param address Address withing the area to be deleted.
*
* @return Zero on success or a value from @ref errno.h on failure.
* @return Zero on success or a value from @ref errno.h on failure.
*/
int as_area_destroy(as_t *as, uintptr_t address)
{
550,15 → 537,15
for (cur = area->used_space.leaf_head.next;
cur != &area->used_space.leaf_head; cur = cur->next) {
btree_node_t *node;
unsigned int i;
int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
uintptr_t b = node->key[i];
size_t j;
count_t j;
pte_t *pte;
for (j = 0; j < (size_t) node->value[i]; j++) {
for (j = 0; j < (count_t) node->value[i]; j++) {
page_table_lock(as, false);
pte = page_mapping_find(as, b + j * PAGE_SIZE);
ASSERT(pte && PTE_VALID(pte) &&
566,7 → 553,7
if (area->backend &&
area->backend->frame_free) {
area->backend->frame_free(area, b +
j * PAGE_SIZE, PTE_GET_FRAME(pte));
j * PAGE_SIZE, PTE_GET_FRAME(pte));
}
page_mapping_remove(as, b + j * PAGE_SIZE);
page_table_unlock(as, false);
577,14 → 564,14
/*
* Finish TLB shootdown sequence.
*/
 
tlb_invalidate_pages(as->asid, area->base, area->pages);
tlb_shootdown_finalize();
/*
* Invalidate potential software translation caches (e.g. TSB on
* sparc64).
*/
as_invalidate_translation_cache(as, area->base, area->pages);
tlb_shootdown_finalize();
btree_destroy(&area->used_space);
 
615,22 → 602,22
* sh_info of the source area. The process of duplicating the
* mapping is done through the backend share function.
*
* @param src_as Pointer to source address space.
* @param src_base Base address of the source address space area.
* @param acc_size Expected size of the source area.
* @param dst_as Pointer to destination address space.
* @param dst_base Target base address.
* @param src_as Pointer to source address space.
* @param src_base Base address of the source address space area.
* @param acc_size Expected size of the source area.
* @param dst_as Pointer to destination address space.
* @param dst_base Target base address.
* @param dst_flags_mask Destination address space area flags mask.
*
* @return Zero on success or ENOENT if there is no such task or if
* there is no such address space area, EPERM if there was
* a problem in accepting the area or ENOMEM if there was a
* problem in allocating destination address space area.
* ENOTSUP is returned if the address space area backend
* does not support sharing.
* @return Zero on success or ENOENT if there is no such task or if there is no
* such address space area, EPERM if there was a problem in accepting the area
* or ENOMEM if there was a problem in allocating destination address space
* area. ENOTSUP is returned if the address space area backend does not support
* sharing or if the kernel detects an attempt to create an illegal address
* alias.
*/
int as_area_share(as_t *src_as, uintptr_t src_base, size_t acc_size,
as_t *dst_as, uintptr_t dst_base, int dst_flags_mask)
as_t *dst_as, uintptr_t dst_base, int dst_flags_mask)
{
ipl_t ipl;
int src_flags;
680,6 → 667,20
return EPERM;
}
 
#ifdef CONFIG_VIRT_IDX_DCACHE
if (!(dst_flags_mask & AS_AREA_EXEC)) {
if (PAGE_COLOR(src_area->base) != PAGE_COLOR(dst_base)) {
/*
* Refuse to create an illegal address alias.
*/
mutex_unlock(&src_area->lock);
mutex_unlock(&src_as->lock);
interrupts_restore(ipl);
return ENOTSUP;
}
}
#endif /* CONFIG_VIRT_IDX_DCACHE */
 
/*
* Now we are committed to sharing the area.
* First, prepare the area for sharing.
688,14 → 689,10
sh_info = src_area->sh_info;
if (!sh_info) {
sh_info = (share_info_t *) malloc(sizeof(share_info_t), 0);
mutex_initialize(&sh_info->lock, MUTEX_PASSIVE);
mutex_initialize(&sh_info->lock);
sh_info->refcount = 2;
btree_create(&sh_info->pagemap);
src_area->sh_info = sh_info;
/*
* Call the backend to setup sharing.
*/
src_area->backend->share(src_area);
} else {
mutex_lock(&sh_info->lock);
sh_info->refcount++;
702,6 → 699,8
mutex_unlock(&sh_info->lock);
}
 
src_area->backend->share(src_area);
 
mutex_unlock(&src_area->lock);
mutex_unlock(&src_as->lock);
 
746,11 → 745,10
*
* The address space area must be locked prior to this call.
*
* @param area Address space area.
* @param access Access mode.
* @param area Address space area.
* @param access Access mode.
*
* @return False if access violates area's permissions, true
* otherwise.
* @return False if access violates area's permissions, true otherwise.
*/
bool as_area_check_access(as_area_t *area, pf_access_t access)
{
766,183 → 764,21
return true;
}
 
/** Change adress space area flags.
*
* The idea is to have the same data, but with a different access mode.
* This is needed e.g. for writing code into memory and then executing it.
* In order for this to work properly, this may copy the data
* into private anonymous memory (unless it's already there).
*
* @param as Address space.
* @param flags Flags of the area memory.
* @param address Address within the area to be changed.
*
* @return Zero on success or a value from @ref errno.h on failure.
*
*/
int as_area_change_flags(as_t *as, int flags, uintptr_t address)
{
as_area_t *area;
uintptr_t base;
link_t *cur;
ipl_t ipl;
int page_flags;
uintptr_t *old_frame;
size_t frame_idx;
size_t used_pages;
/* Flags for the new memory mapping */
page_flags = area_flags_to_page_flags(flags);
 
ipl = interrupts_disable();
mutex_lock(&as->lock);
 
area = find_area_and_lock(as, address);
if (!area) {
mutex_unlock(&as->lock);
interrupts_restore(ipl);
return ENOENT;
}
 
if ((area->sh_info) || (area->backend != &anon_backend)) {
/* Copying shared areas not supported yet */
/* Copying non-anonymous memory not supported yet */
mutex_unlock(&area->lock);
mutex_unlock(&as->lock);
interrupts_restore(ipl);
return ENOTSUP;
}
 
base = area->base;
 
/*
* Compute total number of used pages in the used_space B+tree
*/
used_pages = 0;
 
for (cur = area->used_space.leaf_head.next;
cur != &area->used_space.leaf_head; cur = cur->next) {
btree_node_t *node;
unsigned int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
used_pages += (size_t) node->value[i];
}
}
 
/* An array for storing frame numbers */
old_frame = malloc(used_pages * sizeof(uintptr_t), 0);
 
/*
* Start TLB shootdown sequence.
*/
tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base, area->pages);
 
/*
* Remove used pages from page tables and remember their frame
* numbers.
*/
frame_idx = 0;
 
for (cur = area->used_space.leaf_head.next;
cur != &area->used_space.leaf_head; cur = cur->next) {
btree_node_t *node;
unsigned int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
uintptr_t b = node->key[i];
size_t j;
pte_t *pte;
for (j = 0; j < (size_t) node->value[i]; j++) {
page_table_lock(as, false);
pte = page_mapping_find(as, b + j * PAGE_SIZE);
ASSERT(pte && PTE_VALID(pte) &&
PTE_PRESENT(pte));
old_frame[frame_idx++] = PTE_GET_FRAME(pte);
 
/* Remove old mapping */
page_mapping_remove(as, b + j * PAGE_SIZE);
page_table_unlock(as, false);
}
}
}
 
/*
* Finish TLB shootdown sequence.
*/
 
tlb_invalidate_pages(as->asid, area->base, area->pages);
/*
* Invalidate potential software translation caches (e.g. TSB on
* sparc64).
*/
as_invalidate_translation_cache(as, area->base, area->pages);
tlb_shootdown_finalize();
 
/*
* Set the new flags.
*/
area->flags = flags;
 
/*
* Map pages back in with new flags. This step is kept separate
* so that the memory area could not be accesed with both the old and
* the new flags at once.
*/
frame_idx = 0;
 
for (cur = area->used_space.leaf_head.next;
cur != &area->used_space.leaf_head; cur = cur->next) {
btree_node_t *node;
unsigned int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
uintptr_t b = node->key[i];
size_t j;
for (j = 0; j < (size_t) node->value[i]; j++) {
page_table_lock(as, false);
 
/* Insert the new mapping */
page_mapping_insert(as, b + j * PAGE_SIZE,
old_frame[frame_idx++], page_flags);
 
page_table_unlock(as, false);
}
}
}
 
free(old_frame);
 
mutex_unlock(&area->lock);
mutex_unlock(&as->lock);
interrupts_restore(ipl);
 
return 0;
}
 
 
/** Handle page fault within the current address space.
*
* This is the high-level page fault handler. It decides whether the page fault
* can be resolved by any backend and if so, it invokes the backend to resolve
* the page fault.
* This is the high-level page fault handler. It decides
* whether the page fault can be resolved by any backend
* and if so, it invokes the backend to resolve the page
* fault.
*
* Interrupts are assumed disabled.
*
* @param page Faulting page.
* @param access Access mode that caused the page fault (i.e.
* read/write/exec).
* @param istate Pointer to the interrupted state.
* @param page Faulting page.
* @param access Access mode that caused the fault (i.e. read/write/exec).
* @param istate Pointer to interrupted state.
*
* @return AS_PF_FAULT on page fault, AS_PF_OK on success or
* AS_PF_DEFER if the fault was caused by copy_to_uspace()
* or copy_from_uspace().
* @return AS_PF_FAULT on page fault, AS_PF_OK on success or AS_PF_DEFER if the
* fault was caused by copy_to_uspace() or copy_from_uspace().
*/
int as_page_fault(uintptr_t page, pf_access_t access, istate_t *istate)
{
988,8 → 824,9
page_table_lock(AS, false);
/*
* To avoid race condition between two page faults on the same address,
* we need to make sure the mapping has not been already inserted.
* To avoid race condition between two page faults
* on the same address, we need to make sure
* the mapping has not been already inserted.
*/
if ((pte = page_mapping_find(AS, page))) {
if (PTE_PRESENT(pte)) {
1038,37 → 875,24
/** Switch address spaces.
*
* Note that this function cannot sleep as it is essentially a part of
* scheduling. Sleeping here would lead to deadlock on wakeup. Another
* thing which is forbidden in this context is locking the address space.
* scheduling. Sleeping here would lead to deadlock on wakeup.
*
* When this function is enetered, no spinlocks may be held.
*
* @param old Old address space or NULL.
* @param new New address space.
* @param old Old address space or NULL.
* @param new New address space.
*/
void as_switch(as_t *old_as, as_t *new_as)
{
DEADLOCK_PROBE_INIT(p_asidlock);
preemption_disable();
retry:
(void) interrupts_disable();
if (!spinlock_trylock(&asidlock)) {
/*
* Avoid deadlock with TLB shootdown.
* We can enable interrupts here because
* preemption is disabled. We should not be
* holding any other lock.
*/
(void) interrupts_enable();
DEADLOCK_PROBE(p_asidlock, DEADLOCK_THRESHOLD);
goto retry;
}
preemption_enable();
ipl_t ipl;
bool needs_asid = false;
ipl = interrupts_disable();
spinlock_lock(&inactive_as_with_asid_lock);
 
/*
* First, take care of the old address space.
*/
if (old_as) {
mutex_lock_active(&old_as->lock);
ASSERT(old_as->cpu_refcount);
if((--old_as->cpu_refcount == 0) && (old_as != AS_KERNEL)) {
/*
1077,10 → 901,11
* list of inactive address spaces with assigned
* ASID.
*/
ASSERT(old_as->asid != ASID_INVALID);
list_append(&old_as->inactive_as_with_asid_link,
&inactive_as_with_asid_head);
ASSERT(old_as->asid != ASID_INVALID);
list_append(&old_as->inactive_as_with_asid_link,
&inactive_as_with_asid_head);
}
mutex_unlock(&old_as->lock);
 
/*
* Perform architecture-specific tasks when the address space
1092,15 → 917,36
/*
* Second, prepare the new address space.
*/
mutex_lock_active(&new_as->lock);
if ((new_as->cpu_refcount++ == 0) && (new_as != AS_KERNEL)) {
if (new_as->asid != ASID_INVALID)
if (new_as->asid != ASID_INVALID) {
list_remove(&new_as->inactive_as_with_asid_link);
else
new_as->asid = asid_get();
} else {
/*
* Defer call to asid_get() until new_as->lock is released.
*/
needs_asid = true;
}
}
#ifdef AS_PAGE_TABLE
SET_PTL0_ADDRESS(new_as->genarch.page_table);
#endif
mutex_unlock(&new_as->lock);
 
if (needs_asid) {
/*
* Allocation of new ASID was deferred
* until now in order to avoid deadlock.
*/
asid_t asid;
asid = asid_get();
mutex_lock_active(&new_as->lock);
new_as->asid = asid;
mutex_unlock(&new_as->lock);
}
spinlock_unlock(&inactive_as_with_asid_lock);
interrupts_restore(ipl);
/*
* Perform architecture-specific steps.
1107,8 → 953,6
* (e.g. write ASID to hardware register etc.)
*/
as_install_arch(new_as);
 
spinlock_unlock(&asidlock);
AS = new_as;
}
1115,9 → 959,9
 
/** Convert address space area flags to page flags.
*
* @param aflags Flags of some address space area.
* @param aflags Flags of some address space area.
*
* @return Flags to be passed to page_mapping_insert().
* @return Flags to be passed to page_mapping_insert().
*/
int area_flags_to_page_flags(int aflags)
{
1145,9 → 989,9
* The address space area must be locked.
* Interrupts must be disabled.
*
* @param a Address space area.
* @param a Address space area.
*
* @return Flags to be used in page_mapping_insert().
* @return Flags to be used in page_mapping_insert().
*/
int as_area_get_flags(as_area_t *a)
{
1156,20 → 1000,23
 
/** Create page table.
*
* Depending on architecture, create either address space private or global page
* table.
* Depending on architecture, create either address space
* private or global page table.
*
* @param flags Flags saying whether the page table is for the kernel
* address space.
* @param flags Flags saying whether the page table is for kernel address space.
*
* @return First entry of the page table.
* @return First entry of the page table.
*/
pte_t *page_table_create(int flags)
{
#ifdef __OBJC__
return [as_t page_table_create: flags];
#else
ASSERT(as_operations);
ASSERT(as_operations->page_table_create);
return as_operations->page_table_create(flags);
#endif
}
 
/** Destroy page table.
1176,14 → 1023,18
*
* Destroy page table in architecture specific way.
*
* @param page_table Physical address of PTL0.
* @param page_table Physical address of PTL0.
*/
void page_table_destroy(pte_t *page_table)
{
#ifdef __OBJC__
return [as_t page_table_destroy: page_table];
#else
ASSERT(as_operations);
ASSERT(as_operations->page_table_destroy);
as_operations->page_table_destroy(page_table);
#endif
}
 
/** Lock page table.
1195,28 → 1046,36
* prior to this call. Address space can be locked prior to this
* call in which case the lock argument is false.
*
* @param as Address space.
* @param lock If false, do not attempt to lock as->lock.
* @param as Address space.
* @param lock If false, do not attempt to lock as->lock.
*/
void page_table_lock(as_t *as, bool lock)
{
#ifdef __OBJC__
[as page_table_lock: lock];
#else
ASSERT(as_operations);
ASSERT(as_operations->page_table_lock);
as_operations->page_table_lock(as, lock);
#endif
}
 
/** Unlock page table.
*
* @param as Address space.
* @param unlock If false, do not attempt to unlock as->lock.
* @param as Address space.
* @param unlock If false, do not attempt to unlock as->lock.
*/
void page_table_unlock(as_t *as, bool unlock)
{
#ifdef __OBJC__
[as page_table_unlock: unlock];
#else
ASSERT(as_operations);
ASSERT(as_operations->page_table_unlock);
as_operations->page_table_unlock(as, unlock);
#endif
}
 
 
1224,17 → 1083,17
*
* The address space must be locked and interrupts must be disabled.
*
* @param as Address space.
* @param va Virtual address.
* @param as Address space.
* @param va Virtual address.
*
* @return Locked address space area containing va on success or
* NULL on failure.
* @return Locked address space area containing va on success or NULL on
* failure.
*/
as_area_t *find_area_and_lock(as_t *as, uintptr_t va)
{
as_area_t *a;
btree_node_t *leaf, *lnode;
unsigned int i;
int i;
a = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
if (a) {
1280,19 → 1139,19
*
* The address space must be locked and interrupts must be disabled.
*
* @param as Address space.
* @param va Starting virtual address of the area being tested.
* @param size Size of the area being tested.
* @param avoid_area Do not touch this area.
* @param as Address space.
* @param va Starting virtual address of the area being tested.
* @param size Size of the area being tested.
* @param avoid_area Do not touch this area.
*
* @return True if there is no conflict, false otherwise.
* @return True if there is no conflict, false otherwise.
*/
bool
check_area_conflicts(as_t *as, uintptr_t va, size_t size, as_area_t *avoid_area)
bool check_area_conflicts(as_t *as, uintptr_t va, size_t size,
as_area_t *avoid_area)
{
as_area_t *a;
btree_node_t *leaf, *node;
unsigned int i;
int i;
/*
* We don't want any area to have conflicts with NULL page.
1362,14 → 1221,8
return true;
}
 
/** Return size of the address space area with given base.
*
* @param base Arbitrary address insede the address space area.
*
* @return Size of the address space area in bytes or zero if it
* does not exist.
*/
size_t as_area_get_size(uintptr_t base)
/** Return size of the address space area with given base. */
size_t as_get_size(uintptr_t base)
{
ipl_t ipl;
as_area_t *src_area;
1377,7 → 1230,7
 
ipl = interrupts_disable();
src_area = find_area_and_lock(AS, base);
if (src_area) {
if (src_area){
size = src_area->pages * PAGE_SIZE;
mutex_unlock(&src_area->lock);
} else {
1391,22 → 1244,22
*
* The address space area must be already locked.
*
* @param a Address space area.
* @param page First page to be marked.
* @param count Number of page to be marked.
* @param a Address space area.
* @param page First page to be marked.
* @param count Number of page to be marked.
*
* @return Zero on failure and non-zero on success.
* @return 0 on failure and 1 on success.
*/
int used_space_insert(as_area_t *a, uintptr_t page, size_t count)
int used_space_insert(as_area_t *a, uintptr_t page, count_t count)
{
btree_node_t *leaf, *node;
size_t pages;
unsigned int i;
count_t pages;
int i;
 
ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE));
ASSERT(count);
 
pages = (size_t) btree_search(&a->used_space, page, &leaf);
pages = (count_t) btree_search(&a->used_space, page, &leaf);
if (pages) {
/*
* We hit the beginning of some used space.
1423,8 → 1276,8
if (node) {
uintptr_t left_pg = node->key[node->keys - 1];
uintptr_t right_pg = leaf->key[0];
size_t left_cnt = (size_t) node->value[node->keys - 1];
size_t right_cnt = (size_t) leaf->value[0];
count_t left_cnt = (count_t) node->value[node->keys - 1];
count_t right_cnt = (count_t) leaf->value[0];
/*
* Examine the possibility that the interval fits
1478,7 → 1331,7
}
} else if (page < leaf->key[0]) {
uintptr_t right_pg = leaf->key[0];
size_t right_cnt = (size_t) leaf->value[0];
count_t right_cnt = (count_t) leaf->value[0];
/*
* Investigate the border case in which the left neighbour does
1513,8 → 1366,8
if (node) {
uintptr_t left_pg = leaf->key[leaf->keys - 1];
uintptr_t right_pg = node->key[0];
size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
size_t right_cnt = (size_t) node->value[0];
count_t left_cnt = (count_t) leaf->value[leaf->keys - 1];
count_t right_cnt = (count_t) node->value[0];
/*
* Examine the possibility that the interval fits
1568,7 → 1421,7
}
} else if (page >= leaf->key[leaf->keys - 1]) {
uintptr_t left_pg = leaf->key[leaf->keys - 1];
size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
count_t left_cnt = (count_t) leaf->value[leaf->keys - 1];
/*
* Investigate the border case in which the right neighbour
1606,8 → 1459,8
if (page < leaf->key[i]) {
uintptr_t left_pg = leaf->key[i - 1];
uintptr_t right_pg = leaf->key[i];
size_t left_cnt = (size_t) leaf->value[i - 1];
size_t right_cnt = (size_t) leaf->value[i];
count_t left_cnt = (count_t) leaf->value[i - 1];
count_t right_cnt = (count_t) leaf->value[i];
 
/*
* The interval fits between left_pg and right_pg.
1665,8 → 1518,8
}
}
 
panic("Inconsistency detected while adding %" PRIs " pages of used "
"space at %p.", count, page);
panic("Inconsistency detected while adding %d pages of used space at "
"%p.\n", count, page);
}
 
/** Mark portion of address space area as unused.
1673,22 → 1526,22
*
* The address space area must be already locked.
*
* @param a Address space area.
* @param page First page to be marked.
* @param count Number of page to be marked.
* @param a Address space area.
* @param page First page to be marked.
* @param count Number of page to be marked.
*
* @return Zero on failure and non-zero on success.
* @return 0 on failure and 1 on success.
*/
int used_space_remove(as_area_t *a, uintptr_t page, size_t count)
int used_space_remove(as_area_t *a, uintptr_t page, count_t count)
{
btree_node_t *leaf, *node;
size_t pages;
unsigned int i;
count_t pages;
int i;
 
ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE));
ASSERT(count);
 
pages = (size_t) btree_search(&a->used_space, page, &leaf);
pages = (count_t) btree_search(&a->used_space, page, &leaf);
if (pages) {
/*
* We are lucky, page is the beginning of some interval.
1717,7 → 1570,7
node = btree_leaf_node_left_neighbour(&a->used_space, leaf);
if (node && page < leaf->key[0]) {
uintptr_t left_pg = node->key[node->keys - 1];
size_t left_cnt = (size_t) node->value[node->keys - 1];
count_t left_cnt = (count_t) node->value[node->keys - 1];
 
if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
count * PAGE_SIZE)) {
1733,7 → 1586,7
return 1;
} else if (page + count * PAGE_SIZE <
left_pg + left_cnt*PAGE_SIZE) {
size_t new_cnt;
count_t new_cnt;
/*
* The interval is contained in the rightmost
1757,7 → 1610,7
if (page > leaf->key[leaf->keys - 1]) {
uintptr_t left_pg = leaf->key[leaf->keys - 1];
size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
count_t left_cnt = (count_t) leaf->value[leaf->keys - 1];
 
if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
count * PAGE_SIZE)) {
1772,7 → 1625,7
return 1;
} else if (page + count * PAGE_SIZE < left_pg +
left_cnt * PAGE_SIZE) {
size_t new_cnt;
count_t new_cnt;
/*
* The interval is contained in the rightmost
1799,7 → 1652,7
for (i = 1; i < leaf->keys - 1; i++) {
if (page < leaf->key[i]) {
uintptr_t left_pg = leaf->key[i - 1];
size_t left_cnt = (size_t) leaf->value[i - 1];
count_t left_cnt = (count_t) leaf->value[i - 1];
 
/*
* Now the interval is between intervals corresponding
1819,7 → 1672,7
return 1;
} else if (page + count * PAGE_SIZE <
left_pg + left_cnt * PAGE_SIZE) {
size_t new_cnt;
count_t new_cnt;
/*
* The interval is contained in the
1844,8 → 1697,8
}
 
error:
panic("Inconsistency detected while removing %" PRIs " pages of used "
"space from %p.", count, page);
panic("Inconsistency detected while removing %d pages of used space "
"from %p.\n", count, page);
}
 
/** Remove reference to address space area share info.
1852,7 → 1705,7
*
* If the reference count drops to 0, the sh_info is deallocated.
*
* @param sh_info Pointer to address space area share info.
* @param sh_info Pointer to address space area share info.
*/
void sh_info_remove_reference(share_info_t *sh_info)
{
1871,7 → 1724,7
for (cur = sh_info->pagemap.leaf_head.next;
cur != &sh_info->pagemap.leaf_head; cur = cur->next) {
btree_node_t *node;
unsigned int i;
int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++)
1907,12 → 1760,6
return (unative_t) as_area_resize(AS, address, size, 0);
}
 
/** Wrapper for as_area_change_flags(). */
unative_t sys_as_area_change_flags(uintptr_t address, int flags)
{
return (unative_t) as_area_change_flags(AS, flags, address);
}
 
/** Wrapper for as_area_destroy(). */
unative_t sys_as_area_destroy(uintptr_t address)
{
1921,7 → 1768,7
 
/** Print out information about address space.
*
* @param as Address space.
* @param as Address space.
*/
void as_print(as_t *as)
{
1938,14 → 1785,14
node = list_get_instance(cur, btree_node_t, leaf_link);
unsigned int i;
int i;
for (i = 0; i < node->keys; i++) {
as_area_t *area = node->value[i];
mutex_lock(&area->lock);
printf("as_area: %p, base=%p, pages=%" PRIs
" (%p - %p)\n", area, area->base, area->pages,
area->base, area->base + FRAMES2SIZE(area->pages));
printf("as_area: %p, base=%p, pages=%d (%p - %p)\n",
area, area->base, area->pages, area->base,
area->base + area->pages*PAGE_SIZE);
mutex_unlock(&area->lock);
}
}
/branches/arm/kernel/generic/src/mm/slab.c
129,7 → 129,7
static slab_cache_t *slab_extern_cache;
/** Caches for malloc */
static slab_cache_t *malloc_caches[SLAB_MAX_MALLOC_W - SLAB_MIN_MALLOC_W + 1];
static char *malloc_names[] = {
char *malloc_names[] = {
"malloc-16",
"malloc-32",
"malloc-64",
144,11 → 144,7
"malloc-32K",
"malloc-64K",
"malloc-128K",
"malloc-256K",
"malloc-512K",
"malloc-1M",
"malloc-2M",
"malloc-4M"
"malloc-256K"
};
 
/** Slab descriptor */
156,8 → 152,8
slab_cache_t *cache; /**< Pointer to parent cache. */
link_t link; /**< List of full/partial slabs. */
void *start; /**< Start address of first available item. */
size_t available; /**< Count of available items in this slab. */
size_t nextavail; /**< The index of next available item. */
count_t available; /**< Count of available items in this slab. */
index_t nextavail; /**< The index of next available item. */
} slab_t;
 
#ifdef CONFIG_DEBUG
171,19 → 167,19
* Allocate frames for slab space and initialize
*
*/
static slab_t *slab_space_alloc(slab_cache_t *cache, int flags)
static slab_t * slab_space_alloc(slab_cache_t *cache, int flags)
{
void *data;
slab_t *slab;
size_t fsize;
unsigned int i;
size_t zone = 0;
int i;
unsigned int zone = 0;
data = frame_alloc_generic(cache->order, FRAME_KA | flags, &zone);
if (!data) {
return NULL;
}
if (!(cache->flags & SLAB_CACHE_SLINSIDE)) {
if (! (cache->flags & SLAB_CACHE_SLINSIDE)) {
slab = slab_alloc(slab_extern_cache, flags);
if (!slab) {
frame_free(KA2PA(data));
195,8 → 191,8
}
/* Fill in slab structures */
for (i = 0; i < ((unsigned int) 1 << cache->order); i++)
frame_set_parent(ADDR2PFN(KA2PA(data)) + i, slab, zone);
for (i=0; i < (1 << cache->order); i++)
frame_set_parent(ADDR2PFN(KA2PA(data))+i, slab, zone);
 
slab->start = data;
slab->available = cache->objects;
203,8 → 199,8
slab->nextavail = 0;
slab->cache = cache;
 
for (i = 0; i < cache->objects; i++)
*((int *) (slab->start + i*cache->size)) = i + 1;
for (i=0; i<cache->objects;i++)
*((int *) (slab->start + i*cache->size)) = i+1;
 
atomic_inc(&cache->allocated_slabs);
return slab;
215,7 → 211,7
*
* @return number of freed frames
*/
static size_t slab_space_free(slab_cache_t *cache, slab_t *slab)
static count_t slab_space_free(slab_cache_t *cache, slab_t *slab)
{
frame_free(KA2PA(slab->start));
if (! (cache->flags & SLAB_CACHE_SLINSIDE))
243,7 → 239,8
*
* @return Number of freed pages
*/
static size_t slab_obj_destroy(slab_cache_t *cache, void *obj, slab_t *slab)
static count_t slab_obj_destroy(slab_cache_t *cache, void *obj,
slab_t *slab)
{
int freed = 0;
 
259,7 → 256,7
ASSERT(slab->available < cache->objects);
 
*((int *)obj) = slab->nextavail;
slab->nextavail = (obj - slab->start) / cache->size;
slab->nextavail = (obj - slab->start)/cache->size;
slab->available++;
 
/* Move it to correct list */
284,7 → 281,7
*
* @return Object address or null
*/
static void *slab_obj_create(slab_cache_t *cache, int flags)
static void * slab_obj_create(slab_cache_t *cache, int flags)
{
slab_t *slab;
void *obj;
304,8 → 301,7
return NULL;
spinlock_lock(&cache->slablock);
} else {
slab = list_get_instance(cache->partial_slabs.next, slab_t,
link);
slab = list_get_instance(cache->partial_slabs.next, slab_t, link);
list_remove(&slab->link);
}
obj = slab->start + slab->nextavail * cache->size;
336,7 → 332,8
*
* @param first If true, return first, else last mag
*/
static slab_magazine_t *get_mag_from_cache(slab_cache_t *cache, int first)
static slab_magazine_t * get_mag_from_cache(slab_cache_t *cache,
int first)
{
slab_magazine_t *mag = NULL;
link_t *cur;
371,12 → 368,13
*
* @return Number of freed pages
*/
static size_t magazine_destroy(slab_cache_t *cache, slab_magazine_t *mag)
static count_t magazine_destroy(slab_cache_t *cache,
slab_magazine_t *mag)
{
unsigned int i;
size_t frames = 0;
int i;
count_t frames = 0;
 
for (i = 0; i < mag->busy; i++) {
for (i=0;i < mag->busy; i++) {
frames += slab_obj_destroy(cache, mag->objs[i], NULL);
atomic_dec(&cache->cached_objs);
}
391,7 → 389,7
*
* Assume cpu_magazine lock is held
*/
static slab_magazine_t *get_full_current_mag(slab_cache_t *cache)
static slab_magazine_t * get_full_current_mag(slab_cache_t *cache)
{
slab_magazine_t *cmag, *lastmag, *newmag;
 
425,7 → 423,7
*
* @return Pointer to object or NULL if not available
*/
static void *magazine_obj_get(slab_cache_t *cache)
static void * magazine_obj_get(slab_cache_t *cache)
{
slab_magazine_t *mag;
void *obj;
460,7 → 458,7
* allocate new, exchange last & current
*
*/
static slab_magazine_t *make_empty_current_mag(slab_cache_t *cache)
static slab_magazine_t * make_empty_current_mag(slab_cache_t *cache)
{
slab_magazine_t *cmag,*lastmag,*newmag;
 
529,26 → 527,25
/* Slab cache functions */
 
/** Return number of objects that fit in certain cache size */
static unsigned int comp_objects(slab_cache_t *cache)
static int comp_objects(slab_cache_t *cache)
{
if (cache->flags & SLAB_CACHE_SLINSIDE)
return ((PAGE_SIZE << cache->order) - sizeof(slab_t)) /
cache->size;
return ((PAGE_SIZE << cache->order) - sizeof(slab_t)) / cache->size;
else
return (PAGE_SIZE << cache->order) / cache->size;
}
 
/** Return wasted space in slab */
static unsigned int badness(slab_cache_t *cache)
static int badness(slab_cache_t *cache)
{
unsigned int objects;
unsigned int ssize;
int objects;
int ssize;
 
objects = comp_objects(cache);
ssize = PAGE_SIZE << cache->order;
if (cache->flags & SLAB_CACHE_SLINSIDE)
ssize -= sizeof(slab_t);
return ssize - objects * cache->size;
return ssize - objects*cache->size;
}
 
/**
556,29 → 553,33
*/
static void make_magcache(slab_cache_t *cache)
{
unsigned int i;
int i;
ASSERT(_slab_initialized >= 2);
 
cache->mag_cache = malloc(sizeof(slab_mag_cache_t) * config.cpu_count,
0);
for (i = 0; i < config.cpu_count; i++) {
memsetb(&cache->mag_cache[i], sizeof(cache->mag_cache[i]), 0);
spinlock_initialize(&cache->mag_cache[i].lock,
"slab_maglock_cpu");
cache->mag_cache = malloc(sizeof(slab_mag_cache_t)*config.cpu_count,0);
for (i=0; i < config.cpu_count; i++) {
memsetb((uintptr_t)&cache->mag_cache[i],
sizeof(cache->mag_cache[i]), 0);
spinlock_initialize(&cache->mag_cache[i].lock,
"slab_maglock_cpu");
}
}
 
/** Initialize allocated memory as a slab cache */
static void
_slab_cache_create(slab_cache_t *cache, char *name, size_t size, size_t align,
int (*constructor)(void *obj, int kmflag), int (*destructor)(void *obj),
int flags)
_slab_cache_create(slab_cache_t *cache,
char *name,
size_t size,
size_t align,
int (*constructor)(void *obj, int kmflag),
int (*destructor)(void *obj),
int flags)
{
int pages;
ipl_t ipl;
 
memsetb(cache, sizeof(*cache), 0);
memsetb((uintptr_t)cache, sizeof(*cache), 0);
cache->name = name;
 
if (align < sizeof(unative_t))
596,7 → 597,7
list_initialize(&cache->magazines);
spinlock_initialize(&cache->slablock, "slab_lock");
spinlock_initialize(&cache->maglock, "slab_maglock");
if (!(cache->flags & SLAB_CACHE_NOMAGAZINE))
if (! (cache->flags & SLAB_CACHE_NOMAGAZINE))
make_magcache(cache);
 
/* Compute slab sizes, object counts in slabs etc. */
609,7 → 610,7
if (pages == 1)
cache->order = 0;
else
cache->order = fnzb(pages - 1) + 1;
cache->order = fnzb(pages-1)+1;
 
while (badness(cache) > SLAB_MAX_BADNESS(cache)) {
cache->order += 1;
630,16 → 631,18
}
 
/** Create slab cache */
slab_cache_t *
slab_cache_create(char *name, size_t size, size_t align,
int (*constructor)(void *obj, int kmflag), int (*destructor)(void *obj),
int flags)
slab_cache_t * slab_cache_create(char *name,
size_t size,
size_t align,
int (*constructor)(void *obj, int kmflag),
int (*destructor)(void *obj),
int flags)
{
slab_cache_t *cache;
 
cache = slab_alloc(&slab_cache_cache, 0);
_slab_cache_create(cache, name, size, align, constructor, destructor,
flags);
flags);
return cache;
}
 
649,11 → 652,11
* @param flags If contains SLAB_RECLAIM_ALL, do aggressive freeing
* @return Number of freed pages
*/
static size_t _slab_reclaim(slab_cache_t *cache, int flags)
static count_t _slab_reclaim(slab_cache_t *cache, int flags)
{
unsigned int i;
int i;
slab_magazine_t *mag;
size_t frames = 0;
count_t frames = 0;
int magcount;
if (cache->flags & SLAB_CACHE_NOMAGAZINE)
663,7 → 666,7
* endless loop
*/
magcount = atomic_get(&cache->magazine_counter);
while (magcount-- && (mag=get_mag_from_cache(cache, 0))) {
while (magcount-- && (mag=get_mag_from_cache(cache,0))) {
frames += magazine_destroy(cache,mag);
if (!(flags & SLAB_RECLAIM_ALL) && frames)
break;
672,7 → 675,7
if (flags & SLAB_RECLAIM_ALL) {
/* Free cpu-bound magazines */
/* Destroy CPU magazines */
for (i = 0; i < config.cpu_count; i++) {
for (i=0; i<config.cpu_count; i++) {
spinlock_lock(&cache->mag_cache[i].lock);
 
mag = cache->mag_cache[i].current;
716,8 → 719,8
_slab_reclaim(cache, SLAB_RECLAIM_ALL);
 
/* All slabs must be empty */
if (!list_empty(&cache->full_slabs) ||
!list_empty(&cache->partial_slabs))
if (!list_empty(&cache->full_slabs) \
|| !list_empty(&cache->partial_slabs))
panic("Destroying cache that is not empty.");
 
if (!(cache->flags & SLAB_CACHE_NOMAGAZINE))
725,8 → 728,9
slab_free(&slab_cache_cache, cache);
}
 
/** Allocate new object from cache - if no flags given, always returns memory */
void *slab_alloc(slab_cache_t *cache, int flags)
/** Allocate new object from cache - if no flags given, always returns
memory */
void * slab_alloc(slab_cache_t *cache, int flags)
{
ipl_t ipl;
void *result = NULL;
755,8 → 759,9
 
ipl = interrupts_disable();
 
if ((cache->flags & SLAB_CACHE_NOMAGAZINE) ||
magazine_obj_put(cache, obj)) {
if ((cache->flags & SLAB_CACHE_NOMAGAZINE) \
|| magazine_obj_put(cache, obj)) {
 
slab_obj_destroy(cache, obj, slab);
 
}
771,11 → 776,11
}
 
/* Go through all caches and reclaim what is possible */
size_t slab_reclaim(int flags)
count_t slab_reclaim(int flags)
{
slab_cache_t *cache;
link_t *cur;
size_t frames = 0;
count_t frames = 0;
 
spinlock_lock(&slab_cache_lock);
 
783,8 → 788,7
* memory allocation from interrupts can deadlock.
*/
 
for (cur = slab_cache_list.next; cur != &slab_cache_list;
cur = cur->next) {
for (cur = slab_cache_list.next;cur!=&slab_cache_list; cur=cur->next) {
cache = list_get_instance(cur, slab_cache_t, link);
frames += _slab_reclaim(cache, flags);
}
798,77 → 802,22
/* Print list of slabs */
void slab_print_list(void)
{
int skip = 0;
 
printf("slab name size pages obj/pg slabs cached allocated"
" ctl\n");
printf("---------------- -------- ------ ------ ------ ------ ---------"
" ---\n");
 
while (true) {
slab_cache_t *cache;
link_t *cur;
ipl_t ipl;
int i;
 
/*
* We must not hold the slab_cache_lock spinlock when printing
* the statistics. Otherwise we can easily deadlock if the print
* needs to allocate memory.
*
* Therefore, we walk through the slab cache list, skipping some
* amount of already processed caches during each iteration and
* gathering statistics about the first unprocessed cache. For
* the sake of printing the statistics, we realese the
* slab_cache_lock and reacquire it afterwards. Then the walk
* starts again.
*
* This limits both the efficiency and also accuracy of the
* obtained statistics. The efficiency is decreased because the
* time complexity of the algorithm is quadratic instead of
* linear. The accuracy is impacted because we drop the lock
* after processing one cache. If there is someone else
* manipulating the cache list, we might omit an arbitrary
* number of caches or process one cache multiple times.
* However, we don't bleed for this algorithm for it is only
* statistics.
*/
 
ipl = interrupts_disable();
spinlock_lock(&slab_cache_lock);
 
for (i = 0, cur = slab_cache_list.next;
i < skip && cur != &slab_cache_list;
i++, cur = cur->next)
;
 
if (cur == &slab_cache_list) {
spinlock_unlock(&slab_cache_lock);
interrupts_restore(ipl);
break;
}
 
skip++;
 
slab_cache_t *cache;
link_t *cur;
ipl_t ipl;
ipl = interrupts_disable();
spinlock_lock(&slab_cache_lock);
printf("slab name size pages obj/pg slabs cached allocated ctl\n");
printf("---------------- -------- ------ ------ ------ ------ --------- ---\n");
for (cur = slab_cache_list.next; cur != &slab_cache_list; cur = cur->next) {
cache = list_get_instance(cur, slab_cache_t, link);
 
char *name = cache->name;
uint8_t order = cache->order;
size_t size = cache->size;
unsigned int objects = cache->objects;
long allocated_slabs = atomic_get(&cache->allocated_slabs);
long cached_objs = atomic_get(&cache->cached_objs);
long allocated_objs = atomic_get(&cache->allocated_objs);
int flags = cache->flags;
spinlock_unlock(&slab_cache_lock);
interrupts_restore(ipl);
printf("%-16s %8" PRIs " %6d %6u %6ld %6ld %9ld %-3s\n",
name, size, (1 << order), objects, allocated_slabs,
cached_objs, allocated_objs,
flags & SLAB_CACHE_SLINSIDE ? "in" : "out");
printf("%-16s %8zd %6zd %6zd %6zd %6zd %9zd %-3s\n", cache->name, cache->size, (1 << cache->order), cache->objects, atomic_get(&cache->allocated_slabs), atomic_get(&cache->cached_objs), atomic_get(&cache->allocated_objs), cache->flags & SLAB_CACHE_SLINSIDE ? "in" : "out");
}
spinlock_unlock(&slab_cache_lock);
interrupts_restore(ipl);
}
 
void slab_cache_init(void)
876,24 → 825,32
int i, size;
 
/* Initialize magazine cache */
_slab_cache_create(&mag_cache, "slab_magazine",
sizeof(slab_magazine_t) + SLAB_MAG_SIZE * sizeof(void*),
sizeof(uintptr_t), NULL, NULL, SLAB_CACHE_NOMAGAZINE |
SLAB_CACHE_SLINSIDE);
_slab_cache_create(&mag_cache,
"slab_magazine",
sizeof(slab_magazine_t)+SLAB_MAG_SIZE*sizeof(void*),
sizeof(uintptr_t),
NULL, NULL,
SLAB_CACHE_NOMAGAZINE | SLAB_CACHE_SLINSIDE);
/* Initialize slab_cache cache */
_slab_cache_create(&slab_cache_cache, "slab_cache",
sizeof(slab_cache_cache), sizeof(uintptr_t), NULL, NULL,
SLAB_CACHE_NOMAGAZINE | SLAB_CACHE_SLINSIDE);
_slab_cache_create(&slab_cache_cache,
"slab_cache",
sizeof(slab_cache_cache),
sizeof(uintptr_t),
NULL, NULL,
SLAB_CACHE_NOMAGAZINE | SLAB_CACHE_SLINSIDE);
/* Initialize external slab cache */
slab_extern_cache = slab_cache_create("slab_extern", sizeof(slab_t), 0,
NULL, NULL, SLAB_CACHE_SLINSIDE | SLAB_CACHE_MAGDEFERRED);
slab_extern_cache = slab_cache_create("slab_extern",
sizeof(slab_t),
0, NULL, NULL,
SLAB_CACHE_SLINSIDE | SLAB_CACHE_MAGDEFERRED);
 
/* Initialize structures for malloc */
for (i = 0, size = (1 << SLAB_MIN_MALLOC_W);
i < (SLAB_MAX_MALLOC_W - SLAB_MIN_MALLOC_W + 1);
i++, size <<= 1) {
malloc_caches[i] = slab_cache_create(malloc_names[i], size, 0,
NULL, NULL, SLAB_CACHE_MAGDEFERRED);
for (i=0, size=(1<<SLAB_MIN_MALLOC_W);
i < (SLAB_MAX_MALLOC_W-SLAB_MIN_MALLOC_W+1);
i++, size <<= 1) {
malloc_caches[i] = slab_cache_create(malloc_names[i],
size, 0,
NULL,NULL, SLAB_CACHE_MAGDEFERRED);
}
#ifdef CONFIG_DEBUG
_slab_initialized = 1;
918,11 → 875,9
 
spinlock_lock(&slab_cache_lock);
for (cur = slab_cache_list.next; cur != &slab_cache_list;
cur = cur->next){
for (cur=slab_cache_list.next; cur != &slab_cache_list;cur=cur->next){
s = list_get_instance(cur, slab_cache_t, link);
if ((s->flags & SLAB_CACHE_MAGDEFERRED) !=
SLAB_CACHE_MAGDEFERRED)
if ((s->flags & SLAB_CACHE_MAGDEFERRED) != SLAB_CACHE_MAGDEFERRED)
continue;
make_magcache(s);
s->flags &= ~SLAB_CACHE_MAGDEFERRED;
933,10 → 888,10
 
/**************************************/
/* kalloc/kfree functions */
void *malloc(unsigned int size, int flags)
void * malloc(unsigned int size, int flags)
{
ASSERT(_slab_initialized);
ASSERT(size <= (1 << SLAB_MAX_MALLOC_W));
ASSERT(size && size <= (1 << SLAB_MAX_MALLOC_W));
if (size < (1 << SLAB_MIN_MALLOC_W))
size = (1 << SLAB_MIN_MALLOC_W);
946,7 → 901,7
return slab_alloc(malloc_caches[idx], flags);
}
 
void *realloc(void *ptr, unsigned int size, int flags)
void * realloc(void *ptr, unsigned int size, int flags)
{
ASSERT(_slab_initialized);
ASSERT(size <= (1 << SLAB_MAX_MALLOC_W));
/branches/arm/kernel/generic/src/mm/tlb.c
78,10 → 78,9
* @param page Virtual page address, if required by type.
* @param count Number of pages, if required by type.
*/
void tlb_shootdown_start(tlb_invalidate_type_t type, asid_t asid,
uintptr_t page, size_t count)
void tlb_shootdown_start(tlb_invalidate_type_t type, asid_t asid, uintptr_t page, count_t count)
{
unsigned int i;
int i;
 
CPU->tlb_active = 0;
spinlock_lock(&tlblock);
108,11 → 107,11
/*
* Enqueue the message.
*/
size_t idx = cpu->tlb_messages_count++;
cpu->tlb_messages[idx].type = type;
cpu->tlb_messages[idx].asid = asid;
cpu->tlb_messages[idx].page = page;
cpu->tlb_messages[idx].count = count;
cpu->tlb_messages[cpu->tlb_messages_count].type = type;
cpu->tlb_messages[cpu->tlb_messages_count].asid = asid;
cpu->tlb_messages[cpu->tlb_messages_count].page = page;
cpu->tlb_messages[cpu->tlb_messages_count].count = count;
cpu->tlb_messages_count++;
}
spinlock_unlock(&cpu->lock);
}
143,8 → 142,8
tlb_invalidate_type_t type;
asid_t asid;
uintptr_t page;
size_t count;
unsigned int i;
count_t count;
int i;
ASSERT(CPU);
173,7 → 172,7
tlb_invalidate_pages(asid, page, count);
break;
default:
panic("Unknown type (%d).", type);
panic("unknown type (%d)\n", type);
break;
}
if (type == TLB_INVL_ALL)
/branches/arm/kernel/generic/src/mm/backend_anon.c
72,8 → 72,7
* @param addr Faulting virtual address.
* @param access Access mode that caused the fault (i.e. read/write/exec).
*
* @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK on success (i.e.
* serviced).
* @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK on success (i.e. serviced).
*/
int anon_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access)
{
87,17 → 86,16
/*
* The area is shared, chances are that the mapping can be found
* in the pagemap of the address space area share info
* structure.
* in the pagemap of the address space area share info structure.
* In the case that the pagemap does not contain the respective
* mapping, a new frame is allocated and the mapping is created.
*/
mutex_lock(&area->sh_info->lock);
frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf);
ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf);
if (!frame) {
bool allocate = true;
unsigned int i;
int i;
/*
* Zero can be returned as a valid frame address.
104,8 → 102,7
* Just a small workaround.
*/
for (i = 0; i < leaf->keys; i++) {
if (leaf->key[i] ==
ALIGN_DOWN(addr, PAGE_SIZE) - area->base) {
if (leaf->key[i] == ALIGN_DOWN(addr, PAGE_SIZE)) {
allocate = false;
break;
}
112,15 → 109,12
}
if (allocate) {
frame = (uintptr_t) frame_alloc(ONE_FRAME, 0);
memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
memsetb(PA2KA(frame), FRAME_SIZE, 0);
/*
* Insert the address of the newly allocated
* frame to the pagemap.
* Insert the address of the newly allocated frame to the pagemap.
*/
btree_insert(&area->sh_info->pagemap,
ALIGN_DOWN(addr, PAGE_SIZE) - area->base,
(void *) frame, leaf);
btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE) - area->base, (void *) frame, leaf);
}
}
frame_reference_add(ADDR2PFN(frame));
142,17 → 136,17
* the different causes
*/
frame = (uintptr_t) frame_alloc(ONE_FRAME, 0);
memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
memsetb(PA2KA(frame), FRAME_SIZE, 0);
}
/*
* Map 'page' to 'frame'.
* Note that TLB shootdown is not attempted as only new information is
* being inserted into page tables.
* Note that TLB shootdown is not attempted as only new information is being
* inserted into page tables.
*/
page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
panic("Cannot insert used space.");
panic("Could not insert used space.\n");
return AS_PF_OK;
}
168,6 → 162,9
void anon_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame)
{
frame_free(frame);
#ifdef CONFIG_VIRT_IDX_DCACHE
dcache_flush_frame(page, frame);
#endif
}
 
/** Share the anonymous address space area.
187,34 → 184,28
* Copy used portions of the area to sh_info's page map.
*/
mutex_lock(&area->sh_info->lock);
for (cur = area->used_space.leaf_head.next;
cur != &area->used_space.leaf_head; cur = cur->next) {
for (cur = area->used_space.leaf_head.next; cur != &area->used_space.leaf_head; cur = cur->next) {
btree_node_t *node;
unsigned int i;
int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
uintptr_t base = node->key[i];
size_t count = (size_t) node->value[i];
unsigned int j;
count_t count = (count_t) node->value[i];
int j;
for (j = 0; j < count; j++) {
pte_t *pte;
page_table_lock(area->as, false);
pte = page_mapping_find(area->as,
base + j * PAGE_SIZE);
ASSERT(pte && PTE_VALID(pte) &&
PTE_PRESENT(pte));
btree_insert(&area->sh_info->pagemap,
(base + j * PAGE_SIZE) - area->base,
(void *) PTE_GET_FRAME(pte), NULL);
pte = page_mapping_find(area->as, base + j*PAGE_SIZE);
ASSERT(pte && PTE_VALID(pte) && PTE_PRESENT(pte));
btree_insert(&area->sh_info->pagemap, (base + j*PAGE_SIZE) - area->base,
(void *) PTE_GET_FRAME(pte), NULL);
page_table_unlock(area->as, false);
 
pfn_t pfn = ADDR2PFN(PTE_GET_FRAME(pte));
frame_reference_add(pfn);
frame_reference_add(ADDR2PFN(PTE_GET_FRAME(pte)));
}
 
}
}
mutex_unlock(&area->sh_info->lock);
/branches/arm/kernel/generic/src/mm/buddy.c
35,7 → 35,8
* @brief Buddy allocator framework.
*
* This file contains buddy system allocator framework.
* Specialized functions are needed for this abstract framework to be useful.
* Specialized functions are needed for this abstract framework
* to be useful.
*/
 
#include <mm/buddy.h>
43,29 → 44,29
#include <arch/types.h>
#include <debug.h>
#include <print.h>
#include <macros.h>
 
/** Return size needed for the buddy configuration data. */
size_t buddy_conf_size(size_t max_order)
/** Return size needed for the buddy configuration data */
size_t buddy_conf_size(int max_order)
{
return sizeof(buddy_system_t) + (max_order + 1) * sizeof(link_t);
}
 
 
/** Create buddy system.
/** Create buddy system
*
* Allocate memory for and initialize new buddy system.
*
* @param b Preallocated buddy system control data.
* @param max_order The biggest allocable size will be 2^max_order.
* @param op Operations for new buddy system.
* @param data Pointer to be used by implementation.
* @param b Preallocated buddy system control data.
* @param max_order The biggest allocable size will be 2^max_order.
* @param op Operations for new buddy system.
* @param data Pointer to be used by implementation.
*
* @return New buddy system.
* @return New buddy system.
*/
void
buddy_system_create(buddy_system_t *b, uint8_t max_order,
buddy_system_operations_t *op, void *data)
void buddy_system_create(buddy_system_t *b,
uint8_t max_order,
buddy_system_operations_t *op,
void *data)
{
int i;
 
79,7 → 80,7
ASSERT(op->mark_busy);
 
/*
* Use memory after our own structure.
* Use memory after our own structure
*/
b->order = (link_t *) (&b[1]);
91,15 → 92,14
b->data = data;
}
 
/** Check if buddy system can allocate block.
/** Check if buddy system can allocate block
*
* @param b Buddy system pointer.
* @param i Size of the block (2^i).
* @param b Buddy system pointer
* @param i Size of the block (2^i)
*
* @return True if block can be allocated.
* @return True if block can be allocated
*/
bool buddy_system_can_alloc(buddy_system_t *b, uint8_t i)
{
bool buddy_system_can_alloc(buddy_system_t *b, uint8_t i) {
uint8_t k;
/*
106,13 → 106,12
* If requested block is greater then maximal block
* we know immediatly that we cannot satisfy the request.
*/
if (i > b->max_order)
return false;
if (i > b->max_order) return false;
 
/*
* Check if any bigger or equal order has free elements
*/
for (k = i; k <= b->max_order; k++) {
for (k=i; k <= b->max_order; k++) {
if (!list_empty(&b->order[k])) {
return true;
}
119,11 → 118,12
}
return false;
}
 
/** Allocate PARTICULAR block from buddy system.
/** Allocate PARTICULAR block from buddy system
*
* @return Block of data or NULL if no such block was found.
* @ return Block of data or NULL if no such block was found
*/
link_t *buddy_system_alloc_block(buddy_system_t *b, link_t *block)
{
134,7 → 134,7
ASSERT(left);
list_remove(left);
while (1) {
if (!b->op->get_order(b, left)) {
if (! b->op->get_order(b,left)) {
b->op->mark_busy(b, left);
return left;
}
142,8 → 142,8
order = b->op->get_order(b, left);
 
right = b->op->bisect(b, left);
b->op->set_order(b, left, order - 1);
b->op->set_order(b, right, order - 1);
b->op->set_order(b, left, order-1);
b->op->set_order(b, right, order-1);
 
tmp = b->op->find_block(b, block, BUDDY_SYSTEM_INNER_BLOCK);
 
160,10 → 160,10
 
/** Allocate block from buddy system.
*
* @param b Buddy system pointer.
* @param i Returned block will be 2^i big.
* @param b Buddy system pointer.
* @param i Returned block will be 2^i big.
*
* @return Block of data represented by link_t.
* @return Block of data represented by link_t.
*/
link_t *buddy_system_alloc(buddy_system_t *b, uint8_t i)
{
217,12 → 217,13
buddy_system_free(b, hlp);
return res;
}
 
/** Return block to buddy system.
*
* @param b Buddy system pointer.
* @param block Block to return.
* @param b Buddy system pointer.
* @param block Block to return.
*/
void buddy_system_free(buddy_system_t *b, link_t *block)
{
266,8 → 267,7
b->op->set_order(b, hlp, i + 1);
 
/*
* Recursively add the coalesced block to the list of
* order i + 1.
* Recursively add the coalesced block to the list of order i + 1.
*/
buddy_system_free(b, hlp);
return;
278,7 → 278,46
* Insert block into the list of order i.
*/
list_append(block, &b->order[i]);
 
}
 
/** Prints out structure of buddy system
*
* @param b Pointer to buddy system
* @param elem_size Element size
*/
void buddy_system_structure_print(buddy_system_t *b, size_t elem_size) {
index_t i;
count_t cnt, elem_count = 0, block_count = 0;
link_t * cur;
 
printf("Order\tBlocks\tSize \tBlock size\tElems per block\n");
printf("-----\t------\t--------\t----------\t---------------\n");
for (i=0;i <= b->max_order; i++) {
cnt = 0;
if (!list_empty(&b->order[i])) {
for (cur = b->order[i].next; cur != &b->order[i]; cur = cur->next)
cnt++;
}
printf("#%zd\t%5zd\t%7zdK\t%8zdK\t%6zd\t", i, cnt, (cnt * (1 << i) * elem_size) >> 10, ((1 << i) * elem_size) >> 10, 1 << i);
if (!list_empty(&b->order[i])) {
for (cur = b->order[i].next; cur != &b->order[i]; cur = cur->next) {
b->op->print_id(b, cur);
printf(" ");
}
}
printf("\n");
block_count += cnt;
elem_count += (1 << i) * cnt;
}
printf("-----\t------\t--------\t----------\t---------------\n");
printf("Buddy system contains %zd free elements (%zd blocks)\n" , elem_count, block_count);
 
}
 
/** @}
*/
/branches/arm/kernel/generic/src/mm/backend_phys.c
32,8 → 32,7
 
/**
* @file
* @brief Backend for address space areas backed by continuous physical
* memory.
* @brief Backend for address space areas backed by continuous physical memory.
*/
 
#include <debug.h>
63,8 → 62,7
* @param addr Faulting virtual address.
* @param access Access mode that caused the fault (i.e. read/write/exec).
*
* @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK on success (i.e.
* serviced).
* @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK on success (i.e. serviced).
*/
int phys_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access)
{
74,10 → 72,9
return AS_PF_FAULT;
 
ASSERT(addr - area->base < area->backend_data.frames * FRAME_SIZE);
page_mapping_insert(AS, addr, base + (addr - area->base),
as_area_get_flags(area));
page_mapping_insert(AS, addr, base + (addr - area->base), as_area_get_flags(area));
if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
panic("Cannot insert used space.");
panic("Could not insert used space.\n");
 
return AS_PF_OK;
}
/branches/arm/kernel/generic/src/mm/page.c
40,28 → 40,11
* They however, define the single interface.
*/
 
/*
* Note on memory prefetching and updating memory mappings, also described in:
* AMD x86-64 Architecture Programmer's Manual, Volume 2, System Programming,
* 7.2.1 Special Coherency Considerations.
*
* The processor which modifies a page table mapping can access prefetched data
* from the old mapping. In order to prevent this, we place a memory barrier
* after a mapping is updated.
*
* We assume that the other processors are either not using the mapping yet
* (i.e. during the bootstrap) or are executing the TLB shootdown code. While
* we don't care much about the former case, the processors in the latter case
* will do an implicit serialization by virtue of running the TLB shootdown
* interrupt handler.
*/
 
#include <mm/page.h>
#include <arch/mm/page.h>
#include <arch/mm/asid.h>
#include <mm/as.h>
#include <mm/frame.h>
#include <arch/barrier.h>
#include <arch/types.h>
#include <arch/asm.h>
#include <memstr.h>
82,8 → 65,8
* considering possible crossings
* of page boundaries.
*
* @param s Address of the structure.
* @param size Size of the structure.
* @param s Address of the structure.
* @param size Size of the structure.
*/
void map_structure(uintptr_t s, size_t size)
{
93,11 → 76,8
cnt = length / PAGE_SIZE + (length % PAGE_SIZE > 0);
 
for (i = 0; i < cnt; i++)
page_mapping_insert(AS_KERNEL, s + i * PAGE_SIZE,
s + i * PAGE_SIZE, PAGE_NOT_CACHEABLE | PAGE_WRITE);
page_mapping_insert(AS_KERNEL, s + i * PAGE_SIZE, s + i * PAGE_SIZE, PAGE_NOT_CACHEABLE);
 
/* Repel prefetched accesses to the old mapping. */
memory_barrier();
}
 
/** Insert mapping of page to frame.
107,11 → 87,10
*
* The page table must be locked and interrupts must be disabled.
*
* @param as Address space to wich page belongs.
* @param page Virtual address of the page to be mapped.
* @param frame Physical address of memory frame to which the mapping is
* done.
* @param flags Flags to be used for mapping.
* @param as Address space to wich page belongs.
* @param page Virtual address of the page to be mapped.
* @param frame Physical address of memory frame to which the mapping is done.
* @param flags Flags to be used for mapping.
*/
void page_mapping_insert(as_t *as, uintptr_t page, uintptr_t frame, int flags)
{
119,9 → 98,6
ASSERT(page_mapping_operations->mapping_insert);
page_mapping_operations->mapping_insert(as, page, frame, flags);
/* Repel prefetched accesses to the old mapping. */
memory_barrier();
}
 
/** Remove mapping of page.
132,8 → 108,8
*
* The page table must be locked and interrupts must be disabled.
*
* @param as Address space to wich page belongs.
* @param page Virtual address of the page to be demapped.
* @param as Address space to wich page belongs.
* @param page Virtual address of the page to be demapped.
*/
void page_mapping_remove(as_t *as, uintptr_t page)
{
141,9 → 117,6
ASSERT(page_mapping_operations->mapping_remove);
page_mapping_operations->mapping_remove(as, page);
 
/* Repel prefetched accesses to the old mapping. */
memory_barrier();
}
 
/** Find mapping for virtual page
152,11 → 125,10
*
* The page table must be locked and interrupts must be disabled.
*
* @param as Address space to wich page belongs.
* @param page Virtual page.
* @param as Address space to wich page belongs.
* @param page Virtual page.
*
* @return NULL if there is no such mapping; requested mapping
* otherwise.
* @return NULL if there is no such mapping; requested mapping otherwise.
*/
pte_t *page_mapping_find(as_t *as, uintptr_t page)
{
/branches/arm/kernel/generic/src/mm/backend_elf.c
48,7 → 48,6
#include <memstr.h>
#include <macros.h>
#include <arch.h>
#include <arch/barrier.h>
 
#ifdef CONFIG_VIRT_IDX_DCACHE
#include <arch/mm/cache.h>
68,13 → 67,11
*
* The address space area and page tables must be already locked.
*
* @param area Pointer to the address space area.
* @param addr Faulting virtual address.
* @param access Access mode that caused the fault (i.e.
* read/write/exec).
* @param area Pointer to the address space area.
* @param addr Faulting virtual address.
* @param access Access mode that caused the fault (i.e. read/write/exec).
*
* @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK
* on success (i.e. serviced).
* @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK on success (i.e. serviced).
*/
int elf_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access)
{
81,25 → 78,17
elf_header_t *elf = area->backend_data.elf;
elf_segment_header_t *entry = area->backend_data.segment;
btree_node_t *leaf;
uintptr_t base, frame, page, start_anon;
size_t i;
bool dirty = false;
uintptr_t base, frame;
index_t i;
 
if (!as_area_check_access(area, access))
return AS_PF_FAULT;
 
ASSERT((addr >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) &&
(addr < entry->p_vaddr + entry->p_memsz));
i = (addr - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH;
base = (uintptr_t)
(((void *) elf) + ALIGN_DOWN(entry->p_offset, PAGE_SIZE));
ASSERT((addr >= entry->p_vaddr) && (addr < entry->p_vaddr + entry->p_memsz));
i = (addr - entry->p_vaddr) >> PAGE_WIDTH;
base = (uintptr_t) (((void *) elf) + entry->p_offset);
ASSERT(ALIGN_UP(base, FRAME_SIZE) == base);
 
/* Virtual address of faulting page*/
page = ALIGN_DOWN(addr, PAGE_SIZE);
 
/* Virtual address of the end of initialized part of segment */
start_anon = entry->p_vaddr + entry->p_filesz;
 
if (area->sh_info) {
bool found = false;
 
106,12 → 95,12
/*
* The address space area is shared.
*/
mutex_lock(&area->sh_info->lock);
frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
page - area->base, &leaf);
ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf);
if (!frame) {
unsigned int i;
int i;
 
/*
* Workaround for valid NULL address.
118,7 → 107,7
*/
 
for (i = 0; i < leaf->keys; i++) {
if (leaf->key[i] == page - area->base) {
if (leaf->key[i] == ALIGN_DOWN(addr, PAGE_SIZE)) {
found = true;
break;
}
126,20 → 115,19
}
if (frame || found) {
frame_reference_add(ADDR2PFN(frame));
page_mapping_insert(AS, addr, frame,
as_area_get_flags(area));
if (!used_space_insert(area, page, 1))
panic("Cannot insert used space.");
page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
panic("Could not insert used space.\n");
mutex_unlock(&area->sh_info->lock);
return AS_PF_OK;
}
}
 
/*
* The area is either not shared or the pagemap does not contain the
* mapping.
* The area is either not shared or the pagemap does not contain the mapping.
*/
if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {
if (ALIGN_DOWN(addr, PAGE_SIZE) + PAGE_SIZE < entry->p_vaddr + entry->p_filesz) {
/*
* Initialized portion of the segment. The memory is backed
* directly by the content of the ELF image. Pages are
150,17 → 138,18
*/
if (entry->p_flags & PF_W) {
frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
memcpy((void *) PA2KA(frame),
(void *) (base + i * FRAME_SIZE), FRAME_SIZE);
if (entry->p_flags & PF_X) {
smc_coherence_block((void *) PA2KA(frame),
FRAME_SIZE);
memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), FRAME_SIZE);
if (area->sh_info) {
frame_reference_add(ADDR2PFN(frame));
btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE) - area->base,
(void *) frame, leaf);
}
dirty = true;
 
} else {
frame = KA2PA(base + i * FRAME_SIZE);
frame = KA2PA(base + i*FRAME_SIZE);
}
} else if (page >= start_anon) {
} else if (ALIGN_DOWN(addr, PAGE_SIZE) >= ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) {
/*
* This is the uninitialized portion of the segment.
* It is not physically present in the ELF image.
168,53 → 157,40
* and cleared.
*/
frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
dirty = true;
memsetb(PA2KA(frame), FRAME_SIZE, 0);
 
if (area->sh_info) {
frame_reference_add(ADDR2PFN(frame));
btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE) - area->base,
(void *) frame, leaf);
}
 
} else {
size_t pad_lo, pad_hi;
size_t size;
/*
* The mixed case.
*
* The middle part is backed by the ELF image and
* the lower and upper parts are anonymous memory.
* (The segment can be and often is shorter than 1 page).
* The lower part is backed by the ELF image and
* the upper part is anonymous memory.
*/
if (page < entry->p_vaddr)
pad_lo = entry->p_vaddr - page;
else
pad_lo = 0;
size = entry->p_filesz - (i<<PAGE_WIDTH);
frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
memsetb(PA2KA(frame) + size, FRAME_SIZE - size, 0);
memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), size);
 
if (start_anon < page + PAGE_SIZE)
pad_hi = page + PAGE_SIZE - start_anon;
else
pad_hi = 0;
 
frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
memcpy((void *) (PA2KA(frame) + pad_lo),
(void *) (base + i * FRAME_SIZE + pad_lo),
FRAME_SIZE - pad_lo - pad_hi);
if (entry->p_flags & PF_X) {
smc_coherence_block((void *) (PA2KA(frame) + pad_lo),
FRAME_SIZE - pad_lo - pad_hi);
if (area->sh_info) {
frame_reference_add(ADDR2PFN(frame));
btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE) - area->base,
(void *) frame, leaf);
}
memsetb((void *) PA2KA(frame), pad_lo, 0);
memsetb((void *) (PA2KA(frame) + FRAME_SIZE - pad_hi), pad_hi,
0);
dirty = true;
}
 
if (dirty && area->sh_info) {
frame_reference_add(ADDR2PFN(frame));
btree_insert(&area->sh_info->pagemap, page - area->base,
(void *) frame, leaf);
}
 
if (area->sh_info)
mutex_unlock(&area->sh_info->lock);
 
page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
if (!used_space_insert(area, page, 1))
panic("Cannot insert used space.");
if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
panic("Could not insert used space.\n");
 
return AS_PF_OK;
}
223,10 → 199,9
*
* The address space area and page tables must be already locked.
*
* @param area Pointer to the address space area.
* @param page Page that is mapped to frame. Must be aligned to
* PAGE_SIZE.
* @param frame Frame to be released.
* @param area Pointer to the address space area.
* @param page Page that is mapped to frame. Must be aligned to PAGE_SIZE.
* @param frame Frame to be released.
*
*/
void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame)
233,31 → 208,34
{
elf_header_t *elf = area->backend_data.elf;
elf_segment_header_t *entry = area->backend_data.segment;
uintptr_t base, start_anon;
size_t i;
 
ASSERT((page >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) &&
(page < entry->p_vaddr + entry->p_memsz));
i = (page - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH;
base = (uintptr_t) (((void *) elf) +
ALIGN_DOWN(entry->p_offset, FRAME_SIZE));
start_anon = entry->p_vaddr + entry->p_filesz;
 
if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {
uintptr_t base;
index_t i;
ASSERT((page >= entry->p_vaddr) && (page < entry->p_vaddr + entry->p_memsz));
i = (page - entry->p_vaddr) >> PAGE_WIDTH;
base = (uintptr_t) (((void *) elf) + entry->p_offset);
ASSERT(ALIGN_UP(base, FRAME_SIZE) == base);
if (page + PAGE_SIZE < ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) {
if (entry->p_flags & PF_W) {
/*
* Free the frame with the copy of writable segment
* data.
* Free the frame with the copy of writable segment data.
*/
frame_free(frame);
#ifdef CONFIG_VIRT_IDX_DCACHE
dcache_flush_frame(page, frame);
#endif
}
} else {
/*
* The frame is either anonymous memory or the mixed case (i.e.
* lower part is backed by the ELF image and the upper is
* anonymous). In any case, a frame needs to be freed.
*/
frame_free(frame);
* The frame is either anonymous memory or the mixed case (i.e. lower
* part is backed by the ELF image and the upper is anonymous).
* In any case, a frame needs to be freed.
*/
frame_free(frame);
#ifdef CONFIG_VIRT_IDX_DCACHE
dcache_flush_frame(page, frame);
#endif
}
}
 
269,7 → 247,7
*
* The address space and address space area must be locked prior to the call.
*
* @param area Address space area.
* @param area Address space area.
*/
void elf_share(as_area_t *area)
{
282,12 → 260,10
* Find the node in which to start linear search.
*/
if (area->flags & AS_AREA_WRITE) {
node = list_get_instance(area->used_space.leaf_head.next,
btree_node_t, leaf_link);
node = list_get_instance(area->used_space.leaf_head.next, btree_node_t, leaf_link);
} else {
(void) btree_search(&area->sh_info->pagemap, start_anon, &leaf);
node = btree_leaf_node_left_neighbour(&area->sh_info->pagemap,
leaf);
node = btree_leaf_node_left_neighbour(&area->sh_info->pagemap, leaf);
if (!node)
node = leaf;
}
296,16 → 272,15
* Copy used anonymous portions of the area to sh_info's page map.
*/
mutex_lock(&area->sh_info->lock);
for (cur = &node->leaf_link; cur != &area->used_space.leaf_head;
cur = cur->next) {
unsigned int i;
for (cur = &node->leaf_link; cur != &area->used_space.leaf_head; cur = cur->next) {
int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
uintptr_t base = node->key[i];
size_t count = (size_t) node->value[i];
unsigned int j;
count_t count = (count_t) node->value[i];
int j;
/*
* Skip read-only areas of used space that are backed
312,8 → 287,7
* by the ELF image.
*/
if (!(area->flags & AS_AREA_WRITE))
if (base >= entry->p_vaddr &&
base + count * PAGE_SIZE <= start_anon)
if (base + count*PAGE_SIZE <= start_anon)
continue;
for (j = 0; j < count; j++) {
320,27 → 294,19
pte_t *pte;
/*
* Skip read-only pages that are backed by the
* ELF image.
* Skip read-only pages that are backed by the ELF image.
*/
if (!(area->flags & AS_AREA_WRITE))
if (base >= entry->p_vaddr &&
base + (j + 1) * PAGE_SIZE <=
start_anon)
if (base + (j + 1)*PAGE_SIZE <= start_anon)
continue;
page_table_lock(area->as, false);
pte = page_mapping_find(area->as,
base + j * PAGE_SIZE);
ASSERT(pte && PTE_VALID(pte) &&
PTE_PRESENT(pte));
btree_insert(&area->sh_info->pagemap,
(base + j * PAGE_SIZE) - area->base,
(void *) PTE_GET_FRAME(pte), NULL);
pte = page_mapping_find(area->as, base + j*PAGE_SIZE);
ASSERT(pte && PTE_VALID(pte) && PTE_PRESENT(pte));
btree_insert(&area->sh_info->pagemap, (base + j*PAGE_SIZE) - area->base,
(void *) PTE_GET_FRAME(pte), NULL);
page_table_unlock(area->as, false);
 
pfn_t pfn = ADDR2PFN(PTE_GET_FRAME(pte));
frame_reference_add(pfn);
frame_reference_add(ADDR2PFN(PTE_GET_FRAME(pte)));
}
}
/branches/arm/kernel/generic/src/lib/string.c
File deleted
/branches/arm/kernel/generic/src/lib/objc.c
0,0 → 1,60
/*
* Copyright (c) 2007 Martin Decky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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 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.
*/
 
/** @addtogroup generic
* @{
*/
 
/**
* @file
* @brief Objective C run-time environment.
*
* This file containts the (growing subset of)
* Objective C run-time environment. The code currently
* relies on the external libobjc library, but this
* dependency will be removed eventually.
*/
 
#include <lib/objc.h>
 
@implementation base_t
 
+ (id) new
{
return class_create_instance(self);
}
 
- (id) free
{
return object_dispose(self);
}
 
@end
 
/** @}
*/
/branches/arm/kernel/generic/src/lib/objc_ext.c
0,0 → 1,174
/*
* Copyright (c) 2007 Martin Decky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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 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.
*/
 
/** @addtogroup generic
* @{
*/
 
/**
* @file
* @brief Objective C bindings.
*
* This file provides architecture independent binding
* functions which are needed to link with libobjc run-time
* library. Many of the functions are just dummy.
*/
 
#include <lib/objc_ext.h>
#include <panic.h>
#include <arch/memstr.h>
#include <mm/slab.h>
 
void *stderr;
 
static unsigned short __ctype_b[384] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2,
2, 8195, 8194, 8194, 8194, 8194, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
24577, 49156, 49156, 49156, 49156, 49156, 49156, 49156,
49156, 49156, 49156, 49156, 49156, 49156, 49156, 49156,
55304, 55304, 55304, 55304, 55304, 55304, 55304, 55304,
55304, 55304, 49156, 49156, 49156, 49156, 49156, 49156,
49156, 54536, 54536, 54536, 54536, 54536, 54536, 50440,
50440, 50440, 50440, 50440, 50440, 50440, 50440, 50440,
50440, 50440, 50440, 50440, 50440, 50440, 50440, 50440,
50440, 50440, 50440, 49156, 49156, 49156, 49156, 49156,
49156, 54792, 54792, 54792, 54792, 54792, 54792, 50696,
50696, 50696, 50696, 50696, 50696, 50696, 50696, 50696,
50696, 50696, 50696, 50696, 50696, 50696, 50696, 50696,
50696, 50696, 50696, 49156, 49156, 49156, 49156, 2,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
 
static const unsigned short *__ctype_b_ptr = __ctype_b + 128;
 
void __assert_fail(const char *assertion, const char *file, unsigned int line, const char *function)
{
panic("Run-time assertion (%s:%d:%s) failed (%s)", file, line, function ? function : "", assertion);
}
 
void abort(void)
{
panic("Run-time scheduled abort");
}
 
void *fopen(const char *path, const char *mode)
{
return NULL;
}
 
size_t fread(void *ptr, size_t size, size_t nmemb, void *stream)
{
return 0;
}
 
size_t fwrite(const void *ptr, size_t size, size_t nmemb, void *stream)
{
return 0;
}
 
int fflush(void *stream)
{
return 0;
}
 
int feof(void *stream)
{
return 1;
}
 
int fclose(void *stream)
{
return 0;
}
 
int vfprintf(void *stream, const char *format, va_list ap)
{
return 0;
}
 
int sscanf(const char *str, const char *format, ...)
{
return 0;
}
 
const unsigned short **__ctype_b_loc(void)
{
return &__ctype_b_ptr;
}
 
long int __strtol_internal(const char *__nptr, char **__endptr, int __base, int __group)
{
return 0;
}
 
void *memset(void *s, int c, size_t n)
{
memsetb((uintptr_t) s, n, c);
return s;
}
 
void *calloc(size_t nmemb, size_t size)
{
return malloc(nmemb * size, 0);
}
 
/** @}
*/
/branches/arm/kernel/generic/src/lib/memstr.c
1,6 → 1,5
/*
* Copyright (c) 2001-2004 Jakub Jermar
* Copyright (c) 2008 Jiri Svoboda
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
35,10 → 34,12
* @file
* @brief Memory string operations.
*
* This file provides architecture independent functions to manipulate blocks of
* memory. These functions are optimized as much as generic functions of this
* type can be. However, architectures are free to provide even more optimized
* versions of these functions.
* This file provides architecture independent functions
* to manipulate blocks of memory. These functions
* are optimized as much as generic functions of
* this type can be. However, architectures are
* free to provide even more optimized versions of these
* functions.
*/
 
#include <memstr.h>
45,119 → 46,92
#include <arch/types.h>
#include <align.h>
 
/** Copy block of memory.
/** Copy block of memory
*
* Copy cnt bytes from src address to dst address. The copying is done
* word-by-word and then byte-by-byte. The source and destination memory areas
* cannot overlap.
* Copy cnt bytes from src address to dst address.
* The copying is done word-by-word and then byte-by-byte.
* The source and destination memory areas cannot overlap.
*
* @param src Source address to copy from.
* @param dst Destination address to copy to.
* @param cnt Number of bytes to copy.
* @param src Origin address to copy from.
* @param dst Origin address to copy to.
* @param cnt Number of bytes to copy.
*
* @return Destination address.
*/
void *_memcpy(void *dst, const void *src, size_t cnt)
void *_memcpy(void * dst, const void *src, size_t cnt)
{
unsigned int i, j;
int i, j;
if (ALIGN_UP((uintptr_t) src, sizeof(unative_t)) != (uintptr_t) src ||
ALIGN_UP((uintptr_t) dst, sizeof(unative_t)) != (uintptr_t) dst) {
ALIGN_UP((uintptr_t) dst, sizeof(unative_t)) != (uintptr_t) dst) {
for (i = 0; i < cnt; i++)
((uint8_t *) dst)[i] = ((uint8_t *) src)[i];
} else {
for (i = 0; i < cnt / sizeof(unative_t); i++)
for (i = 0; i < cnt/sizeof(unative_t); i++)
((unative_t *) dst)[i] = ((unative_t *) src)[i];
for (j = 0; j < cnt % sizeof(unative_t); j++)
((uint8_t *)(((unative_t *) dst) + i))[j] =
((uint8_t *)(((unative_t *) src) + i))[j];
for (j = 0; j < cnt%sizeof(unative_t); j++)
((uint8_t *)(((unative_t *) dst) + i))[j] = ((uint8_t *)(((unative_t *) src) + i))[j];
}
return (char *) dst;
return (char *) src;
}
 
/** Move memory block with possible overlapping.
/** Fill block of memory
*
* Copy cnt bytes from src address to dst address. The source and destination
* memory areas may overlap.
* Fill cnt bytes at dst address with the value x.
* The filling is done byte-by-byte.
*
* @param src Source address to copy from.
* @param dst Destination address to copy to.
* @param cnt Number of bytes to copy.
* @param dst Origin address to fill.
* @param cnt Number of bytes to fill.
* @param x Value to fill.
*
* @return Destination address.
*/
void *memmove(void *dst, const void *src, size_t n)
void _memsetb(uintptr_t dst, size_t cnt, uint8_t x)
{
const uint8_t *sp;
uint8_t *dp;
 
/* Nothing to do? */
if (src == dst)
return dst;
 
/* Non-overlapping? */
if (dst >= src + n || src >= dst + n) {
return memcpy(dst, src, n);
}
 
/* Which direction? */
if (src > dst) {
/* Forwards. */
sp = src;
dp = dst;
 
while (n-- != 0)
*dp++ = *sp++;
} else {
/* Backwards. */
sp = src + (n - 1);
dp = dst + (n - 1);
 
while (n-- != 0)
*dp-- = *sp--;
}
 
return dst;
int i;
uint8_t *p = (uint8_t *) dst;
for (i = 0; i < cnt; i++)
p[i] = x;
}
 
/** Fill block of memory
*
* Fill cnt bytes at dst address with the value x. The filling is done
* byte-by-byte.
* Fill cnt words at dst address with the value x.
* The filling is done word-by-word.
*
* @param dst Destination address to fill.
* @param cnt Number of bytes to fill.
* @param x Value to fill.
* @param dst Origin address to fill.
* @param cnt Number of words to fill.
* @param x Value to fill.
*
*/
void _memsetb(void *dst, size_t cnt, uint8_t x)
void _memsetw(uintptr_t dst, size_t cnt, uint16_t x)
{
unsigned int i;
uint8_t *p = (uint8_t *) dst;
int i;
uint16_t *p = (uint16_t *) dst;
for (i = 0; i < cnt; i++)
p[i] = x;
p[i] = x;
}
 
/** Fill block of memory.
/** Copy string
*
* Fill cnt words at dst address with the value x. The filling is done
* word-by-word.
* Copy string from src address to dst address.
* The copying is done char-by-char until the null
* character. The source and destination memory areas
* cannot overlap.
*
* @param dst Destination address to fill.
* @param cnt Number of words to fill.
* @param x Value to fill.
* @param src Origin string to copy from.
* @param dst Origin string to copy to.
*
*/
void _memsetw(void *dst, size_t cnt, uint16_t x)
char *strcpy(char *dest, const char *src)
{
unsigned int i;
uint16_t *p = (uint16_t *) dst;
char *orig = dest;
for (i = 0; i < cnt; i++)
p[i] = x;
while ((*(dest++) = *(src++)));
return orig;
}
 
/** @}
/branches/arm/kernel/generic/src/lib/func.c
47,7 → 47,7
 
/** Halt wrapper
*
* Set halt flag and halt the CPU.
* Set halt flag and halt the cpu.
*
*/
void halt()
54,7 → 54,9
{
#ifdef CONFIG_DEBUG
bool rundebugger = false;
 
// TODO test_and_set not defined on all arches
// if (!test_and_set(&haltstate))
if (!atomic_get(&haltstate)) {
atomic_set(&haltstate, 1);
rundebugger = true;
62,22 → 64,118
#else
atomic_set(&haltstate, 1);
#endif
 
interrupts_disable();
#if (defined(CONFIG_DEBUG)) && (defined(CONFIG_KCONSOLE))
if ((rundebugger) && (kconsole_check_poll()))
kconsole("panic", "\nLast resort kernel console ready.\n", false);
#endif
#ifdef CONFIG_DEBUG
if (rundebugger) {
printf("\n");
kconsole("panic"); /* Run kconsole as a last resort to user */
}
#endif
if (CPU)
printf("cpu%u: halted\n", CPU->id);
printf("cpu%d: halted\n", CPU->id);
else
printf("cpu: halted\n");
cpu_halt();
}
 
/** Return number of characters in a string.
*
* @param str NULL terminated string.
*
* @return Number of characters in str.
*/
size_t strlen(const char *str)
{
int i;
for (i = 0; str[i]; i++)
;
return i;
}
 
/** Compare two NULL terminated strings
*
* Do a char-by-char comparison of two NULL terminated strings.
* The strings are considered equal iff they consist of the same
* characters on the minimum of their lengths.
*
* @param src First string to compare.
* @param dst Second string to compare.
*
* @return 0 if the strings are equal, -1 if first is smaller, 1 if second smaller.
*
*/
int strcmp(const char *src, const char *dst)
{
for (; *src && *dst; src++, dst++) {
if (*src < *dst)
return -1;
if (*src > *dst)
return 1;
}
if (*src == *dst)
return 0;
if (!*src)
return -1;
return 1;
}
 
 
/** Compare two NULL terminated strings
*
* Do a char-by-char comparison of two NULL terminated strings.
* The strings are considered equal iff they consist of the same
* characters on the minimum of their lengths and specified maximal
* length.
*
* @param src First string to compare.
* @param dst Second string to compare.
* @param len Maximal length for comparison.
*
* @return 0 if the strings are equal, -1 if first is smaller, 1 if second smaller.
*
*/
int strncmp(const char *src, const char *dst, size_t len)
{
int i;
for (i = 0; *src && *dst && i < len; src++, dst++, i++) {
if (*src < *dst)
return -1;
if (*src > *dst)
return 1;
}
if (i == len || *src == *dst)
return 0;
if (!*src)
return -1;
return 1;
}
 
 
 
/** Copy NULL terminated string.
*
* Copy at most 'len' characters from string 'src' to 'dest'.
* If 'src' is shorter than 'len', '\0' is inserted behind the
* last copied character.
*
* @param src Source string.
* @param dest Destination buffer.
* @param len Size of destination buffer.
*/
void strncpy(char *dest, const char *src, size_t len)
{
int i;
for (i = 0; i < len; i++) {
if (!(dest[i] = src[i]))
return;
}
dest[i-1] = '\0';
}
 
/** Convert ascii representation to unative_t
*
* Supports 0x for hexa & 0 for octal notation.
125,23 → 223,20
 
void order(const uint64_t val, uint64_t *rv, char *suffix)
{
if (val > 10000000000000000000ULL) {
*rv = val / 1000000000000000000ULL;
*suffix = 'Z';
} else if (val > 1000000000000000000ULL) {
*rv = val / 1000000000000000ULL;
if (val > 1000000000000000000LL) {
*rv = val / 1000000000000000LL;
*suffix = 'E';
} else if (val > 1000000000000000ULL) {
*rv = val / 1000000000000ULL;
} else if (val > 1000000000000000LL) {
*rv = val / 1000000000000LL;
*suffix = 'T';
} else if (val > 1000000000000ULL) {
*rv = val / 1000000000ULL;
} else if (val > 1000000000000LL) {
*rv = val / 1000000000LL;
*suffix = 'G';
} else if (val > 1000000000ULL) {
*rv = val / 1000000ULL;
} else if (val > 1000000000LL) {
*rv = val / 1000000LL;
*suffix = 'M';
} else if (val > 1000000ULL) {
*rv = val / 1000ULL;
} else if (val > 1000000LL) {
*rv = val / 1000LL;
*suffix = 'k';
} else {
*rv = val;
/branches/arm/kernel/generic/src/lib/elf.c
56,37 → 56,29
"irrecoverable error"
};
 
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf,
as_t *as, int flags);
static int section_header(elf_section_header_t *entry, elf_header_t *elf,
as_t *as);
static int load_segment(elf_segment_header_t *entry, elf_header_t *elf,
as_t *as);
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as);
static int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
 
/** ELF loader
*
* @param header Pointer to ELF header in memory
* @param as Created and properly mapped address space
* @param flags A combination of ELD_F_*
* @return EE_OK on success
*/
unsigned int elf_load(elf_header_t *header, as_t * as, int flags)
int elf_load(elf_header_t *header, as_t * as)
{
int i, rc;
 
/* Identify ELF */
if (header->e_ident[EI_MAG0] != ELFMAG0 ||
header->e_ident[EI_MAG1] != ELFMAG1 ||
header->e_ident[EI_MAG2] != ELFMAG2 ||
header->e_ident[EI_MAG3] != ELFMAG3) {
if (header->e_ident[EI_MAG0] != ELFMAG0 || header->e_ident[EI_MAG1] != ELFMAG1 ||
header->e_ident[EI_MAG2] != ELFMAG2 || header->e_ident[EI_MAG3] != ELFMAG3) {
return EE_INVALID;
}
/* Identify ELF compatibility */
if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
header->e_machine != ELF_MACHINE ||
header->e_ident[EI_VERSION] != EV_CURRENT ||
header->e_version != EV_CURRENT ||
if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING || header->e_machine != ELF_MACHINE ||
header->e_ident[EI_VERSION] != EV_CURRENT || header->e_version != EV_CURRENT ||
header->e_ident[EI_CLASS] != ELF_CLASS) {
return EE_INCOMPATIBLE;
}
101,17 → 93,9
if (header->e_type != ET_EXEC)
return EE_UNSUPPORTED;
 
/* Check if the ELF image starts on a page boundary */
if (ALIGN_UP((uintptr_t)header, PAGE_SIZE) != (uintptr_t)header)
return EE_UNSUPPORTED;
 
/* Walk through all segment headers and process them. */
for (i = 0; i < header->e_phnum; i++) {
elf_segment_header_t *seghdr;
 
seghdr = &((elf_segment_header_t *)(((uint8_t *) header) +
header->e_phoff))[i];
rc = segment_header(seghdr, header, as, flags);
rc = segment_header(&((elf_segment_header_t *)(((uint8_t *) header) + header->e_phoff))[i], header, as);
if (rc != EE_OK)
return rc;
}
118,11 → 102,7
 
/* Inspect all section headers and proccess them. */
for (i = 0; i < header->e_shnum; i++) {
elf_section_header_t *sechdr;
 
sechdr = &((elf_section_header_t *)(((uint8_t *) header) +
header->e_shoff))[i];
rc = section_header(sechdr, header, as);
rc = section_header(&((elf_section_header_t *)(((uint8_t *) header) + header->e_shoff))[i], header, as);
if (rc != EE_OK)
return rc;
}
136,9 → 116,9
*
* @return NULL terminated description of error.
*/
char *elf_error(unsigned int rc)
char *elf_error(int rc)
{
ASSERT(rc < sizeof(error_codes) / sizeof(char *));
ASSERT(rc < sizeof(error_codes)/sizeof(char *));
 
return error_codes[rc];
}
151,11 → 131,8
*
* @return EE_OK on success, error code otherwise.
*/
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf,
as_t *as, int flags)
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
{
char *interp;
 
switch (entry->p_type) {
case PT_NULL:
case PT_PHDR:
165,16 → 142,6
break;
case PT_DYNAMIC:
case PT_INTERP:
interp = (char *)elf + entry->p_offset;
/* FIXME */
/*if (memcmp((uintptr_t)interp, (uintptr_t)ELF_INTERP_ZSTR,
ELF_INTERP_ZLEN) != 0) {
return EE_UNSUPPORTED;
}*/
if ((flags & ELD_F_LOADER) == 0) {
return EE_LOADER;
}
break;
case PT_SHLIB:
case PT_NOTE:
case PT_LOPROC:
199,15 → 166,12
as_area_t *a;
int flags = 0;
mem_backend_data_t backend_data;
uintptr_t base;
size_t mem_sz;
backend_data.elf = elf;
backend_data.segment = entry;
 
if (entry->p_align > 1) {
if ((entry->p_offset % entry->p_align) !=
(entry->p_vaddr % entry->p_align)) {
if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) {
return EE_INVALID;
}
}
220,15 → 184,14
flags |= AS_AREA_READ;
flags |= AS_AREA_CACHEABLE;
 
/*
* Align vaddr down, inserting a little "gap" at the beginning.
* Adjust area size, so that its end remains in place.
/*
* Check if the virtual address starts on page boundary.
*/
base = ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE);
mem_sz = entry->p_memsz + (entry->p_vaddr - base);
if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr)
return EE_UNSUPPORTED;
 
a = as_area_create(as, flags, mem_sz, base,
AS_AREA_ATTR_NONE, &elf_backend, &backend_data);
a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE,
&elf_backend, &backend_data);
if (!a)
return EE_MEMORY;
247,20 → 210,9
*
* @return EE_OK on success, error code otherwise.
*/
static int section_header(elf_section_header_t *entry, elf_header_t *elf,
as_t *as)
static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as)
{
switch (entry->sh_type) {
case SHT_PROGBITS:
if (entry->sh_flags & SHF_TLS) {
/* .tdata */
}
break;
case SHT_NOBITS:
if (entry->sh_flags & SHF_TLS) {
/* .tbss */
}
break;
default:
break;
}
/branches/arm/kernel/generic/src/lib/rd.c
38,24 → 38,18
*/
 
#include <lib/rd.h>
#include <byteorder.h>
#include <arch/byteorder.h>
#include <mm/frame.h>
#include <sysinfo/sysinfo.h>
#include <ddi/ddi.h>
#include <align.h>
 
static parea_t rd_parea; /**< Physical memory area for rd. */
 
/**
* RAM disk initialization routine. At this point, the RAM disk memory is shared
* and information about the share is provided as sysinfo values to the
* userspace tasks.
*/
int init_rd(rd_header_t *header, size_t size)
int init_rd(rd_header * header, size_t size)
{
/* Identify RAM disk */
if ((header->magic[0] != RD_MAG0) || (header->magic[1] != RD_MAG1) ||
(header->magic[2] != RD_MAG2) || (header->magic[3] != RD_MAG3))
(header->magic[2] != RD_MAG2) || (header->magic[3] != RD_MAG3))
return RE_INVALID;
/* Identify version */
79,7 → 73,7
if ((hsize % FRAME_SIZE) || (dsize % FRAME_SIZE))
return RE_UNSUPPORTED;
if (hsize > size)
return RE_INVALID;
86,16 → 80,18
if ((uint64_t) hsize + dsize > size)
dsize = size - hsize;
rd_parea.pbase = ALIGN_DOWN((uintptr_t) KA2PA((void *) header + hsize),
FRAME_SIZE);
rd_parea.pbase = KA2PA((void *) header + hsize);
rd_parea.vbase = (uintptr_t) ((void *) header + hsize);
rd_parea.frames = SIZE2FRAMES(dsize);
rd_parea.cacheable = true;
ddi_parea_register(&rd_parea);
 
sysinfo_set_item_val("rd", NULL, true);
sysinfo_set_item_val("rd.header_size", NULL, hsize);
sysinfo_set_item_val("rd.size", NULL, dsize);
sysinfo_set_item_val("rd.address.physical", NULL,
(unative_t) KA2PA((void *) header + hsize));
sysinfo_set_item_val("rd.address.physical", NULL, (unative_t)
KA2PA((void *) header + hsize));
sysinfo_set_item_val("rd.address.color", NULL, (unative_t)
PAGE_COLOR((uintptr_t) header + hsize));
 
return RE_OK;
}
/branches/arm/kernel/generic/src/lib/sort.c
45,8 → 45,8
 
#define EBUFSIZE 32
 
void _qsort(void * data, size_t n, size_t e_size, int (* cmp) (void * a, void * b), void *tmp, void *pivot);
void _bubblesort(void * data, size_t n, size_t e_size, int (* cmp) (void * a, void * b), void *slot);
void _qsort(void * data, count_t n, size_t e_size, int (* cmp) (void * a, void * b), void *tmp, void *pivot);
void _bubblesort(void * data, count_t n, size_t e_size, int (* cmp) (void * a, void * b), void *slot);
 
/** Quicksort wrapper
*
61,7 → 61,7
* @param cmp Comparator function.
*
*/
void qsort(void * data, size_t n, size_t e_size, int (* cmp) (void * a, void * b))
void qsort(void * data, count_t n, size_t e_size, int (* cmp) (void * a, void * b))
{
uint8_t buf_tmp[EBUFSIZE];
uint8_t buf_pivot[EBUFSIZE];
93,20 → 93,17
* @param pivot Pointer to scratch memory buffer e_size bytes long.
*
*/
void _qsort(void * data, size_t n, size_t e_size, int (* cmp) (void * a, void * b), void *tmp, void *pivot)
void _qsort(void * data, count_t n, size_t e_size, int (* cmp) (void * a, void * b), void *tmp, void *pivot)
{
if (n > 4) {
unsigned int i = 0, j = n - 1;
int i = 0, j = n - 1;
 
memcpy(pivot, data, e_size);
 
while (1) {
while ((cmp(data + i * e_size, pivot) < 0) && (i < n))
i++;
while ((cmp(data + j * e_size, pivot) >= 0) && (j > 0))
j--;
if (i < j) {
while ((cmp(data + i * e_size, pivot) < 0) && i < n) i++;
while ((cmp(data + j * e_size, pivot) >=0) && j > 0) j--;
if (i<j) {
memcpy(tmp, data + i * e_size, e_size);
memcpy(data + i * e_size, data + j * e_size, e_size);
memcpy(data + j * e_size, tmp, e_size);
133,7 → 130,7
* @param cmp Comparator function.
*
*/
void bubblesort(void * data, size_t n, size_t e_size, int (* cmp) (void * a, void * b))
void bubblesort(void * data, count_t n, size_t e_size, int (* cmp) (void * a, void * b))
{
uint8_t buf_slot[EBUFSIZE];
void * slot = buf_slot;
160,7 → 157,7
* @param slot Pointer to scratch memory buffer e_size bytes long.
*
*/
void _bubblesort(void * data, size_t n, size_t e_size, int (* cmp) (void * a, void * b), void *slot)
void _bubblesort(void * data, count_t n, size_t e_size, int (* cmp) (void * a, void * b), void *slot)
{
bool done = false;
void * p;
/branches/arm/kernel/generic/src/syscall/syscall.c
32,116 → 32,115
 
/**
* @file
* @brief Syscall table and syscall wrappers.
* @brief Syscall table and syscall wrappers.
*/
 
#include <syscall/syscall.h>
#include <proc/thread.h>
#include <proc/task.h>
#include <proc/program.h>
#include <mm/as.h>
#include <print.h>
#include <putchar.h>
#include <errno.h>
#include <arch.h>
#include <debug.h>
#include <ddi/device.h>
#include <ipc/sysipc.h>
#include <synch/futex.h>
#include <synch/smc.h>
#include <ddi/ddi.h>
#include <ipc/event.h>
#include <security/cap.h>
#include <syscall/copy.h>
#include <sysinfo/sysinfo.h>
#include <console/console.h>
#include <udebug/udebug.h>
#include <console/klog.h>
 
/** Dispatch system call */
unative_t syscall_handler(unative_t a1, unative_t a2, unative_t a3,
unative_t a4, unative_t a5, unative_t a6, unative_t id)
/** Print using kernel facility
*
* Some simulators can print only through kernel. Userspace can use
* this syscall to facilitate it.
*/
static unative_t sys_io(int fd, const void * buf, size_t count)
{
unative_t rc;
size_t i;
char *data;
int rc;
 
#ifdef CONFIG_UDEBUG
bool debug;
if (count > PAGE_SIZE)
return ELIMIT;
 
/*
* Early check for undebugged tasks. We do not lock anything as this
* test need not be precise in either way.
*/
debug = THREAD->udebug.active;
data = (char *) malloc(count, 0);
if (!data)
return ENOMEM;
if (debug) {
udebug_syscall_event(a1, a2, a3, a4, a5, a6, id, 0, false);
rc = copy_from_uspace(data, buf, count);
if (rc) {
free(data);
return rc;
}
#endif
 
for (i = 0; i < count; i++)
putchar(data[i]);
free(data);
if (id < SYSCALL_END) {
rc = syscall_table[id](a1, a2, a3, a4, a5, a6);
} else {
printf("Task %" PRIu64": Unknown syscall %#" PRIxn, TASK->taskid, id);
return count;
}
 
/** Tell kernel to get keyboard/console access again */
static unative_t sys_debug_enable_console(void)
{
arch_grab_console();
return 0;
}
 
/** Dispatch system call */
unative_t syscall_handler(unative_t a1, unative_t a2, unative_t a3,
unative_t a4, unative_t id)
{
unative_t rc;
 
if (id < SYSCALL_END)
rc = syscall_table[id](a1, a2, a3, a4);
else {
klog_printf("TASK %lld: Unknown syscall id %d",TASK->taskid,id);
task_kill(TASK->taskid);
thread_exit();
}
if (THREAD->interrupted)
thread_exit();
#ifdef CONFIG_UDEBUG
if (debug) {
udebug_syscall_event(a1, a2, a3, a4, a5, a6, id, rc, true);
/*
* Stopping point needed for tasks that only invoke
* non-blocking system calls. Not needed if the task
* is not being debugged (it cannot block here).
*/
udebug_stoppable_begin();
udebug_stoppable_end();
}
#endif
return rc;
}
 
syshandler_t syscall_table[SYSCALL_END] = {
(syshandler_t) sys_klog,
(syshandler_t) sys_io,
(syshandler_t) sys_tls_set,
/* Thread and task related syscalls. */
(syshandler_t) sys_thread_create,
(syshandler_t) sys_thread_exit,
(syshandler_t) sys_thread_get_id,
(syshandler_t) sys_task_get_id,
(syshandler_t) sys_task_set_name,
(syshandler_t) sys_program_spawn_loader,
/* Synchronization related syscalls. */
(syshandler_t) sys_futex_sleep_timeout,
(syshandler_t) sys_futex_wakeup,
(syshandler_t) sys_smc_coherence,
/* Address space related syscalls. */
(syshandler_t) sys_as_area_create,
(syshandler_t) sys_as_area_resize,
(syshandler_t) sys_as_area_change_flags,
(syshandler_t) sys_as_area_destroy,
/* IPC related syscalls. */
(syshandler_t) sys_ipc_call_sync_fast,
(syshandler_t) sys_ipc_call_sync_slow,
(syshandler_t) sys_ipc_call_sync,
(syshandler_t) sys_ipc_call_async_fast,
(syshandler_t) sys_ipc_call_async_slow,
(syshandler_t) sys_ipc_call_async,
(syshandler_t) sys_ipc_answer_fast,
(syshandler_t) sys_ipc_answer_slow,
(syshandler_t) sys_ipc_answer,
(syshandler_t) sys_ipc_forward_fast,
(syshandler_t) sys_ipc_forward_slow,
(syshandler_t) sys_ipc_wait_for_call,
(syshandler_t) sys_ipc_hangup,
(syshandler_t) sys_ipc_register_irq,
(syshandler_t) sys_ipc_unregister_irq,
 
/* Event notification syscalls. */
(syshandler_t) sys_event_subscribe,
/* Capabilities related syscalls. */
(syshandler_t) sys_cap_grant,
148,7 → 147,6
(syshandler_t) sys_cap_revoke,
/* DDI related syscalls. */
(syshandler_t) sys_device_assign_devno,
(syshandler_t) sys_physmem_map,
(syshandler_t) sys_iospace_enable,
(syshandler_t) sys_preempt_control,
158,10 → 156,7
(syshandler_t) sys_sysinfo_value,
/* Debug calls */
(syshandler_t) sys_debug_enable_console,
(syshandler_t) sys_debug_disable_console,
(syshandler_t) sys_ipc_connect_kbox
(syshandler_t) sys_debug_enable_console
};
 
/** @}
/branches/arm/kernel/generic/src/main/shutdown.c
File deleted
/branches/arm/kernel/generic/src/main/kinit.c
32,7 → 32,7
 
/**
* @file
* @brief Kernel initialization thread.
* @brief Kernel initialization thread.
*
* This file contains kinit kernel thread which carries out
* high level system initialization.
47,7 → 47,6
#include <proc/scheduler.h>
#include <proc/task.h>
#include <proc/thread.h>
#include <proc/program.h>
#include <panic.h>
#include <func.h>
#include <cpu.h>
64,8 → 63,6
#include <security/cap.h>
#include <lib/rd.h>
#include <ipc/ipc.h>
#include <debug.h>
#include <string.h>
 
#ifdef CONFIG_SMP
#include <smp/smp.h>
74,15 → 71,6
#include <synch/waitq.h>
#include <synch/spinlock.h>
 
#define ALIVE_CHARS 4
 
#ifdef CONFIG_KCONSOLE
static char alive[ALIVE_CHARS] = "-\\|/";
#endif
 
#define INIT_PREFIX "init:"
#define INIT_PREFIX_LEN 5
 
/** Kernel initialization thread.
*
* kinit takes care of higher level kernel
93,19 → 81,16
*/
void kinit(void *arg)
{
thread_t *t;
 
#if defined(CONFIG_SMP) || defined(CONFIG_KCONSOLE)
thread_t *thread;
#endif
/*
* Detach kinit as nobody will call thread_join_timeout() on it.
*/
thread_detach(THREAD);
 
interrupts_disable();
#ifdef CONFIG_SMP
 
#ifdef CONFIG_SMP
if (config.cpu_count > 1) {
waitq_initialize(&ap_completion_wq);
/*
114,130 → 99,99
* not mess together with kcpulb threads.
* Just a beautification.
*/
thread = thread_create(kmp, NULL, TASK, THREAD_FLAG_WIRED, "kmp", true);
if (thread != NULL) {
spinlock_lock(&thread->lock);
thread->cpu = &cpus[0];
spinlock_unlock(&thread->lock);
thread_ready(thread);
if ((t = thread_create(kmp, NULL, TASK, THREAD_FLAG_WIRED,
"kmp", true))) {
spinlock_lock(&t->lock);
t->cpu = &cpus[0];
spinlock_unlock(&t->lock);
thread_ready(t);
} else
panic("Unable to create kmp thread.");
thread_join(thread);
thread_detach(thread);
panic("thread_create/kmp\n");
thread_join(t);
thread_detach(t);
}
#endif /* CONFIG_SMP */
/*
* Now that all CPUs are up, we can report what we've found.
*/
cpu_list();
 
#ifdef CONFIG_SMP
if (config.cpu_count > 1) {
size_t i;
unsigned int i;
/*
* For each CPU, create its load balancing thread.
*/
for (i = 0; i < config.cpu_count; i++) {
thread = thread_create(kcpulb, NULL, TASK, THREAD_FLAG_WIRED, "kcpulb", true);
if (thread != NULL) {
spinlock_lock(&thread->lock);
thread->cpu = &cpus[i];
spinlock_unlock(&thread->lock);
thread_ready(thread);
 
if ((t = thread_create(kcpulb, NULL, TASK,
THREAD_FLAG_WIRED, "kcpulb", true))) {
spinlock_lock(&t->lock);
t->cpu = &cpus[i];
spinlock_unlock(&t->lock);
thread_ready(t);
} else
printf("Unable to create kcpulb thread for cpu" PRIs "\n", i);
panic("thread_create/kcpulb\n");
 
}
}
#endif /* CONFIG_SMP */
 
/*
* At this point SMP, if present, is configured.
*/
arch_post_smp_init();
#ifdef CONFIG_KCONSOLE
if (stdin) {
/*
* Create kernel console.
*/
thread = thread_create(kconsole_thread, NULL, TASK, 0, "kconsole", false);
if (thread != NULL)
thread_ready(thread);
else
printf("Unable to create kconsole thread\n");
}
#endif /* CONFIG_KCONSOLE */
interrupts_enable();
 
/*
* Create user tasks, load RAM disk images.
* Create kernel console.
*/
size_t i;
program_t programs[CONFIG_INIT_TASKS];
t = thread_create(kconsole, (void *) "kconsole", TASK, 0, "kconsole", false);
if (t)
thread_ready(t);
else
panic("thread_create/kconsole\n");
 
interrupts_enable();
 
count_t i;
for (i = 0; i < init.cnt; i++) {
/*
* Run user tasks, load RAM disk images.
*/
if (init.tasks[i].addr % FRAME_SIZE) {
printf("init[%" PRIs "].addr is not frame aligned\n", i);
printf("init[%d].addr is not frame aligned", i);
continue;
}
/*
* Construct task name from the 'init:' prefix and the
* name stored in the init structure (if any).
*/
char namebuf[TASK_NAME_BUFLEN];
char *name;
name = init.tasks[i].name;
if (name[0] == 0)
name = "<unknown>";
ASSERT(TASK_NAME_BUFLEN >= INIT_PREFIX_LEN);
str_cpy(namebuf, TASK_NAME_BUFLEN, INIT_PREFIX);
str_cpy(namebuf + INIT_PREFIX_LEN,
TASK_NAME_BUFLEN - INIT_PREFIX_LEN, name);
 
int rc = program_create_from_image((void *) init.tasks[i].addr,
namebuf, &programs[i]);
if ((rc == 0) && (programs[i].task != NULL)) {
task_t *utask = task_run_program((void *) init.tasks[i].addr,
"uspace");
if (utask) {
/*
* Set capabilities to init userspace tasks.
*/
cap_set(programs[i].task, CAP_CAP | CAP_MEM_MANAGER |
cap_set(utask, CAP_CAP | CAP_MEM_MANAGER |
CAP_IO_MANAGER | CAP_PREEMPT_CONTROL | CAP_IRQ_REG);
if (!ipc_phone_0)
ipc_phone_0 = &programs[i].task->answerbox;
} else if (rc == 0) {
/* It was the program loader and was registered */
if (!ipc_phone_0)
ipc_phone_0 = &utask->answerbox;
} else {
/* RAM disk image */
int rd = init_rd((rd_header_t *) init.tasks[i].addr, init.tasks[i].size);
int rd = init_rd((rd_header *) init.tasks[i].addr,
init.tasks[i].size);
if (rd != RE_OK)
printf("Init binary %" PRIs " not used (error %d)\n", i, rd);
printf("Init binary %zd not used.\n", i);
}
}
/*
* Run user tasks.
*/
for (i = 0; i < init.cnt; i++) {
if (programs[i].task != NULL)
program_ready(&programs[i]);
}
#ifdef CONFIG_KCONSOLE
 
 
if (!stdin) {
thread_sleep(10);
printf("kinit: No stdin\nKernel alive: .");
unsigned int i = 0;
while (true) {
printf("\b%c", alive[i % ALIVE_CHARS]);
while (1) {
thread_sleep(1);
i++;
printf("kinit... ");
}
}
#endif /* CONFIG_KCONSOLE */
}
 
/** @}
/branches/arm/kernel/generic/src/main/main.c
32,7 → 32,7
 
/**
* @file
* @brief Main initialization kernel function for all processors.
* @brief Main initialization kernel function for all processors.
*
* During kernel boot, all processors, after architecture dependent
* initialization, start executing code found in this file. After
57,14 → 57,13
#include <proc/scheduler.h>
#include <proc/thread.h>
#include <proc/task.h>
#include <proc/tasklet.h>
#include <main/kinit.h>
#include <main/version.h>
#include <console/kconsole.h>
#include <console/console.h>
#include <cpu.h>
#include <align.h>
#include <interrupt.h>
#include <arch/mm/memory_init.h>
#include <mm/frame.h>
#include <mm/page.h>
#include <genarch/mm/page_pt.h>
79,10 → 78,9
#include <ipc/ipc.h>
#include <macros.h>
#include <adt/btree.h>
#include <console/klog.h>
#include <smp/smp.h>
#include <ddi/ddi.h>
#include <main/main.h>
#include <ipc/event.h>
 
/** Global configuration structure. */
config_t config;
89,7 → 87,7
 
/** Initial user-space tasks */
init_t init = {
.cnt = 0
0
};
 
/** Boot allocations. */
105,15 → 103,17
* the linker or the low level assembler code with
* appropriate sizes and addresses.
*/
uintptr_t hardcoded_load_address = 0; /**< Virtual address of where the kernel
* is loaded. */
size_t hardcoded_ktext_size = 0; /**< Size of the kernel code in bytes.
*/
size_t hardcoded_kdata_size = 0; /**< Size of the kernel data in bytes.
*/
uintptr_t stack_safe = 0; /**< Lowest safe stack virtual address.
*/
 
/** Virtual address of where the kernel is loaded. */
uintptr_t hardcoded_load_address = 0;
/** Size of the kernel code in bytes. */
size_t hardcoded_ktext_size = 0;
/** Size of the kernel data in bytes. */
size_t hardcoded_kdata_size = 0;
/** Lowest safe stack virtual address. */
uintptr_t stack_safe = 0;
void main_bsp(void);
void main_ap(void);
 
/*
* These two functions prevent stack from underflowing during the
130,11 → 130,9
 
/** Main kernel routine for bootstrap CPU.
*
* The code here still runs on the boot stack, which knows nothing about
* preemption counts. Because of that, this function cannot directly call
* functions that disable or enable preemption (e.g. spinlock_lock()). The
* primary task of this function is to calculate address of a new stack and
* switch to it.
* Initializes the kernel by bootstrap CPU.
* This function passes control directly to
* main_bsp_separated_stack().
*
* Assuming interrupts_disable().
*
145,6 → 143,8
config.cpu_active = 1;
config.base = hardcoded_load_address;
config.memory_size = get_memory_size();
config.kernel_size = ALIGN_UP(hardcoded_ktext_size +
hardcoded_kdata_size, PAGE_SIZE);
config.stack_size = CONFIG_STACK_SIZE;
153,7 → 153,7
config.stack_base = config.base + config.kernel_size;
/* Avoid placing stack on top of init */
size_t i;
count_t i;
for (i = 0; i < init.cnt; i++) {
if (PA_overlaps(config.stack_base, config.stack_size,
init.tasks[i].addr, init.tasks[i].size))
187,93 → 187,89
*/
void main_bsp_separated_stack(void)
{
/* Keep this the first thing. */
task_t *k;
thread_t *t;
count_t i;
the_initialize(THE);
version_print();
LOG("\nconfig.base=%#" PRIp " config.kernel_size=%" PRIs
"\nconfig.stack_base=%#" PRIp " config.stack_size=%" PRIs,
config.base, config.kernel_size, config.stack_base,
config.stack_size);
#ifdef CONFIG_KCONSOLE
 
/*
* kconsole data structures must be initialized very early
* because other subsystems will register their respective
* commands.
*/
LOG_EXEC(kconsole_init());
#endif
kconsole_init();
/*
* Exception handler initialization, before architecture
* starts adding its own handlers
*/
LOG_EXEC(exc_init());
exc_init();
 
/*
* Memory management subsystems initialization.
*/
LOG_EXEC(arch_pre_mm_init());
LOG_EXEC(frame_init());
*/
arch_pre_mm_init();
frame_init();
/* Initialize at least 1 memory segment big enough for slab to work. */
LOG_EXEC(slab_cache_init());
LOG_EXEC(btree_init());
LOG_EXEC(as_init());
LOG_EXEC(page_init());
LOG_EXEC(tlb_init());
LOG_EXEC(ddi_init());
LOG_EXEC(tasklet_init());
LOG_EXEC(arch_post_mm_init());
LOG_EXEC(arch_pre_smp_init());
LOG_EXEC(smp_init());
slab_cache_init();
btree_init();
as_init();
page_init();
tlb_init();
ddi_init();
arch_post_mm_init();
 
version_print();
printf("kernel: %.*p hardcoded_ktext_size=%zdK, "
"hardcoded_kdata_size=%zdK\n", sizeof(uintptr_t) * 2,
config.base, hardcoded_ktext_size >> 10,
hardcoded_kdata_size >> 10);
printf("stack: %.*p size=%zdK\n", sizeof(uintptr_t) * 2,
config.stack_base, config.stack_size >> 10);
 
arch_pre_smp_init();
smp_init();
/* Slab must be initialized after we know the number of processors. */
LOG_EXEC(slab_enable_cpucache());
slab_enable_cpucache();
 
printf("config.memory_size=%zdM\n", config.memory_size >> 20);
printf("config.cpu_count=%zd\n", config.cpu_count);
cpu_init();
printf("Detected %" PRIs " CPU(s), %" PRIu64" MiB free memory\n",
config.cpu_count, SIZE2MB(zone_total_size()));
calibrate_delay_loop();
clock_counter_init();
timeout_init();
scheduler_init();
task_init();
thread_init();
futex_init();
klog_init();
LOG_EXEC(cpu_init());
LOG_EXEC(calibrate_delay_loop());
LOG_EXEC(clock_counter_init());
LOG_EXEC(timeout_init());
LOG_EXEC(scheduler_init());
LOG_EXEC(task_init());
LOG_EXEC(thread_init());
LOG_EXEC(futex_init());
if (init.cnt > 0) {
size_t i;
for (i = 0; i < init.cnt; i++)
LOG("init[%" PRIs "].addr=%#" PRIp ", init[%" PRIs
"].size=%#" PRIs, i, init.tasks[i].addr, i,
printf("init[%zd].addr=%.*p, init[%zd].size=%zd\n", i,
sizeof(uintptr_t) * 2, init.tasks[i].addr, i,
init.tasks[i].size);
} else
printf("No init binaries found.\n");
printf("No init binaries found\n");
LOG_EXEC(ipc_init());
LOG_EXEC(event_init());
LOG_EXEC(klog_init());
ipc_init();
 
/*
* Create kernel task.
*/
task_t *kernel = task_create(AS_KERNEL, "kernel");
if (!kernel)
panic("Cannot create kernel task.");
k = task_create(AS_KERNEL, "kernel");
if (!k)
panic("can't create kernel task\n");
/*
* Create the first thread.
*/
thread_t *kinit_thread
= thread_create(kinit, NULL, kernel, 0, "kinit", true);
if (!kinit_thread)
panic("Cannot create kinit thread.");
LOG_EXEC(thread_ready(kinit_thread));
t = thread_create(kinit, NULL, k, 0, "kinit", true);
if (!t)
panic("can't create kinit thread\n");
thread_ready(t);
/*
* This call to scheduler() will return to kinit,
326,7 → 322,6
* collide with another CPU coming up. To prevent this, we
* switch to this cpu's private stack prior to waking kmp up.
*/
context_save(&CPU->saved_context);
context_set(&CPU->saved_context, FADDR(main_ap_separated_stack),
(uintptr_t) CPU->stack, CPU_STACK_SIZE);
context_restore(&CPU->saved_context);
/branches/arm/kernel/generic/src/main/uinit.c
45,10 → 45,7
#include <proc/thread.h>
#include <userspace.h>
#include <mm/slab.h>
#include <arch.h>
#include <udebug/udebug.h>
 
 
/** Thread used to bring up userspace thread.
*
* @param arg Pointer to structure containing userspace entry and stack
57,20 → 54,6
void uinit(void *arg)
{
uspace_arg_t uarg;
 
/*
* So far, we don't have a use for joining userspace threads so we
* immediately detach each uinit thread. If joining of userspace threads
* is required, some userspace API based on the kernel mechanism will
* have to be implemented. Moreover, garbage collecting of threads that
* didn't detach themselves and nobody else joined them will have to be
* deployed for the event of forceful task termination.
*/
thread_detach(THREAD);
 
#ifdef CONFIG_UDEBUG
udebug_stoppable_end();
#endif
uarg.uspace_entry = ((uspace_arg_t *) arg)->uspace_entry;
uarg.uspace_stack = ((uspace_arg_t *) arg)->uspace_stack;
79,14 → 62,6
uarg.uspace_thread_arg = NULL;
 
free((uspace_arg_t *) arg);
/*
* Disable interrupts so that the execution of userspace() is not
* disturbed by any interrupts as some of the userspace()
* implementations will switch to the userspace stack before switching
* the mode.
*/
(void) interrupts_disable();
userspace(&uarg);
}
 
/branches/arm/kernel/generic/src/main/version.c
34,22 → 34,21
 
#include <main/version.h>
#include <print.h>
#include <macros.h>
 
char *project = "SPARTAN kernel";
char *copyright = "Copyright (c) 2001-2009 HelenOS project";
char *release = STRING(RELEASE);
char *name = STRING(NAME);
char *arch = STRING(KARCH);
char *copyright = "Copyright (c) 2001-2007 HelenOS project";
char *release = RELEASE;
char *name = NAME;
char *arch = ARCH;
 
#ifdef REVISION
char *revision = ", revision " STRING(REVISION);
char *revision = ", revision " REVISION;
#else
char *revision = "";
#endif
 
#ifdef TIMESTAMP
char *timestamp = " on " STRING(TIMESTAMP);
char *timestamp = " on " TIMESTAMP;
#else
char *timestamp = "";
#endif
/branches/arm/kernel/generic/src/proc/program.c
File deleted
/branches/arm/kernel/generic/src/proc/tasklet.c
File deleted
/branches/arm/kernel/generic/src/proc/scheduler.c
207,7 → 207,7
 
interrupts_disable();
for (i = 0; i < RQ_COUNT; i++) {
for (i = 0; i<RQ_COUNT; i++) {
r = &CPU->rq[i];
spinlock_lock(&r->lock);
if (r->n == 0) {
377,8 → 377,7
void scheduler_separated_stack(void)
{
int priority;
DEADLOCK_PROBE_INIT(p_joinwq);
 
ASSERT(CPU != NULL);
if (THREAD) {
405,17 → 404,14
* Avoid deadlock.
*/
spinlock_unlock(&THREAD->lock);
delay(HZ);
delay(10);
spinlock_lock(&THREAD->lock);
DEADLOCK_PROBE(p_joinwq,
DEADLOCK_THRESHOLD);
goto repeat;
}
_waitq_wakeup_unsafe(&THREAD->join_wq,
WAKEUP_FIRST);
_waitq_wakeup_unsafe(&THREAD->join_wq, false);
spinlock_unlock(&THREAD->join_wq.lock);
THREAD->state = Lingering;
THREAD->state = Undead;
spinlock_unlock(&THREAD->lock);
}
break;
451,8 → 447,8
/*
* Entering state is unexpected.
*/
panic("tid%" PRIu64 ": unexpected state %s.",
THREAD->tid, thread_states[THREAD->state]);
panic("tid%d: unexpected state %s\n", THREAD->tid,
thread_states[THREAD->state]);
break;
}
 
504,9 → 500,9
THREAD->state = Running;
 
#ifdef SCHEDULER_VERBOSE
printf("cpu%u: tid %" PRIu64 " (priority=%d, ticks=%" PRIu64
", nrdy=%ld)\n", CPU->id, THREAD->tid, THREAD->priority,
THREAD->ticks, atomic_get(&CPU->nrdy));
printf("cpu%d: tid %d (priority=%d, ticks=%lld, nrdy=%ld)\n",
CPU->id, THREAD->tid, THREAD->priority, THREAD->ticks,
atomic_get(&CPU->nrdy));
#endif
 
/*
572,7 → 568,7
* Searching least priority queues on all CPU's first and most priority
* queues on all CPU's last.
*/
for (j = RQ_COUNT - 1; j >= 0; j--) {
for (j= RQ_COUNT - 1; j >= 0; j--) {
for (i = 0; i < config.cpu_active; i++) {
link_t *l;
runq_t *r;
613,8 → 609,8
*/
spinlock_lock(&t->lock);
if ((!(t->flags & (THREAD_FLAG_WIRED |
THREAD_FLAG_STOLEN))) &&
(!(t->fpu_context_engaged))) {
THREAD_FLAG_STOLEN))) &&
(!(t->fpu_context_engaged)) ) {
/*
* Remove t from r.
*/
640,9 → 636,9
*/
spinlock_lock(&t->lock);
#ifdef KCPULB_VERBOSE
printf("kcpulb%u: TID %" PRIu64 " -> cpu%u, "
"nrdy=%ld, avg=%ld\n", CPU->id, t->tid,
CPU->id, atomic_get(&CPU->nrdy),
printf("kcpulb%d: TID %d -> cpu%d, nrdy=%ld, "
"avg=%nd\n", CPU->id, t->tid, CPU->id,
atomic_get(&CPU->nrdy),
atomic_get(&nrdy) / config.cpu_active);
#endif
t->flags |= THREAD_FLAG_STOLEN;
708,7 → 704,7
continue;
 
spinlock_lock(&cpus[cpu].lock);
printf("cpu%u: address=%p, nrdy=%ld, needs_relink=%" PRIs "\n",
printf("cpu%d: address=%p, nrdy=%ld, needs_relink=%ld\n",
cpus[cpu].id, &cpus[cpu], atomic_get(&cpus[cpu].nrdy),
cpus[cpu].needs_relink);
719,11 → 715,11
spinlock_unlock(&r->lock);
continue;
}
printf("\trq[%u]: ", i);
printf("\trq[%d]: ", i);
for (cur = r->rq_head.next; cur != &r->rq_head;
cur = cur->next) {
t = list_get_instance(cur, thread_t, rq_link);
printf("%" PRIu64 "(%s) ", t->tid,
printf("%d(%s) ", t->tid,
thread_states[t->state]);
}
printf("\n");
/branches/arm/kernel/generic/src/proc/task.c
35,34 → 35,38
* @brief Task management.
*/
 
#include <main/uinit.h>
#include <proc/thread.h>
#include <proc/task.h>
#include <proc/uarg.h>
#include <mm/as.h>
#include <mm/slab.h>
#include <atomic.h>
#include <synch/spinlock.h>
#include <synch/waitq.h>
#include <arch.h>
#include <arch/barrier.h>
#include <adt/avl.h>
#include <panic.h>
#include <adt/btree.h>
#include <adt/list.h>
#include <ipc/ipc.h>
#include <ipc/ipcrsc.h>
#include <security/cap.h>
#include <memstr.h>
#include <print.h>
#include <lib/elf.h>
#include <errno.h>
#include <func.h>
#include <string.h>
#include <syscall/copy.h>
#include <macros.h>
#include <ipc/event.h>
#include <console/klog.h>
 
/** Spinlock protecting the tasks_tree AVL tree. */
#ifndef LOADED_PROG_STACK_PAGES_NO
#define LOADED_PROG_STACK_PAGES_NO 1
#endif
 
/** Spinlock protecting the tasks_btree B+tree. */
SPINLOCK_INITIALIZE(tasks_lock);
 
/** AVL tree of active tasks.
/** B+tree of active tasks.
*
* The task is guaranteed to exist after it was found in the tasks_tree as
* The task is guaranteed to exist after it was found in the tasks_btree as
* long as:
* @li the tasks_lock is held,
* @li the task's lock is held when task's lock is acquired before releasing
70,73 → 74,34
* @li the task's refcount is greater than 0
*
*/
avltree_t tasks_tree;
btree_t tasks_btree;
 
static task_id_t task_counter = 0;
 
/** Initialize kernel tasks support. */
static void ktaskclnp(void *arg);
static void ktaskgc(void *arg);
 
/** Initialize tasks
*
* Initialize kernel tasks support.
*
*/
void task_init(void)
{
TASK = NULL;
avltree_create(&tasks_tree);
btree_create(&tasks_btree);
}
 
/*
* The idea behind this walker is to remember a single task different from
* TASK.
*/
static bool task_done_walker(avltree_node_t *node, void *arg)
{
task_t *t = avltree_get_instance(node, task_t, tasks_tree_node);
task_t **tp = (task_t **) arg;
 
if (t != TASK) {
*tp = t;
return false; /* stop walking */
}
 
return true; /* continue the walk */
}
 
/** Kill all tasks except the current task. */
void task_done(void)
{
task_t *t;
do { /* Repeat until there are any tasks except TASK */
/* Messing with task structures, avoid deadlock */
ipl_t ipl = interrupts_disable();
spinlock_lock(&tasks_lock);
t = NULL;
avltree_walk(&tasks_tree, task_done_walker, &t);
if (t != NULL) {
task_id_t id = t->taskid;
spinlock_unlock(&tasks_lock);
interrupts_restore(ipl);
#ifdef CONFIG_DEBUG
printf("Killing task %" PRIu64 "\n", id);
#endif
task_kill(id);
thread_usleep(10000);
} else {
spinlock_unlock(&tasks_lock);
interrupts_restore(ipl);
}
} while (t != NULL);
}
 
/** Create new task with no threads.
/** Create new task
*
* @param as Task's address space.
* @param name Symbolic name (a copy is made).
* Create new task with no threads.
*
* @return New task's structure.
* @param as Task's address space.
* @param name Symbolic name.
*
* @return New task's structure
*
*/
task_t *task_create(as_t *as, char *name)
{
151,29 → 116,16
spinlock_initialize(&ta->lock, "task_ta_lock");
list_initialize(&ta->th_head);
ta->as = as;
 
memcpy(ta->name, name, TASK_NAME_BUFLEN);
ta->name[TASK_NAME_BUFLEN - 1] = 0;
 
atomic_set(&ta->refcount, 0);
atomic_set(&ta->lifecount, 0);
ta->name = name;
ta->main_thread = NULL;
ta->refcount = 0;
ta->context = CONTEXT;
 
ta->capabilities = 0;
ta->accept_new_threads = true;
ta->cycles = 0;
 
#ifdef CONFIG_UDEBUG
/* Init debugging stuff */
udebug_task_init(&ta->udebug);
 
/* Init kbox stuff */
ipc_answerbox_init(&ta->kb.box, ta);
ta->kb.thread = NULL;
mutex_initialize(&ta->kb.cleanup_lock, MUTEX_PASSIVE);
ta->kb.finished = false;
#endif
 
ipc_answerbox_init(&ta->answerbox, ta);
ipc_answerbox_init(&ta->answerbox);
for (i = 0; i < IPC_MAX_PHONES; i++)
ipc_phone_init(&ta->phones[i]);
if ((ipc_phone_0) && (context_check(ipc_phone_0->task->context,
181,7 → 133,7
ipc_phone_connect(&ta->phones[0], ipc_phone_0);
atomic_set(&ta->active_calls, 0);
 
mutex_initialize(&ta->futexes_lock, MUTEX_PASSIVE);
mutex_initialize(&ta->futexes_lock);
btree_create(&ta->futexes);
ipl = interrupts_disable();
188,141 → 140,148
 
/*
* Increment address space reference count.
* TODO: Reconsider the locking scheme.
*/
atomic_inc(&as->refcount);
mutex_lock(&as->lock);
as->refcount++;
mutex_unlock(&as->lock);
 
spinlock_lock(&tasks_lock);
 
ta->taskid = ++task_counter;
avltree_node_initialize(&ta->tasks_tree_node);
ta->tasks_tree_node.key = ta->taskid;
avltree_insert(&tasks_tree, &ta->tasks_tree_node);
btree_insert(&tasks_btree, (btree_key_t) ta->taskid, (void *) ta, NULL);
 
spinlock_unlock(&tasks_lock);
interrupts_restore(ipl);
/*
* Notify about task creation.
*/
if (event_is_subscribed(EVENT_WAIT))
event_notify_3(EVENT_WAIT, TASK_CREATE, LOWER32(ta->taskid),
UPPER32(ta->taskid));
 
return ta;
}
 
/** Destroy task.
*
* @param t Task to be destroyed.
* @param t Task to be destroyed.
*/
void task_destroy(task_t *t)
{
/*
* Remove the task from the task B+tree.
*/
spinlock_lock(&tasks_lock);
avltree_delete(&tasks_tree, &t->tasks_tree_node);
spinlock_unlock(&tasks_lock);
 
/*
* Perform architecture specific task destruction.
*/
task_destroy_arch(t);
btree_destroy(&t->futexes);
 
mutex_lock_active(&t->as->lock);
if (--t->as->refcount == 0) {
mutex_unlock(&t->as->lock);
as_destroy(t->as);
/*
* t->as is destroyed.
*/
} else
mutex_unlock(&t->as->lock);
free(t);
TASK = NULL;
}
 
/** Create new task with 1 thread and run it
*
* @param program_addr Address of program executable image.
* @param name Program name.
*
* @return Task of the running program or NULL on error.
*/
task_t * task_run_program(void *program_addr, char *name)
{
as_t *as;
as_area_t *a;
int rc;
thread_t *t1, *t2;
task_t *task;
uspace_arg_t *kernel_uarg;
 
as = as_create(0);
ASSERT(as);
 
rc = elf_load((elf_header_t *) program_addr, as);
if (rc != EE_OK) {
as_destroy(as);
return NULL;
}
kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
kernel_uarg->uspace_entry =
(void *) ((elf_header_t *) program_addr)->e_entry;
kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS;
kernel_uarg->uspace_thread_function = NULL;
kernel_uarg->uspace_thread_arg = NULL;
kernel_uarg->uspace_uarg = NULL;
task = task_create(as, name);
ASSERT(task);
 
/*
* Free up dynamically allocated state.
* Create the data as_area.
*/
btree_destroy(&t->futexes);
a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
LOADED_PROG_STACK_PAGES_NO * PAGE_SIZE, USTACK_ADDRESS,
AS_AREA_ATTR_NONE, &anon_backend, NULL);
 
/*
* Drop our reference to the address space.
* Create the main thread.
*/
if (atomic_predec(&t->as->refcount) == 0)
as_destroy(t->as);
t1 = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE,
"uinit", false);
ASSERT(t1);
/*
* Notify about task destruction.
* Create killer thread for the new task.
*/
if (event_is_subscribed(EVENT_WAIT))
event_notify_3(EVENT_WAIT, TASK_DESTROY, LOWER32(t->taskid),
UPPER32(t->taskid));
free(t);
TASK = NULL;
t2 = thread_create(ktaskgc, t1, task, 0, "ktaskgc", true);
ASSERT(t2);
thread_ready(t2);
 
thread_ready(t1);
 
return task;
}
 
/** Syscall for reading task ID from userspace.
*
* @param uspace_task_id userspace address of 8-byte buffer
* where to store current task ID.
* @param uspace_task_id Userspace address of 8-byte buffer where to store
* current task ID.
*
* @return Zero on success or an error code from @ref errno.h.
* @return 0 on success or an error code from @ref errno.h.
*/
unative_t sys_task_get_id(task_id_t *uspace_task_id)
{
/*
* No need to acquire lock on TASK because taskid remains constant for
* the lifespan of the task.
* No need to acquire lock on TASK because taskid
* remains constant for the lifespan of the task.
*/
return (unative_t) copy_to_uspace(uspace_task_id, &TASK->taskid,
sizeof(TASK->taskid));
}
 
/** Syscall for setting the task name.
/** Find task structure corresponding to task ID.
*
* The name simplifies identifying the task in the task list.
* The tasks_lock must be already held by the caller of this function
* and interrupts must be disabled.
*
* @param name The new name for the task. (typically the same
* as the command used to execute it).
* @param id Task ID.
*
* @return 0 on success or an error code from @ref errno.h.
* @return Task structure address or NULL if there is no such task ID.
*/
unative_t sys_task_set_name(const char *uspace_name, size_t name_len)
task_t *task_find_by_id(task_id_t id)
{
int rc;
char namebuf[TASK_NAME_BUFLEN];
 
/* Cap length of name and copy it from userspace. */
 
if (name_len > TASK_NAME_BUFLEN - 1)
name_len = TASK_NAME_BUFLEN - 1;
 
rc = copy_from_uspace(namebuf, uspace_name, name_len);
if (rc != 0)
return (unative_t) rc;
 
namebuf[name_len] = '\0';
str_cpy(TASK->name, TASK_NAME_BUFLEN, namebuf);
 
return EOK;
}
 
/** Find task structure corresponding to task ID.
*
* The tasks_lock must be already held by the caller of this function and
* interrupts must be disabled.
*
* @param id Task ID.
*
* @return Task structure address or NULL if there is no such task
* ID.
*/
task_t *task_find_by_id(task_id_t id) { avltree_node_t *node;
btree_node_t *leaf;
node = avltree_search(&tasks_tree, (avltree_key_t) id);
 
if (node)
return avltree_get_instance(node, task_t, tasks_tree_node);
return NULL;
return (task_t *) btree_search(&tasks_btree, (btree_key_t) id, &leaf);
}
 
/** Get accounting data of given task.
*
* Note that task lock of 't' must be already held and interrupts must be
* already disabled.
* Note that task lock of 't' must be already held and
* interrupts must be already disabled.
*
* @param t Pointer to thread.
* @param t Pointer to thread.
*
* @return Number of cycles used by the task and all its threads
* so far.
*/
uint64_t task_get_accounting(task_t *t)
{
351,17 → 310,15
 
/** Kill task.
*
* This function is idempotent.
* It signals all the task's threads to bail it out.
* @param id ID of the task to be killed.
*
* @param id ID of the task to be killed.
*
* @return Zero on success or an error code from errno.h.
* @return 0 on success or an error code from errno.h
*/
int task_kill(task_id_t id)
{
ipl_t ipl;
task_t *ta;
thread_t *t;
link_t *cur;
 
if (id == 1)
369,23 → 326,37
ipl = interrupts_disable();
spinlock_lock(&tasks_lock);
 
if (!(ta = task_find_by_id(id))) {
spinlock_unlock(&tasks_lock);
interrupts_restore(ipl);
return ENOENT;
}
 
spinlock_lock(&ta->lock);
ta->refcount++;
spinlock_unlock(&ta->lock);
 
btree_remove(&tasks_btree, ta->taskid, NULL);
spinlock_unlock(&tasks_lock);
t = thread_create(ktaskclnp, NULL, ta, 0, "ktaskclnp", true);
spinlock_lock(&ta->lock);
ta->accept_new_threads = false;
ta->refcount--;
 
/*
* Interrupt all threads.
*/
spinlock_lock(&ta->lock);
* Interrupt all threads except ktaskclnp.
*/
for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
thread_t *thr;
bool sleeping = false;
bool sleeping = false;
thr = list_get_instance(cur, thread_t, th_link);
if (thr == t)
continue;
spinlock_lock(&thr->lock);
thr->interrupted = true;
if (thr->state == Sleeping)
395,73 → 366,196
if (sleeping)
waitq_interrupt_sleep(thr);
}
spinlock_unlock(&ta->lock);
interrupts_restore(ipl);
if (t)
thread_ready(t);
 
return 0;
}
 
static bool task_print_walker(avltree_node_t *node, void *arg)
{
task_t *t = avltree_get_instance(node, task_t, tasks_tree_node);
int j;
spinlock_lock(&t->lock);
uint64_t cycles;
char suffix;
order(task_get_accounting(t), &cycles, &suffix);
 
#ifdef __32_BITS__
printf("%-6" PRIu64 " %-12s %-3" PRIu32 " %10p %10p %9" PRIu64
"%c %7ld %6ld", t->taskid, t->name, t->context, t, t->as, cycles,
suffix, atomic_get(&t->refcount), atomic_get(&t->active_calls));
#endif
 
#ifdef __64_BITS__
printf("%-6" PRIu64 " %-12s %-3" PRIu32 " %18p %18p %9" PRIu64
"%c %7ld %6ld", t->taskid, t->name, t->context, t, t->as, cycles,
suffix, atomic_get(&t->refcount), atomic_get(&t->active_calls));
#endif
 
for (j = 0; j < IPC_MAX_PHONES; j++) {
if (t->phones[j].callee)
printf(" %d:%p", j, t->phones[j].callee);
}
printf("\n");
spinlock_unlock(&t->lock);
return true;
}
 
/** Print task list */
void task_print_list(void)
{
link_t *cur;
ipl_t ipl;
/* Messing with task structures, avoid deadlock */
/* Messing with thread structures, avoid deadlock */
ipl = interrupts_disable();
spinlock_lock(&tasks_lock);
printf("taskid name ctx address as cycles threads "
"calls callee\n");
printf("------ ---------- --- ---------- ---------- ---------- ------- " "------ ------>\n");
 
#ifdef __32_BITS__
printf("taskid name ctx address as "
"cycles threads calls callee\n");
printf("------ ------------ --- ---------- ---------- "
"---------- ------- ------ ------>\n");
#endif
for (cur = tasks_btree.leaf_head.next; cur != &tasks_btree.leaf_head;
cur = cur->next) {
btree_node_t *node;
unsigned int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
task_t *t;
int j;
 
#ifdef __64_BITS__
printf("taskid name ctx address as "
"cycles threads calls callee\n");
printf("------ ------------ --- ------------------ ------------------ "
"---------- ------- ------ ------>\n");
#endif
t = (task_t *) node->value[i];
spinlock_lock(&t->lock);
uint64_t cycles;
char suffix;
order(task_get_accounting(t), &cycles, &suffix);
printf("%-6lld %-10s %-3ld %#10zx %#10zx %9llu%c %7zd "
"%6zd", t->taskid, t->name, t->context, t, t->as,
cycles, suffix, t->refcount,
atomic_get(&t->active_calls));
for (j = 0; j < IPC_MAX_PHONES; j++) {
if (t->phones[j].callee)
printf(" %zd:%#zx", j,
t->phones[j].callee);
}
printf("\n");
spinlock_unlock(&t->lock);
}
}
 
avltree_walk(&tasks_tree, task_print_walker, NULL);
 
spinlock_unlock(&tasks_lock);
interrupts_restore(ipl);
}
 
/** Kernel thread used to cleanup the task after it is killed. */
void ktaskclnp(void *arg)
{
ipl_t ipl;
thread_t *t = NULL, *main_thread;
link_t *cur;
bool again;
 
thread_detach(THREAD);
 
loop:
ipl = interrupts_disable();
spinlock_lock(&TASK->lock);
main_thread = TASK->main_thread;
/*
* Find a thread to join.
*/
again = false;
for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
t = list_get_instance(cur, thread_t, th_link);
 
spinlock_lock(&t->lock);
if (t == THREAD) {
spinlock_unlock(&t->lock);
continue;
} else if (t == main_thread) {
spinlock_unlock(&t->lock);
continue;
} else if (t->join_type != None) {
spinlock_unlock(&t->lock);
again = true;
continue;
} else {
t->join_type = TaskClnp;
spinlock_unlock(&t->lock);
again = false;
break;
}
}
spinlock_unlock(&TASK->lock);
interrupts_restore(ipl);
if (again) {
/*
* Other cleanup (e.g. ktaskgc) is in progress.
*/
scheduler();
goto loop;
}
if (t != THREAD) {
ASSERT(t != main_thread); /* uninit is joined and detached
* in ktaskgc */
thread_join(t);
thread_detach(t);
goto loop; /* go for another thread */
}
/*
* Now there are no other threads in this task
* and no new threads can be created.
*/
 
ipc_cleanup();
futex_cleanup();
klog_printf("Cleanup of task %lld completed.", TASK->taskid);
}
 
/** Kernel thread used to kill the userspace task when its main thread exits.
*
* This thread waits until the main userspace thread (i.e. uninit) exits.
* When this happens, the task is killed. In the meantime, exited threads
* are garbage collected.
*
* @param arg Pointer to the thread structure of the task's main thread.
*/
void ktaskgc(void *arg)
{
thread_t *t = (thread_t *) arg;
loop:
/*
* Userspace threads cannot detach themselves,
* therefore the thread pointer is guaranteed to be valid.
*/
if (thread_join_timeout(t, 1000000, SYNCH_FLAGS_NONE) ==
ESYNCH_TIMEOUT) { /* sleep uninterruptibly here! */
ipl_t ipl;
link_t *cur;
thread_t *thr = NULL;
/*
* The join timed out. Try to do some garbage collection of
* Undead threads.
*/
more_gc:
ipl = interrupts_disable();
spinlock_lock(&TASK->lock);
for (cur = TASK->th_head.next; cur != &TASK->th_head;
cur = cur->next) {
thr = list_get_instance(cur, thread_t, th_link);
spinlock_lock(&thr->lock);
if (thr != t && thr->state == Undead &&
thr->join_type == None) {
thr->join_type = TaskGC;
spinlock_unlock(&thr->lock);
break;
}
spinlock_unlock(&thr->lock);
thr = NULL;
}
spinlock_unlock(&TASK->lock);
interrupts_restore(ipl);
if (thr) {
thread_join(thr);
thread_detach(thr);
scheduler();
goto more_gc;
}
goto loop;
}
thread_detach(t);
task_kill(TASK->taskid);
}
 
/** @}
*/
/branches/arm/kernel/generic/src/proc/thread.c
51,7 → 51,7
#include <cpu.h>
#include <func.h>
#include <context.h>
#include <adt/avl.h>
#include <adt/btree.h>
#include <adt/list.h>
#include <time/clock.h>
#include <time/timeout.h>
69,11 → 69,6
#include <errno.h>
 
 
#ifndef LOADED_PROG_STACK_PAGES_NO
#define LOADED_PROG_STACK_PAGES_NO 1
#endif
 
 
/** Thread states */
char *thread_states[] = {
"Invalid",
82,27 → 77,27
"Ready",
"Entering",
"Exiting",
"Lingering"
"Undead"
};
 
/** Lock protecting the threads_tree AVL tree.
/** Lock protecting the threads_btree B+tree.
*
* For locking rules, see declaration thereof.
*/
SPINLOCK_INITIALIZE(threads_lock);
 
/** AVL tree of all threads.
/** B+tree of all threads.
*
* When a thread is found in the threads_tree AVL tree, it is guaranteed to
* When a thread is found in the threads_btree B+tree, it is guaranteed to
* exist as long as the threads_lock is held.
*/
avltree_t threads_tree;
btree_t threads_btree;
 
SPINLOCK_INITIALIZE(tidlock);
thread_id_t last_tid = 0;
uint32_t last_tid = 0;
 
static slab_cache_t *thread_slab;
#ifdef CONFIG_FPU
#ifdef ARCH_HAS_FPU
slab_cache_t *fpu_context_slab;
#endif
 
161,29 → 156,25
/* call the architecture-specific part of the constructor */
thr_constructor_arch(t);
#ifdef CONFIG_FPU
#ifdef CONFIG_FPU_LAZY
#ifdef ARCH_HAS_FPU
# ifdef CONFIG_FPU_LAZY
t->saved_fpu_context = NULL;
#else
t->saved_fpu_context = slab_alloc(fpu_context_slab, kmflags);
# else
t->saved_fpu_context = slab_alloc(fpu_context_slab,kmflags);
if (!t->saved_fpu_context)
return -1;
#endif
#endif
# endif
#endif
 
t->kstack = (uint8_t *) frame_alloc(STACK_FRAMES, FRAME_KA | kmflags);
if (!t->kstack) {
#ifdef CONFIG_FPU
if (! t->kstack) {
#ifdef ARCH_HAS_FPU
if (t->saved_fpu_context)
slab_free(fpu_context_slab, t->saved_fpu_context);
slab_free(fpu_context_slab,t->saved_fpu_context);
#endif
return -1;
}
 
#ifdef CONFIG_UDEBUG
mutex_initialize(&t->udebug.lock, MUTEX_PASSIVE);
#endif
 
return 0;
}
 
196,9 → 187,9
thr_destructor_arch(t);
 
frame_free(KA2PA(t->kstack));
#ifdef CONFIG_FPU
#ifdef ARCH_HAS_FPU
if (t->saved_fpu_context)
slab_free(fpu_context_slab, t->saved_fpu_context);
slab_free(fpu_context_slab,t->saved_fpu_context);
#endif
return 1; /* One page freed */
}
211,16 → 202,16
void thread_init(void)
{
THREAD = NULL;
atomic_set(&nrdy, 0);
atomic_set(&nrdy,0);
thread_slab = slab_cache_create("thread_slab", sizeof(thread_t), 0,
thr_constructor, thr_destructor, 0);
 
#ifdef CONFIG_FPU
#ifdef ARCH_HAS_FPU
fpu_context_slab = slab_cache_create("fpu_slab", sizeof(fpu_context_t),
FPU_CONTEXT_ALIGN, NULL, NULL, 0);
#endif
 
avltree_create(&threads_tree);
btree_create(&threads_btree);
}
 
/** Make thread ready
241,13 → 232,12
 
spinlock_lock(&t->lock);
 
ASSERT(!(t->state == Ready));
ASSERT(! (t->state == Ready));
 
i = (t->priority < RQ_COUNT - 1) ? ++t->priority : t->priority;
cpu = CPU;
if (t->flags & THREAD_FLAG_WIRED) {
ASSERT(t->cpu != NULL);
cpu = t->cpu;
}
t->state = Ready;
269,25 → 259,65
interrupts_restore(ipl);
}
 
/** Destroy thread memory structure
*
* Detach thread from all queues, cpus etc. and destroy it.
*
* Assume thread->lock is held!!
*/
void thread_destroy(thread_t *t)
{
bool destroy_task = false;
 
ASSERT(t->state == Exiting || t->state == Undead);
ASSERT(t->task);
ASSERT(t->cpu);
 
spinlock_lock(&t->cpu->lock);
if(t->cpu->fpu_owner == t)
t->cpu->fpu_owner = NULL;
spinlock_unlock(&t->cpu->lock);
 
spinlock_unlock(&t->lock);
 
spinlock_lock(&threads_lock);
btree_remove(&threads_btree, (btree_key_t) ((uintptr_t ) t), NULL);
spinlock_unlock(&threads_lock);
 
/*
* Detach from the containing task.
*/
spinlock_lock(&t->task->lock);
list_remove(&t->th_link);
if (--t->task->refcount == 0) {
t->task->accept_new_threads = false;
destroy_task = true;
}
spinlock_unlock(&t->task->lock);
if (destroy_task)
task_destroy(t->task);
slab_free(thread_slab, t);
}
 
/** Create new thread
*
* Create a new thread.
*
* @param func Thread's implementing function.
* @param arg Thread's implementing function argument.
* @param task Task to which the thread belongs. The caller must
* guarantee that the task won't cease to exist during the
* call. The task's lock may not be held.
* @param flags Thread flags.
* @param name Symbolic name (a copy is made).
* @param uncounted Thread's accounting doesn't affect accumulated task
* accounting.
* @param func Thread's implementing function.
* @param arg Thread's implementing function argument.
* @param task Task to which the thread belongs.
* @param flags Thread flags.
* @param name Symbolic name.
* @param uncounted Thread's accounting doesn't affect accumulated task
* accounting.
*
* @return New thread's structure on success, NULL on failure.
* @return New thread's structure on success, NULL on failure.
*
*/
thread_t *thread_create(void (* func)(void *), void *arg, task_t *task,
int flags, char *name, bool uncounted)
int flags, char *name, bool uncounted)
{
thread_t *t;
ipl_t ipl;
297,7 → 327,8
return NULL;
/* Not needed, but good for debugging */
memsetb(t->kstack, THREAD_STACK_SIZE * 1 << STACK_FRAMES, 0);
memsetb((uintptr_t) t->kstack, THREAD_STACK_SIZE * 1 << STACK_FRAMES,
0);
ipl = interrupts_disable();
spinlock_lock(&tidlock);
316,7 → 347,6
interrupts_restore(ipl);
memcpy(t->name, name, THREAD_NAME_BUFLEN);
t->name[THREAD_NAME_BUFLEN - 1] = 0;
t->thread_code = func;
t->thread_arg = arg;
339,6 → 369,7
t->in_copy_to_uspace = false;
 
t->interrupted = false;
t->join_type = None;
t->detached = false;
waitq_initialize(&t->join_wq);
349,88 → 380,23
t->fpu_context_exists = 0;
t->fpu_context_engaged = 0;
 
avltree_node_initialize(&t->threads_tree_node);
t->threads_tree_node.key = (uintptr_t) t;
 
#ifdef CONFIG_UDEBUG
/* Init debugging stuff */
udebug_thread_initialize(&t->udebug);
#endif
 
/* might depend on previous initialization */
thread_create_arch(t);
 
if (!(flags & THREAD_FLAG_NOATTACH))
thread_attach(t, task);
 
return t;
}
 
/** Destroy thread memory structure
*
* Detach thread from all queues, cpus etc. and destroy it.
*
* Assume thread->lock is held!!
*/
void thread_destroy(thread_t *t)
{
ASSERT(t->state == Exiting || t->state == Lingering);
ASSERT(t->task);
ASSERT(t->cpu);
 
spinlock_lock(&t->cpu->lock);
if (t->cpu->fpu_owner == t)
t->cpu->fpu_owner = NULL;
spinlock_unlock(&t->cpu->lock);
 
spinlock_unlock(&t->lock);
 
spinlock_lock(&threads_lock);
avltree_delete(&threads_tree, &t->threads_tree_node);
spinlock_unlock(&threads_lock);
 
/*
* Detach from the containing task.
*/
spinlock_lock(&t->task->lock);
list_remove(&t->th_link);
spinlock_unlock(&t->task->lock);
 
/*
* t is guaranteed to be the very last thread of its task.
* It is safe to destroy the task.
*/
if (atomic_predec(&t->task->refcount) == 0)
task_destroy(t->task);
slab_free(thread_slab, t);
}
 
/** Make the thread visible to the system.
*
* Attach the thread structure to the current task and make it visible in the
* threads_tree.
*
* @param t Thread to be attached to the task.
* @param task Task to which the thread is to be attached.
*/
void thread_attach(thread_t *t, task_t *task)
{
ipl_t ipl;
 
/*
* Attach to the specified task.
* Attach to the containing task.
*/
ipl = interrupts_disable();
ipl = interrupts_disable();
spinlock_lock(&task->lock);
 
atomic_inc(&task->refcount);
 
/* Must not count kbox thread into lifecount */
if (t->flags & THREAD_FLAG_USPACE)
atomic_inc(&task->lifecount);
 
if (!task->accept_new_threads) {
spinlock_unlock(&task->lock);
slab_free(thread_slab, t);
interrupts_restore(ipl);
return NULL;
}
list_append(&t->th_link, &task->th_head);
if (task->refcount++ == 0)
task->main_thread = t;
spinlock_unlock(&task->lock);
 
/*
437,10 → 403,13
* Register this thread in the system-wide list.
*/
spinlock_lock(&threads_lock);
avltree_insert(&threads_tree, &t->threads_tree_node);
btree_insert(&threads_btree, (btree_key_t) ((uintptr_t) t), (void *) t,
NULL);
spinlock_unlock(&threads_lock);
interrupts_restore(ipl);
return t;
}
 
/** Terminate thread.
452,25 → 421,6
{
ipl_t ipl;
 
if (THREAD->flags & THREAD_FLAG_USPACE) {
#ifdef CONFIG_UDEBUG
/* Generate udebug THREAD_E event */
udebug_thread_e_event();
#endif
if (atomic_predec(&TASK->lifecount) == 0) {
/*
* We are the last userspace thread in the task that
* still has not exited. With the exception of the
* moment the task was created, new userspace threads
* can only be created by threads of the same task.
* We are safe to perform cleanup.
*/
ipc_cleanup();
futex_cleanup();
LOG("Cleanup of task %" PRIu64" completed.", TASK->taskid);
}
}
 
restart:
ipl = interrupts_disable();
spinlock_lock(&THREAD->lock);
480,7 → 430,6
interrupts_restore(ipl);
goto restart;
}
THREAD->state = Exiting;
spinlock_unlock(&THREAD->lock);
scheduler();
537,8 → 486,8
 
/** Detach thread.
*
* Mark the thread as detached, if the thread is already in the Lingering
* state, deallocate its resources.
* Mark the thread as detached, if the thread is already in the Undead state,
* deallocate its resources.
*
* @param t Thread to be detached.
*/
547,13 → 496,13
ipl_t ipl;
 
/*
* Since the thread is expected not to be already detached,
* Since the thread is expected to not be already detached,
* pointer to it must be still valid.
*/
ipl = interrupts_disable();
spinlock_lock(&t->lock);
ASSERT(!t->detached);
if (t->state == Lingering) {
if (t->state == Undead) {
thread_destroy(t); /* unlocks &t->lock */
interrupts_restore(ipl);
return;
601,75 → 550,54
interrupts_restore(ipl);
}
 
static bool thread_walker(avltree_node_t *node, void *arg)
{
thread_t *t = avltree_get_instance(node, thread_t, threads_tree_node);
uint64_t cycles;
char suffix;
order(t->cycles, &cycles, &suffix);
 
#ifdef __32_BITS__
printf("%-6" PRIu64" %-10s %10p %-8s %10p %-3" PRIu32 " %10p %10p %9" PRIu64 "%c ",
t->tid, t->name, t, thread_states[t->state], t->task,
t->task->context, t->thread_code, t->kstack, cycles, suffix);
#endif
 
#ifdef __64_BITS__
printf("%-6" PRIu64" %-10s %18p %-8s %18p %-3" PRIu32 " %18p %18p %9" PRIu64 "%c ",
t->tid, t->name, t, thread_states[t->state], t->task,
t->task->context, t->thread_code, t->kstack, cycles, suffix);
#endif
if (t->cpu)
printf("%-4u", t->cpu->id);
else
printf("none");
if (t->state == Sleeping) {
#ifdef __32_BITS__
printf(" %10p", t->sleep_queue);
#endif
 
#ifdef __64_BITS__
printf(" %18p", t->sleep_queue);
#endif
}
printf("\n");
 
return true;
}
 
/** Print list of threads debug info */
void thread_print_list(void)
{
link_t *cur;
ipl_t ipl;
/* Messing with thread structures, avoid deadlock */
ipl = interrupts_disable();
spinlock_lock(&threads_lock);
printf("tid name address state task ctx code "
" stack cycles cpu kstack waitqueue\n");
printf("------ ---------- ---------- -------- ---------- --- --------"
"-- ---------- ---------- ---- ---------- ----------\n");
 
#ifdef __32_BITS__
printf("tid name address state task "
"ctx code stack cycles cpu "
"waitqueue\n");
printf("------ ---------- ---------- -------- ---------- "
"--- ---------- ---------- ---------- ---- "
"----------\n");
#endif
for (cur = threads_btree.leaf_head.next;
cur != &threads_btree.leaf_head; cur = cur->next) {
btree_node_t *node;
unsigned int i;
 
#ifdef __64_BITS__
printf("tid name address state task "
"ctx code stack cycles cpu "
"waitqueue\n");
printf("------ ---------- ------------------ -------- ------------------ "
"--- ------------------ ------------------ ---------- ---- "
"------------------\n");
#endif
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
thread_t *t;
t = (thread_t *) node->value[i];
uint64_t cycles;
char suffix;
order(t->cycles, &cycles, &suffix);
printf("%-6zd %-10s %#10zx %-8s %#10zx %-3ld %#10zx "
"%#10zx %9llu%c ", t->tid, t->name, t,
thread_states[t->state], t->task, t->task->context,
t->thread_code, t->kstack, cycles, suffix);
if (t->cpu)
printf("%-4zd", t->cpu->id);
else
printf("none");
if (t->state == Sleeping)
printf(" %#10zx %#10zx", t->kstack,
t->sleep_queue);
printf("\n");
}
}
 
avltree_walk(&threads_tree, thread_walker, NULL);
 
spinlock_unlock(&threads_lock);
interrupts_restore(ipl);
}
685,13 → 613,13
*/
bool thread_exists(thread_t *t)
{
avltree_node_t *node;
 
node = avltree_search(&threads_tree, (avltree_key_t) ((uintptr_t) t));
btree_node_t *leaf;
return node != NULL;
return btree_search(&threads_btree, (btree_key_t) ((uintptr_t) t),
&leaf) != NULL;
}
 
 
/** Update accounting of current thread.
*
* Note that thread_lock on THREAD must be already held and
708,29 → 636,19
/** Process syscall to create new thread.
*
*/
unative_t sys_thread_create(uspace_arg_t *uspace_uarg, char *uspace_name,
size_t name_len, thread_id_t *uspace_thread_id)
unative_t sys_thread_create(uspace_arg_t *uspace_uarg, char *uspace_name)
{
thread_t *t;
char namebuf[THREAD_NAME_BUFLEN];
uspace_arg_t *kernel_uarg;
uint32_t tid;
int rc;
 
if (name_len > THREAD_NAME_BUFLEN - 1)
name_len = THREAD_NAME_BUFLEN - 1;
 
rc = copy_from_uspace(namebuf, uspace_name, name_len);
rc = copy_from_uspace(namebuf, uspace_name, THREAD_NAME_BUFLEN);
if (rc != 0)
return (unative_t) rc;
 
namebuf[name_len] = 0;
 
/*
* In case of failure, kernel_uarg will be deallocated in this function.
* In case of success, kernel_uarg will be freed in uinit().
*/
kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
rc = copy_from_uspace(kernel_uarg, uspace_uarg, sizeof(uspace_arg_t));
if (rc != 0) {
free(kernel_uarg);
737,49 → 655,15
return (unative_t) rc;
}
 
t = thread_create(uinit, kernel_uarg, TASK,
THREAD_FLAG_USPACE | THREAD_FLAG_NOATTACH, namebuf, false);
t = thread_create(uinit, kernel_uarg, TASK, THREAD_FLAG_USPACE, namebuf,
false);
if (t) {
if (uspace_thread_id != NULL) {
int rc;
 
rc = copy_to_uspace(uspace_thread_id, &t->tid,
sizeof(t->tid));
if (rc != 0) {
/*
* We have encountered a failure, but the thread
* has already been created. We need to undo its
* creation now.
*/
 
/*
* The new thread structure is initialized, but
* is still not visible to the system.
* We can safely deallocate it.
*/
slab_free(thread_slab, t);
free(kernel_uarg);
 
return (unative_t) rc;
}
}
#ifdef CONFIG_UDEBUG
/*
* Generate udebug THREAD_B event and attach the thread.
* This must be done atomically (with the debug locks held),
* otherwise we would either miss some thread or receive
* THREAD_B events for threads that already existed
* and could be detected with THREAD_READ before.
*/
udebug_thread_b_event_attach(t, TASK);
#else
thread_attach(t, TASK);
#endif
tid = t->tid;
thread_ready(t);
 
return 0;
} else
return (unative_t) tid;
} else {
free(kernel_uarg);
}
 
return (unative_t) ENOMEM;
}
794,22 → 678,6
return 0;
}
 
/** Syscall for getting TID.
*
* @param uspace_thread_id Userspace address of 8-byte buffer where to store
* current thread ID.
*
* @return 0 on success or an error code from @ref errno.h.
/** @}
*/
unative_t sys_thread_get_id(thread_id_t *uspace_thread_id)
{
/*
* No need to acquire lock on THREAD because tid
* remains constant for the lifespan of the thread.
*/
return (unative_t) copy_to_uspace(uspace_thread_id, &THREAD->tid,
sizeof(THREAD->tid));
}
 
/** @}
*/
/branches/arm/kernel/generic/src/ddi/irq.c
39,8 → 39,7
*
* This code is designed to support:
* - multiple devices sharing single IRQ
* - multiple IRQs per single device
* - multiple instances of the same device
* - multiple IRQs per signle device
*
*
* Note about architectures.
69,11 → 68,8
 
#include <ddi/irq.h>
#include <adt/hash_table.h>
#include <mm/slab.h>
#include <arch/types.h>
#include <synch/spinlock.h>
#include <console/console.h>
#include <memstr.h>
#include <arch.h>
 
#define KEY_INR 0
80,33 → 76,23
#define KEY_DEVNO 1
 
/**
* Spinlock protecting the kernel IRQ hash table.
* Spinlock protecting the hash table.
* This lock must be taken only when interrupts are disabled.
*/
SPINLOCK_INITIALIZE(irq_kernel_hash_table_lock);
/** The kernel IRQ hash table. */
static hash_table_t irq_kernel_hash_table;
SPINLOCK_INITIALIZE(irq_hash_table_lock);
static hash_table_t irq_hash_table;
 
/**
* Spinlock protecting the uspace IRQ hash table.
* This lock must be taken only when interrupts are disabled.
*/
SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock);
/** The uspace IRQ hash table. */
hash_table_t irq_uspace_hash_table;
 
/**
* Hash table operations for cases when we know that
* there will be collisions between different keys.
*/
static size_t irq_ht_hash(unative_t *key);
static bool irq_ht_compare(unative_t *key, size_t keys, link_t *item);
static void irq_ht_remove(link_t *item);
static index_t irq_ht_hash(unative_t *key);
static bool irq_ht_compare(unative_t *key, count_t keys, link_t *item);
 
static hash_table_operations_t irq_ht_ops = {
.hash = irq_ht_hash,
.compare = irq_ht_compare,
.remove_callback = irq_ht_remove,
.remove_callback = NULL /* not used */
};
 
/**
115,27 → 101,22
* However, there might be still collisions among
* elements with single key (sharing of one IRQ).
*/
static size_t irq_lin_hash(unative_t *key);
static bool irq_lin_compare(unative_t *key, size_t keys, link_t *item);
static void irq_lin_remove(link_t *item);
static index_t irq_lin_hash(unative_t *key);
static bool irq_lin_compare(unative_t *key, count_t keys, link_t *item);
 
static hash_table_operations_t irq_lin_ops = {
.hash = irq_lin_hash,
.compare = irq_lin_compare,
.remove_callback = irq_lin_remove,
.remove_callback = NULL /* not used */
};
 
/** Number of buckets in either of the hash tables. */
static size_t buckets;
 
/** Initialize IRQ subsystem.
*
* @param inrs Numbers of unique IRQ numbers or INRs.
* @param chains Number of chains in the hash table.
*/
void irq_init(size_t inrs, size_t chains)
void irq_init(count_t inrs, count_t chains)
{
buckets = chains;
/*
* Be smart about the choice of the hash table operations.
* In cases in which inrs equals the requested number of
142,17 → 123,10
* chains (i.e. where there is no collision between
* different keys), we can use optimized set of operations.
*/
if (inrs == chains) {
hash_table_create(&irq_uspace_hash_table, chains, 2,
&irq_lin_ops);
hash_table_create(&irq_kernel_hash_table, chains, 2,
&irq_lin_ops);
} else {
hash_table_create(&irq_uspace_hash_table, chains, 2,
&irq_ht_ops);
hash_table_create(&irq_kernel_hash_table, chains, 2,
&irq_ht_ops);
}
if (inrs == chains)
hash_table_create(&irq_hash_table, chains, 2, &irq_lin_ops);
else
hash_table_create(&irq_hash_table, chains, 2, &irq_ht_ops);
}
 
/** Initialize one IRQ structure.
162,12 → 136,20
*/
void irq_initialize(irq_t *irq)
{
memsetb(irq, sizeof(irq_t), 0);
link_initialize(&irq->link);
spinlock_initialize(&irq->lock, "irq.lock");
link_initialize(&irq->notif_cfg.link);
irq->inr = -1;
irq->devno = -1;
irq->trigger = (irq_trigger_t) 0;
irq->claim = NULL;
irq->handler = NULL;
irq->arg = NULL;
irq->notif_cfg.notify = false;
irq->notif_cfg.answerbox = NULL;
irq->notif_cfg.code = NULL;
irq->notif_cfg.method = 0;
irq->notif_cfg.counter = 0;
link_initialize(&irq->notif_cfg.link);
}
 
/** Register IRQ for device.
174,10 → 156,9
*
* The irq structure must be filled with information
* about the interrupt source and with the claim()
* function pointer and handler() function pointer.
* function pointer and irq_handler() function pointer.
*
* @param irq IRQ structure belonging to a device.
* @return True on success, false on failure.
* @param irq IRQ structure belonging to a device.
*/
void irq_register(irq_t *irq)
{
188,101 → 169,88
};
ipl = interrupts_disable();
spinlock_lock(&irq_kernel_hash_table_lock);
spinlock_lock(&irq->lock);
hash_table_insert(&irq_kernel_hash_table, key, &irq->link);
spinlock_unlock(&irq->lock);
spinlock_unlock(&irq_kernel_hash_table_lock);
spinlock_lock(&irq_hash_table_lock);
hash_table_insert(&irq_hash_table, key, &irq->link);
spinlock_unlock(&irq_hash_table_lock);
interrupts_restore(ipl);
}
 
/** Search and lock the uspace IRQ hash table.
/** Dispatch the IRQ.
*
* We assume this function is only called from interrupt
* context (i.e. that interrupts are disabled prior to
* this call).
*
* This function attempts to lookup a fitting IRQ
* structure. In case of success, return with interrupts
* disabled and holding the respective structure.
*
* @param inr Interrupt number (aka inr or irq).
*
* @return IRQ structure of the respective device or NULL.
*/
static irq_t *irq_dispatch_and_lock_uspace(inr_t inr)
irq_t *irq_dispatch_and_lock(inr_t inr)
{
link_t *lnk;
unative_t key[] = {
(unative_t) inr,
(unative_t) -1 /* search will use claim() instead of devno */
(unative_t) -1 /* search will use claim() instead of devno */
};
spinlock_lock(&irq_uspace_hash_table_lock);
lnk = hash_table_find(&irq_uspace_hash_table, key);
spinlock_lock(&irq_hash_table_lock);
 
lnk = hash_table_find(&irq_hash_table, key);
if (lnk) {
irq_t *irq;
irq = hash_table_get_instance(lnk, irq_t, link);
spinlock_unlock(&irq_uspace_hash_table_lock);
 
spinlock_unlock(&irq_hash_table_lock);
return irq;
}
spinlock_unlock(&irq_uspace_hash_table_lock);
return NULL;
spinlock_unlock(&irq_hash_table_lock);
 
return NULL;
}
 
/** Search and lock the kernel IRQ hash table.
/** Find the IRQ structure corresponding to inr and devno.
*
* This functions attempts to lookup the IRQ structure
* corresponding to its arguments. On success, this
* function returns with interrups disabled, holding
* the lock of the respective IRQ structure.
*
* This function assumes interrupts are already disabled.
*
* @param inr INR being looked up.
* @param devno Devno being looked up.
*
* @return Locked IRQ structure on success or NULL on failure.
*/
static irq_t *irq_dispatch_and_lock_kernel(inr_t inr)
irq_t *irq_find_and_lock(inr_t inr, devno_t devno)
{
link_t *lnk;
unative_t key[] = {
unative_t keys[] = {
(unative_t) inr,
(unative_t) -1 /* search will use claim() instead of devno */
(unative_t) devno
};
spinlock_lock(&irq_kernel_hash_table_lock);
lnk = hash_table_find(&irq_kernel_hash_table, key);
spinlock_lock(&irq_hash_table_lock);
 
lnk = hash_table_find(&irq_hash_table, keys);
if (lnk) {
irq_t *irq;
irq = hash_table_get_instance(lnk, irq_t, link);
spinlock_unlock(&irq_kernel_hash_table_lock);
 
spinlock_unlock(&irq_hash_table_lock);
return irq;
}
spinlock_unlock(&irq_kernel_hash_table_lock);
return NULL;
}
spinlock_unlock(&irq_hash_table_lock);
 
/** Dispatch the IRQ.
*
* We assume this function is only called from interrupt
* context (i.e. that interrupts are disabled prior to
* this call).
*
* This function attempts to lookup a fitting IRQ
* structure. In case of success, return with interrupts
* disabled and holding the respective structure.
*
* @param inr Interrupt number (aka inr or irq).
*
* @return IRQ structure of the respective device or NULL.
*/
irq_t *irq_dispatch_and_lock(inr_t inr)
{
irq_t *irq;
/*
* If the kernel console is silenced,
* then try first the uspace handlers,
* eventually fall back to kernel handlers.
*
* If the kernel console is active,
* then do it the other way around.
*/
if (silent) {
irq = irq_dispatch_and_lock_uspace(inr);
if (irq)
return irq;
return irq_dispatch_and_lock_kernel(inr);
}
irq = irq_dispatch_and_lock_kernel(inr);
if (irq)
return irq;
return irq_dispatch_and_lock_uspace(inr);
return NULL;
}
 
/** Compute hash index for the key.
298,10 → 266,10
*
* @return Index into the hash table.
*/
size_t irq_ht_hash(unative_t key[])
index_t irq_ht_hash(unative_t key[])
{
inr_t inr = (inr_t) key[KEY_INR];
return inr % buckets;
return inr % irq_hash_table.entries;
}
 
/** Compare hash table element with a key.
324,7 → 292,7
*
* @return True on match or false otherwise.
*/
bool irq_ht_compare(unative_t key[], size_t keys, link_t *item)
bool irq_ht_compare(unative_t key[], count_t keys, link_t *item)
{
irq_t *irq = hash_table_get_instance(item, irq_t, link);
inr_t inr = (inr_t) key[KEY_INR];
335,8 → 303,7
spinlock_lock(&irq->lock);
if (devno == -1) {
/* Invoked by irq_dispatch_and_lock(). */
rv = ((irq->inr == inr) &&
(irq->claim(irq) == IRQ_ACCEPT));
rv = ((irq->inr == inr) && (irq->claim() == IRQ_ACCEPT));
} else {
/* Invoked by irq_find_and_lock(). */
rv = ((irq->inr == inr) && (irq->devno == devno));
349,17 → 316,6
return rv;
}
 
/** Unlock IRQ structure after hash_table_remove().
*
* @param lnk Link in the removed and locked IRQ structure.
*/
void irq_ht_remove(link_t *lnk)
{
irq_t *irq __attribute__((unused))
= hash_table_get_instance(lnk, irq_t, link);
spinlock_unlock(&irq->lock);
}
 
/** Compute hash index for the key.
*
* This function computes hash index into
371,7 → 327,7
*
* @return Index into the hash table.
*/
size_t irq_lin_hash(unative_t key[])
index_t irq_lin_hash(unative_t key[])
{
inr_t inr = (inr_t) key[KEY_INR];
return inr;
397,7 → 353,7
*
* @return True on match or false otherwise.
*/
bool irq_lin_compare(unative_t key[], size_t keys, link_t *item)
bool irq_lin_compare(unative_t key[], count_t keys, link_t *item)
{
irq_t *irq = list_get_instance(item, irq_t, link);
devno_t devno = (devno_t) key[KEY_DEVNO];
406,7 → 362,7
spinlock_lock(&irq->lock);
if (devno == -1) {
/* Invoked by irq_dispatch_and_lock() */
rv = (irq->claim(irq) == IRQ_ACCEPT);
rv = (irq->claim() == IRQ_ACCEPT);
} else {
/* Invoked by irq_find_and_lock() */
rv = (irq->devno == devno);
419,16 → 375,5
return rv;
}
 
/** Unlock IRQ structure after hash_table_remove().
*
* @param lnk Link in the removed and locked IRQ structure.
*/
void irq_lin_remove(link_t *lnk)
{
irq_t *irq __attribute__((unused))
= hash_table_get_instance(lnk, irq_t, link);
spinlock_unlock(&irq->lock);
}
 
/** @}
*/
/branches/arm/kernel/generic/src/ddi/ddi.c
29,10 → 29,10
/** @addtogroup genericddi
* @{
*/
 
/**
* @file
* @brief Device Driver Interface functions.
* @brief Device Driver Interface functions.
*
* This file contains functions that comprise the Device Driver Interface.
* These are the functions for mapping physical memory and enabling I/O
68,100 → 68,95
*
* @param parea Pointer to physical area structure.
*
* @todo This function doesn't check for overlaps. It depends on the kernel to
* create disjunct physical memory areas.
*/
void ddi_parea_register(parea_t *parea)
{
ipl_t ipl = interrupts_disable();
ipl_t ipl;
 
ipl = interrupts_disable();
spinlock_lock(&parea_lock);
/*
* We don't check for overlaps here as the kernel is pretty sane.
* TODO: we should really check for overlaps here.
* However, we should be safe because the kernel is pretty sane and
* memory of different devices doesn't overlap.
*/
btree_insert(&parea_btree, (btree_key_t) parea->pbase, parea, NULL);
 
spinlock_unlock(&parea_lock);
interrupts_restore(ipl);
interrupts_restore(ipl);
}
 
/** Map piece of physical memory into virtual address space of current task.
*
* @param pf Physical address of the starting frame.
* @param vp Virtual address of the starting page.
* @param pf Physical address of the starting frame.
* @param vp Virtual address of the starting page.
* @param pages Number of pages to map.
* @param flags Address space area flags for the mapping.
*
* @return 0 on success, EPERM if the caller lacks capabilities to use this
* syscall, EBADMEM if pf or vf is not page aligned, ENOENT if there
* is no task matching the specified ID or the physical address space
* is not enabled for mapping and ENOMEM if there was a problem in
* creating address space area.
*
* syscall, ENOENT if there is no task matching the specified ID or the
* physical address space is not enabled for mapping and ENOMEM if there
* was a problem in creating address space area. ENOTSUP is returned when
* an attempt to create an illegal address alias is detected.
*/
static int ddi_physmem_map(uintptr_t pf, uintptr_t vp, size_t pages, int flags)
static int ddi_physmem_map(uintptr_t pf, uintptr_t vp, count_t pages, int flags)
{
ASSERT(TASK);
ASSERT((pf % FRAME_SIZE) == 0);
ASSERT((vp % PAGE_SIZE) == 0);
ipl_t ipl;
cap_t caps;
mem_backend_data_t backend_data;
 
backend_data.base = pf;
backend_data.frames = pages;
/*
* Make sure the caller is authorised to make this syscall.
*/
cap_t caps = cap_get(TASK);
caps = cap_get(TASK);
if (!(caps & CAP_MEM_MANAGER))
return EPERM;
mem_backend_data_t backend_data;
backend_data.base = pf;
backend_data.frames = pages;
ipl_t ipl = interrupts_disable();
/* Find the zone of the physical memory */
spinlock_lock(&zones.lock);
size_t znum = find_zone(ADDR2PFN(pf), pages, 0);
if (znum == (size_t) -1) {
/* Frames not found in any zones
* -> assume it is hardware device and allow mapping
 
ipl = interrupts_disable();
 
/*
* Check if the physical memory area is enabled for mapping.
* If the architecture supports virtually indexed caches, intercept
* attempts to create an illegal address alias.
*/
spinlock_lock(&parea_lock);
parea_t *parea;
btree_node_t *nodep;
parea = (parea_t *) btree_search(&parea_btree, (btree_key_t) pf, &nodep);
if (!parea || parea->frames < pages || ((flags & AS_AREA_CACHEABLE) &&
!parea->cacheable) || (!(flags & AS_AREA_CACHEABLE) &&
parea->cacheable)) {
/*
* This physical memory area cannot be mapped.
*/
spinlock_unlock(&zones.lock);
goto map;
spinlock_unlock(&parea_lock);
interrupts_restore(ipl);
return ENOENT;
}
if (zones.info[znum].flags & ZONE_FIRMWARE) {
/* Frames are part of firmware */
spinlock_unlock(&zones.lock);
goto map;
}
if (zone_flags_available(zones.info[znum].flags)) {
/* Frames are part of physical memory, check if the memory
* region is enabled for mapping.
 
#ifdef CONFIG_VIRT_IDX_DCACHE
if (PAGE_COLOR(parea->vbase) != PAGE_COLOR(vp)) {
/*
* Refuse to create an illegal address alias.
*/
spinlock_unlock(&zones.lock);
spinlock_lock(&parea_lock);
btree_node_t *nodep;
parea_t *parea = (parea_t *) btree_search(&parea_btree,
(btree_key_t) pf, &nodep);
if ((!parea) || (parea->frames < pages))
goto err;
spinlock_unlock(&parea_lock);
goto map;
interrupts_restore(ipl);
return ENOTSUP;
}
err:
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return ENOENT;
map:
#endif /* CONFIG_VIRT_IDX_DCACHE */
 
spinlock_unlock(&parea_lock);
 
spinlock_lock(&TASK->lock);
if (!as_area_create(TASK->as, flags, pages * PAGE_SIZE, vp,
AS_AREA_ATTR_NONE, &phys_backend, &backend_data)) {
if (!as_area_create(TASK->as, flags, pages * PAGE_SIZE, vp, AS_AREA_ATTR_NONE,
&phys_backend, &backend_data)) {
/*
* The address space area could not have been created.
* We report it using ENOMEM.
187,24 → 182,28
* @param size Size of the enabled I/O space..
*
* @return 0 on success, EPERM if the caller lacks capabilities to use this
* syscall, ENOENT if there is no task matching the specified ID.
*
* syscall, ENOENT if there is no task matching the specified ID.
*/
static int ddi_iospace_enable(task_id_t id, uintptr_t ioaddr, size_t size)
{
ipl_t ipl;
cap_t caps;
task_t *t;
int rc;
/*
* Make sure the caller is authorised to make this syscall.
*/
cap_t caps = cap_get(TASK);
caps = cap_get(TASK);
if (!(caps & CAP_IO_MANAGER))
return EPERM;
ipl_t ipl = interrupts_disable();
ipl = interrupts_disable();
spinlock_lock(&tasks_lock);
task_t *task = task_find_by_id(id);
t = task_find_by_id(id);
if ((!task) || (!context_check(CONTEXT, task->context))) {
if ((!t) || (!context_check(CONTEXT, t->context))) {
/*
* There is no task with the specified ID
* or the task belongs to a different security
214,16 → 213,15
interrupts_restore(ipl);
return ENOENT;
}
 
/* Lock the task and release the lock protecting tasks_btree. */
spinlock_lock(&task->lock);
spinlock_lock(&t->lock);
spinlock_unlock(&tasks_lock);
 
rc = ddi_iospace_enable_arch(t, ioaddr, size);
int rc = ddi_iospace_enable_arch(task, ioaddr, size);
spinlock_unlock(&task->lock);
spinlock_unlock(&t->lock);
interrupts_restore(ipl);
return rc;
}
 
235,14 → 233,13
* @param flags Flags of newly mapped pages
*
* @return 0 on success, otherwise it returns error code found in errno.h
*
*/
*/
unative_t sys_physmem_map(unative_t phys_base, unative_t virt_base,
unative_t pages, unative_t flags)
{
return (unative_t) ddi_physmem_map(ALIGN_DOWN((uintptr_t) phys_base,
FRAME_SIZE), ALIGN_DOWN((uintptr_t) virt_base, PAGE_SIZE),
(size_t) pages, (int) flags);
(count_t) pages, (int) flags);
}
 
/** Wrapper for SYS_ENABLE_IOSPACE syscall.
250,15 → 247,16
* @param uspace_io_arg User space address of DDI argument structure.
*
* @return 0 on success, otherwise it returns error code found in errno.h
*
*/
*/
unative_t sys_iospace_enable(ddi_ioarg_t *uspace_io_arg)
{
ddi_ioarg_t arg;
int rc = copy_from_uspace(&arg, uspace_io_arg, sizeof(ddi_ioarg_t));
int rc;
rc = copy_from_uspace(&arg, uspace_io_arg, sizeof(ddi_ioarg_t));
if (rc != 0)
return (unative_t) rc;
return (unative_t) ddi_iospace_enable((task_id_t) arg.task_id,
(uintptr_t) arg.ioaddr, (size_t) arg.size);
}
266,24 → 264,20
/** Disable or enable preemption.
*
* @param enable If non-zero, the preemption counter will be decremented,
* leading to potential enabling of preemption. Otherwise
* the preemption counter will be incremented, preventing
* preemption from occurring.
* leading to potential enabling of preemption. Otherwise the preemption
* counter will be incremented, preventing preemption from occurring.
*
* @return Zero on success or EPERM if callers capabilities are not sufficient.
*
*/
*/
unative_t sys_preempt_control(int enable)
{
if (!cap_get(TASK) & CAP_PREEMPT_CONTROL)
return EPERM;
if (enable)
preemption_enable();
else
preemption_disable();
return 0;
if (!cap_get(TASK) & CAP_PREEMPT_CONTROL)
return EPERM;
if (enable)
preemption_enable();
else
preemption_disable();
return 0;
}
 
/** @}
/branches/arm/kernel/generic/src/ddi/device.c
31,7 → 31,7
*/
/**
* @file
* @brief Device numbers.
* @brief Device numbers.
*/
 
#include <arch/types.h>
47,16 → 47,13
*/
devno_t device_assign_devno(void)
{
devno_t devno = (devno_t) atomic_postinc(&last);
devno_t devno;
 
devno = (devno_t) atomic_postinc(&last);
ASSERT(devno >= 0);
 
return devno;
}
 
unative_t sys_device_assign_devno(void)
{
return (unative_t) device_assign_devno();
}
 
/** @}
*/
/branches/arm/kernel/generic/src/cpu/cpu.c
64,10 → 64,10
cpus = (cpu_t *) malloc(sizeof(cpu_t) * config.cpu_count,
FRAME_ATOMIC);
if (!cpus)
panic("Cannot allocate CPU structures.");
panic("malloc/cpus");
 
/* initialize everything */
memsetb(cpus, sizeof(cpu_t) * config.cpu_count, 0);
memsetb((uintptr_t) cpus, sizeof(cpu_t) * config.cpu_count, 0);
 
for (i = 0; i < config.cpu_count; i++) {
cpus[i].stack = (uint8_t *) frame_alloc(STACK_FRAMES, FRAME_KA | FRAME_ATOMIC);
86,7 → 86,7
}
#endif /* CONFIG_SMP */
 
CPU = &cpus[config.cpu_active - 1];
CPU = &cpus[config.cpu_active-1];
CPU->active = 1;
CPU->tlb_active = 1;
104,7 → 104,7
if (cpus[i].active)
cpu_print_report(&cpus[i]);
else
printf("cpu%u: not active\n", i);
printf("cpu%d: not active\n", i);
}
}
 
/branches/arm/kernel/generic/src/console/cmd.c
31,8 → 31,8
*/
 
/**
* @file cmd.c
* @brief Kernel console command wrappers.
* @file cmd.c
* @brief Kernel console command wrappers.
*
* This file is meant to contain all wrapper functions for
* all kconsole commands. The point is in separating
48,11 → 48,10
#include <arch/types.h>
#include <adt/list.h>
#include <arch.h>
#include <config.h>
#include <func.h>
#include <string.h>
#include <macros.h>
#include <debug.h>
#include <symtab.h>
#include <cpu.h>
#include <mm/tlb.h>
#include <arch/mm/tlb.h>
64,9 → 63,6
#include <proc/task.h>
#include <ipc/ipc.h>
#include <ipc/irq.h>
#include <ipc/event.h>
#include <symtab.h>
#include <errno.h>
 
#ifdef CONFIG_TEST
#include <test.h>
81,22 → 77,12
.argc = 0
};
 
static int cmd_reboot(cmd_arg_t *argv);
static cmd_info_t reboot_info = {
.name = "reboot",
.description = "Reboot.",
.func = cmd_reboot,
static cmd_info_t exit_info = {
.name = "exit",
.description = "Exit kconsole",
.argc = 0
};
 
static int cmd_uptime(cmd_arg_t *argv);
static cmd_info_t uptime_info = {
.name = "uptime",
.description = "Print uptime information.",
.func = cmd_uptime,
.argc = 0
};
 
static int cmd_continue(cmd_arg_t *argv);
static cmd_info_t continue_info = {
.name = "continue",
206,10 → 192,10
};
 
/* Data and methods for 'call0' command. */
static char call0_buf[MAX_CMDLINE + 1];
static char carg1_buf[MAX_CMDLINE + 1];
static char carg2_buf[MAX_CMDLINE + 1];
static char carg3_buf[MAX_CMDLINE + 1];
static char call0_buf[MAX_CMDLINE+1];
static char carg1_buf[MAX_CMDLINE+1];
static char carg2_buf[MAX_CMDLINE+1];
static char carg3_buf[MAX_CMDLINE+1];
 
static int cmd_call0(cmd_arg_t *argv);
static cmd_arg_t call0_argv = {
225,21 → 211,6
.argv = &call0_argv
};
 
/* Data and methods for 'mcall0' command. */
static int cmd_mcall0(cmd_arg_t *argv);
static cmd_arg_t mcall0_argv = {
.type = ARG_TYPE_STRING,
.buffer = call0_buf,
.len = sizeof(call0_buf)
};
static cmd_info_t mcall0_info = {
.name = "mcall0",
.description = "mcall0 <function> -> call function() on each CPU.",
.func = cmd_mcall0,
.argc = 1,
.argv = &mcall0_argv
};
 
/* Data and methods for 'call1' command. */
static int cmd_call1(cmd_arg_t *argv);
static cmd_arg_t call1_argv[] = {
331,17 → 302,6
.argc = 0
};
 
/* Data and methods for 'physmem' command. */
static int cmd_physmem(cmd_arg_t *argv);
cmd_info_t physmem_info = {
.name = "physmem",
.description = "Print physical memory configuration.",
.help = NULL,
.func = cmd_physmem,
.argc = 0,
.argv = NULL
};
 
/* Data and methods for 'tlb' command. */
static int cmd_tlb(cmd_arg_t *argv);
cmd_info_t tlb_info = {
395,17 → 355,17
.argc = 0
};
 
/* Data and methods for 'ipc' command */
static int cmd_ipc(cmd_arg_t *argv);
static cmd_arg_t ipc_argv = {
/* Data and methods for 'ipc_task' command */
static int cmd_ipc_task(cmd_arg_t *argv);
static cmd_arg_t ipc_task_argv = {
.type = ARG_TYPE_INT,
};
static cmd_info_t ipc_info = {
.name = "ipc",
.description = "ipc <taskid> Show IPC information of given task.",
.func = cmd_ipc,
static cmd_info_t ipc_task_info = {
.name = "ipc_task",
.description = "ipc_task <taskid> Show IPC information of given task.",
.func = cmd_ipc_task,
.argc = 1,
.argv = &ipc_argv
.argv = &ipc_task_argv
};
 
/* Data and methods for 'zone' command */
446,7 → 406,6
 
static cmd_info_t *basic_commands[] = {
&call0_info,
&mcall0_info,
&call1_info,
&call2_info,
&call3_info,
453,11 → 412,10
&continue_info,
&cpus_info,
&desc_info,
&reboot_info,
&uptime_info,
&exit_info,
&halt_info,
&help_info,
&ipc_info,
&ipc_task_info,
&set4_info,
&slabs_info,
&symaddr_info,
464,7 → 422,6
&sched_info,
&threads_info,
&tasks_info,
&physmem_info,
&tlb_info,
&version_info,
&zones_info,
492,12 → 449,13
/** Initialize and register commands. */
void cmd_init(void)
{
unsigned int i;
int i;
 
for (i = 0; basic_commands[i]; i++) {
for (i=0;basic_commands[i]; i++) {
cmd_initialize(basic_commands[i]);
if (!cmd_register(basic_commands[i]))
printf("Cannot register command %s\n", basic_commands[i]->name);
panic("could not register command %s\n",
basic_commands[i]->name);
}
}
 
510,69 → 468,26
*/
int cmd_help(cmd_arg_t *argv)
{
link_t *cur;
 
spinlock_lock(&cmd_lock);
link_t *cur;
size_t len = 0;
for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
cmd_info_t *hlp;
hlp = list_get_instance(cur, cmd_info_t, link);
spinlock_lock(&hlp->lock);
if (str_length(hlp->name) > len)
len = str_length(hlp->name);
spinlock_unlock(&hlp->lock);
}
for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
cmd_info_t *hlp;
hlp = list_get_instance(cur, cmd_info_t, link);
spinlock_lock(&hlp->lock);
printf("%-*s %s\n", len, hlp->name, hlp->description);
printf("%s - %s\n", hlp->name, hlp->description);
 
spinlock_unlock(&hlp->lock);
}
spinlock_unlock(&cmd_lock);
return 1;
}
spinlock_unlock(&cmd_lock);
 
 
/** Reboot the system.
*
* @param argv Argument vector.
*
* @return 0 on failure, 1 on success.
*/
int cmd_reboot(cmd_arg_t *argv)
{
reboot();
/* Not reached */
return 1;
}
 
 
/** Print system uptime information.
*
* @param argv Argument vector.
*
* @return 0 on failure, 1 on success.
*/
int cmd_uptime(cmd_arg_t *argv)
{
ASSERT(uptime);
/* This doesn't have to be very accurate */
unative_t sec = uptime->seconds1;
printf("Up %" PRIun " days, %" PRIun " hours, %" PRIun " minutes, %" PRIun " seconds\n",
sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
return 1;
}
 
/** Describe specified command.
*
* @param argv Argument vector.
582,7 → 497,7
int cmd_desc(cmd_arg_t *argv)
{
link_t *cur;
 
spinlock_lock(&cmd_lock);
for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
590,8 → 505,8
hlp = list_get_instance(cur, cmd_info_t, link);
spinlock_lock(&hlp->lock);
if (str_lcmp(hlp->name, (const char *) argv->buffer, str_length(hlp->name)) == 0) {
 
if (strncmp(hlp->name, (const char *) argv->buffer, strlen(hlp->name)) == 0) {
printf("%s - %s\n", hlp->name, hlp->description);
if (hlp->help)
hlp->help();
598,12 → 513,12
spinlock_unlock(&hlp->lock);
break;
}
 
spinlock_unlock(&hlp->lock);
}
spinlock_unlock(&cmd_lock);
 
return 1;
}
 
620,55 → 535,33
{
uintptr_t symaddr;
char *symbol;
unative_t (*fnc)(void);
fncptr_t fptr;
int rc;
unative_t (*f)(void);
#ifdef ia64
struct {
unative_t f;
unative_t gp;
}fptr;
#endif
 
symbol = (char *) argv->buffer;
rc = symtab_addr_lookup(symbol, &symaddr);
 
if (rc == ENOENT)
printf("Symbol %s not found.\n", symbol);
else if (rc == EOVERFLOW) {
symtab_print_search(symbol);
symaddr = get_symbol_addr((char *) argv->buffer);
if (!symaddr)
printf("Symbol %s not found.\n", argv->buffer);
else if (symaddr == (uintptr_t) -1) {
symtab_print_search((char *) argv->buffer);
printf("Duplicate symbol, be more specific.\n");
} else if (rc == EOK) {
fnc = (unative_t (*)(void)) arch_construct_function(&fptr,
(void *) symaddr, (void *) cmd_call0);
printf("Calling %s() (%p)\n", symbol, symaddr);
printf("Result: %#" PRIxn "\n", fnc());
} else {
printf("No symbol information available.\n");
symbol = get_symtab_entry(symaddr);
printf("Calling f(): %.*p: %s\n", sizeof(uintptr_t) * 2, symaddr, symbol);
#ifdef ia64
fptr.f = symaddr;
fptr.gp = ((unative_t *)cmd_call2)[1];
f = (unative_t (*)(void)) &fptr;
#else
f = (unative_t (*)(void)) symaddr;
#endif
printf("Result: %#zx\n", f());
}
return 1;
}
 
/** Call function with zero parameters on each CPU */
int cmd_mcall0(cmd_arg_t *argv)
{
/*
* For each CPU, create a thread which will
* call the function.
*/
size_t i;
for (i = 0; i < config.cpu_count; i++) {
if (!cpus[i].active)
continue;
thread_t *t;
if ((t = thread_create((void (*)(void *)) cmd_call0, (void *) argv, TASK, THREAD_FLAG_WIRED, "call0", false))) {
spinlock_lock(&t->lock);
t->cpu = &cpus[i];
spinlock_unlock(&t->lock);
printf("cpu%u: ", i);
thread_ready(t);
thread_join(t);
thread_detach(t);
} else
printf("Unable to create thread for cpu%u\n", i);
}
return 1;
}
 
677,27 → 570,35
{
uintptr_t symaddr;
char *symbol;
unative_t (*fnc)(unative_t, ...);
unative_t (*f)(unative_t,...);
unative_t arg1 = argv[1].intval;
fncptr_t fptr;
int rc;
#ifdef ia64
struct {
unative_t f;
unative_t gp;
}fptr;
#endif
 
symbol = (char *) argv->buffer;
rc = symtab_addr_lookup(symbol, &symaddr);
 
if (rc == ENOENT) {
printf("Symbol %s not found.\n", symbol);
} else if (rc == EOVERFLOW) {
symtab_print_search(symbol);
symaddr = get_symbol_addr((char *) argv->buffer);
if (!symaddr)
printf("Symbol %s not found.\n", argv->buffer);
else if (symaddr == (uintptr_t) -1) {
symtab_print_search((char *) argv->buffer);
printf("Duplicate symbol, be more specific.\n");
} else if (rc == EOK) {
fnc = (unative_t (*)(unative_t, ...)) arch_construct_function(&fptr, (void *) symaddr, (void *) cmd_call1);
printf("Calling f(%#" PRIxn "): %p: %s\n", arg1, symaddr, symbol);
printf("Result: %#" PRIxn "\n", fnc(arg1));
} else {
printf("No symbol information available.\n");
symbol = get_symtab_entry(symaddr);
 
printf("Calling f(%#zx): %.*p: %s\n", arg1, sizeof(uintptr_t) * 2, symaddr, symbol);
#ifdef ia64
fptr.f = symaddr;
fptr.gp = ((unative_t *)cmd_call2)[1];
f = (unative_t (*)(unative_t,...)) &fptr;
#else
f = (unative_t (*)(unative_t,...)) symaddr;
#endif
printf("Result: %#zx\n", f(arg1));
}
 
return 1;
}
 
706,28 → 607,36
{
uintptr_t symaddr;
char *symbol;
unative_t (*fnc)(unative_t, unative_t, ...);
unative_t (*f)(unative_t,unative_t,...);
unative_t arg1 = argv[1].intval;
unative_t arg2 = argv[2].intval;
fncptr_t fptr;
int rc;
#ifdef ia64
struct {
unative_t f;
unative_t gp;
}fptr;
#endif
 
symbol = (char *) argv->buffer;
rc = symtab_addr_lookup(symbol, &symaddr);
 
if (rc == ENOENT) {
printf("Symbol %s not found.\n", symbol);
} else if (rc == EOVERFLOW) {
symtab_print_search(symbol);
symaddr = get_symbol_addr((char *) argv->buffer);
if (!symaddr)
printf("Symbol %s not found.\n", argv->buffer);
else if (symaddr == (uintptr_t) -1) {
symtab_print_search((char *) argv->buffer);
printf("Duplicate symbol, be more specific.\n");
} else if (rc == EOK) {
fnc = (unative_t (*)(unative_t, unative_t, ...)) arch_construct_function(&fptr, (void *) symaddr, (void *) cmd_call2);
printf("Calling f(%#" PRIxn ", %#" PRIxn "): %p: %s\n",
arg1, arg2, symaddr, symbol);
printf("Result: %#" PRIxn "\n", fnc(arg1, arg2));
} else {
printf("No symbol information available.\n");
symbol = get_symtab_entry(symaddr);
printf("Calling f(0x%zx,0x%zx): %.*p: %s\n",
arg1, arg2, sizeof(uintptr_t) * 2, symaddr, symbol);
#ifdef ia64
fptr.f = symaddr;
fptr.gp = ((unative_t *)cmd_call2)[1];
f = (unative_t (*)(unative_t,unative_t,...)) &fptr;
#else
f = (unative_t (*)(unative_t,unative_t,...)) symaddr;
#endif
printf("Result: %#zx\n", f(arg1, arg2));
}
return 1;
}
 
736,29 → 645,37
{
uintptr_t symaddr;
char *symbol;
unative_t (*fnc)(unative_t, unative_t, unative_t, ...);
unative_t (*f)(unative_t,unative_t,unative_t,...);
unative_t arg1 = argv[1].intval;
unative_t arg2 = argv[2].intval;
unative_t arg3 = argv[3].intval;
fncptr_t fptr;
int rc;
symbol = (char *) argv->buffer;
rc = symtab_addr_lookup(symbol, &symaddr);
#ifdef ia64
struct {
unative_t f;
unative_t gp;
}fptr;
#endif
 
if (rc == ENOENT) {
printf("Symbol %s not found.\n", symbol);
} else if (rc == EOVERFLOW) {
symtab_print_search(symbol);
symaddr = get_symbol_addr((char *) argv->buffer);
if (!symaddr)
printf("Symbol %s not found.\n", argv->buffer);
else if (symaddr == (uintptr_t) -1) {
symtab_print_search((char *) argv->buffer);
printf("Duplicate symbol, be more specific.\n");
} else if (rc == EOK) {
fnc = (unative_t (*)(unative_t, unative_t, unative_t, ...)) arch_construct_function(&fptr, (void *) symaddr, (void *) cmd_call3);
printf("Calling f(%#" PRIxn ",%#" PRIxn ", %#" PRIxn "): %p: %s\n",
arg1, arg2, arg3, symaddr, symbol);
printf("Result: %#" PRIxn "\n", fnc(arg1, arg2, arg3));
} else {
printf("No symbol information available.\n");
symbol = get_symtab_entry(symaddr);
printf("Calling f(0x%zx,0x%zx, 0x%zx): %.*p: %s\n",
arg1, arg2, arg3, sizeof(uintptr_t) * 2, symaddr, symbol);
#ifdef ia64
fptr.f = symaddr;
fptr.gp = ((unative_t *)cmd_call2)[1];
f = (unative_t (*)(unative_t,unative_t,unative_t,...)) &fptr;
#else
f = (unative_t (*)(unative_t,unative_t,unative_t,...)) symaddr;
#endif
printf("Result: %#zx\n", f(arg1, arg2, arg3));
}
return 1;
}
 
793,49 → 710,33
return 1;
}
 
/** Command for printing physical memory configuration.
*
* @param argv Not used.
*
* @return Always returns 1.
*/
int cmd_physmem(cmd_arg_t *argv)
{
physmem_print();
return 1;
}
 
/** Write 4 byte value to address */
int cmd_set4(cmd_arg_t *argv)
{
uintptr_t addr;
uint32_t *addr ;
uint32_t arg1 = argv[1].intval;
bool pointer = false;
int rc;
 
if (((char *)argv->buffer)[0] == '*') {
rc = symtab_addr_lookup((char *) argv->buffer + 1, &addr);
addr = (uint32_t *) get_symbol_addr((char *) argv->buffer + 1);
pointer = true;
} else if (((char *) argv->buffer)[0] >= '0' &&
((char *)argv->buffer)[0] <= '9') {
rc = EOK;
addr = atoi((char *)argv->buffer);
} else {
rc = symtab_addr_lookup((char *) argv->buffer, &addr);
}
((char *)argv->buffer)[0] <= '9')
addr = (uint32_t *)atoi((char *)argv->buffer);
else
addr = (uint32_t *)get_symbol_addr((char *) argv->buffer);
 
if (rc == ENOENT)
if (!addr)
printf("Symbol %s not found.\n", argv->buffer);
else if (rc == EOVERFLOW) {
else if (addr == (uint32_t *) -1) {
symtab_print_search((char *) argv->buffer);
printf("Duplicate symbol, be more specific.\n");
} else if (rc == EOK) {
} else {
if (pointer)
addr = *(uintptr_t *) addr;
printf("Writing %#" PRIx64 " -> %p\n", arg1, addr);
*(uint32_t *) addr = arg1;
} else {
printf("No symbol information available.\n");
addr = (uint32_t *)(*(unative_t *)addr);
printf("Writing 0x%x -> %.*p\n", arg1, sizeof(uintptr_t) * 2, addr);
*addr = arg1;
}
return 1;
914,7 → 815,7
*
* return Always 1
*/
int cmd_ipc(cmd_arg_t * argv) {
int cmd_ipc_task(cmd_arg_t * argv) {
ipc_print_task(argv[0].intval);
return 1;
}
953,11 → 854,8
int cmd_continue(cmd_arg_t *argv)
{
printf("The kernel will now relinquish the console.\n");
release_console();
event_notify_0(EVENT_KCONSOLE);
indev_pop_character(stdin);
printf("Use userspace controls to redraw the screen.\n");
arch_release_console();
return 1;
}
 
970,23 → 868,18
*/
int cmd_tests(cmd_arg_t *argv)
{
size_t len = 0;
test_t *test;
for (test = tests; test->name != NULL; test++) {
if (str_length(test->name) > len)
len = str_length(test->name);
}
for (test = tests; test->name != NULL; test++)
printf("%-*s %s%s\n", len, test->name, test->desc, (test->safe ? "" : " (unsafe)"));
printf("%s\t\t%s%s\n", test->name, test->desc, (test->safe ? "" : " (unsafe)"));
printf("%-*s Run all safe tests\n", len, "*");
printf("*\t\tRun all safe tests\n");
return 1;
}
 
static bool run_test(const test_t *test)
{
printf("%s (%s)\n", test->name, test->desc);
printf("%s\t\t%s\n", test->name, test->desc);
/* Update and read thread accounting
for benchmarking */
997,8 → 890,7
interrupts_restore(ipl);
/* Execute the test */
test_quiet = false;
char *ret = test->entry();
char * ret = test->entry(false);
/* Update and read thread accounting */
ipl = interrupts_disable();
1011,7 → 903,7
char suffix;
order(dt, &cycles, &suffix);
printf("Time: %" PRIu64 "%c cycles\n", cycles, suffix);
printf("Time: %llu%c cycles\n", cycles, suffix);
if (ret == NULL) {
printf("Test passed\n");
1039,7 → 931,7
}
for (i = 0; i < cnt; i++) {
printf("%s (%u/%u) ... ", test->name, i + 1, cnt);
printf("%s (%d/%d) ... ", test->name, i + 1, cnt);
/* Update and read thread accounting
for benchmarking */
1050,8 → 942,7
interrupts_restore(ipl);
/* Execute the test */
test_quiet = true;
char * ret = test->entry();
char * ret = test->entry(true);
/* Update and read thread accounting */
ipl = interrupts_disable();
1068,7 → 959,7
data[i] = dt;
order(dt, &cycles, &suffix);
printf("OK (%" PRIu64 "%c cycles)\n", cycles, suffix);
printf("OK (%llu%c cycles)\n", cycles, suffix);
}
if (ret) {
1081,7 → 972,7
}
order(sum / (uint64_t) cnt, &cycles, &suffix);
printf("Average\t\t%" PRIu64 "%c\n", cycles, suffix);
printf("Average\t\t%llu%c\n", cycles, suffix);
}
free(data);
1099,7 → 990,7
{
test_t *test;
if (str_cmp((char *) argv->buffer, "*") == 0) {
if (strcmp((char *) argv->buffer, "*") == 0) {
for (test = tests; test->name != NULL; test++) {
if (test->safe) {
printf("\n");
1111,7 → 1002,7
bool fnd = false;
for (test = tests; test->name != NULL; test++) {
if (str_cmp(test->name, (char *) argv->buffer) == 0) {
if (strcmp(test->name, (char *) argv->buffer) == 0) {
fnd = true;
run_test(test);
break;
1136,33 → 1027,24
test_t *test;
uint32_t cnt = argv[1].intval;
if (str_cmp((char *) argv->buffer, "*") == 0) {
for (test = tests; test->name != NULL; test++) {
if (test->safe) {
if (!run_bench(test, cnt))
break;
}
bool fnd = false;
for (test = tests; test->name != NULL; test++) {
if (strcmp(test->name, (char *) argv->buffer) == 0) {
fnd = true;
if (test->safe)
run_bench(test, cnt);
else
printf("Unsafe test\n");
break;
}
} else {
bool fnd = false;
}
for (test = tests; test->name != NULL; test++) {
if (str_cmp(test->name, (char *) argv->buffer) == 0) {
fnd = true;
if (test->safe)
run_bench(test, cnt);
else
printf("Unsafe test\n");
break;
}
}
if (!fnd)
printf("Unknown test\n");
}
if (!fnd)
printf("Unknown test\n");
 
return 1;
}
 
/branches/arm/kernel/generic/src/console/kconsole.c
31,11 → 31,10
*/
 
/**
* @file kconsole.c
* @brief Kernel console.
* @file kconsole.c
* @brief Kernel console.
*
* This file contains kernel thread managing the kernel console.
*
*/
 
#include <console/kconsole.h>
50,14 → 49,8
#include <macros.h>
#include <debug.h>
#include <func.h>
#include <string.h>
#include <symtab.h>
#include <macros.h>
#include <sysinfo/sysinfo.h>
#include <ddi/device.h>
#include <symtab.h>
#include <errno.h>
#include <putchar.h>
#include <string.h>
 
/** Simple kernel console.
*
66,7 → 59,7
* but makes it possible for other kernel subsystems to
* register their own commands.
*/
 
/** Locking.
*
* There is a list of cmd_info_t structures. This list
81,36 → 74,33
* When locking two cmd info structures, structure with
* lower address must be locked first.
*/
SPINLOCK_INITIALIZE(cmd_lock); /**< Lock protecting command list. */
LIST_INITIALIZE(cmd_head); /**< Command list. */
 
SPINLOCK_INITIALIZE(cmd_lock); /**< Lock protecting command list. */
LIST_INITIALIZE(cmd_head); /**< Command list. */
static cmd_info_t *parse_cmdline(char *cmdline, size_t len);
static bool parse_argument(char *cmdline, size_t len, index_t *start,
index_t *end);
static char history[KCONSOLE_HISTORY][MAX_CMDLINE] = {};
 
static wchar_t history[KCONSOLE_HISTORY][MAX_CMDLINE] = {};
static size_t history_pos = 0;
 
/** Initialize kconsole data structures
*
* This is the most basic initialization, almost no
* other kernel subsystem is ready yet.
*
*/
/** Initialize kconsole data structures. */
void kconsole_init(void)
{
unsigned int i;
int i;
 
cmd_init();
for (i = 0; i < KCONSOLE_HISTORY; i++)
history[i][0] = 0;
history[i][0] = '\0';
}
 
 
/** Register kconsole command.
*
* @param cmd Structure describing the command.
*
* @return False on failure, true on success.
*
* @return 0 on failure, 1 on success.
*/
bool cmd_register(cmd_info_t *cmd)
int cmd_register(cmd_info_t *cmd)
{
link_t *cur;
120,14 → 110,16
* Make sure the command is not already listed.
*/
for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
cmd_info_t *hlp = list_get_instance(cur, cmd_info_t, link);
cmd_info_t *hlp;
hlp = list_get_instance(cur, cmd_info_t, link);
 
if (hlp == cmd) {
/* The command is already there. */
spinlock_unlock(&cmd_lock);
return false;
return 0;
}
 
/* Avoid deadlock. */
if (hlp < cmd) {
spinlock_lock(&hlp->lock);
136,13 → 128,13
spinlock_lock(&cmd->lock);
spinlock_lock(&hlp->lock);
}
if (str_cmp(hlp->name, cmd->name) == 0) {
if ((strncmp(hlp->name, cmd->name, max(strlen(cmd->name),
strlen(hlp->name))) == 0)) {
/* The command is already there. */
spinlock_unlock(&hlp->lock);
spinlock_unlock(&cmd->lock);
spinlock_unlock(&cmd_lock);
return false;
return 0;
}
spinlock_unlock(&hlp->lock);
155,274 → 147,293
list_append(&cmd->link, &cmd_head);
spinlock_unlock(&cmd_lock);
return true;
return 1;
}
 
/** Print count times a character */
static void print_cc(wchar_t ch, size_t count)
static void rdln_print_c(char ch, int count)
{
size_t i;
int i;
for (i = 0; i < count; i++)
putchar(ch);
}
 
/** Insert character to string */
static void insert_char(char *str, char ch, int pos)
{
int i;
for (i = strlen(str); i > pos; i--)
str[i] = str[i - 1];
str[pos] = ch;
}
 
/** Try to find a command beginning with prefix */
static const char *cmdtab_search_one(const char *name, link_t **startpos)
static const char * cmdtab_search_one(const char *name,link_t **startpos)
{
size_t namelen = str_length(name);
size_t namelen = strlen(name);
const char *curname;
 
spinlock_lock(&cmd_lock);
if (*startpos == NULL)
 
if (!*startpos)
*startpos = cmd_head.next;
 
for (; *startpos != &cmd_head; *startpos = (*startpos)->next) {
cmd_info_t *hlp = list_get_instance(*startpos, cmd_info_t, link);
const char *curname = hlp->name;
if (str_length(curname) < namelen)
cmd_info_t *hlp;
hlp = list_get_instance(*startpos, cmd_info_t, link);
 
curname = hlp->name;
if (strlen(curname) < namelen)
continue;
if (str_lcmp(curname, name, namelen) == 0) {
spinlock_unlock(&cmd_lock);
return (curname + str_lsize(curname, namelen));
if (strncmp(curname, name, namelen) == 0) {
spinlock_unlock(&cmd_lock);
return curname+namelen;
}
}
spinlock_unlock(&cmd_lock);
spinlock_unlock(&cmd_lock);
return NULL;
}
 
/** Command completion of the commands
 
/** Command completion of the commands
*
* @param name String to match, changed to hint on exit
* @param size Input buffer size
*
* @return Number of found matches
*
* @param name - string to match, changed to hint on exit
* @return number of found matches
*/
static int cmdtab_compl(char *input, size_t size)
static int cmdtab_compl(char *name)
{
const char *name = input;
size_t found = 0;
link_t *pos = NULL;
const char *hint;
char output[MAX_CMDLINE];
output[0] = 0;
while ((hint = cmdtab_search_one(name, &pos))) {
if ((found == 0) || (str_length(output) > str_length(hint)))
str_cpy(output, MAX_CMDLINE, hint);
pos = pos->next;
static char output[MAX_SYMBOL_NAME+1];
link_t *startpos = NULL;
const char *foundtxt;
int found = 0;
int i;
 
output[0] = '\0';
while ((foundtxt = cmdtab_search_one(name, &startpos))) {
startpos = startpos->next;
if (!found)
strncpy(output, foundtxt, strlen(foundtxt)+1);
else {
for (i = 0; output[i] && foundtxt[i] &&
output[i] == foundtxt[i]; i++)
;
output[i] = '\0';
}
found++;
}
if ((found > 1) && (str_length(output) != 0)) {
if (!found)
return 0;
 
if (found > 1 && !strlen(output)) {
printf("\n");
pos = NULL;
while ((hint = cmdtab_search_one(name, &pos))) {
cmd_info_t *hlp = list_get_instance(pos, cmd_info_t, link);
printf("%s (%s)\n", hlp->name, hlp->description);
pos = pos->next;
startpos = NULL;
while ((foundtxt = cmdtab_search_one(name, &startpos))) {
cmd_info_t *hlp;
hlp = list_get_instance(startpos, cmd_info_t, link);
printf("%s - %s\n", hlp->name, hlp->description);
startpos = startpos->next;
}
}
strncpy(name, output, MAX_SYMBOL_NAME);
return found;
if (found > 0)
str_cpy(input, size, output);
return found;
}
 
static wchar_t *clever_readline(const char *prompt, indev_t *indev)
static char * clever_readline(const char *prompt, chardev_t *input)
{
static int histposition = 0;
 
static char tmp[MAX_CMDLINE+1];
int curlen = 0, position = 0;
char *current = history[histposition];
int i;
char mod; /* Command Modifier */
char c;
 
printf("%s> ", prompt);
size_t position = 0;
wchar_t *current = history[history_pos];
current[0] = 0;
while (true) {
wchar_t ch = indev_pop_character(indev);
if (ch == '\n') {
/* Enter */
putchar(ch);
while (1) {
c = _getc(input);
if (c == '\n') {
putchar(c);
break;
}
if (ch == '\b') {
/* Backspace */
} if (c == '\b') { /* Backspace */
if (position == 0)
continue;
if (wstr_remove(current, position - 1)) {
position--;
putchar('\b');
printf("%ls ", current + position);
print_cc('\b', wstr_length(current) - position + 1);
continue;
}
for (i = position; i < curlen; i++)
current[i - 1] = current[i];
curlen--;
position--;
putchar('\b');
for (i = position; i < curlen; i++)
putchar(current[i]);
putchar(' ');
rdln_print_c('\b', curlen - position + 1);
continue;
}
if (ch == '\t') {
/* Tab completion */
if (c == '\t') { /* Tabulator */
int found;
 
/* Move to the end of the word */
for (; (current[position] != 0) && (!isspace(current[position]));
for (; position < curlen && current[position] != ' ';
position++)
putchar(current[position]);
if (position == 0)
continue;
/* Find the beginning of the word
and copy it to tmp */
size_t beg;
for (beg = position - 1; (beg > 0) && (!isspace(current[beg]));
beg--);
if (isspace(current[beg]))
beg++;
char tmp[STR_BOUNDS(MAX_CMDLINE)];
wstr_nstr(tmp, current + beg, position - beg + 1);
int found;
if (beg == 0) {
/* Command completion */
found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE));
} else {
/* Symbol completion */
found = symtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE));
/* Copy to tmp last word */
for (i = position - 1; i >= 0 && current[i] != ' '; i--)
;
/* If word begins with * or &, skip it */
if (tmp[0] == '*' || tmp[0] == '&')
for (i = 1; tmp[i]; i++)
tmp[i - 1] = tmp[i];
i++; /* I is at the start of the word */
strncpy(tmp, current + i, position - i + 1);
 
if (i == 0) { /* Command completion */
found = cmdtab_compl(tmp);
} else { /* Symtab completion */
found = symtab_compl(tmp);
}
if (found == 0)
 
if (found == 0)
continue;
if (found > 1) {
/* No unique hint, list was printed */
printf("%s> ", prompt);
printf("%ls", current);
print_cc('\b', wstr_length(current) - position);
continue;
}
/* We have a hint */
size_t off = 0;
size_t i = 0;
while ((ch = str_decode(tmp, &off, STR_NO_LIMIT)) != 0) {
if (!wstr_linsert(current, ch, position + i, MAX_CMDLINE))
break;
i++;
}
printf("%ls", current + position);
position += str_length(tmp);
print_cc('\b', wstr_length(current) - position);
if (position == wstr_length(current)) {
/* Insert a space after the last completed argument */
if (wstr_linsert(current, ' ', position, MAX_CMDLINE)) {
printf("%ls", current + position);
for (i = 0; tmp[i] && curlen < MAX_CMDLINE;
i++, curlen++)
insert_char(current, tmp[i], i + position);
 
if (strlen(tmp) || found == 1) { /* If we have a hint */
for (i = position; i < curlen; i++)
putchar(current[i]);
position += strlen(tmp);
/* Add space to end */
if (found == 1 && position == curlen &&
curlen < MAX_CMDLINE) {
current[position] = ' ';
curlen++;
position++;
putchar(' ');
}
} else { /* No hint, table was printed */
printf("%s> ", prompt);
for (i = 0; i < curlen; i++)
putchar(current[i]);
position += strlen(tmp);
}
rdln_print_c('\b', curlen - position);
continue;
}
if (ch == U_LEFT_ARROW) {
/* Left */
if (position > 0) {
putchar('\b');
position--;
}
continue;
}
if (ch == U_RIGHT_ARROW) {
/* Right */
if (position < wstr_length(current)) {
putchar(current[position]);
position++;
}
continue;
}
if ((ch == U_UP_ARROW) || (ch == U_DOWN_ARROW)) {
/* Up, down */
print_cc('\b', position);
print_cc(' ', wstr_length(current));
print_cc('\b', wstr_length(current));
if (ch == U_UP_ARROW) {
/* Up */
if (history_pos == 0)
history_pos = KCONSOLE_HISTORY - 1;
if (c == 0x1b) { /* Special command */
mod = _getc(input);
c = _getc(input);
 
if (mod != 0x5b && mod != 0x4f)
continue;
 
if (c == 0x33 && _getc(input) == 0x7e) {
/* Delete */
if (position == curlen)
continue;
for (i = position + 1; i < curlen; i++) {
putchar(current[i]);
current[i - 1] = current[i];
}
putchar(' ');
rdln_print_c('\b', curlen - position);
curlen--;
} else if (c == 0x48) { /* Home */
rdln_print_c('\b', position);
position = 0;
} else if (c == 0x46) { /* End */
for (i = position; i < curlen; i++)
putchar(current[i]);
position = curlen;
} else if (c == 0x44) { /* Left */
if (position > 0) {
putchar('\b');
position--;
}
continue;
} else if (c == 0x43) { /* Right */
if (position < curlen) {
putchar(current[position]);
position++;
}
continue;
} else if (c == 0x41 || c == 0x42) {
/* Up, down */
rdln_print_c('\b', position);
rdln_print_c(' ', curlen);
rdln_print_c('\b', curlen);
if (c == 0x41) /* Up */
histposition--;
else
history_pos--;
} else {
/* Down */
history_pos++;
history_pos = history_pos % KCONSOLE_HISTORY;
histposition++;
if (histposition < 0) {
histposition = KCONSOLE_HISTORY - 1;
} else {
histposition =
histposition % KCONSOLE_HISTORY;
}
current = history[histposition];
printf("%s", current);
curlen = strlen(current);
position = curlen;
continue;
}
current = history[history_pos];
printf("%ls", current);
position = wstr_length(current);
continue;
}
if (ch == U_HOME_ARROW) {
/* Home */
print_cc('\b', position);
position = 0;
if (curlen >= MAX_CMDLINE)
continue;
}
if (ch == U_END_ARROW) {
/* End */
printf("%ls", current + position);
position = wstr_length(current);
continue;
}
if (ch == U_DELETE) {
/* Delete */
if (position == wstr_length(current))
continue;
if (wstr_remove(current, position)) {
printf("%ls ", current + position);
print_cc('\b', wstr_length(current) - position + 1);
}
continue;
}
if (wstr_linsert(current, ch, position, MAX_CMDLINE)) {
printf("%ls", current + position);
position++;
print_cc('\b', wstr_length(current) - position);
}
 
insert_char(current, c, position);
 
curlen++;
for (i = position; i < curlen; i++)
putchar(current[i]);
position++;
rdln_print_c('\b',curlen - position);
}
if (curlen) {
histposition++;
histposition = histposition % KCONSOLE_HISTORY;
}
if (wstr_length(current) > 0) {
history_pos++;
history_pos = history_pos % KCONSOLE_HISTORY;
}
current[curlen] = '\0';
return current;
}
 
bool kconsole_check_poll(void)
/** Kernel console managing thread.
*
* @param prompt Kernel console prompt (e.g kconsole/panic).
*/
void kconsole(void *prompt)
{
return check_poll(stdin);
cmd_info_t *cmd_info;
count_t len;
char *cmdline;
 
if (!stdin) {
printf("%s: no stdin\n", __FUNCTION__);
return;
}
while (true) {
cmdline = clever_readline((char *) prompt, stdin);
len = strlen(cmdline);
if (!len)
continue;
cmd_info = parse_cmdline(cmdline, len);
if (!cmd_info)
continue;
if (strncmp(cmd_info->name, "exit",
min(strlen(cmd_info->name), 5)) == 0)
break;
(void) cmd_info->func(cmd_info->argv);
}
}
 
static bool parse_int_arg(const char *text, size_t len, unative_t *result)
static int parse_int_arg(char *text, size_t len, unative_t *result)
{
static char symname[MAX_SYMBOL_NAME];
uintptr_t symaddr;
bool isaddr = false;
bool isptr = false;
436,113 → 447,63
text++;
len--;
}
if ((text[0] < '0') || (text[0] > '9')) {
char symname[MAX_SYMBOL_NAME];
str_ncpy(symname, MAX_SYMBOL_NAME, text, len + 1);
uintptr_t symaddr;
int rc = symtab_addr_lookup(symname, &symaddr);
switch (rc) {
case ENOENT:
if (text[0] < '0' || text[0] > '9') {
strncpy(symname, text, min(len + 1, MAX_SYMBOL_NAME));
symaddr = get_symbol_addr(symname);
if (!symaddr) {
printf("Symbol %s not found.\n", symname);
return false;
case EOVERFLOW:
return -1;
}
if (symaddr == (uintptr_t) -1) {
printf("Duplicate symbol %s.\n", symname);
symtab_print_search(symname);
return false;
case ENOTSUP:
printf("No symbol information available.\n");
return false;
return -1;
}
if (isaddr)
*result = (unative_t) symaddr;
*result = (unative_t)symaddr;
else if (isptr)
*result = **((unative_t **) symaddr);
*result = **((unative_t **)symaddr);
else
*result = *((unative_t *) symaddr);
} else {
/* It's a number - convert it */
*result = *((unative_t *)symaddr);
} else { /* It's a number - convert it */
*result = atoi(text);
if (isptr)
*result = *((unative_t *) *result);
*result = *((unative_t *)*result);
}
return true;
}
 
/** Parse argument.
*
* Find start and end positions of command line argument.
*
* @param cmdline Command line as read from the input device.
* @param size Size (in bytes) of the string.
* @param start On entry, 'start' contains pointer to the offset
* of the first unprocessed character of cmdline.
* On successful exit, it marks beginning of the next argument.
* @param end Undefined on entry. On exit, 'end' is the offset of the first
* character behind the next argument.
*
* @return False on failure, true on success.
*
*/
static bool parse_argument(const char *cmdline, size_t size, size_t *start, size_t *end)
{
ASSERT(start != NULL);
ASSERT(end != NULL);
bool found_start = false;
size_t offset = *start;
size_t prev = *start;
wchar_t ch;
while ((ch = str_decode(cmdline, &offset, size)) != 0) {
if (!found_start) {
if (!isspace(ch)) {
*start = prev;
found_start = true;
}
} else {
if (isspace(ch))
break;
}
prev = offset;
}
*end = prev;
return found_start;
return 0;
}
 
/** Parse command line.
*
* @param cmdline Command line as read from input device.
* @param size Size (in bytes) of the string.
* @param cmdline Command line as read from input device.
* @param len Command line length.
*
* @return Structure describing the command.
*
*/
static cmd_info_t *parse_cmdline(const char *cmdline, size_t size)
cmd_info_t *parse_cmdline(char *cmdline, size_t len)
{
size_t start = 0;
size_t end = 0;
if (!parse_argument(cmdline, size, &start, &end)) {
index_t start = 0, end = 0;
cmd_info_t *cmd = NULL;
link_t *cur;
count_t i;
int error = 0;
if (!parse_argument(cmdline, len, &start, &end)) {
/* Command line did not contain alphanumeric word. */
return NULL;
}
 
spinlock_lock(&cmd_lock);
cmd_info_t *cmd = NULL;
link_t *cur;
for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
cmd_info_t *hlp = list_get_instance(cur, cmd_info_t, link);
cmd_info_t *hlp;
hlp = list_get_instance(cur, cmd_info_t, link);
spinlock_lock(&hlp->lock);
if (str_lcmp(hlp->name, cmdline + start,
max(str_length(hlp->name),
str_nlength(cmdline + start, (size_t) (end - start) - 1))) == 0) {
if (strncmp(hlp->name, &cmdline[start], max(strlen(hlp->name),
end - start + 1)) == 0) {
cmd = hlp;
break;
}
550,7 → 511,7
spinlock_unlock(&hlp->lock);
}
spinlock_unlock(&cmd_lock);
spinlock_unlock(&cmd_lock);
if (!cmd) {
/* Unknown command. */
557,7 → 518,7
printf("Unknown command.\n");
return NULL;
}
 
/* cmd == hlp is locked */
/*
566,54 → 527,51
* converted to those specified in the cmd info
* structure.
*/
bool error = false;
size_t i;
 
for (i = 0; i < cmd->argc; i++) {
start = end;
if (!parse_argument(cmdline, size, &start, &end)) {
char *buf;
start = end + 1;
if (!parse_argument(cmdline, len, &start, &end)) {
printf("Too few arguments.\n");
spinlock_unlock(&cmd->lock);
return NULL;
}
char *buf;
error = 0;
switch (cmd->argv[i].type) {
case ARG_TYPE_STRING:
buf = (char *) cmd->argv[i].buffer;
str_ncpy(buf, cmd->argv[i].len, cmdline + start,
end - start);
strncpy(buf, (const char *) &cmdline[start],
min((end - start) + 2, cmd->argv[i].len));
buf[min((end - start) + 1, cmd->argv[i].len - 1)] = '\0';
break;
case ARG_TYPE_INT:
if (!parse_int_arg(cmdline + start, end - start,
case ARG_TYPE_INT:
if (parse_int_arg(cmdline + start, end - start + 1,
&cmd->argv[i].intval))
error = true;
error = 1;
break;
case ARG_TYPE_VAR:
if ((start < end - 1) && (cmdline[start] == '"')) {
if (cmdline[end - 1] == '"') {
buf = (char *) cmd->argv[i].buffer;
str_ncpy(buf, cmd->argv[i].len,
cmdline + start + 1,
(end - start) - 1);
cmd->argv[i].intval = (unative_t) buf;
cmd->argv[i].vartype = ARG_TYPE_STRING;
} else {
printf("Wrong synxtax.\n");
error = true;
}
} else if (parse_int_arg(cmdline + start,
end - start, &cmd->argv[i].intval)) {
if (start != end && cmdline[start] == '"' &&
cmdline[end] == '"') {
buf = (char *) cmd->argv[i].buffer;
strncpy(buf, (const char *) &cmdline[start + 1],
min((end-start), cmd->argv[i].len));
buf[min((end - start), cmd->argv[i].len - 1)] =
'\0';
cmd->argv[i].intval = (unative_t) buf;
cmd->argv[i].vartype = ARG_TYPE_STRING;
} else if (!parse_int_arg(cmdline + start, end - start + 1,
&cmd->argv[i].intval)) {
cmd->argv[i].vartype = ARG_TYPE_INT;
} else {
printf("Unrecognized variable argument.\n");
error = true;
error = 1;
}
break;
case ARG_TYPE_INVALID:
default:
printf("Invalid argument type\n");
error = true;
printf("invalid argument type\n");
error = 1;
break;
}
}
623,8 → 581,8
return NULL;
}
start = end;
if (parse_argument(cmdline, size, &start, &end)) {
start = end + 1;
if (parse_argument(cmdline, len, &start, &end)) {
printf("Too many arguments.\n");
spinlock_unlock(&cmd->lock);
return NULL;
634,55 → 592,42
return cmd;
}
 
/** Kernel console prompt.
/** Parse argument.
*
* @param prompt Kernel console prompt (e.g kconsole/panic).
* @param msg Message to display in the beginning.
* @param kcon Wait for keypress to show the prompt
* and never exit.
* Find start and end positions of command line argument.
*
* @param cmdline Command line as read from the input device.
* @param len Number of characters in cmdline.
* @param start On entry, 'start' contains pointer to the index
* of first unprocessed character of cmdline.
* On successful exit, it marks beginning of the next argument.
* @param end Undefined on entry. On exit, 'end' points to the last character
* of the next argument.
*
* @return false on failure, true on success.
*/
void kconsole(char *prompt, char *msg, bool kcon)
bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end)
{
if (!stdin) {
LOG("No stdin for kernel console");
return;
}
index_t i;
bool found_start = false;
if (msg)
printf("%s", msg);
ASSERT(start != NULL);
ASSERT(end != NULL);
if (kcon)
indev_pop_character(stdin);
else
printf("Type \"exit\" to leave the console.\n");
while (true) {
wchar_t *tmp = clever_readline((char *) prompt, stdin);
size_t len = wstr_length(tmp);
if (!len)
continue;
char cmdline[STR_BOUNDS(MAX_CMDLINE)];
wstr_nstr(cmdline, tmp, STR_BOUNDS(MAX_CMDLINE));
if ((!kcon) && (len == 4) && (str_lcmp(cmdline, "exit", 4) == 0))
break;
cmd_info_t *cmd_info = parse_cmdline(cmdline, STR_BOUNDS(MAX_CMDLINE));
if (!cmd_info)
continue;
(void) cmd_info->func(cmd_info->argv);
for (i = *start; i < len; i++) {
if (!found_start) {
if (is_white(cmdline[i]))
(*start)++;
else
found_start = true;
} else {
if (is_white(cmdline[i]))
break;
}
}
}
*end = i - 1;
 
/** Kernel console managing thread.
*
*/
void kconsole_thread(void *data)
{
kconsole("kconsole", "Kernel console ready (press any key to activate)\n", true);
return found_start;
}
 
/** @}
/branches/arm/kernel/generic/src/console/console.c
35,267 → 35,134
 
#include <console/console.h>
#include <console/chardev.h>
#include <sysinfo/sysinfo.h>
#include <synch/waitq.h>
#include <synch/spinlock.h>
#include <arch/types.h>
#include <ddi/irq.h>
#include <ddi/ddi.h>
#include <ipc/event.h>
#include <ipc/irq.h>
#include <arch.h>
#include <func.h>
#include <print.h>
#include <putchar.h>
#include <atomic.h>
#include <syscall/copy.h>
#include <errno.h>
#include <string.h>
 
#define KLOG_PAGES 4
#define KLOG_LENGTH (KLOG_PAGES * PAGE_SIZE / sizeof(wchar_t))
#define KLOG_LATENCY 8
#define BUFLEN 2048
static char debug_buffer[BUFLEN];
static size_t offset = 0;
/** Initialize stdout to something that does not print, but does not fail
*
* Save data in some buffer so that it could be retrieved in the debugger
*/
static void null_putchar(chardev_t *d, const char ch)
{
if (offset >= BUFLEN)
offset = 0;
debug_buffer[offset++] = ch;
}
 
/** Kernel log cyclic buffer */
static wchar_t klog[KLOG_LENGTH] __attribute__ ((aligned (PAGE_SIZE)));
 
/** Kernel log initialized */
static bool klog_inited = false;
/** First kernel log characters */
static size_t klog_start = 0;
/** Number of valid kernel log characters */
static size_t klog_len = 0;
/** Number of stored (not printed) kernel log characters */
static size_t klog_stored = 0;
/** Number of stored kernel log characters for uspace */
static size_t klog_uspace = 0;
 
/** Kernel log spinlock */
SPINLOCK_INITIALIZE(klog_lock);
 
/** Physical memory area used for klog buffer */
static parea_t klog_parea;
 
static indev_operations_t stdin_ops = {
.poll = NULL
static chardev_operations_t null_stdout_ops = {
.write = null_putchar
};
chardev_t null_stdout = {
.name = "null",
.op = &null_stdout_ops
};
 
/** Silence output */
bool silent = false;
/** Standard input character device. */
chardev_t *stdin = NULL;
chardev_t *stdout = &null_stdout;
 
/** Standard input and output character devices */
indev_t *stdin = NULL;
outdev_t *stdout = NULL;
 
indev_t *stdin_wire(void)
{
if (stdin == NULL) {
stdin = malloc(sizeof(indev_t), FRAME_ATOMIC);
if (stdin != NULL)
indev_initialize("stdin", stdin, &stdin_ops);
}
return stdin;
}
 
/** Initialize kernel logging facility
/** Get character from character device. Do not echo character.
*
* The shared area contains kernel cyclic buffer. Userspace application may
* be notified on new data with indication of position and size
* of the data within the circular buffer.
* @param chardev Character device.
*
* @return Character read.
*/
void klog_init(void)
uint8_t _getc(chardev_t *chardev)
{
void *faddr = (void *) KA2PA(klog);
ASSERT((uintptr_t) faddr % FRAME_SIZE == 0);
klog_parea.pbase = (uintptr_t) faddr;
klog_parea.frames = SIZE2FRAMES(sizeof(klog));
ddi_parea_register(&klog_parea);
sysinfo_set_item_val("klog.faddr", NULL, (unative_t) faddr);
sysinfo_set_item_val("klog.pages", NULL, KLOG_PAGES);
spinlock_lock(&klog_lock);
klog_inited = true;
spinlock_unlock(&klog_lock);
}
uint8_t ch;
ipl_t ipl;
 
void grab_console(void)
{
bool prev = silent;
silent = false;
arch_grab_console();
/* Force the console to print the prompt */
if ((stdin) && (prev))
indev_push_character(stdin, '\n');
}
if (atomic_get(&haltstate)) {
/* If we are here, we are hopefully on the processor, that
* issued the 'halt' command, so proceed to read the character
* directly from input
*/
if (chardev->op->read)
return chardev->op->read(chardev);
/* no other way of interacting with user, halt */
if (CPU)
printf("cpu%d: ", CPU->id);
else
printf("cpu: ");
printf("halted - no kconsole\n");
cpu_halt();
}
 
void release_console(void)
{
silent = true;
arch_release_console();
}
waitq_sleep(&chardev->wq);
ipl = interrupts_disable();
spinlock_lock(&chardev->lock);
ch = chardev->buffer[(chardev->index - chardev->counter) % CHARDEV_BUFLEN];
chardev->counter--;
spinlock_unlock(&chardev->lock);
interrupts_restore(ipl);
 
/** Tell kernel to get keyboard/console access again */
unative_t sys_debug_enable_console(void)
{
#ifdef CONFIG_KCONSOLE
grab_console();
return true;
#else
return false;
#endif
}
chardev->op->resume(chardev);
 
/** Tell kernel to relinquish keyboard/console access */
unative_t sys_debug_disable_console(void)
{
release_console();
return true;
return ch;
}
 
/** Get string from input character device.
/** Get string from character device.
*
* Read characters from input character device until first occurrence
* Read characters from character device until first occurrence
* of newline character.
*
* @param indev Input character device.
* @param buf Buffer where to store string terminated by NULL.
* @param chardev Character device.
* @param buf Buffer where to store string terminated by '\0'.
* @param buflen Size of the buffer.
*
* @return Number of characters read.
*
*/
size_t gets(indev_t *indev, char *buf, size_t buflen)
count_t gets(chardev_t *chardev, char *buf, size_t buflen)
{
size_t offset = 0;
size_t count = 0;
buf[offset] = 0;
wchar_t ch;
while ((ch = indev_pop_character(indev)) != '\n') {
index_t index = 0;
char ch;
 
while (index < buflen) {
ch = _getc(chardev);
if (ch == '\b') {
if (count > 0) {
/* Space, backspace, space */
if (index > 0) {
index--;
/* Space backspace, space */
putchar('\b');
putchar(' ');
putchar('\b');
count--;
offset = str_lsize(buf, count);
buf[offset] = 0;
}
continue;
}
putchar(ch);
 
if (ch == '\n') { /* end of string => write 0, return */
buf[index] = '\0';
return (count_t) index;
}
if (chr_encode(ch, buf, &offset, buflen - 1) == EOK) {
putchar(ch);
count++;
buf[offset] = 0;
}
buf[index++] = ch;
}
return count;
return (count_t) index;
}
 
/** Get character from input device & echo it to screen */
wchar_t getc(indev_t *indev)
/** Get character from device & echo it to screen */
uint8_t getc(chardev_t *chardev)
{
wchar_t ch = indev_pop_character(indev);
uint8_t ch;
 
ch = _getc(chardev);
putchar(ch);
return ch;
}
 
void klog_update(void)
void putchar(char c)
{
spinlock_lock(&klog_lock);
if ((klog_inited) && (event_is_subscribed(EVENT_KLOG)) && (klog_uspace > 0)) {
event_notify_3(EVENT_KLOG, klog_start, klog_len, klog_uspace);
klog_uspace = 0;
}
spinlock_unlock(&klog_lock);
if (stdout->op->write)
stdout->op->write(stdout, c);
}
 
void putchar(const wchar_t ch)
{
spinlock_lock(&klog_lock);
if ((klog_stored > 0) && (stdout) && (stdout->op->write)) {
/* Print charaters stored in kernel log */
size_t i;
for (i = klog_len - klog_stored; i < klog_len; i++)
stdout->op->write(stdout, klog[(klog_start + i) % KLOG_LENGTH], silent);
klog_stored = 0;
}
/* Store character in the cyclic kernel log */
klog[(klog_start + klog_len) % KLOG_LENGTH] = ch;
if (klog_len < KLOG_LENGTH)
klog_len++;
else
klog_start = (klog_start + 1) % KLOG_LENGTH;
if ((stdout) && (stdout->op->write))
stdout->op->write(stdout, ch, silent);
else {
/* The character is just in the kernel log */
if (klog_stored < klog_len)
klog_stored++;
}
/* The character is stored for uspace */
if (klog_uspace < klog_len)
klog_uspace++;
/* Check notify uspace to update */
bool update;
if ((klog_uspace > KLOG_LATENCY) || (ch == '\n'))
update = true;
else
update = false;
spinlock_unlock(&klog_lock);
if (update)
klog_update();
}
 
/** Print using kernel facility
*
* Print to kernel log.
*
*/
unative_t sys_klog(int fd, const void *buf, size_t size)
{
char *data;
int rc;
if (size > PAGE_SIZE)
return ELIMIT;
if (size > 0) {
data = (char *) malloc(size + 1, 0);
if (!data)
return ENOMEM;
rc = copy_from_uspace(data, buf, size);
if (rc) {
free(data);
return rc;
}
data[size] = 0;
printf("%s", data);
free(data);
} else
klog_update();
return size;
}
 
/** @}
*/
/branches/arm/kernel/generic/src/console/chardev.c
33,119 → 33,46
*/
 
#include <console/chardev.h>
#include <putchar.h>
#include <synch/waitq.h>
#include <synch/spinlock.h>
#include <print.h>
#include <func.h>
#include <arch.h>
 
/** Initialize input character device.
/** Initialize character device.
*
* @param indev Input character device.
* @param op Implementation of input character device operations.
*
* @param chardev Character device.
* @param op Implementation of character device operations.
*/
void indev_initialize(char *name, indev_t *indev,
indev_operations_t *op)
void chardev_initialize(char *name,chardev_t *chardev,
chardev_operations_t *op)
{
indev->name = name;
waitq_initialize(&indev->wq);
spinlock_initialize(&indev->lock, "indev");
indev->counter = 0;
indev->index = 0;
indev->op = op;
chardev->name = name;
 
waitq_initialize(&chardev->wq);
spinlock_initialize(&chardev->lock, "chardev");
chardev->counter = 0;
chardev->index = 0;
chardev->op = op;
}
 
/** Push character read from input character device.
*
* @param indev Input character device.
* @param ch Character being pushed.
*
* @param chardev Character device.
* @param ch Character being pushed.
*/
void indev_push_character(indev_t *indev, wchar_t ch)
void chardev_push_character(chardev_t *chardev, uint8_t ch)
{
ASSERT(indev);
spinlock_lock(&indev->lock);
if (indev->counter == INDEV_BUFLEN - 1) {
/* Buffer full */
spinlock_unlock(&indev->lock);
return;
spinlock_lock(&chardev->lock);
chardev->counter++;
if (chardev->counter == CHARDEV_BUFLEN - 1) {
/* buffer full => disable device interrupt */
chardev->op->suspend(chardev);
}
indev->counter++;
indev->buffer[indev->index++] = ch;
/* Index modulo size of buffer */
indev->index = indev->index % INDEV_BUFLEN;
waitq_wakeup(&indev->wq, WAKEUP_FIRST);
spinlock_unlock(&indev->lock);
chardev->buffer[chardev->index++] = ch;
chardev->index = chardev->index % CHARDEV_BUFLEN; /* index modulo size of buffer */
waitq_wakeup(&chardev->wq, WAKEUP_FIRST);
spinlock_unlock(&chardev->lock);
}
 
/** Pop character from input character device.
*
* @param indev Input character device.
*
* @return Character read.
*
*/
wchar_t indev_pop_character(indev_t *indev)
{
if (atomic_get(&haltstate)) {
/* If we are here, we are hopefully on the processor that
* issued the 'halt' command, so proceed to read the character
* directly from input
*/
if (check_poll(indev))
return indev->op->poll(indev);
/* No other way of interacting with user */
interrupts_disable();
if (CPU)
printf("cpu%u: ", CPU->id);
else
printf("cpu: ");
printf("halted (no polling input)\n");
cpu_halt();
}
waitq_sleep(&indev->wq);
ipl_t ipl = interrupts_disable();
spinlock_lock(&indev->lock);
wchar_t ch = indev->buffer[(indev->index - indev->counter) % INDEV_BUFLEN];
indev->counter--;
spinlock_unlock(&indev->lock);
interrupts_restore(ipl);
return ch;
}
 
/** Initialize output character device.
*
* @param outdev Output character device.
* @param op Implementation of output character device operations.
*
*/
void outdev_initialize(char *name, outdev_t *outdev,
outdev_operations_t *op)
{
outdev->name = name;
spinlock_initialize(&outdev->lock, "outdev");
outdev->op = op;
}
 
bool check_poll(indev_t *indev)
{
if (indev == NULL)
return false;
if (indev->op == NULL)
return false;
return (indev->op->poll != NULL);
}
 
/** @}
*/
/branches/arm/kernel/generic/src/console/klog.c
0,0 → 1,156
/*
* Copyright (c) 2006 Ondrej Palkovsky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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 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.
*/
 
/** @addtogroup genericklog
* @{
*/
/** @file
*/
 
#include <mm/frame.h>
#include <sysinfo/sysinfo.h>
#include <console/klog.h>
#include <print.h>
#include <ddi/device.h>
#include <ddi/irq.h>
#include <ddi/ddi.h>
#include <ipc/irq.h>
 
/** Physical memory area used for klog. */
static parea_t klog_parea;
/*
* For now, we use 0 as INR.
* However, on some architectures 0 is the clock interrupt (e.g. amd64 and
* ia32). It is therefore desirable to have architecture specific definition of
* KLOG_VIRT_INR in the future.
*/
#define KLOG_VIRT_INR 0
 
/* Order of frame to be allocated for klog communication */
#define KLOG_ORDER 0
 
static char *klog;
static int klogsize;
static int klogpos;
 
SPINLOCK_INITIALIZE(klog_lock);
 
static irq_t klog_irq;
 
static irq_ownership_t klog_claim(void);
 
/** Initialize kernel logging facility
*
* Allocate pages that are to be shared with uspace for console data.
* The shared area is a circular buffer. Userspace application may
* be notified on new data with indication of position and size
* of the data within the circular buffer.
*/
void klog_init(void)
{
void *faddr;
 
faddr = frame_alloc(KLOG_ORDER, FRAME_ATOMIC);
if (!faddr)
panic("Cannot allocate page for klog");
klog = (char *) PA2KA(faddr);
devno_t devno = device_assign_devno();
klog_parea.pbase = (uintptr_t) faddr;
klog_parea.vbase = (uintptr_t) klog;
klog_parea.frames = 1 << KLOG_ORDER;
klog_parea.cacheable = true;
ddi_parea_register(&klog_parea);
 
sysinfo_set_item_val("klog.faddr", NULL, (unative_t) faddr);
sysinfo_set_item_val("klog.fcolor", NULL, (unative_t)
PAGE_COLOR((uintptr_t) klog));
sysinfo_set_item_val("klog.pages", NULL, 1 << KLOG_ORDER);
sysinfo_set_item_val("klog.devno", NULL, devno);
sysinfo_set_item_val("klog.inr", NULL, KLOG_VIRT_INR);
 
irq_initialize(&klog_irq);
klog_irq.devno = devno;
klog_irq.inr = KLOG_VIRT_INR;
klog_irq.claim = klog_claim;
irq_register(&klog_irq);
 
klogsize = PAGE_SIZE << KLOG_ORDER;
klogpos = 0;
}
 
/** Allways refuse IRQ ownership.
*
* This is not a real IRQ, so we always decline.
*
* @return Always returns IRQ_DECLINE.
*/
irq_ownership_t klog_claim(void)
{
return IRQ_DECLINE;
}
 
static void klog_vprintf(const char *fmt, va_list args)
{
int ret;
va_list atst;
 
va_copy(atst, args);
spinlock_lock(&klog_lock);
 
ret = vsnprintf(klog+klogpos, klogsize-klogpos, fmt, atst);
if (ret >= klogsize-klogpos) {
klogpos = 0;
if (ret >= klogsize)
goto out;
}
ipc_irq_send_msg(&klog_irq, klogpos, ret, 0);
klogpos += ret;
if (klogpos >= klogsize)
klogpos = 0;
out:
spinlock_unlock(&klog_lock);
va_end(atst);
}
 
/** Printf a message to kernel-uspace log */
void klog_printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
klog_vprintf(fmt, args);
 
va_end(args);
}
 
/** @}
*/
/branches/arm/kernel/generic/src/adt/avl.c
File deleted
/branches/arm/kernel/generic/src/adt/hash_table.c
32,7 → 32,7
 
/**
* @file
* @brief Implementation of generic chained hash table.
* @brief Implementation of generic chained hash table.
*
* This file contains implementation of generic chained hash table.
*/
51,22 → 51,20
* @param max_keys Maximal number of keys needed to identify an item.
* @param op Hash table operations structure.
*/
void hash_table_create(hash_table_t *h, size_t m, size_t max_keys, hash_table_operations_t *op)
void hash_table_create(hash_table_t *h, count_t m, count_t max_keys, hash_table_operations_t *op)
{
size_t i;
index_t i;
 
ASSERT(h);
ASSERT(op);
ASSERT(op->hash);
ASSERT(op->compare);
ASSERT(op && op->hash && op->compare);
ASSERT(max_keys > 0);
h->entry = (link_t *) malloc(m * sizeof(link_t), 0);
if (!h->entry)
panic("Cannot allocate memory for hash table.");
if (!h->entry) {
panic("cannot allocate memory for hash table\n");
}
memsetb((uintptr_t) h->entry, m * sizeof(link_t), 0);
memsetb(h->entry, m * sizeof(link_t), 0);
for (i = 0; i < m; i++)
list_initialize(&h->entry[i]);
83,14 → 81,11
*/
void hash_table_insert(hash_table_t *h, unative_t key[], link_t *item)
{
size_t chain;
index_t chain;
 
ASSERT(item);
ASSERT(h);
ASSERT(h->op);
ASSERT(h->op->hash);
ASSERT(h->op->compare);
ASSERT(h && h->op && h->op->hash && h->op->compare);
 
chain = h->op->hash(key);
ASSERT(chain < h->entries);
107,13 → 102,10
link_t *hash_table_find(hash_table_t *h, unative_t key[])
{
link_t *cur;
size_t chain;
ASSERT(h);
ASSERT(h->op);
ASSERT(h->op->hash);
ASSERT(h->op->compare);
index_t chain;
 
ASSERT(h && h->op && h->op->hash && h->op->compare);
 
chain = h->op->hash(key);
ASSERT(chain < h->entries);
131,25 → 123,22
 
/** Remove all matching items from hash table.
*
* For each removed item, h->remove_callback() is called (if not NULL).
* For each removed item, h->remove_callback() is called.
*
* @param h Hash table.
* @param key Array of keys that will be compared against items of the hash table.
* @param keys Number of keys in the key array.
*/
void hash_table_remove(hash_table_t *h, unative_t key[], size_t keys)
void hash_table_remove(hash_table_t *h, unative_t key[], count_t keys)
{
size_t chain;
index_t chain;
link_t *cur;
ASSERT(h);
ASSERT(h->op);
ASSERT(h->op->hash);
ASSERT(h->op->compare);
 
ASSERT(h && h->op && h->op->hash && h->op->compare && h->op->remove_callback);
ASSERT(keys <= h->max_keys);
if (keys == h->max_keys) {
 
/*
* All keys are known, hash_table_find() can be used to find the entry.
*/
157,8 → 146,7
cur = hash_table_find(h, key);
if (cur) {
list_remove(cur);
if (h->op->remove_callback)
h->op->remove_callback(cur);
h->op->remove_callback(cur);
}
return;
}
176,8 → 164,7
cur = cur->prev;
list_remove(hlp);
if (h->op->remove_callback)
h->op->remove_callback(hlp);
h->op->remove_callback(hlp);
continue;
}
/branches/arm/kernel/generic/src/adt/btree.c
63,9 → 63,9
static void node_remove_key_and_rsubtree(btree_node_t *node, btree_key_t key);
static btree_node_t *node_split(btree_node_t *node, btree_key_t key, void *value, btree_node_t *rsubtree, btree_key_t *median);
static btree_node_t *node_combine(btree_node_t *node);
static size_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right);
static void rotate_from_right(btree_node_t *lnode, btree_node_t *rnode, size_t idx);
static void rotate_from_left(btree_node_t *lnode, btree_node_t *rnode, size_t idx);
static index_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right);
static void rotate_from_right(btree_node_t *lnode, btree_node_t *rnode, index_t idx);
static void rotate_from_left(btree_node_t *lnode, btree_node_t *rnode, index_t idx);
static bool try_insert_by_rotation_to_left(btree_node_t *node, btree_key_t key, void *value, btree_node_t *rsubtree);
static bool try_insert_by_rotation_to_right(btree_node_t *node, btree_key_t key, void *value, btree_node_t *rsubtree);
static bool try_rotation_from_left(btree_node_t *rnode);
124,7 → 124,7
lnode = leaf_node;
if (!lnode) {
if (btree_search(t, key, &lnode)) {
panic("B-tree %p already contains key %" PRIu64 ".", t, key);
panic("B-tree %p already contains key %d\n", t, key);
}
}
137,7 → 137,7
*/
void btree_destroy_subtree(btree_node_t *root)
{
size_t i;
count_t i;
 
if (root->keys) {
for (i = 0; i < root->keys + 1; i++) {
224,7 → 224,7
lnode = leaf_node;
if (!lnode) {
if (!btree_search(t, key, &lnode)) {
panic("B-tree %p does not contain key %" PRIu64 ".", t, key);
panic("B-tree %p does not contain key %d\n", t, key);
}
}
269,7 → 269,7
}
if (node->keys > FILL_FACTOR) {
size_t i;
count_t i;
 
/*
* The key can be immediatelly removed.
285,7 → 285,7
}
} else {
size_t idx;
index_t idx;
btree_node_t *rnode, *parent;
 
/*
335,7 → 335,7
continue;
} else {
void *val;
size_t i;
count_t i;
/*
* Now if the key is smaller than cur->key[i]
442,11 → 442,11
*/
void node_insert_key_and_lsubtree(btree_node_t *node, btree_key_t key, void *value, btree_node_t *lsubtree)
{
size_t i;
count_t i;
 
for (i = 0; i < node->keys; i++) {
if (key < node->key[i]) {
size_t j;
count_t j;
for (j = node->keys; j > i; j--) {
node->key[j] = node->key[j - 1];
478,11 → 478,11
*/
void node_insert_key_and_rsubtree(btree_node_t *node, btree_key_t key, void *value, btree_node_t *rsubtree)
{
size_t i;
count_t i;
 
for (i = 0; i < node->keys; i++) {
if (key < node->key[i]) {
size_t j;
count_t j;
for (j = node->keys; j > i; j--) {
node->key[j] = node->key[j - 1];
510,7 → 510,7
*/
void node_remove_key_and_lsubtree(btree_node_t *node, btree_key_t key)
{
size_t i, j;
count_t i, j;
for (i = 0; i < node->keys; i++) {
if (key == node->key[i]) {
524,7 → 524,7
return;
}
}
panic("Node %p does not contain key %" PRIu64 ".", node, key);
panic("node %p does not contain key %d\n", node, key);
}
 
/** Remove key and its right subtree pointer from B-tree node.
538,7 → 538,7
*/
void node_remove_key_and_rsubtree(btree_node_t *node, btree_key_t key)
{
size_t i, j;
count_t i, j;
for (i = 0; i < node->keys; i++) {
if (key == node->key[i]) {
551,7 → 551,7
return;
}
}
panic("Node %p does not contain key %" PRIu64 ".", node, key);
panic("node %p does not contain key %d\n", node, key);
}
 
/** Split full B-tree node and insert new key-value-right-subtree triplet.
576,7 → 576,7
btree_node_t *node_split(btree_node_t *node, btree_key_t key, void *value, btree_node_t *rsubtree, btree_key_t *median)
{
btree_node_t *rnode;
size_t i, j;
count_t i, j;
 
ASSERT(median);
ASSERT(node->keys == BTREE_MAX_KEYS);
603,7 → 603,7
* Copy big keys, values and subtree pointers to the new right sibling.
* If this is an index node, do not copy the median.
*/
i = (size_t) INDEX_NODE(node);
i = (count_t) INDEX_NODE(node);
for (i += MEDIAN_HIGH_INDEX(node), j = 0; i < node->keys; i++, j++) {
rnode->key[j] = node->key[i];
rnode->value[j] = node->value[i];
636,9 → 636,9
*/
btree_node_t *node_combine(btree_node_t *node)
{
size_t idx;
index_t idx;
btree_node_t *rnode;
size_t i;
count_t i;
 
ASSERT(!ROOT_NODE(node));
685,15 → 685,15
*
* @return Index of the key associated with the subtree.
*/
size_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right)
index_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right)
{
size_t i;
count_t i;
for (i = 0; i < node->keys + 1; i++) {
if (subtree == node->subtree[i])
return i - (int) (right != false);
}
panic("Node %p does not contain subtree %p.", node, subtree);
panic("node %p does not contain subtree %p\n", node, subtree);
}
 
/** Rotate one key-value-rsubtree triplet from the left sibling to the right sibling.
706,7 → 706,7
* @param rnode Right sibling.
* @param idx Index of the parent node key that is taking part in the rotation.
*/
void rotate_from_left(btree_node_t *lnode, btree_node_t *rnode, size_t idx)
void rotate_from_left(btree_node_t *lnode, btree_node_t *rnode, index_t idx)
{
btree_key_t key;
 
743,7 → 743,7
* @param rnode Right sibling.
* @param idx Index of the parent node key that is taking part in the rotation.
*/
void rotate_from_right(btree_node_t *lnode, btree_node_t *rnode, size_t idx)
void rotate_from_right(btree_node_t *lnode, btree_node_t *rnode, index_t idx)
{
btree_key_t key;
 
786,7 → 786,7
*/
bool try_insert_by_rotation_to_left(btree_node_t *node, btree_key_t inskey, void *insvalue, btree_node_t *rsubtree)
{
size_t idx;
index_t idx;
btree_node_t *lnode;
 
/*
833,7 → 833,7
*/
bool try_insert_by_rotation_to_right(btree_node_t *node, btree_key_t inskey, void *insvalue, btree_node_t *rsubtree)
{
size_t idx;
index_t idx;
btree_node_t *rnode;
 
/*
872,7 → 872,7
*/
bool try_rotation_from_left(btree_node_t *rnode)
{
size_t idx;
index_t idx;
btree_node_t *lnode;
 
/*
907,7 → 907,7
*/
bool try_rotation_from_right(btree_node_t *lnode)
{
size_t idx;
index_t idx;
btree_node_t *rnode;
 
/*
940,7 → 940,7
*/
void btree_print(btree_t *t)
{
size_t i;
count_t i;
int depth = t->root->depth;
link_t head, *cur;
 
970,7 → 970,7
 
printf("(");
for (i = 0; i < node->keys; i++) {
printf("%" PRIu64 "%s", node->key[i], i < node->keys - 1 ? "," : "");
printf("%lld%s", node->key[i], i < node->keys - 1 ? "," : "");
if (node->depth && node->subtree[i]) {
list_append(&node->subtree[i]->bfs_link, &head);
}
992,7 → 992,7
 
printf("(");
for (i = 0; i < node->keys; i++)
printf("%" PRIu64 "%s", node->key[i], i < node->keys - 1 ? "," : "");
printf("%lld%s", node->key[i], i < node->keys - 1 ? "," : "");
printf(")");
}
printf("\n");
/branches/arm/kernel/generic/src/adt/bitmap.c
54,7 → 54,7
* @param map Address of the memory used to hold the map.
* @param bits Number of bits stored in bitmap.
*/
void bitmap_initialize(bitmap_t *bitmap, uint8_t *map, size_t bits)
void bitmap_initialize(bitmap_t *bitmap, uint8_t *map, count_t bits)
{
bitmap->map = map;
bitmap->bits = bits;
66,13 → 66,13
* @param start Starting bit.
* @param bits Number of bits to set.
*/
void bitmap_set_range(bitmap_t *bitmap, size_t start, size_t bits)
void bitmap_set_range(bitmap_t *bitmap, index_t start, count_t bits)
{
size_t i = 0;
size_t aligned_start;
size_t lub; /* leading unaligned bits */
size_t amb; /* aligned middle bits */
size_t tab; /* trailing aligned bits */
index_t i=0;
index_t aligned_start;
count_t lub; /* leading unaligned bits */
count_t amb; /* aligned middle bits */
count_t tab; /* trailing aligned bits */
ASSERT(start + bits <= bitmap->bits);
116,13 → 116,13
* @param start Starting bit.
* @param bits Number of bits to clear.
*/
void bitmap_clear_range(bitmap_t *bitmap, size_t start, size_t bits)
void bitmap_clear_range(bitmap_t *bitmap, index_t start, count_t bits)
{
size_t i = 0;
size_t aligned_start;
size_t lub; /* leading unaligned bits */
size_t amb; /* aligned middle bits */
size_t tab; /* trailing aligned bits */
index_t i=0;
index_t aligned_start;
count_t lub; /* leading unaligned bits */
count_t amb; /* aligned middle bits */
count_t tab; /* trailing aligned bits */
ASSERT(start + bits <= bitmap->bits);
168,9 → 168,9
* @param src Source bitmap.
* @param bits Number of bits to copy.
*/
void bitmap_copy(bitmap_t *dst, bitmap_t *src, size_t bits)
void bitmap_copy(bitmap_t *dst, bitmap_t *src, count_t bits)
{
size_t i;
index_t i;
ASSERT(bits <= dst->bits);
ASSERT(bits <= src->bits);
/branches/arm/kernel/generic/src/synch/smc.c
File deleted
/branches/arm/kernel/generic/src/synch/waitq.c
54,13 → 54,13
#include <context.h>
#include <adt/list.h>
 
static void waitq_sleep_timed_out(void *data);
static void waitq_timeouted_sleep(void *data);
 
/** Initialize wait queue
*
* Initialize wait queue.
*
* @param wq Pointer to wait queue to be initialized.
* @param wq Pointer to wait queue to be initialized.
*/
void waitq_initialize(waitq_t *wq)
{
71,7 → 71,7
 
/** Handle timeout during waitq_sleep_timeout() call
*
* This routine is called when waitq_sleep_timeout() times out.
* This routine is called when waitq_sleep_timeout() timeouts.
* Interrupts are disabled.
*
* It is supposed to try to remove 'its' thread from the wait queue;
79,14 → 79,13
* overlap. In that case it behaves just as though there was no
* timeout at all.
*
* @param data Pointer to the thread that called waitq_sleep_timeout().
* @param data Pointer to the thread that called waitq_sleep_timeout().
*/
void waitq_sleep_timed_out(void *data)
void waitq_timeouted_sleep(void *data)
{
thread_t *t = (thread_t *) data;
waitq_t *wq;
bool do_wakeup = false;
DEADLOCK_PROBE_INIT(p_wqlock);
 
spinlock_lock(&threads_lock);
if (!thread_exists(t))
97,7 → 96,6
if ((wq = t->sleep_queue)) { /* assignment */
if (!spinlock_trylock(&wq->lock)) {
spinlock_unlock(&t->lock);
DEADLOCK_PROBE(p_wqlock, DEADLOCK_THRESHOLD);
goto grab_locks; /* avoid deadlock */
}
 
123,7 → 121,7
* This routine attempts to interrupt a thread from its sleep in a waitqueue.
* If the thread is not found sleeping, no action is taken.
*
* @param t Thread to be interrupted.
* @param t Thread to be interrupted.
*/
void waitq_interrupt_sleep(thread_t *t)
{
130,7 → 128,6
waitq_t *wq;
bool do_wakeup = false;
ipl_t ipl;
DEADLOCK_PROBE_INIT(p_wqlock);
 
ipl = interrupts_disable();
spinlock_lock(&threads_lock);
150,7 → 147,6
if (!spinlock_trylock(&wq->lock)) {
spinlock_unlock(&t->lock);
DEADLOCK_PROBE(p_wqlock, DEADLOCK_THRESHOLD);
goto grab_locks; /* avoid deadlock */
}
 
183,9 → 179,9
* This function is really basic in that other functions as waitq_sleep()
* and all the *_timeout() functions use it.
*
* @param wq Pointer to wait queue.
* @param usec Timeout in microseconds.
* @param flags Specify mode of the sleep.
* @param wq Pointer to wait queue.
* @param usec Timeout in microseconds.
* @param flags Specify mode of the sleep.
*
* The sleep can be interrupted only if the
* SYNCH_FLAGS_INTERRUPTIBLE bit is specified in flags.
200,23 → 196,22
* If usec is zero and the SYNCH_FLAGS_NON_BLOCKING bit is set in flags, the
* call will immediately return, reporting either success or failure.
*
* @return Returns one of ESYNCH_WOULD_BLOCK, ESYNCH_TIMEOUT,
* ESYNCH_INTERRUPTED, ESYNCH_OK_ATOMIC and
* ESYNCH_OK_BLOCKED.
* @return One of: ESYNCH_WOULD_BLOCK, ESYNCH_TIMEOUT, ESYNCH_INTERRUPTED,
* ESYNCH_OK_ATOMIC, ESYNCH_OK_BLOCKED.
*
* @li ESYNCH_WOULD_BLOCK means that the sleep failed because at the time of
* the call there was no pending wakeup.
* @li ESYNCH_WOULD_BLOCK means that the sleep failed because at the time of the
* call there was no pending wakeup.
*
* @li ESYNCH_TIMEOUT means that the sleep timed out.
* @li ESYNCH_TIMEOUT means that the sleep timed out.
*
* @li ESYNCH_INTERRUPTED means that somebody interrupted the sleeping thread.
* @li ESYNCH_INTERRUPTED means that somebody interrupted the sleeping thread.
*
* @li ESYNCH_OK_ATOMIC means that the sleep succeeded and that there was
* a pending wakeup at the time of the call. The caller was not put
* asleep at all.
* @li ESYNCH_OK_ATOMIC means that the sleep succeeded and that there was
* a pending wakeup at the time of the call. The caller was not put
* asleep at all.
*
* @li ESYNCH_OK_BLOCKED means that the sleep succeeded; the full sleep was
* attempted.
* @li ESYNCH_OK_BLOCKED means that the sleep succeeded; the full sleep was
* attempted.
*/
int waitq_sleep_timeout(waitq_t *wq, uint32_t usec, int flags)
{
234,9 → 229,9
* This function will return holding the lock of the wait queue
* and interrupts disabled.
*
* @param wq Wait queue.
* @param wq Wait queue.
*
* @return Interrupt level as it existed on entry to this function.
* @return Interrupt level as it existed on entry to this function.
*/
ipl_t waitq_sleep_prepare(waitq_t *wq)
{
272,9 → 267,9
* to the call to waitq_sleep_prepare(). If necessary, the wait queue
* lock is released.
*
* @param wq Wait queue.
* @param rc Return code of waitq_sleep_timeout_unsafe().
* @param ipl Interrupt level returned by waitq_sleep_prepare().
* @param wq Wait queue.
* @param rc Return code of waitq_sleep_timeout_unsafe().
* @param ipl Interrupt level returned by waitq_sleep_prepare().
*/
void waitq_sleep_finish(waitq_t *wq, int rc, ipl_t ipl)
{
292,14 → 287,14
/** Internal implementation of waitq_sleep_timeout().
*
* This function implements logic of sleeping in a wait queue.
* This call must be preceded by a call to waitq_sleep_prepare()
* and followed by a call to waitq_sleep_finish().
* This call must be preceeded by a call to waitq_sleep_prepare()
* and followed by a call to waitq_slee_finish().
*
* @param wq See waitq_sleep_timeout().
* @param usec See waitq_sleep_timeout().
* @param flags See waitq_sleep_timeout().
* @param wq See waitq_sleep_timeout().
* @param usec See waitq_sleep_timeout().
* @param flags See waitq_sleep_timeout().
*
* @return See waitq_sleep_timeout().
* @return See waitq_sleep_timeout().
*/
int waitq_sleep_timeout_unsafe(waitq_t *wq, uint32_t usec, int flags)
{
356,7 → 351,7
}
THREAD->timeout_pending = true;
timeout_register(&THREAD->sleep_timeout, (uint64_t) usec,
waitq_sleep_timed_out, THREAD);
waitq_timeouted_sleep, THREAD);
}
 
list_append(&THREAD->wq_link, &wq->head);
384,10 → 379,11
* Besides its 'normal' wakeup operation, it attempts to unregister possible
* timeout.
*
* @param wq Pointer to wait queue.
* @param mode Wakeup mode.
* @param wq Pointer to wait queue.
* @param all If this is non-zero, all sleeping threads will be woken up and
* missed count will be zeroed.
*/
void waitq_wakeup(waitq_t *wq, wakeup_mode_t mode)
void waitq_wakeup(waitq_t *wq, bool all)
{
ipl_t ipl;
 
394,10 → 390,10
ipl = interrupts_disable();
spinlock_lock(&wq->lock);
 
_waitq_wakeup_unsafe(wq, mode);
_waitq_wakeup_unsafe(wq, all);
 
spinlock_unlock(&wq->lock);
interrupts_restore(ipl);
spinlock_unlock(&wq->lock);
interrupts_restore(ipl);
}
 
/** Internal SMP- and IRQ-unsafe version of waitq_wakeup()
405,27 → 401,22
* This is the internal SMP- and IRQ-unsafe version of waitq_wakeup(). It
* assumes wq->lock is already locked and interrupts are already disabled.
*
* @param wq Pointer to wait queue.
* @param mode If mode is WAKEUP_FIRST, then the longest waiting
* thread, if any, is woken up. If mode is WAKEUP_ALL, then
* all waiting threads, if any, are woken up. If there are
* no waiting threads to be woken up, the missed wakeup is
* recorded in the wait queue.
* @param wq Pointer to wait queue.
* @param all If this is non-zero, all sleeping threads will be woken up and
* missed count will be zeroed.
*/
void _waitq_wakeup_unsafe(waitq_t *wq, wakeup_mode_t mode)
void _waitq_wakeup_unsafe(waitq_t *wq, bool all)
{
thread_t *t;
size_t count = 0;
 
loop:
if (list_empty(&wq->head)) {
wq->missed_wakeups++;
if (count && mode == WAKEUP_ALL)
wq->missed_wakeups--;
if (all)
wq->missed_wakeups = 0;
return;
}
 
count++;
t = list_get_instance(wq->head.next, thread_t, wq_link);
/*
432,7 → 423,7
* Lock the thread prior to removing it from the wq.
* This is not necessary because of mutual exclusion
* (the link belongs to the wait queue), but because
* of synchronization with waitq_sleep_timed_out()
* of synchronization with waitq_timeouted_sleep()
* and thread_interrupt_sleep().
*
* In order for these two functions to work, the following
454,7 → 445,7
 
thread_ready(t);
 
if (mode == WAKEUP_ALL)
if (all)
goto loop;
}
 
/branches/arm/kernel/generic/src/synch/rwlock.c
82,7 → 82,7
*/
void rwlock_initialize(rwlock_t *rwl) {
spinlock_initialize(&rwl->lock, "rwlock_t");
mutex_initialize(&rwl->exclusive, MUTEX_PASSIVE);
mutex_initialize(&rwl->exclusive);
rwl->readers_in = 0;
}
 
231,10 → 231,10
interrupts_restore(ipl);
break;
case ESYNCH_OK_ATOMIC:
panic("_mutex_lock_timeout() == ESYNCH_OK_ATOMIC.");
panic("_mutex_lock_timeout()==ESYNCH_OK_ATOMIC\n");
break;
default:
panic("Invalid ESYNCH.");
panic("invalid ESYNCH\n");
break;
}
return rc;
/branches/arm/kernel/generic/src/synch/condvar.c
43,7 → 43,7
 
/** Initialize condition variable.
*
* @param cv Condition variable.
* @param cv Condition variable.
*/
void condvar_initialize(condvar_t *cv)
{
50,10 → 50,11
waitq_initialize(&cv->wq);
}
 
/** Signal the condition has become true to the first waiting thread by waking
* it up.
/**
* Signal the condition has become true
* to the first waiting thread by waking it up.
*
* @param cv Condition variable.
* @param cv Condition variable.
*/
void condvar_signal(condvar_t *cv)
{
60,10 → 61,11
waitq_wakeup(&cv->wq, WAKEUP_FIRST);
}
 
/** Signal the condition has become true to all waiting threads by waking
* them up.
/**
* Signal the condition has become true
* to all waiting threads by waking them up.
*
* @param cv Condition variable.
* @param cv Condition variable.
*/
void condvar_broadcast(condvar_t *cv)
{
72,17 → 74,17
 
/** Wait for the condition becoming true.
*
* @param cv Condition variable.
* @param mtx Mutex.
* @param usec Timeout value in microseconds.
* @param flags Select mode of operation.
* @param cv Condition variable.
* @param mtx Mutex.
* @param usec Timeout value in microseconds.
* @param flags Select mode of operation.
*
* For exact description of meaning of possible combinations of usec and flags,
* see comment for waitq_sleep_timeout(). Note that when
* SYNCH_FLAGS_NON_BLOCKING is specified here, ESYNCH_WOULD_BLOCK is always
* returned.
* For exact description of meaning of possible combinations
* of usec and flags, see comment for waitq_sleep_timeout().
* Note that when SYNCH_FLAGS_NON_BLOCKING is specified here,
* ESYNCH_WOULD_BLOCK is always returned.
*
* @return See comment for waitq_sleep_timeout().
* @return See comment for waitq_sleep_timeout().
*/
int _condvar_wait_timeout(condvar_t *cv, mutex_t *mtx, uint32_t usec, int flags)
{
/branches/arm/kernel/generic/src/synch/spinlock.c
32,9 → 32,9
 
/**
* @file
* @brief Spinlocks.
* @brief Spinlocks.
*/
 
#include <synch/spinlock.h>
#include <atomic.h>
#include <arch/barrier.h>
73,9 → 73,11
* @param sl Pointer to spinlock_t structure.
*/
#ifdef CONFIG_DEBUG_SPINLOCK
#define DEADLOCK_THRESHOLD 100000000
void spinlock_lock_debug(spinlock_t *sl)
{
size_t i = 0;
count_t i = 0;
char *symbol;
bool deadlock_reported = false;
 
preemption_disable();
82,7 → 84,7
while (test_and_set(&sl->val)) {
 
/*
* We need to be careful about printf_lock and fb_lock.
* We need to be careful about printflock and fb_lock.
* Both of them are used to report deadlocks via
* printf() and fb_putchar().
*
92,13 → 94,13
* However, we encountered false positives caused by very
* slow VESA framebuffer interaction (especially when
* run in a simulator) that caused problems with both
* printf_lock and fb_lock.
* printflock and fb_lock.
*
* Possible deadlocks on both printf_lock and fb_lock
* Possible deadlocks on both printflock and fb_lock
* are therefore not reported as they would cause an
* infinite recursion.
*/
if (sl == &printf_lock)
if (sl == &printflock)
continue;
#ifdef CONFIG_FB
if (sl == &fb_lock)
105,10 → 107,13
continue;
#endif
if (i++ > DEADLOCK_THRESHOLD) {
printf("cpu%u: looping on spinlock %" PRIp ":%s, "
"caller=%" PRIp "(%s)\n", CPU->id, sl, sl->name,
CALLER, symtab_fmt_name_lookup(CALLER));
printf("cpu%d: looping on spinlock %.*p:%s, "
"caller=%.*p", CPU->id, sizeof(uintptr_t) * 2, sl,
sl->name, sizeof(uintptr_t) * 2, CALLER);
symbol = get_symtab_entry(CALLER);
if (symbol)
printf("(%s)", symbol);
printf("\n");
i = 0;
deadlock_reported = true;
}
115,7 → 120,7
}
 
if (deadlock_reported)
printf("cpu%u: not deadlocked\n", CPU->id);
printf("cpu%d: not deadlocked\n", CPU->id);
 
/*
* Prevent critical section code from bleeding out this way up.
/branches/arm/kernel/generic/src/synch/futex.c
59,8 → 59,8
static void futex_initialize(futex_t *futex);
 
static futex_t *futex_find(uintptr_t paddr);
static size_t futex_ht_hash(unative_t *key);
static bool futex_ht_compare(unative_t *key, size_t keys, link_t *item);
static index_t futex_ht_hash(unative_t *key);
static bool futex_ht_compare(unative_t *key, count_t keys, link_t *item);
static void futex_ht_remove_callback(link_t *item);
 
/**
115,7 → 115,6
uintptr_t paddr;
pte_t *t;
ipl_t ipl;
int rc;
ipl = interrupts_disable();
 
135,17 → 134,9
interrupts_restore(ipl);
 
futex = futex_find(paddr);
 
#ifdef CONFIG_UDEBUG
udebug_stoppable_begin();
#endif
rc = waitq_sleep_timeout(&futex->wq, usec, flags |
return (unative_t) waitq_sleep_timeout(&futex->wq, usec, flags |
SYNCH_FLAGS_INTERRUPTIBLE);
 
#ifdef CONFIG_UDEBUG
udebug_stoppable_end();
#endif
return (unative_t) rc;
}
 
/** Wakeup one thread waiting in futex wait queue.
288,9 → 279,9
*
* @return Index into futex hash table.
*/
size_t futex_ht_hash(unative_t *key)
index_t futex_ht_hash(unative_t *key)
{
return (*key & (FUTEX_HT_SIZE - 1));
return *key & (FUTEX_HT_SIZE-1);
}
 
/** Compare futex hash table item with a key.
300,7 → 291,7
*
* @return True if the item matches the key. False otherwise.
*/
bool futex_ht_compare(unative_t *key, size_t keys, link_t *item)
bool futex_ht_compare(unative_t *key, count_t keys, link_t *item)
{
futex_t *futex;
 
333,7 → 324,7
for (cur = TASK->futexes.leaf_head.next;
cur != &TASK->futexes.leaf_head; cur = cur->next) {
btree_node_t *node;
unsigned int i;
int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
/branches/arm/kernel/generic/src/synch/mutex.c
38,54 → 38,42
#include <synch/mutex.h>
#include <synch/semaphore.h>
#include <synch/synch.h>
#include <debug.h>
 
/** Initialize mutex.
/** Initialize mutex
*
* @param mtx Mutex.
* @param type Type of the mutex.
* Initialize mutex.
*
* @param mtx Mutex.
*/
void mutex_initialize(mutex_t *mtx, mutex_type_t type)
void mutex_initialize(mutex_t *mtx)
{
mtx->type = type;
semaphore_initialize(&mtx->sem, 1);
}
 
/** Acquire mutex.
/** Acquire mutex
*
* Acquire mutex.
* Timeout mode and non-blocking mode can be requested.
*
* @param mtx Mutex.
* @param usec Timeout in microseconds.
* @param flags Specify mode of operation.
* @param mtx Mutex.
* @param usec Timeout in microseconds.
* @param flags Specify mode of operation.
*
* For exact description of possible combinations of
* usec and flags, see comment for waitq_sleep_timeout().
*
* @return See comment for waitq_sleep_timeout().
* @return See comment for waitq_sleep_timeout().
*/
int _mutex_lock_timeout(mutex_t *mtx, uint32_t usec, int flags)
{
int rc;
 
if (mtx->type == MUTEX_PASSIVE) {
rc = _semaphore_down_timeout(&mtx->sem, usec, flags);
} else {
ASSERT(mtx->type == MUTEX_ACTIVE);
ASSERT(usec == SYNCH_NO_TIMEOUT);
ASSERT(!(flags & SYNCH_FLAGS_INTERRUPTIBLE));
do {
rc = semaphore_trydown(&mtx->sem);
} while (SYNCH_FAILED(rc) &&
!(flags & SYNCH_FLAGS_NON_BLOCKING));
}
 
return rc;
return _semaphore_down_timeout(&mtx->sem, usec, flags);
}
 
/** Release mutex.
/** Release mutex
*
* @param mtx Mutex.
* Release mutex.
*
* @param mtx Mutex.
*/
void mutex_unlock(mutex_t *mtx)
{
/branches/arm/kernel/generic/src/ipc/kbox.c
File deleted
/branches/arm/kernel/generic/src/ipc/event.c
File deleted
Property changes:
Deleted: svn:mergeinfo
/branches/arm/kernel/generic/src/ipc/sysipc.c
42,38 → 42,22
#include <ipc/sysipc.h>
#include <ipc/irq.h>
#include <ipc/ipcrsc.h>
#include <ipc/kbox.h>
#include <udebug/udebug_ipc.h>
#include <arch/interrupt.h>
#include <print.h>
#include <syscall/copy.h>
#include <security/cap.h>
#include <mm/as.h>
#include <print.h>
 
/**
* Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
* requests.
*/
#define DATA_XFER_LIMIT (64 * 1024)
 
#define GET_CHECK_PHONE(phone, phoneid, err) \
{ \
if (phoneid > IPC_MAX_PHONES) { \
err; \
} \
phone = &TASK->phones[phoneid]; \
#define GET_CHECK_PHONE(phone,phoneid,err) { \
if (phoneid > IPC_MAX_PHONES) { err; } \
phone = &TASK->phones[phoneid]; \
}
 
#define STRUCT_TO_USPACE(dst, src) copy_to_uspace(dst, src, sizeof(*(src)))
#define STRUCT_TO_USPACE(dst,src) copy_to_uspace(dst,src,sizeof(*(src)))
 
/** Decide if the method is a system method.
*
* @param method Method to be decided.
*
* @return Return 1 if the method is a system method.
* Otherwise return 0.
*/
static inline int method_is_system(unative_t method)
/** Return true if the method is a system method */
static inline int is_system_method(unative_t method)
{
if (method <= IPC_M_LAST_SYSTEM)
return 1;
80,100 → 64,53
return 0;
}
 
/** Decide if the message with this method is forwardable.
/** Return true if the message with this method is forwardable
*
* - some system messages may be forwarded, for some of them
* it is useless
*
* @param method Method to be decided.
*
* @return Return 1 if the method is forwardable.
* Otherwise return 0.
*/
static inline int method_is_forwardable(unative_t method)
static inline int is_forwardable(unative_t method)
{
switch (method) {
case IPC_M_CONNECTION_CLONE:
case IPC_M_CONNECT_ME:
case IPC_M_PHONE_HUNGUP:
/* This message is meant only for the original recipient. */
return 0;
default:
return 1;
}
if (method == IPC_M_PHONE_HUNGUP || method == IPC_M_AS_AREA_SEND \
|| method == IPC_M_AS_AREA_RECV)
return 0; /* This message is meant only for the receiver */
return 1;
}
 
/** Decide if the message with this method is immutable on forward.
*
* - some system messages may be forwarded but their content cannot be altered
*
* @param method Method to be decided.
*
* @return Return 1 if the method is immutable on forward.
* Otherwise return 0.
/****************************************************/
/* Functions that preprocess answer before sending
* it to the recepient
*/
static inline int method_is_immutable(unative_t method)
{
switch (method) {
case IPC_M_SHARE_OUT:
case IPC_M_SHARE_IN:
case IPC_M_DATA_WRITE:
case IPC_M_DATA_READ:
return 1;
break;
default:
return 0;
}
}
 
 
/***********************************************************************
* Functions that preprocess answer before sending it to the recepient.
***********************************************************************/
 
/** Decide if the caller (e.g. ipc_answer()) should save the old call contents
* for answer_preprocess().
*
* @param call Call structure to be decided.
*
* @return Return 1 if the old call contents should be saved.
* Return 0 otherwise.
/** Return true if the caller (ipc_answer) should save
* the old call contents for answer_preprocess
*/
static inline int answer_need_old(call_t *call)
{
switch (IPC_GET_METHOD(call->data)) {
case IPC_M_CONNECTION_CLONE:
case IPC_M_CONNECT_ME:
case IPC_M_CONNECT_TO_ME:
case IPC_M_CONNECT_ME_TO:
case IPC_M_SHARE_OUT:
case IPC_M_SHARE_IN:
case IPC_M_DATA_WRITE:
case IPC_M_DATA_READ:
if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
return 1;
default:
return 0;
}
if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_ME_TO)
return 1;
if (IPC_GET_METHOD(call->data) == IPC_M_AS_AREA_SEND)
return 1;
if (IPC_GET_METHOD(call->data) == IPC_M_AS_AREA_RECV)
return 1;
return 0;
}
 
/** Interpret process answer as control information.
/** Interpret process answer as control information
*
* This function is called directly after sys_ipc_answer().
*
* @param answer Call structure with the answer.
* @param olddata Saved data of the request.
*
* @return Return 0 on success or an error code.
* This function is called directly after sys_ipc_answer
*/
static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
{
int phoneid;
 
if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
if (IPC_GET_RETVAL(answer->data) == EHANGUP) {
/* In case of forward, hangup the forwared phone,
* not the originator
*/
mutex_lock(&answer->data.phone->lock);
spinlock_lock(&answer->data.phone->lock);
spinlock_lock(&TASK->answerbox.lock);
if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
list_remove(&answer->data.phone->link);
180,72 → 117,31
answer->data.phone->state = IPC_PHONE_SLAMMED;
}
spinlock_unlock(&TASK->answerbox.lock);
mutex_unlock(&answer->data.phone->lock);
spinlock_unlock(&answer->data.phone->lock);
}
 
if (!olddata)
return 0;
 
if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECTION_CLONE) {
phoneid = IPC_GET_ARG1(*olddata);
phone_t *phone = &TASK->phones[phoneid];
if (IPC_GET_RETVAL(answer->data) != EOK) {
/*
* The recipient of the cloned phone rejected the offer.
* In this case, the connection was established at the
* request time and therefore we need to slam the phone.
* We don't merely hangup as that would result in
* sending IPC_M_HUNGUP to the third party on the
* other side of the cloned phone.
*/
mutex_lock(&phone->lock);
if (phone->state == IPC_PHONE_CONNECTED) {
spinlock_lock(&phone->callee->lock);
list_remove(&phone->link);
phone->state = IPC_PHONE_SLAMMED;
spinlock_unlock(&phone->callee->lock);
}
mutex_unlock(&phone->lock);
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME) {
phone_t *phone = (phone_t *)IPC_GET_ARG5(*olddata);
if (IPC_GET_RETVAL(answer->data) != EOK) {
/*
* The other party on the cloned phoned rejected our
* request for connection on the protocol level.
* We need to break the connection without sending
* IPC_M_HUNGUP back.
*/
mutex_lock(&phone->lock);
if (phone->state == IPC_PHONE_CONNECTED) {
spinlock_lock(&phone->callee->lock);
list_remove(&phone->link);
phone->state = IPC_PHONE_SLAMMED;
spinlock_unlock(&phone->callee->lock);
}
mutex_unlock(&phone->lock);
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
phoneid = IPC_GET_ARG5(*olddata);
if (IPC_GET_RETVAL(answer->data) != EOK) {
if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
phoneid = IPC_GET_ARG3(*olddata);
if (IPC_GET_RETVAL(answer->data)) {
/* The connection was not accepted */
phone_dealloc(phoneid);
} else {
/* The connection was accepted */
phone_connect(phoneid, &answer->sender->answerbox);
/* Set 'phone hash' as arg5 of response */
IPC_SET_ARG5(answer->data,
(unative_t) &TASK->phones[phoneid]);
phone_connect(phoneid,&answer->sender->answerbox);
/* Set 'phone identification' as arg3 of response */
IPC_SET_ARG3(answer->data, (unative_t)&TASK->phones[phoneid]);
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
/* If the users accepted call, connect */
if (IPC_GET_RETVAL(answer->data) == EOK) {
ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata),
&TASK->answerbox);
if (!IPC_GET_RETVAL(answer->data)) {
ipc_phone_connect((phone_t *)IPC_GET_ARG3(*olddata),
&TASK->answerbox);
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_SHARE_OUT) {
if (!IPC_GET_RETVAL(answer->data)) {
/* Accepted, handle as_area receipt */
} else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_SEND) {
if (!IPC_GET_RETVAL(answer->data)) { /* Accepted, handle as_area receipt */
ipl_t ipl;
int rc;
as_t *as;
256,13 → 152,12
spinlock_unlock(&answer->sender->lock);
interrupts_restore(ipl);
rc = as_area_share(as, IPC_GET_ARG1(*olddata),
IPC_GET_ARG2(*olddata), AS,
IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata));
rc = as_area_share(as, IPC_GET_ARG1(*olddata), IPC_GET_ARG2(*olddata),
AS, IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata));
IPC_SET_RETVAL(answer->data, rc);
return rc;
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_SHARE_IN) {
} else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_RECV) {
if (!IPC_GET_RETVAL(answer->data)) {
ipl_t ipl;
as_t *as;
274,172 → 169,40
spinlock_unlock(&answer->sender->lock);
interrupts_restore(ipl);
rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
IPC_GET_ARG2(*olddata), as, IPC_GET_ARG1(*olddata),
IPC_GET_ARG2(answer->data));
rc = as_area_share(AS, IPC_GET_ARG1(answer->data), IPC_GET_ARG2(*olddata),
as, IPC_GET_ARG1(*olddata), IPC_GET_ARG2(answer->data));
IPC_SET_RETVAL(answer->data, rc);
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_DATA_READ) {
ASSERT(!answer->buffer);
if (!IPC_GET_RETVAL(answer->data)) {
/* The recipient agreed to send data. */
uintptr_t src = IPC_GET_ARG1(answer->data);
uintptr_t dst = IPC_GET_ARG1(*olddata);
size_t max_size = IPC_GET_ARG2(*olddata);
size_t size = IPC_GET_ARG2(answer->data);
if (size && size <= max_size) {
/*
* Copy the destination VA so that this piece of
* information is not lost.
*/
IPC_SET_ARG1(answer->data, dst);
 
answer->buffer = malloc(size, 0);
int rc = copy_from_uspace(answer->buffer,
(void *) src, size);
if (rc) {
IPC_SET_RETVAL(answer->data, rc);
free(answer->buffer);
answer->buffer = NULL;
}
} else if (!size) {
IPC_SET_RETVAL(answer->data, EOK);
} else {
IPC_SET_RETVAL(answer->data, ELIMIT);
}
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_DATA_WRITE) {
ASSERT(answer->buffer);
if (!IPC_GET_RETVAL(answer->data)) {
/* The recipient agreed to receive data. */
int rc;
uintptr_t dst;
size_t size;
size_t max_size;
 
dst = (uintptr_t)IPC_GET_ARG1(answer->data);
size = (size_t)IPC_GET_ARG2(answer->data);
max_size = (size_t)IPC_GET_ARG2(*olddata);
 
if (size <= max_size) {
rc = copy_to_uspace((void *) dst,
answer->buffer, size);
if (rc)
IPC_SET_RETVAL(answer->data, rc);
} else {
IPC_SET_RETVAL(answer->data, ELIMIT);
}
}
free(answer->buffer);
answer->buffer = NULL;
}
return 0;
}
 
static void phones_lock(phone_t *p1, phone_t *p2)
{
if (p1 < p2) {
mutex_lock(&p1->lock);
mutex_lock(&p2->lock);
} else if (p1 > p2) {
mutex_lock(&p2->lock);
mutex_lock(&p1->lock);
} else {
mutex_lock(&p1->lock);
}
}
 
static void phones_unlock(phone_t *p1, phone_t *p2)
{
mutex_unlock(&p1->lock);
if (p1 != p2)
mutex_unlock(&p2->lock);
}
 
/** Called before the request is sent.
/** Called before the request is sent
*
* @param call Call structure with the request.
* @param phone Phone that the call will be sent through.
*
* @return Return 0 on success, ELIMIT or EPERM on error.
* @return 0 - no error, -1 - report error to user
*/
static int request_preprocess(call_t *call, phone_t *phone)
static int request_preprocess(call_t *call)
{
int newphid;
size_t size;
uintptr_t src;
int rc;
 
switch (IPC_GET_METHOD(call->data)) {
case IPC_M_CONNECTION_CLONE: {
phone_t *cloned_phone;
GET_CHECK_PHONE(cloned_phone, IPC_GET_ARG1(call->data),
return ENOENT);
phones_lock(cloned_phone, phone);
if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
phone->state != IPC_PHONE_CONNECTED) {
phones_unlock(cloned_phone, phone);
return EINVAL;
}
/*
* We can be pretty sure now that both tasks exist and we are
* connected to them. As we continue to hold the phone locks,
* we are effectively preventing them from finishing their
* potential cleanup.
*/
newphid = phone_alloc(phone->callee->task);
if (newphid < 0) {
phones_unlock(cloned_phone, phone);
return ELIMIT;
}
ipc_phone_connect(&phone->callee->task->phones[newphid],
cloned_phone->callee);
phones_unlock(cloned_phone, phone);
/* Set the new phone for the callee. */
IPC_SET_ARG1(call->data, newphid);
break;
}
case IPC_M_CONNECT_ME:
IPC_SET_ARG5(call->data, (unative_t) phone);
break;
case IPC_M_CONNECT_ME_TO:
newphid = phone_alloc(TASK);
newphid = phone_alloc();
if (newphid < 0)
return ELIMIT;
/* Set arg5 for server */
IPC_SET_ARG5(call->data, (unative_t) &TASK->phones[newphid]);
/* Set arg3 for server */
IPC_SET_ARG3(call->data, (unative_t)&TASK->phones[newphid]);
call->flags |= IPC_CALL_CONN_ME_TO;
call->priv = newphid;
break;
case IPC_M_SHARE_OUT:
size = as_area_get_size(IPC_GET_ARG1(call->data));
if (!size)
case IPC_M_AS_AREA_SEND:
size = as_get_size(IPC_GET_ARG1(call->data));
if (!size) {
return EPERM;
}
IPC_SET_ARG2(call->data, size);
break;
case IPC_M_DATA_READ:
size = IPC_GET_ARG2(call->data);
if ((size <= 0 || (size > DATA_XFER_LIMIT)))
return ELIMIT;
break;
case IPC_M_DATA_WRITE:
src = IPC_GET_ARG1(call->data);
size = IPC_GET_ARG2(call->data);
if (size > DATA_XFER_LIMIT)
return ELIMIT;
call->buffer = (uint8_t *) malloc(size, 0);
rc = copy_from_uspace(call->buffer, (void *) src, size);
if (rc != 0) {
free(call->buffer);
return rc;
}
break;
#ifdef CONFIG_UDEBUG
case IPC_M_DEBUG_ALL:
return udebug_request_preprocess(call, phone);
#endif
default:
break;
}
446,18 → 209,16
return 0;
}
 
/*******************************************************************************
* Functions called to process received call/answer before passing it to uspace.
*******************************************************************************/
/****************************************************/
/* Functions called to process received call/answer
* before passing to uspace
*/
 
/** Do basic kernel processing of received call answer.
*
* @param call Call structure with the answer.
*/
/** Do basic kernel processing of received call answer */
static void process_answer(call_t *call)
{
if (((native_t) IPC_GET_RETVAL(call->data) == EHANGUP) &&
(call->flags & IPC_CALL_FORWARDED))
if (IPC_GET_RETVAL(call->data) == EHANGUP && \
call->flags & IPC_CALL_FORWARDED)
IPC_SET_RETVAL(call->data, EFORWARD);
 
if (call->flags & IPC_CALL_CONN_ME_TO) {
464,123 → 225,61
if (IPC_GET_RETVAL(call->data))
phone_dealloc(call->priv);
else
IPC_SET_ARG5(call->data, call->priv);
IPC_SET_ARG3(call->data, call->priv);
}
 
if (call->buffer) {
/* This must be an affirmative answer to IPC_M_DATA_READ. */
/* or IPC_M_DEBUG_ALL/UDEBUG_M_MEM_READ... */
uintptr_t dst = IPC_GET_ARG1(call->data);
size_t size = IPC_GET_ARG2(call->data);
int rc = copy_to_uspace((void *) dst, call->buffer, size);
if (rc)
IPC_SET_RETVAL(call->data, rc);
free(call->buffer);
call->buffer = NULL;
}
}
 
/** Do basic kernel processing of received call request.
/** Do basic kernel processing of received call request
*
* @param box Destination answerbox structure.
* @param call Call structure with the request.
*
* @return Return 0 if the call should be passed to userspace.
* Return -1 if the call should be ignored.
* @return 0 - the call should be passed to userspace, 1 - ignore call
*/
static int process_request(answerbox_t *box, call_t *call)
static int process_request(answerbox_t *box,call_t *call)
{
int phoneid;
 
if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) {
phoneid = phone_alloc(TASK);
phoneid = phone_alloc();
if (phoneid < 0) { /* Failed to allocate phone */
IPC_SET_RETVAL(call->data, ELIMIT);
ipc_answer(box, call);
ipc_answer(box,call);
return -1;
}
IPC_SET_ARG5(call->data, phoneid);
}
switch (IPC_GET_METHOD(call->data)) {
case IPC_M_DEBUG_ALL:
return -1;
default:
break;
}
IPC_SET_ARG3(call->data, phoneid);
}
return 0;
}
 
/** Make a fast call over IPC, wait for reply and return to user.
/** Send a call over IPC, wait for reply, return to user
*
* This function can handle only three arguments of payload, but is faster than
* the generic function (i.e. sys_ipc_call_sync_slow()).
*
* @param phoneid Phone handle for the call.
* @param method Method of the call.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param data Address of userspace structure where the reply call will
* be stored.
*
* @return Returns 0 on success.
* Return ENOENT if there is no such phone handle.
* @return Call identification, returns -1 on fatal error,
-2 on 'Too many async request, handle answers first
*/
unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method,
unative_t arg1, unative_t arg2, unative_t arg3, ipc_data_t *data)
unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method,
unative_t arg1, ipc_data_t *data)
{
call_t call;
phone_t *phone;
int res;
int rc;
 
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
ipc_call_static_init(&call);
IPC_SET_METHOD(call.data, method);
IPC_SET_ARG1(call.data, arg1);
IPC_SET_ARG2(call.data, arg2);
IPC_SET_ARG3(call.data, arg3);
/*
* To achieve deterministic behavior, zero out arguments that are beyond
* the limits of the fast version.
*/
IPC_SET_ARG4(call.data, 0);
IPC_SET_ARG5(call.data, 0);
 
if (!(res = request_preprocess(&call, phone))) {
#ifdef CONFIG_UDEBUG
udebug_stoppable_begin();
#endif
rc = ipc_call_sync(phone, &call);
#ifdef CONFIG_UDEBUG
udebug_stoppable_end();
#endif
if (rc != EOK)
return rc;
if (!(res=request_preprocess(&call))) {
ipc_call_sync(phone, &call);
process_answer(&call);
 
} else {
} else
IPC_SET_RETVAL(call.data, res);
}
rc = STRUCT_TO_USPACE(&data->args, &call.data.args);
if (rc != 0)
return rc;
STRUCT_TO_USPACE(&data->args, &call.data.args);
 
return 0;
}
 
/** Make a synchronous IPC call allowing to transmit the entire payload.
*
* @param phoneid Phone handle for the call.
* @param question Userspace address of call data with the request.
* @param reply Userspace address of call data where to store the
* answer.
*
* @return Zero on success or an error code.
*/
unative_t sys_ipc_call_sync_slow(unative_t phoneid, ipc_data_t *question,
ipc_data_t *reply)
/** Synchronous IPC call allowing to send whole message */
unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question,
ipc_data_t *reply)
{
call_t call;
phone_t *phone;
588,23 → 287,14
int rc;
 
ipc_call_static_init(&call);
rc = copy_from_uspace(&call.data.args, &question->args,
sizeof(call.data.args));
rc = copy_from_uspace(&call.data.args, &question->args, sizeof(call.data.args));
if (rc != 0)
return (unative_t) rc;
 
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
if (!(res = request_preprocess(&call, phone))) {
#ifdef CONFIG_UDEBUG
udebug_stoppable_begin();
#endif
rc = ipc_call_sync(phone, &call);
#ifdef CONFIG_UDEBUG
udebug_stoppable_end();
#endif
if (rc != EOK)
return rc;
if (!(res=request_preprocess(&call))) {
ipc_call_sync(phone, &call);
process_answer(&call);
} else
IPC_SET_RETVAL(call.data, res);
616,9 → 306,9
return 0;
}
 
/** Check that the task did not exceed the allowed limit of asynchronous calls.
/** Check that the task did not exceed allowed limit
*
* @return Return 0 if limit not reached or -1 if limit exceeded.
* @return 0 - Limit OK, -1 - limit exceeded
*/
static int check_call_limit(void)
{
629,25 → 319,13
return 0;
}
 
/** Make a fast asynchronous call over IPC.
/** Send an asynchronous call over ipc
*
* This function can only handle four arguments of payload, but is faster than
* the generic function sys_ipc_call_async_slow().
*
* @param phoneid Phone handle for the call.
* @param method Method of the call.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
* @param arg3 Service-defined payload argument.
* @param arg4 Service-defined payload argument.
*
* @return Return call hash on success.
* Return IPC_CALLRET_FATAL in case of a fatal error and
* IPC_CALLRET_TEMPORARY if there are too many pending
* asynchronous requests; answers should be handled first.
* @return Call identification, returns -1 on fatal error,
-2 on 'Too many async request, handle answers first
*/
unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method,
unative_t arg1, unative_t arg2, unative_t arg3, unative_t arg4)
unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method,
unative_t arg1, unative_t arg2)
{
call_t *call;
phone_t *phone;
662,15 → 340,9
IPC_SET_METHOD(call->data, method);
IPC_SET_ARG1(call->data, arg1);
IPC_SET_ARG2(call->data, arg2);
IPC_SET_ARG3(call->data, arg3);
IPC_SET_ARG4(call->data, arg4);
/*
* To achieve deterministic behavior, zero out arguments that are beyond
* the limits of the fast version.
*/
IPC_SET_ARG5(call->data, 0);
IPC_SET_ARG3(call->data, 0);
 
if (!(res = request_preprocess(call, phone)))
if (!(res=request_preprocess(call)))
ipc_call(phone, call);
else
ipc_backsend_err(phone, call, res);
678,14 → 350,11
return (unative_t) call;
}
 
/** Make an asynchronous IPC call allowing to transmit the entire payload.
/** Synchronous IPC call allowing to send whole message
*
* @param phoneid Phone handle for the call.
* @param data Userspace address of call data with the request.
*
* @return See sys_ipc_call_async_fast().
* @return The same as sys_ipc_call_async
*/
unative_t sys_ipc_call_async_slow(unative_t phoneid, ipc_data_t *data)
unative_t sys_ipc_call_async(unative_t phoneid, ipc_data_t *data)
{
call_t *call;
phone_t *phone;
698,13 → 367,12
GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
 
call = ipc_call_alloc(0);
rc = copy_from_uspace(&call->data.args, &data->args,
sizeof(call->data.args));
rc = copy_from_uspace(&call->data.args, &data->args, sizeof(call->data.args));
if (rc != 0) {
ipc_call_free(call);
return (unative_t) rc;
}
if (!(res = request_preprocess(call, phone)))
if (!(res=request_preprocess(call)))
ipc_call(phone, call);
else
ipc_backsend_err(phone, call, res);
712,29 → 380,15
return (unative_t) call;
}
 
/** Forward a received call to another destination - common code for both the
* fast and the slow version.
/** Forward received call to another destination
*
* @param callid Hash of the call to forward.
* @param phoneid Phone handle to use for forwarding.
* @param method New method to use for the forwarded call.
* @param arg1 New value of the first argument for the forwarded call.
* @param arg2 New value of the second argument for the forwarded call.
* @param arg3 New value of the third argument for the forwarded call.
* @param arg4 New value of the fourth argument for the forwarded call.
* @param arg5 New value of the fifth argument for the forwarded call.
* @param mode Flags that specify mode of the forward operation.
* @param slow If true, arg3, arg4 and arg5 are considered. Otherwise
* the function considers only the fast version arguments:
* i.e. arg1 and arg2.
* The arg1 and arg2 are changed in the forwarded message
*
* @return Return 0 on succes, otherwise return an error code.
*
* Warning: Make sure that ARG5 is not rewritten for certain system IPC
* Warning: If implementing non-fast version, make sure that
* arg3 is not rewritten for certain system IPC
*/
static unative_t sys_ipc_forward_common(unative_t callid, unative_t phoneid,
unative_t method, unative_t arg1, unative_t arg2, unative_t arg3,
unative_t arg4, unative_t arg5, int mode, bool slow)
unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid,
unative_t method, unative_t arg1)
{
call_t *call;
phone_t *phone;
742,7 → 396,7
call = get_call(callid);
if (!call)
return ENOENT;
 
call->flags |= IPC_CALL_FORWARDED;
 
GET_CHECK_PHONE(phone, phoneid, {
749,125 → 403,35
IPC_SET_RETVAL(call->data, EFORWARD);
ipc_answer(&TASK->answerbox, call);
return ENOENT;
});
});
 
if (!method_is_forwardable(IPC_GET_METHOD(call->data))) {
if (!is_forwardable(IPC_GET_METHOD(call->data))) {
IPC_SET_RETVAL(call->data, EFORWARD);
ipc_answer(&TASK->answerbox, call);
return EPERM;
}
 
/*
* Userspace is not allowed to change method of system methods on
* forward, allow changing ARG1, ARG2, ARG3 and ARG4 by means of method,
* arg1, arg2 and arg3.
* If the method is immutable, don't change anything.
/* Userspace is not allowed to change method of system methods
* on forward, allow changing ARG1 and ARG2 by means of method and arg1
*/
if (!method_is_immutable(IPC_GET_METHOD(call->data))) {
if (method_is_system(IPC_GET_METHOD(call->data))) {
if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
phone_dealloc(IPC_GET_ARG5(call->data));
if (is_system_method(IPC_GET_METHOD(call->data))) {
if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
phone_dealloc(IPC_GET_ARG3(call->data));
 
IPC_SET_ARG1(call->data, method);
IPC_SET_ARG2(call->data, arg1);
IPC_SET_ARG3(call->data, arg2);
if (slow) {
IPC_SET_ARG4(call->data, arg3);
/*
* For system methods we deliberately don't
* overwrite ARG5.
*/
}
} else {
IPC_SET_METHOD(call->data, method);
IPC_SET_ARG1(call->data, arg1);
IPC_SET_ARG2(call->data, arg2);
if (slow) {
IPC_SET_ARG3(call->data, arg3);
IPC_SET_ARG4(call->data, arg4);
IPC_SET_ARG5(call->data, arg5);
}
}
IPC_SET_ARG1(call->data, method);
IPC_SET_ARG2(call->data, arg1);
} else {
IPC_SET_METHOD(call->data, method);
IPC_SET_ARG1(call->data, arg1);
}
 
return ipc_forward(call, phone, &TASK->answerbox, mode);
return ipc_forward(call, phone, &TASK->answerbox);
}
 
/** Forward a received call to another destination - fast version.
*
* @param callid Hash of the call to forward.
* @param phoneid Phone handle to use for forwarding.
* @param method New method to use for the forwarded call.
* @param arg1 New value of the first argument for the forwarded call.
* @param arg2 New value of the second argument for the forwarded call.
* @param mode Flags that specify mode of the forward operation.
*
* @return Return 0 on succes, otherwise return an error code.
*
* In case the original method is a system method, ARG1, ARG2 and ARG3 are
* overwritten in the forwarded message with the new method and the new
* arg1 and arg2, respectively. Otherwise the METHOD, ARG1 and ARG2 are
* rewritten with the new method, arg1 and arg2, respectively. Also note there
* is a set of immutable methods, for which the new method and arguments are not
* set and these values are ignored.
*/
unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid,
unative_t method, unative_t arg1, unative_t arg2, int mode)
/** Send IPC answer */
unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval,
unative_t arg1, unative_t arg2)
{
return sys_ipc_forward_common(callid, phoneid, method, arg1, arg2, 0, 0,
0, mode, false);
}
 
/** Forward a received call to another destination - slow version.
*
* @param callid Hash of the call to forward.
* @param phoneid Phone handle to use for forwarding.
* @param data Userspace address of the new IPC data.
* @param mode Flags that specify mode of the forward operation.
*
* @return Return 0 on succes, otherwise return an error code.
*
* This function is the slow verision of the sys_ipc_forward_fast interface.
* It can copy all five new arguments and the new method from the userspace.
* It naturally extends the functionality of the fast version. For system
* methods, it additionally stores the new value of arg3 to ARG4. For non-system
* methods, it additionally stores the new value of arg3, arg4 and arg5,
* respectively, to ARG3, ARG4 and ARG5, respectively.
*/
unative_t sys_ipc_forward_slow(unative_t callid, unative_t phoneid,
ipc_data_t *data, int mode)
{
ipc_data_t newdata;
int rc;
 
rc = copy_from_uspace(&newdata.args, &data->args,
sizeof(newdata.args));
if (rc != 0)
return (unative_t) rc;
 
return sys_ipc_forward_common(callid, phoneid,
IPC_GET_METHOD(newdata), IPC_GET_ARG1(newdata),
IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true);
}
 
/** Answer an IPC call - fast version.
*
* This function can handle only two return arguments of payload, but is faster
* than the generic sys_ipc_answer().
*
* @param callid Hash of the call to be answered.
* @param retval Return value of the answer.
* @param arg1 Service-defined return value.
* @param arg2 Service-defined return value.
* @param arg3 Service-defined return value.
* @param arg4 Service-defined return value.
*
* @return Return 0 on success, otherwise return an error code.
*/
unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval,
unative_t arg1, unative_t arg2, unative_t arg3, unative_t arg4)
{
call_t *call;
ipc_data_t saved_data;
int saveddata = 0;
889,13 → 453,6
IPC_SET_RETVAL(call->data, retval);
IPC_SET_ARG1(call->data, arg1);
IPC_SET_ARG2(call->data, arg2);
IPC_SET_ARG3(call->data, arg3);
IPC_SET_ARG4(call->data, arg4);
/*
* To achieve deterministic behavior, zero out arguments that are beyond
* the limits of the fast version.
*/
IPC_SET_ARG5(call->data, 0);
rc = answer_preprocess(call, saveddata ? &saved_data : NULL);
 
ipc_answer(&TASK->answerbox, call);
902,14 → 459,8
return rc;
}
 
/** Answer an IPC call.
*
* @param callid Hash of the call to be answered.
* @param data Userspace address of call data with the answer.
*
* @return Return 0 on success, otherwise return an error code.
*/
unative_t sys_ipc_answer_slow(unative_t callid, ipc_data_t *data)
/** Send IPC answer */
unative_t sys_ipc_answer(unative_t callid, ipc_data_t *data)
{
call_t *call;
ipc_data_t saved_data;
929,7 → 480,7
saveddata = 1;
}
rc = copy_from_uspace(&call->data.args, &data->args,
sizeof(call->data.args));
sizeof(call->data.args));
if (rc != 0)
return rc;
 
940,11 → 491,8
return rc;
}
 
/** Hang up a phone.
/** Hang up the phone
*
* @param Phone handle of the phone to be hung up.
*
* @return Return 0 on success or an error code.
*/
unative_t sys_ipc_hangup(int phoneid)
{
958,33 → 506,20
return 0;
}
 
/** Wait for an incoming IPC call or an answer.
/** Wait for incoming ipc call or answer
*
* @param calldata Pointer to buffer where the call/answer data is stored.
* @param usec Timeout. See waitq_sleep_timeout() for explanation.
* @param flags Select mode of sleep operation. See waitq_sleep_timeout()
* for explanation.
* @param calldata Pointer to buffer where the call/answer data is stored
* @param usec Timeout. See waitq_sleep_timeout() for explanation.
* @param flags Select mode of sleep operation. See waitq_sleep_timeout() for explanation.
*
* @return Hash of the call.
* If IPC_CALLID_NOTIFICATION bit is set in the hash, the
* call is a notification. IPC_CALLID_ANSWERED denotes an
* answer.
* @return Callid, if callid & 1, then the call is answer
*/
unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, int flags)
{
call_t *call;
 
restart:
 
#ifdef CONFIG_UDEBUG
udebug_stoppable_begin();
#endif
call = ipc_wait_for_call(&TASK->answerbox, usec,
flags | SYNCH_FLAGS_INTERRUPTIBLE);
 
#ifdef CONFIG_UDEBUG
udebug_stoppable_end();
#endif
restart:
call = ipc_wait_for_call(&TASK->answerbox, usec, flags | SYNCH_FLAGS_INTERRUPTIBLE);
if (!call)
return 0;
 
998,7 → 533,7
 
ipc_call_free(call);
return ((unative_t) call) | IPC_CALLID_NOTIFICATION;
return ((unative_t)call) | IPC_CALLID_NOTIFICATION;
}
 
if (call->flags & IPC_CALL_ANSWERED) {
1006,22 → 541,17
 
ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
 
atomic_dec(&TASK->active_calls);
 
if (call->flags & IPC_CALL_DISCARD_ANSWER) {
ipc_call_free(call);
goto restart;
} else {
/*
* Decrement the counter of active calls only if the
* call is not an answer to IPC_M_PHONE_HUNGUP,
* which doesn't contribute to the counter.
*/
atomic_dec(&TASK->active_calls);
}
 
STRUCT_TO_USPACE(&calldata->args, &call->data.args);
ipc_call_free(call);
 
return ((unative_t) call) | IPC_CALLID_ANSWERED;
return ((unative_t)call) | IPC_CALLID_ANSWERED;
}
 
if (process_request(&TASK->answerbox, call))
1030,37 → 560,21
/* Include phone address('id') of the caller in the request,
* copy whole call->data, not only call->data.args */
if (STRUCT_TO_USPACE(calldata, &call->data)) {
/*
* The callee will not receive this call and no one else has
* a chance to answer it. Reply with the EPARTY error code.
*/
ipc_data_t saved_data;
int saveddata = 0;
 
if (answer_need_old(call)) {
memcpy(&saved_data, &call->data, sizeof(call->data));
saveddata = 1;
}
IPC_SET_RETVAL(call->data, EPARTY);
(void) answer_preprocess(call, saveddata ? &saved_data : NULL);
ipc_answer(&TASK->answerbox, call);
return 0;
}
return (unative_t)call;
}
 
/** Connect an IRQ handler to a task.
/** Connect irq handler to task.
*
* @param inr IRQ number.
* @param devno Device number.
* @param method Method to be associated with the notification.
* @param ucode Uspace pointer to the top-half pseudocode.
* @param inr IRQ number.
* @param devno Device number.
* @param method Method to be associated with the notification.
* @param ucode Uspace pointer to the top-half pseudocode.
*
* @return EPERM or a return code returned by ipc_irq_register().
* @return EPERM or a return code returned by ipc_irq_register().
*/
unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method,
irq_code_t *ucode)
unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method, irq_code_t *ucode)
{
if (!(cap_get(TASK) & CAP_IRQ_REG))
return EPERM;
1068,12 → 582,10
return ipc_irq_register(&TASK->answerbox, inr, devno, method, ucode);
}
 
/** Disconnect an IRQ handler from a task.
/** Disconnect irq handler from task.
*
* @param inr IRQ number.
* @param devno Device number.
*
* @return Zero on success or EPERM on error..
* @param inr IRQ number.
* @param devno Device number.
*/
unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno)
{
1085,30 → 597,5
return 0;
}
 
#include <console/console.h>
 
/**
* Syscall connect to a task by id.
*
* @return Phone id on success, or negative error code.
*/
unative_t sys_ipc_connect_kbox(sysarg64_t *uspace_taskid_arg)
{
#ifdef CONFIG_UDEBUG
sysarg64_t taskid_arg;
int rc;
rc = copy_from_uspace(&taskid_arg, uspace_taskid_arg, sizeof(sysarg64_t));
if (rc != 0)
return (unative_t) rc;
 
LOG("sys_ipc_connect_kbox(%" PRIu64 ")\n", taskid_arg.value);
 
return ipc_connect_kbox(taskid_arg.value);
#else
return (unative_t) ENOTSUP;
#endif
}
 
/** @}
*/
/branches/arm/kernel/generic/src/ipc/irq.c
44,28 → 44,8
* - ARG1: payload modified by a 'top-half' handler
* - ARG2: payload modified by a 'top-half' handler
* - ARG3: payload modified by a 'top-half' handler
* - ARG4: payload modified by a 'top-half' handler
* - ARG5: payload modified by a 'top-half' handler
* - in_phone_hash: interrupt counter (may be needed to assure correct order
* in multithreaded drivers)
*
* Note on synchronization for ipc_irq_register(), ipc_irq_unregister(),
* ipc_irq_cleanup() and IRQ handlers:
*
* By always taking all of the uspace IRQ hash table lock, IRQ structure lock
* and answerbox lock, we can rule out race conditions between the
* registration functions and also the cleanup function. Thus the observer can
* either see the IRQ structure present in both the hash table and the
* answerbox list or absent in both. Views in which the IRQ structure would be
* linked in the hash table but not in the answerbox list, or vice versa, are
* not possible.
*
* By always taking the hash table lock and the IRQ structure lock, we can
* rule out a scenario in which we would free up an IRQ structure, which is
* still referenced by, for example, an IRQ handler. The locking scheme forces
* us to lock the IRQ structure only after any progressing IRQs on that
* structure are finished. Because we hold the hash table lock, we prevent new
* IRQs from taking new references to the IRQ structure.
*/
 
#include <arch.h>
78,10 → 58,72
#include <console/console.h>
#include <print.h>
 
/** Free the top-half pseudocode.
/** Execute code associated with IRQ notification.
*
* @param code Pointer to the top-half pseudocode.
* @param call Notification call.
* @param code Top-half pseudocode.
*/
static void code_execute(call_t *call, irq_code_t *code)
{
int i;
unative_t dstval = 0;
if (!code)
return;
for (i=0; i < code->cmdcount;i++) {
switch (code->cmds[i].cmd) {
case CMD_MEM_READ_1:
dstval = *((uint8_t *)code->cmds[i].addr);
break;
case CMD_MEM_READ_2:
dstval = *((uint16_t *)code->cmds[i].addr);
break;
case CMD_MEM_READ_4:
dstval = *((uint32_t *)code->cmds[i].addr);
break;
case CMD_MEM_READ_8:
dstval = *((uint64_t *)code->cmds[i].addr);
break;
case CMD_MEM_WRITE_1:
*((uint8_t *)code->cmds[i].addr) = code->cmds[i].value;
break;
case CMD_MEM_WRITE_2:
*((uint16_t *)code->cmds[i].addr) = code->cmds[i].value;
break;
case CMD_MEM_WRITE_4:
*((uint32_t *)code->cmds[i].addr) = code->cmds[i].value;
break;
case CMD_MEM_WRITE_8:
*((uint64_t *)code->cmds[i].addr) = code->cmds[i].value;
break;
#if defined(ia32) || defined(amd64)
case CMD_PORT_READ_1:
dstval = inb((long)code->cmds[i].addr);
break;
case CMD_PORT_WRITE_1:
outb((long)code->cmds[i].addr, code->cmds[i].value);
break;
#endif
#if defined(ia64) && defined(SKI)
case CMD_IA64_GETCHAR:
dstval = _getc(&ski_uconsole);
break;
#endif
#if defined(ppc32)
case CMD_PPC32_GETCHAR:
dstval = cuda_get_scancode();
break;
#endif
default:
break;
}
if (code->cmds[i].dstarg && code->cmds[i].dstarg < 4) {
call->data.args[code->cmds[i].dstarg] = dstval;
}
}
}
 
static void code_free(irq_code_t *code)
{
if (code) {
90,13 → 132,7
}
}
 
/** Copy the top-half pseudocode from userspace into the kernel.
*
* @param ucode Userspace address of the top-half pseudocode.
*
* @return Kernel address of the copied pseudocode.
*/
static irq_code_t *code_from_uspace(irq_code_t *ucode)
static irq_code_t * code_from_uspace(irq_code_t *ucode)
{
irq_code_t *code;
irq_cmd_t *ucmds;
114,9 → 150,8
return NULL;
}
ucmds = code->cmds;
code->cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0);
rc = copy_from_uspace(code->cmds, ucmds,
sizeof(code->cmds[0]) * code->cmdcount);
code->cmds = malloc(sizeof(code->cmds[0]) * (code->cmdcount), 0);
rc = copy_from_uspace(code->cmds, ucmds, sizeof(code->cmds[0]) * (code->cmdcount));
if (rc != 0) {
free(code->cmds);
free(code);
126,143 → 161,162
return code;
}
 
/** Unregister task from IRQ notification.
*
* @param box Answerbox associated with the notification.
* @param inr IRQ numbe.
* @param devno Device number.
*/
void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
{
ipl_t ipl;
irq_t *irq;
 
ipl = interrupts_disable();
irq = irq_find_and_lock(inr, devno);
if (irq) {
if (irq->notif_cfg.answerbox == box) {
code_free(irq->notif_cfg.code);
irq->notif_cfg.notify = false;
irq->notif_cfg.answerbox = NULL;
irq->notif_cfg.code = NULL;
irq->notif_cfg.method = 0;
irq->notif_cfg.counter = 0;
 
spinlock_lock(&box->irq_lock);
list_remove(&irq->notif_cfg.link);
spinlock_unlock(&box->irq_lock);
spinlock_unlock(&irq->lock);
}
}
interrupts_restore(ipl);
}
 
/** Register an answerbox as a receiving end for IRQ notifications.
*
* @param box Receiving answerbox.
* @param inr IRQ number.
* @param devno Device number.
* @param box Receiving answerbox.
* @param inr IRQ number.
* @param devno Device number.
* @param method Method to be associated with the notification.
* @param ucode Uspace pointer to top-half pseudocode.
* @param ucode Uspace pointer to top-half pseudocode.
*
* @return EBADMEM, ENOENT or EEXISTS on failure or 0 on success.
*
*/
int ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno,
unative_t method, irq_code_t *ucode)
int ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno, unative_t method, irq_code_t *ucode)
{
ipl_t ipl;
irq_code_t *code;
irq_t *irq;
link_t *hlp;
unative_t key[] = {
(unative_t) inr,
(unative_t) devno
};
 
if (ucode) {
code = code_from_uspace(ucode);
if (!code)
return EBADMEM;
} else {
} else
code = NULL;
 
ipl = interrupts_disable();
irq = irq_find_and_lock(inr, devno);
if (!irq) {
interrupts_restore(ipl);
code_free(code);
return ENOENT;
}
/*
* Allocate and populate the IRQ structure.
*/
irq = malloc(sizeof(irq_t), 0);
irq_initialize(irq);
irq->devno = devno;
irq->inr = inr;
irq->claim = ipc_irq_top_half_claim;
irq->handler = ipc_irq_top_half_handler;
if (irq->notif_cfg.answerbox) {
spinlock_unlock(&irq->lock);
interrupts_restore(ipl);
code_free(code);
return EEXISTS;
}
irq->notif_cfg.notify = true;
irq->notif_cfg.answerbox = box;
irq->notif_cfg.method = method;
irq->notif_cfg.code = code;
irq->notif_cfg.counter = 0;
/*
* Enlist the IRQ structure in the uspace IRQ hash table and the
* answerbox's list.
*/
ipl = interrupts_disable();
spinlock_lock(&irq_uspace_hash_table_lock);
hlp = hash_table_find(&irq_uspace_hash_table, key);
if (hlp) {
irq_t *hirq __attribute__((unused))
= hash_table_get_instance(hlp, irq_t, link);
/* hirq is locked */
spinlock_unlock(&hirq->lock);
code_free(code);
spinlock_unlock(&irq_uspace_hash_table_lock);
free(irq);
interrupts_restore(ipl);
return EEXISTS;
}
spinlock_lock(&irq->lock); /* Not really necessary, but paranoid */
 
spinlock_lock(&box->irq_lock);
hash_table_insert(&irq_uspace_hash_table, key, &irq->link);
list_append(&irq->notif_cfg.link, &box->irq_head);
spinlock_unlock(&box->irq_lock);
 
spinlock_unlock(&irq->lock);
spinlock_unlock(&irq_uspace_hash_table_lock);
interrupts_restore(ipl);
return EOK;
 
return 0;
}
 
/** Unregister task from IRQ notification.
/** Add call to proper answerbox queue.
*
* @param box Answerbox associated with the notification.
* @param inr IRQ number.
* @param devno Device number.
* Assume irq->lock is locked.
*
*/
int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
static void send_call(irq_t *irq, call_t *call)
{
ipl_t ipl;
unative_t key[] = {
(unative_t) inr,
(unative_t) devno
};
link_t *lnk;
irq_t *irq;
spinlock_lock(&irq->notif_cfg.answerbox->irq_lock);
list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock);
waitq_wakeup(&irq->notif_cfg.answerbox->wq, WAKEUP_FIRST);
}
 
ipl = interrupts_disable();
spinlock_lock(&irq_uspace_hash_table_lock);
lnk = hash_table_find(&irq_uspace_hash_table, key);
if (!lnk) {
spinlock_unlock(&irq_uspace_hash_table_lock);
interrupts_restore(ipl);
return ENOENT;
}
irq = hash_table_get_instance(lnk, irq_t, link);
/* irq is locked */
spinlock_lock(&box->irq_lock);
ASSERT(irq->notif_cfg.answerbox == box);
/* Free up the pseudo code and associated structures. */
code_free(irq->notif_cfg.code);
/** Send notification message
*
*/
void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3)
{
call_t *call;
 
/* Remove the IRQ from the answerbox's list. */
list_remove(&irq->notif_cfg.link);
spinlock_lock(&irq->lock);
 
/*
* We need to drop the IRQ lock now because hash_table_remove() will try
* to reacquire it. That basically violates the natural locking order,
* but a deadlock in hash_table_remove() is prevented by the fact that
* we already held the IRQ lock and didn't drop the hash table lock in
* the meantime.
*/
if (irq->notif_cfg.answerbox) {
call = ipc_call_alloc(FRAME_ATOMIC);
if (!call) {
spinlock_unlock(&irq->lock);
return;
}
call->flags |= IPC_CALL_NOTIF;
IPC_SET_METHOD(call->data, irq->notif_cfg.method);
IPC_SET_ARG1(call->data, a1);
IPC_SET_ARG2(call->data, a2);
IPC_SET_ARG3(call->data, a3);
/* Put a counter to the message */
call->priv = ++irq->notif_cfg.counter;
send_call(irq, call);
}
spinlock_unlock(&irq->lock);
}
 
/* Remove the IRQ from the uspace IRQ hash table. */
hash_table_remove(&irq_uspace_hash_table, key, 2);
spinlock_unlock(&irq_uspace_hash_table_lock);
spinlock_unlock(&box->irq_lock);
/* Free up the IRQ structure. */
free(irq);
interrupts_restore(ipl);
return EOK;
/** Notify task that an irq had occurred.
*
* We expect interrupts to be disabled and the irq->lock already held.
*/
void ipc_irq_send_notif(irq_t *irq)
{
call_t *call;
 
ASSERT(irq);
 
if (irq->notif_cfg.answerbox) {
call = ipc_call_alloc(FRAME_ATOMIC);
if (!call) {
return;
}
call->flags |= IPC_CALL_NOTIF;
/* Put a counter to the message */
call->priv = ++irq->notif_cfg.counter;
/* Set up args */
IPC_SET_METHOD(call->data, irq->notif_cfg.method);
 
/* Execute code to handle irq */
code_execute(call, irq->notif_cfg.code);
send_call(irq, call);
}
}
 
 
/** Disconnect all IRQ notifications from an answerbox.
*
* This function is effective because the answerbox contains
269,7 → 323,7
* list of all irq_t structures that are registered to
* send notifications to it.
*
* @param box Answerbox for which we want to carry out the cleanup.
* @param box Answerbox for which we want to carry out the cleanup.
*/
void ipc_irq_cleanup(answerbox_t *box)
{
277,14 → 331,11
loop:
ipl = interrupts_disable();
spinlock_lock(&irq_uspace_hash_table_lock);
spinlock_lock(&box->irq_lock);
while (box->irq_head.next != &box->irq_head) {
link_t *cur = box->irq_head.next;
irq_t *irq;
DEADLOCK_PROBE_INIT(p_irqlock);
unative_t key[2];
irq = list_get_instance(cur, irq_t, notif_cfg.link);
if (!spinlock_trylock(&irq->lock)) {
292,212 → 343,31
* Avoid deadlock by trying again.
*/
spinlock_unlock(&box->irq_lock);
spinlock_unlock(&irq_uspace_hash_table_lock);
interrupts_restore(ipl);
DEADLOCK_PROBE(p_irqlock, DEADLOCK_THRESHOLD);
goto loop;
}
key[0] = irq->inr;
key[1] = irq->devno;
ASSERT(irq->notif_cfg.answerbox == box);
/* Unlist from the answerbox. */
list_remove(&irq->notif_cfg.link);
/* Free up the pseudo code and associated structures. */
/*
* Don't forget to free any top-half pseudocode.
*/
code_free(irq->notif_cfg.code);
/*
* We need to drop the IRQ lock now because hash_table_remove()
* will try to reacquire it. That basically violates the natural
* locking order, but a deadlock in hash_table_remove() is
* prevented by the fact that we already held the IRQ lock and
* didn't drop the hash table lock in the meantime.
*/
irq->notif_cfg.notify = false;
irq->notif_cfg.answerbox = NULL;
irq->notif_cfg.code = NULL;
irq->notif_cfg.method = 0;
irq->notif_cfg.counter = 0;
 
spinlock_unlock(&irq->lock);
/* Remove from the hash table. */
hash_table_remove(&irq_uspace_hash_table, key, 2);
free(irq);
}
spinlock_unlock(&box->irq_lock);
spinlock_unlock(&irq_uspace_hash_table_lock);
interrupts_restore(ipl);
}
 
/** Add a call to the proper answerbox queue.
*
* Assume irq->lock is locked.
*
* @param irq IRQ structure referencing the target answerbox.
* @param call IRQ notification call.
*/
static void send_call(irq_t *irq, call_t *call)
{
spinlock_lock(&irq->notif_cfg.answerbox->irq_lock);
list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock);
waitq_wakeup(&irq->notif_cfg.answerbox->wq, WAKEUP_FIRST);
}
 
/** Apply the top-half pseudo code to find out whether to accept the IRQ or not.
*
* @param irq IRQ structure.
*
* @return IRQ_ACCEPT if the interrupt is accepted by the
* pseudocode. IRQ_DECLINE otherwise.
*/
irq_ownership_t ipc_irq_top_half_claim(irq_t *irq)
{
unsigned int i;
unative_t dstval;
irq_code_t *code = irq->notif_cfg.code;
unative_t *scratch = irq->notif_cfg.scratch;
 
if (!irq->notif_cfg.notify)
return IRQ_DECLINE;
if (!code)
return IRQ_DECLINE;
for (i = 0; i < code->cmdcount; i++) {
unsigned int srcarg = code->cmds[i].srcarg;
unsigned int dstarg = code->cmds[i].dstarg;
if (srcarg >= IPC_CALL_LEN)
break;
if (dstarg >= IPC_CALL_LEN)
break;
switch (code->cmds[i].cmd) {
case CMD_PIO_READ_8:
dstval = pio_read_8((ioport8_t *) code->cmds[i].addr);
if (dstarg)
scratch[dstarg] = dstval;
break;
case CMD_PIO_READ_16:
dstval = pio_read_16((ioport16_t *) code->cmds[i].addr);
if (dstarg)
scratch[dstarg] = dstval;
break;
case CMD_PIO_READ_32:
dstval = pio_read_32((ioport32_t *) code->cmds[i].addr);
if (dstarg)
scratch[dstarg] = dstval;
break;
case CMD_PIO_WRITE_8:
pio_write_8((ioport8_t *) code->cmds[i].addr,
(uint8_t) code->cmds[i].value);
break;
case CMD_PIO_WRITE_16:
pio_write_16((ioport16_t *) code->cmds[i].addr,
(uint16_t) code->cmds[i].value);
break;
case CMD_PIO_WRITE_32:
pio_write_32((ioport32_t *) code->cmds[i].addr,
(uint32_t) code->cmds[i].value);
break;
case CMD_BTEST:
if (srcarg && dstarg) {
dstval = scratch[srcarg] & code->cmds[i].value;
scratch[dstarg] = dstval;
}
break;
case CMD_PREDICATE:
if (srcarg && !scratch[srcarg]) {
i += code->cmds[i].value;
continue;
}
break;
case CMD_ACCEPT:
return IRQ_ACCEPT;
break;
case CMD_DECLINE:
default:
return IRQ_DECLINE;
}
}
return IRQ_DECLINE;
}
 
 
/* IRQ top-half handler.
*
* We expect interrupts to be disabled and the irq->lock already held.
*
* @param irq IRQ structure.
*/
void ipc_irq_top_half_handler(irq_t *irq)
{
ASSERT(irq);
 
if (irq->notif_cfg.answerbox) {
call_t *call;
 
call = ipc_call_alloc(FRAME_ATOMIC);
if (!call)
return;
call->flags |= IPC_CALL_NOTIF;
/* Put a counter to the message */
call->priv = ++irq->notif_cfg.counter;
 
/* Set up args */
IPC_SET_METHOD(call->data, irq->notif_cfg.method);
IPC_SET_ARG1(call->data, irq->notif_cfg.scratch[1]);
IPC_SET_ARG2(call->data, irq->notif_cfg.scratch[2]);
IPC_SET_ARG3(call->data, irq->notif_cfg.scratch[3]);
IPC_SET_ARG4(call->data, irq->notif_cfg.scratch[4]);
IPC_SET_ARG5(call->data, irq->notif_cfg.scratch[5]);
 
send_call(irq, call);
}
}
 
/** Send notification message.
*
* @param irq IRQ structure.
* @param a1 Driver-specific payload argument.
* @param a2 Driver-specific payload argument.
* @param a3 Driver-specific payload argument.
* @param a4 Driver-specific payload argument.
* @param a5 Driver-specific payload argument.
*/
void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3,
unative_t a4, unative_t a5)
{
call_t *call;
 
spinlock_lock(&irq->lock);
 
if (irq->notif_cfg.answerbox) {
call = ipc_call_alloc(FRAME_ATOMIC);
if (!call) {
spinlock_unlock(&irq->lock);
return;
}
call->flags |= IPC_CALL_NOTIF;
/* Put a counter to the message */
call->priv = ++irq->notif_cfg.counter;
 
IPC_SET_METHOD(call->data, irq->notif_cfg.method);
IPC_SET_ARG1(call->data, a1);
IPC_SET_ARG2(call->data, a2);
IPC_SET_ARG3(call->data, a3);
IPC_SET_ARG4(call->data, a4);
IPC_SET_ARG5(call->data, a5);
send_call(irq, call);
}
spinlock_unlock(&irq->lock);
}
 
/** @}
*/
/branches/arm/kernel/generic/src/ipc/ipcrsc.c
34,8 → 34,8
 
/* IPC resources management
*
* The goal of this source code is to properly manage IPC resources and allow
* straight and clean clean-up procedure upon task termination.
* The goal of this source code is to properly manage IPC resources
* and allow straight and clean clean-up procedure upon task termination.
*
* The pattern of usage of the resources is:
* - allocate empty phone slot, connect | deallocate slot
47,24 → 47,24
*
* Locking strategy
*
* - To use a phone, disconnect a phone etc., the phone must be first locked and
* then checked that it is connected
* - To connect an allocated phone it need not be locked (assigning pointer is
* atomic on all platforms)
* - To use a phone, disconnect a phone etc., the phone must be
* first locked and then checked that it is connected
* - To connect an allocated phone it need not be locked (assigning
* pointer is atomic on all platforms)
*
* - To find an empty phone slot, the TASK must be locked
* - To answer a message, the answerbox must be locked
* - The locking of phone and answerbox is done at the ipc_ level.
* It is perfectly correct to pass unconnected phone to these functions and
* proper reply will be generated.
* It is perfectly correct to pass unconnected phone to these functions
* and proper reply will be generated.
*
* Locking order
*
* - first phone, then answerbox
* + Easy locking on calls
* - Very hard traversing list of phones when disconnecting because the phones
* may disconnect during traversal of list of connected phones. The only
* possibility is try_lock with restart of list traversal.
* - Very hard traversing list of phones when disconnecting because
* the phones may disconnect during traversal of list of connected phones.
* The only possibility is try_lock with restart of list traversal.
*
* Destroying is less frequent, this approach is taken.
*
71,23 → 71,24
* Phone call
*
* *** Connect_me_to ***
* The caller sends IPC_M_CONNECT_ME_TO to an answerbox. The server receives
* 'phoneid' of the connecting phone as an ARG5. If it answers with RETVAL=0,
* the phonecall is accepted, otherwise it is refused.
* The caller sends IPC_M_CONNECT_ME_TO to an answerbox. The server
* receives 'phoneid' of the connecting phone as an ARG3. If it answers
* with RETVAL=0, the phonecall is accepted, otherwise it is refused.
*
* *** Connect_to_me ***
* The caller sends IPC_M_CONNECT_TO_ME.
* The server receives an automatically opened phoneid. If it accepts
* (RETVAL=0), it can use the phoneid immediately.
* Possible race condition can arise, when the client receives messages from new
* connection before getting response for connect_to_me message. Userspace
* should implement handshake protocol that would control it.
* The caller sends IPC_M_CONNECT_TO_ME, with special
* The server receives an automatically
* opened phoneid. If it accepts (RETVAL=0), it can use the phoneid
* immediately.
* Possible race condition can arise, when the client receives messages
* from new connection before getting response for connect_to_me message.
* Userspace should implement handshake protocol that would control it.
*
* Phone hangup
*
* *** The caller hangs up (sys_ipc_hangup) ***
* - The phone is disconnected (no more messages can be sent over this phone),
* all in-progress messages are correctly handled. The answerbox receives
* all in-progress messages are correctly handled. The anwerbox receives
* IPC_M_PHONE_HUNGUP call from the phone that hung up. When all async
* calls are answered, the phone is deallocated.
*
132,17 → 133,12
#include <ipc/ipcrsc.h>
#include <debug.h>
 
/** Find call_t * in call table according to callid.
/** Find call_t * in call table according to callid
*
* @todo Some speedup (hash table?)
*
* @param callid Userspace hash of the call. Currently it is the call
* structure kernel address.
*
* @return NULL on not found, otherwise pointer to the call
* structure.
* TODO: Some speedup (hash table?)
* @return NULL on not found, otherwise pointer to call structure
*/
call_t *get_call(unative_t callid)
call_t * get_call(unative_t callid)
{
link_t *lst;
call_t *call, *result = NULL;
149,9 → 145,9
 
spinlock_lock(&TASK->answerbox.lock);
for (lst = TASK->answerbox.dispatched_calls.next;
lst != &TASK->answerbox.dispatched_calls; lst = lst->next) {
lst != &TASK->answerbox.dispatched_calls; lst = lst->next) {
call = list_get_instance(lst, call_t, link);
if ((unative_t) call == callid) {
if ((unative_t)call == callid) {
result = call;
break;
}
160,40 → 156,30
return result;
}
 
/** Allocate new phone slot in the specified task.
*
* @param t Task for which to allocate a new phone.
*
* @return New phone handle or -1 if the phone handle limit is
* exceeded.
*/
int phone_alloc(task_t *t)
/** Allocate new phone slot in current TASK structure */
int phone_alloc(void)
{
int i;
 
spinlock_lock(&t->lock);
for (i = 0; i < IPC_MAX_PHONES; i++) {
if (t->phones[i].state == IPC_PHONE_HUNGUP &&
atomic_get(&t->phones[i].active_calls) == 0)
t->phones[i].state = IPC_PHONE_FREE;
spinlock_lock(&TASK->lock);
for (i=0; i < IPC_MAX_PHONES; i++) {
if (TASK->phones[i].state == IPC_PHONE_HUNGUP && \
atomic_get(&TASK->phones[i].active_calls) == 0)
TASK->phones[i].state = IPC_PHONE_FREE;
 
if (t->phones[i].state == IPC_PHONE_FREE) {
t->phones[i].state = IPC_PHONE_CONNECTING;
if (TASK->phones[i].state == IPC_PHONE_FREE) {
TASK->phones[i].state = IPC_PHONE_CONNECTING;
break;
}
}
spinlock_unlock(&t->lock);
spinlock_unlock(&TASK->lock);
 
if (i == IPC_MAX_PHONES)
if (i >= IPC_MAX_PHONES)
return -1;
 
return i;
}
 
/** Mark a phone structure free.
*
* @param phone Phone structure to be marked free.
*/
static void phone_deallocp(phone_t *phone)
{
ASSERT(phone->state == IPC_PHONE_CONNECTING);
202,11 → 188,9
phone->state = IPC_PHONE_FREE;
}
 
/** Free slot from a disconnected phone.
/** Free slot from a disconnected phone
*
* All already sent messages will be correctly processed.
*
* @param phoneid Phone handle of the phone to be freed.
* All already sent messages will be correctly processed
*/
void phone_dealloc(int phoneid)
{
213,10 → 197,9
phone_deallocp(&TASK->phones[phoneid]);
}
 
/** Connect phone to a given answerbox.
/** Connect phone to a given answerbox
*
* @param phoneid Phone handle to be connected.
* @param box Answerbox to which to connect the phone handle.
* @param phoneid The slot that will be connected
*
* The procedure _enforces_ that the user first marks the phone
* busy (e.g. via phone_alloc) and then connects the phone, otherwise
/branches/arm/kernel/generic/src/ipc/ipc.c
34,17 → 34,13
 
/* Lock ordering
*
* First the answerbox, then the phone.
* First the answerbox, then the phone
*/
 
#include <synch/synch.h>
#include <synch/spinlock.h>
#include <synch/mutex.h>
#include <synch/waitq.h>
#include <synch/synch.h>
#include <ipc/ipc.h>
#include <ipc/kbox.h>
#include <ipc/event.h>
#include <errno.h>
#include <mm/slab.h>
#include <arch.h>
51,55 → 47,43
#include <proc/task.h>
#include <memstr.h>
#include <debug.h>
 
#include <print.h>
#include <console/console.h>
#include <proc/thread.h>
#include <arch/interrupt.h>
#include <ipc/irq.h>
 
/** Open channel that is assigned automatically to new tasks */
/* Open channel that is assigned automatically to new tasks */
answerbox_t *ipc_phone_0 = NULL;
 
static slab_cache_t *ipc_call_slab;
 
/** Initialize a call structure.
*
* @param call Call structure to be initialized.
*/
/* Initialize new call */
static void _ipc_call_init(call_t *call)
{
memsetb(call, sizeof(*call), 0);
memsetb((uintptr_t)call, sizeof(*call), 0);
call->callerbox = &TASK->answerbox;
call->sender = TASK;
call->buffer = NULL;
}
 
/** Allocate and initialize a call structure.
/** Allocate & initialize call structure
*
* The call is initialized, so that the reply will be directed to
* TASK->answerbox.
* The call is initialized, so that the reply will be directed
* to TASK->answerbox
*
* @param flags Parameters for slab_alloc (e.g FRAME_ATOMIC).
*
* @return If flags permit it, return NULL, or initialized kernel
* call structure.
* @param flags Parameters for slab_alloc (ATOMIC, etc.)
*/
call_t *ipc_call_alloc(int flags)
call_t * ipc_call_alloc(int flags)
{
call_t *call;
 
call = slab_alloc(ipc_call_slab, flags);
if (call)
_ipc_call_init(call);
_ipc_call_init(call);
 
return call;
}
 
/** Initialize a statically allocated call structure.
*
* @param call Statically allocated kernel call structure to be
* initialized.
*/
/** Initialize allocated call */
void ipc_call_static_init(call_t *call)
{
_ipc_call_init(call);
106,25 → 90,15
call->flags |= IPC_CALL_STATIC_ALLOC;
}
 
/** Deallocate a call structure.
*
* @param call Call structure to be freed.
*/
/** Deallocate call stracuture */
void ipc_call_free(call_t *call)
{
ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC));
/* Check to see if we have data in the IPC_M_DATA_SEND buffer. */
if (call->buffer)
free(call->buffer);
slab_free(ipc_call_slab, call);
}
 
/** Initialize an answerbox structure.
*
* @param box Answerbox structure to be initialized.
* @param task Task to which the answerbox belongs.
/** Initialize answerbox structure
*/
void ipc_answerbox_init(answerbox_t *box, task_t *task)
void ipc_answerbox_init(answerbox_t *box)
{
spinlock_initialize(&box->lock, "ipc_box_lock");
spinlock_initialize(&box->irq_lock, "ipc_box_irqlock");
135,17 → 109,13
list_initialize(&box->answers);
list_initialize(&box->irq_notifs);
list_initialize(&box->irq_head);
box->task = task;
box->task = TASK;
}
 
/** Connect a phone to an answerbox.
*
* @param phone Initialized phone structure.
* @param box Initialized answerbox structure.
*/
/** Connect phone to answerbox */
void ipc_phone_connect(phone_t *phone, answerbox_t *box)
{
mutex_lock(&phone->lock);
spinlock_lock(&phone->lock);
 
phone->state = IPC_PHONE_CONNECTED;
phone->callee = box;
154,47 → 124,35
list_append(&phone->link, &box->connected_phones);
spinlock_unlock(&box->lock);
 
mutex_unlock(&phone->lock);
spinlock_unlock(&phone->lock);
}
 
/** Initialize a phone structure.
*
* @param phone Phone structure to be initialized.
/** Initialize phone structure and connect phone to answerbox
*/
void ipc_phone_init(phone_t *phone)
{
mutex_initialize(&phone->lock, MUTEX_PASSIVE);
spinlock_initialize(&phone->lock, "phone_lock");
phone->callee = NULL;
phone->state = IPC_PHONE_FREE;
atomic_set(&phone->active_calls, 0);
}
 
/** Helper function to facilitate synchronous calls.
*
* @param phone Destination kernel phone structure.
* @param request Call structure with request.
*
* @return EOK on success or EINTR if the sleep was interrupted.
*/
int ipc_call_sync(phone_t *phone, call_t *request)
/** Helper function to facilitate synchronous calls */
void ipc_call_sync(phone_t *phone, call_t *request)
{
answerbox_t sync_box;
 
ipc_answerbox_init(&sync_box, TASK);
ipc_answerbox_init(&sync_box);
 
/* We will receive data in a special box. */
/* We will receive data on special box */
request->callerbox = &sync_box;
 
ipc_call(phone, request);
if (!ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT,
SYNCH_FLAGS_INTERRUPTIBLE))
return EINTR;
return EOK;
ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
}
 
/** Answer a message which was not dispatched and is not listed in any queue.
*
* @param call Call structure to be answered.
/** Answer message that was not dispatched and is not entered in
* any queue
*/
static void _ipc_answer_free_call(call_t *call)
{
202,23 → 160,16
 
call->flags |= IPC_CALL_ANSWERED;
 
if (call->flags & IPC_CALL_FORWARDED) {
if (call->caller_phone) {
/* Demasquerade the caller phone. */
call->data.phone = call->caller_phone;
}
}
 
spinlock_lock(&callerbox->lock);
list_append(&call->link, &callerbox->answers);
spinlock_unlock(&callerbox->lock);
waitq_wakeup(&callerbox->wq, WAKEUP_FIRST);
waitq_wakeup(&callerbox->wq, 0);
}
 
/** Answer a message which is in a callee queue.
/** Answer message, that is in callee queue
*
* @param box Answerbox that is answering the message.
* @param call Modified request that is being sent back.
* @param box Answerbox that is answering the message
* @param call Modified request that is being sent back
*/
void ipc_answer(answerbox_t *box, call_t *call)
{
230,14 → 181,10
_ipc_answer_free_call(call);
}
 
/** Simulate sending back a message.
/** Simulate sending back a message
*
* Most errors are better handled by forming a normal backward
* message and sending it as a normal answer.
*
* @param phone Phone structure the call should appear to come from.
* @param call Call structure to be answered.
* @param err Return value to be used for the answer.
*/
void ipc_backsend_err(phone_t *phone, call_t *call, unative_t err)
{
247,15 → 194,10
_ipc_answer_free_call(call);
}
 
/** Unsafe unchecking version of ipc_call.
*
* @param phone Phone structure the call comes from.
* @param box Destination answerbox structure.
* @param call Call structure with request.
*/
/* Unsafe unchecking ipc_call */
static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
{
if (!(call->flags & IPC_CALL_FORWARDED)) {
if (! (call->flags & IPC_CALL_FORWARDED)) {
atomic_inc(&phone->active_calls);
call->data.phone = phone;
}
263,24 → 205,21
spinlock_lock(&box->lock);
list_append(&call->link, &box->calls);
spinlock_unlock(&box->lock);
waitq_wakeup(&box->wq, WAKEUP_FIRST);
waitq_wakeup(&box->wq, 0);
}
 
/** Send an asynchronous request using a phone to an answerbox.
/** Send a asynchronous request using phone to answerbox
*
* @param phone Phone structure the call comes from and which is
* connected to the destination answerbox.
* @param call Call structure with request.
*
* @return Return 0 on success, ENOENT on error.
* @param phone Phone connected to answerbox.
* @param call Structure representing the call.
*/
int ipc_call(phone_t *phone, call_t *call)
{
answerbox_t *box;
 
mutex_lock(&phone->lock);
spinlock_lock(&phone->lock);
if (phone->state != IPC_PHONE_CONNECTED) {
mutex_unlock(&phone->lock);
spinlock_unlock(&phone->lock);
if (call->flags & IPC_CALL_FORWARDED) {
IPC_SET_RETVAL(call->data, EFORWARD);
_ipc_answer_free_call(call);
295,19 → 234,18
box = phone->callee;
_ipc_call(phone, box, call);
mutex_unlock(&phone->lock);
spinlock_unlock(&phone->lock);
return 0;
}
 
/** Disconnect phone from answerbox.
/** Disconnect phone from answerbox
*
* This call leaves the phone in the HUNGUP state. The change to 'free' is done
* This call leaves the phone in HUNGUP state. The change to 'free' is done
* lazily later.
*
* @param phone Phone structure to be hung up.
* @param phone Phone to be hung up
*
* @return Return 0 if the phone is disconnected.
* Return -1 if the phone was already disconnected.
* @return 0 - phone disconnected, -1 - the phone was already disconnected
*/
int ipc_phone_hangup(phone_t *phone)
{
314,11 → 252,10
answerbox_t *box;
call_t *call;
mutex_lock(&phone->lock);
if (phone->state == IPC_PHONE_FREE ||
phone->state == IPC_PHONE_HUNGUP ||
phone->state == IPC_PHONE_CONNECTING) {
mutex_unlock(&phone->lock);
spinlock_lock(&phone->lock);
if (phone->state == IPC_PHONE_FREE || phone->state ==IPC_PHONE_HUNGUP \
|| phone->state == IPC_PHONE_CONNECTING) {
spinlock_unlock(&phone->lock);
return -1;
}
box = phone->callee;
328,61 → 265,51
list_remove(&phone->link);
spinlock_unlock(&box->lock);
 
call = ipc_call_alloc(0);
IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
call->flags |= IPC_CALL_DISCARD_ANSWER;
_ipc_call(phone, box, call);
if (phone->state != IPC_PHONE_SLAMMED) {
call = ipc_call_alloc(0);
IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
call->flags |= IPC_CALL_DISCARD_ANSWER;
_ipc_call(phone, box, call);
}
}
 
phone->state = IPC_PHONE_HUNGUP;
mutex_unlock(&phone->lock);
spinlock_unlock(&phone->lock);
 
return 0;
}
 
/** Forwards call from one answerbox to another one.
/** Forwards call from one answerbox to a new one
*
* @param call Call structure to be redirected.
* @param newphone Phone structure to target answerbox.
* @param oldbox Old answerbox structure.
* @param mode Flags that specify mode of the forward operation.
*
* @return Return 0 if forwarding succeeded or an error code if
* there was error.
* @param call Call to be redirected.
* @param newphone Phone to target answerbox.
* @param oldbox Old answerbox
* @return 0 on forward ok, error code, if there was error
*
* The return value serves only as an information for the forwarder,
* the original caller is notified automatically with EFORWARD.
* - the return value serves only as an information for the forwarder,
* the original caller is notified automatically with EFORWARD
*/
int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox, int mode)
int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox)
{
spinlock_lock(&oldbox->lock);
list_remove(&call->link);
spinlock_unlock(&oldbox->lock);
 
if (mode & IPC_FF_ROUTE_FROM_ME) {
if (!call->caller_phone)
call->caller_phone = call->data.phone;
call->data.phone = newphone;
}
 
return ipc_call(newphone, call);
}
 
 
/** Wait for a phone call.
/** Wait for phone call
*
* @param box Answerbox expecting the call.
* @param usec Timeout in microseconds. See documentation for
* waitq_sleep_timeout() for decription of its special
* meaning.
* @param flags Select mode of sleep operation. See documentation for
* waitq_sleep_timeout() for description of its special
* meaning.
* @return Recived call structure or NULL.
*
* To distinguish between a call and an answer, have a look at call->flags.
* @param box Answerbox expecting the call.
* @param usec Timeout in microseconds. See documentation for waitq_sleep_timeout() for
* decription of its special meaning.
* @param flags Select mode of sleep operation. See documentation for waitq_sleep_timeout()i
* for description of its special meaning.
* @return Recived message address
* - to distinguish between call and answer, look at call->flags
*/
call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags)
call_t * ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags)
{
call_t *request;
ipl_t ipl;
423,18 → 350,13
return request;
}
 
/** Answer all calls from list with EHANGUP answer.
*
* @param lst Head of the list to be cleaned up.
*/
void ipc_cleanup_call_list(link_t *lst)
/** Answer all calls from list with EHANGUP msg */
static void ipc_cleanup_call_list(link_t *lst)
{
call_t *call;
 
while (!list_empty(lst)) {
call = list_get_instance(lst->next, call_t, link);
if (call->buffer)
free(call->buffer);
list_remove(&call->link);
 
IPC_SET_RETVAL(call->data, EHANGUP);
442,104 → 364,44
}
}
 
/** Disconnects all phones connected to an answerbox.
/** Cleans up all IPC communication of the current task
*
* @param box Answerbox to disconnect phones from.
* @param notify_box If true, the answerbox will get a hangup message for
* each disconnected phone.
* Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
* have to change it as well if you want to cleanup other current then current.
*/
void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box)
void ipc_cleanup(void)
{
int i;
call_t *call;
phone_t *phone;
DEADLOCK_PROBE_INIT(p_phonelck);
ipl_t ipl;
call_t *call;
 
call = notify_box ? ipc_call_alloc(0) : NULL;
/* Disconnect all our phones ('ipc_phone_hangup') */
for (i=0;i < IPC_MAX_PHONES; i++)
ipc_phone_hangup(&TASK->phones[i]);
 
/* Disconnect all connected irqs */
ipc_irq_cleanup(&TASK->answerbox);
 
/* Disconnect all phones connected to our answerbox */
restart_phones:
ipl = interrupts_disable();
spinlock_lock(&box->lock);
while (!list_empty(&box->connected_phones)) {
phone = list_get_instance(box->connected_phones.next,
phone_t, link);
if (SYNCH_FAILED(mutex_trylock(&phone->lock))) {
spinlock_unlock(&box->lock);
interrupts_restore(ipl);
DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD);
spinlock_lock(&TASK->answerbox.lock);
while (!list_empty(&TASK->answerbox.connected_phones)) {
phone = list_get_instance(TASK->answerbox.connected_phones.next,
phone_t, link);
if (! spinlock_trylock(&phone->lock)) {
spinlock_unlock(&TASK->answerbox.lock);
goto restart_phones;
}
/* Disconnect phone */
ASSERT(phone->state == IPC_PHONE_CONNECTED);
 
phone->state = IPC_PHONE_SLAMMED;
list_remove(&phone->link);
phone->state = IPC_PHONE_SLAMMED;
 
if (notify_box) {
mutex_unlock(&phone->lock);
spinlock_unlock(&box->lock);
interrupts_restore(ipl);
 
/*
* Send one message to the answerbox for each
* phone. Used to make sure the kbox thread
* wakes up after the last phone has been
* disconnected.
*/
IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
call->flags |= IPC_CALL_DISCARD_ANSWER;
_ipc_call(phone, box, call);
 
/* Allocate another call in advance */
call = ipc_call_alloc(0);
 
/* Must start again */
goto restart_phones;
}
 
mutex_unlock(&phone->lock);
spinlock_unlock(&phone->lock);
}
 
spinlock_unlock(&box->lock);
interrupts_restore(ipl);
 
/* Free unused call */
if (call)
ipc_call_free(call);
}
 
/** Cleans up all IPC communication of the current task.
*
* Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
* have to change it as well if you want to cleanup other tasks than TASK.
*/
void ipc_cleanup(void)
{
int i;
call_t *call;
 
/* Disconnect all our phones ('ipc_phone_hangup') */
for (i = 0; i < IPC_MAX_PHONES; i++)
ipc_phone_hangup(&TASK->phones[i]);
 
/* Unsubscribe from any event notifications. */
event_cleanup_answerbox(&TASK->answerbox);
 
/* Disconnect all connected irqs */
ipc_irq_cleanup(&TASK->answerbox);
 
/* Disconnect all phones connected to our regular answerbox */
ipc_answerbox_slam_phones(&TASK->answerbox, false);
 
#ifdef CONFIG_UDEBUG
/* Clean up kbox thread and communications */
ipc_kbox_cleanup();
#endif
 
/* Answer all messages in 'calls' and 'dispatched_calls' queues */
spinlock_lock(&TASK->answerbox.lock);
ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
ipc_cleanup_call_list(&TASK->answerbox.calls);
spinlock_unlock(&TASK->answerbox.lock);
549,8 → 411,8
/* Go through all phones, until all are FREE... */
/* Locking not needed, no one else should modify
* it, when we are in cleanup */
for (i = 0; i < IPC_MAX_PHONES; i++) {
if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
for (i=0;i < IPC_MAX_PHONES; i++) {
if (TASK->phones[i].state == IPC_PHONE_HUNGUP && \
atomic_get(&TASK->phones[i].active_calls) == 0)
TASK->phones[i].state = IPC_PHONE_FREE;
569,19 → 431,11
if (i == IPC_MAX_PHONES)
break;
call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
SYNCH_FLAGS_NONE);
ASSERT((call->flags & IPC_CALL_ANSWERED) ||
(call->flags & IPC_CALL_NOTIF));
ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC));
call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
ASSERT((call->flags & IPC_CALL_ANSWERED) || (call->flags & IPC_CALL_NOTIF));
ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
/*
* Record the receipt of this call in the current task's counter
* of active calls. IPC_M_PHONE_HUNGUP calls do not contribute
* to this counter so do not record answers to them either.
*/
if (!(call->flags & IPC_CALL_DISCARD_ANSWER))
atomic_dec(&TASK->active_calls);
atomic_dec(&TASK->active_calls);
ipc_call_free(call);
}
}
590,15 → 444,11
/** Initilize IPC subsystem */
void ipc_init(void)
{
ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL,
NULL, 0);
ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL, NULL, 0);
}
 
 
/** List answerbox contents.
*
* @param taskid Task ID.
*/
/** Kconsole - list answerbox contents */
void ipc_print_task(task_id_t taskid)
{
task_t *task;
616,13 → 466,10
 
/* Print opened phones & details */
printf("PHONE:\n");
for (i = 0; i < IPC_MAX_PHONES; i++) {
if (SYNCH_FAILED(mutex_trylock(&task->phones[i].lock))) {
printf("%d: mutex busy\n", i);
continue;
}
for (i=0; i < IPC_MAX_PHONES;i++) {
spinlock_lock(&task->phones[i].lock);
if (task->phones[i].state != IPC_PHONE_FREE) {
printf("%d: ", i);
printf("%d: ",i);
switch (task->phones[i].state) {
case IPC_PHONE_CONNECTING:
printf("connecting ");
642,10 → 489,9
default:
break;
}
printf("active: %ld\n",
atomic_get(&task->phones[i].active_calls));
printf("active: %d\n", atomic_get(&task->phones[i].active_calls));
}
mutex_unlock(&task->phones[i].lock);
spinlock_unlock(&task->phones[i].lock);
}
 
 
652,45 → 498,29
/* Print answerbox - calls */
spinlock_lock(&task->answerbox.lock);
printf("ABOX - CALLS:\n");
for (tmp = task->answerbox.calls.next; tmp != &task->answerbox.calls;
tmp = tmp->next) {
for (tmp=task->answerbox.calls.next; tmp != &task->answerbox.calls;tmp = tmp->next) {
call = list_get_instance(tmp, call_t, link);
printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun
" A1:%" PRIun " A2:%" PRIun " A3:%" PRIun
" A4:%" PRIun " A5:%" PRIun " Flags:%x\n", call,
call->sender->taskid,
IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
call->flags);
printf("Callid: %p Srctask:%lld M:%d A1:%d A2:%d A3:%d Flags:%x\n",call,
call->sender->taskid, IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), call->flags);
}
/* Print answerbox - calls */
printf("ABOX - DISPATCHED CALLS:\n");
for (tmp = task->answerbox.dispatched_calls.next;
tmp != &task->answerbox.dispatched_calls;
tmp = tmp->next) {
for (tmp=task->answerbox.dispatched_calls.next;
tmp != &task->answerbox.dispatched_calls;
tmp = tmp->next) {
call = list_get_instance(tmp, call_t, link);
printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun
" A1:%" PRIun " A2:%" PRIun " A3:%" PRIun
" A4:%" PRIun " A5:%" PRIun " Flags:%x\n", call,
call->sender->taskid,
IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
call->flags);
printf("Callid: %p Srctask:%lld M:%d A1:%d A2:%d A3:%d Flags:%x\n",call,
call->sender->taskid, IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), call->flags);
}
/* Print answerbox - calls */
printf("ABOX - ANSWERS:\n");
for (tmp = task->answerbox.answers.next;
tmp != &task->answerbox.answers;
tmp = tmp->next) {
for (tmp=task->answerbox.answers.next; tmp != &task->answerbox.answers; tmp = tmp->next) {
call = list_get_instance(tmp, call_t, link);
printf("Callid:%p M:%" PRIun " A1:%" PRIun " A2:%" PRIun
" A3:%" PRIun " A4:%" PRIun " A5:%" PRIun " Flags:%x\n",
call, IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
call->flags);
printf("Callid:%p M:%d A1:%d A2:%d A3:%d Flags:%x\n",call,
IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data), call->flags);
}
 
spinlock_unlock(&task->answerbox.lock);
/branches/arm/kernel/generic/src/debug/symtab.c
32,222 → 32,168
 
/**
* @file
* @brief Kernel symbol resolver.
* @brief Kernel symbol resolver.
*/
 
#include <symtab.h>
#include <byteorder.h>
#include <string.h>
#include <arch/byteorder.h>
#include <func.h>
#include <print.h>
#include <arch/types.h>
#include <typedefs.h>
#include <errno.h>
 
/** Get name of a symbol that seems most likely to correspond to address.
/** Return entry that seems most likely to correspond to argument.
*
* Return entry that seems most likely to correspond
* to address passed in the argument.
*
* @param addr Address.
* @param name Place to store pointer to the symbol name.
*
* @return Zero on success or negative error code, ENOENT if not found,
* ENOTSUP if symbol table not available.
*
* @return Pointer to respective symbol string on success, NULL otherwise.
*/
int symtab_name_lookup(unative_t addr, char **name)
char * get_symtab_entry(unative_t addr)
{
#ifdef CONFIG_SYMTAB
size_t i;
for (i = 1; symbol_table[i].address_le; i++) {
count_t i;
 
for (i=1;symbol_table[i].address_le;++i) {
if (addr < uint64_t_le2host(symbol_table[i].address_le))
break;
}
if (addr >= uint64_t_le2host(symbol_table[i - 1].address_le)) {
*name = symbol_table[i - 1].symbol_name;
return EOK;
}
*name = NULL;
return ENOENT;
#else
*name = NULL;
return ENOTSUP;
#endif
if (addr >= uint64_t_le2host(symbol_table[i-1].address_le))
return symbol_table[i-1].symbol_name;
return NULL;
}
 
/** Lookup symbol by address and format for display.
/** Find symbols that match the parameter forward and print them.
*
* Returns name of closest corresponding symbol, "Not found" if none exists
* or "N/A" if no symbol information is available.
*
* @param addr Address.
* @param name Place to store pointer to the symbol name.
*
* @return Pointer to a human-readable string.
*
* @param name - search string
* @param startpos - starting position, changes to found position
* @return Pointer to the part of string that should be completed or NULL
*/
char *symtab_fmt_name_lookup(unative_t addr)
static char * symtab_search_one(const char *name, int *startpos)
{
char *name;
int rc = symtab_name_lookup(addr, &name);
switch (rc) {
case EOK:
return name;
case ENOENT:
return "Not found";
default:
return "N/A";
}
}
int namelen = strlen(name);
char *curname;
int i,j;
int colonoffset = -1;
 
#ifdef CONFIG_SYMTAB
for (i=0;name[i];i++)
if (name[i] == ':') {
colonoffset = i;
break;
}
 
/** Find symbols that match the parameter forward and print them.
*
* @param name Search string
* @param startpos Starting position, changes to found position
*
* @return Pointer to the part of string that should be completed or NULL.
*
*/
static const char *symtab_search_one(const char *name, size_t *startpos)
{
size_t namelen = str_length(name);
size_t pos;
for (pos = *startpos; symbol_table[pos].address_le; pos++) {
const char *curname = symbol_table[pos].symbol_name;
/* Find a ':' in curname */
const char *colon = str_chr(curname, ':');
if (colon == NULL)
for (i=*startpos;symbol_table[i].address_le;++i) {
/* Find a ':' in name */
curname = symbol_table[i].symbol_name;
for (j=0; curname[j] && curname[j] != ':'; j++)
;
if (!curname[j])
continue;
if (str_length(curname) < namelen)
j -= colonoffset;
curname += j;
if (strlen(curname) < namelen)
continue;
if (str_lcmp(name, curname, namelen) == 0) {
*startpos = pos;
return (curname + str_lsize(curname, namelen));
if (strncmp(curname, name, namelen) == 0) {
*startpos = i;
return curname+namelen;
}
}
return NULL;
}
 
#endif
 
/** Return address that corresponds to the entry.
/** Return address that corresponds to the entry
*
* Search symbol table, and if there is one match, return it
*
* @param name Name of the symbol
* @param addr Place to store symbol address
*
* @return Zero on success, ENOENT - not found, EOVERFLOW - duplicate
* symbol, ENOTSUP - no symbol information available.
*
* @return 0 - Not found, -1 - Duplicate symbol, other - address of symbol
*/
int symtab_addr_lookup(const char *name, uintptr_t *addr)
uintptr_t get_symbol_addr(const char *name)
{
#ifdef CONFIG_SYMTAB
size_t found = 0;
size_t pos = 0;
const char *hint;
while ((hint = symtab_search_one(name, &pos))) {
if (str_length(hint) == 0) {
*addr = uint64_t_le2host(symbol_table[pos].address_le);
count_t found = 0;
uintptr_t addr = NULL;
char *hint;
int i;
 
i = 0;
while ((hint=symtab_search_one(name, &i))) {
if (!strlen(hint)) {
addr = uint64_t_le2host(symbol_table[i].address_le);
found++;
}
pos++;
i++;
}
if (found > 1)
return EOVERFLOW;
if (found < 1)
return ENOENT;
return EOK;
#else
return ENOTSUP;
#endif
return ((uintptr_t) -1);
return addr;
}
 
/** Find symbols that match parameter and print them */
/** Find symbols that match parameter and prints them */
void symtab_print_search(const char *name)
{
#ifdef CONFIG_SYMTAB
size_t pos = 0;
while (symtab_search_one(name, &pos)) {
uintptr_t addr = uint64_t_le2host(symbol_table[pos].address_le);
char *realname = symbol_table[pos].symbol_name;
printf("%p: %s\n", addr, realname);
pos++;
int i;
uintptr_t addr;
char *realname;
 
 
i = 0;
while (symtab_search_one(name, &i)) {
addr = uint64_t_le2host(symbol_table[i].address_le);
realname = symbol_table[i].symbol_name;
printf("%.*p: %s\n", sizeof(uintptr_t) * 2, addr, realname);
i++;
}
#else
printf("No symbol information available.\n");
#endif
}
 
/** Symtab completion
*
* @param input Search string, completes to symbol name
* @param size Input buffer size
*
* @return 0 - nothing found, 1 - success, >1 print duplicates
*
* @param input - Search string, completes to symbol name
* @returns - 0 - nothing found, 1 - success, >1 print duplicates
*/
int symtab_compl(char *input, size_t size)
int symtab_compl(char *input)
{
#ifdef CONFIG_SYMTAB
const char *name = input;
/* Allow completion of pointers */
if ((name[0] == '*') || (name[0] == '&'))
char output[MAX_SYMBOL_NAME+1];
int startpos = 0;
char *foundtxt;
int found = 0;
int i;
char *name = input;
 
/* Allow completion of pointers */
if (name[0] == '*' || name[0] == '&')
name++;
/* Do not print all symbols */
if (str_length(name) == 0)
 
/* Do not print everything */
if (!strlen(name))
return 0;
size_t found = 0;
size_t pos = 0;
const char *hint;
char output[MAX_SYMBOL_NAME];
output[0] = 0;
while ((hint = symtab_search_one(name, &pos))) {
if ((found == 0) || (str_length(output) > str_length(hint)))
str_cpy(output, MAX_SYMBOL_NAME, hint);
pos++;
 
output[0] = '\0';
 
while ((foundtxt = symtab_search_one(name, &startpos))) {
startpos++;
if (!found)
strncpy(output, foundtxt, strlen(foundtxt)+1);
else {
for (i=0; output[i] && foundtxt[i] && output[i]==foundtxt[i]; i++)
;
output[i] = '\0';
}
found++;
}
if ((found > 1) && (str_length(output) != 0)) {
if (!found)
return 0;
 
if (found > 1 && !strlen(output)) {
printf("\n");
pos = 0;
while ((hint = symtab_search_one(name, &pos))) {
printf("%s\n", symbol_table[pos].symbol_name);
pos++;
startpos = 0;
while ((foundtxt = symtab_search_one(name, &startpos))) {
printf("%s\n", symbol_table[startpos].symbol_name);
startpos++;
}
}
if (found > 0)
str_cpy(input, size, output);
strncpy(input, output, MAX_SYMBOL_NAME);
return found;
#else
return 0;
#endif
}
 
/** @}
/branches/arm/kernel/generic/src/time/timeout.c
32,7 → 32,7
 
/**
* @file
* @brief Timeout management functions.
* @brief Timeout management functions.
*/
 
#include <time/timeout.h>
45,6 → 45,7
#include <arch/asm.h>
#include <arch.h>
 
 
/** Initialize timeouts
*
* Initialize kernel timeouts.
61,7 → 62,7
*
* Initialize all members except the lock.
*
* @param t Timeout to be initialized.
* @param t Timeout to be initialized.
*
*/
void timeout_reinitialize(timeout_t *t)
78,7 → 79,7
*
* Initialize all members including the lock.
*
* @param t Timeout to be initialized.
* @param t Timeout to be initialized.
*
*/
void timeout_initialize(timeout_t *t)
94,14 → 95,14
* to timeout list and make it execute in
* time microseconds (or slightly more).
*
* @param t Timeout structure.
* @param time Number of usec in the future to execute the handler.
* @param f Timeout handler function.
* @param arg Timeout handler argument.
* @param t Timeout structure.
* @param time Number of usec in the future to execute
* the handler.
* @param f Timeout handler function.
* @param arg Timeout handler argument.
*
*/
void
timeout_register(timeout_t *t, uint64_t time, timeout_handler_t f, void *arg)
void timeout_register(timeout_t *t, uint64_t time, timeout_handler_t f, void *arg)
{
timeout_t *hlp = NULL;
link_t *l, *m;
113,7 → 114,7
spinlock_lock(&t->lock);
 
if (t->cpu)
panic("Unexpected: t->cpu != 0.");
panic("t->cpu != 0");
 
t->cpu = CPU;
t->ticks = us2ticks(time);
165,9 → 166,9
*
* Remove timeout from timeout list.
*
* @param t Timeout to unregister.
* @param t Timeout to unregister.
*
* @return True on success, false on failure.
* @return true on success, false on failure.
*/
bool timeout_unregister(timeout_t *t)
{
174,7 → 175,6
timeout_t *hlp;
link_t *l;
ipl_t ipl;
DEADLOCK_PROBE_INIT(p_tolock);
 
grab_locks:
ipl = interrupts_disable();
186,8 → 186,7
}
if (!spinlock_trylock(&t->cpu->timeoutlock)) {
spinlock_unlock(&t->lock);
interrupts_restore(ipl);
DEADLOCK_PROBE(p_tolock, DEADLOCK_THRESHOLD);
interrupts_restore(ipl);
goto grab_locks;
}
/branches/arm/kernel/generic/src/time/clock.c
41,6 → 41,7
#include <time/clock.h>
#include <time/timeout.h>
#include <arch/types.h>
#include <config.h>
#include <synch/spinlock.h>
#include <synch/waitq.h>
56,12 → 57,16
#include <mm/frame.h>
#include <ddi/ddi.h>
 
/* Pointer to variable with uptime */
uptime_t *uptime;
 
/** Physical memory area of the real time clock */
/** Physical memory area of the real time clock. */
static parea_t clock_parea;
 
/* Pointers to public variables with time */
struct ptime {
unative_t seconds1;
unative_t useconds;
unative_t seconds2;
};
struct ptime *public_time;
/* Variable holding fragment of second, so that we would update
* seconds correctly
*/
79,16 → 84,19
 
faddr = frame_alloc(ONE_FRAME, FRAME_ATOMIC);
if (!faddr)
panic("Cannot allocate page for clock.");
panic("Cannot allocate page for clock");
uptime = (uptime_t *) PA2KA(faddr);
uptime->seconds1 = 0;
uptime->seconds2 = 0;
uptime->useconds = 0;
public_time = (struct ptime *) PA2KA(faddr);
 
/* TODO: We would need some arch dependent settings here */
public_time->seconds1 = 0;
public_time->seconds2 = 0;
public_time->useconds = 0;
 
clock_parea.pbase = (uintptr_t) faddr;
clock_parea.vbase = (uintptr_t) public_time;
clock_parea.frames = 1;
clock_parea.cacheable = true;
ddi_parea_register(&clock_parea);
 
/*
96,6 → 104,8
* physmem_map() the clock_parea.
*/
sysinfo_set_item_val("clock.cacheable", NULL, (unative_t) true);
sysinfo_set_item_val("clock.fcolor", NULL, (unative_t)
PAGE_COLOR(clock_parea.vbase));
sysinfo_set_item_val("clock.faddr", NULL, (unative_t) faddr);
}
 
108,16 → 118,16
static void clock_update_counters(void)
{
if (CPU->id == 0) {
secfrag += 1000000 / HZ;
secfrag += 1000000/HZ;
if (secfrag >= 1000000) {
secfrag -= 1000000;
uptime->seconds1++;
public_time->seconds1++;
write_barrier();
uptime->useconds = secfrag;
public_time->useconds = secfrag;
write_barrier();
uptime->seconds2 = uptime->seconds1;
public_time->seconds2 = public_time->seconds1;
} else
uptime->useconds += 1000000 / HZ;
public_time->useconds += 1000000/HZ;
}
}
 
134,8 → 144,8
timeout_t *h;
timeout_handler_t f;
void *arg;
size_t missed_clock_ticks = CPU->missed_clock_ticks;
unsigned int i;
count_t missed_clock_ticks = CPU->missed_clock_ticks;
int i;
 
/*
* To avoid lock ordering problems,
187,19 → 197,7
spinlock_unlock(&THREAD->lock);
if (!ticks && !PREEMPTION_DISABLED) {
#ifdef CONFIG_UDEBUG
istate_t *istate;
#endif
scheduler();
#ifdef CONFIG_UDEBUG
/*
* Give udebug chance to stop the thread
* before it begins executing userspace code.
*/
istate = THREAD->udebug.uspace_state;
if (istate && istate_from_uspace(istate))
udebug_before_thread_runs();
#endif
}
}
 
/branches/arm/kernel/generic/src/sysinfo/sysinfo.c
163,8 → 163,7
i = 0;
}
}
 
panic("Not reached.");
panic("Not reached\n");
return NULL;
}
 
178,7 → 177,7
sysinfo_item_t *item = sysinfo_create_path(name, root);
if (item != NULL) { /* If in subsystem, unable to create or return so unable to set */
item->val.val = val;
item->val.val=val;
item->val_type = SYSINFO_VAL_VAL;
}
}
193,7 → 192,7
sysinfo_item_t *item = sysinfo_create_path(name, root);
if (item != NULL) { /* If in subsystem, unable to create or return so unable to set */
item->val.fn = fn;
item->val.fn=fn;
item->val_type = SYSINFO_VAL_FUNCTION;
}
}
245,7 → 244,7
break;
}
printf("%s %s val:%" PRIun "(%" PRIxn ") sub:%s\n", root->name, vtype, val,
printf("%s %s val:%d(%x) sub:%s\n", root->name, vtype, val,
val, (root->subinfo_type == SYSINFO_SUBINFO_NONE) ?
"NON" : ((root->subinfo_type == SYSINFO_SUBINFO_TABLE) ?
"TAB" : "FUN"));
282,15 → 281,10
return ret;
}
 
#define SYSINFO_MAX_LEN 1024
 
unative_t sys_sysinfo_valid(unative_t ptr, unative_t len)
{
char *str;
sysinfo_rettype_t ret = {0, 0};
 
if (len > SYSINFO_MAX_LEN)
return ret.valid;
str = malloc(len + 1, 0);
ASSERT(str);
305,9 → 299,6
{
char *str;
sysinfo_rettype_t ret = {0, 0};
if (len > SYSINFO_MAX_LEN)
return ret.val;
str = malloc(len + 1, 0);
ASSERT(str);
/branches/arm/kernel/generic/src/interrupt/interrupt.c
42,6 → 42,7
#include <debug.h>
#include <console/kconsole.h>
#include <console/console.h>
#include <console/chardev.h>
#include <console/cmd.h>
#include <panic.h>
#include <print.h>
67,13 → 68,13
iroutine old;
spinlock_lock(&exctbl_lock);
 
old = exc_table[n].f;
exc_table[n].f = f;
exc_table[n].name = name;
spinlock_unlock(&exctbl_lock);
 
spinlock_unlock(&exctbl_lock);
 
return old;
}
 
85,17 → 86,8
void exc_dispatch(int n, istate_t *istate)
{
ASSERT(n < IVT_ITEMS);
 
#ifdef CONFIG_UDEBUG
if (THREAD) THREAD->udebug.uspace_state = istate;
#endif
exc_table[n].f(n + IVT_FIRST, istate);
 
#ifdef CONFIG_UDEBUG
if (THREAD) THREAD->udebug.uspace_state = NULL;
#endif
 
/* This is a safe place to exit exiting thread */
if (THREAD && THREAD->interrupted && istate_from_uspace(istate))
thread_exit();
108,80 → 100,53
panic("Unhandled exception %d.", n);
}
 
#ifdef CONFIG_KCONSOLE
 
/** kconsole cmd - print all exceptions */
static int cmd_exc_print(cmd_arg_t *argv)
static int exc_print_cmd(cmd_arg_t *argv)
{
#if (IVT_ITEMS > 0)
unsigned int i;
int i;
char *symbol;
 
spinlock_lock(&exctbl_lock);
 
#ifdef __32_BITS__
printf("Exc Description Handler Symbol\n");
printf("--- -------------------- ---------- --------\n");
#endif
 
#ifdef __64_BITS__
printf("Exc Description Handler Symbol\n");
printf("--- -------------------- ------------------ --------\n");
#endif
for (i = 0; i < IVT_ITEMS; i++) {
symbol = symtab_fmt_name_lookup((unative_t) exc_table[i].f);
 
#ifdef __32_BITS__
printf("%-3u %-20s %10p %s\n", i + IVT_FIRST, exc_table[i].name,
exc_table[i].f, symbol);
#endif
 
#ifdef __64_BITS__
printf("%-3u %-20s %18p %s\n", i + IVT_FIRST, exc_table[i].name,
exc_table[i].f, symbol);
#endif
if (((i + 1) % 20) == 0) {
printf(" -- Press any key to continue -- ");
printf("Exc Description Handler\n");
for (i=0; i < IVT_ITEMS; i++) {
symbol = get_symtab_entry((unative_t)exc_table[i].f);
if (!symbol)
symbol = "not found";
printf("%d %s %.*p(%s)\n", i + IVT_FIRST, exc_table[i].name,
sizeof(uintptr_t) * 2, exc_table[i].f,symbol);
if (!((i+1) % 20)) {
printf("Press any key to continue.");
spinlock_unlock(&exctbl_lock);
indev_pop_character(stdin);
getc(stdin);
spinlock_lock(&exctbl_lock);
printf("\n");
}
}
spinlock_unlock(&exctbl_lock);
#endif
return 1;
}
 
 
static cmd_info_t exc_info = {
.name = "exc",
.description = "Print exception table.",
.func = cmd_exc_print,
.func = exc_print_cmd,
.help = NULL,
.argc = 0,
.argv = NULL
};
 
#endif
 
/** Initialize generic exception handling support */
void exc_init(void)
{
int i;
 
for (i = 0; i < IVT_ITEMS; i++)
for (i=0;i < IVT_ITEMS; i++)
exc_register(i, "undef", (iroutine) exc_undef);
 
#ifdef CONFIG_KCONSOLE
cmd_initialize(&exc_info);
if (!cmd_register(&exc_info))
printf("Cannot register command %s\n", exc_info.name);
#endif
panic("could not register command %s\n", exc_info.name);
}
 
/** @}