2018-10-16 09:01:38 +00:00
/*
* Really really * really * Q & D malloc ( ) and free ( ) implementations
* just to get going . Don ' t ever let anyone see this shit . : ^ )
*/
# include "types.h"
# include "kmalloc.h"
# include "StdLib.h"
# include "i386.h"
# include "system.h"
2019-01-12 20:48:41 +00:00
# include "Process.h"
# include "Scheduler.h"
2018-11-10 15:25:59 +00:00
# include <AK/Assertions.h>
2018-10-16 09:01:38 +00:00
# define SANITIZE_KMALLOC
typedef struct
{
2018-11-16 23:11:08 +00:00
dword start ;
dword nchunk ;
2018-10-16 09:01:38 +00:00
} PACKED allocation_t ;
# define CHUNK_SIZE 128
2018-10-29 20:54:11 +00:00
# define POOL_SIZE (1024 * 1024)
2018-10-16 09:01:38 +00:00
2018-11-01 15:23:12 +00:00
# define PAGE_ALIGNED_BASE_PHYSICAL 0x300000
# define ETERNAL_BASE_PHYSICAL 0x200000
# define BASE_PHYS 0x100000
2018-10-16 09:01:38 +00:00
2018-11-02 19:41:58 +00:00
# define RANGE_SIZE 0x100000
2018-11-09 00:25:31 +00:00
static byte alloc_map [ POOL_SIZE / CHUNK_SIZE / 8 ] ;
2018-10-16 09:01:38 +00:00
2018-12-02 22:34:50 +00:00
volatile size_t sum_alloc = 0 ;
volatile size_t sum_free = POOL_SIZE ;
2018-10-31 22:19:15 +00:00
volatile size_t kmalloc_sum_eternal = 0 ;
static byte * s_next_eternal_ptr ;
2018-11-02 19:41:58 +00:00
static byte * s_end_of_eternal_range ;
2018-10-26 22:14:24 +00:00
bool is_kmalloc_address ( void * ptr )
{
2018-10-31 22:19:15 +00:00
if ( ptr > = ( byte * ) ETERNAL_BASE_PHYSICAL & & ptr < s_next_eternal_ptr )
return true ;
2018-11-09 09:03:21 +00:00
return ( dword ) ptr > = BASE_PHYS & & ( dword ) ptr < = ( BASE_PHYS + POOL_SIZE ) ;
2018-10-26 22:14:24 +00:00
}
2018-11-09 00:25:31 +00:00
void kmalloc_init ( )
2018-10-16 09:01:38 +00:00
{
memset ( & alloc_map , 0 , sizeof ( alloc_map ) ) ;
memset ( ( void * ) BASE_PHYS , 0 , POOL_SIZE ) ;
2018-10-31 22:19:15 +00:00
kmalloc_sum_eternal = 0 ;
2018-10-16 09:01:38 +00:00
sum_alloc = 0 ;
sum_free = POOL_SIZE ;
2018-10-31 22:19:15 +00:00
s_next_eternal_ptr = ( byte * ) ETERNAL_BASE_PHYSICAL ;
2018-11-02 19:41:58 +00:00
s_end_of_eternal_range = s_next_eternal_ptr + RANGE_SIZE ;
2018-10-31 22:19:15 +00:00
}
void * kmalloc_eternal ( size_t size )
{
void * ptr = s_next_eternal_ptr ;
s_next_eternal_ptr + = size ;
2018-11-02 19:41:58 +00:00
ASSERT ( s_next_eternal_ptr < s_end_of_eternal_range ) ;
2018-10-31 22:19:15 +00:00
kmalloc_sum_eternal + = size ;
return ptr ;
2018-10-16 09:01:38 +00:00
}
2018-12-26 20:31:46 +00:00
void * kmalloc_aligned ( size_t size , size_t alignment )
{
void * ptr = kmalloc ( size + alignment + sizeof ( void * ) ) ;
dword max_addr = ( dword ) ptr + alignment ;
void * aligned_ptr = ( void * ) ( max_addr - ( max_addr % alignment ) ) ;
( ( void * * ) aligned_ptr ) [ - 1 ] = ptr ;
return aligned_ptr ;
}
void kfree_aligned ( void * ptr )
{
kfree ( ( ( void * * ) ptr ) [ - 1 ] ) ;
}
2018-11-01 08:01:51 +00:00
void * kmalloc_page_aligned ( size_t size )
{
2018-12-26 20:31:46 +00:00
void * ptr = kmalloc_aligned ( size , PAGE_SIZE ) ;
dword d = ( dword ) ptr ;
ASSERT ( ( d & PAGE_MASK ) = = d ) ;
2018-11-01 08:01:51 +00:00
return ptr ;
}
2019-01-12 22:23:35 +00:00
void * kmalloc_impl ( dword size )
2018-10-16 09:01:38 +00:00
{
2018-10-24 09:07:53 +00:00
InterruptDisabler disabler ;
2018-10-23 22:51:19 +00:00
2018-11-16 23:11:08 +00:00
dword chunks_needed , chunks_here , first_chunk ;
dword real_size ;
dword i , j , k ;
2018-10-16 09:01:38 +00:00
/* We need space for the allocation_t structure at the head of the block. */
real_size = size + sizeof ( allocation_t ) ;
if ( sum_free < real_size ) {
2019-01-12 20:48:41 +00:00
kprintf ( " %s<%u> kmalloc(): PANIC! Out of memory (sucks, dude) \n sum_free=%u, real_size=%x \n " , current - > name ( ) . characters ( ) , current - > pid ( ) , sum_free , real_size ) ;
2018-10-16 09:01:38 +00:00
HANG ;
return 0L ;
}
chunks_needed = real_size / CHUNK_SIZE ;
if ( real_size % CHUNK_SIZE )
chunks_needed + + ;
chunks_here = 0 ;
first_chunk = 0 ;
for ( i = 0 ; i < ( POOL_SIZE / CHUNK_SIZE / 8 ) ; + + i )
{
2018-11-12 14:25:57 +00:00
if ( alloc_map [ i ] = = 0xff ) {
// Skip over completely full bucket.
chunks_here = 0 ;
continue ;
}
// FIXME: This scan can be optimized further with LZCNT.
2018-10-16 09:01:38 +00:00
for ( j = 0 ; j < 8 ; + + j )
{
if ( ! ( alloc_map [ i ] & ( 1 < < j ) ) )
{
if ( chunks_here = = 0 )
{
/* Mark where potential allocation starts. */
first_chunk = i * 8 + j ;
}
chunks_here + + ;
if ( chunks_here = = chunks_needed )
{
auto * a = ( allocation_t * ) ( BASE_PHYS + ( first_chunk * CHUNK_SIZE ) ) ;
2018-11-16 23:11:08 +00:00
byte * ptr = ( byte * ) a ;
2018-10-16 09:01:38 +00:00
ptr + = sizeof ( allocation_t ) ;
a - > nchunk = chunks_needed ;
a - > start = first_chunk ;
for ( k = first_chunk ; k < ( first_chunk + chunks_needed ) ; + + k )
{
alloc_map [ k / 8 ] | = 1 < < ( k % 8 ) ;
}
sum_alloc + = a - > nchunk * CHUNK_SIZE ;
sum_free - = a - > nchunk * CHUNK_SIZE ;
# ifdef SANITIZE_KMALLOC
memset ( ptr , 0xbb , ( a - > nchunk * CHUNK_SIZE ) - sizeof ( allocation_t ) ) ;
# endif
return ptr ;
}
}
else
{
/* This is in use, so restart chunks_here counter. */
chunks_here = 0 ;
}
}
}
2019-01-12 20:48:41 +00:00
kprintf ( " %s<%u> kmalloc(): PANIC! Out of memory (no suitable block for size %u) \n " , current - > name ( ) . characters ( ) , current - > pid ( ) , size ) ;
2018-10-16 09:01:38 +00:00
HANG ;
2018-10-26 20:32:35 +00:00
return nullptr ;
2018-10-16 09:01:38 +00:00
}
2018-11-09 00:25:31 +00:00
void kfree ( void * ptr )
2018-10-16 09:01:38 +00:00
{
if ( ! ptr )
return ;
2018-10-24 09:07:53 +00:00
InterruptDisabler disabler ;
2018-10-23 22:51:19 +00:00
2018-11-16 23:11:08 +00:00
allocation_t * a = ( allocation_t * ) ( ( ( ( byte * ) ptr ) - sizeof ( allocation_t ) ) ) ;
2018-10-16 09:01:38 +00:00
#if 0
2018-11-16 23:11:08 +00:00
dword hdr = ( dword ) a ;
dword mhdr = hdr & ~ 0x7 ;
2018-10-16 09:01:38 +00:00
kprintf ( " hdr / mhdr %p / %p \n " , hdr , mhdr ) ;
ASSERT ( hdr = = mhdr ) ;
# endif
2018-11-16 23:11:08 +00:00
for ( dword k = a - > start ; k < ( a - > start + a - > nchunk ) ; + + k ) {
2018-10-16 09:01:38 +00:00
alloc_map [ k / 8 ] & = ~ ( 1 < < ( k % 8 ) ) ;
}
sum_alloc - = a - > nchunk * CHUNK_SIZE ;
sum_free + = a - > nchunk * CHUNK_SIZE ;
# ifdef SANITIZE_KMALLOC
memset ( a , 0xaa , a - > nchunk * CHUNK_SIZE ) ;
# endif
}
2018-12-02 22:34:50 +00:00
void * operator new ( size_t size )
2018-10-16 09:01:38 +00:00
{
return kmalloc ( size ) ;
}
2018-12-02 22:34:50 +00:00
void * operator new [ ] ( size_t size )
2018-10-16 09:01:38 +00:00
{
return kmalloc ( size ) ;
}
void operator delete ( void * ptr )
{
return kfree ( ptr ) ;
}
void operator delete [ ] ( void * ptr )
{
return kfree ( ptr ) ;
}
void operator delete ( void * ptr , unsigned int )
{
return kfree ( ptr ) ;
}
void operator delete [ ] ( void * ptr , unsigned int )
{
return kfree ( ptr ) ;
}