2016-11-25 17:18:40 +01:00
|
|
|
/*
|
|
|
|
* This file is part of Jehanne.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2016 Giacomo Tesio <giacomo@tesio.it>
|
|
|
|
*
|
|
|
|
* Jehanne 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, version 2 of the License.
|
|
|
|
*
|
|
|
|
* Jehanne 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 Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define MLG(fmt, ...) //print("%#p %s[%d] %#p %s: " fmt "\n", up, up?up->text:"kernel", up?up->pid:-1, getcallerpc(), __func__, __VA_ARGS__)
|
|
|
|
|
|
|
|
typedef unsigned int PagePointer;
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
/* regusterb a memory region available */
|
|
|
|
extern int umem_region(uintptr_t base, uint32_t npages);
|
|
|
|
|
2016-11-25 17:18:40 +01:00
|
|
|
/* Initialize the user memory system */
|
|
|
|
extern void umem_init(void);
|
|
|
|
|
|
|
|
/* Test user memory system (while work in progress) */
|
|
|
|
extern void umem_test(void);
|
|
|
|
|
|
|
|
extern int umem_available(uintptr_t need);
|
|
|
|
|
|
|
|
/* Atomically assign a new virtual Page to *slot.
|
|
|
|
*
|
|
|
|
* Returns 1 on success, 0 on failure.
|
|
|
|
*
|
|
|
|
* Failures include:
|
|
|
|
* - not enough memory in the system
|
|
|
|
* - slot already filled when the page is ready.
|
|
|
|
*/
|
|
|
|
extern int page_new(PagePointer *slot, int clear);
|
|
|
|
|
|
|
|
/* Atomically set *slot to nil and dispose the page previously there.
|
|
|
|
*
|
|
|
|
* Returns 1 on success, 0 on failure.
|
|
|
|
*/
|
|
|
|
extern int page_dispose(PagePointer *slot);
|
|
|
|
|
|
|
|
/* Atomically assign to an empty target a page equivalent to page.
|
|
|
|
*
|
|
|
|
* Obviously, this function exists because you should do no assumption
|
|
|
|
* on the value of *target after a successful call, except that the
|
|
|
|
* memory pointed by it is the same pointed by page.
|
|
|
|
*
|
|
|
|
* Returns 1 if at exit *target points to the same memory of page,
|
|
|
|
* 0 otherwise.
|
|
|
|
*/
|
|
|
|
extern int page_assign(PagePointer *target, PagePointer page);
|
|
|
|
|
|
|
|
/* Replace the page in *slot with a copy
|
|
|
|
*
|
|
|
|
* Returns 1 on success, 0 on failure.
|
|
|
|
*
|
|
|
|
* Failures can be caused by:
|
|
|
|
* - not enough memory in the system
|
|
|
|
* - slot empty on entry
|
|
|
|
* - slot changed during the operation (should we panic instead?)
|
|
|
|
*/
|
|
|
|
extern int page_duplicate(PagePointer *slot);
|
|
|
|
|
|
|
|
/* just like page_duplicate but does not duplicate
|
|
|
|
* if exists only one reference to the page
|
|
|
|
*/
|
|
|
|
extern int page_duplicate_shared(PagePointer *slot);
|
|
|
|
|
|
|
|
/* Return the address of the physical memory referenced by page */
|
|
|
|
extern uintptr_t page_pa(PagePointer page);
|
|
|
|
|
|
|
|
/* Return a pointer to the physical memory referenced by page */
|
|
|
|
extern char* page_kmap(PagePointer page);
|
|
|
|
|
|
|
|
/* Dispose the pointer to the physical memory referenced by page */
|
|
|
|
extern void page_kunmap(PagePointer page, char **memory);
|
|
|
|
|
|
|
|
/* A PageTableEntry holds actual UserPages
|
|
|
|
* It allows to split the segment memory into chunks
|
|
|
|
* that are going to be allocated on demand.
|
|
|
|
*/
|
|
|
|
typedef struct PageTableEntry
|
|
|
|
{
|
|
|
|
PagePointer pages[PTEPERTAB]; /* Page map for this chunk of pte */
|
|
|
|
uint8_t first; /* First used entry */
|
|
|
|
uint8_t last; /* Last used entry */
|
|
|
|
} PageTableEntry;
|
|
|
|
|
|
|
|
typedef struct PageTable
|
|
|
|
{
|
|
|
|
uintptr_t base; /* base address of the fist page
|
|
|
|
* it might differ from the segment's base
|
|
|
|
*/
|
|
|
|
unsigned short mapsize;/* => max segment size is 64 GiB */
|
|
|
|
PageTableEntry* map[];
|
|
|
|
} PageTable;
|
|
|
|
|
|
|
|
extern int rawmem_register(char* name, uintptr_t pa, unsigned int attr, uintptr_t size);
|
|
|
|
|
|
|
|
/* find the RawMemory *name and fill the required infos
|
|
|
|
*
|
|
|
|
* Return 1 on success, 0 on failure
|
|
|
|
* On success *name is replaced with the string present in the found memory
|
|
|
|
*/
|
|
|
|
extern int rawmem_find(char** name, uintptr_t *pa, unsigned int *attr, uintptr_t *size);
|
|
|
|
|
|
|
|
extern int rawmem_lookup(uintptr_t addr, char** name, uintptr_t *pa, unsigned int *attr, uintptr_t *size);
|
|
|
|
|
|
|
|
#define NLOAD 2 /* Number of load sections handled */
|
|
|
|
|
|
|
|
typedef unsigned int ElfSegPointer;
|
|
|
|
|
|
|
|
typedef short ImagePointer;
|
|
|
|
|
|
|
|
typedef enum SegmentType
|
|
|
|
{
|
|
|
|
SgLoad = 0x0, /* in elf, replaces text and data */
|
|
|
|
SgBSS = 0x1,
|
|
|
|
SgStack = 0x2,
|
|
|
|
SgShared = 0x3,
|
|
|
|
SgPhysical = 0x4
|
|
|
|
} SegmentType;
|
|
|
|
#define SegmentTypesMask 0x7
|
|
|
|
extern char *segment_types[SegmentTypesMask+1];
|
|
|
|
|
|
|
|
typedef enum SegFlag
|
|
|
|
{
|
|
|
|
SgCached = 1<<0, /* RawMemory can be cached */
|
|
|
|
SgCExec = 1<<1 /* Detach at exec */
|
|
|
|
} SegFlag;
|
|
|
|
#define SegFlagMask 0x3
|
|
|
|
|
|
|
|
typedef enum SegPermission
|
|
|
|
{
|
|
|
|
SgRead = 1<<0,
|
|
|
|
SgWrite = 1<<1,
|
|
|
|
SgExecute = 1<<2
|
|
|
|
} SegPermission;
|
|
|
|
#define SegPermissionMask 0x7
|
|
|
|
|
|
|
|
/* NOTE: we keep FaultTypes in sync with SegPermission */
|
|
|
|
typedef enum FaultType
|
|
|
|
{
|
|
|
|
FaultRead = 1<<0,
|
|
|
|
FaultWrite = 1<<1,
|
|
|
|
FaultExecute = 1<<2
|
|
|
|
} FaultType;
|
|
|
|
#define FaultTypeMask 0x7
|
|
|
|
extern char *fault_types[]; /* defined in segments.c */
|
|
|
|
|
|
|
|
typedef struct ProcSegment
|
|
|
|
{
|
|
|
|
Ref r;
|
|
|
|
SegmentType type : 3;
|
|
|
|
SegPermission permissions : 3;
|
|
|
|
SegFlag flags : 2;
|
|
|
|
QLock ql; /* grow or shrink */
|
|
|
|
uintptr_t base; /* virtual base */
|
|
|
|
uintptr_t top; /* virtual top */
|
|
|
|
PageTable* table; /* physical pages mapped to virtual base */
|
|
|
|
|
|
|
|
union {
|
|
|
|
ElfSegPointer image; /* prototype in file attached to this segment */
|
|
|
|
char* vmem; /* name of "virtual" memory area attached (see umem/raw.c) */
|
|
|
|
uintptr_t pmem; /* base address of physical memory area attached (see umem/raw.c) */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* semacquire/semrelease */
|
|
|
|
Lock semalock;
|
|
|
|
Sema sema;
|
|
|
|
} ProcSegment;
|
|
|
|
|
|
|
|
extern int image_attach(ImagePointer* slot, Chan *c, Ldseg* segments);
|
|
|
|
|
|
|
|
extern Chan* image_chan(ElfSegPointer image);
|
|
|
|
|
|
|
|
extern int image_segments(ElfSegPointer segments[NLOAD], ImagePointer image);
|
|
|
|
|
|
|
|
extern void image_assign(ImagePointer *slot, ImagePointer img);
|
|
|
|
|
|
|
|
/* 1 if ptr refer to an attached image, 0 otherwise */
|
|
|
|
extern int image_known(ElfSegPointer ptr);
|
|
|
|
|
|
|
|
/* Fill *page (if zero) with the page from segment holding va.
|
|
|
|
*
|
|
|
|
* Returns 1 on success.
|
|
|
|
*
|
|
|
|
* If the operation requires I/O and such I/O fails, it will notify
|
|
|
|
* and pexit the current process, *without* returning to the caller.
|
|
|
|
*
|
|
|
|
* Return 0 as failure if
|
|
|
|
* - *page is already filled (might occurs if different processes sharing
|
|
|
|
* the same image segment race over the page)
|
|
|
|
* - there is not enough memory available to perform the operation
|
|
|
|
*/
|
|
|
|
extern int image_fill(PagePointer* page, ElfSegPointer segment, uintptr_t va);
|
|
|
|
|
|
|
|
extern void image_release(ImagePointer ptr);
|
|
|
|
|
|
|
|
extern char* segment_name(ProcSegment *s);
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
extern void segment_relocate(ProcSegment *s, uintptr_t newbase, uintptr_t newtop);
|
|
|
|
|
2016-11-25 17:18:40 +01:00
|
|
|
extern int segment_userinit(ProcSegment** slot, int text);
|
|
|
|
|
|
|
|
extern int segment_global(ProcSegment** slot, SegFlag flags, uintptr_t va, char *name);
|
|
|
|
|
|
|
|
extern int segment_load(ProcSegment** slot, ElfSegPointer segment, Ldseg* elfinfo);
|
|
|
|
|
|
|
|
extern int segment_physical(ProcSegment** slot, SegPermission permissions, SegFlag flags, uintptr_t va, uintptr_t pa);
|
|
|
|
|
|
|
|
extern int segment_virtual(ProcSegment** slot, SegmentType type, SegPermission permissions, SegFlag flags, uintptr_t base, uintptr_t top);
|
|
|
|
|
|
|
|
extern int segment_fault(uintptr_t *mmuphys, uintptr_t *va, ProcSegment* segment, FaultType type);
|
|
|
|
|
|
|
|
extern int segment_fork(ProcSegment **s);
|
|
|
|
|
|
|
|
extern int segment_share(ProcSegment **s);
|
|
|
|
|
|
|
|
extern int segment_grow(ProcSegment *s, uintptr_t top);
|
|
|
|
|
|
|
|
/* replaces the text segment *s with a copy that has debugging enable/disabled
|
|
|
|
* (or just inform if *s has debugging enabled)
|
|
|
|
* - if enable is nil, returns 1 if debug is enabled in *s, 0 otherwise
|
|
|
|
* - if *enable is 0, try to replace *s with a NOT debuggable copy,
|
|
|
|
* returning 0 if it's *s is already not debuggable and 1 otherwise
|
|
|
|
* - otherwise, try to replace *s with a debuggable copy, returning 0
|
|
|
|
* if it's already a debuggable segment and 1 otherwise
|
|
|
|
*/
|
|
|
|
extern int segment_debug(ProcSegment** s, int* enable);
|
|
|
|
|
|
|
|
/* return the PagePointer for va, or zero if the page has not been faulted yet */
|
|
|
|
extern PagePointer segment_page(ProcSegment* s, uintptr_t va);
|
|
|
|
|
|
|
|
extern void segment_free_pages(ProcSegment *s, uintptr_t from, uintptr_t to);
|
|
|
|
|
|
|
|
extern void segment_release(ProcSegment** s);
|
|
|
|
|
|
|
|
/* these should be in a proc related header */
|
|
|
|
extern ProcSegment* proc_segment(Proc *p, uintptr_t va);
|
|
|
|
extern void proc_check_pages(void);
|
|
|
|
extern int proc_own_pagepool(Proc *p);
|
|
|
|
extern int proc_segment_detach(Proc *p, uintptr_t va);
|
|
|
|
|
2017-01-12 00:35:27 +01:00
|
|
|
typedef struct MemoryStats
|
|
|
|
{
|
|
|
|
unsigned long memory;
|
|
|
|
unsigned long kernel;
|
|
|
|
unsigned long user_available;
|
|
|
|
unsigned long user;
|
|
|
|
} MemoryStats;
|
|
|
|
|
|
|
|
/* fills stats with memory statistics */
|
|
|
|
extern void memory_stats(MemoryStats *stats);
|