XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
/* XFESystem's freestanding C support for the unmodified Microsoft runtime.
 * No host libc or Cosmos code is used. Every heap block owns real kernel pages.
 * The deliberately simple page heap is reclaimable; it is not a bump allocator.
 */
#include <stdint.h>
#include <stddef.h>
#include <limits.h>

extern void *xfe_runtime_alloc_pages(uint64_t pages);
extern int xfe_runtime_free_pages(void *base, uint64_t pages);
extern void xfe_runtime_halt(const char *reason);
/* Bootstrap has one executing context. The full PAL supplies the strong,
 * per-thread definition before threaded managed-runtime acceptance. */
static int bootstrap_errno;
__attribute__((weak)) int *__errno_location(void){return &bootstrap_errno;}

void *memcpy(void *restrict dst, const void *restrict src, size_t size) {
    unsigned char *d=dst;const unsigned char *s=src;
    for(size_t i=0;i<size;i++)d[i]=s[i];return dst;
}
void *memmove(void *dst, const void *src, size_t size) {
    unsigned char *d=dst;const unsigned char *s=src;
    if((uintptr_t)d<(uintptr_t)s)for(size_t i=0;i<size;i++)d[i]=s[i];
    else if(d!=s)for(size_t i=size;i;i--)d[i-1]=s[i-1];return dst;
}
void *memset(void *dst,int value,size_t size) {
    unsigned char *d=dst;for(size_t i=0;i<size;i++)d[i]=(unsigned char)value;return dst;
}
int memcmp(const void *a,const void *b,size_t size) {
    const unsigned char *x=a,*y=b;
    for(size_t i=0;i<size;i++)if(x[i]!=y[i])return x[i]<y[i]?-1:1;return 0;
}
int bcmp(const void *a,const void *b,size_t size){return memcmp(a,b,size);}
size_t strlen(const char *text){size_t n=0;while(text[n])n++;return n;}
size_t strnlen(const char *text,size_t limit){size_t n=0;while(n<limit&&text[n])n++;return n;}
int strcmp(const char *a,const char *b){while(*a&&*a==*b){a++;b++;}return (unsigned char)*a-(unsigned char)*b;}
int strncmp(const char *a,const char *b,size_t n){for(size_t i=0;i<n;i++){if(a[i]!=b[i])return (unsigned char)a[i]-(unsigned char)b[i];if(!a[i])return 0;}return 0;}
static unsigned char ascii_lower(unsigned char c){return c>='A'&&c<='Z'?c+32:c;}
int strcasecmp(const char *a,const char *b){for(;;a++,b++){int x=ascii_lower((unsigned char)*a),y=ascii_lower((unsigned char)*b);if(x!=y||!x)return x-y;}}
char *strcpy(char *dst,const char *src){size_t n=strlen(src)+1;memcpy(dst,src,n);return dst;}
char *strncpy(char *dst,const char *src,size_t n){size_t i=0;for(;i<n&&src[i];i++)dst[i]=src[i];for(;i<n;i++)dst[i]=0;return dst;}
char *strcat(char *dst,const char *src){strcpy(dst+strlen(dst),src);return dst;}
char *strncat(char *dst,const char *src,size_t n){size_t d=strlen(dst),i=0;for(;i<n&&src[i];i++)dst[d+i]=src[i];dst[d+i]=0;return dst;}
char *strchr(const char *text,int c){for(;;text++){if((unsigned char)*text==(unsigned char)c)return (char*)text;if(!*text)return 0;}}
char *strrchr(const char *text,int c){char *last=0;for(;;text++){if((unsigned char)*text==(unsigned char)c)last=(char*)text;if(!*text)return last;}}
char *strstr(const char *text,const char *needle){size_t n=strlen(needle);if(!n)return (char*)text;for(;*text;text++)if(!strncmp(text,needle,n))return (char*)text;return 0;}
static int contains(const char *set,char c){for(;*set;set++)if(*set==c)return 1;return 0;}
char *strtok_r(char *text,const char *delimiters,char **state){
    char *cursor=text?text:*state;if(!cursor)return 0;
    while(*cursor&&contains(delimiters,*cursor))cursor++;
    if(!*cursor){*state=cursor;return 0;}char *start=cursor;
    while(*cursor&&!contains(delimiters,*cursor))cursor++;
    if(*cursor)*cursor++=0;*state=cursor;return start;
}

