Index: arch/makefile ================================================================== --- arch/makefile +++ arch/makefile @@ -5,5 +5,9 @@ grep "#define __NR_" $< | sed 's;^#define __NR_;%define sys.;' > $@ ${TMP}/calls.x86.lin.64.s: ${lin-headers}/unistd_64.h ${TMP} grep "#define __NR_" $< | sed 's;^#define __NR_;%define sys.;' > $@ ${TMP}/calls.x86.fbsd.%.s: ${fbsd-headers}/syscall.h ${TMP} grep "#define SYS_" $< | sed 's;^#define SYS_;%define sys.;' > $@ +${TMP}/typesize: typesize.c + $(CC) -std=c11 $< -o $@ +${TMP}/typesize.def: ${TMP}/typesize + $< > $@ ADDED arch/typesize.c Index: arch/typesize.c ================================================================== --- arch/typesize.c +++ arch/typesize.c @@ -0,0 +1,40 @@ +#include +#include +#include + +#define sflag(flag,val) printf("-D"#flag"=\"%s\" ", val) +#define mflag(flag,val) printf("-D"#flag"=-%llu ", val + 1) +#define iflag(flag,val) printf("-D"#flag"=%llu ", val) +#define fflag(flag,val) printf("-D"#flag"=%Lf ", val) +#define type_found(val) (found_type & (val / 8)) +#define checkbits(type,x) \ + if(!type_found(x) && sizeof(type) == (x/CHAR_BIT)) \ + sflag(type_bit##x, #type), found_type |= (x / 8) + +#define describe_integral(type,label) { \ + unsigned type maxval = -1; \ + unsigned type smaxval = (maxval/2) - 1; \ + iflag(type_max_u_##label, maxval); \ + iflag(type_max_s_##label, smaxval); \ + mflag(type_min_s_##label, smaxval); \ + iflag(type_##label##_bits, (CHAR_BIT * sizeof(type))); \ + checkbits(type, 8); else checkbits(type,16); else \ + checkbits(type,32); else checkbits(type,64); else \ + checkbits(type,128); else \ + if (!found_sz && sizeof(type) == sizeof(size_t)) \ + found_sz = 1, sflag(type_sz, "unsigned " #type); \ + if (!found_ofs && sizeof(type) == sizeof(ptrdiff_t)) \ + found_ofs = 1, sflag(type_offset, "signed " #type); \ +} + +int main() { + int found_sz = 0, found_ofs = 0, found_type = 0; + iflag(byte_bits,CHAR_BIT); + describe_integral(char,char); + describe_integral(short,short); + describe_integral(int,int); + describe_integral(long,long); + describe_integral(long long,llong); + printf("\n"); + return 0; +} ADDED kconf/kconf.md Index: kconf/kconf.md ================================================================== --- kconf/kconf.md +++ kconf/kconf.md @@ -0,0 +1,64 @@ +# kconf + +while there are a number of existing configuration parser libraries out there, they all have their problems, and all depend on libc. since configuration string parsing is a fairly core functionality that would force many programs to either write their own code or drag libc back into their dependencies, supplying a basic parser with libk makes sense. + +## basic principles + +kconf is intended to be fast, lightweight, transparent, and low-overhead. + +to initialize a kconf structure, we begin by supplying a list of *atoms.* like in Xlib, an atom is a performant way to reference a known string of text from a compiled program. we can do this in two different ways, either by generating the values ourselves at compile time with an enum, or by generating them at runtime using the appropriate kconf interface. note that if you supply your own with an enum, because zero is used for in-band error signalling, the first atom should always be an error token. alternately, it may be explicitly set to a non-zero number and a return value of zero can be checked for implicitly or against a literal 0. + +note that, in a recurring libk pattern, if an element count of zero (or `null`) is passed to a function that takes an array of nullables, that function will treat its array argument as a null-terminated array to be counted at runtime. + +kconf is initialized by filling out the struct `kconf` with the parameters of operations and then passing it to the appropriate function. + + enum atoms { parse_error, user, pw, email, atomct }; + kconf kc = { + .decl = { atomct, { + { user, {4, "user" } }, + { pw, {8, "password"} }, + { email, {5, "email" } } + }} + }; + + /* with runtime counts: + * enum atoms { parse_error, user, pw, email }; + * kconf kc = { + * .decl = { null, { + * { user, {0, "user" } }, + * { pw, {0, "password"} }, + * { email, {0, "email" } }, + * { null } + * }} + * }; */ + + /* with macros: + * enum atoms { parse_error, user, password, email }; + * kconf kc = { + * .decl = {Kmpsa(kconf_decl, { + * Kconf_atom(user), + * Kconf_atom(password), + * Kconf_atom(email) + * })}; + * }; */ + +## types + +### struct kconf + * `union { kconf_decl decl; kconf_gen gen; };` + +### struct kconf_atom + + * `sz key` + * `ksraw string` + +### struct kconf_pair + + * `kconf_atom atom` + * `ksraw* dest` + + +## macros + + * `Kconf_atom(atom)` - a convenience macro for definining an pre-defined atom structure (`kconf_atom`), under the assumption that the C enumerator name is the same as the string used to name the field in the configuration file. inserts the text `{atom, {sizeof(#atom), #atom}}` + * `Kconf_atom_pfx(pfx,atom)` - a convenience macro for definining an pre-defined atom structure (`kconf_atom`), under the assumption that the C enumerator name is the string used to name the field in the configuration file with a prefix attached. inserts the text `{pfx##atom, {sizeof(#atom), #atom}}` ADDED kconf/makefile Index: kconf/makefile ================================================================== --- kconf/makefile +++ kconf/makefile @@ -0,0 +1,1 @@ +include ../modmake Index: kcore/core.h ================================================================== --- kcore/core.h +++ kcore/core.h @@ -87,10 +87,16 @@ # define KFstd_cpp11 # define KVstd c++11 # endif /* TODO: add more */ # endif #endif + +#ifdef KFstd_c11 +# define Kassert _Static_assert +#else +# define Kassert(x) { struct { int assertion_failed[(x) ? 1 : -1] }; } +#endif /* hooo boy. null. that one's got a storied * history across the versions and dialects. * below, we try to find the ideal way to * offer a "null" "keyword" depending on @@ -119,12 +125,12 @@ # define noreturn _Noreturn #else # define noreturn #endif -noreturn void kstop(longstat code); +noreturn void kstop(stat_long code); #ifdef KFclean # undef noreturn #endif #endif Index: kcore/def.h.m ================================================================== --- kcore/def.h.m +++ kcore/def.h.m @@ -2,10 +2,12 @@ --- ~ lexi hale --- this file gathers information on the environment it's --- being compiled in, setting macros that other headers --- need. it will be emitted as . --- vim: ft=c +#ifndef KIdef +#define KIdef [ifdef atom_target_bits] [define target: [atom_target_arch].[atom_target_os].[atom_target_bits]] #define KVbits [atom_target_bits] [else] @@ -28,5 +30,7 @@ # define Kerror(msg) Kpragma(GCC error #msg) #else # define Kerror(msg) Kpragma(message #msg) #endif #define Knoimpl(fn) Kerror(no implementation of fn for platform [target]) + +#endif Index: kcore/magic.h ================================================================== --- kcore/magic.h +++ kcore/magic.h @@ -4,18 +4,25 @@ * software. for this reason, we define here a variety * of "magical numbers" used to signal or describe * various states, messages, and errors. suggestions are * welcome. */ +#ifndef KImagic +#define KImagic + #include typedef enum kbad { // values to be returned by an entry function kbad_ok = 0, /* the requested operation completed * successfully */ + kbad_mem = 1, + /* the system does not have enough free + * memory to complete the requested operation */ + /* these are synchronized with freebsd's existing * sysexit.h conventions. */ kbad_usage = 64, /* # fbsd EX_USAGE * a usage screen was displayed to the user @@ -63,5 +70,7 @@ * to do the thing requested */ kbad_conf = 78, /* # fbsd EX_CONFIG * your configuration is fucked */ } kbad; + +#endif Index: kcore/makefile ================================================================== --- kcore/makefile +++ kcore/makefile @@ -5,10 +5,13 @@ # gen-headers = type.h include ../modmake +${OUT}/k/type.h: type.h.m ${TMP}/typesize.def + $(m-comp) $< $(file < ${TMP}/typesize.def) > $@ + ## the below code predates the introduction of gpp ## to generate these headers from templates instead ## of trying to write one for everypossible arch ## tuple. it is left as a monument to a terrible ## and now blissfully forgotten past. Index: kcore/stop.fn.c ================================================================== --- kcore/stop.fn.c +++ kcore/stop.fn.c @@ -7,11 +7,11 @@ #include // so we know what system this is #include #ifdef KFenv_posix # define STOPFN kio_posix_exit - extern void STOPFN(int); + extern noreturn void STOPFN(int); #else Knoimpl(kstop) #endif -noreturn void kstop (longstat code) { STOPFN(code); } +noreturn void kstop (stat_long code) { STOPFN(code); } Index: kcore/testbin.exe.c ================================================================== --- kcore/testbin.exe.c +++ kcore/testbin.exe.c @@ -1,18 +1,31 @@ #include #include #include #include + +struct object { + u8 a; + s16 b; + bool c; +}; kbad entry(kenv e) { const char msg[] = "hello from libk\n"; ksraw ptr = { Kmsz(msg), msg }; bool maybe = true; maybe = no; if (kiosend(e.std, ptr, null) == kiocond_ok) { - return kbad_ok; + /* great, continue */ } else { return kbad_io; } + + struct object* block = kmheapa(sizeof (struct object) * 4); + if (block == null) return kbad_mem; else return kbad_ok; + + block[1].a = 5; + + return kbad_ok; } Index: kcore/type.h.m ================================================================== --- kcore/type.h.m +++ kcore/type.h.m @@ -1,63 +1,154 @@ ---- kcore/type.h.m → +--- kcore/type.h.m → --- ~ lexi hale --- this file gathers information on the environment it's --- being compiled in, defining types that our code --- needs. it will be emitted as . --- vim: ft=c +#ifndef KItype +#define KItype + +typedef unsigned char kc_uint_min; +typedef signed char kc_sint_min; +typedef unsigned long long kc_uint_max; +typedef signed long long kc_sint_max; + +[ifdef type_bit8] + typedef unsigned [type_bit8] u8; + typedef signed [type_bit8] s8; +[else] + typedef kc_uint_min u8; + typedef kc_sint_min s8; +[endif] + +[ifdef type_bit16] + typedef unsigned [type_bit16] u16; + typedef signed [type_bit16] s16; +[else] + typedef kc_uint_max u16; + typedef kc_sint_max s16; +[endif] + +[ifdef type_bit32] + typedef unsigned [type_bit32] u32; + typedef signed [type_bit32] s32; +[else] + typedef kc_uint_max u32; + typedef kc_sint_max s32; +[endif] + +[ifdef type_bit64] + typedef unsigned [type_bit64] u64; + typedef signed [type_bit64] s64; + [ifndef type_bit128] +# if defined(__GNUC__) || defined(__clang__) + typedef unsigned __int128_t u128; + typedef signed __int128_t s128; +# else + typedef kc_uint_max u128; + typedef kc_sint_max s128; +# endif + [endif] +[else] + typedef kc_uint_max u64; + typedef kc_sint_max s64; + + typedef kc_uint_max u128; + typedef kc_sint_max s128; +[endif] + +[ifdef type_bit128] + typedef unsigned [type_bit128] u128; + typedef signed [type_bit128] s128; +[endif] + +enum /* max-min values of each type */ { + /* assuming two's complement. TODO: check math */ + /* TODO: figure out how to calc min */ + kc_byte_bits = [byte_bits], + u8_min = 0, u8_max = ((u8)-1), + u16_min = 0, u16_max = ((u16)-1), + u32_min = 0, u32_max = ((u32)-1), + u64_min = 0, u32_max = ((u64)-1), + u128_min = 0, u128_max = ((u128)-1), + + [define merge: $1$2] + [define [sspec type]: + [merge [type],_min] = 0 - ((1 << sizeof([type]) * kc_byte_bits) / 2), + [merge [type],_max] = (1 << sizeof([type]) * kc_byte_bits) / 2 - 1] + + [sspec s8], [sspec s16], [sspec s32], + [sspec s64], [sspec s128], + + kc_min_uchar = 0, kc_max_uchar = [type_max_u_char], + kc_min_ushort = 0, kc_max_ushort = [type_max_u_short], + kc_min_uint = 0, kc_max_uint = [type_max_u_int], + kc_min_ulong = 0, kc_max_ulong = [type_max_u_long], + kc_min_ullong = 0, kc_max_ullong = [type_max_u_llong], + + kc_min_schar = [type_min_s_char], kc_max_schar = [type_max_s_char], + kc_min_sshort = [type_min_s_short], kc_max_sshort = [type_max_s_short], + kc_min_sint = [type_min_s_int], kc_max_sint = [type_max_s_int], + kc_min_slong = [type_min_s_long], kc_max_slong = [type_max_s_long], + kc_min_sllong = [type_min_s_llong], kc_max_sllong = [type_max_s_llong], +}; -// arch bit length [atom_target_bits] ---- make some gigantic fucking assumptions -[if [atom_target_bits] >= 8] - typedef unsigned char u8; - typedef signed char s8; - [if [atom_target_bits] >= 16] - typedef unsigned short u16; - typedef signed short s16; - [if [atom_target_bits] >= 32] - typedef unsigned long u32; - typedef signed long s32; - [if [atom_target_bits] >= 64] - typedef unsigned long long u64; - typedef signed long long s64; - [if [atom_target_arch] == x86] - #if defined(__GNUC__) || defined(__clang__) - typedef __uint128_t u128; - typedef __int128_t s128; - #endif - [endif] - [endif] - [endif] - [endif] +[ifdef type_sz] + typedef [type_sz] sz; +[else] +# ifdef __cplusplus + /* C++ gives us a clean, standardized way to do this */ + typedef decltype (sizeof(char)) sz; +# else +# if defined(__GNUC__) || defined(__clang__) + typedef __typeof__ (sizeof(char)) sz; +# else + /* we're stumped - set sz to the safest possible value under + * the circumstances, and warn the user. */ +# warning no authoritative sz (size_t) type definition \ + available; defaulting to largest unsigned integer type + typedef kc_uint_max sz; +# endif +# endif [endif] -typedef u[atom_target_bits] sz; -typedef s[atom_target_bits] ssz; - ---- make sure something unlikely doesn't happen -[define [maxtype name, n]: - [if [n] > [atom_target_bits]] - typedef u[atom_target_bits] [name] - [else] - typedef u[n] [name] - [endif]] +[ifdef type_offset] + typedef [type_offset] offset; +[else] +# ifdef __cplusplus + /* C++ gives us a clean, standardized way to do this */ + typedef decltype (((void*)-1) - 1) offset; +# else +# if defined(__GNUC__) || defined(__clang__) + typedef __typeof__ (((void*)10) - ((void*)5)) offset; +# else + /* no dice - set offset to the safest possible value under + * the circumstances, and warn the user. */ +# warning no authoritative offset (ptrdiff_t) type definition \ + available; defaulting to largest unsigned integer type + typedef kc_sint_max offset; +# endif +# endif +[endif] // exit status integer types - pls use kbad in instead [if [target_posix] == yes] /* by convention, posix return values are 8-bit, * but note that many modern UNIXes do technically * support higher-bit values. for this reason, * longstat is defined differently under posix. */ typedef u8 stat; - [maxtype longstat, 32]; + typedef u32 stat_long; [else] [if ([atom_target_os] == win) || ([atom_target_os] == vms)] - [maxtype stat, 32] + typedef u32 stat; [else] typedef u8 stat; /* we don't know a specific exit status type * for your arch so we're going with a sane * default. if this is wrong, help us fix it! */ [endif] - typedef stat longstat; + typedef stat stat_long; [endif] + +#endif ADDED kdb/kdb.md Index: kdb/kdb.md ================================================================== --- kdb/kdb.md +++ kdb/kdb.md @@ -0,0 +1,34 @@ +# kdb + +kdb is a module for storing and loading data from files. + +## model + +the first argument to all kdb functions is of type `struct kdb`, which describes the database to be accessed. the first field of that struct is a pointer to a struct of type `struct kdb_fmt` which describes the format of the database. + +kdb encodes records as a tuple of three fields: (kind, key, value). `kind` is a 16-bit integer, `key` is an integer of platform width, and `value` is a blob decoded according to the type of the record, which is not saved in the database itself. records are indexed by the tuple (kind, key); `key` may be null. `kind` denotes the structure of the record, and is user-defined. + +to use strings as the keys for database entries, either atoms should be stored in the database or a hash function may be used. kdb contains procedures to automate the use of atoms as keys. + +## types + +### struct kdb + + * `struct kdb_fmt* fmt` + * `enum kdb_conn conn` + * `union { kfile* file; const kdb_store* mem; kmptr ptr; } store;` + +### struct kdb_rec + + * `u16 kind` + * `word key` + * `ksraw value` + +### enum kdb_conn + + * `kdb_conn_none`: no database is connected; calls will fail + * `kdb_conn_file`: the database is stored in a file; calls to modify it will modify the file on-disk + * `kdb_conn_file_static`: the database is stored in a file; calls to modify it will fail. if the file is writable to the process, can be seamlessly changed to `kdb_conn_file` and vice-versa + * `kdb_conn_mem`: the database is stored in-memory, allocated by kmem and referenced by `ptr`. calls to modify it will re-allocate memory via the appropriate interfaces. + * `kdb_conn_mem_static`: the database is stored in-memory, referenced by `mem`; calls to modify it will fail + ADDED kdb/makefile Index: kdb/makefile ================================================================== --- kdb/makefile +++ kdb/makefile @@ -0,0 +1,1 @@ +include ../modmake Index: kio/io.h ================================================================== --- kio/io.h +++ kio/io.h @@ -41,18 +41,24 @@ kiostream out; // text can be written to this stream } kiochan; typedef enum kiocond { - kiocond_ok, - // success - kiocond_fail, - // action failed + /* to check if a call failed, perform (x >= kiocond_fail) where x + * is that call's return value. more typically however you should + * select explicitly against kiocond_ok or kiocond_partial, since + * those situations will usually need to be handled differently. */ + + kiocond_ok, // success + kiocond_partial, // partial read or write + + kiocond_fail, // action failed - unspecified reason + kiocond_fail_closed_stream, // action failed because stream is closed } kiocond; kiocond kiosend(kiochan, ksraw, sz*); // send data to a channel kiocond kiorecv(kiochan, ksraw*); // receive data from a channel kmptr kiorecvall(kiochan, kmcell*, kmkind); // automatically allocate a bufer for a channel // kmkind is only used if kmcell* is NULL kiocond kiocon(kiochan, kiochan); // connect one channel to another #endif DELETED kio/kio_posix_fd_write.fn.x86.lin.32.s Index: kio/kio_posix_fd_write.fn.x86.lin.32.s ================================================================== --- kio/kio_posix_fd_write.fn.x86.lin.32.s +++ kio/kio_posix_fd_write.fn.x86.lin.32.s @@ -1,14 +0,0 @@ -bits 32 -global kio_posix_fd_write - -%include "../arch/x86.lin.32.s" -; vim: ft=nasm - -kio_posix_fd_write: - mov sys.reg.0, sys.call.write - mov sys.reg.1, [esp + 4] ; holy god but this took the most - mov sys.reg.2, [esp + 8] ; stupidly long time to fucking - mov sys.reg.3, [esp + 12]; figure out - sys.call - ret - DELETED kio/kio_posix_fd_write.fn.x86.lin.64.s Index: kio/kio_posix_fd_write.fn.x86.lin.64.s ================================================================== --- kio/kio_posix_fd_write.fn.x86.lin.64.s +++ kio/kio_posix_fd_write.fn.x86.lin.64.s @@ -1,14 +0,0 @@ -bits 64 -global kio_posix_fd_write - -%include "../arch/x86.lin.64.s" -; vim: ft=nasm - -kio_posix_fd_write: - mov sys.reg.0, sys.write - ; mov sys.reg.1, ccall.reg.0 - nop - ; mov sys.reg.2, ccall.reg.1 - nop - ; mov sys.reg.3, ccall.reg.2 - nop - sys.call - ret - ADDED kio/posix_fd_write.fn.x86.lin.32.s Index: kio/posix_fd_write.fn.x86.lin.32.s ================================================================== --- kio/posix_fd_write.fn.x86.lin.32.s +++ kio/posix_fd_write.fn.x86.lin.32.s @@ -0,0 +1,14 @@ +bits 32 +global kio_posix_fd_write + +%include "../arch/x86.lin.32.s" +; vim: ft=nasm + +kio_posix_fd_write: + mov sys.reg.0, sys.call.write + mov sys.reg.1, [esp + 4] ; holy god but this took the most + mov sys.reg.2, [esp + 8] ; stupidly long time to fucking + mov sys.reg.3, [esp + 12]; figure out + sys.call + ret + ADDED kio/posix_fd_write.fn.x86.lin.64.s Index: kio/posix_fd_write.fn.x86.lin.64.s ================================================================== --- kio/posix_fd_write.fn.x86.lin.64.s +++ kio/posix_fd_write.fn.x86.lin.64.s @@ -0,0 +1,14 @@ +bits 64 +global kio_posix_fd_write + +%include "../arch/x86.lin.64.s" +; vim: ft=nasm + +kio_posix_fd_write: + mov sys.reg.0, sys.write + ; mov sys.reg.1, ccall.reg.0 - nop + ; mov sys.reg.2, ccall.reg.1 - nop + ; mov sys.reg.3, ccall.reg.2 - nop + sys.call + ret + DELETED kio/send.c Index: kio/send.c ================================================================== --- kio/send.c +++ kio/send.c @@ -1,30 +0,0 @@ -#include -#include -#include -/* send.c - kiosend() - * ~ lexi hale - * kiosend() writes to a channel with an open out stream - */ - -// we define all platform functions here, -// whether or not they're for the correct -// platform - only the ones actually called -// by the generated code will be linked -extern sz kio_posix_fd_write(int fd, const char* buf, sz len); - -kiocond kiosend(kiochan target, ksraw string, sz* len) { -# ifdef KFenv_posix - sz size = kio_posix_fd_write(target.out.platform_fd, string.ptr, string.size); - if (size == -1) return kiocond_fail; //TODO: retrieve errno and offer more specific errors -# else -# if KVos == win -# error windows IO send function not yet defined -# else - Knoimpl(kiosend,KVos); -# error missing implementation // boring error for plebs -# endif -# endif - - if (len != null) *len = size; - return kiocond_ok; -} Index: kio/send.fn.c ================================================================== --- kio/send.fn.c +++ kio/send.fn.c @@ -1,33 +1,32 @@ #include #include #include -/* send.c - kiosend() +/* send.c - kiosend() "send to channel" * ~ lexi hale * kiosend() writes to a channel with an open out stream */ -// we define all platform functions here, -// whether or not they're for the correct -// platform - only the ones actually called -// by the generated code will be linked +/* we define all platform functions here, + * whether or not they're for the correct + * platform - only the ones actually called + * by the generated code will be linked */ extern sz kio_posix_fd_write(int fd, const char* buf, sz len); kiocond kiosend(kiochan target, ksraw string, sz* len) { + if (target.out.kind == kiostream_closed) return kiocond_fail_closed_stream; + # ifdef KFenv_posix sz size = kio_posix_fd_write(target.out.platform_fd, string.ptr, string.size); if (size == -1) return kiocond_fail; //TODO: retrieve errno and offer more specific errors # else # if KVos == win # error windows IO send function not yet defined # else - _Pragma("GCC diagnostic error \"" // fancy error for gcc - "IO send fn for platform " #KVos " not defined" - "\"")) -# error IO send fn not defined for platform - // boring error for plebs + Knoimpl(kiosend,KVos); +# error missing implementation // boring error for plebs # endif # endif if (len != null) *len = size; return kiocond_ok; } ADDED kmem/heapa.fn.c Index: kmem/heapa.fn.c ================================================================== --- kmem/heapa.fn.c +++ kmem/heapa.fn.c @@ -0,0 +1,60 @@ +#include +#include +/* heapa.c - kmheapa() "heap alloc" + * ~ lexi hale + * kmheapa() allocates a pointer on the heap à la libc malloc() + * see also: kmheapf() "heap free" + */ + +/* we define all platform functions here, + * whether or not they're for the correct + * platform - only the ones actually called + * by the generated code will be linked, + * linker errors are our friend here! */ +extern void* kmem_posix_mmap(void* addr, + unsigned long sz, unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long off); + +enum posix_prot { + posix_prot_none = 0, + posix_prot_read = 1 << 0, + posix_prot_write = 1 << 1, + posix_prot_exec = 1 << 2 +}; + +enum posix_map { + posix_map_shared = 1, + posix_map_private = 2 +}; + +enum posix_flag { + posix_flag_fixed = 0x10, + posix_flag_anonymous = 0x20, + + /* platform flags */ + posix_flag_linux_hugetlb = 0x40000 +}; + +void* kmheapa(sz len) { + /* allocate an object on the heap and return + * a pointer, or NULL if the allocation failed. */ + void* val; + +# ifdef KFenv_posix + /* posix APIs - we've got it easy */ + val = kmem_posix_mmap(null, len, posix_prot_read | posix_prot_write, + posix_flag_anonymous, -1, 0); + /* impl note: while per manpage fd is "ignored" + * for MAP_ANONYMOUS, "some implementations" require + * a value of -1 */ + + if (val == (void*) -1) return null; + /* worth retrieving errno? discuss */ + +# else + Knoimpl(kmheapa,KVos); +# error missing implementation +# endif + + return val; +} Index: kmem/kmem.md ================================================================== --- kmem/kmem.md +++ kmem/kmem.md @@ -157,5 +157,8 @@ ## macros kmem defines the following macros. * `Kmsz(array)` - a convenience macro to return the number of elements in a static array. inserts the text `( sizeof (array) / sizeof (array) [0] )` + * `Kmszs(type, struct)` - a convenience macro to return the size of a struct. requires compound literals. + * `Kmszsa(type, array)` - calculates the number of elements in an array of a given struct type. inserts the text `( sizeof ( (type) array ) / sizeof (type) )` + * `Kmpsa(type, struct)` - a convenience macro to insert a "pascal struct array" - that is, a struct array prefixed with a size value. this is equivalent to `Kmszsa(type, array), array` Index: kmem/mem.h ================================================================== --- kmem/mem.h +++ kmem/mem.h @@ -33,6 +33,11 @@ kmshred shred; void* ref; kmcell* cell; } kmptr; +/* heap functions */ + +void* kmheapa(sz); +void kmheapf(void*); + #endif ADDED kmem/posix_mmap.fn.x86.lin.64.s Index: kmem/posix_mmap.fn.x86.lin.64.s ================================================================== --- kmem/posix_mmap.fn.x86.lin.64.s +++ kmem/posix_mmap.fn.x86.lin.64.s @@ -0,0 +1,24 @@ +bits 64 +%include "../arch/x86.lin.64.s" +%include "../arch/x86.cdecl.64.s" +; vim: ft=nasm + +global kmem_posix_mmap +kmem_posix_mmap: + ; to call mmap, we need to translate the cdecl64 + ; register arguments to their appropriate syscall64 + ; registers. these are mostly the same, with one + ; obnoxious exception. the NOPs have been written + ; in as comments to aid in understanding. + + mov sys.reg.1, ccall.reg.0 ;nop - rdi → rdi + mov sys.reg.2, ccall.reg.1 ;nop - rsi → rsi + mov sys.reg.3, ccall.reg.2 ;nop - rdx → rdx + mov sys.reg.4, ccall.reg.3 ; OP - rcx → r10 + mov sys.reg.5, ccall.reg.4 ;nop - r8 → r8 + mov sys.reg.6, ccall.reg.5 ;nop - r9 → r9 + + mov sys.reg.0, sys.mmap + sys.call + + mov ccall.reg.ret, sys.reg.ret ; rax → rdi Index: kstr/str.h ================================================================== --- kstr/str.h +++ kstr/str.h @@ -8,8 +8,13 @@ kmptr ptr; } kstr; typedef struct ksraw { sz size; - char* ptr; + const char* ptr; } ksraw; + +typedef struct ksmut { + sz size; + char* ptr; +} ksmut; #endif Index: makefile ================================================================== --- makefile +++ makefile @@ -102,18 +102,21 @@ cd $* && $(MAKE) tool %.dbg: %/makefile $(OUT) cd $* && $(MAKE) dbg -%.def: %/makefile $(TMP)/precomp.g $(OUT) $(OUT)/k +%.def: %/makefile $(TMP)/precomp.g $(TMP)/typesize.def $(OUT) $(OUT)/k cd $* && $(MAKE) def %.calls: arch/makefile cd arch && $(MAKE) $(TMP)/calls.$*.s $(TMP)/precomp.g: grammar/precomp.g.gpp $(TMP) cd grammar && $(MAKE) $@ + +$(TMP)/typesize.def: arch/makefile $(TMP) + cd arch && $(MAKE) $@ $(OUT)/libk.so: $(fnobjects) ld -shared $(COMPLIB) -o $@ $^ @# $(CC) -shared -fPIC -nostdlib $(COMPLIB) -o $@ $(OUT)/*.o