/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); |
} |
/** @} |