typedef struct {uint64_t magic,size,pages,check,pad[4];} heap_header;
#define HEAP_MAGIC UINT64_C(0x5846454e41544956)
static uint64_t irq_save(void){uint64_t flags;__asm__ volatile("pushfq; popq %0; cli":"=r"(flags)::"memory");return flags;}
static void irq_restore(uint64_t flags){__asm__ volatile("pushq %0; popfq"::"r"(flags):"memory","cc");}
void *malloc(size_t size){
    if(!size||size>SIZE_MAX-sizeof(heap_header)-4095)return 0;
    uint64_t pages=(size+sizeof(heap_header)+4095)/4096;
    uint64_t flags=irq_save();heap_header *head=xfe_runtime_alloc_pages(pages);
    if(head){head->magic=HEAP_MAGIC;head->size=size;head->pages=pages;head->check=(uintptr_t)head^pages^size^HEAP_MAGIC;}
    irq_restore(flags);return head?(void*)(head+1):0;
}
void free(void *pointer){
    if(!pointer)return;heap_header *head=(heap_header*)pointer-1;
    uint64_t flags=irq_save();
    if(((uintptr_t)head&4095)||head->magic!=HEAP_MAGIC||!head->pages||
       head->check!=((uintptr_t)head^head->pages^head->size^HEAP_MAGIC))xfe_runtime_halt("LIBC_INVALID_FREE");
    uint64_t pages=head->pages;head->magic=0;
    if(!xfe_runtime_free_pages(head,pages))xfe_runtime_halt("LIBC_PAGE_RELEASE");irq_restore(flags);
}
void *calloc(size_t count,size_t size){if(size&&count>SIZE_MAX/size)return 0;size_t total=count*size;void *p=malloc(total);if(p)memset(p,0,total);return p;}
void *realloc(void *pointer,size_t size){
    if(!pointer)return malloc(size);if(!size){free(pointer);return 0;}
    heap_header *old=(heap_header*)pointer-1;
    if(old->magic!=HEAP_MAGIC||old->check!=((uintptr_t)old^old->pages^old->size^HEAP_MAGIC))xfe_runtime_halt("LIBC_INVALID_REALLOC");
    if(size<=old->pages*4096-sizeof(heap_header)){old->size=size;old->check=(uintptr_t)old^old->pages^size^HEAP_MAGIC;return pointer;}
    void *next=malloc(size);if(!next)return 0;memcpy(next,pointer,old->size<size?old->size:size);free(pointer);return next;
}

// Correct transcendental/numeric semantics come from the pinned external
// mathematical runtime library. It contains no scheduling or hardware code.
extern double floor(double),ceil(double),trunc(double),log(double);
extern double pow(double,double),sin(double),cos(double),acos(double),fmod(double,double),exp(double);

static int ascii_space(char c){return c==' '||c=='\t'||c=='\n'||c=='\r'||c=='\f'||c=='\v';}
static int digit(char c){if(c>='0'&&c<='9')return c-'0';c=(char)ascii_lower((unsigned char)c);return c>='a'&&c<='z'?c-'a'+10:-1;}
static uint64_t parse_integer(const char *text,char **end,int base,int *negative,int *overflow){
    const char *original=text;while(ascii_space(*text))text++;*negative=0;*overflow=0;
    if(*text=='+'||*text=='-'){*negative=*text=='-';text++;}
    if(base&& (base<2||base>36)){if(end)*end=(char*)original;*__errno_location()=22;return 0;}
    if((!base||base==16)&&text[0]=='0'&&(text[1]=='x'||text[1]=='X')&&digit(text[2])>=0&&digit(text[2])<16){base=16;text+=2;}
    if(!base)base=*text=='0'?8:10;
    const char *first=text;uint64_t value=0;
    for(;;text++){int d=digit(*text);if(d<0||d>=base)break;
        if(value>(UINT64_MAX-(unsigned)d)/(unsigned)base)*overflow=1;
        else if(!*overflow)value=value*(unsigned)base+(unsigned)d;}
    if(end)*end=(char*)(text==first?original:text);return value;
}
unsigned long long strtoull(const char *text,char **end,int base){int negative,overflow;uint64_t v=parse_integer(text,end,base,&negative,&overflow);if(overflow){*__errno_location()=34;return UINT64_MAX;}return negative?0-v:v;}
long long strtoll(const char *text,char **end,int base){int negative,overflow;uint64_t v=parse_integer(text,end,base,&negative,&overflow);if(overflow||v>(negative?UINT64_C(0x8000000000000000):INT64_MAX)){*__errno_location()=34;return negative?INT64_MIN:INT64_MAX;}return negative?(long long)(0-v):(long long)v;}
unsigned long strtoul(const char *text,char **end,int base){return (unsigned long)strtoull(text,end,base);}
long strtol(const char *text,char **end,int base){return (long)strtoll(text,end,base);}

int xfe_libc_selftest(void){
    char a[32]="abcdef",b[32];memmove(a+1,a,5);if(strcmp(a,"aabcde"))return 0;
    memmove(a,a+1,5);a[5]=0;if(strcmp(a,"abcde"))return 0;
    strcpy(b,"hello");strcat(b," world");if(strcmp(b,"hello world")||strcasecmp("AbC","aBc")||strncmp(b,"hello",5))return 0;
    if(strstr(b,"world")!=b+6||strrchr(b,'l')!=b+9||strchr(b,0)!=b+11)return 0;
    char token[16]=" a,,b ",*state=0;if(strcmp(strtok_r(token," ,",&state),"a")||strcmp(strtok_r(0," ,",&state),"b")||strtok_r(0," ,",&state))return 0;
    char *end=0;if(strtoll("-0x10!",&end,0)!=-16||*end!='!'||strtoull("18446744073709551615",&end,10)!=UINT64_MAX||*end)return 0;
    if(floor(-1.25)!=-2||ceil(1.25)!=2||trunc(-1.25)!=-1||log(1)!=0)return 0;
    double error=log(2)-0.6931471805599453094;if(error>1e-14||error< -1e-14)return 0;
    if(pow(2,10)!=1024||fmod(-5.5,2)!=-1.5||exp(0)!=1)return 0;
    error=sin(1.57079632679489661923)-1;if(error>1e-14||error< -1e-14)return 0;
    if(cos(0)!=1||acos(2)==acos(2))return 0; // Domain error must be a real NaN.
    unsigned char *p=calloc(17,3);if(!p)return 0;for(unsigned i=0;i<51;i++)if(p[i])return 0;
    p[0]=37;p[50]=91;unsigned char *q=realloc(p,8193);if(!q||q[0]!=37||q[50]!=91)return 0;
    free(q);if(calloc(SIZE_MAX,2)||malloc(SIZE_MAX))return 0;
    return 1;
}