/branches/dd/kernel/generic/include/udebug/udebug_ipc.h |
---|
File deleted |
/branches/dd/kernel/generic/include/udebug/udebug.h |
---|
File deleted |
/branches/dd/kernel/generic/include/udebug/udebug_ops.h |
---|
File deleted |
/branches/dd/kernel/generic/include/string.h |
---|
File deleted |
/branches/dd/kernel/generic/include/ipc/kbox.h |
---|
File deleted |
/branches/dd/kernel/generic/include/ipc/ipc.h |
---|
195,12 → 195,6 |
*/ |
#define IPC_M_DATA_READ 7 |
/** 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 8 |
/* Well-known methods */ |
#define IPC_M_LAST_SYSTEM 511 |
#define IPC_M_PING 512 |
287,13 → 281,6 |
/** 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); |
300,7 → 287,7 |
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_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 *); |
313,8 → 300,6 |
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 answerbox_t *ipc_phone_0; |
/branches/dd/kernel/generic/include/ipc/sysipc.h |
---|
53,13 → 53,10 |
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 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/dd/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,21 → 43,16 |
#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_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) \ |
69,8 → 64,8 |
#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); |
extern void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, |
unative_t a3, unative_t a4, unative_t a5); |
#endif |
/branches/dd/kernel/generic/include/proc/program.h |
---|
File deleted |
/branches/dd/kernel/generic/include/proc/task.h |
---|
52,11 → 52,7 |
#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. */ |
70,8 → 66,8 |
* threads. |
*/ |
SPINLOCK_DECLARE(lock); |
char name[TASK_NAME_BUFLEN]; |
char *name; |
/** List of threads contained in this task. */ |
link_t th_head; |
/** Address space. */ |
97,15 → 93,7 |
* certain extent. |
*/ |
atomic_t active_calls; |
#ifdef CONFIG_UDEBUG |
/** Debugging stuff. */ |
udebug_task_t udebug; |
/** Kernel answerbox. */ |
kbox_t kb; |
#endif |
/** Architecture specific task data. */ |
task_arch_t arch; |
128,6 → 116,7 |
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); |
144,7 → 133,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/dd/kernel/generic/include/proc/thread.h |
---|
46,7 → 46,6 |
#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 |
204,12 → 203,6 |
/** Thread's kernel stack. */ |
uint8_t *kstack; |
#ifdef CONFIG_UDEBUG |
/** Debugging stuff */ |
udebug_thread_t udebug; |
#endif |
} thread_t; |
/** Thread list lock. |
259,8 → 252,7 |
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_create(uspace_arg_t *uspace_uarg, char *uspace_name, 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); |
/branches/dd/kernel/generic/include/byteorder.h |
---|
51,14 → 51,6 |
#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) |
69,14 → 61,6 |
#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) |
/branches/dd/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 |
339,10 → 338,6 |
extern char *elf_error(unsigned 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/dd/kernel/generic/include/lib/rd.h |
---|
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/dd/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/dd/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/dd/kernel/generic/include/mm/slab.h |
---|
53,13 → 53,12 |
#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) (((unsigned int) 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 */ |
100,7 → 99,7 |
int flags; |
/* Computed values */ |
uint8_t order; /**< Order of frames to be allocated */ |
uint8_t order; /**< Order of frames to be allocated */ |
unsigned int objects; /**< Number of objects that fit in */ |
/* Statistics */ |
122,13 → 121,14 |
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 count_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,9 → 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/dd/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,47 |
/** 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; |
/** |
* Number of processors on wich is this address space active. |
* Protected by asidlock. |
*/ |
count_t cpu_refcount; |
/** |
* Address space identifier. |
* Constant on architectures that do not support ASIDs. |
* Protected by asidlock. |
*/ |
asid_t asid; |
/** Number of references (i.e tasks that reference this as). */ |
atomic_t refcount; |
mutex_t lock; |
/** B+tree of address space areas. */ |
btree_t as_area_btree; |
/** 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 |
123,6 → 168,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 |
203,7 → 249,10 |
extern as_t *AS_KERNEL; |
#ifndef __OBJC__ |
extern as_operations_t *as_operations; |
#endif |
extern link_t inactive_as_with_asid_head; |
extern void as_init(void); |
220,7 → 269,6 |
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); |
251,19 → 299,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 unsigned 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/dd/kernel/generic/include/mm/frame.h |
---|
38,82 → 38,35 |
#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 |
#define FOUR_FRAMES 2 |
#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 { |
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 { |
pfn_t base; /**< Frame_no of the first frame |
in the frames array */ |
count_t count; /**< Size of zone */ |
count_t free_count; /**< Number of free frame_t |
structures */ |
count_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); |
count_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); |
136,37 → 89,31 |
return (size_t) (frames << FRAME_WIDTH); |
} |
static inline bool zone_flags_available(zone_flags_t flags) |
{ |
return ((flags & (ZONE_RESERVED | ZONE_FIRMWARE)) == 0); |
} |
#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) |
#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) |
#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, count_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 count_t find_zone(pfn_t frame, count_t count, count_t hint); |
extern count_t zone_create(pfn_t, count_t, pfn_t, zone_flags_t); |
extern void *frame_get_parent(pfn_t, count_t); |
extern void frame_set_parent(pfn_t, void *, count_t); |
extern void frame_mark_unavailable(pfn_t, count_t); |
extern uintptr_t zone_conf_size(count_t); |
extern bool zone_merge(count_t, count_t); |
extern int zone_create(pfn_t start, count_t count, pfn_t confframe, int flags); |
extern void *frame_get_parent(pfn_t frame, unsigned int hint); |
extern void frame_set_parent(pfn_t frame, void *data, unsigned int hint); |
extern void frame_mark_unavailable(pfn_t start, count_t count); |
extern uintptr_t zone_conf_size(count_t count); |
extern void zone_merge(unsigned int z1, unsigned int z2); |
extern void zone_merge_all(void); |
extern uint64_t zone_total_size(void); |
174,7 → 121,7 |
* Console functions |
*/ |
extern void zone_print_list(void); |
extern void zone_print_one(count_t); |
extern void zone_print_one(unsigned int znum); |
#endif |
/branches/dd/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/dd/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/dd/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,16 → 38,15 |
#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_MEMORY_SIZE (8 * 1024 * 1024) |
#define CONFIG_TASK_NAME_BUFLEN 32 |
#define CONFIG_INIT_TASKS 32 |
typedef struct { |
uintptr_t addr; |
size_t size; |
char name[CONFIG_TASK_NAME_BUFLEN]; |
} init_task_t; |
typedef struct { |
66,14 → 65,14 |
} ballocs_t; |
typedef struct { |
count_t cpu_count; /**< Number of processors detected. */ |
volatile count_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 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/dd/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 |
37,25 → 37,22 |
#include <arch/types.h> |
#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 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 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))) |
/** Return true if the intervals overlap. |
/** 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) |
62,35 → 59,19 |
{ |
uintptr_t e1 = s1 + sz1; |
uintptr_t e2 = s2 + sz2; |
return ((s1 < e2) && (s2 < e1)); |
return (s1 < e2) && (s2 < e1); |
} |
/* 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 SIZE2KB(size) (size >> 10) |
#define SIZE2MB(size) (size >> 20) |
#define KB2SIZE(kb) ((kb) << 10) |
#define MB2SIZE(mb) ((mb) << 20) |
#define STRING(arg) STRING_ARG(arg) |
#define STRING_ARG(arg) #arg |
#define STRING(arg) STRING_ARG(arg) |
#define STRING_ARG(arg) #arg |
/** 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/dd/kernel/generic/include/errno.h |
---|
48,18 → 48,14 |
* 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 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 */ |
#define EOVERFLOW -15 /* The result does not fit its size. */ |
#endif |
/branches/dd/kernel/generic/include/panic.h |
---|
36,15 → 36,15 |
#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, __func__, \ |
__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/dd/kernel/generic/include/syscall/syscall.h |
---|
36,26 → 36,17 |
#define KERN_SYSCALL_H_ |
typedef enum { |
SYS_KLOG = 0, |
SYS_IO = 0, |
SYS_TLS_SET = 1, /* Hardcoded in AMD64, IA32 uspace - fibril.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_ASYNC_FAST, |
63,25 → 54,18 |
SYS_IPC_ANSWER_FAST, |
SYS_IPC_ANSWER_SLOW, |
SYS_IPC_FORWARD_FAST, |
SYS_IPC_FORWARD_SLOW, |
SYS_IPC_WAIT, |
SYS_IPC_HANGUP, |
SYS_IPC_REGISTER_IRQ, |
SYS_IPC_UNREGISTER_IRQ, |
SYS_CAP_GRANT, |
SYS_CAP_REVOKE, |
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; |
/branches/dd/kernel/generic/include/adt/avl.h |
---|
36,7 → 36,6 |
#define KERN_AVLTREE_H_ |
#include <arch/types.h> |
#include <typedefs.h> |
/** |
* Macro for getting a pointer to the structure which contains the avltree |
/branches/dd/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 { |
/branches/dd/kernel/generic/include/adt/bitmap.h |
---|
49,14 → 49,6 |
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,index_t bit) |
{ |
if(bit >= bitmap->bits) |
return 0; |
return !! ((bitmap->map)[bit/8] & (1 << (bit & 7))); |
} |
#endif |
/** @} |
/branches/dd/kernel/generic/include/synch/smc.h |
---|
File deleted |
/branches/dd/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> |
111,8 → 110,8 |
#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", \ |
printf("Deadlock probe %s: exceeded threshold %d\n", \ |
"cpu%d: function=%s, line=%d\n", \ |
#pname, (value), CPU->id, __func__, __LINE__); \ |
} |
#else |
/branches/dd/kernel/generic/include/synch/mutex.h |
---|
39,26 → 39,20 |
#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) \ |
#define mutex_lock(mtx) \ |
_mutex_lock_timeout((mtx), SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE) |
#define mutex_trylock(mtx) \ |
#define mutex_trylock(mtx) \ |
_mutex_lock_timeout((mtx), SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NON_BLOCKING) |
#define mutex_lock_timeout(mtx, usec) \ |
#define mutex_lock_timeout(mtx, usec) \ |
_mutex_lock_timeout((mtx), (usec), SYNCH_FLAGS_NON_BLOCKING) |
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/dd/kernel/generic/include/interrupt.h |
---|
40,16 → 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__); \ |
klog_printf("Task %llu 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/dd/kernel/generic/include/arch.h |
---|
63,11 → 63,12 |
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); |
78,7 → 79,6 |
extern void reboot(void); |
extern void arch_reboot(void); |
extern void *arch_construct_function(fncptr_t *fptr, void *addr, void *caller); |
#endif |
/branches/dd/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,8 → 95,6 |
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. */ |
144,29 → 138,22 |
/** 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(count_t, count_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/dd/kernel/generic/include/ddi/device.h |
---|
35,9 → 35,6 |
#ifndef KERN_DEVICE_H_ |
#define KERN_DEVICE_H_ |
#include <arch/types.h> |
#include <typedefs.h> |
extern devno_t device_assign_devno(void); |
#endif |
/branches/dd/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/dd/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/dd/kernel/generic/include/console/chardev.h |
---|
50,7 → 50,7 |
/** Resume pushing characters. */ |
void (* resume)(struct chardev *); |
/** Write character to stream. */ |
void (* write)(struct chardev *, char c, bool silent); |
void (* write)(struct chardev *, char c); |
/** Read character directly from device, assume interrupts disabled. */ |
char (* read)(struct chardev *); |
} chardev_operations_t; |
/branches/dd/kernel/generic/include/console/kconsole.h |
---|
37,7 → 37,6 |
#include <adt/list.h> |
#include <synch/spinlock.h> |
#include <ipc/irq.h> |
#define MAX_CMDLINE 256 |
#define KCONSOLE_HISTORY 10 |
84,16 → 83,11 |
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 void kconsole(char *prompt, char *msg, bool kcon); |
extern void kconsole_thread(void *data); |
extern void kconsole(void *prompt); |
extern int cmd_register(cmd_info_t *cmd); |
/branches/dd/kernel/generic/include/console/console.h |
---|
41,21 → 41,11 |
extern chardev_t *stdin; |
extern chardev_t *stdout; |
extern bool silent; |
extern void console_init(void); |
extern void klog_init(void); |
extern void klog_update(void); |
extern uint8_t getc(chardev_t *chardev); |
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 grab_console(void); |
extern void release_console(void); |
extern void arch_grab_console(void); |
extern void arch_release_console(void); |
/branches/dd/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/dd/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/dd/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/dd/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/dd/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/dd/kernel/generic/include/typedefs.h |
---|
35,26 → 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 volatile uint8_t ioport8_t; |
typedef volatile uint16_t ioport16_t; |
typedef volatile uint32_t ioport32_t; |
#endif |
/** @} |
/branches/dd/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/dd/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/dd/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/dd/kernel/generic/src/udebug/udebug.c |
---|
File deleted |
/branches/dd/kernel/generic/src/udebug/udebug_ops.c |
---|
File deleted |
/branches/dd/kernel/generic/src/udebug/udebug_ipc.c |
---|
File deleted |
/branches/dd/kernel/generic/src/ipc/kbox.c |
---|
File deleted |
/branches/dd/kernel/generic/src/ipc/sysipc.c |
---|
42,9 → 42,8 |
#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> |
271,12 → 270,12 |
/* The recipient agreed to receive data. */ |
int rc; |
uintptr_t dst; |
size_t size; |
size_t max_size; |
uintptr_t size; |
uintptr_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); |
dst = IPC_GET_ARG1(answer->data); |
size = IPC_GET_ARG2(answer->data); |
max_size = IPC_GET_ARG2(*olddata); |
if (size <= max_size) { |
rc = copy_to_uspace((void *) dst, |
296,11 → 295,10 |
/** 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. |
*/ |
static int request_preprocess(call_t *call, phone_t *phone) |
static int request_preprocess(call_t *call) |
{ |
int newphid; |
size_t size; |
342,10 → 340,6 |
return rc; |
} |
break; |
#ifdef CONFIG_UDEBUG |
case IPC_M_DEBUG_ALL: |
return udebug_request_preprocess(call, phone); |
#endif |
default: |
break; |
} |
375,7 → 369,6 |
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); |
406,13 → 399,7 |
return -1; |
} |
IPC_SET_ARG5(call->data, phoneid); |
} |
switch (IPC_GET_METHOD(call->data)) { |
case IPC_M_DEBUG_ALL: |
return -1; |
default: |
break; |
} |
} |
return 0; |
} |
439,7 → 426,7 |
phone_t *phone; |
int res; |
int rc; |
GET_CHECK_PHONE(phone, phoneid, return ENOENT); |
ipc_call_static_init(&call); |
454,18 → 441,9 |
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 { |
IPC_SET_RETVAL(call.data, res); |
} |
501,16 → 479,8 |
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); |
576,7 → 546,7 |
*/ |
IPC_SET_ARG5(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); |
610,7 → 580,7 |
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); |
618,8 → 588,7 |
return (unative_t) call; |
} |
/** Forward a received call to another destination - common code for both the |
* fast and the slow version. |
/** Forward a received call to another destination. |
* |
* @param callid Hash of the call to forward. |
* @param phoneid Phone handle to use for forwarding. |
626,21 → 595,23 |
* @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. |
* |
* @return Return 0 on succes, otherwise return an error code. |
* |
* Warning: Make sure that ARG5 is not rewritten for certain system IPC |
* 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 argument is not set and |
* these values are ignored. |
* |
* Warning: When implementing support for changing additional payload |
* arguments, make sure that ARG5 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, unative_t arg2, int mode) |
{ |
call_t *call; |
phone_t *phone; |
648,7 → 619,7 |
call = get_call(callid); |
if (!call) |
return ENOENT; |
call->flags |= IPC_CALL_FORWARDED; |
GET_CHECK_PHONE(phone, phoneid, { |
655,7 → 626,7 |
IPC_SET_RETVAL(call->data, EFORWARD); |
ipc_answer(&TASK->answerbox, call); |
return ENOENT; |
}); |
}); |
if (!method_is_forwardable(IPC_GET_METHOD(call->data))) { |
IPC_SET_RETVAL(call->data, EFORWARD); |
665,8 → 636,8 |
/* |
* 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. |
* forward, allow changing ARG1, ARG2 and ARG3 by means of method, |
* arg1 and arg2. |
* If the method is immutable, don't change anything. |
*/ |
if (!method_is_immutable(IPC_GET_METHOD(call->data))) { |
677,22 → 648,10 |
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); |
} |
} |
} |
699,64 → 658,6 |
return ipc_forward(call, phone, &TASK->answerbox, mode); |
} |
/** 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) |
{ |
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 |
880,17 → 781,9 |
{ |
call_t *call; |
restart: |
#ifdef CONFIG_UDEBUG |
udebug_stoppable_begin(); |
#endif |
restart: |
call = ipc_wait_for_call(&TASK->answerbox, usec, |
flags | SYNCH_FLAGS_INTERRUPTIBLE); |
#ifdef CONFIG_UDEBUG |
udebug_stoppable_end(); |
#endif |
if (!call) |
return 0; |
912,16 → 805,11 |
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); |
936,21 → 824,6 |
/* 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; |
991,30 → 864,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/dd/kernel/generic/src/ipc/ipc.c |
---|
43,7 → 43,6 |
#include <synch/waitq.h> |
#include <synch/synch.h> |
#include <ipc/ipc.h> |
#include <ipc/kbox.h> |
#include <errno.h> |
#include <mm/slab.h> |
#include <arch.h> |
52,7 → 51,6 |
#include <debug.h> |
#include <print.h> |
#include <console/console.h> |
#include <proc/thread.h> |
#include <arch/interrupt.h> |
#include <ipc/irq.h> |
68,7 → 66,7 |
*/ |
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; |
89,8 → 87,7 |
call_t *call; |
call = slab_alloc(ipc_call_slab, flags); |
if (call) |
_ipc_call_init(call); |
_ipc_call_init(call); |
return call; |
} |
163,7 → 160,7 |
*/ |
void ipc_phone_init(phone_t *phone) |
{ |
mutex_initialize(&phone->lock, MUTEX_PASSIVE); |
mutex_initialize(&phone->lock); |
phone->callee = NULL; |
phone->state = IPC_PHONE_FREE; |
atomic_set(&phone->active_calls, 0); |
173,10 → 170,8 |
* |
* @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) |
void ipc_call_sync(phone_t *phone, call_t *request) |
{ |
answerbox_t sync_box; |
186,10 → 181,7 |
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. |
202,13 → 194,6 |
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); |
361,11 → 346,8 |
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; |
if (mode & IPC_FF_ROUTE_FROM_ME) |
call->data.phone = newphone; |
} |
return ipc_call(newphone, call); |
} |
429,7 → 411,7 |
* |
* @param lst Head of the list to be cleaned up. |
*/ |
void ipc_cleanup_call_list(link_t *lst) |
static void ipc_cleanup_call_list(link_t *lst) |
{ |
call_t *call; |
444,31 → 426,33 |
} |
} |
/** 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 tasks than TASK. |
*/ |
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, |
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 (SYNCH_FAILED(mutex_trylock(&phone->lock))) { |
spinlock_unlock(&box->lock); |
interrupts_restore(ipl); |
spinlock_unlock(&TASK->answerbox.lock); |
DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD); |
goto restart_phones; |
} |
475,70 → 459,13 |
/* 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(&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]); |
/* 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); |
574,13 → 501,7 |
(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); |
} |
} |
641,7 → 562,7 |
default: |
break; |
} |
printf("active: %ld\n", |
printf("active: %d\n", |
atomic_get(&task->phones[i].active_calls)); |
} |
mutex_unlock(&task->phones[i].lock); |
654,10 → 575,8 |
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, |
printf("Callid: %p Srctask:%llu M:%d A1:%d A2:%d A3:%d " |
"A4:%d A5:%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), |
IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), |
665,14 → 584,12 |
} |
/* 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, |
printf("Callid: %p Srctask:%llu M:%d A1:%d A2:%d A3:%d " |
"A4:%d A5:%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), |
IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), |
680,12 → 597,10 |
} |
/* Print answerbox - calls */ |
printf("ABOX - ANSWERS:\n"); |
for (tmp = task->answerbox.answers.next; |
tmp != &task->answerbox.answers; |
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", |
printf("Callid:%p M:%d A1:%d A2:%d A3:%d A4:%d A5:%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), |
IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data), |
/branches/dd/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,8 → 58,78 |
#include <console/console.h> |
#include <print.h> |
/** Free the top-half pseudocode. |
/** Execute code associated with IRQ notification. |
* |
* @param call Notification call. |
* @param code Top-half pseudocode. |
*/ |
static void code_execute(call_t *call, irq_code_t *code) |
{ |
unsigned 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 < |
IPC_CALL_LEN) { |
call->data.args[code->cmds[i].dstarg] = dstval; |
} |
} |
} |
/** Free top-half pseudocode. |
* |
* @param code Pointer to the top-half pseudocode. |
*/ |
static void code_free(irq_code_t *code) |
90,7 → 140,7 |
} |
} |
/** Copy the top-half pseudocode from userspace into the kernel. |
/** Copy top-half pseudocode from userspace into the kernel. |
* |
* @param ucode Userspace address of the top-half pseudocode. |
* |
126,6 → 176,38 |
return code; |
} |
/** Unregister task from IRQ notification. |
* |
* @param box Answerbox associated with the notification. |
* @param inr IRQ number. |
* @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. |
142,10 → 224,6 |
ipl_t ipl; |
irq_code_t *code; |
irq_t *irq; |
unative_t key[] = { |
(unative_t) inr, |
(unative_t) devno |
}; |
if (ucode) { |
code = code_from_uspace(ucode); |
155,15 → 233,21 |
code = NULL; |
} |
/* |
* 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; |
ipl = interrupts_disable(); |
irq = irq_find_and_lock(inr, devno); |
if (!irq) { |
interrupts_restore(ipl); |
code_free(code); |
return ENOENT; |
} |
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; |
170,140 → 254,14 |
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); |
spinlock_lock(&irq->lock); |
spinlock_lock(&box->irq_lock); |
if (hash_table_find(&irq_uspace_hash_table, key)) { |
code_free(code); |
spinlock_unlock(&box->irq_lock); |
spinlock_unlock(&irq->lock); |
spinlock_unlock(&irq_uspace_hash_table_lock); |
free(irq); |
interrupts_restore(ipl); |
return EEXISTS; |
} |
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; |
} |
/** Unregister task from IRQ notification. |
* |
* @param box Answerbox associated with the notification. |
* @param inr IRQ number. |
* @param devno Device number. |
*/ |
int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno) |
{ |
ipl_t ipl; |
unative_t key[] = { |
(unative_t) inr, |
(unative_t) devno |
}; |
link_t *lnk; |
irq_t *irq; |
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); |
spinlock_lock(&irq->lock); |
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); |
/* Remove the IRQ from the answerbox's list. */ |
list_remove(&irq->notif_cfg.link); |
/* 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(&irq->lock); |
spinlock_unlock(&box->irq_lock); |
/* Free up the IRQ structure. */ |
free(irq); |
interrupts_restore(ipl); |
return EOK; |
} |
/** Disconnect all IRQ notifications from an answerbox. |
* |
* This function is effective because the answerbox contains |
* 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. |
*/ |
void ipc_irq_cleanup(answerbox_t *box) |
{ |
ipl_t ipl; |
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)) { |
/* |
* 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); |
/* Remove from the hash table. */ |
hash_table_remove(&irq_uspace_hash_table, key, 2); |
/* Free up the pseudo code and associated structures. */ |
code_free(irq->notif_cfg.code); |
spinlock_unlock(&irq->lock); |
free(irq); |
} |
spinlock_unlock(&box->irq_lock); |
spinlock_unlock(&irq_uspace_hash_table_lock); |
interrupts_restore(ipl); |
return 0; |
} |
/** Add a call to the proper answerbox queue. |
322,158 → 280,125 |
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. |
/** Send notification message. |
* |
* @param irq IRQ structure. |
* |
* @return IRQ_ACCEPT if the interrupt is accepted by the |
* pseudocode. IRQ_DECLINE otherwise. |
* @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. |
*/ |
irq_ownership_t ipc_irq_top_half_claim(irq_t *irq) |
void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3, |
unative_t a4, unative_t a5) |
{ |
unsigned int i; |
unative_t dstval; |
irq_code_t *code = irq->notif_cfg.code; |
unative_t *scratch = irq->notif_cfg.scratch; |
call_t *call; |
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; |
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; |
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); |
/* Put a counter to the message */ |
call->priv = ++irq->notif_cfg.counter; |
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; |
} |
send_call(irq, call); |
} |
return IRQ_DECLINE; |
spinlock_unlock(&irq->lock); |
} |
/* IRQ top-half handler. |
/** Notify a task that an IRQ had occurred. |
* |
* 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) |
void ipc_irq_send_notif(irq_t *irq) |
{ |
call_t *call; |
ASSERT(irq); |
if (irq->notif_cfg.answerbox) { |
call_t *call; |
call = ipc_call_alloc(FRAME_ATOMIC); |
if (!call) |
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]); |
/* Execute code to handle irq */ |
code_execute(call, irq->notif_cfg.code); |
send_call(irq, call); |
} |
} |
/** Send notification message. |
/** Disconnect all IRQ notifications from an answerbox. |
* |
* @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. |
* This function is effective because the answerbox contains |
* 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. |
*/ |
void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3, |
unative_t a4, unative_t a5) |
void ipc_irq_cleanup(answerbox_t *box) |
{ |
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; |
ipl_t ipl; |
loop: |
ipl = interrupts_disable(); |
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); |
irq = list_get_instance(cur, irq_t, notif_cfg.link); |
if (!spinlock_trylock(&irq->lock)) { |
/* |
* Avoid deadlock by trying again. |
*/ |
spinlock_unlock(&box->irq_lock); |
interrupts_restore(ipl); |
DEADLOCK_PROBE(p_irqlock, DEADLOCK_THRESHOLD); |
goto loop; |
} |
call->flags |= IPC_CALL_NOTIF; |
/* Put a counter to the message */ |
call->priv = ++irq->notif_cfg.counter; |
ASSERT(irq->notif_cfg.answerbox == box); |
list_remove(&irq->notif_cfg.link); |
/* |
* Don't forget to free any top-half pseudocode. |
*/ |
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; |
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); |
} |
spinlock_unlock(&irq->lock); |
spinlock_unlock(&box->irq_lock); |
interrupts_restore(ipl); |
} |
/** @} |
/branches/dd/kernel/generic/src/ipc/ipcrsc.c |
---|
170,6 → 170,7 |
int i; |
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) |
182,9 → 183,8 |
} |
spinlock_unlock(&TASK->lock); |
if (i == IPC_MAX_PHONES) |
if (i >= IPC_MAX_PHONES) |
return -1; |
return i; |
} |
/branches/dd/kernel/generic/src/lib/string.c |
---|
File deleted |
/branches/dd/kernel/generic/src/lib/elf.c |
---|
57,7 → 57,7 |
}; |
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, |
as_t *as, int flags); |
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, |
67,10 → 67,9 |
* |
* @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) |
unsigned int elf_load(elf_header_t *header, as_t * as) |
{ |
int i, rc; |
111,7 → 110,7 |
seghdr = &((elf_segment_header_t *)(((uint8_t *) header) + |
header->e_phoff))[i]; |
rc = segment_header(seghdr, header, as, flags); |
rc = segment_header(seghdr, header, as); |
if (rc != EE_OK) |
return rc; |
} |
152,10 → 151,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) |
as_t *as) |
{ |
char *interp; |
switch (entry->p_type) { |
case PT_NULL: |
case PT_PHDR: |
165,16 → 162,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: |
/branches/dd/kernel/generic/src/lib/rd.c |
---|
42,6 → 42,7 |
#include <mm/frame.h> |
#include <sysinfo/sysinfo.h> |
#include <ddi/ddi.h> |
#include <print.h> |
#include <align.h> |
static parea_t rd_parea; /**< Physical memory area for rd. */ |
48,14 → 49,14 |
/** |
* 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. |
* 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 → 80,10 |
if ((hsize % FRAME_SIZE) || (dsize % FRAME_SIZE)) |
return RE_UNSUPPORTED; |
if (dsize % FRAME_SIZE) |
return RE_UNSUPPORTED; |
if (hsize > size) |
return RE_INVALID; |
86,16 → 90,17 |
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 = ALIGN_DOWN((uintptr_t) KA2PA((void *) header + hsize), FRAME_SIZE); |
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)); |
return RE_OK; |
} |
/branches/dd/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,93 |
#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; |
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; |
unsigned 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; |
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/dd/kernel/generic/src/lib/func.c |
---|
55,6 → 55,8 |
#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; |
64,19 → 66,116 |
#endif |
interrupts_disable(); |
#if (defined(CONFIG_DEBUG)) && (defined(CONFIG_KCONSOLE)) |
if (rundebugger) |
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) |
{ |
unsigned 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) |
{ |
unsigned 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. |
/branches/dd/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) dispose |
{ |
return object_dispose(self); |
} |
@end |
/** @} |
*/ |
/branches/dd/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/dd/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,12 |
* |
* 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) |
{ |
118,7 → 116,7 |
*/ |
for (i = 0; i < leaf->keys; i++) { |
if (leaf->key[i] == page - area->base) { |
if (leaf->key[i] == page) { |
found = true; |
break; |
} |
129,7 → 127,7 |
page_mapping_insert(AS, addr, frame, |
as_area_get_flags(area)); |
if (!used_space_insert(area, page, 1)) |
panic("Cannot insert used space."); |
panic("Could not insert used space.\n"); |
mutex_unlock(&area->sh_info->lock); |
return AS_PF_OK; |
} |
152,10 → 150,6 |
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); |
} |
dirty = true; |
} else { |
frame = KA2PA(base + i * FRAME_SIZE); |
168,7 → 162,7 |
* and cleared. |
*/ |
frame = (uintptr_t)frame_alloc(ONE_FRAME, 0); |
memsetb((void *) PA2KA(frame), FRAME_SIZE, 0); |
memsetb(PA2KA(frame), FRAME_SIZE, 0); |
dirty = true; |
} else { |
size_t pad_lo, pad_hi; |
193,13 → 187,8 |
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); |
} |
memsetb((void *) PA2KA(frame), pad_lo, 0); |
memsetb((void *) (PA2KA(frame) + FRAME_SIZE - pad_hi), pad_hi, |
0); |
memsetb(PA2KA(frame), pad_lo, 0); |
memsetb(PA2KA(frame) + FRAME_SIZE - pad_hi, pad_hi, 0); |
dirty = true; |
} |
214,7 → 203,7 |
page_mapping_insert(AS, addr, frame, as_area_get_flags(area)); |
if (!used_space_insert(area, page, 1)) |
panic("Cannot insert used space."); |
panic("Could not insert used space.\n"); |
return AS_PF_OK; |
} |
223,10 → 212,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) |
269,7 → 257,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) |
{ |
/branches/dd/kernel/generic/src/mm/slab.c |
---|
167,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; |
count_t zone = 0; |
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)); |
200,7 → 200,7 |
slab->cache = cache; |
for (i = 0; i < cache->objects; i++) |
*((int *) (slab->start + i*cache->size)) = i + 1; |
*((int *) (slab->start + i*cache->size)) = i+1; |
atomic_inc(&cache->allocated_slabs); |
return slab; |
239,7 → 239,8 |
* |
* @return Number of freed pages |
*/ |
static count_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; |
255,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 */ |
280,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; |
300,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; |
332,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; |
367,7 → 368,8 |
* |
* @return Number of freed pages |
*/ |
static count_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; |
count_t frames = 0; |
387,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; |
421,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; |
456,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; |
528,8 → 530,7 |
static unsigned 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; |
} |
556,25 → 557,28 |
ASSERT(_slab_initialized >= 2); |
cache->mag_cache = malloc(sizeof(slab_mag_cache_t) * config.cpu_count, |
0); |
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"); |
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)) |
592,7 → 596,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. */ |
605,7 → 609,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; |
626,16 → 630,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; |
} |
659,7 → 665,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; |
712,8 → 718,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)) |
721,8 → 727,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; |
751,8 → 758,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); |
} |
779,8 → 787,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); |
} |
794,77 → 801,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) |
872,24 → 824,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; |
914,11 → 874,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; |
929,7 → 887,7 |
/**************************************/ |
/* kalloc/kfree functions */ |
void *malloc(unsigned int size, int flags) |
void * malloc(unsigned int size, int flags) |
{ |
ASSERT(_slab_initialized); |
ASSERT(size && size <= (1 << SLAB_MAX_MALLOC_W)); |
942,7 → 900,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/dd/kernel/generic/src/mm/tlb.c |
---|
173,7 → 173,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/dd/kernel/generic/src/mm/backend_anon.c |
---|
78,6 → 78,7 |
int anon_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access) |
{ |
uintptr_t frame; |
bool dirty = false; |
if (!as_area_check_access(area, access)) |
return AS_PF_FAULT; |
105,7 → 106,7 |
*/ |
for (i = 0; i < leaf->keys; i++) { |
if (leaf->key[i] == |
ALIGN_DOWN(addr, PAGE_SIZE) - area->base) { |
ALIGN_DOWN(addr, PAGE_SIZE)) { |
allocate = false; |
break; |
} |
112,7 → 113,8 |
} |
if (allocate) { |
frame = (uintptr_t) frame_alloc(ONE_FRAME, 0); |
memsetb((void *) PA2KA(frame), FRAME_SIZE, 0); |
memsetb(PA2KA(frame), FRAME_SIZE, 0); |
dirty = true; |
/* |
* Insert the address of the newly allocated |
142,7 → 144,8 |
* the different causes |
*/ |
frame = (uintptr_t) frame_alloc(ONE_FRAME, 0); |
memsetb((void *) PA2KA(frame), FRAME_SIZE, 0); |
memsetb(PA2KA(frame), FRAME_SIZE, 0); |
dirty = true; |
} |
/* |
152,7 → 155,7 |
*/ |
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; |
} |
/branches/dd/kernel/generic/src/mm/as.c |
---|
82,6 → 82,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,6 → 93,7 |
* Slab for as_t objects. |
*/ |
static slab_cache_t *as_slab; |
#endif |
/** |
* This lock serializes access to the ASID subsystem. |
111,11 → 113,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 → 126,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 → 139,7 |
return as_destructor_arch(as); |
} |
#endif |
/** Initialize address space subsystem. */ |
void as_init(void) |
141,29 → 146,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); |
180,7 → 189,7 |
#else |
page_table_create(flags); |
#endif |
return as; |
} |
190,8 → 199,6 |
* 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) |
{ |
256,7 → 263,11 |
interrupts_restore(ipl); |
#ifdef __OBJC__ |
[as free]; |
#else |
slab_free(as_slab, as); |
#endif |
} |
/** Create address space area of common attributes. |
263,19 → 274,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 → 312,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 → 324,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 → 339,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 → 400,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 → 410,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); |
/* |
444,8 → 455,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 → 463,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++) { |
515,10 → 526,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) |
{ |
615,19 → 626,18 |
* 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. |
*/ |
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) |
688,7 → 698,7 |
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; |
746,11 → 756,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 → 775,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; |
index_t frame_idx; |
count_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 += (count_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]; |
count_t j; |
pte_t *pte; |
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) && |
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]; |
count_t j; |
for (j = 0; j < (count_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 → 835,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)) { |
1043,8 → 891,8 |
* |
* 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) |
{ |
1115,9 → 963,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 → 993,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 → 1004,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 → 1027,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 → 1050,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,11 → 1087,11 |
* |
* 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) |
{ |
1280,15 → 1143,15 |
* |
* 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; |
1377,7 → 1240,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,11 → 1254,11 |
* |
* 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, count_t count) |
{ |
1665,8 → 1528,8 |
} |
} |
panic("Inconsistency detected while adding %" PRIc " 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,11 → 1536,11 |
* |
* 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, count_t count) |
{ |
1844,8 → 1707,8 |
} |
error: |
panic("Inconsistency detected while removing %" PRIc " 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 → 1715,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) |
{ |
1907,12 → 1770,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 → 1778,7 |
/** Print out information about address space. |
* |
* @param as Address space. |
* @param as Address space. |
*/ |
void as_print(as_t *as) |
{ |
1943,9 → 1800,9 |
as_area_t *area = node->value[i]; |
mutex_lock(&area->lock); |
printf("as_area: %p, base=%p, pages=%" PRIc |
" (%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/dd/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,17 → 67,43 |
#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; |
count_t mem_avail_req = 0; /**< Number of frames requested. */ |
count_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 */ |
/********************/ |
84,20 → 118,22 |
return (index_t) (frame - zone->frames) + zone->base; |
} |
static inline bool frame_index_valid(zone_t *zone, index_t index) |
static inline int frame_index_valid(zone_t *zone, index_t index) |
{ |
return (index < zone->count); |
} |
static inline index_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); |
} |
/** 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 → 141,142 |
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 count_t zones_insert_zone(pfn_t base, count_t count) |
static int zones_add_zone(zone_t *newzone) |
{ |
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) { |
printf("Maximum zone count %u exceeded!\n", ZONES_MAX); |
return (count_t) -1; |
spinlock_unlock(&zones.lock); |
interrupts_restore(ipl); |
return -1; |
} |
count_t i; |
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 (count_t) -1; |
return -1; |
} |
if (base < zones.info[i].base) |
if (newzone->base < z->base) |
break; |
} |
/* Move other zones up */ |
count_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. |
/** |
* Try to find a zone where can we find the frame |
* |
* Assume interrupts are disabled and zones lock is |
* locked. |
* Assume interrupts are disabled. |
* |
* @return Total number of available frames. |
* |
* @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 count_t total_frames_free(void) |
static zone_t * find_zone_and_lock(pfn_t frame, unsigned int *pzone) |
{ |
count_t total = 0; |
count_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. |
* |
*/ |
count_t find_zone(pfn_t frame, count_t count, count_t hint) |
{ |
if (hint >= zones.count) |
hint = 0; |
count_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) { |
/* Unlock the global lock */ |
spinlock_unlock(&zones.lock); |
if (pzone) |
*pzone = i; |
return z; |
} |
spinlock_unlock(&z->lock); |
i++; |
if (i >= zones.count) |
i = 0; |
} while (i != hint); |
return (count_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 count_t find_free_zone(uint8_t order, zone_flags_t flags, count_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; |
count_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 (count_t) -1; |
} while(i != hint); |
spinlock_unlock(&zones.lock); |
return NULL; |
} |
/**************************/ |
250,146 → 283,167 |
/* 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, |
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; |
index_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; |
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); |
index_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 → 454,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 → 462,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, 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,643 → 524,521 |
} |
} |
/** Return frame from zone. */ |
static frame_t *zone_get_frame(zone_t *zone, index_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. */ |
/** 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); |
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(count_t z1, count_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 */ |
count_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(count_t znum, pfn_t pfn, count_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)); |
count_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); |
count_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(count_t znum, pfn_t frame_idx, count_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(frame_idx + count < zone->count); |
order = zone->frames[frame_idx].buddy_order; |
ASSERT((count_t) (1 << order) >= count); |
/* Reduce all blocks to order 0 */ |
count_t i; |
for (i = 0; i < (count_t) (1 << order); i++) { |
frame_t *frame = &zones.info[znum].frames[i + frame_idx]; |
frame = &zone->frames[i + frame_idx]; |
frame->buddy_order = 0; |
if (!frame->refcount) |
frame->refcount = 1; |
ASSERT(frame->refcount == 1); |
} |
/* Free unneeded frames */ |
for (i = count; i < (count_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(count_t z1, count_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 >= zones.count) || (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 */ |
count_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) |
{ |
count_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, count_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)); |
count_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(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 |
*/ |
count_t zone_create(pfn_t start, count_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 |
*/ |
count_t confcount = SIZE2FRAMES(zone_conf_size(count)); |
if ((confframe >= start) && (confframe < start + count)) { |
for (; confframe < start + count; confframe++) { |
uintptr_t addr = PFN2ADDR(confframe); |
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 (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(config.base), config.kernel_size)) |
continue; |
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; |
} |
KA2PA(init.tasks[i].addr), |
init.tasks[i].size)) { |
overlap = true; |
break; |
} |
if (overlap) |
continue; |
if (confframe >= start + count) |
panic("Cannot find configuration data for zone."); |
break; |
} |
count_t znum = zones_insert_zone(start, count); |
if (znum == (count_t) -1) { |
spinlock_unlock(&zones.lock); |
interrupts_restore(ipl); |
return (count_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)) { |
count_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 */ |
count_t znum = zones_insert_zone(start, count); |
if (znum == (count_t) -1) { |
spinlock_unlock(&zones.lock); |
interrupts_restore(ipl); |
return (count_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, count_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); |
count_t znum = find_zone(pfn, 1, hint); |
ASSERT(znum != (count_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, count_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; |
count_t znum = find_zone(pfn, 1, hint); |
ASSERT(znum != (count_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, count_t *pzone) |
void * frame_alloc_generic(uint8_t order, int flags, unsigned int *pzone) |
{ |
count_t size = ((count_t) 1) << order; |
ipl_t ipl; |
count_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. |
*/ |
count_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 == (count_t) -1) && (!(flags & FRAME_NO_RECLAIM))) { |
count_t freed = slab_reclaim(0); |
if (freed > 0) |
znum = find_free_zone(order, |
FRAME_TO_ZONE_FLAGS(flags), hint); |
if (znum == (count_t) -1) { |
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); |
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 == (count_t) -1) { |
if (flags & FRAME_ATOMIC) { |
spinlock_unlock(&zones.lock); |
interrupts_restore(ipl); |
return NULL; |
} |
#ifdef CONFIG_DEBUG |
count_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 %" PRIc " frames, " |
"%" PRIc " 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; |
count_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); |
count_t znum = find_zone(pfn, 1, NULL); |
zone = find_zone_and_lock(pfn,NULL); |
ASSERT(zone); |
ASSERT(znum != (count_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. |
1111,56 → 1047,55 |
* 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. |
*/ |
count_t znum = find_zone(pfn, 1, NULL); |
zone = find_zone_and_lock(pfn,NULL); |
ASSERT(zone); |
ASSERT(znum != (count_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. */ |
/** 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; |
count_t i; |
for (i = 0; i < count; i++) { |
count_t znum = find_zone(start + i, 1, 0); |
if (znum == (count_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) { |
1175,28 → 1110,36 |
frame_mark_unavailable(pfn, |
SIZE2FRAMES(init.tasks[i].size)); |
} |
if (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(); |
/** Return total size of all zones |
* |
*/ |
uint64_t zone_total_size(void) { |
zone_t *zone = NULL; |
unsigned int i; |
ipl_t ipl; |
uint64_t total = 0; |
ipl = interrupts_disable(); |
spinlock_lock(&zones.lock); |
uint64_t total = 0; |
count_t i; |
for (i = 0; i < zones.count; i++) |
total += (uint64_t) FRAMES2SIZE(zones.info[i].count); |
for (i = 0; i < zones.count; i++) { |
zone = zones.info[i]; |
spinlock_lock(&zone->lock); |
total += (uint64_t) FRAMES2SIZE(zone->count); |
spinlock_unlock(&zone->lock); |
} |
spinlock_unlock(&zones.lock); |
interrupts_restore(ipl); |
1204,128 → 1147,86 |
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 |
/** 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); |
/* |
* 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). |
*/ |
if (sizeof(void *) == 4) { |
printf("# base address free frames busy frames\n"); |
printf("-- ------------ ------------ ------------\n"); |
} else { |
printf("# base address free frames busy frames\n"); |
printf("-- -------------------- ------------ ------------\n"); |
} |
count_t i; |
for (i = 0;; i++) { |
ipl_t ipl = interrupts_disable(); |
spinlock_lock(&zones.lock); |
for (i = 0; i < zones.count; i++) { |
zone = zones.info[i]; |
spinlock_lock(&zone->lock); |
if (i >= zones.count) { |
spinlock_unlock(&zones.lock); |
interrupts_restore(ipl); |
break; |
} |
if (sizeof(void *) == 4) |
printf("%-2d %#10zx %12zd %12zd\n", i, PFN2ADDR(zone->base), |
zone->free_count, zone->busy_count); |
else |
printf("%-2d %#18zx %12zd %12zd\n", i, PFN2ADDR(zone->base), |
zone->free_count, zone->busy_count); |
uintptr_t base = PFN2ADDR(zones.info[i].base); |
count_t count = zones.info[i].count; |
zone_flags_t flags = zones.info[i].flags; |
count_t free_count = zones.info[i].free_count; |
count_t busy_count = zones.info[i].busy_count; |
spinlock_unlock(&zones.lock); |
interrupts_restore(ipl); |
bool available = zone_flags_available(flags); |
printf("%-2" PRIc, i); |
#ifdef __32_BITS__ |
printf(" %10p", base); |
#endif |
#ifdef __64_BITS__ |
printf(" %18p", base); |
#endif |
printf(" %12" PRIc " %c%c%c ", count, |
available ? 'A' : ' ', |
(flags & ZONE_RESERVED) ? 'R' : ' ', |
(flags & ZONE_FIRMWARE) ? 'F' : ' '); |
if (available) |
printf("%12" PRIc " %12" PRIc, |
free_count, busy_count); |
printf("\n"); |
spinlock_unlock(&zone->lock); |
} |
spinlock_unlock(&zones.lock); |
interrupts_restore(ipl); |
} |
/** Prints zone details. |
* |
* @param num Zone base address or zone number. |
* |
*/ |
void zone_print_one(count_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); |
count_t znum = (count_t) -1; |
count_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 == (count_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; |
count_t count = zones.info[i].count; |
count_t free_count = zones.info[i].free_count; |
count_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 (%zd KB)\n", zone->count, |
SIZE2KB(FRAMES2SIZE(zone->count))); |
printf("Allocated space: %zd frames (%zd KB)\n", zone->busy_count, |
SIZE2KB(FRAMES2SIZE(zone->busy_count))); |
printf("Available space: %zd frames (%zd KB)\n", zone->free_count, |
SIZE2KB(FRAMES2SIZE(zone->free_count))); |
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: %" PRIc "\n", znum); |
printf("Zone base address: %p\n", base); |
printf("Zone size: %" PRIc " 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: %" PRIc " frames (%" PRIs " KiB)\n", |
busy_count, SIZE2KB(FRAMES2SIZE(busy_count))); |
printf("Available space: %" PRIc " frames (%" PRIs " KiB)\n", |
free_count, SIZE2KB(FRAMES2SIZE(free_count))); |
} |
} |
/** @} |
*/ |
/branches/dd/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 | PAGE_WRITE); |
/* 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/dd/kernel/generic/src/mm/backend_phys.c |
---|
77,7 → 77,7 |
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/dd/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/dd/kernel/generic/src/synch/smc.c |
---|
File deleted |
/branches/dd/kernel/generic/src/synch/futex.c |
---|
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. |
/branches/dd/kernel/generic/src/synch/spinlock.c |
---|
106,8 → 106,9 |
continue; |
#endif |
if (i++ > DEADLOCK_THRESHOLD) { |
printf("cpu%u: looping on spinlock %" PRIp ":%s, caller=%" PRIp, |
CPU->id, sl, sl->name, 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); |
118,7 → 119,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/dd/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/dd/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/dd/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/dd/kernel/generic/src/time/timeout.c |
---|
113,7 → 113,7 |
spinlock_lock(&t->lock); |
if (t->cpu) |
panic("Unexpected: t->cpu != 0."); |
panic("t->cpu != 0"); |
t->cpu = CPU; |
t->ticks = us2ticks(time); |
/branches/dd/kernel/generic/src/time/clock.c |
---|
79,7 → 79,7 |
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); |
88,7 → 88,9 |
uptime->useconds = 0; |
clock_parea.pbase = (uintptr_t) faddr; |
clock_parea.vbase = (uintptr_t) uptime; |
clock_parea.frames = 1; |
clock_parea.cacheable = true; |
ddi_parea_register(&clock_parea); |
/* |
187,19 → 189,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/dd/kernel/generic/src/proc/program.c |
---|
File deleted |
/branches/dd/kernel/generic/src/proc/thread.c |
---|
67,13 → 67,9 |
#include <main/uinit.h> |
#include <syscall/copy.h> |
#include <errno.h> |
#include <console/klog.h> |
#ifndef LOADED_PROG_STACK_PAGES_NO |
#define LOADED_PROG_STACK_PAGES_NO 1 |
#endif |
/** Thread states */ |
char *thread_states[] = { |
"Invalid", |
102,7 → 98,7 |
thread_id_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,7 → 157,7 |
/* call the architecture-specific part of the constructor */ |
thr_constructor_arch(t); |
#ifdef CONFIG_FPU |
#ifdef ARCH_HAS_FPU |
#ifdef CONFIG_FPU_LAZY |
t->saved_fpu_context = NULL; |
#else |
169,11 → 165,11 |
if (!t->saved_fpu_context) |
return -1; |
#endif |
#endif |
#endif |
t->kstack = (uint8_t *) frame_alloc(STACK_FRAMES, FRAME_KA | kmflags); |
if (!t->kstack) { |
#ifdef CONFIG_FPU |
#ifdef ARCH_HAS_FPU |
if (t->saved_fpu_context) |
slab_free(fpu_context_slab, t->saved_fpu_context); |
#endif |
180,10 → 176,6 |
return -1; |
} |
#ifdef CONFIG_UDEBUG |
mutex_initialize(&t->udebug.lock, MUTEX_PASSIVE); |
#endif |
return 0; |
} |
196,7 → 188,7 |
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); |
#endif |
211,11 → 203,11 |
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 |
279,7 → 271,7 |
* 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 name Symbolic name. |
* @param uncounted Thread's accounting doesn't affect accumulated task |
* accounting. |
* |
297,7 → 289,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 → 309,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; |
352,11 → 344,6 |
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); |
419,17 → 406,12 |
ipl_t ipl; |
/* |
* Attach to the specified task. |
* Attach to the current task. |
*/ |
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); |
atomic_inc(&task->lifecount); |
list_append(&t->th_link, &task->th_head); |
spinlock_unlock(&task->lock); |
452,22 → 434,18 |
{ |
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. |
*/ |
if (atomic_predec(&TASK->lifecount) == 0) { |
/* |
* We are the last thread in the task that still has not exited. |
* With the exception of the moment the task was created, new |
* threads can only be created by threads of the same task. |
* We are safe to perform cleanup. |
*/ |
if (THREAD->flags & THREAD_FLAG_USPACE) { |
ipc_cleanup(); |
futex_cleanup(); |
LOG("Cleanup of task %" PRIu64" completed.", TASK->taskid); |
futex_cleanup(); |
klog_printf("Cleanup of task %llu completed.", |
TASK->taskid); |
} |
} |
603,37 → 581,33 |
static bool thread_walker(avltree_node_t *node, void *arg) |
{ |
thread_t *t = avltree_get_instance(node, thread_t, threads_tree_node); |
thread_t *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 (sizeof(void *) == 4) |
printf("%-6llu %-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); |
else |
printf("%-6llu %-10s %#18zx %-8s %#18zx %-3ld %#18zx %#18zx %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("%-4u", t->cpu->id); |
printf("%-4zd", 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 |
if (sizeof(uintptr_t) == 4) |
printf(" %#10zx", t->sleep_queue); |
else |
printf(" %#18zx", t->sleep_queue); |
} |
printf("\n"); |
649,25 → 623,23 |
/* Messing with thread structures, avoid deadlock */ |
ipl = interrupts_disable(); |
spinlock_lock(&threads_lock); |
if (sizeof(uintptr_t) == 4) { |
printf("tid name address state task " |
"ctx code stack cycles cpu " |
"waitqueue\n"); |
printf("------ ---------- ---------- -------- ---------- " |
"--- ---------- ---------- ---------- ---- " |
"----------\n"); |
} else { |
printf("tid name address state task " |
"ctx code stack cycles cpu " |
"waitqueue\n"); |
printf("------ ---------- ------------------ -------- ------------------ " |
"--- ------------------ ------------------ ---------- ---- " |
"------------------\n"); |
} |
#ifdef __32_BITS__ |
printf("tid name address state task " |
"ctx code stack cycles cpu " |
"waitqueue\n"); |
printf("------ ---------- ---------- -------- ---------- " |
"--- ---------- ---------- ---------- ---- " |
"----------\n"); |
#endif |
#ifdef __64_BITS__ |
printf("tid name address state task " |
"ctx code stack cycles cpu " |
"waitqueue\n"); |
printf("------ ---------- ------------------ -------- ------------------ " |
"--- ------------------ ------------------ ---------- ---- " |
"------------------\n"); |
#endif |
avltree_walk(&threads_tree, thread_walker, NULL); |
spinlock_unlock(&threads_lock); |
692,6 → 664,7 |
return node != NULL; |
} |
/** Update accounting of current thread. |
* |
* Note that thread_lock on THREAD must be already held and |
709,7 → 682,7 |
* |
*/ |
unative_t sys_thread_create(uspace_arg_t *uspace_uarg, char *uspace_name, |
size_t name_len, thread_id_t *uspace_thread_id) |
thread_id_t *uspace_thread_id) |
{ |
thread_t *t; |
char namebuf[THREAD_NAME_BUFLEN]; |
716,15 → 689,10 |
uspace_arg_t *kernel_uarg; |
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(). |
763,18 → 731,7 |
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 |
thread_ready(t); |
return 0; |
/branches/dd/kernel/generic/src/proc/task.c |
---|
35,8 → 35,10 |
* @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> |
43,18 → 45,23 |
#include <synch/spinlock.h> |
#include <synch/waitq.h> |
#include <arch.h> |
#include <arch/barrier.h> |
#include <panic.h> |
#include <adt/avl.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> |
#ifndef LOADED_PROG_STACK_PAGES_NO |
#define LOADED_PROG_STACK_PAGES_NO 1 |
#endif |
/** Spinlock protecting the tasks_tree AVL tree. */ |
SPINLOCK_INITIALIZE(tasks_lock); |
72,7 → 79,11 |
static task_id_t task_counter = 0; |
/** Initialize kernel tasks support. */ |
/** Initialize tasks |
* |
* Initialize kernel tasks support. |
* |
*/ |
void task_init(void) |
{ |
TASK = NULL; |
80,8 → 91,7 |
} |
/* |
* The idea behind this walker is to remember a single task different from |
* TASK. |
* 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) |
{ |
96,7 → 106,9 |
return true; /* continue the walk */ |
} |
/** Kill all tasks except the current task. */ |
/** Kill all tasks except the current task. |
* |
*/ |
void task_done(void) |
{ |
task_t *t; |
116,7 → 128,7 |
interrupts_restore(ipl); |
#ifdef CONFIG_DEBUG |
printf("Killing task %" PRIu64 "\n", id); |
printf("Killing task %llu\n", id); |
#endif |
task_kill(id); |
thread_usleep(10000); |
128,13 → 140,15 |
} 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) |
{ |
149,10 → 163,7 |
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'; |
ta->name = name; |
atomic_set(&ta->refcount, 0); |
atomic_set(&ta->lifecount, 0); |
ta->context = CONTEXT; |
159,18 → 170,7 |
ta->capabilities = 0; |
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); |
for (i = 0; i < IPC_MAX_PHONES; i++) |
ipc_phone_init(&ta->phones[i]); |
179,7 → 179,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(); |
202,7 → 202,7 |
/** Destroy task. |
* |
* @param t Task to be destroyed. |
* @param t Task to be destroyed. |
*/ |
void task_destroy(task_t *t) |
{ |
233,63 → 233,90 |
TASK = NULL; |
} |
/** Syscall for reading task ID from userspace. |
/** Create new task with 1 thread and run it |
* |
* @param uspace_task_id userspace address of 8-byte buffer |
* where to store current task ID. |
* @param program_addr Address of program executable image. |
* @param name Program name. |
* |
* @return Zero on success or an error code from @ref errno.h. |
* @return Task of the running program or NULL on error. |
*/ |
unative_t sys_task_get_id(task_id_t *uspace_task_id) |
task_t *task_run_program(void *program_addr, char *name) |
{ |
as_t *as; |
as_area_t *a; |
unsigned int rc; |
thread_t *t; |
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); |
/* |
* No need to acquire lock on TASK because taskid remains constant for |
* the lifespan of the task. |
* Create the data as_area. |
*/ |
return (unative_t) copy_to_uspace(uspace_task_id, &TASK->taskid, |
sizeof(TASK->taskid)); |
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); |
/* |
* Create the main thread. |
*/ |
t = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE, |
"uinit", false); |
ASSERT(t); |
thread_ready(t); |
return task; |
} |
/** Syscall for setting the task name. |
/** Syscall for reading task ID from userspace. |
* |
* The name simplifies identifying the task in the task list. |
* @param uspace_task_id Userspace address of 8-byte buffer where to store |
* current task ID. |
* |
* @param name The new name for the task. (typically the same |
* as the command used to execute it). |
* |
* @return 0 on success or an error code from @ref errno.h. |
*/ |
unative_t sys_task_set_name(const char *uspace_name, size_t name_len) |
unative_t sys_task_get_id(task_id_t *uspace_task_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'; |
strncpy(TASK->name, namebuf, TASK_NAME_BUFLEN); |
return EOK; |
/* |
* 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)); |
} |
/** 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. |
* The tasks_lock must be already held by the caller of this function |
* and interrupts must be disabled. |
* |
* @param id Task ID. |
* @param id Task ID. |
* |
* @return Task structure address or NULL if there is no such 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; |
task_t *task_find_by_id(task_id_t id) |
{ |
avltree_node_t *node; |
node = avltree_search(&tasks_tree, (avltree_key_t) id); |
300,13 → 327,11 |
/** 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) |
{ |
338,9 → 363,9 |
* 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) |
{ |
361,7 → 386,7 |
spinlock_unlock(&tasks_lock); |
/* |
* Interrupt all threads. |
* Interrupt all threads except ktaskclnp. |
*/ |
spinlock_lock(&ta->lock); |
for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
369,7 → 394,7 |
bool sleeping = false; |
thr = list_get_instance(cur, thread_t, th_link); |
spinlock_lock(&thr->lock); |
thr->interrupted = true; |
if (thr->state == Sleeping) |
395,22 → 420,18 |
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 |
if (sizeof(void *) == 4) |
printf("%-6llu %-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)); |
else |
printf("%-6llu %-10s %-3ld %#18zx %#18zx %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(" %d:%p", j, t->phones[j].callee); |
printf(" %zd:%#zx", j, t->phones[j].callee); |
} |
printf("\n"); |
426,21 → 447,19 |
/* Messing with task structures, avoid deadlock */ |
ipl = interrupts_disable(); |
spinlock_lock(&tasks_lock); |
if (sizeof(void *) == 4) { |
printf("taskid name ctx address as " |
"cycles threads calls callee\n"); |
printf("------ ---------- --- ---------- ---------- " |
"---------- ------- ------ ------>\n"); |
} else { |
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 |
#ifdef __64_BITS__ |
printf("taskid name ctx address as " |
"cycles threads calls callee\n"); |
printf("------ ------------ --- ------------------ ------------------ " |
"---------- ------- ------ ------>\n"); |
#endif |
avltree_walk(&tasks_tree, task_print_walker, NULL); |
spinlock_unlock(&tasks_lock); |
/branches/dd/kernel/generic/src/proc/tasklet.c |
---|
51,7 → 51,7 |
tasklet_list = malloc(sizeof(tasklet_descriptor_t *) * config.cpu_count, 0); |
if (!tasklet_list) |
panic("Error initializing tasklets."); |
panic("Error initializing tasklets"); |
for (i = 0; i < config.cpu_count; i++) |
tasklet_list[i] = NULL; |
/branches/dd/kernel/generic/src/proc/scheduler.c |
---|
451,8 → 451,8 |
/* |
* Entering state is unexpected. |
*/ |
panic("tid%" PRIu64 ": unexpected state %s.", |
THREAD->tid, thread_states[THREAD->state]); |
panic("tid%llu: unexpected state %s\n", THREAD->tid, |
thread_states[THREAD->state]); |
break; |
} |
504,9 → 504,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 %llu (priority=%d, ticks=%llu, nrdy=%ld)\n", |
CPU->id, THREAD->tid, THREAD->priority, THREAD->ticks, |
atomic_get(&CPU->nrdy)); |
#endif |
/* |
640,9 → 640,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 %llu -> 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 → 708,7 |
continue; |
spinlock_lock(&cpus[cpu].lock); |
printf("cpu%u: address=%p, nrdy=%ld, needs_relink=%" PRIc "\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 → 719,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("%llu(%s) ", t->tid, |
thread_states[t->state]); |
} |
printf("\n"); |
/branches/dd/kernel/generic/src/debug/symtab.c |
---|
37,10 → 37,8 |
#include <symtab.h> |
#include <byteorder.h> |
#include <string.h> |
#include <func.h> |
#include <print.h> |
#include <arch/types.h> |
#include <typedefs.h> |
/** Return entry that seems most likely to correspond to argument. |
* |
141,7 → 139,7 |
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", addr, realname); |
printf("%.*p: %s\n", sizeof(uintptr_t) * 2, addr, realname); |
i++; |
} |
} |
/branches/dd/kernel/generic/src/main/main.c |
---|
61,7 → 61,6 |
#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> |
79,9 → 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> |
/** Global configuration structure. */ |
config_t config; |
105,15 → 104,18 |
* appropriate sizes and addresses. |
*/ |
/** Virtual address of where the kernel is loaded. */ |
/**< Virtual address of where the kernel is loaded. */ |
uintptr_t hardcoded_load_address = 0; |
/** Size of the kernel code in bytes. */ |
/**< Size of the kernel code in bytes. */ |
size_t hardcoded_ktext_size = 0; |
/** Size of the kernel data in bytes. */ |
/**< Size of the kernel data in bytes. */ |
size_t hardcoded_kdata_size = 0; |
/** Lowest safe stack virtual address. */ |
/**< 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 |
* kernel boot phase when SP is set to the very top of the reserved |
129,11 → 131,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(). |
* |
186,97 → 186,90 |
*/ |
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(); |
tasklet_init(); |
arch_post_mm_init(); |
version_print(); |
printf("kernel: %.*p hardcoded_ktext_size=%zd KB, " |
"hardcoded_kdata_size=%zd KB\n", sizeof(uintptr_t) * 2, |
config.base, SIZE2KB(hardcoded_ktext_size), |
SIZE2KB(hardcoded_kdata_size)); |
printf("stack: %.*p size=%zd KB\n", sizeof(uintptr_t) * 2, |
config.stack_base, SIZE2KB(config.stack_size)); |
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("Detected %" PRIc " CPU(s), %" PRIu64" MiB free memory\n", |
config.cpu_count, SIZE2MB(zone_total_size())); |
printf("Detected %zu CPU(s), %llu MB free memory\n", |
config.cpu_count, SIZE2MB(zone_total_size())); |
cpu_init(); |
LOG_EXEC(cpu_init()); |
calibrate_delay_loop(); |
clock_counter_init(); |
timeout_init(); |
scheduler_init(); |
task_init(); |
thread_init(); |
futex_init(); |
klog_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) { |
count_t i; |
for (i = 0; i < init.cnt; i++) |
LOG("init[%" PRIc "].addr=%#" PRIp ", init[%" PRIc |
"].size=%#" PRIs "\n", 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"); |
LOG_EXEC(ipc_init()); |
LOG_EXEC(klog_init()); |
LOG_EXEC(console_init()); |
#ifdef CONFIG_KCONSOLE |
LOG_EXEC(kconsole_notify_init()); |
#endif |
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, |
329,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/dd/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-2008 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/dd/kernel/generic/src/main/uinit.c |
---|
46,9 → 46,7 |
#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 |
67,10 → 65,6 |
* 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; |
/branches/dd/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,18 → 99,24 |
* 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) { |
count_t i; |
133,119 → 124,75 |
* 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" PRIc "\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. |
*/ |
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; |
program_t programs[CONFIG_INIT_TASKS]; |
for (i = 0; i < init.cnt; i++) { |
/* |
* Run user tasks, load RAM disk images. |
*/ |
if (init.tasks[i].addr % FRAME_SIZE) { |
printf("init[%" PRIc "].addr is not frame aligned\n", i); |
printf("init[%d].addr is not frame aligned", i); |
continue; |
} |
task_t *utask = task_run_program((void *) init.tasks[i].addr, |
"uspace"); |
/* |
* 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); |
strncpy(namebuf, INIT_PREFIX, TASK_NAME_BUFLEN); |
strncpy(namebuf + INIT_PREFIX_LEN, name, |
TASK_NAME_BUFLEN - INIT_PREFIX_LEN); |
int rc = program_create_from_image((void *) init.tasks[i].addr, |
namebuf, &programs[i]); |
if ((rc == 0) && (programs[i].task != NULL)) { |
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 %" PRIc " not used (error %d)\n", i, rd); |
printf("Init binary %zd not used, error code %d.\n", i, rd); |
} |
} |
/* |
* Run user tasks with small delays |
* to avoid intermixed klog output. |
* |
* TODO: This certainly does not guarantee |
* anything, it just works in most of the |
* cases. Some better way how to achieve |
* nice klog output should be found. |
*/ |
for (i = 0; i < init.cnt; i++) { |
if (programs[i].task != NULL) { |
program_ready(&programs[i]); |
thread_usleep(10000); |
} |
} |
#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/dd/kernel/generic/src/interrupt/interrupt.c |
---|
86,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(); |
109,10 → 100,8 |
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; |
119,32 → 108,27 |
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 |
if (sizeof(void *) == 4) { |
printf("Exc Description Handler Symbol\n"); |
printf("--- -------------------- ---------- --------\n"); |
} else { |
printf("Exc Description Handler Symbol\n"); |
printf("--- -------------------- ------------------ --------\n"); |
} |
for (i = 0; i < IVT_ITEMS; i++) { |
symbol = get_symtab_entry((unative_t) exc_table[i].f); |
if (!symbol) |
symbol = "not found"; |
#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 (sizeof(void *) == 4) |
printf("%-3u %-20s %#10zx %s\n", i + IVT_FIRST, exc_table[i].name, |
exc_table[i].f, symbol); |
else |
printf("%-3u %-20s %#18zx %s\n", i + IVT_FIRST, exc_table[i].name, |
exc_table[i].f, symbol); |
if (((i + 1) % 20) == 0) { |
printf(" -- Press any key to continue -- "); |
spinlock_unlock(&exctbl_lock); |
160,31 → 144,26 |
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); |
} |
/** @} |
/branches/dd/kernel/generic/src/printf/printf_core.c |
---|
40,7 → 40,7 |
#include <print.h> |
#include <arch/arg.h> |
#include <macros.h> |
#include <string.h> |
#include <func.h> |
#include <arch.h> |
/** show prefixes 0x or 0 */ |
75,6 → 75,7 |
PrintfQualifierInt, |
PrintfQualifierLong, |
PrintfQualifierLongLong, |
PrintfQualifierNative, |
PrintfQualifierPointer |
} qualifier_t; |
431,6 → 432,7 |
* - "" Signed or unsigned int (default value).@n |
* - "l" Signed or unsigned long int.@n |
* - "ll" Signed or unsigned long long int.@n |
* - "z" unative_t (non-standard extension).@n |
* |
* |
* CONVERSION:@n |
484,7 → 486,7 |
while ((c = fmt[i])) { |
/* control character */ |
if (c == '%') { |
if (c == '%' ) { |
/* print common characters if any processed */ |
if (i > j) { |
if ((retval = printf_putnchars(&fmt[j], |
534,7 → 536,7 |
} else if (fmt[i] == '*') { |
/* get width value from argument list */ |
i++; |
width = (int) va_arg(ap, int); |
width = (int)va_arg(ap, int); |
if (width < 0) { |
/* negative width sets '-' flag */ |
width *= -1; |
557,7 → 559,7 |
* list. |
*/ |
i++; |
precision = (int) va_arg(ap, int); |
precision = (int)va_arg(ap, int); |
if (precision < 0) { |
/* ignore negative precision */ |
precision = 0; |
583,6 → 585,9 |
qualifier = PrintfQualifierLongLong; |
} |
break; |
case 'z': /* unative_t */ |
qualifier = PrintfQualifierNative; |
break; |
default: |
/* default type */ |
qualifier = PrintfQualifierInt; |
622,7 → 627,7 |
* Integer values |
*/ |
case 'P': /* pointer */ |
flags |= __PRINTF_FLAG_BIGCHARS; |
flags |= __PRINTF_FLAG_BIGCHARS; |
case 'p': |
flags |= __PRINTF_FLAG_PREFIX; |
base = 16; |
665,28 → 670,34 |
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; |
case PrintfQualifierNative: |
size = sizeof(unative_t); |
number = (uint64_t)va_arg(ap, unative_t); |
break; |
default: /* Unknown qualifier */ |
counter = -counter; |
goto out; |
697,7 → 708,7 |
flags |= __PRINTF_FLAG_NEGATIVE; |
if (size == sizeof(uint64_t)) { |
number = -((int64_t) number); |
number = -((int64_t)number); |
} else { |
number = ~number; |
number &= |
723,7 → 734,7 |
} |
if (i > j) { |
if ((retval = printf_putnchars(&fmt[j], (unative_t) (i - j), |
if ((retval = printf_putnchars(&fmt[j], (unative_t)(i - j), |
ps)) < 0) { /* error */ |
counter = -counter; |
goto out; |
733,6 → 744,7 |
} |
out: |
return counter; |
} |
/branches/dd/kernel/generic/src/printf/vprintf.c |
---|
37,8 → 37,6 |
#include <putchar.h> |
#include <synch/spinlock.h> |
#include <arch/asm.h> |
#include <arch/types.h> |
#include <typedefs.h> |
SPINLOCK_INITIALIZE(printf_lock); /**< vprintf spinlock */ |
62,13 → 60,13 |
{ |
struct printf_spec ps = {(int(*)(void *, size_t, void *)) vprintf_write, NULL}; |
ipl_t ipl = interrupts_disable(); |
int irqpri = interrupts_disable(); |
spinlock_lock(&printf_lock); |
int ret = printf_core(fmt, &ps, ap); |
spinlock_unlock(&printf_lock); |
interrupts_restore(ipl); |
interrupts_restore(irqpri); |
return ret; |
} |
/branches/dd/kernel/generic/src/console/cmd.c |
---|
50,7 → 50,6 |
#include <arch.h> |
#include <config.h> |
#include <func.h> |
#include <string.h> |
#include <macros.h> |
#include <debug.h> |
#include <symtab.h> |
399,17 → 398,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 */ |
462,7 → 461,7 |
&uptime_info, |
&halt_info, |
&help_info, |
&ipc_info, |
&ipc_task_info, |
&set4_info, |
&slabs_info, |
&symaddr_info, |
502,7 → 501,7 |
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); |
} |
} |
515,31 → 514,23 |
*/ |
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 (strlen(hlp->name) > len) |
len = strlen(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); |
spinlock_unlock(&cmd_lock); |
return 1; |
} |
572,7 → 563,7 |
/* This doesn't have to be very accurate */ |
unative_t sec = uptime->seconds1; |
printf("Up %" PRIun " days, %" PRIun " hours, %" PRIun " minutes, %" PRIun " seconds\n", |
printf("Up %u days, %u hours, %u minutes, %u seconds\n", |
sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60); |
return 1; |
625,9 → 616,14 |
{ |
uintptr_t symaddr; |
char *symbol; |
unative_t (*fnc)(void); |
fncptr_t fptr; |
unative_t (*f)(void); |
#ifdef ia64 |
struct { |
unative_t f; |
unative_t gp; |
} fptr; |
#endif |
symaddr = get_symbol_addr((char *) argv->buffer); |
if (!symaddr) |
printf("Symbol %s not found.\n", argv->buffer); |
636,9 → 632,15 |
printf("Duplicate symbol, be more specific.\n"); |
} else { |
symbol = get_symtab_entry(symaddr); |
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()); |
printf("Calling %s() (%.*p)\n", symbol, sizeof(uintptr_t) * 2, symaddr); |
#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; |
678,10 → 680,15 |
{ |
uintptr_t symaddr; |
char *symbol; |
unative_t (*fnc)(unative_t, ...); |
unative_t (*f)(unative_t,...); |
unative_t arg1 = argv[1].intval; |
fncptr_t fptr; |
#ifdef ia64 |
struct { |
unative_t f; |
unative_t gp; |
}fptr; |
#endif |
symaddr = get_symbol_addr((char *) argv->buffer); |
if (!symaddr) |
printf("Symbol %s not found.\n", argv->buffer); |
690,9 → 697,16 |
printf("Duplicate symbol, be more specific.\n"); |
} else { |
symbol = get_symtab_entry(symaddr); |
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)); |
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; |
703,11 → 717,16 |
{ |
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; |
#ifdef ia64 |
struct { |
unative_t f; |
unative_t gp; |
}fptr; |
#endif |
symaddr = get_symbol_addr((char *) argv->buffer); |
if (!symaddr) |
printf("Symbol %s not found.\n", argv->buffer); |
716,10 → 735,16 |
printf("Duplicate symbol, be more specific.\n"); |
} else { |
symbol = get_symtab_entry(symaddr); |
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)); |
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; |
730,12 → 755,17 |
{ |
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; |
#ifdef ia64 |
struct { |
unative_t f; |
unative_t gp; |
}fptr; |
#endif |
symaddr = get_symbol_addr((char *) argv->buffer); |
if (!symaddr) |
printf("Symbol %s not found.\n", argv->buffer); |
744,10 → 774,16 |
printf("Duplicate symbol, be more specific.\n"); |
} else { |
symbol = get_symtab_entry(symaddr); |
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)); |
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; |
820,7 → 856,7 |
} else { |
if (pointer) |
addr = (uint32_t *)(*(unative_t *)addr); |
printf("Writing %#" PRIx64 " -> %p\n", arg1, addr); |
printf("Writing 0x%x -> %.*p\n", arg1, sizeof(uintptr_t) * 2, addr); |
*addr = arg1; |
} |
901,7 → 937,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; |
} |
940,11 → 976,8 |
int cmd_continue(cmd_arg_t *argv) |
{ |
printf("The kernel will now relinquish the console.\n"); |
release_console(); |
if ((kconsole_notify) && (kconsole_irq.notif_cfg.notify)) |
ipc_irq_send_msg_0(&kconsole_irq); |
printf("Use userspace controls to redraw the screen.\n"); |
arch_release_console(); |
return 1; |
} |
957,23 → 990,18 |
*/ |
int cmd_tests(cmd_arg_t *argv) |
{ |
size_t len = 0; |
test_t *test; |
for (test = tests; test->name != NULL; test++) { |
if (strlen(test->name) > len) |
len = strlen(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,7 → 1025,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"); |
1025,7 → 1053,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 */ |
1053,7 → 1081,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) { |
1066,7 → 1094,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); |
/branches/dd/kernel/generic/src/console/console.c |
---|
35,59 → 35,30 |
#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/device.h> |
#include <ddi/irq.h> |
#include <ddi/ddi.h> |
#include <ipc/irq.h> |
#include <arch.h> |
#include <func.h> |
#include <print.h> |
#include <atomic.h> |
#define KLOG_SIZE PAGE_SIZE |
#define KLOG_LATENCY 8 |
/** Kernel log cyclic buffer */ |
static char klog[KLOG_SIZE] __attribute__ ((aligned (PAGE_SIZE))); |
/** Kernel log initialized */ |
static bool klog_inited = false; |
/** First kernel log characters */ |
static index_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; |
/** Silence output */ |
bool silent = false; |
/** Kernel log spinlock */ |
SPINLOCK_INITIALIZE(klog_lock); |
/** Physical memory area used for klog buffer */ |
static parea_t klog_parea; |
/* |
* For now, we use 0 as INR. |
* However, it is therefore desirable to have architecture specific |
* definition of KLOG_VIRT_INR in the future. |
#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 |
*/ |
#define KLOG_VIRT_INR 0 |
static void null_putchar(chardev_t *d, const char ch) |
{ |
if (offset >= BUFLEN) |
offset = 0; |
debug_buffer[offset++] = ch; |
} |
static irq_t klog_irq; |
static chardev_operations_t null_stdout_ops = { |
.suspend = NULL, |
.resume = NULL, |
.write = NULL, |
.read = NULL |
.write = null_putchar |
}; |
chardev_t null_stdout = { |
95,88 → 66,10 |
.op = &null_stdout_ops |
}; |
/** Allways refuse IRQ ownership. |
* |
* This is not a real IRQ, so we always decline. |
* |
* @return Always returns IRQ_DECLINE. |
*/ |
static irq_ownership_t klog_claim(irq_t *irq) |
{ |
return IRQ_DECLINE; |
} |
static void stdin_suspend(chardev_t *d) |
{ |
} |
static void stdin_resume(chardev_t *d) |
{ |
} |
static chardev_operations_t stdin_ops = { |
.suspend = stdin_suspend, |
.resume = stdin_resume, |
}; |
/** Standard input character device */ |
static chardev_t _stdin; |
/** Standard input character device. */ |
chardev_t *stdin = NULL; |
chardev_t *stdout = &null_stdout; |
void console_init(void) |
{ |
chardev_initialize("stdin", &_stdin, &stdin_ops); |
stdin = &_stdin; |
} |
/** Initialize kernel logging facility |
* |
* 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. |
*/ |
void klog_init(void) |
{ |
void *faddr = (void *) KA2PA(klog); |
ASSERT((uintptr_t) faddr % FRAME_SIZE == 0); |
ASSERT(KLOG_SIZE % FRAME_SIZE == 0); |
devno_t devno = device_assign_devno(); |
klog_parea.pbase = (uintptr_t) faddr; |
klog_parea.frames = SIZE2FRAMES(KLOG_SIZE); |
ddi_parea_register(&klog_parea); |
sysinfo_set_item_val("klog.faddr", NULL, (unative_t) faddr); |
sysinfo_set_item_val("klog.pages", NULL, SIZE2FRAMES(KLOG_SIZE)); |
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); |
spinlock_lock(&klog_lock); |
klog_inited = true; |
spinlock_unlock(&klog_lock); |
} |
void grab_console(void) |
{ |
silent = false; |
arch_grab_console(); |
} |
void release_console(void) |
{ |
silent = true; |
arch_release_console(); |
} |
/** Get character from character device. Do not echo character. |
* |
* @param chardev Character device. |
197,10 → 90,10 |
return chardev->op->read(chardev); |
/* no other way of interacting with user, halt */ |
if (CPU) |
printf("cpu%u: ", CPU->id); |
printf("cpu%d: ", CPU->id); |
else |
printf("cpu: "); |
printf("halted (no kconsole)\n"); |
printf("halted - no kconsole\n"); |
cpu_halt(); |
} |
232,7 → 125,7 |
{ |
index_t index = 0; |
char ch; |
while (index < buflen) { |
ch = _getc(chardev); |
if (ch == '\b') { |
246,7 → 139,7 |
continue; |
} |
putchar(ch); |
if (ch == '\n') { /* end of string => write 0, return */ |
buf[index] = '\0'; |
return (count_t) index; |
266,60 → 159,10 |
return ch; |
} |
void klog_update(void) |
{ |
spinlock_lock(&klog_lock); |
if ((klog_inited) && (klog_irq.notif_cfg.notify) && (klog_uspace > 0)) { |
ipc_irq_send_msg_3(&klog_irq, klog_start, klog_len, klog_uspace); |
klog_uspace = 0; |
} |
spinlock_unlock(&klog_lock); |
} |
void putchar(char c) |
{ |
spinlock_lock(&klog_lock); |
if ((klog_stored > 0) && (stdout->op->write)) { |
/* Print charaters stored in kernel log */ |
index_t i; |
for (i = klog_len - klog_stored; i < klog_len; i++) |
stdout->op->write(stdout, klog[(klog_start + i) % KLOG_SIZE], silent); |
klog_stored = 0; |
} |
/* Store character in the cyclic kernel log */ |
klog[(klog_start + klog_len) % KLOG_SIZE] = c; |
if (klog_len < KLOG_SIZE) |
klog_len++; |
else |
klog_start = (klog_start + 1) % KLOG_SIZE; |
if (stdout->op->write) |
stdout->op->write(stdout, c, 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) || (c == '\n')) |
update = true; |
else |
update = false; |
spinlock_unlock(&klog_lock); |
if (update) |
klog_update(); |
stdout->op->write(stdout, c); |
} |
/** @} |
/branches/dd/kernel/generic/src/console/klog.c |
---|
0,0 → 1,154 |
/* |
* 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.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_2(&klog_irq, klogpos, ret); |
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/dd/kernel/generic/src/console/kconsole.c |
---|
49,11 → 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> |
/** Simple kernel console. |
* |
86,39 → 83,10 |
index_t *end); |
static char history[KCONSOLE_HISTORY][MAX_CMDLINE] = {}; |
/* |
* For now, we use 0 as INR. |
* However, it is therefore desirable to have architecture specific |
* definition of KCONSOLE_VIRT_INR in the future. |
*/ |
#define KCONSOLE_VIRT_INR 0 |
bool kconsole_notify = false; |
irq_t kconsole_irq; |
/** Allways refuse IRQ ownership. |
* |
* This is not a real IRQ, so we always decline. |
* |
* @return Always returns IRQ_DECLINE. |
* |
*/ |
static irq_ownership_t kconsole_claim(irq_t *irq) |
{ |
return IRQ_DECLINE; |
} |
/** 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++) |
126,29 → 94,6 |
} |
/** Initialize kconsole notification mechanism |
* |
* Initialize the virtual IRQ notification mechanism. |
* |
*/ |
void kconsole_notify_init(void) |
{ |
devno_t devno = device_assign_devno(); |
sysinfo_set_item_val("kconsole.present", NULL, true); |
sysinfo_set_item_val("kconsole.devno", NULL, devno); |
sysinfo_set_item_val("kconsole.inr", NULL, KCONSOLE_VIRT_INR); |
irq_initialize(&kconsole_irq); |
kconsole_irq.devno = devno; |
kconsole_irq.inr = KCONSOLE_VIRT_INR; |
kconsole_irq.claim = kconsole_claim; |
irq_register(&kconsole_irq); |
kconsole_notify = true; |
} |
/** Register kconsole command. |
* |
* @param cmd Structure describing the command. |
224,7 → 169,7 |
} |
/** 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 = strlen(name); |
const char *curname; |
258,7 → 203,7 |
*/ |
static int cmdtab_compl(char *name) |
{ |
static char output[MAX_SYMBOL_NAME + 1]; |
static char output[MAX_SYMBOL_NAME+1]; |
link_t *startpos = NULL; |
const char *foundtxt; |
int found = 0; |
268,7 → 213,7 |
while ((foundtxt = cmdtab_search_one(name, &startpos))) { |
startpos = startpos->next; |
if (!found) |
strncpy(output, foundtxt, strlen(foundtxt) + 1); |
strncpy(output, foundtxt, strlen(foundtxt)+1); |
else { |
for (i = 0; output[i] && foundtxt[i] && |
output[i] == foundtxt[i]; i++) |
295,11 → 240,11 |
} |
static char *clever_readline(const char *prompt, chardev_t *input) |
static char * clever_readline(const char *prompt, chardev_t *input) |
{ |
static int histposition = 0; |
static char tmp[MAX_CMDLINE + 1]; |
static char tmp[MAX_CMDLINE+1]; |
int curlen = 0, position = 0; |
char *current = history[histposition]; |
int i; |
312,8 → 257,7 |
if (c == '\n') { |
putchar(c); |
break; |
} |
if (c == '\b') { /* Backspace */ |
} if (c == '\b') { /* Backspace */ |
if (position == 0) |
continue; |
for (i = position; i < curlen; i++) |
456,15 → 400,11 |
return current; |
} |
/** Kernel console prompt. |
/** Kernel console managing thread. |
* |
* @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. |
* |
*/ |
void kconsole(char *prompt, char *msg, bool kcon) |
void kconsole(void *prompt) |
{ |
cmd_info_t *cmd_info; |
count_t len; |
471,42 → 411,25 |
char *cmdline; |
if (!stdin) { |
LOG("No stdin for kernel console"); |
printf("%s: no stdin\n", __func__); |
return; |
} |
if (msg) |
printf("%s", msg); |
if (kcon) |
_getc(stdin); |
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 ((!kcon) |
&& (strncmp(cmd_info->name, "exit", min(strlen(cmd_info->name), 5)) == 0)) |
if (strncmp(cmd_info->name, "exit", |
min(strlen(cmd_info->name), 5)) == 0) |
break; |
(void) cmd_info->func(cmd_info->argv); |
} |
} |
/** Kernel console managing thread. |
* |
*/ |
void kconsole_thread(void *data) |
{ |
kconsole("kconsole", "Kernel console ready (press any key to activate)\n", true); |
} |
static int parse_int_arg(char *text, size_t len, unative_t *result) |
{ |
static char symname[MAX_SYMBOL_NAME]; |
620,8 → 543,7 |
buf = (char *) cmd->argv[i].buffer; |
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'; |
buf[min((end - start) + 1, cmd->argv[i].len - 1)] = '\0'; |
break; |
case ARG_TYPE_INT: |
if (parse_int_arg(cmdline + start, end - start + 1, |
638,8 → 560,8 |
'\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)) { |
} 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"); |
/branches/dd/kernel/generic/src/console/chardev.c |
---|
42,7 → 42,7 |
* @param chardev Character device. |
* @param op Implementation of character device operations. |
*/ |
void chardev_initialize(char *name, chardev_t *chardev, |
void chardev_initialize(char *name,chardev_t *chardev, |
chardev_operations_t *op) |
{ |
chardev->name = name; |
/branches/dd/kernel/generic/src/syscall/syscall.c |
---|
38,7 → 38,6 |
#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> |
47,43 → 46,40 |
#include <debug.h> |
#include <ipc/sysipc.h> |
#include <synch/futex.h> |
#include <synch/smc.h> |
#include <ddi/ddi.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> |
/** Print using kernel facility |
* |
* Print to kernel log. |
* |
* Some simulators can print only through kernel. Userspace can use |
* this syscall to facilitate it. |
*/ |
static unative_t sys_klog(int fd, const void * buf, size_t count) |
static unative_t sys_io(int fd, const void * buf, size_t count) |
{ |
size_t i; |
char *data; |
int rc; |
if (count > PAGE_SIZE) |
return ELIMIT; |
data = (char *) malloc(count, 0); |
if (!data) |
return ENOMEM; |
if (count > 0) { |
data = (char *) malloc(count + 1, 0); |
if (!data) |
return ENOMEM; |
rc = copy_from_uspace(data, buf, count); |
if (rc) { |
free(data); |
return rc; |
} |
data[count] = 0; |
printf("%s", data); |
rc = copy_from_uspace(data, buf, count); |
if (rc) { |
free(data); |
} else |
klog_update(); |
return rc; |
} |
for (i = 0; i < count; i++) |
putchar(data[i]); |
free(data); |
return count; |
} |
91,21 → 87,10 |
/** Tell kernel to get keyboard/console access again */ |
static unative_t sys_debug_enable_console(void) |
{ |
#ifdef CONFIG_KCONSOLE |
grab_console(); |
return true; |
#else |
return false; |
#endif |
arch_grab_console(); |
return 0; |
} |
/** Tell kernel to relinquish keyboard/console access */ |
static unative_t sys_debug_disable_console(void) |
{ |
release_console(); |
return true; |
} |
/** 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) |
112,13 → 97,11 |
{ |
unative_t rc; |
#ifdef CONFIG_UDEBUG |
udebug_syscall_event(a1, a2, a3, a4, a5, a6, id, 0, false); |
#endif |
if (id < SYSCALL_END) { |
if (id < SYSCALL_END) |
rc = syscall_table[id](a1, a2, a3, a4, a5, a6); |
} else { |
printf("Task %" PRIu64": Unknown syscall %#" PRIxn, TASK->taskid, id); |
else { |
klog_printf("TASK %llu: Unknown syscall id %llx", TASK->taskid, |
id); |
task_kill(TASK->taskid); |
thread_exit(); |
} |
125,22 → 108,12 |
if (THREAD->interrupted) |
thread_exit(); |
#ifdef CONFIG_UDEBUG |
udebug_syscall_event(a1, a2, a3, a4, a5, a6, id, rc, true); |
/* |
* Stopping point needed for tasks that only invoke non-blocking |
* system calls. |
*/ |
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. */ |
147,20 → 120,15 |
(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. */ |
171,7 → 139,6 |
(syshandler_t) sys_ipc_answer_fast, |
(syshandler_t) sys_ipc_answer_slow, |
(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, |
191,10 → 158,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/dd/kernel/generic/src/adt/avl.c |
---|
43,7 → 43,7 |
* |
* Every node has a pointer to its parent which allows insertion of multiple |
* identical keys into the tree. |
* |
* |
* Be careful when using this tree because of the base atribute which is added |
* to every inserted node key. There is no rule in which order nodes with the |
* same key are visited. |
/branches/dd/kernel/generic/src/adt/btree.c |
---|
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); |
} |
} |
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); |
} |
} |
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. |
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. |
693,7 → 693,7 |
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. |
970,7 → 970,7 |
printf("("); |
for (i = 0; i < node->keys; i++) { |
printf("%" PRIu64 "%s", node->key[i], i < node->keys - 1 ? "," : ""); |
printf("%llu%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("%llu%s", node->key[i], i < node->keys - 1 ? "," : ""); |
printf(")"); |
} |
printf("\n"); |
/branches/dd/kernel/generic/src/adt/hash_table.c |
---|
61,9 → 61,9 |
h->entry = (link_t *) malloc(m * sizeof(link_t), 0); |
if (!h->entry) { |
panic("Cannot allocate memory for hash table."); |
panic("cannot allocate memory for hash table\n"); |
} |
memsetb(h->entry, m * sizeof(link_t), 0); |
memsetb((uintptr_t) h->entry, m * sizeof(link_t), 0); |
for (i = 0; i < m; i++) |
list_initialize(&h->entry[i]); |
/branches/dd/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,22 → 76,13 |
#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. |
*/ |
123,9 → 110,6 |
.remove_callback = NULL /* not used */ |
}; |
/** Number of buckets in either of the hash tables. */ |
static count_t buckets; |
/** Initialize IRQ subsystem. |
* |
* @param inrs Numbers of unique IRQ numbers or INRs. |
133,7 → 117,6 |
*/ |
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 |
140,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. |
160,12 → 136,21 |
*/ |
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->preack = false; |
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. |
172,10 → 157,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) |
{ |
186,101 → 170,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. |
299,7 → 270,7 |
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. |
333,8 → 304,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)); |
393,7 → 363,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); |
/branches/dd/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,82 |
* |
* @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. |
*/ |
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); |
count_t znum = find_zone(ADDR2PFN(pf), pages, 0); |
if (znum == (count_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; |
} |
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. |
*/ |
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 ENOENT; |
} |
err: |
spinlock_unlock(&zones.lock); |
interrupts_restore(ipl); |
return ENOENT; |
map: |
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 → 169,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 → 200,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,8 → 220,7 |
* @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) |
{ |
250,15 → 234,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 → 251,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/dd/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/dd/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); |