2021-05-23 22:24:02 +08:00

185 lines
4.2 KiB
C

/*
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
* You can use this software according to the terms and conditions of the Mulan PSL v1.
* You may obtain a copy of Mulan PSL v1 at:
* http://license.coscl.org.cn/MulanPSL
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v1 for more details.
*/
#include <common/macro.h>
#include <common/types.h>
#include <common/kprint.h>
#include "slab.h"
#include "buddy.h"
/* local variables */
slab_header_t *slabs[SLAB_MAX_ORDER + 1];
/* local functions */
static inline u64 size_to_order(u64 size)
{
u64 order = 0;
int tmp = size;
while (tmp > 1) {
tmp >>= 1;
order += 1;
}
if (size > (1 << order))
order += 1;
return order;
}
static inline u64 order_to_size(u64 order)
{
return 1UL << order;
}
static void *alloc_slab_memory(u64 size)
{
struct page *p_page, *page;
void *addr;
u64 order, page_num;
void *page_addr;
int i;
order = size_to_order(size / BUDDY_PAGE_SIZE);
p_page = buddy_get_pages(&global_mem, order);
if (p_page == NULL) {
kwarn("failed to alloc_slab_memory: out of memory\n");
BUG_ON(1);
}
addr = page_to_virt(&global_mem, p_page);
//BUG_ON(check_alignment((u64)addr, SLAB_INIT_SIZE));
page_num = order_to_size(order);
for (i = 0; i < page_num; i++) {
page_addr = (void *)((u64) addr + i * BUDDY_PAGE_SIZE);
page = virt_to_page(&global_mem, page_addr);
page->slab = addr;
}
return addr;
}
static slab_header_t *init_slab_cache(int order, int size)
{
void *addr;
slab_slot_list_t *slot;
slab_header_t *slab;
u64 cnt, obj_size;
int i;
addr = alloc_slab_memory(size);
slab = (slab_header_t *) addr;
obj_size = order_to_size(order);
/* the first slot is used as metadata */
cnt = size / obj_size - 1;
slot = (slab_slot_list_t *) (addr + obj_size);
slab->free_list_head = (void *)slot;
slab->next_slab = NULL;
slab->order = order;
/* the last slot has no next one */
for (i = 0; i < cnt - 1; i++) {
slot->next_free = (void *)((u64) slot + obj_size);
slot = (slab_slot_list_t *) ((u64) slot + obj_size);
}
slot->next_free = NULL;
return slab;
}
static void *_alloc_in_slab_nolock(slab_header_t * slab_header, int order)
{
slab_slot_list_t *first_slot;
void *next_slot;
slab_header_t *next_slab;
slab_header_t *new_slab;
first_slot = (slab_slot_list_t *) (slab_header->free_list_head);
if (likely(first_slot != NULL)) {
next_slot = first_slot->next_free;
slab_header->free_list_head = next_slot;
return first_slot;
}
next_slab = slab_header->next_slab;
while (next_slab != NULL) {
first_slot = (slab_slot_list_t *) (next_slab->free_list_head);
if (likely(first_slot != NULL)) {
next_slot = first_slot->next_free;
next_slab->free_list_head = next_slot;
return first_slot;
}
next_slab = next_slab->next_slab;
}
//alloc new slab
new_slab = init_slab_cache(order, SLAB_INIT_SIZE);
new_slab->next_slab = slab_header;
slabs[order] = new_slab;
return _alloc_in_slab_nolock(new_slab, order);
}
static void *_alloc_in_slab(slab_header_t * slab_header, int order)
{
void *free_slot;
free_slot = _alloc_in_slab_nolock(slab_header, order);
return free_slot;
}
/*
* exported functions
*/
void init_slab()
{
int order;
/* slab obj size: 32, 64, 128, 256, 512, 1024, 2048 */
for (order = SLAB_MIN_ORDER; order <= SLAB_MAX_ORDER; order++) {
slabs[order] = init_slab_cache(order, SLAB_INIT_SIZE);
}
kdebug("mm: finish initing slab allocators\n");
}
void *alloc_in_slab(u64 size)
{
int order;
BUG_ON(size > order_to_size(SLAB_MAX_ORDER));
order = (int)size_to_order(size);
if (order < SLAB_MIN_ORDER)
order = SLAB_MIN_ORDER;
return _alloc_in_slab(slabs[order], order);
}
void free_in_slab(void *addr)
{
struct page *page;
slab_header_t *slab;
slab_slot_list_t *slot;
slot = (slab_slot_list_t *) addr;
page = virt_to_page(&global_mem, addr);
BUG_ON(page == NULL);
slab = page->slab;
slot->next_free = slab->free_list_head;
slab->free_list_head = slot;
}