Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3972 → Rev 3973

/trunk/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
 
/trunk/kernel/generic/include/mm/frame.h
39,6 → 39,7
#include <arch/types.h>
#include <adt/list.h>
#include <mm/buddy.h>
#include <synch/spinlock.h>
#include <arch/mm/page.h>
#include <arch/mm/frame.h>
 
67,15 → 68,52
 
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
#define ZONE_RESERVED 0x08
/** Zone is used by firmware (not available for allocation) */
#define ZONE_FIRMWARE 0x10
#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);
98,6 → 136,11
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) \
117,6 → 160,7
extern void frame_free(uintptr_t);
extern void frame_reference_add(pfn_t);
 
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);
/trunk/kernel/generic/include/mm/page.h
61,7 → 61,6
extern void map_structure(uintptr_t s, size_t size);
 
extern uintptr_t hw_map(uintptr_t physaddr, size_t size);
extern void hw_area(void);
 
#endif
 
/trunk/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
47,7 → 47,7
#include <mm/as.h>
#include <synch/spinlock.h>
#include <syscall/copy.h>
#include <adt/list.h>
#include <adt/btree.h>
#include <arch.h>
#include <align.h>
#include <errno.h>
55,13 → 55,13
/** This lock protects the parea_btree. */
SPINLOCK_INITIALIZE(parea_lock);
 
/** List with enabled physical memory areas. */
static LIST_INITIALIZE(parea_head);
/** B+tree with enabled physical memory areas. */
static btree_t parea_btree;
 
/** Initialize DDI. */
void ddi_init(void)
{
hw_area();
btree_create(&parea_btree);
}
 
/** Enable piece of physical memory for mapping by physmem_map().
68,22 → 68,16
*
* @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;
ipl = interrupts_disable();
ipl_t ipl = interrupts_disable();
spinlock_lock(&parea_lock);
/*
* TODO: we should really check for overlaps here.
* However, we should be safe because the kernel is pretty sane.
* We don't check for overlaps here as the kernel is pretty sane.
*/
link_initialize(&parea->link);
list_append(&parea->link, &parea_head);
btree_insert(&parea_btree, (btree_key_t) parea->pbase, parea, NULL);
spinlock_unlock(&parea_lock);
interrupts_restore(ipl);
91,64 → 85,83
 
/** 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, 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, 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.
*
*/
static int ddi_physmem_map(uintptr_t pf, uintptr_t vp, pfn_t pages, int flags)
static int ddi_physmem_map(uintptr_t pf, uintptr_t vp, count_t pages, int flags)
{
ipl_t ipl;
cap_t caps;
mem_backend_data_t backend_data;
ASSERT(TASK);
ASSERT((pf % FRAME_SIZE) == 0);
ASSERT((vp % PAGE_SIZE) == 0);
backend_data.base = pf;
backend_data.frames = pages;
/*
* Make sure the caller is authorised to make this syscall.
*/
caps = cap_get(TASK);
cap_t caps = cap_get(TASK);
if (!(caps & CAP_MEM_MANAGER))
return EPERM;
ipl = interrupts_disable();
mem_backend_data_t backend_data;
backend_data.base = pf;
backend_data.frames = pages;
/*
* Check if the physical memory area is enabled for mapping.
*/
spinlock_lock(&parea_lock);
ipl_t ipl = interrupts_disable();
bool fnd = false;
link_t *cur;
/* Find the zone of the physical memory */
spinlock_lock(&zones.lock);
count_t znum = find_zone(ADDR2PFN(pf), pages, 0);
for (cur = parea_head.next; cur != &parea_head; cur = cur->next) {
parea_t *parea = list_get_instance(cur, parea_t, link);
if ((parea->pbase <= pf) && (ADDR2PFN(pf - parea->pbase) + pages <= parea->frames)) {
fnd = true;
break;
}
if (znum == (count_t) -1) {
/* Frames not found in any zones
* -> assume it is hardware device and allow mapping
*/
spinlock_unlock(&zones.lock);
goto map;
}
spinlock_unlock(&parea_lock);
if (zones.info[znum].flags & ZONE_FIRMWARE) {
/* Frames are part of firmware */
spinlock_unlock(&zones.lock);
goto map;
}
if (!fnd) {
/*
* Physical memory area cannot be mapped.
if (zone_flags_available(zones.info[znum].flags)) {
/* Frames are part of physical memory, check if the memory
* region is enabled for mapping.
*/
interrupts_restore(ipl);
return ENOENT;
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;
}
err:
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return ENOENT;
map:
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.
174,28 → 187,24
* @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.
*/
caps = cap_get(TASK);
cap_t caps = cap_get(TASK);
if (!(caps & CAP_IO_MANAGER))
return EPERM;
ipl = interrupts_disable();
ipl_t ipl = interrupts_disable();
spinlock_lock(&tasks_lock);
t = task_find_by_id(id);
task_t *task = task_find_by_id(id);
if ((!t) || (!context_check(CONTEXT, t->context))) {
if ((!task) || (!context_check(CONTEXT, task->context))) {
/*
* There is no task with the specified ID
* or the task belongs to a different security
205,15 → 214,16
interrupts_restore(ipl);
return ENOENT;
}
 
/* Lock the task and release the lock protecting tasks_btree. */
spinlock_lock(&t->lock);
spinlock_lock(&task->lock);
spinlock_unlock(&tasks_lock);
 
rc = ddi_iospace_enable_arch(t, ioaddr, size);
spinlock_unlock(&t->lock);
int rc = ddi_iospace_enable_arch(task, ioaddr, size);
spinlock_unlock(&task->lock);
interrupts_restore(ipl);
return rc;
}
 
225,13 → 235,14
* @param flags Flags of newly mapped pages
*
* @return 0 on success, otherwise it returns error code found in errno.h
*/
*
*/
unative_t sys_physmem_map(unative_t phys_base, unative_t virt_base,
unative_t pages, unative_t flags)
{
return (unative_t) ddi_physmem_map(ALIGN_DOWN((uintptr_t) phys_base,
FRAME_SIZE), ALIGN_DOWN((uintptr_t) virt_base, PAGE_SIZE),
(pfn_t) pages, (int) flags);
(count_t) pages, (int) flags);
}
 
/** Wrapper for SYS_ENABLE_IOSPACE syscall.
239,16 → 250,15
* @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;
rc = copy_from_uspace(&arg, uspace_io_arg, sizeof(ddi_ioarg_t));
int 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);
}
256,19 → 266,23
/** 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;
}
 
/trunk/kernel/generic/src/mm/frame.c
48,7 → 48,6
#include <panic.h>
#include <debug.h>
#include <adt/list.h>
#include <synch/spinlock.h>
#include <synch/mutex.h>
#include <synch/condvar.h>
#include <arch/asm.h>
60,42 → 59,9
#include <macros.h>
#include <config.h>
 
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;
zones_t zones;
 
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;
 
static zones_t zones;
 
/*
* Synchronization primitives used to sleep when there is no memory
* available.
*/
128,11 → 94,6
return (frame - zone->frames);
}
 
static inline bool zone_flags_available(zone_flags_t flags)
{
return ((flags & (ZONE_RESERVED | ZONE_FIRMWARE)) == 0);
}
 
/** Initialize frame structure.
*
* @param frame Frame structure to be initialized.
180,8 → 141,11
/* Move other zones up */
count_t j;
for (j = i; j < zones.count; j++)
zones.info[j + 1] = zones.info[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];
}
zones.count++;
206,18 → 170,19
return total;
}
 
