Skip to content

Commit

Permalink
Feature: Page Frame Allocator
Browse files Browse the repository at this point in the history
  • Loading branch information
ppenna committed Dec 14, 2018
1 parent 778d46e commit 58dbdae
Show file tree
Hide file tree
Showing 2 changed files with 237 additions and 0 deletions.
124 changes: 124 additions & 0 deletions include/nanvix/mm.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,128 @@

/**@}*/

/*============================================================================*
* Page Frame Allocator *
*============================================================================*/

/**
* @addtogroup kernel-mm-frame Frame Allocator
* @ingroup kernel-mm
*
* @brief Page Frame Allocator
*/
/**@{*/

/**
* @brief Number of page frames for user use.
*/
#define NUM_UFRAMES (UMEM_SIZE/PAGE_SIZE)

/**
* @param Null frame.
*/
#define FRAME_NULL ((frame_t) -1)

/**
* @brief Asserts if a frame ID is valid.
*
* The frame_is_valid_id() function asserts whether or not the
* frame @p ID is valid.
*
* @returns If @p id is valid, non zero is returned. Otherwise,
* zero is returned instead.
*
* @author Pedro Henrique Penna
*/
static inline int frame_is_valid_id(int id)
{
return ((id >= 0) && (id < NUM_UFRAMES));
}

/**
* @brief Converts an ID of a user page frame to a page frame number.
*
* @param id ID of target user page frame.
*
* @returns Frame number of target user page frame.
*
* @author Pedro Henrique Penna
*/
static inline frame_t frame_id_to_num(int id)
{
/* Invalid ID. */
if (!frame_is_valid_id(id))
return (FRAME_NULL);

return ((UBASE_PHYS >> PAGE_SHIFT) + id);
}

/**
* @brief Asserts if a frame number is valid.
*
* The frame_is_valid_num() function asserts whether or not the
* frame number @p frame is valid.
*
* @returns If @p frame is valid, non zero is returned. Otherwise,
* zero is returned instead.
*
* @author Pedro Henrique Penna
*/
static inline int frame_is_valid_num(frame_t frame)
{
return (
(frame >= (UBASE_PHYS >> PAGE_SHIFT)) &&
(frame < ((UBASE_PHYS >> PAGE_SHIFT) + NUM_UFRAMES))
);
}

/**
* @brief Converts a page frame number to an ID of a user page frame.
*
* @param frame Number of the target page frame.
*
* @returns ID of target user page frame.
*
* @author Pedro Henrique Penna
*/
static inline int frame_num_to_id(frame_t frame)
{
/* Invalid frame. */
if (!frame_is_valid_num(frame))
return (-1);

return (frame - (UBASE_PHYS >> PAGE_SHIFT));
}

/**
* @brief Allocates a page frame.
*
* @returns Upon successful completion, the number of the
* allocated page frame is returned. Upon failure, @p FRAME_NULL
* is returned instead.
*/
EXTERN frame_t frame_alloc(void);

/**
* @brief Frees a page frame.
*
* @param frame Number of the target page frame.
*
* @returns Upon successful completion, zero is returned. Upon
* failure, a negative error code is returned instead.
*/
EXTERN int frame_free(frame_t frame);

/**
* @brief Runs unit tests on the frame allocator.
*/
EXTERN void frame_test_driver(void);

/**
* @brief Initializes the frame allocator.
*/
EXTERN void frame_init(void);

/**@}*/

#endif /** NANVIX_MM_H_ */
113 changes: 113 additions & 0 deletions src/kernel/mm/frame.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* MIT License
*
* Copyright(c) 2011-2018 Pedro Henrique Penna <pedrohenriquepenna@gmail.com>
* 2015-2016 Davidson Francis <davidsondfgl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#include <nanvix/hal/hal.h>
#include <nanvix/const.h>
#include <nanvix/mm.h>
#include <nanvix/klib.h>
#include <errno.h>

/**
* @brief Reference count for page frames.
*/
PRIVATE int frames[NUM_UFRAMES] = {0, };

/*============================================================================*
* frame_alloc() *
*============================================================================*/

/**
* The frame_alloc() function searches sequentially, for a free frame
* to be allocated. The first free frame is allocated (if any) and its
* number is returned.
*/
PUBLIC frame_t frame_alloc(void)
{
/* Search for a free frame. */
for (int i = 0; i < NUM_UFRAMES; i++)
{
/* Found it. */
if (frames[i] == 0)
{
frames[i] = 1;
hal_dcache_invalidate();

return (frame_id_to_num(i));
}
}

kprintf("mm: page frame overflow");

return (FRAME_NULL);
}

/*============================================================================*
* frame_free() *
*============================================================================*/

/**
* The frame_free() function frees a previously allocated page frame
* whose number equals to @p frame.
*/
PUBLIC int frame_free(frame_t frame)
{
if (!frame_is_valid_num(frame))
return (-EINVAL);

if (frames[frame_num_to_id(frame)] == 0)
{
kprintf("mm: double free on page frame");
return (-EFAULT);
}

frames[frame_num_to_id(frame)]--;
hal_dcache_invalidate();

return (0);
}

/*============================================================================*
* frame_init() *
*============================================================================*/

/**
* The frame_init() function initializes internal structures of the
* page frame allocator. Additionally, if the kernel is compiled
* without the @p NDEBUG build option, unit tests on the page frame
* allocator are launched once its initialization is completed.
*/
PUBLIC void frame_init(void)
{
kprintf("initializing the page frame allocator");

#ifndef __NANVIX_FAST_BOOT
for (int i = 0; i < NUM_UFRAMES; i++)
frames[i] = 0;
#endif

#ifndef NDEBUG
frame_test_driver();
#endif
}

0 comments on commit 58dbdae

Please sign in to comment.