263 lines
8.2 KiB

* This file is part of Jehanne.
* Copyright (C) 2016 Giacomo Tesio <>
* 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
* 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 <>.
#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;
/* regusterb a memory region available */
extern int umem_region(uintptr_t base, uint32_t npages);
/* 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);
extern void segment_relocate(ProcSegment *s, uintptr_t newbase, uintptr_t newtop);
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);
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);