/** Find a zone with a given frame.
/** 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.
*
*/
static count_t find_zone(pfn_t frame, count_t hint)
count_t find_zone(pfn_t frame, count_t count, count_t hint)
{
if (hint >= zones.count)
hint = 0;
225,7 → 190,7
count_t i = hint;
do {
if ((zones.info[i].base <= frame)
&& (zones.info[i].base + zones.info[i].count > frame))
&& (zones.info[i].base + zones.info[i].count >= frame + count))
return i;
i++;
765,10 → 730,14
ADDR2PFN(KA2PA((uintptr_t) zones.info[z2].frames)),
zones.info[z2].count);
/* Shift existing zones */
/* Move zones down */
count_t i;
for (i = z2 + 1; i < zones.count; i++)
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--;
errout:
964,7 → 933,7
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
count_t znum = find_zone(pfn, hint);
count_t znum = find_zone(pfn, 1, hint);
ASSERT(znum != (count_t) -1);
980,7 → 949,7
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
count_t znum = find_zone(pfn, hint);
count_t znum = find_zone(pfn, 1, hint);
ASSERT(znum != (count_t) -1);
1111,7 → 1080,7
* First, find host frame zone for addr.
*/
pfn_t pfn = ADDR2PFN(frame);
count_t znum = find_zone(pfn, NULL);
count_t znum = find_zone(pfn, 1, NULL);
ASSERT(znum != (count_t) -1);
1150,7 → 1119,7
/*
* First, find host frame zone for addr.
*/
count_t znum = find_zone(pfn, NULL);
count_t znum = find_zone(pfn, 1, NULL);
ASSERT(znum != (count_t) -1);
1168,7 → 1137,7
count_t i;
for (i = 0; i < count; i++) {
count_t znum = find_zone(start + i, 0);
count_t znum = find_zone(start + i, 1, 0);
if (znum == (count_t) -1) /* PFN not found */
continue;
1237,13 → 1206,13
void zone_print_list(void)
{
#ifdef __32_BITS__
printf("# base address flags free frames busy frames\n");
printf("-- ------------ -------- ------------ ------------\n");
printf("# base address frames flags free frames busy frames\n");
printf("-- ------------ ------------ -------- ------------ ------------\n");
#endif
 
#ifdef __64_BITS__
printf("# base address flags free frames busy frames\n");
printf("-- -------------------- -------- ------------ ------------\n");
printf("# base address frames flags free frames busy frames\n");
printf("-- -------------------- ------------ -------- ------------ ------------\n");
#endif
/*
1269,6 → 1238,7
}
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;
1278,23 → 1248,25
bool available = zone_flags_available(flags);
printf("%-2" PRIc, i);
#ifdef __32_BITS__
printf("%-2" PRIc " %10p %c%c%c ", i, base,
available ? 'A' : ' ',
(flags & ZONE_RESERVED) ? 'R' : ' ',
(flags & ZONE_FIRMWARE) ? 'F' : ' ');
printf(" %10p", base);
#endif
#ifdef __64_BITS__
printf("%-2" PRIc " %18p %c%c%c ", i, base,
printf(" %18p", base);
#endif
printf(" %12" PRIc " %c%c%c ", count,
available ? 'A' : ' ',
(flags & ZONE_RESERVED) ? 'R' : ' ',
(flags & ZONE_FIRMWARE) ? 'F' : ' ');
#endif
if (available)
printf("%12" PRIc " %12" PRIc,
free_count, busy_count);
printf("\n");
}
}