Refactor kernel segment bookkeeping.
This commit is contained in:
parent
68aba3d137
commit
d71179b540
|
@ -117,6 +117,7 @@ poll.o \
|
|||
process.o \
|
||||
refcount.o \
|
||||
scheduler.o \
|
||||
segment.o \
|
||||
serialterminal.o \
|
||||
signal.o \
|
||||
sound.o \
|
||||
|
|
115
sortix/elf.cpp
115
sortix/elf.cpp
|
@ -28,6 +28,7 @@
|
|||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sortix/mman.h>
|
||||
|
@ -35,6 +36,7 @@
|
|||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/memorymanagement.h>
|
||||
#include <sortix/kernel/process.h>
|
||||
#include <sortix/kernel/segment.h>
|
||||
#include <sortix/kernel/symbol.h>
|
||||
|
||||
#include "elf.h"
|
||||
|
@ -42,25 +44,6 @@
|
|||
namespace Sortix {
|
||||
namespace ELF {
|
||||
|
||||
static int ToProgramSectionType(int flags)
|
||||
{
|
||||
switch ( flags & (PF_X | PF_R | PF_W) )
|
||||
{
|
||||
case 0:
|
||||
return SEG_NONE;
|
||||
case PF_X:
|
||||
case PF_X | PF_R:
|
||||
case PF_X | PF_W:
|
||||
case PF_X | PF_R | PF_W:
|
||||
return SEG_TEXT;
|
||||
case PF_R:
|
||||
case PF_W:
|
||||
case PF_R | PF_W:
|
||||
default:
|
||||
return SEG_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This code doesn't respect that the size of program headers and section
|
||||
// headers may vary depending on the ELF header and that using a simple
|
||||
// table indexation isn't enough.
|
||||
|
@ -114,34 +97,47 @@ addr_t Construct32(Process* process, const uint8_t* file, size_t filelen)
|
|||
assert(pht->offset + pht->filesize < filelen);
|
||||
assert(pht->filesize <= pht->memorysize);
|
||||
|
||||
ProcessSegment* segment = new ProcessSegment;
|
||||
if ( segment == NULL )
|
||||
return 0;
|
||||
segment->position = mapto;
|
||||
segment->size = Page::AlignUp(mapbytes);
|
||||
segment->type = ToProgramSectionType(pht->flags);
|
||||
|
||||
int prot = PROT_FORK | PROT_KREAD | PROT_KWRITE;
|
||||
if ( pht->flags & PF_X ) { prot |= PROT_EXEC; }
|
||||
if ( pht->flags & PF_R ) { prot |= PROT_READ; }
|
||||
if ( pht->flags & PF_W ) { prot |= PROT_WRITE; }
|
||||
|
||||
if ( segment->Intersects(process->segments) )
|
||||
if ( (pht->flags & (PF_X | PF_R | PF_W)) == (PF_R | PF_W) )
|
||||
prot |= PROT_HEAP;
|
||||
|
||||
struct segment segment;
|
||||
segment.addr = mapto;
|
||||
segment.size = Page::AlignUp(mapbytes);
|
||||
segment.prot = prot;
|
||||
|
||||
kthread_mutex_lock(&process->segment_lock);
|
||||
|
||||
if ( !IsUserspaceSegment(&segment) ||
|
||||
IsSegmentOverlapping(process, &segment) )
|
||||
{
|
||||
delete segment;
|
||||
kthread_mutex_unlock(&process->segment_lock);
|
||||
process->ResetAddressSpace();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( !Memory::MapRange(mapto, mapbytes, prot) )
|
||||
// TODO: Memory leak of segment?
|
||||
return 0;
|
||||
assert(process == CurrentProcess());
|
||||
|
||||
// Insert our newly allocated memory into the processes segment
|
||||
// list such that it can be reclaimed later.
|
||||
if ( process->segments )
|
||||
process->segments->prev = segment;
|
||||
segment->next = process->segments;
|
||||
process->segments = segment;
|
||||
if ( !Memory::MapRange(segment.addr, segment.size, prot) )
|
||||
{
|
||||
kthread_mutex_unlock(&process->segment_lock);
|
||||
process->ResetAddressSpace();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( !AddSegment(process, &segment) )
|
||||
{
|
||||
Memory::UnmapRange(segment.addr, segment.size);
|
||||
kthread_mutex_unlock(&process->segment_lock);
|
||||
process->ResetAddressSpace();
|
||||
return 0;
|
||||
}
|
||||
|
||||
kthread_mutex_unlock(&process->segment_lock);
|
||||
|
||||
// Copy as much data as possible and memset the rest to 0.
|
||||
uint8_t* memdest = (uint8_t*) virtualaddr;
|
||||
|
@ -269,36 +265,47 @@ addr_t Construct64(Process* process, const uint8_t* file, size_t filelen)
|
|||
assert(pht->offset + pht->filesize < filelen);
|
||||
assert(pht->filesize <= pht->memorysize);
|
||||
|
||||
ProcessSegment* segment = new ProcessSegment;
|
||||
if ( segment == NULL )
|
||||
return 0;
|
||||
segment->position = mapto;
|
||||
segment->size = Page::AlignUp(mapbytes);
|
||||
segment->type = ToProgramSectionType(pht->flags);
|
||||
|
||||
int prot = PROT_FORK | PROT_KREAD | PROT_KWRITE;
|
||||
if ( pht->flags & PF_X ) { prot |= PROT_EXEC; }
|
||||
if ( pht->flags & PF_R ) { prot |= PROT_READ; }
|
||||
if ( pht->flags & PF_W ) { prot |= PROT_WRITE; }
|
||||
|
||||
if ( segment->Intersects(process->segments) )
|
||||
if ( (pht->flags & (PF_X | PF_R | PF_W)) == (PF_R | PF_W) )
|
||||
prot |= PROT_HEAP;
|
||||
|
||||
struct segment segment;
|
||||
segment.addr = mapto;
|
||||
segment.size = Page::AlignUp(mapbytes);
|
||||
segment.prot = prot;
|
||||
|
||||
kthread_mutex_lock(&process->segment_lock);
|
||||
|
||||
if ( !IsUserspaceSegment(&segment) ||
|
||||
IsSegmentOverlapping(process, &segment) )
|
||||
{
|
||||
delete segment;
|
||||
kthread_mutex_unlock(&process->segment_lock);
|
||||
process->ResetAddressSpace();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( !Memory::MapRange(mapto, mapbytes, prot) )
|
||||
assert(process == CurrentProcess());
|
||||
|
||||
if ( !Memory::MapRange(segment.addr, segment.size, prot) )
|
||||
{
|
||||
// TODO: Memory leak of segment?
|
||||
kthread_mutex_unlock(&process->segment_lock);
|
||||
process->ResetAddressSpace();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Insert our newly allocated memory into the processes segment
|
||||
// list such that it can be reclaimed later.
|
||||
if ( process->segments )
|
||||
process->segments->prev = segment;
|
||||
segment->next = process->segments;
|
||||
process->segments = segment;
|
||||
if ( !AddSegment(process, &segment) )
|
||||
{
|
||||
Memory::UnmapRange(segment.addr, segment.size);
|
||||
kthread_mutex_unlock(&process->segment_lock);
|
||||
process->ResetAddressSpace();
|
||||
return 0;
|
||||
}
|
||||
|
||||
kthread_mutex_unlock(&process->segment_lock);
|
||||
|
||||
// Copy as much data as possible and memset the rest to 0.
|
||||
uint8_t* memdest = (uint8_t*) virtualaddr;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <sortix/kernel/clock.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/segment.h>
|
||||
#include <sortix/kernel/time.h>
|
||||
#include <sortix/kernel/timer.h>
|
||||
#include <sortix/kernel/user-timer.h>
|
||||
|
@ -50,30 +51,6 @@ struct ioctx_struct;
|
|||
typedef struct ioctx_struct ioctx_t;
|
||||
struct Symbol;
|
||||
|
||||
const int SEG_NONE = 0;
|
||||
const int SEG_TEXT = 1;
|
||||
const int SEG_DATA = 2;
|
||||
const int SEG_STACK = 3;
|
||||
const int SEG_OTHER = 4;
|
||||
|
||||
struct ProcessSegment
|
||||
{
|
||||
public:
|
||||
ProcessSegment() : prev(NULL), next(NULL) { }
|
||||
|
||||
public:
|
||||
ProcessSegment* prev;
|
||||
ProcessSegment* next;
|
||||
addr_t position;
|
||||
size_t size;
|
||||
int type;
|
||||
|
||||
public:
|
||||
bool Intersects(ProcessSegment* segments);
|
||||
ProcessSegment* Fork();
|
||||
|
||||
};
|
||||
|
||||
class Process
|
||||
{
|
||||
friend void Process__OnLastThreadExit(void*);
|
||||
|
@ -156,7 +133,10 @@ public:
|
|||
kthread_mutex_t threadlock;
|
||||
|
||||
public:
|
||||
ProcessSegment* segments;
|
||||
struct segment* segments;
|
||||
size_t segments_used;
|
||||
size_t segments_length;
|
||||
kthread_mutex_t segment_lock;
|
||||
|
||||
public:
|
||||
kthread_mutex_t user_timers_lock;
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/kernel/segment.h
|
||||
Structure representing a segment in a process.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_KERNEL_SEGMENT_H
|
||||
#define INCLUDE_SORTIX_KERNEL_SEGMENT_H
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class Process;
|
||||
|
||||
struct segment
|
||||
{
|
||||
uintptr_t addr;
|
||||
size_t size;
|
||||
int prot;
|
||||
};
|
||||
|
||||
static inline int segmentcmp(const void* a_ptr, const void* b_ptr)
|
||||
{
|
||||
const struct segment* a = (const struct segment*) a_ptr;
|
||||
const struct segment* b = (const struct segment*) b_ptr;
|
||||
return a->addr < b->addr ? -1 :
|
||||
b->addr < a->addr ? 1 :
|
||||
a->size < b->size ? -1 :
|
||||
b->size < a->size ? 1 :
|
||||
0 ;
|
||||
}
|
||||
|
||||
bool AreSegmentsOverlapping(const struct segment* a, const struct segment* b);
|
||||
bool IsUserspaceSegment(const struct segment* segment);
|
||||
struct segment* FindOverlappingSegment(Process* process, const struct segment* new_segment);
|
||||
bool IsSegmentOverlapping(Process* process, const struct segment* new_segment);
|
||||
bool AddSegment(Process* process, const struct segment* new_segment);
|
||||
bool PlaceSegment(struct segment* solution, Process* process, void* addr_ptr,
|
||||
size_t size, int flags);
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -43,6 +43,7 @@
|
|||
#define PROT_KERNEL (PROT_KEXEC | PROT_KWRITE | PROT_KREAD)
|
||||
|
||||
#define PROT_FORK (1<<6)
|
||||
#define PROT_HEAP (1<<7)
|
||||
|
||||
#define MAP_SHARED (1<<0)
|
||||
#define MAP_PRIVATE (1<<1)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sortix/clock.h>
|
||||
|
@ -60,53 +61,6 @@
|
|||
|
||||
namespace Sortix {
|
||||
|
||||
bool ProcessSegment::Intersects(ProcessSegment* segments)
|
||||
{
|
||||
for ( ProcessSegment* tmp = segments; tmp != NULL; tmp = tmp->next )
|
||||
{
|
||||
if ( tmp->position < position + size &&
|
||||
position < tmp->position + tmp->size )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( next ) { return next->Intersects(segments); }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ProcessSegment* ProcessSegment::Fork()
|
||||
{
|
||||
ProcessSegment* nextclone = NULL;
|
||||
if ( next )
|
||||
{
|
||||
nextclone = next->Fork();
|
||||
if ( nextclone == NULL ) { return NULL; }
|
||||
}
|
||||
|
||||
ProcessSegment* clone = new ProcessSegment();
|
||||
if ( clone == NULL )
|
||||
{
|
||||
while ( nextclone != NULL )
|
||||
{
|
||||
ProcessSegment* todelete = nextclone;
|
||||
nextclone = nextclone->next;
|
||||
delete todelete;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( nextclone )
|
||||
nextclone->prev = clone;
|
||||
clone->next = nextclone;
|
||||
clone->position = position;
|
||||
clone->size = size;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
Process::Process()
|
||||
{
|
||||
string_table = NULL;
|
||||
|
@ -140,6 +94,10 @@ Process::Process()
|
|||
ptrlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
idlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
user_timers_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||
segments = NULL;
|
||||
segments_used = 0;
|
||||
segments_length = 0;
|
||||
segment_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||
mmapfrom = 0x80000000UL;
|
||||
exitstatus = -1;
|
||||
pid = AllocatePID();
|
||||
|
@ -370,16 +328,17 @@ void Process::LastPrayer()
|
|||
|
||||
void Process::ResetAddressSpace()
|
||||
{
|
||||
assert(Memory::GetAddressSpace() == addrspace);
|
||||
ProcessSegment* tmp = segments;
|
||||
while ( tmp != NULL )
|
||||
{
|
||||
Memory::UnmapRange(tmp->position, tmp->size);
|
||||
ProcessSegment* todelete = tmp;
|
||||
tmp = tmp->next;
|
||||
delete todelete;
|
||||
}
|
||||
ScopedLock lock(&segment_lock);
|
||||
|
||||
assert(Memory::GetAddressSpace() == addrspace);
|
||||
|
||||
for ( size_t i = 0; i < segments_used; i++ )
|
||||
Memory::UnmapRange(segments[i].addr, segments[i].size);
|
||||
|
||||
Memory::Flush();
|
||||
|
||||
segments_used = segments_length = 0;
|
||||
free(segments);
|
||||
segments = NULL;
|
||||
}
|
||||
|
||||
|
@ -645,34 +604,34 @@ Process* Process::Fork()
|
|||
if ( !clone )
|
||||
return NULL;
|
||||
|
||||
ProcessSegment* clonesegments = NULL;
|
||||
struct segment* clone_segments = NULL;
|
||||
|
||||
// Fork the segment list.
|
||||
if ( segments )
|
||||
{
|
||||
clonesegments = segments->Fork();
|
||||
if ( clonesegments == NULL ) { delete clone; return NULL; }
|
||||
size_t segments_size = sizeof(struct segment) * segments_used;
|
||||
if ( !(clone_segments = (struct segment*) malloc(segments_size)) )
|
||||
{
|
||||
delete clone;
|
||||
return NULL;
|
||||
}
|
||||
memcpy(clone_segments, segments, segments_size);
|
||||
}
|
||||
|
||||
// Fork address-space here and copy memory.
|
||||
clone->addrspace = Memory::Fork();
|
||||
if ( !clone->addrspace )
|
||||
{
|
||||
// Delete the segment list, since they are currently bogus.
|
||||
ProcessSegment* tmp = clonesegments;
|
||||
while ( tmp != NULL )
|
||||
{
|
||||
ProcessSegment* todelete = tmp;
|
||||
tmp = tmp->next;
|
||||
delete todelete;
|
||||
}
|
||||
|
||||
delete clone; return NULL;
|
||||
free(clone_segments);
|
||||
delete clone;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Now it's too late to clean up here, if anything goes wrong, we simply
|
||||
// ask the process to commit suicide before it goes live.
|
||||
clone->segments = clonesegments;
|
||||
clone->segments = clone_segments;
|
||||
clone->segments_used = segments_used;
|
||||
clone->segments_length = segments_used;
|
||||
|
||||
// Remember the relation to the child process.
|
||||
AddChildProcess(clone);
|
||||
|
@ -759,8 +718,6 @@ Process* Process::Fork()
|
|||
|
||||
void Process::ResetForExecute()
|
||||
{
|
||||
// TODO: Delete all threads and their stacks.
|
||||
|
||||
string_table_length = 0;
|
||||
symbol_table_length = 0;
|
||||
delete[] string_table; string_table = NULL;
|
||||
|
@ -1145,48 +1102,60 @@ void Process::Remove(Process* process)
|
|||
pidlist->Remove(index);
|
||||
}
|
||||
|
||||
void* sys_sbrk(intptr_t increment)
|
||||
static void* sys_sbrk(intptr_t increment)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
ProcessSegment* dataseg = NULL;
|
||||
for ( ProcessSegment* iter = process->segments; iter; iter = iter->next )
|
||||
ScopedLock lock(&process->segment_lock);
|
||||
|
||||
// Locate the heap segment.
|
||||
struct segment* heap_segment = NULL;
|
||||
for ( size_t i = process->segments_used; !heap_segment && i != 0; i-- )
|
||||
{
|
||||
if ( !iter->type == SEG_DATA )
|
||||
struct segment* candidate = &process->segments[i-1];
|
||||
if ( !(candidate->prot & PROT_HEAP) )
|
||||
continue;
|
||||
if ( dataseg && iter->position < dataseg->position )
|
||||
continue;
|
||||
dataseg = iter;
|
||||
heap_segment = candidate;
|
||||
}
|
||||
if ( !dataseg )
|
||||
if ( !heap_segment )
|
||||
return errno = ENOMEM, (void*) -1UL;
|
||||
addr_t currentend = dataseg->position + dataseg->size;
|
||||
addr_t newend = currentend + increment;
|
||||
if ( newend < dataseg->position )
|
||||
return errno = EINVAL, (void*) -1UL;
|
||||
if ( newend < currentend )
|
||||
|
||||
assert(IsUserspaceSegment(heap_segment));
|
||||
|
||||
// Decrease the size of the heap segment if requested.
|
||||
if ( increment < 0 )
|
||||
{
|
||||
addr_t unmapfrom = Page::AlignUp(newend);
|
||||
if ( unmapfrom < currentend )
|
||||
{
|
||||
size_t unmapbytes = Page::AlignUp(currentend - unmapfrom);
|
||||
Memory::UnmapRange(unmapfrom, unmapbytes);
|
||||
}
|
||||
uintptr_t abs_amount = Page::AlignDown(- (uintptr_t) increment);
|
||||
if ( heap_segment->size < abs_amount )
|
||||
abs_amount = heap_segment->size;
|
||||
uintptr_t new_end = heap_segment->addr + heap_segment->size - abs_amount;
|
||||
Memory::UnmapRange(new_end, abs_amount);
|
||||
heap_segment->size -= abs_amount;
|
||||
// TODO: How do we handle that the heap shrinks to 0 bytes?
|
||||
}
|
||||
else if ( currentend < newend )
|
||||
|
||||
// Increase the size of the heap if requested.
|
||||
if ( 0 < increment )
|
||||
{
|
||||
// TODO: HACK: Make a safer way of expanding the data segment
|
||||
// without segments possibly colliding!
|
||||
addr_t mapfrom = Page::AlignUp(currentend);
|
||||
if ( mapfrom < newend )
|
||||
{
|
||||
size_t mapbytes = Page::AlignUp(newend - mapfrom);
|
||||
int prot = PROT_FORK | PROT_READ | PROT_WRITE | PROT_KREAD | PROT_KWRITE;
|
||||
if ( !Memory::MapRange(mapfrom, mapbytes, prot) )
|
||||
return (void*) -1UL;
|
||||
}
|
||||
uintptr_t abs_amount = Page::AlignUp(increment);
|
||||
uintptr_t max_growth = 0 - (heap_segment->addr + heap_segment->size);
|
||||
if ( max_growth < abs_amount )
|
||||
return errno = ENOMEM, (void*) -1UL;
|
||||
struct segment growth;
|
||||
growth.addr = heap_segment->addr + heap_segment->size;
|
||||
growth.size = abs_amount;
|
||||
growth.prot = heap_segment->prot;
|
||||
if ( !IsUserspaceSegment(&growth) )
|
||||
return errno = ENOMEM, (void*) -1UL;
|
||||
if ( FindOverlappingSegment(process, &growth) )
|
||||
return errno = ENOMEM, (void*) -1UL;
|
||||
if ( !Memory::MapRange(growth.addr, growth.size, growth.prot) )
|
||||
return errno = ENOMEM, (void*) -1UL;
|
||||
heap_segment->size += growth.size;
|
||||
}
|
||||
dataseg->size += increment;
|
||||
return (void*) newend;
|
||||
|
||||
assert(IsUserspaceSegment(heap_segment));
|
||||
|
||||
return (void*) (heap_segment->addr + heap_segment->size);
|
||||
}
|
||||
|
||||
size_t sys_getpagesize()
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
segment.cpp
|
||||
Structure representing a segment in a process.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sortix/kernel/decl.h>
|
||||
#include <sortix/kernel/memorymanagement.h>
|
||||
#include <sortix/kernel/process.h>
|
||||
#include <sortix/kernel/segment.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
bool AreSegmentsOverlapping(const struct segment* a, const struct segment* b)
|
||||
{
|
||||
return a->addr < b->addr + b->size && b->addr < a->addr + a->size;
|
||||
}
|
||||
|
||||
bool IsUserspaceSegment(const struct segment* segment)
|
||||
{
|
||||
uintptr_t userspace_addr;
|
||||
size_t userspace_size;
|
||||
Memory::GetUserVirtualArea(&userspace_addr, &userspace_size);
|
||||
if ( segment->addr < userspace_addr )
|
||||
return false;
|
||||
uintptr_t userspace_end = userspace_addr + userspace_size;
|
||||
if ( userspace_end - segment->addr < segment->size )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct segment* FindOverlappingSegment(Process* process, const struct segment* new_segment)
|
||||
{
|
||||
// process->segment_lock is held at this point.
|
||||
|
||||
// TODO: Speed up using binary search.
|
||||
for ( size_t i = 0; i < process->segments_used; i++ )
|
||||
{
|
||||
struct segment* segment = &process->segments[i];
|
||||
if ( AreSegmentsOverlapping(segment, new_segment) )
|
||||
return segment;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool IsSegmentOverlapping(Process* process, const struct segment* new_segment)
|
||||
{
|
||||
// process->segment_lock is held at this point.
|
||||
|
||||
return FindOverlappingSegment(process, new_segment) != NULL;
|
||||
}
|
||||
|
||||
bool AddSegment(Process* process, const struct segment* new_segment)
|
||||
{
|
||||
// process->segment_lock is held at this point.
|
||||
|
||||
// assert(!IsSegmentOverlapping(new_segment));
|
||||
|
||||
// Check if we need to expand the segment list.
|
||||
if ( process->segments_used == process->segments_length )
|
||||
{
|
||||
size_t new_length = process->segments_length ?
|
||||
process->segments_length * 2 : 8;
|
||||
size_t new_size = new_length * sizeof(struct segment);
|
||||
struct segment* new_segments =
|
||||
(struct segment*) realloc(process->segments, new_size);
|
||||
if ( !new_segments )
|
||||
return false;
|
||||
process->segments = new_segments;
|
||||
process->segments_length = new_length;
|
||||
}
|
||||
|
||||
// Add the new segment to the segment list.
|
||||
process->segments[process->segments_used++] = *new_segment;
|
||||
|
||||
// Sort the segment list after address.
|
||||
qsort(process->segments, process->segments_used, sizeof(struct segment),
|
||||
segmentcmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
Loading…
Reference in New Issue