Make terminal ui binaries work well everywhere

Here's some screenshots of an emulator tui program that was compiled on
Linux, then scp'd it to Windows, Mac, and FreeBSD.

https://justine.storage.googleapis.com/blinkenlights-cmdexe.png
https://justine.storage.googleapis.com/blinkenlights-imac.png
https://justine.storage.googleapis.com/blinkenlights-freebsd.png
https://justine.storage.googleapis.com/blinkenlights-lisp.png

How is this even possible that we have a nontrivial ui binary that just
works on Mac, Windows, Linux, and BSD? Surely a first ever achievement.

Fixed many bugs. Bootstrapped John McCarthy's metacircular evaluator on
bare metal in half the size of Altair BASIC (about 2.5kb) and ran it in
emulator for fun and profit.
This commit is contained in:
Justine Tunney 2020-10-10 21:18:53 -07:00
parent 680daf1210
commit 9e3e985ae5
276 changed files with 7026 additions and 3790 deletions

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,8 @@ TOOL_BUILD_EMUBIN_BINS = \
o/$(MODE)/tool/build/emubin/prime.bin \
o/$(MODE)/tool/build/emubin/prime.bin.dbg \
o/$(MODE)/tool/build/emubin/pi.bin \
o/$(MODE)/tool/build/emubin/pi.bin.dbg
o/$(MODE)/tool/build/emubin/pi.bin.dbg \
o/$(MODE)/tool/build/emubin/linmap.elf
TOOL_BUILD_EMUBIN_A = o/$(MODE)/tool/build/emubin/emubin.a
TOOL_BUILD_EMUBIN_FILES := $(wildcard tool/build/emubin/*)
@ -50,6 +51,13 @@ o/$(MODE)/tool/build/emubin/%.bin.dbg: \
$(TOOL_BUILD_EMUBIN_A).pkg
@$(ELFLINK) -e emucrt -z max-page-size=0x10
o/$(MODE)/tool/build/emubin/%.elf: \
$(TOOL_BUILD_EMUBIN_DEPS) \
$(TOOL_BUILD_EMUBIN_A) \
o/$(MODE)/tool/build/emubin/%.o \
$(ELF)
@$(ELFLINK)
o/dbg/tool/build/emubin/lisp.real.com.dbg: \
$(TOOL_BUILD_EMUBIN_DEPS) \
$(TOOL_BUILD_EMUBIN_A) \

View file

@ -17,7 +17,16 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "tool/build/lib/machine.h"
#include "libc/linux/exit.h"
#include "libc/linux/fstat.h"
#include "libc/linux/mmap.h"
#include "libc/linux/open.h"
void InitMachine(struct Machine *m) {
struct stat st;
void _start(void) {
long fd = LinuxOpen("/etc/passwd", 0, 0);
LinuxFstat(fd, &st);
LinuxMmap((void *)0x000000000000, st.st_size, 1, 2, fd, 0);
LinuxExit(0);
}

View file

@ -16,237 +16,20 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "tool/build/emubin/lisp.h"
#define TRACE 0
#define ERRORS 1
#define LONG long
#define WORD short
#define WORDS 8192
#define TRACE 0 // print eval input output
#define RETRO 1 // auto capitalize input
#define ERRORS 1 // print messages or undefined behavior
#define DELETE 1 // allow backspace to rub out symbol
#define QUOTES 1 // allow 'X shorthand (QUOTE X)
#define MUTABLE 0 // allow setting globals
#define PROMPT 1 // show repl prompt
#define WORD short
#define WORDS 8192
/*───────────────────────────────────────────────────────────────────────────│─╗
The LISP Challenge § Impure x86_64 Linux 8086 PC BIOS System Integration
*/
#define TYPE(x) /* a.k.a. x&1 */ \
({ \
char IsAtom; \
asm("test%z1\t$1,%1" : "=@ccnz"(IsAtom) : "Qm"((char)x)); \
IsAtom; \
})
#define OBJECT(t, v) /* a.k.a. v<<1|t */ \
({ \
__typeof(v) Val = (v); \
asm("shl\t%0" : "+r"(Val)); \
Val | (t); \
})
#define SUB(x, y) /* a.k.a. x-y */ \
({ \
__typeof(x) Reg = (x); \
asm("sub\t%1,%0" : "+rm"(Reg) : "g"(y)); \
Reg; \
})
#define STOS(di, c) asm("stos%z1" : "+D"(di), "=m"(*(di)) : "a"(c))
#define LODS(si) \
({ \
typeof(*(si)) c; \
asm("lods%z2" : "+S"(si), "=a"(c) : "m"(*(si))); \
c; \
})
#define REAL_READ_(REG, BASE, INDEX, DISP) \
({ \
__typeof(*(BASE)) Reg; \
if (__builtin_constant_p(INDEX) && !(INDEX)) { \
asm("mov\t%c2(%1),%0" \
: REG(Reg) \
: "bDS"(BASE), "i"((DISP) * sizeof(*(BASE))), \
"m"(BASE[(INDEX) + (DISP)])); \
} else { \
asm("mov\t%c3(%1,%2),%0" \
: REG(Reg) \
: "b"(BASE), "DS"((long)(INDEX) * sizeof(*(BASE))), \
"i"((DISP) * sizeof(*(BASE))), "m"(BASE[(INDEX) + (DISP)])); \
} \
Reg; \
})
/* #ifdef __REAL_MODE__ */
#define REAL_READ(BASE, INDEX, DISP) /* a.k.a. b[i] */ \
(sizeof(*(BASE)) == 1 ? REAL_READ_("=Q", BASE, INDEX, DISP) \
: REAL_READ_("=r", BASE, INDEX, DISP))
/* #else */
/* #define REAL_READ(BASE, INDEX, DISP) BASE[INDEX + DISP] */
/* #endif */
#define REAL_READ_ARRAY_FIELD_(REG, OBJECT, MEMBER, INDEX, DISP) \
({ \
__typeof(*(OBJECT->MEMBER)) Reg; \
if (!(OBJECT)) { \
asm("mov\t%c2(%1),%0" \
: REG(Reg) \
: "bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
sizeof(*(OBJECT->MEMBER)) * (DISP)), \
"m"(OBJECT->MEMBER)); \
} else { \
asm("mov\t%c3(%1,%2),%0" \
: REG(Reg) \
: "b"(OBJECT), "DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
sizeof(*(OBJECT->MEMBER)) * (DISP)), \
"m"(OBJECT->MEMBER)); \
} \
Reg; \
})
/* #ifdef __REAL_MODE__ */
#define REAL_READ_ARRAY_FIELD(OBJECT, MEMBER, INDEX, DISP) /* o->m[i] */ \
(sizeof(*(OBJECT->MEMBER)) == 1 \
? REAL_READ_ARRAY_FIELD_("=Q", OBJECT, MEMBER, INDEX, DISP) \
: REAL_READ_ARRAY_FIELD_("=r", OBJECT, MEMBER, INDEX, DISP))
/* #else */
/* #define REAL_READ_ARRAY_FIELD(o, m, i, d) o->m[i + d] */
/* #endif */
#define REAL_WRITE_ARRAY_FIELD_(REG, OBJECT, MEMBER, INDEX, DISP, VALUE) \
do { \
if (!(OBJECT)) { \
asm("mov\t%1,%c3(%2)" \
: "=m"(OBJECT->MEMBER) \
: REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), \
"bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
} else { \
asm("mov\t%1,%c4(%2,%3)" \
: "=m"(OBJECT->MEMBER) \
: REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), "b"(OBJECT), \
"DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
} \
} while (0)
/* #ifdef __REAL_MODE__ */
#define REAL_WRITE_ARRAY_FIELD(OBJECT, MEMBER, INDEX, DISP, VALUE) \
do { \
__typeof(*(OBJECT->MEMBER)) Reg; \
switch (sizeof(*(OBJECT->MEMBER))) { \
case 1: \
REAL_WRITE_ARRAY_FIELD_("Q", OBJECT, MEMBER, INDEX, DISP, VALUE); \
break; \
default: \
REAL_WRITE_ARRAY_FIELD_("ri", OBJECT, MEMBER, INDEX, DISP, VALUE); \
break; \
} \
} while (0)
/* #else */
/* #define REAL_WRITE_ARRAY_FIELD(o, m, i, d, v) o->m[i + d] = v */
/* #endif */
long jb[8];
int setjmp(void *) __attribute__((__returns_twice__));
int longjmp(void *, int) __attribute__((__noreturn__));
static inline void *SetMemory(void *di, int al, unsigned long cx) {
asm("rep stosb"
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(cx), "a"(al));
return di;
}
static inline void *CopyMemory(void *di, void *si, unsigned long cx) {
asm("rep movsb"
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(si), "2"(cx));
return di;
}
static void RawMode(void) {
#ifndef __REAL_MODE__
int rc;
int c[14];
asm volatile("syscall"
: "=a"(rc)
: "0"(0x10), "D"(0), "S"(0x5401), "d"(c)
: "rcx", "r11", "memory");
c[0] &= ~0b0000010111111000; // INPCK|ISTRIP|PARMRK|INLCR|IGNCR|ICRNL|IXON
c[2] &= ~0b0000000100110000; // CSIZE|PARENB
c[2] |= 0b00000000000110000; // CS8
c[3] &= ~0b1000000001011010; // ECHONL|ECHO|ECHOE|IEXTEN|ICANON
asm volatile("syscall"
: "=a"(rc)
: "0"(0x10), "D"(0), "S"(0x5402), "d"(c)
: "rcx", "r11", "memory");
#endif
}
__attribute__((__noinline__)) static void PrintChar(LONG c) {
#ifdef __REAL_MODE__
asm volatile("mov\t$0x0E,%%ah\n\t"
"int\t$0x10"
: /* no outputs */
: "a"(c), "b"(7)
: "memory");
#else
static short buf;
int rc;
buf = c;
asm volatile("syscall"
: "=a"(rc)
: "0"(1), "D"(1), "S"(&buf), "d"(1)
: "rcx", "r11", "memory");
#endif
}
static void PrintString(char *s) {
char c;
for (;;) {
if (!(c = REAL_READ(s, 0, 0))) break;
PrintChar(c);
++s;
}
}
static int XlatChar(LONG c) {
if (c == 0x7F) return '\b';
if (c >= 'a') {
asm volatile("" ::: "memory");
if (c <= 'z') c -= 'a' - 'A';
}
return c;
}
static int EchoChar(LONG c) {
if (c != '\b') {
PrintChar(c);
if (c == '\r') {
PrintChar('\n');
}
}
return c;
}
__attribute__((__noinline__)) static noinline int ReadChar(void) {
int c;
#ifdef __REAL_MODE__
asm volatile("int\t$0x16" : "=a"(c) : "0"(0) : "memory");
#else
static int buf;
asm volatile("syscall"
: "=a"(c)
: "0"(0), "D"(0), "S"(&buf), "d"(1)
: "rcx", "r11", "memory");
c = buf;
#endif
return EchoChar(XlatChar(c));
}
/*───────────────────────────────────────────────────────────────────────────│─╗
The LISP Challenge § Pure Original LISP Machine
The LISP Challenge § LISP Machine
*/
#define ATOM 0
@ -261,10 +44,8 @@ __attribute__((__noinline__)) static noinline int ReadChar(void) {
#define ATOM_CAR 50
#define ATOM_CDR 58
#define ATOM_CONS 66
#define ATOM_LABEL 76
#define ATOM_LAMBDA 88
#define ATOM_SET 102
#define ATOM_DEFUN 110
#define ATOM_LAMBDA 76
#define ATOM_SET 90
#define Quote(x) List(ATOM_QUOTE, x)
#define List(x, y) Cons(x, Cons(y, NIL))
@ -279,9 +60,6 @@ __attribute__((__noinline__)) static noinline int ReadChar(void) {
#define VALUE(x) ((x) >> 1)
#define PTR(i) ((i) << 1 | CONS)
#define ARRAYLEN(A) \
((sizeof(A) / sizeof(*(A))) / ((unsigned)!(sizeof(A) % sizeof(*(A)))))
struct Lisp {
WORD mem[WORDS];
unsigned char syntax[256];
@ -289,25 +67,24 @@ struct Lisp {
WORD globals;
WORD index;
char token[128];
long jb[8];
char str[WORDS];
};
_Static_assert(sizeof(struct Lisp) <= 0x7c00 - 0x600,
"LISP Machine too large for real mode");
_Alignas(char) const char kSymbols[] = "\
NIL\0T\0QUOTE\0ATOM\0EQ\0COND\0CAR\0CDR\0CONS\0LABEL\0LAMBDA\0SET\0DEFUN\0";
_Alignas(WORD) const WORD kGlobals[] = {
[0] = PTR(2), // ((T . T) (NIL . NIL))
[1] = PTR(4), //
[2] = ATOM_T, // (T . T)
[3] = ATOM_T, //
[4] = PTR(6), // ((NIL . NIL))
[5] = NIL, //
[6] = NIL, // (NIL . NIL)
[7] = NIL, //
};
_Alignas(char) const char kSymbols[] = "NIL\0"
"T\0"
"QUOTE\0"
"ATOM\0"
"EQ\0"
"COND\0"
"CAR\0"
"CDR\0"
"CONS\0"
"LAMBDA\0"
"SET\0";
#ifdef __REAL_MODE__
static struct Lisp *const q;
@ -315,56 +92,55 @@ static struct Lisp *const q;
static struct Lisp q[1];
#endif
static void Print(LONG);
static void Print(long);
static WORD GetList(void);
static WORD GetObject(void);
static void PrintObject(LONG);
static WORD Eval(LONG, LONG);
static void PrintObject(long);
static WORD Eval(long, long);
static void SetupSyntax(void) {
q->syntax[' '] = ' ';
q->syntax['\t'] = ' ';
q->syntax['\r'] = ' ';
q->syntax['\n'] = ' ';
q->syntax['('] = '(';
q->syntax[')'] = ')';
q->syntax['.'] = '.';
q->syntax['\''] = '\'';
unsigned char *syntax = q->syntax;
asm("" : "+bSD"(syntax));
syntax[' '] = ' ';
syntax['\r'] = ' ';
syntax['\n'] = ' ';
syntax['('] = '(';
syntax[')'] = ')';
syntax['.'] = '.';
#if QUOTES
syntax['\''] = '\'';
#endif
}
static inline WORD Car(LONG x) {
return REAL_READ_ARRAY_FIELD(q, mem, VALUE(x), 0);
static inline WORD Car(long x) {
return PEEK_ARRAY(q, mem, VALUE(x), 0);
}
static inline WORD Cdr(LONG x) {
return REAL_READ_ARRAY_FIELD(q, mem, VALUE(x), 1);
static inline WORD Cdr(long x) {
return PEEK_ARRAY(q, mem, VALUE(x), 1);
}
static WORD Set(long i, long k, long v) {
POKE_ARRAY(q, mem, VALUE(i), 0, k);
POKE_ARRAY(q, mem, VALUE(i), 1, v);
return i;
}
static WORD Cons(WORD car, WORD cdr) {
#if TRACE
PrintString("CONS->");
Print(car);
PrintString(" ");
Print(cdr);
#endif
int i, cell;
i = q->index;
REAL_WRITE_ARRAY_FIELD(q, mem, i, 0, car);
REAL_WRITE_ARRAY_FIELD(q, mem, i, 1, cdr);
POKE_ARRAY(q, mem, i, 0, car);
POKE_ARRAY(q, mem, i, 1, cdr);
q->index = i + 2;
cell = OBJECT(CONS, i);
#if TRACE
PrintString("CONS<-");
Print(cell);
#endif
return cell;
}
static void SetupBuiltins(void) {
CopyMemory(q->str, kSymbols, sizeof(kSymbols));
CopyMemory(q->mem, kGlobals, sizeof(kGlobals));
q->index = ARRAYLEN(kGlobals);
q->mem[0] = PTR(2);
q->globals = PTR(0);
q->index = 4;
}
static char *StpCpy(char *d, char *s) {
@ -383,7 +159,7 @@ WORD Intern(char *s) {
c = LODS(z);
while (c) {
for (j = 0;; ++j) {
if (c != REAL_READ(s, j, 0)) {
if (c != PEEK(s, j, 0)) {
break;
}
if (!c) {
@ -400,7 +176,33 @@ WORD Intern(char *s) {
}
forceinline unsigned char XlatSyntax(unsigned char b) {
return REAL_READ_ARRAY_FIELD(q, syntax, b, 0);
return PEEK_ARRAY(q, syntax, b, 0);
}
static void PrintString(char *s) {
char c;
for (;;) {
if (!(c = PEEK(s, 0, 0))) break;
PrintChar(c);
++s;
}
}
static int GetChar(void) {
int c;
c = ReadChar();
#if RETRO
if (c >= 'a') {
CompilerBarrier();
if (c <= 'z') c -= 'a' - 'A';
}
#endif
#if DELETE
if (c == '\b') return c;
#endif
PrintChar(c);
if (c == '\r') PrintChar('\n');
return c;
}
static void GetToken(void) {
@ -409,20 +211,20 @@ static void GetToken(void) {
b = q->look;
t = q->token;
while (XlatSyntax(b) == ' ') {
b = ReadChar();
b = GetChar();
}
if (XlatSyntax(b)) {
STOS(t, b);
b = ReadChar();
b = GetChar();
} else {
while (b && !XlatSyntax(b)) {
if (b != '\b') {
if (!DELETE || b != '\b') {
STOS(t, b);
} else if (t > q->token) {
PrintString("\b \b");
if (t > q->token) --t;
}
b = ReadChar();
b = GetChar();
}
}
STOS(t, 0);
@ -447,12 +249,14 @@ static WORD GetList(void) {
switch (*q->token & 0xFF) {
default:
return AddList(GetObject());
case '\'':
return AddList(GetQuote());
case ')':
return NIL;
case '.':
return ConsumeObject();
#if QUOTES
case '\'':
return AddList(GetQuote());
#endif
}
}
@ -460,15 +264,17 @@ static WORD GetObject(void) {
switch (*q->token & 0xFF) {
default:
return Intern(q->token);
case '\'':
return GetQuote();
case '(':
return GetList();
#if QUOTES
case '\'':
return GetQuote();
#endif
}
}
static WORD ReadObject(void) {
q->look = ReadChar();
q->look = GetChar();
GetToken();
return GetObject();
}
@ -477,11 +283,18 @@ static WORD Read(void) {
return ReadObject();
}
static void PrintAtom(LONG x) {
static void PrintAtom(long x) {
PrintString(q->str + VALUE(x));
}
static void PrintList(LONG x) {
static void PrintList(long x) {
#if QUOTES
if (Car(x) == ATOM_QUOTE) {
PrintChar('\'');
PrintObject(Cadr(x));
return;
}
#endif
PrintChar('(');
PrintObject(Car(x));
while ((x = Cdr(x))) {
@ -491,12 +304,13 @@ static void PrintList(LONG x) {
} else {
PrintString(" . ");
PrintObject(x);
break;
}
}
PrintChar(')');
}
static void PrintObject(LONG x) {
static void PrintObject(long x) {
if (TYPE(x) == ATOM) {
PrintAtom(x);
} else {
@ -504,19 +318,13 @@ static void PrintObject(LONG x) {
}
}
static void Print(LONG i) {
static void Print(long i) {
PrintObject(i);
PrintString("\r\n");
}
__attribute__((__noreturn__)) static void Reset(void) {
longjmp(jb, 1);
}
__attribute__((__noreturn__)) static void OnUndefined(LONG x) {
PrintString("UNDEF! ");
Print(x);
Reset();
longjmp(q->jb, 1);
}
__attribute__((__noreturn__)) static void OnArity(void) {
@ -524,145 +332,69 @@ __attribute__((__noreturn__)) static void OnArity(void) {
Reset();
}
__attribute__((__noreturn__)) static void OnUndefined(long x) {
PrintString("UNDEF! ");
Print(x);
Reset();
}
#if !ERRORS
#define OnUndefined(x) __builtin_unreachable()
#define OnArity() __builtin_unreachable()
#define OnUndefined(x) __builtin_unreachable()
#endif
/*───────────────────────────────────────────────────────────────────────────│─╗
The LISP Challenge § Bootstrap John McCarthy's Metacircular Evaluator
*/
static WORD Atom(LONG x) {
static WORD Atom(long x) {
return BOOL(TYPE(x) == ATOM);
}
static WORD Null(LONG x) {
static WORD Null(long x) {
return BOOL(!x);
}
static WORD Eq(LONG x, LONG y) {
return BOOL(x == y); /* undefined if !Atom(x)||!Atom(y) */
static WORD Eq(long x, long y) {
return BOOL(x == y);
}
static WORD Assoc(LONG x, LONG y) {
if (Null(y)) OnUndefined(x);
if (Eq(Caar(y), x)) return Cdar(y);
return Assoc(x, Cdr(y));
static WORD Arg1(long e, long a) {
return Eval(Cadr(e), a);
}
static WORD Append(LONG x, LONG y) {
#if TRACE
PrintString("APPEND->");
Print(x);
PrintString(" ");
Print(y);
#endif
if (!Null(x)) {
x = Cons(Car(x), Append(Cdr(x), y));
} else {
x = y;
}
#if TRACE
PrintString("APPEND<-");
Print(x);
#endif
return x;
static WORD Arg2(long e, long a) {
return Eval(Caddr(e), a);
}
/**
* Gives list of pairs of corresponding elements of the lists x and y.
* E.g. pair[(A,B,C);(X,(Y,Z),U)] = ((A.X),(B.(Y,Z)),(C.U))
* @note recoded to make lists in dot notation
* @note it's zip() basically
*/
static WORD Pair_(LONG x, LONG y) {
static WORD Append(long x, long y) {
return Null(x) ? y : Cons(Car(x), Append(Cdr(x), y));
}
static WORD Evcon(long c, long a) {
return Eval(Caar(c), a) ? Eval(Cadar(c), a) : Evcon(Cdr(c), a);
}
static WORD Evlis(long m, long a) {
return m ? Cons(Eval(Car(m), a), Evlis(Cdr(m), a)) : NIL;
}
static WORD Assoc(long x, long y) {
if (!y) OnUndefined(x);
return Eq(Caar(y), x) ? Cdar(y) : Assoc(x, Cdr(y));
}
static WORD Pair(long x, long y) {
if (Null(x) && Null(y)) {
return NIL;
} else if (TYPE(x) == CONS && TYPE(y) == CONS) {
return Cons(Cons(Car(x), Car(y)), Pair_(Cdr(x), Cdr(y)));
} else if (!Atom(x) && !Atom(y)) {
return Cons(Cons(Car(x), Car(y)), Pair(Cdr(x), Cdr(y)));
} else {
OnArity();
}
}
static WORD Pair(LONG x, LONG y) {
#if TRACE
PrintString("PAIR->");
Print(x);
PrintString(" ");
Print(y);
#endif
x = Pair_(x, y);
#if TRACE
PrintString("PAIR<-");
Print(x);
#endif
return x;
}
static WORD Appq(long m) {
if (m) {
return Cons(List(ATOM_QUOTE, Car(m)), Appq(Cdr(m)));
} else {
return NIL;
}
}
static WORD Apply(long f, long a) {
return Eval(Cons(f, Appq(a)), NIL);
}
static WORD Evcon(LONG c, LONG a) {
if (Eval(Caar(c), a)) {
return Eval(Cadar(c), a);
} else {
return Evcon(Cdr(c), a);
}
}
static WORD Evlis_(LONG m, LONG a) {
if (m) {
return Cons(Eval(Car(m), a), Evlis_(Cdr(m), a));
} else {
return NIL;
}
}
static WORD Evlis(LONG m, LONG a) {
#if TRACE
PrintString("EVLIS->");
Print(m);
PrintString(" ");
Print(a);
#endif
m = Evlis_(m, a);
#if TRACE
PrintString("EVLIS<-");
Print(m);
#endif
return m;
}
static WORD Set(LONG e) {
WORD name, value;
name = Car(e);
value = Cadr(e);
q->globals = Cons(Cons(name, value), q->globals);
return value;
}
static WORD Defun(LONG e) {
WORD name, args, body, lamb;
name = Car(e);
args = Cadr(e);
body = Caddr(e);
lamb = Cons(ATOM_LAMBDA, List(args, body));
q->globals = Cons(Cons(name, lamb), q->globals);
return name;
}
static WORD Evaluate(LONG e, LONG a) {
static WORD Evaluate(long e, long a) {
if (Atom(e)) {
return Assoc(e, a);
} else if (Atom(Car(e))) {
@ -670,26 +402,24 @@ static WORD Evaluate(LONG e, LONG a) {
case ATOM_QUOTE:
return Cadr(e);
case ATOM_ATOM:
return Atom(Eval(Cadr(e), a));
return Atom(Arg1(e, a));
case ATOM_EQ:
return Eq(Eval(Cadr(e), a), Eval(Caddr(e), a));
return Eq(Arg1(e, a), Arg2(e, a));
case ATOM_COND:
return Evcon(Cdr(e), a);
case ATOM_CAR:
return Car(Eval(Cadr(e), a));
return Car(Arg1(e, a));
case ATOM_CDR:
return Cdr(Eval(Cadr(e), a));
return Cdr(Arg1(e, a));
case ATOM_CONS:
return Cons(Eval(Cadr(e), a), Eval(Caddr(e), a));
case ATOM_DEFUN:
return Defun(Cdr(e));
return Cons(Arg1(e, a), Arg2(e, a));
#if MUTABLE
case ATOM_SET:
return Set(Cdr(e));
return Cdar(Set(a, Cons(Arg1(e, a), Arg2(e, a)), Cons(Car(a), Cdr(a))));
#endif
default:
return Eval(Cons(Assoc(Car(e), a), Evlis(Cdr(e), a)), a);
}
} else if (Eq(Caar(e), ATOM_LABEL)) {
return Eval(Cons(Caddar(e), Cdr(e)), Cons(Cons(Cadar(e), Car(e)), a));
} else if (Eq(Caar(e), ATOM_LAMBDA)) {
return Eval(Caddar(e), Append(Pair(Cadar(e), Evlis(Cdr(e), a)), a));
} else {
@ -697,7 +427,8 @@ static WORD Evaluate(LONG e, LONG a) {
}
}
static WORD Eval(LONG e, LONG a) {
static WORD Eval(long e, long a) {
WORD r;
#if TRACE
PrintString("->");
Print(e);
@ -717,9 +448,13 @@ static WORD Eval(LONG e, LONG a) {
*/
void Repl(void) {
setjmp(jb);
#if ERRORS
setjmp(q->jb);
#endif
for (;;) {
#if PROMPT
PrintString("* ");
#endif
Print(Eval(Read(), q->globals));
}
}
@ -728,8 +463,10 @@ int main(int argc, char *argv[]) {
/* RawMode(); */
SetupSyntax();
SetupBuiltins();
#if PROMPT
PrintString("THE LISP CHALLENGE V1\r\n"
"VISIT GITHUB.COM/JART\r\n");
#endif
Repl();
return 0;
}

182
tool/build/emubin/lisp.h Normal file
View file

@ -0,0 +1,182 @@
/*───────────────────────────────────────────────────────────────────────────│─╗
The LISP Challenge § Hardware Integration w/ x86_64 Linux & 8086 PC BIOS
*/
#define CompilerBarrier() asm volatile("" ::: "memory");
#define TYPE(x) /* a.k.a. x&1 */ \
({ \
char IsAtom; \
asm("test%z1\t$1,%1" : "=@ccnz"(IsAtom) : "Qm"((char)x)); \
IsAtom; \
})
#define OBJECT(t, v) /* a.k.a. v<<1|t */ \
({ \
__typeof(v) Val = (v); \
asm("shl\t%0" : "+r"(Val)); \
Val | (t); \
})
#define SUB(x, y) /* a.k.a. x-y */ \
({ \
__typeof(x) Reg = (x); \
asm("sub\t%1,%0" : "+rm"(Reg) : "g"(y)); \
Reg; \
})
#define STOS(di, c) asm("stos%z1" : "+D"(di), "=m"(*(di)) : "a"(c))
#define LODS(si) \
({ \
typeof(*(si)) c; \
asm("lods%z2" : "+S"(si), "=a"(c) : "m"(*(si))); \
c; \
})
#define PEEK_(REG, BASE, INDEX, DISP) \
({ \
__typeof(*(BASE)) Reg; \
if (__builtin_constant_p(INDEX) && !(INDEX)) { \
asm("mov\t%c2(%1),%0" \
: REG(Reg) \
: "bDS"(BASE), "i"((DISP) * sizeof(*(BASE))), \
"m"(BASE[(INDEX) + (DISP)])); \
} else { \
asm("mov\t%c3(%1,%2),%0" \
: REG(Reg) \
: "b"(BASE), "DS"((long)(INDEX) * sizeof(*(BASE))), \
"i"((DISP) * sizeof(*(BASE))), "m"(BASE[(INDEX) + (DISP)])); \
} \
Reg; \
})
#define PEEK(BASE, INDEX, DISP) /* a.k.a. b[i] */ \
(sizeof(*(BASE)) == 1 ? PEEK_("=Q", BASE, INDEX, DISP) \
: PEEK_("=r", BASE, INDEX, DISP))
#define PEEK_ARRAY_(REG, OBJECT, MEMBER, INDEX, DISP) \
({ \
__typeof(*(OBJECT->MEMBER)) Reg; \
if (!(OBJECT)) { \
asm("mov\t%c2(%1),%0" \
: REG(Reg) \
: "bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
sizeof(*(OBJECT->MEMBER)) * (DISP)), \
"m"(OBJECT->MEMBER)); \
} else { \
asm("mov\t%c3(%1,%2),%0" \
: REG(Reg) \
: "b"(OBJECT), "DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
sizeof(*(OBJECT->MEMBER)) * (DISP)), \
"m"(OBJECT->MEMBER)); \
} \
Reg; \
})
#define PEEK_ARRAY(OBJECT, MEMBER, INDEX, DISP) /* o->m[i] */ \
(sizeof(*(OBJECT->MEMBER)) == 1 \
? PEEK_ARRAY_("=Q", OBJECT, MEMBER, INDEX, DISP) \
: PEEK_ARRAY_("=r", OBJECT, MEMBER, INDEX, DISP))
#define POKE_ARRAY_(REG, OBJECT, MEMBER, INDEX, DISP, VALUE) \
do { \
if (!(OBJECT)) { \
asm("mov\t%1,%c3(%2)" \
: "=m"(OBJECT->MEMBER) \
: REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), \
"bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
} else { \
asm("mov\t%1,%c4(%2,%3)" \
: "=m"(OBJECT->MEMBER) \
: REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), "b"(OBJECT), \
"DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
} \
} while (0)
#define POKE_ARRAY(OBJECT, MEMBER, INDEX, DISP, VALUE) /* o->m[i]=v */ \
do { \
__typeof(*(OBJECT->MEMBER)) Reg; \
switch (sizeof(*(OBJECT->MEMBER))) { \
case 1: \
POKE_ARRAY_("Q", OBJECT, MEMBER, INDEX, DISP, VALUE); \
break; \
default: \
POKE_ARRAY_("r", OBJECT, MEMBER, INDEX, DISP, VALUE); \
break; \
} \
} while (0)
int setjmp(void *) __attribute__((__returns_twice__));
int longjmp(void *, int) __attribute__((__noreturn__));
static inline void *SetMemory(void *di, int al, unsigned long cx) {
asm("rep stosb"
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(cx), "a"(al));
return di;
}
static inline void *CopyMemory(void *di, void *si, unsigned long cx) {
asm("rep movsb"
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(si), "2"(cx));
return di;
}
static void RawMode(void) {
#ifndef __REAL_MODE__
int rc;
int c[14];
asm volatile("syscall"
: "=a"(rc)
: "0"(0x10), "D"(0), "S"(0x5401), "d"(c)
: "rcx", "r11", "memory");
c[0] &= ~0b0000010111111000; // INPCK|ISTRIP|PARMRK|INLCR|IGNCR|ICRNL|IXON
c[2] &= ~0b0000000100110000; // CSIZE|PARENB
c[2] |= 0b00000000000110000; // CS8
c[3] &= ~0b1000000001011010; // ECHONL|ECHO|ECHOE|IEXTEN|ICANON
asm volatile("syscall"
: "=a"(rc)
: "0"(0x10), "D"(0), "S"(0x5402), "d"(c)
: "rcx", "r11", "memory");
#endif
}
__attribute__((__noinline__)) static void PrintChar(long c) {
#ifdef __REAL_MODE__
asm volatile("mov\t$0x0E,%%ah\n\t"
"int\t$0x10"
: /* no outputs */
: "a"(c), "b"(7)
: "memory");
#else
static short buf;
int rc;
buf = c;
asm volatile("syscall"
: "=a"(rc)
: "0"(1), "D"(1), "S"(&buf), "d"(1)
: "rcx", "r11", "memory");
#endif
}
static int ReadChar(void) {
int c;
#ifdef __REAL_MODE__
asm volatile("int\t$0x16" : "=a"(c) : "0"(0) : "memory");
#else
static int buf;
asm volatile("syscall"
: "=a"(c)
: "0"(0), "D"(0), "S"(&buf), "d"(1)
: "rcx", "r11", "memory");
c = buf;
#endif
return c;
}

View file

@ -23,12 +23,13 @@ ENTRY(_start)
SECTIONS {
.text 0x7c00 - 0x600 : {
*(.start)
*(.start .start.*)
rodata = .;
*(.rodata .rodata.*)
. = 0x1fe;
SHORT(0xaa55);
*(.text .text.*)
BYTE(0x90);
_etext = .;
. = ALIGN(512);
}

View file

@ -1,12 +1,30 @@
(DEFUN FF (X)
(COND ((ATOM X) X)
((QUOTE T) (FF (CAR X)))))
(FF '(A B C))
;; (SET 'APPLY '(LAMBDA (E ARGS)
;; ((LAMBDA (APPQ)
;; (CONS ))
;; '(LAMBDA (M)
;; (COND ((EQ M 'NIL) 'NIL)
;; ('T (CONS (QUOTE (CAR M))
;; (APPQ (CONS 'QUOTE (CDR M))))))))))
;; (SET 'LIST '(LAMBDA (X Y) (CONS X (CONS Y 'NIL))))
;; (SET 'AND '(LAMBDA (P Q) (COND ((EQ P 'T) Q) ('T 'F))))
;; (SET 'OR '(LAMBDA (P Q) (COND ((EQ P 'T) 'T) ('T Q))))
;; (SET 'NOT '(LAMBDA (P) (COND ((EQ P 'F) 'T) ('T 'T))))
;; (SET 'IMPLIES '(LAMBDA (P Q) (COND ((EQ P 'T) Q) ('T 'T))))
((LABEL FF
(LAMBDA (X)
(COND ((ATOM X)
X)
((QUOTE T)
(FF (CAR X))))))
(QUOTE ((A B) C)))
((LAMBDA (CALL MKQUOT NULL AND APPEND KEYS VALS E A)
(CALL (CONS (CONS (QUOTE LAMBDA) (CONS (KEYS (QUOTE A)) (CONS E NIL))) (VALS (QUOTE A)))))
(QUOTE (LAMBDA (X) (X)))
(QUOTE (LAMBDA (X) (CONS (QUOTE QUOTE) (CONS X NIL))))
(QUOTE (LAMBDA (P Q) (COND ((EQ P (QUOTE T)) Q) ((QUOTE T) (QUOTE F)))))
(QUOTE (LAMBDA (X) (AND (QUOTE (ATOM X)) (QUOTE (EQ X NIL)))))
(QUOTE (LAMBDA (X Y) (COND ((EQ X NIL) Y) ((QUOTE T) (CONS (CAR X) (APPEND (QUOTE (CDR X)) (QUOTE Y)))))))
(QUOTE (LAMBDA (A) (COND ((EQ A NIL) NIL) ((QUOTE T) (CONS (CAR (CAR A)) (KEYS (QUOTE (CDR A))))))))
(QUOTE (LAMBDA (A) (COND ((EQ A NIL) NIL) ((QUOTE T) (CONS (MKQUOT (QUOTE (CDR (CAR A)))) (VALS (QUOTE (CDR A))))))))
(QUOTE (AND (QUOTE A) (QUOTE C)))
(CONS (CONS (QUOTE A) (QUOTE B)) (CONS (CONS (QUOTE C) (QUOTE D)) NIL)))
((LAMBDA (FF X) (FF 'X))
'(LAMBDA (X)
(COND ((ATOM X) X)
((QUOTE T) (FF '(CAR X)))))
'((A) B C))

View file

@ -17,11 +17,15 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
.code16
.section .start,"ax",@progbits
.code16
.section .start,"ax",@progbits
_start: jmp 1f
1: ljmp $0x600>>4,$_begin
.type _start,@function
.size _start,.-_start
.globl _start
_begin: push %cs
pop %ds
push %cs
@ -42,26 +46,24 @@ _begin: push %cs
mov $v_sectors+0x0200,%ax
int $0x13
xor %bp,%bp
sub $6,%sp
call main
nop
.type _start,@function
.size _start,.-_start
.globl _start
.globl v_sectors
.globl main
jmp main
.type _begin,@function
.size _begin,.-_begin
.section .start.setjmp,"ax",@progbits
setjmp: mov %sp,%ax
stosw # sp
stosw
xchg %ax,%si
movsw %ss:(%si),(%di) # ip
movsw %ss:(%si),(%di)
mov %bp,%ax
stosw # bp
ret
stosw
ret $6
.type setjmp,@function
.size setjmp,.-setjmp
.globl setjmp
.previous
.section .start.longjmp,"ax",@progbits
longjmp:
mov (%di),%sp
mov 2(%di),%dx
@ -72,23 +74,4 @@ longjmp:
.type longjmp,@function
.size longjmp,.-longjmp
.globl longjmp
.globl q.syntax
.type q.syntax,@function
.globl q.look
.type q.look,@function
.globl q.globals
.type q.globals,@function
.globl q.index
.type q.index,@function
.globl q.token
.type q.token,@function
.globl q.str
.type q.str,@function
.globl boot
.type boot,@function
.globl bss
.type bss,@function
.globl rodata
.type rodata,@function
.previous

11
tool/build/lib/argv.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ARGV_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_ARGV_H_
#include "tool/build/lib/machine.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void LoadArgv(struct Machine *, const char *, char **, char **);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ARGV_H_ */

View file

@ -19,6 +19,7 @@
*/
#include "libc/alg/arraylist2.h"
#include "libc/assert.h"
#include "libc/log/log.h"
#include "tool/build/lib/breakpoint.h"
void PopBreakpoint(struct Breakpoints *bps) {

View file

@ -22,6 +22,8 @@
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/str/tpencode.h"
#include "tool/build/lib/buffer.h"
@ -38,8 +40,13 @@ void AppendStr(struct Buffer *b, const char *s) {
}
void AppendWide(struct Buffer *b, wint_t wc) {
char cbuf[8];
AppendData(b, cbuf, tpencode(cbuf, 8, wc, false));
uint64_t wb;
wb = wc;
if (!isascii(wb)) wb = tpenc(wb);
do {
AppendChar(b, wb & 0xFF);
wb >>= 8;
} while (wb);
}
void AppendFmt(struct Buffer *b, const char *fmt, ...) {

View file

@ -178,9 +178,9 @@ static long DisAppendOpLines(struct Dis *d, struct Machine *m, int64_t addr) {
void *r;
int64_t ip;
unsigned k;
uint8_t b[15];
struct DisOp op;
long i, n, symbol;
uint8_t *p, b[15];
n = 15;
ip = addr - Read64(m->cs);
if ((symbol = DisFindSym(d, ip)) != -1) {
@ -202,8 +202,9 @@ static long DisAppendOpLines(struct Dis *d, struct Machine *m, int64_t addr) {
if (!(r = FindReal(m, addr))) return -1;
k = 0x1000 - (addr & 0xfff);
if (n <= k) {
memcpy(b, r, n);
p = r;
} else {
p = b;
memcpy(b, r, k);
if ((r = FindReal(m, addr + k))) {
memcpy(b + k, r, n - k);
@ -212,7 +213,7 @@ static long DisAppendOpLines(struct Dis *d, struct Machine *m, int64_t addr) {
}
}
xed_decoded_inst_zero_set_mode(d->xedd, m->mode);
xed_instruction_length_decode(d->xedd, b, n);
xed_instruction_length_decode(d->xedd, p, n);
n = d->xedd->op.error ? 1 : d->xedd->length;
op.addr = addr;
op.size = n;
@ -240,7 +241,6 @@ long Dis(struct Dis *d, struct Machine *m, uint64_t addr, uint64_t ip,
}
const char *DisGetLine(struct Dis *d, struct Machine *m, size_t i) {
char *p;
void *r[2];
uint8_t b[15];
if (i >= d->ops.i) return "";
@ -250,10 +250,9 @@ const char *DisGetLine(struct Dis *d, struct Machine *m, size_t i) {
xed_instruction_length_decode(
d->xedd, AccessRam(m, d->ops.p[i].addr, d->ops.p[i].size, r, b, true),
d->ops.p[i].size);
d->addr = d->ops.p[i].addr;
d->m = m;
p = DisLineCode(d, d->buf);
CHECK_LT(p - d->buf, sizeof(d->buf));
d->addr = d->ops.p[i].addr;
CHECK_LT(DisLineCode(d, d->buf) - d->buf, sizeof(d->buf));
return d->buf;
}

View file

@ -17,10 +17,8 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/arraylist.h"
#include "libc/alg/arraylist2.h"
#include "libc/assert.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/macros.h"
@ -44,7 +42,8 @@ static const Elf64_Ehdr kObjHeader = {
.e_machine = EM_NEXGEN32E,
.e_version = 1,
.e_ehsize = sizeof(Elf64_Ehdr),
.e_shentsize = sizeof(Elf64_Shdr)};
.e_shentsize = sizeof(Elf64_Shdr),
};
static size_t AppendSection(struct ElfWriter *elf, const char *name,
int sh_type, int sh_flags) {
@ -193,7 +192,7 @@ void elfwriter_close(struct ElfWriter *elf) {
void elfwriter_align(struct ElfWriter *elf, size_t addralign, size_t entsize) {
elf->entsize = entsize;
elf->addralign = addralign;
elf->wrote = roundup(elf->wrote, addralign);
elf->wrote = ROUNDUP(elf->wrote, addralign);
}
size_t elfwriter_startsection(struct ElfWriter *elf, const char *name,
@ -214,7 +213,7 @@ void *elfwriter_reserve(struct ElfWriter *elf, size_t size) {
do {
greed = greed + (greed >> 1);
} while (need > greed);
greed = roundup(greed, FRAMESIZE);
greed = ROUNDUP(greed, FRAMESIZE);
CHECK_NE(-1, ftruncate(elf->fd, greed));
CHECK_NE(MAP_FAILED, mmap((char *)elf->map + elf->mapsize,
greed - elf->mapsize, PROT_READ | PROT_WRITE,

View file

@ -23,11 +23,11 @@
void elfwriter_yoink(struct ElfWriter *elf, const char *symbol) {
unsigned char *p;
struct ElfWriterSymRef sym;
const unsigned char nopl[8] = "\x0f\x1f\x04\x25\x00\x00\x00\x00";
const unsigned char kNopl[8] = "\017\037\004\045\000\000\000\000";
p = elfwriter_reserve(elf, 8);
memcpy(p, nopl, sizeof(nopl));
memcpy(p, kNopl, sizeof(kNopl));
sym = elfwriter_linksym(elf, symbol, ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
STV_HIDDEN);
elfwriter_appendrela(elf, sizeof(nopl) - 4, sym, R_X86_64_32, 0);
elfwriter_commit(elf, sizeof(nopl));
elfwriter_appendrela(elf, sizeof(kNopl) - 4, sym, R_X86_64_32, 0);
elfwriter_commit(elf, sizeof(kNopl));
}

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ENDIAN_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_ENDIAN_H_
#include "libc/dce.h"
#include "libc/str/str.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#if __BYTE_ORDER__ + 0 == 1234

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_
#include "libc/calls/struct/iovec.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -9,8 +10,8 @@ struct MachineFds {
int fd;
struct MachineFdCb {
int (*close)(int);
ssize_t (*read)(int, void *, size_t);
ssize_t (*write)(int, const void *, size_t);
ssize_t (*readv)(int, const struct iovec *, int);
ssize_t (*writev)(int, const struct iovec *, int);
int (*ioctl)(int, uint64_t, void *);
} * cb;
} * p;

View file

@ -75,12 +75,12 @@ void LoadInstruction(struct Machine *m) {
key = ip & (ARRAYLEN(m->icache) - 1);
m->xedd = (struct XedDecodedInst *)m->icache[key];
if ((ip & 0xfff) < 0x1000 - 15) {
if (ip - (ip & 0xfff) == m->codevirt && ip) {
addr = m->codereal + (ip & 0xfff);
if (ip - (ip & 0xfff) == m->codevirt && m->codehost) {
addr = m->codehost + (ip & 0xfff);
} else {
m->codevirt = ip - (ip & 0xfff);
m->codereal = ResolveAddress(m, m->codevirt);
addr = m->codereal + (ip & 0xfff);
m->codehost = ResolveAddress(m, m->codevirt);
addr = m->codehost + (ip & 0xfff);
}
if (!IsOpcodeEqual(m->xedd, addr)) {
DecodeInstruction(m, addr, 15);

View file

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/struct/iovec.h"
#include "libc/sysv/consts/fileno.h"
#include "tool/build/lib/ioports.h"
@ -26,7 +27,7 @@ static int OpE9Read(struct Machine *m) {
fd = STDIN_FILENO;
if (fd >= m->fds.i) return -1;
if (!m->fds.p[fd].cb) return -1;
if (m->fds.p[fd].cb->read(m->fds.p[fd].fd, &b, 1) == 1) {
if (m->fds.p[fd].cb->readv(m->fds.p[fd].fd, &(struct iovec){&b, 1}, 1) == 1) {
return b;
} else {
return -1;
@ -38,7 +39,7 @@ static void OpE9Write(struct Machine *m, uint8_t b) {
fd = STDOUT_FILENO;
if (fd >= m->fds.i) return;
if (!m->fds.p[fd].cb) return;
m->fds.p[fd].cb->write(m->fds.p[fd].fd, &b, 1);
m->fds.p[fd].cb->writev(m->fds.p[fd].fd, &(struct iovec){&b, 1}, 1);
}
uint64_t OpIn(struct Machine *m, uint16_t p) {

53
tool/build/lib/iovs.c Normal file
View file

@ -0,0 +1,53 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/str.h"
#include "tool/build/lib/iovs.h"
/**
* Appends memory region to i/o vector builder.
*/
int AppendIovs(struct Iovs *ib, void *base, size_t len) {
unsigned i, n;
struct iovec *p;
if (len) {
p = ib->p;
i = ib->i;
n = ib->n;
if (i && (intptr_t)base == (intptr_t)p[i - 1].iov_base + p[i - 1].iov_len) {
p[i - 1].iov_len += len;
} else {
if (unlikely(i == n)) {
n += n >> 1;
if (p == ib->init) {
if (!(p = malloc(sizeof(struct iovec) * n))) return -1;
memcpy(p, ib->init, sizeof(ib->init));
} else {
if (!(p = realloc(p, sizeof(struct iovec) * n))) return -1;
}
ib->p = p;
ib->n = n;
}
p[i].iov_base = base;
p[i].iov_len = len;
++ib->i;
}
}
return 0;
}

31
tool/build/lib/iovs.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_IOVS_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_IOVS_H_
#include "libc/calls/struct/iovec.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct Iovs {
struct iovec *p;
unsigned i, n;
struct iovec init[2];
};
int AppendIovs(struct Iovs *, void *, size_t);
forceinline void InitIovs(struct Iovs *ib) {
ib->p = ib->init;
ib->i = 0;
ib->n = ARRAYLEN(ib->init);
}
forceinline void FreeIovs(struct Iovs *ib) {
if (ib->p != ib->init) {
free(ib->p);
}
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_IOVS_H_ */

View file

@ -23,20 +23,21 @@
#include "libc/elf/elf.h"
#include "libc/elf/struct/phdr.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/nexgen32e/vendor.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "tool/build/lib/argv.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/loader.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#define DSOLOL "ERROR: ELF not ET_EXEC try `gcc -static -o foo foo.c`\n"
static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
Elf64_Phdr *phdr) {
void *rbss;
@ -45,13 +46,20 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
align = MAX(phdr->p_align, PAGESIZE);
CHECK_EQ(1, popcnt(align));
CHECK_EQ(0, (phdr->p_vaddr - phdr->p_offset) % align);
/*-Type-Offset---VirtAddr-----------PhysAddr-----------FileSiz--MemSiz---Flg-Align----*/
/*-LOAD-0x000000-0x0000000000400000-0x0000000000400000-0x0008e4-0x0008e4-R-E-0x200000-*/
/*-LOAD-0x000fe0-0x0000000000600fe0-0x0000000000600fe0-0x000030-0x000310-RW--0x200000-*/
felf = (int64_t)(intptr_t)code;
vstart = ROUNDDOWN(phdr->p_vaddr, align);
vbss = ROUNDUP(phdr->p_vaddr + phdr->p_filesz, align);
vend = ROUNDUP(phdr->p_vaddr + phdr->p_memsz, align);
fstart = felf + ROUNDDOWN(phdr->p_offset, align);
fend = felf + ROUNDUP(phdr->p_offset + phdr->p_filesz, align);
fend = felf + phdr->p_offset + phdr->p_filesz;
bsssize = vend - vbss;
LOGF("LOADELFLOADSEGMENT"
" VSTART %#lx VBSS %#lx VEND %#lx"
" FSTART %#lx FEND %#lx BSSSIZE %#lx",
vstart, vbss, vend, fstart, fend, bsssize);
m->brk = MAX(m->brk, vend);
CHECK_GE(vend, vstart);
CHECK_GE(fend, fstart);
@ -61,12 +69,9 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
CHECK_GE(vend - vstart, fstart - fend);
CHECK_LE(phdr->p_filesz, phdr->p_memsz);
CHECK_EQ(felf + phdr->p_offset - fstart, phdr->p_vaddr - vstart);
CHECK_NE(-1, RegisterMemory(m, vstart, (void *)fstart, fend - fstart));
if (bsssize) {
CHECK_NE(MAP_FAILED, (rbss = mmap(NULL, bsssize, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
CHECK_NE(-1, RegisterMemory(m, vbss, rbss, bsssize));
}
CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart));
VirtualRecv(m, vstart, (void *)fstart, fend - fstart);
if (bsssize) CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize));
if (phdr->p_memsz - phdr->p_filesz > bsssize) {
VirtualSet(m, phdr->p_vaddr + phdr->p_filesz, 0,
phdr->p_memsz - phdr->p_filesz - bsssize);
@ -76,11 +81,8 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
static void LoadElf(struct Machine *m, struct Elf *elf) {
unsigned i;
Elf64_Phdr *phdr;
if (elf->ehdr->e_type != ET_EXEC) {
write(STDERR_FILENO, DSOLOL, strlen(DSOLOL));
exit(1);
}
m->ip = elf->base = elf->ehdr->e_entry;
LOGF("LOADELF ENTRY %p", m->ip);
for (i = 0; i < elf->ehdr->e_phnum; ++i) {
phdr = getelfsegmentheaderaddress(elf->ehdr, elf->size, i);
switch (phdr->p_type) {
@ -114,10 +116,11 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
struct Elf *elf) {
int fd;
ssize_t rc;
int64_t sp;
char *real;
void *stack;
struct stat st;
char *real, *memory;
size_t i, codesize, mappedsize, extrasize, stacksize;
size_t i, codesize, mappedsize, extrasize;
DCHECK_NOTNULL(prog);
elf->prog = prog;
if ((fd = open(prog, O_RDONLY)) == -1 ||
@ -148,14 +151,11 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
ResetCpu(m);
if (m->mode == XED_MACHINE_MODE_REAL) {
elf->base = 0x7c00;
CHECK_NE(MAP_FAILED,
(memory = mmap(NULL, BIGPAGESIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
RegisterMemory(m, 0, memory, BIGPAGESIZE);
CHECK_NE(-1, ReserveVirtual(m, 0, BIGPAGESIZE));
m->ip = 0x7c00;
Write64(m->cs, 0);
Write64(m->dx, 0);
memcpy(memory + 0x7c00, elf->map, 512);
VirtualRecv(m, m->ip, elf->map, 512);
if (memcmp(elf->map, "\177ELF", 4) == 0) {
elf->ehdr = (void *)elf->map;
elf->size = codesize;
@ -166,11 +166,9 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
elf->size = 0;
}
} else {
stacksize = STACKSIZE;
CHECK_NE(MAP_FAILED, (stack = mmap(NULL, stacksize, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
Write64(m->sp, 0x0000800000000000);
RegisterMemory(m, 0x0000800000000000 - stacksize, stack, stacksize);
sp = 0x800000000000;
Write64(m->sp, sp);
CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE));
LoadArgv(m, prog, args, vars);
if (memcmp(elf->map, "\177ELF", 4) == 0) {
elf->ehdr = (void *)elf->map;

View file

@ -17,11 +17,6 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/conv/conv.h"
#include "libc/dce.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "tool/build/lib/abp.h"
@ -558,7 +553,7 @@ static void OpMovZvqpIvqp(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexbSrm(m, rde), m->xedd->op.uimm0);
}
static void OpIncZv(struct Machine *m, uint32_t rde) {
static relegated void OpIncZv(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
Write32(RegSrm(m, rde), Inc32(Read32(RegSrm(m, rde)), 0, &m->flags));
} else {
@ -566,7 +561,7 @@ static void OpIncZv(struct Machine *m, uint32_t rde) {
}
}
static void OpDecZv(struct Machine *m, uint32_t rde) {
static relegated void OpDecZv(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
Write32(RegSrm(m, rde), Dec32(Read32(RegSrm(m, rde)), 0, &m->flags));
} else {
@ -888,22 +883,6 @@ static void OpBsubiImm(struct Machine *m, uint32_t rde) {
Bsubi(m, rde, m->xedd->op.uimm0);
}
static relegated void LoadFarPointer(struct Machine *m, uint32_t rde,
uint8_t seg[8]) {
uint32_t fp;
fp = Read32(ComputeReserveAddressRead4(m, rde));
Write64(seg, (fp & 0x0000ffff) << 4);
Write16(RegRexrReg(m, rde), fp >> 16);
}
static relegated void OpLes(struct Machine *m, uint32_t rde) {
LoadFarPointer(m, rde, m->es);
}
static relegated void OpLds(struct Machine *m, uint32_t rde) {
LoadFarPointer(m, rde, m->ds);
}
static void OpLgdtMs(struct Machine *m, uint32_t rde) {
}
@ -1234,6 +1213,22 @@ static void OpNegEb(struct Machine *m, uint32_t rde) {
AluEb(m, rde, Neg8);
}
static relegated void LoadFarPointer(struct Machine *m, uint32_t rde,
uint8_t seg[8]) {
uint32_t fp;
fp = Read32(ComputeReserveAddressRead4(m, rde));
Write64(seg, (fp & 0x0000ffff) << 4);
Write16(RegRexrReg(m, rde), fp >> 16);
}
static relegated void OpLes(struct Machine *m, uint32_t rde) {
LoadFarPointer(m, rde, m->es);
}
static relegated void OpLds(struct Machine *m, uint32_t rde) {
LoadFarPointer(m, rde, m->ds);
}
static relegated void Loop(struct Machine *m, uint32_t rde, bool cond) {
uint64_t cx;
cx = Read64(m->cx) - 1;
@ -1386,10 +1381,12 @@ static void OpSalc(struct Machine *m, uint32_t rde) {
}
static void OpNopEv(struct Machine *m, uint32_t rde) {
if (ModrmMod(rde) == 0b01 && ModrmReg(rde) == 0 && ModrmRm(rde) == 0b101) {
OpBofram(m, rde);
} else {
OpNoop(m, rde);
switch (ModrmMod(rde) << 6 | ModrmReg(rde) << 3 | ModrmRm(rde)) {
case 0x45:
OpBofram(m, rde);
break;
default:
OpNoop(m, rde);
}
}

View file

@ -5,10 +5,6 @@
#include "tool/build/lib/fds.h"
#include "tool/build/lib/pml4t.h"
#define kXmmIntegral 0
#define kXmmDouble 1
#define kXmmFloat 2
#define kMachineHalt -1
#define kMachineDecodeError -2
#define kMachineUndefinedInstruction -3
@ -28,7 +24,7 @@ struct Machine {
uint8_t cs[8];
uint8_t ss[8];
uint64_t codevirt;
uint8_t *codereal;
uint8_t *codehost;
uint32_t mode;
uint32_t flags;
uint32_t tlbindex;
@ -59,13 +55,15 @@ struct Machine {
uint8_t r15[8];
};
};
uint8_t *real;
uint64_t realsize;
uint64_t *cr3;
struct TlbEntry {
int64_t v;
void *r;
struct MachineTlb {
int64_t virt;
uint8_t *host;
} tlb[16];
struct MachineReal {
size_t i, n;
uint8_t *p;
} real;
uint64_t cr3;
uint8_t xmm[16][16] aligned(16);
uint8_t es[8];
uint8_t ds[8];
@ -76,34 +74,34 @@ struct Machine {
union {
uint32_t cw;
struct {
unsigned im : 1; /* invalid operation mask */
unsigned dm : 1; /* denormal operand mask */
unsigned zm : 1; /* zero divide mask */
unsigned om : 1; /* overflow mask */
unsigned um : 1; /* underflow mask */
unsigned pm : 1; /* precision mask */
unsigned _p1 : 2; /* reserved */
unsigned pc : 2; /* precision: 32,∅,64,80 */
unsigned rc : 2; /* rounding: even,→-∞,→+∞,→0 */
unsigned im : 1; // invalid operation mask
unsigned dm : 1; // denormal operand mask
unsigned zm : 1; // zero divide mask
unsigned om : 1; // overflow mask
unsigned um : 1; // underflow mask
unsigned pm : 1; // precision mask
unsigned _p1 : 2; // reserved
unsigned pc : 2; // precision: 32,∅,64,80
unsigned rc : 2; // rounding: even,→-∞,→+∞,→0
};
};
union {
uint32_t sw;
struct {
unsigned ie : 1; /* invalid operation */
unsigned de : 1; /* denormalized operand */
unsigned ze : 1; /* zero divide */
unsigned oe : 1; /* overflow */
unsigned ue : 1; /* underflow */
unsigned pe : 1; /* precision */
unsigned sf : 1; /* stack fault */
unsigned es : 1; /* exception summary status */
unsigned c0 : 1; /* condition 0 */
unsigned c1 : 1; /* condition 1 */
unsigned c2 : 1; /* condition 2 */
unsigned sp : 3; /* top stack */
unsigned c3 : 1; /* condition 3 */
unsigned bf : 1; /* busy flag */
unsigned ie : 1; // invalid operation
unsigned de : 1; // denormalized operand
unsigned ze : 1; // zero divide
unsigned oe : 1; // overflow
unsigned ue : 1; // underflow
unsigned pe : 1; // precision
unsigned sf : 1; // stack fault
unsigned es : 1; // exception summary status
unsigned c0 : 1; // condition 0
unsigned c1 : 1; // condition 1
unsigned c2 : 1; // condition 2
unsigned sp : 3; // top stack
unsigned c3 : 1; // condition 3
unsigned bf : 1; // busy flag
};
};
int tw;
@ -111,28 +109,33 @@ struct Machine {
int64_t ip;
int64_t dp;
} fpu;
struct {
struct MachineSse {
union {
uint32_t mxcsr;
struct {
unsigned ie : 1; /* invalid operation flag */
unsigned de : 1; /* denormal flag */
unsigned ze : 1; /* divide by zero flag */
unsigned oe : 1; /* overflow flag */
unsigned ue : 1; /* underflow flag */
unsigned pe : 1; /* precision flag */
unsigned daz : 1; /* denormals are zeros */
unsigned im : 1; /* invalid operation mask */
unsigned dm : 1; /* denormal mask */
unsigned zm : 1; /* divide by zero mask */
unsigned om : 1; /* overflow mask */
unsigned um : 1; /* underflow mask */
unsigned pm : 1; /* precision mask */
unsigned rc : 2; /* rounding control */
unsigned ftz : 1; /* flush to zero */
unsigned ie : 1; // invalid operation flag
unsigned de : 1; // denormal flag
unsigned ze : 1; // divide by zero flag
unsigned oe : 1; // overflow flag
unsigned ue : 1; // underflow flag
unsigned pe : 1; // precision flag
unsigned daz : 1; // denormals are zeros
unsigned im : 1; // invalid operation mask
unsigned dm : 1; // denormal mask
unsigned zm : 1; // divide by zero mask
unsigned om : 1; // overflow mask
unsigned um : 1; // underflow mask
unsigned pm : 1; // precision mask
unsigned rc : 2; // rounding control
unsigned ftz : 1; // flush to zero
};
};
} sse;
struct MachineRealFree {
uint64_t i;
uint64_t n;
struct MachineRealFree *next;
} * realfree;
struct FreeList {
uint32_t i;
void *p[6];
@ -141,18 +144,23 @@ struct Machine {
int64_t bofram[2];
jmp_buf onhalt;
int64_t faultaddr;
uint8_t stash[4096];
uint8_t xmmtype[2][8];
uint8_t icache[4096 / 4][40] aligned(16);
struct MachineFds fds;
uint8_t stash[4096];
uint8_t icache[1024][40];
} aligned(64);
struct Machine *NewMachine(void) nodiscard;
void FreeMachine(struct Machine *);
void ResetMem(struct Machine *);
void ResetCpu(struct Machine *);
void ResetTlb(struct Machine *);
void LoadInstruction(struct Machine *);
void ExecuteInstruction(struct Machine *);
struct Machine *NewMachine(void) nodiscard;
void LoadArgv(struct Machine *, const char *, char **, char **);
void InitMachine(struct Machine *);
long AllocateLinearPage(struct Machine *);
int ReserveVirtual(struct Machine *, int64_t, size_t);
char *FormatPml4t(struct Machine *) nodiscard;
int64_t FindVirtual(struct Machine *, int64_t, size_t);
int FreeVirtual(struct Machine *, int64_t, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -31,39 +31,54 @@
#include "tool/build/lib/throw.h"
void SetReadAddr(struct Machine *m, int64_t addr, uint32_t size) {
m->readaddr = addr;
m->readsize = size;
if (size) {
m->readaddr = addr;
m->readsize = size;
}
}
void SetWriteAddr(struct Machine *m, int64_t addr, uint32_t size) {
m->writeaddr = addr;
m->writesize = size;
if (size) {
m->writeaddr = addr;
m->writesize = size;
}
}
void *FindReal(struct Machine *m, int64_t v) {
uint64_t *p;
unsigned skew;
unsigned char i;
skew = v & 0xfff;
v &= -0x1000;
void *FindReal(struct Machine *m, int64_t virt) {
uint8_t *host;
uint64_t real, pte, *pt;
unsigned skew, level, i;
if (!(-0x800000000000 <= virt && virt < 0x800000000000)) {
return NULL;
}
skew = virt & 0xfff;
virt &= -0x1000;
for (i = 0; i < ARRAYLEN(m->tlb); ++i) {
if (m->tlb[i].v == v && m->tlb[i].r) {
return (char *)m->tlb[i].r + skew;
if (m->tlb[i].virt == virt && m->tlb[i].host) {
return m->tlb[i].host + skew;
}
}
for (p = m->cr3, i = 39; i >= 12; i -= 9) {
if (IsValidPage(p[(v >> i) & 511])) {
p = UnmaskPageAddr(p[(v >> i) & 511]);
} else {
level = 39;
real = m->cr3;
for (;;) {
if (real + 0x1000 > m->real.n) {
return NULL;
}
host = m->real.p + real;
if (level < 12) break;
pt = (uint64_t *)host;
pte = pt[(virt >> level) & 511];
if (!(pte & 1)) {
return NULL;
}
real = pte & 0x00007ffffffff000;
level -= 9;
}
m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1);
m->tlb[m->tlbindex] = m->tlb[0];
m->tlb[0].r = p;
m->tlb[0].v = ROUNDDOWN(v, 0x1000);
DCHECK_NOTNULL(p);
return (char *)p + skew;
m->tlb[0].host = host;
m->tlb[0].virt = virt;
return host + skew;
}
void *ResolveAddress(struct Machine *m, int64_t v) {
@ -196,7 +211,7 @@ void *LoadStr(struct Machine *m, int64_t addr) {
if (!addr) return NULL;
if (!(page = FindReal(m, addr))) return NULL;
if ((p = memchr(page, '\0', have))) {
SetReadAddr(m, addr, p - page);
SetReadAddr(m, addr, p - page + 1);
return page;
}
CHECK_LT(m->freelist.i, ARRAYLEN(m->freelist.p));
@ -205,7 +220,7 @@ void *LoadStr(struct Machine *m, int64_t addr) {
for (;;) {
if (!(page = FindReal(m, addr + have))) break;
if ((p = memccpy(copy + have, page, '\0', 0x1000))) {
SetReadAddr(m, addr, have + (p - (copy + have)));
SetReadAddr(m, addr, have + (p - (copy + have)) + 1);
return (m->freelist.p[m->freelist.i++] = copy);
}
have += 0x1000;
@ -217,19 +232,19 @@ void *LoadStr(struct Machine *m, int64_t addr) {
}
void *LoadBuf(struct Machine *m, int64_t addr, size_t size) {
char *buf, *copy;
size_t have, need;
char *buf, *copy, *page;
have = 0x1000 - (addr & 0xfff);
if (!addr) return NULL;
if (!(buf = FindReal(m, addr))) return NULL;
if (size > have) {
CHECK_LT(m->freelist.i, ARRAYLEN(m->freelist.p));
if (!(copy = malloc(size))) return NULL;
memcpy(copy, buf, have);
buf = memcpy(copy, buf, have);
do {
need = MIN(0x1000, size - have);
if ((buf = FindReal(m, addr + have))) {
memcpy(copy + have, buf, need);
if ((page = FindReal(m, addr + have))) {
memcpy(copy + have, page, need);
have += need;
} else {
free(copy);

View file

@ -17,35 +17,167 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "libc/x/x.h"
#include "tool/build/lib/buffer.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/pml4t.h"
void *MallocPage(void) {
void *p;
size_t n;
if ((p = memalign(4096, 4096))) {
memset(p, 0, 4096);
}
return p;
}
int RegisterMemory(struct Machine *m, int64_t v, void *r, size_t n) {
return RegisterPml4t(m->cr3, v, (int64_t)(intptr_t)r, n, MallocPage);
}
void ResetRam(struct Machine *m) {
FreePml4t(m->cr3, -0x800000000000, 0x800000000000, free, munmap);
}
struct Machine *NewMachine(void) {
struct Machine *m;
m = memalign(alignof(struct Machine), sizeof(struct Machine));
memset(m, 0, sizeof(struct Machine));
m = xmemalignzero(alignof(struct Machine), sizeof(struct Machine));
m->mode = XED_MACHINE_MODE_LONG_64;
InitMachine(m);
ResetCpu(m);
ResetMem(m);
return m;
}
static void FreeMachineRealFree(struct Machine *m) {
struct MachineRealFree *rf;
while ((rf = m->realfree)) {
m->realfree = rf->next;
free(rf);
}
}
void FreeMachine(struct Machine *m) {
if (m) {
FreeMachineRealFree(m);
free(m->real.p);
free(m);
}
}
void ResetMem(struct Machine *m) {
FreeMachineRealFree(m);
ResetTlb(m);
m->real.i = 0;
m->cr3 = AllocateLinearPage(m);
}
long AllocateLinearPage(struct Machine *m) {
uint8_t *p;
size_t i, n;
struct MachineRealFree *rf;
if ((rf = m->realfree)) {
DCHECK(rf->n);
DCHECK_EQ(0, rf->i & 0xfff);
DCHECK_EQ(0, rf->n & 0xfff);
DCHECK_LE(rf->i + rf->n, m->real.i);
i = rf->i;
rf->i += 0x1000;
if (!(rf->n -= 0x1000)) {
m->realfree = rf->next;
free(rf);
}
} else {
i = m->real.i;
n = m->real.n;
p = m->real.p;
if (i == n) {
if (n) {
n += n >> 1;
} else {
n = 0x10000;
}
n = ROUNDUP(n, 0x1000);
if ((p = realloc(p, n))) {
m->real.p = p;
m->real.n = n;
ResetTlb(m);
} else {
return -1;
}
}
DCHECK_EQ(0, i & 0xfff);
DCHECK_EQ(0, n & 0xfff);
DCHECK_LE(i + 0x1000, n);
m->real.i += 0x1000;
}
memset(m->real.p + i, 0, 0x1000); /* TODO: lazy page clearing */
return i;
}
static uint64_t MachineRead64(struct Machine *m, unsigned long i) {
CHECK_LE(i + 8, m->real.n);
return Read64(m->real.p + i);
}
static void MachineWrite64(struct Machine *m, unsigned long i, uint64_t x) {
CHECK_LE(i + 8, m->real.n);
Write64(m->real.p + i, x);
}
int ReserveVirtual(struct Machine *m, int64_t virt, size_t size) {
int64_t level, pt, ti, mi, end;
for (end = virt + size; virt < end; virt += 0x1000) {
for (pt = m->cr3, level = 39; level >= 12; level -= 9) {
pt = pt & 0x00007ffffffff000;
ti = (virt >> level) & 511;
DEBUGF("reserve %p level %d table %p index %ld", virt, level, pt, ti);
mi = pt + ti * 8;
pt = MachineRead64(m, mi);
if (!(pt & 1)) {
if ((pt = AllocateLinearPage(m)) == -1) return -1;
MachineWrite64(m, mi, pt | 7);
}
}
}
return 0;
}
int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) {
uint64_t i, pt, got;
got = 0;
do {
if (virt >= 0x800000000000) return enomem();
for (pt = m->cr3, i = 39; i >= 12; i -= 9) {
pt = MachineRead64(m, (pt & 0x7ffffffff000) + ((virt >> i) & 511) * 8);
if (!(pt & 1)) break;
}
if (i >= 12) {
got += 1ull << i;
} else {
virt += 0x1000;
got = 0;
}
} while (got < size);
return virt;
}
int FreeVirtual(struct Machine *m, int64_t base, size_t size) {
struct MachineRealFree *rf;
uint64_t i, mi, pt, la, end, virt;
for (virt = base, end = virt + size; virt < end;) {
for (pt = m->cr3, i = 39;; i -= 9) {
mi = (pt & 0x7ffffffff000) + ((virt >> i) & 511) * 8;
pt = MachineRead64(m, mi);
if (!(pt & 1)) {
break;
} else if (i == 12) {
MachineWrite64(m, mi, 0);
la = pt & 0x7ffffffff000;
if (m->realfree && la == m->realfree->i + m->realfree->n) {
m->realfree->n += 0x1000;
} else if ((rf = malloc(sizeof(struct MachineRealFree)))) {
rf->i = la;
rf->n = 0x1000;
rf->next = m->realfree;
m->realfree = rf;
}
break;
}
}
virt += 1ull << i;
}
return 0;
}

View file

@ -1,192 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/pml4t.h"
static int64_t MakeAddress(unsigned short a[4]) {
uint64_t x;
x = 0;
x |= a[0];
x <<= 9;
x |= a[1];
x <<= 9;
x |= a[2];
x <<= 9;
x |= a[3];
x <<= 12;
return SignExtendAddr(x);
}
static uint64_t *GetPageTable(pml4t_t p, long i, void *NewPhysicalPage(void)) {
uint64_t *res;
DCHECK_ALIGNED(4096, p);
DCHECK(0 <= i && i < 512);
if (IsValidPage(p[i])) {
res = UnmaskPageAddr(p[i]);
} else if ((res = NewPhysicalPage())) {
DCHECK_ALIGNED(4096, res);
p[i] = MaskPageAddr(res) | 0b11;
}
return res;
}
static void PtFinder(uint64_t *a, uint64_t *b, uint64_t n, pml4t_t pd, int k) {
unsigned i;
uint64_t e, c;
while (*b - *a < n) {
i = (*b >> k) & 511;
e = pd[i];
c = ROUNDUP(*b + 1, 1 << k);
if (!IsValidPage(e)) {
*b = c;
} else if (k && *b - *a + (c - *b) > n) {
PtFinder(a, b, n, UnmaskPageAddr(e), k - 9);
} else {
*a = *b = c;
}
if (((*b >> k) & 511) < i) {
break;
}
}
}
/**
* Locates free memory range.
*
* @param h specifies signedness and around where to start searching
* @return virtual page address with size bytes free, or -1 w/ errno
*/
int64_t FindPml4t(pml4t_t pml4t, uint64_t h, uint64_t n) {
uint64_t a, b;
n = ROUNDUP(n, 4096) >> 12;
a = b = (h & 0x0000fffffffff000) >> 12;
if (!n || n > 0x10000000) return einval();
PtFinder(&a, &b, n, pml4t, 9 * 3);
if (b > 0x0000001000000000) return eoverflow();
if (h < 0x0000800000000000 && b > 0x0000000800000000) return eoverflow();
if (b - a < n) return enomem();
return a << 12;
}
/**
* Maps virtual page region to system memory region.
*
* @param pml4t is root of 48-bit page tables
* @param v is fixed page-aligned virtual address, rounded down
* @param r is real memory address, rounded down
* @param n is number of bytes needed, rounded up
* @return 0 on success, or -1 w/ errno
* @note existing pages are overwritten
*/
int RegisterPml4t(pml4t_t pml4t, int64_t v, int64_t r, size_t n,
void *NewPhysicalPage(void)) {
unsigned i, j, k, l;
uint64_t *pdpt, *pdt, *pd, u;
if (!n) return 0;
u = ROUNDDOWN(r, 4096);
n = ROUNDUP(n, 4096) >> 12;
i = (v >> 39) & 511;
j = (v >> 30) & 511;
k = (v >> 21) & 511;
l = (v >> 12) & 511;
if (u + n > 0x800000000000) return eoverflow();
if (r + n > 0x800000000000) return eoverflow();
for (; i < 512; ++i) {
if (!(pdpt = GetPageTable(pml4t, i, NewPhysicalPage))) return -1;
for (; j < 512; ++j) {
if (!(pdt = GetPageTable(pdpt, j, NewPhysicalPage))) return -1;
for (; k < 512; ++k) {
if (!(pd = GetPageTable(pdt, k, NewPhysicalPage))) return -1;
for (; l < 512; ++l) {
pd[l] = MaskPageAddr(u) | 0b11;
if (!--n) return 0;
u += 4096;
}
l = 0;
}
k = 0;
}
j = 0;
}
return enomem();
}
/**
* Unmaps pages and frees page tables.
*/
int FreePml4t(pml4t_t pml4t, int64_t addr, uint64_t size,
void FreePhysicalPageTable(void *),
int FreePhysicalPages(void *, size_t)) {
int rc;
char *pages;
uint64_t i, *pdpt, *pdt, *pd;
unsigned short r, s[4], a[4], R[2][2] = {{256, 512}, {0, 256}};
a[0] = addr >> 39;
a[1] = addr >> 30;
a[2] = addr >> 21;
a[3] = addr >> 12;
size = ROUNDUP(size, 4096) >> 12;
for (rc = r = 0; r < ARRAYLEN(R); ++r) {
for (a[0] &= 511; size && R[r][0] <= a[0] && a[0] < R[r][1]; ++a[0]) {
if (!IsValidPage(pml4t[a[0]])) continue;
pdpt = UnmaskPageAddr(pml4t[a[0]]);
for (s[1] = (a[1] &= 511); size && a[1] < 512; ++a[1]) {
if (!IsValidPage(pdpt[a[1]])) continue;
pdt = UnmaskPageAddr(pdpt[a[1]]);
for (s[2] = (a[2] &= 511); size && a[2] < 512; ++a[2]) {
if (!IsValidPage(pdt[a[2]])) continue;
pd = UnmaskPageAddr(pdt[a[2]]);
for (s[3] = (a[3] &= 511); size && a[3] < 512; ++a[3]) {
if (IsValidPage(pd[a[3]])) {
pages = UnmaskPageAddr(pd[a[3]]);
pd[a[3]] = 0;
for (i = 1; i + 1 < size && a[3] + i < 512; ++i) {
if (!IsValidPage(pd[a[3] + i])) break;
if (UnmaskPageAddr(pd[a[3] + i]) != pages + i * 4096) break;
pd[a[3] + i] = 0;
}
FreePhysicalPages(pages, i * 4096);
a[3] += i - 1;
size -= i;
}
}
if (s[3] == 0 && a[3] == 512) {
FreePhysicalPageTable(pd);
pdt[a[2]] = 0;
}
}
if (s[2] == 0 && a[2] == 512) {
FreePhysicalPageTable(pdt);
pdpt[a[1]] = 0;
}
}
if (s[1] == 0 && a[1] == 512) {
FreePhysicalPageTable(pdpt);
pml4t[a[0]] = 0;
}
}
}
return 0;
}

View file

@ -4,17 +4,9 @@
COSMOPOLITAN_C_START_
#define IsValidPage(x) ((x)&1)
#define UnmaskPageAddr(x) ((void *)SignExtendAddr(MaskPageAddr(x)))
#define MaskPageAddr(x) ((int64_t)(intptr_t)(x)&0x00007ffffffff000)
#define SignExtendAddr(x) (!((x)&0x800000000000) ? (x) : (x) | -0x800000000000)
typedef uint64_t pml4t_t[512] aligned(4096);
int FreePml4t(pml4t_t, int64_t, uint64_t, void (*)(void *),
int (*)(void *, size_t));
int RegisterPml4t(pml4t_t, int64_t, int64_t, size_t, void *(*)(void));
int64_t FindPml4t(pml4t_t, uint64_t, uint64_t);
char *FormatPml4t(pml4t_t) nodiscard;
#define MaskPageAddr(x) ((x)&0x00007ffffffff000)
#define UnmaskPageAddr(x) SignExtendAddr(MaskPageAddr(x))
#define SignExtendAddr(x) ((int64_t)((uint64_t)(x) << 16) >> 16)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/x/x.h"
@ -59,12 +60,17 @@ static void FormatEndPage(struct Pml4tFormater *pp, int64_t end) {
AppendFmt(&pp->b, "%p %p %,ld bytes", end - 1, size, size);
}
char *FormatPml4t(uint64_t pml4t[512]) {
static void *GetPt(struct Machine *m, uint64_t r) {
CHECK_LE(r + 0x1000, m->real.n);
return m->real.p + r;
}
char *FormatPml4t(struct Machine *m) {
uint64_t *pd[4];
unsigned short i, a[4];
struct Pml4tFormater pp = {0};
unsigned short range[][2] = {{256, 512}, {0, 256}};
pd[0] = pml4t;
pd[0] = GetPt(m, m->cr3);
for (i = 0; i < ARRAYLEN(range); ++i) {
a[0] = range[i][0];
do {
@ -72,19 +78,19 @@ char *FormatPml4t(uint64_t pml4t[512]) {
if (!IsValidPage(pd[0][a[0]])) {
if (pp.t) FormatEndPage(&pp, MakeAddress(a));
} else {
pd[1] = UnmaskPageAddr(pd[0][a[0]]);
pd[1] = GetPt(m, UnmaskPageAddr(pd[0][a[0]]));
do {
a[2] = a[3] = 0;
if (!IsValidPage(pd[1][a[1]])) {
if (pp.t) FormatEndPage(&pp, MakeAddress(a));
} else {
pd[2] = UnmaskPageAddr(pd[1][a[1]]);
pd[2] = GetPt(m, UnmaskPageAddr(pd[1][a[1]]));
do {
a[3] = 0;
if (!IsValidPage(pd[2][a[2]])) {
if (pp.t) FormatEndPage(&pp, MakeAddress(a));
} else {
pd[3] = UnmaskPageAddr(pd[2][a[2]]);
pd[3] = GetPt(m, UnmaskPageAddr(pd[2][a[2]]));
do {
if (!IsValidPage(pd[3][a[3]])) {
if (pp.t) FormatEndPage(&pp, MakeAddress(a));

File diff suppressed because it is too large Load diff

View file

@ -2,19 +2,31 @@
#define COSMOPOLITAN_TOOL_BUILD_LIB_PTY_H_
#include "tool/build/lib/buffer.h"
#define kMachinePtyFg 0x01
#define kMachinePtyBg 0x02
#define kMachinePtyTrue 0x04
#define kMachinePtyBold 0x08
#define kMachinePtyFaint 0x10
#define kMachinePtyFlip 0x20
#define kMachinePtyBlink 0x40
#define kMachinePtyFg 0x0001
#define kMachinePtyBg 0x0002
#define kMachinePtyBold 0x0004
#define kMachinePtyFlip 0x0008
#define kMachinePtyFaint 0x0010
#define kMachinePtyUnder 0x0020
#define kMachinePtyDunder 0x0040
#define kMachinePtyTrue 0x0080
#define kMachinePtyBlink 0x0100
#define kMachinePtyItalic 0x0200
#define kMachinePtyFraktur 0x0400
#define kMachinePtyStrike 0x0800
#define kMachinePtyConceal 0x1000
#define kMachinePtyNocursor 0x01
#define kMachinePtyBlinkcursor 0x02
#define kMachinePtyNocanon 0x04
#define kMachinePtyNoecho 0x08
#define kMachinePtyNoopost 0x10
#define kMachinePtyBell 0x001
#define kMachinePtyRedzone 0x002
#define kMachinePtyNocursor 0x004
#define kMachinePtyBlinkcursor 0x008
#define kMachinePtyNocanon 0x010
#define kMachinePtyNoecho 0x020
#define kMachinePtyNoopost 0x040
#define kMachinePtyLed1 0x080
#define kMachinePtyLed2 0x100
#define kMachinePtyLed3 0x200
#define kMachinePtyLed4 0x400
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -24,16 +36,18 @@ struct MachinePty {
int x;
int yn;
int xn;
uint32_t u8;
uint32_t n8;
uint32_t pr;
uint32_t fg;
uint32_t bg;
uint32_t u8;
uint32_t n8;
uint32_t conf;
uint32_t save;
uint32_t *wcs;
uint32_t *prs;
uint32_t *fgs;
uint32_t *bgs;
uint32_t *prs;
uint32_t conf;
wchar_t *xlat;
enum MachinePtyState {
kMachinePtyAscii,
kMachinePtyUtf8,
@ -57,6 +71,11 @@ ssize_t MachinePtyRead(struct MachinePty *, void *, size_t);
ssize_t MachinePtyWrite(struct MachinePty *, const void *, size_t);
ssize_t MachinePtyWriteInput(struct MachinePty *, const void *, size_t);
void MachinePtyAppendLine(struct MachinePty *, struct Buffer *, unsigned);
void MachinePtyFullReset(struct MachinePty *);
void MachinePtyMemmove(struct MachinePty *, long, long, long);
void MachinePtyErase(struct MachinePty *, long, long);
void MachinePtySetY(struct MachinePty *, int);
void MachinePtySetX(struct MachinePty *, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -60,17 +60,9 @@ static void ResetSse(struct Machine *m) {
m->sse.rc = RINT;
m->sse.ftz = false;
memset(m->xmm, 0, sizeof(m->xmm));
memset(m->xmmtype, 0, sizeof(m->xmmtype));
}
static void ResetTlb(struct Machine *m) {
m->tlbindex = 0;
memset(m->tlb, 0, sizeof(m->tlb));
}
void ResetCpu(struct Machine *m) {
m->codevirt = 0;
m->codereal = NULL;
m->faultaddr = 0;
m->stashsize = 0;
m->stashaddr = 0;
@ -89,7 +81,13 @@ void ResetCpu(struct Machine *m) {
memset(m->reg, 0, sizeof(m->reg));
memset(m->bofram, 0, sizeof(m->bofram));
memset(&m->freelist, 0, sizeof(m->freelist));
ResetTlb(m);
ResetSse(m);
ResetFpu(m);
}
void ResetTlb(struct Machine *m) {
m->tlbindex = 0;
memset(m->tlb, 0, sizeof(m->tlb));
m->codevirt = 0;
m->codehost = NULL;
}

View file

@ -94,7 +94,6 @@
#include "libc/intrin/punpcklwd.h"
#include "libc/intrin/pxor.h"
#include "libc/macros.h"
#include "libc/str/str.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"

View file

@ -24,6 +24,7 @@
#include "libc/intrin/pshufw.h"
#include "libc/intrin/shufpd.h"
#include "libc/intrin/shufps.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/str/str.h"
@ -387,33 +388,26 @@ static void VspsdWspsd(struct Machine *m, uint32_t rde,
double_v opd(struct Machine *, double_v, double_v)) {
float_v xf, yf;
double_v xd, yd;
switch (Rep(rde) | Osz(rde)) {
case 0:
memcpy(&yf, GetModrmRegisterXmmPointerRead16(m, rde), 16);
memcpy(&xf, XmmRexrReg(m, rde), 16);
xf = opf(m, xf, yf);
memcpy(XmmRexrReg(m, rde), &xf, 16);
break;
case 1:
memcpy(&yd, GetModrmRegisterXmmPointerRead16(m, rde), 16);
memcpy(&xd, XmmRexrReg(m, rde), 16);
xd = opd(m, xd, yd);
memcpy(XmmRexrReg(m, rde), &xd, 16);
break;
case 2:
memcpy(&yd, GetModrmRegisterXmmPointerRead8(m, rde), 8);
memcpy(&xd, XmmRexrReg(m, rde), 8);
xd = opd(m, xd, yd);
memcpy(XmmRexrReg(m, rde), &xd, 8);
break;
case 3:
memcpy(&yf, GetModrmRegisterXmmPointerRead4(m, rde), 4);
memcpy(&xf, XmmRexrReg(m, rde), 4);
xf = opf(m, xf, yf);
memcpy(XmmRexrReg(m, rde), &xf, 4);
break;
default:
unreachable;
if (Rep(rde) == 2) {
memcpy(&yd, GetModrmRegisterXmmPointerRead8(m, rde), 8);
memcpy(&xd, XmmRexrReg(m, rde), 8);
xd = opd(m, xd, yd);
memcpy(XmmRexrReg(m, rde), &xd, 8);
} else if (Rep(rde) == 3) {
memcpy(&yf, GetModrmRegisterXmmPointerRead4(m, rde), 4);
memcpy(&xf, XmmRexrReg(m, rde), 4);
xf = opf(m, xf, yf);
memcpy(XmmRexrReg(m, rde), &xf, 4);
} else if (Osz(rde)) {
memcpy(&yd, GetModrmRegisterXmmPointerRead16(m, rde), 16);
memcpy(&xd, XmmRexrReg(m, rde), 16);
xd = opd(m, xd, yd);
memcpy(XmmRexrReg(m, rde), &xd, 16);
} else {
memcpy(&yf, GetModrmRegisterXmmPointerRead16(m, rde), 16);
memcpy(&xf, XmmRexrReg(m, rde), 16);
xf = opf(m, xf, yf);
memcpy(XmmRexrReg(m, rde), &xf, 16);
}
}

View file

@ -172,7 +172,12 @@ static void MovqVqWq(struct Machine *m, uint32_t rde) {
}
static void MovssVpsWps(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead4(m, rde), 4);
if (IsModrmRegister(rde)) {
memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 4);
} else {
memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead4(m, rde), 4);
memset(XmmRexrReg(m, rde) + 4, 0, 12);
}
}
static void MovssWpsVps(struct Machine *m, uint32_t rde) {
@ -180,11 +185,16 @@ static void MovssWpsVps(struct Machine *m, uint32_t rde) {
}
static void MovsdVpsWps(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde), 8);
if (IsModrmRegister(rde)) {
memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 8);
} else {
memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8);
memset(XmmRexrReg(m, rde) + 8, 0, 8);
}
}
static void MovsdWpsVps(struct Machine *m, uint32_t rde) {
memcpy(GetModrmRegisterXmmPointerWrite16(m, rde), XmmRexrReg(m, rde), 8);
memcpy(GetModrmRegisterXmmPointerWrite8(m, rde), XmmRexrReg(m, rde), 8);
}
static void MovhlpsVqUq(struct Machine *m, uint32_t rde) {

View file

@ -34,6 +34,8 @@
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/vendor.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
@ -65,6 +67,7 @@
#include "libc/x/x.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/iovs.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/pml4t.h"
@ -93,8 +96,8 @@
const struct MachineFdCb kMachineFdCbHost = {
.close = close,
.read = read,
.write = write,
.readv = readv,
.writev = writev,
.ioctl = ioctl,
};
@ -281,10 +284,10 @@ static int XlatTcp(int x) {
switch (x) {
XLAT(1, TCP_NODELAY);
XLAT(2, TCP_MAXSEG);
XLAT(23, TCP_FASTOPEN);
XLAT(4, TCP_KEEPIDLE);
XLAT(5, TCP_KEEPINTVL);
XLAT(6, TCP_KEEPCNT);
XLAT(23, TCP_FASTOPEN);
default:
return x;
}
@ -398,18 +401,58 @@ static int XlatRusage(int x) {
}
}
static void *VirtualSendRead(struct Machine *m, void *dst, int64_t addr,
uint64_t n) {
static void VirtualSendRead(struct Machine *m, void *dst, int64_t addr,
uint64_t n) {
VirtualSend(m, dst, addr, n);
SetReadAddr(m, addr, n);
return dst;
}
static void *VirtualRecvWrite(struct Machine *m, int64_t addr, void *dst,
uint64_t n) {
VirtualRecv(m, addr, dst, n);
static void VirtualRecvWrite(struct Machine *m, int64_t addr, void *src,
uint64_t n) {
VirtualRecv(m, addr, src, n);
SetWriteAddr(m, addr, n);
return dst;
}
static int AppendIovsReal(struct Machine *m, struct Iovs *ib, int64_t addr,
size_t size) {
void *real;
size_t have;
unsigned got;
while (size) {
if (!(real = FindReal(m, addr))) return efault();
have = 0x1000 - (addr & 0xfff);
got = MIN(size, have);
if (AppendIovs(ib, real, got) == -1) return -1;
addr += got;
size -= got;
}
return 0;
}
static int AppendIovsGuest(struct Machine *m, struct Iovs *iv, int64_t iovaddr,
long iovlen) {
int rc;
long i, iovsize;
struct iovec *guestiovs;
if (!__builtin_mul_overflow(iovlen, sizeof(struct iovec), &iovsize) &&
(0 <= iovsize && iovsize <= 0x7ffff000)) {
if ((guestiovs = malloc(iovsize))) {
VirtualSendRead(m, guestiovs, iovaddr, iovsize);
for (rc = i = 0; i < iovlen; ++i) {
if (AppendIovsReal(m, iv, (intptr_t)guestiovs[i].iov_base,
guestiovs[i].iov_len) == -1) {
rc = -1;
break;
}
}
free(guestiovs);
} else {
rc = enomem();
}
} else {
rc = eoverflow();
}
return rc;
}
static struct sigaction *CoerceSigactionToCosmo(
@ -463,44 +506,52 @@ static int OpMadvise(struct Machine *m, int64_t addr, size_t length,
}
static int64_t OpBrk(struct Machine *m, int64_t addr) {
void *real;
if (addr && addr != m->brk) {
if (addr < m->brk) {
addr = ROUNDUP(addr, FRAMESIZE);
FreePml4t(m->cr3, addr, m->brk - addr, free, munmap);
addr = ROUNDUP(addr, PAGESIZE);
if (addr > m->brk) {
if (ReserveVirtual(m, m->brk, addr - m->brk) != -1) {
m->brk = addr;
}
} else if (addr < m->brk) {
if (FreeVirtual(m, addr, m->brk - addr) != -1) {
m->brk = addr;
} else {
addr = ROUNDUP(addr, FRAMESIZE);
if ((real = mmap(NULL, addr - m->brk, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) {
CHECK_NE(-1, RegisterMemory(m, m->brk, real, addr - m->brk));
m->brk = addr;
}
}
}
return m->brk;
}
static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
int flags, int fd, int64_t off) {
void *real;
int flags, int fd, int64_t offset) {
void *tmp;
LOGF("MMAP%s %p %,ld %#x %#x %d %#lx", IsGenuineCosmo() ? " SIMULATED" : "",
virt, size, prot, flags, fd, offset);
flags = XlatMapFlags(flags);
if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1;
real = mmap(NULL, size, prot, flags & ~MAP_FIXED, fd, off);
if (real == MAP_FAILED) return -1;
if (!(flags & MAP_FIXED)) {
if (0 <= virt && virt < 0x400000) virt = 0x400000;
if ((virt = FindPml4t(m->cr3, virt, size)) == -1) return -1;
if (!virt) {
if ((virt = FindVirtual(m, m->brk, size)) == -1) return -1;
m->brk = virt + size;
} else {
if ((virt = FindVirtual(m, virt, size)) == -1) return -1;
}
}
if (ReserveVirtual(m, virt, size) == -1) return -1;
if (fd != -1 && !(flags & MAP_ANONYMOUS)) {
/* TODO: lazy page loading */
CHECK_NOTNULL((tmp = malloc(size)));
CHECK_EQ(size, pread(fd, tmp, size, offset));
VirtualRecvWrite(m, virt, tmp, size);
free(tmp);
}
CHECK_NE(-1, RegisterMemory(m, virt, real, size));
return virt;
}
static int OpMunmap(struct Machine *m, int64_t addr, uint64_t size) {
return FreePml4t(m->cr3, addr, size, free, munmap);
return FreeVirtual(m, addr, size);
}
static int OpMsync(struct Machine *m, int64_t virt, size_t size, int flags) {
return enosys();
#if 0
size_t i;
void *page;
virt = ROUNDDOWN(virt, 4096);
@ -510,42 +561,7 @@ static int OpMsync(struct Machine *m, int64_t virt, size_t size, int flags) {
if (msync(page, 4096, flags) == -1) return -1;
}
return 0;
}
static void *GetDirectBuf(struct Machine *m, int64_t addr, size_t *size) {
void *page;
*size = MIN(*size, 0x1000 - (addr & 0xfff));
if (!(page = FindReal(m, addr))) return MAP_FAILED;
return page;
}
static struct iovec *GetDirectIov(struct Machine *m, int64_t addr, int *len) {
int i;
size_t n, size;
struct iovec *iov;
if (!__builtin_mul_overflow(sizeof(*iov), *len, &n) && n <= 0x7ffff000) {
if ((iov = malloc(n))) {
VirtualSendRead(m, iov, addr, n);
for (i = 0; i < *len; ++i) {
size = iov[i].iov_len;
if ((iov[i].iov_base = GetDirectBuf(
m, (int64_t)(intptr_t)iov[i].iov_base, &size)) == MAP_FAILED) {
free(iov);
return (struct iovec *)efault();
}
if (size < iov[i].iov_len) {
iov[i].iov_len = size;
*len = i + 1;
break;
}
}
return iov;
} else {
return (struct iovec *)-1;
}
} else {
return (struct iovec *)eoverflow();
}
#endif
}
static int OpClose(struct Machine *m, int fd) {
@ -575,36 +591,39 @@ static int OpOpenat(struct Machine *m, int dirfd, int64_t path, int flags,
}
static int OpPipe(struct Machine *m, int64_t pipefds_addr) {
void *p[2];
uint8_t b[8];
int rc, i, j, *pipefds;
if ((i = MachineFdAdd(&m->fds)) == -1) return -1;
if ((j = MachineFdAdd(&m->fds)) == -1) return -1;
if ((rc = pipe((pipefds = BeginStoreNp(m, pipefds_addr, 8, p, b)))) != -1) {
EndStoreNp(m, pipefds_addr, 8, p, b);
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = pipefds[0];
m->fds.p[j].cb = &kMachineFdCbHost;
m->fds.p[j].fd = pipefds[1];
} else {
int i, j, pipefds[2];
if ((i = MachineFdAdd(&m->fds)) != -1) {
if ((j = MachineFdAdd(&m->fds)) != -1) {
if (pipe(pipefds) != -1) {
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = pipefds[0];
m->fds.p[j].cb = &kMachineFdCbHost;
m->fds.p[j].fd = pipefds[1];
pipefds[0] = i;
pipefds[1] = j;
VirtualRecvWrite(m, pipefds_addr, pipefds, sizeof(pipefds));
return 0;
}
MachineFdRemove(&m->fds, j);
}
MachineFdRemove(&m->fds, i);
MachineFdRemove(&m->fds, j);
}
return rc;
return -1;
}
static int OpDup(struct Machine *m, int fd) {
int i, rc;
if ((fd = XlatFd(m, fd)) == -1) return -1;
if ((i = MachineFdAdd(&m->fds)) == -1) return -1;
if ((rc = dup(fd)) != -1) {
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = rc;
rc = i;
} else {
MachineFdRemove(&m->fds, i);
int i;
if ((fd = XlatFd(m, fd)) != -1) {
if ((i = MachineFdAdd(&m->fds)) != -1) {
if ((fd = dup(fd)) != -1) {
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = fd;
return i;
}
MachineFdRemove(&m->fds, i);
}
}
return rc;
return -1;
}
static int OpDup2(struct Machine *m, int fd, int newfd) {
@ -708,24 +727,70 @@ static int OpSetsockopt(struct Machine *m, int fd, int level, int optname,
}
static ssize_t OpRead(struct Machine *m, int fd, int64_t addr, size_t size) {
void *data;
ssize_t rc;
if (!(0 <= fd && fd < m->fds.i) || !m->fds.p[fd].cb) return ebadf();
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = m->fds.p[fd].cb->read(m->fds.p[fd].fd, data, size)) != -1) {
SetWriteAddr(m, addr, rc);
struct Iovs iv;
InitIovs(&iv);
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
if ((rc = m->fds.p[fd].cb->readv(m->fds.p[fd].fd, iv.p, iv.i)) != -1) {
SetWriteAddr(m, addr, rc);
}
}
} else {
rc = ebadf();
}
FreeIovs(&iv);
return rc;
}
static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size,
int64_t offset) {
ssize_t rc;
struct Iovs iv;
InitIovs(&iv);
if ((rc = XlatFd(m, fd)) != -1) {
fd = rc;
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
if ((rc = preadv(fd, iv.p, iv.i, offset)) != -1) {
SetWriteAddr(m, addr, rc);
}
}
}
FreeIovs(&iv);
return rc;
}
static ssize_t OpWrite(struct Machine *m, int fd, int64_t addr, size_t size) {
void *data;
ssize_t rc;
if (!(0 <= fd && fd < m->fds.i) || !m->fds.p[fd].cb) return ebadf();
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = m->fds.p[fd].cb->write(m->fds.p[fd].fd, data, size)) != -1) {
SetReadAddr(m, addr, size);
struct Iovs iv;
InitIovs(&iv);
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
if ((rc = m->fds.p[fd].cb->writev(m->fds.p[fd].fd, iv.p, iv.i)) != -1) {
SetReadAddr(m, addr, rc);
}
}
} else {
rc = ebadf();
}
FreeIovs(&iv);
return rc;
}
static ssize_t OpPwrite(struct Machine *m, int fd, int64_t addr, size_t size,
int64_t offset) {
ssize_t rc;
struct Iovs iv;
InitIovs(&iv);
if ((rc = XlatFd(m, fd)) != -1) {
fd = rc;
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
if ((rc = pwritev(fd, iv.p, iv.i, offset)) != -1) {
SetReadAddr(m, addr, rc);
}
}
}
FreeIovs(&iv);
return rc;
}
@ -746,9 +811,9 @@ static int IoctlTcgets(struct Machine *m, int fd, int64_t addr,
if ((rc = fn(fd, TCGETS, &tio)) != -1) {
memcpy(&tio2, &tio, sizeof(tio));
tio2.c_iflag = 0;
if (tio.c_iflag & ISIG) tio2.c_iflag |= ISIG_LINUX;
if (tio.c_iflag & ICANON) tio2.c_iflag |= ICANON_LINUX;
if (tio.c_iflag & ECHO) tio2.c_iflag |= ECHO_LINUX;
if (tio.c_lflag & ISIG) tio2.c_lflag |= ISIG_LINUX;
if (tio.c_lflag & ICANON) tio2.c_lflag |= ICANON_LINUX;
if (tio.c_lflag & ECHO) tio2.c_lflag |= ECHO_LINUX;
tio2.c_oflag = 0;
if (tio.c_oflag & OPOST) tio2.c_oflag |= OPOST_LINUX;
VirtualRecvWrite(m, addr, &tio2, sizeof(tio2));
@ -762,9 +827,9 @@ static int IoctlTcsets(struct Machine *m, int fd, int64_t request, int64_t addr,
VirtualSendRead(m, &tio, addr, sizeof(tio));
memcpy(&tio2, &tio, sizeof(tio));
tio2.c_iflag = 0;
if (tio.c_iflag & ISIG_LINUX) tio2.c_iflag |= ISIG;
if (tio.c_iflag & ICANON_LINUX) tio2.c_iflag |= ICANON;
if (tio.c_iflag & ECHO_LINUX) tio2.c_iflag |= ECHO;
if (tio.c_lflag & ISIG_LINUX) tio2.c_lflag |= ISIG;
if (tio.c_lflag & ICANON_LINUX) tio2.c_lflag |= ICANON;
if (tio.c_lflag & ECHO_LINUX) tio2.c_lflag |= ECHO;
tio2.c_oflag = 0;
if (tio.c_oflag & OPOST_LINUX) tio2.c_oflag |= OPOST;
return fn(fd, request, &tio2);
@ -791,44 +856,34 @@ static int OpIoctl(struct Machine *m, int fd, uint64_t request, int64_t addr) {
}
}
static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size,
int64_t offset) {
void *data;
ssize_t rc;
if ((fd = XlatFd(m, fd)) == -1) return -1;
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = pread(fd, data, size, offset)) != -1) SetWriteAddr(m, addr, rc);
return rc;
}
static ssize_t OpPwrite(struct Machine *m, int fd, int64_t addr, size_t size,
int64_t offset) {
void *data;
ssize_t rc;
if ((fd = XlatFd(m, fd)) == -1) return -1;
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = pwrite(fd, data, size, offset)) != -1) SetReadAddr(m, addr, size);
return rc;
}
static ssize_t OpReadv(struct Machine *m, int fd, int64_t iovaddr, int iovlen) {
ssize_t rc;
struct iovec *iov;
if ((fd = XlatFd(m, fd)) == -1) return -1;
if ((iov = GetDirectIov(m, iovaddr, &iovlen)) == MAP_FAILED) return -1;
rc = readv(fd, iov, iovlen);
free(iov);
struct Iovs iv;
InitIovs(&iv);
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
if ((rc = AppendIovsGuest(m, &iv, iovaddr, iovlen)) != -1) {
rc = m->fds.p[fd].cb->readv(m->fds.p[fd].fd, iv.p, iv.i);
}
} else {
rc = ebadf();
}
FreeIovs(&iv);
return rc;
}
static ssize_t OpWritev(struct Machine *m, int fd, int64_t iovaddr,
int iovlen) {
ssize_t rc;
struct iovec *iov;
if ((fd = XlatFd(m, fd)) == -1) return -1;
if ((iov = GetDirectIov(m, iovaddr, &iovlen)) == MAP_FAILED) return -1;
rc = writev(fd, iov, iovlen);
free(iov);
struct Iovs iv;
InitIovs(&iv);
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
if ((rc = AppendIovsGuest(m, &iv, iovaddr, iovlen)) != -1) {
rc = m->fds.p[fd].cb->writev(m->fds.p[fd].fd, iv.p, iv.i);
}
} else {
rc = ebadf();
}
FreeIovs(&iv);
return rc;
}
@ -850,33 +905,25 @@ static int OpFaccessat(struct Machine *m, int dirfd, int64_t path, int mode,
return faccessat(dirfd, LoadStr(m, path), mode, flags);
}
static int OpFstatat(struct Machine *m, int dirfd, int64_t path, int64_t st,
static int OpFstatat(struct Machine *m, int dirfd, int64_t path, int64_t staddr,
int flags) {
int rc;
void *stp[2];
uint8_t *stbuf;
struct stat st;
flags = XlatAtf(flags);
if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1;
if (!(stbuf = malloc(sizeof(struct stat)))) return enomem();
if ((rc = fstatat(dirfd, LoadStr(m, path),
BeginStoreNp(m, st, sizeof(stbuf), stp, stbuf), flags)) !=
-1) {
EndStoreNp(m, st, sizeof(stbuf), stp, stbuf);
if ((rc = fstatat(dirfd, LoadStr(m, path), &st, flags)) != -1) {
VirtualRecvWrite(m, staddr, &st, sizeof(struct stat));
}
free(stbuf);
return rc;
}
static int OpFstat(struct Machine *m, int fd, int64_t st) {
static int OpFstat(struct Machine *m, int fd, int64_t staddr) {
int rc;
void *stp[2];
uint8_t *stbuf;
struct stat st;
if ((fd = XlatFd(m, fd)) == -1) return -1;
if (!(stbuf = malloc(sizeof(struct stat)))) return enomem();
if ((rc = fstat(fd, BeginStoreNp(m, st, sizeof(stbuf), stp, stbuf))) != -1) {
EndStoreNp(m, st, sizeof(stbuf), stp, stbuf);
if ((rc = fstat(fd, &st)) != -1) {
VirtualRecvWrite(m, staddr, &st, sizeof(struct stat));
}
free(stbuf);
return rc;
}
@ -1091,21 +1138,34 @@ static int OpGettimeofday(struct Machine *m, int64_t tv, int64_t tz) {
static int OpPoll(struct Machine *m, int64_t fdsaddr, uint64_t nfds,
int32_t timeout_ms) {
int rc;
size_t n;
struct pollfd *fds;
if (!__builtin_mul_overflow(sizeof(*fds), nfds, &n) && n <= 0x7ffff000) {
if ((fds = malloc(n))) {
VirtualSendRead(m, fds, fdsaddr, n);
rc = poll(fds, nfds, timeout_ms);
free(fds);
return rc;
int count, i;
uint64_t fdssize;
struct pollfd *hostfds, *guestfds;
if (!__builtin_mul_overflow(nfds, sizeof(struct pollfd), &fdssize) &&
fdssize <= 0x7ffff000) {
hostfds = malloc(fdssize);
guestfds = malloc(fdssize);
if (hostfds && guestfds) {
VirtualSendRead(m, guestfds, fdsaddr, fdssize);
memcpy(hostfds, guestfds, fdssize);
for (i = 0; i < nfds; ++i) {
hostfds[i].fd = XlatFd(m, hostfds[i].fd);
}
if ((count = poll(hostfds, nfds, timeout_ms)) != -1) {
for (i = 0; i < count; ++i) {
hostfds[i].fd = guestfds[i].fd;
}
VirtualRecvWrite(m, fdsaddr, hostfds, count * sizeof(struct pollfd));
}
} else {
return enomem();
count = enomem();
}
free(guestfds);
free(hostfds);
} else {
return einval();
count = einval();
}
return count;
}
static int OpSigprocmask(struct Machine *m, int how, int64_t setaddr,
@ -1303,7 +1363,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
SYSCALL(0x177, vmsplice(di, P(si), dx, r0));
CASE(0xE7, HaltMachine(m, di | 0x100));
default:
/* LOGF("missing syscall 0x%03x", ax); */
LOGF("missing syscall 0x%03x", ax);
ax = enosys();
break;
}

View file

@ -18,9 +18,12 @@
02110-1301 USA
*/
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/vendor.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "tool/build/lib/address.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/throw.h"
static bool IsHaltingInitialized(struct Machine *m) {
@ -40,7 +43,15 @@ void ThrowDivideError(struct Machine *m) {
void ThrowSegmentationFault(struct Machine *m, int64_t va) {
m->faultaddr = va;
m->ip -= m->xedd->length;
if (m->xedd) m->ip -= m->xedd->length;
WARNF("%s%s ADDR %p IP %p AX %lx CX %lx DX %lx BX %lx SP %lx "
"BP %lx SI %lx DI %lx R8 %lx R9 %lx R10 %lx R11 %lx R12 %lx R13 %lx "
"R14 %lx R15 %lx",
"SEGMENTATION FAULT", IsGenuineCosmo() ? " SIMULATED" : "", va, m->ip,
Read64(m->ax), Read64(m->cx), Read64(m->dx), Read64(m->bx),
Read64(m->sp), Read64(m->bp), Read64(m->si), Read64(m->di),
Read64(m->r8), Read64(m->r9), Read64(m->r10), Read64(m->r11),
Read64(m->r12), Read64(m->r13), Read64(m->r14), Read64(m->r15));
HaltMachine(m, kMachineSegmentationFault);
}
@ -49,7 +60,7 @@ void ThrowProtectionFault(struct Machine *m) {
}
void OpUd(struct Machine *m, uint32_t rde) {
m->ip -= m->xedd->length;
if (m->xedd) m->ip -= m->xedd->length;
HaltMachine(m, kMachineUndefinedInstruction);
}

View file

@ -24,13 +24,14 @@
#include "tool/build/lib/endian.h"
#include "tool/build/lib/time.h"
/**
* @fileoverview i am the timelorde
*/
void OpPause(struct Machine *m, uint32_t rde) {
sched_yield();
}
/**
* I am the timelorde.
*/
void OpRdtsc(struct Machine *m, uint32_t rde) {
uint64_t c;
struct timespec ts;

View file

@ -30,22 +30,17 @@
#include "tool/build/lib/pty.h"
#include "tool/build/lib/syscall.h"
struct Machine m[1];
int main(int argc, char *argv[]) {
int rc;
struct Elf elf;
const char *codepath;
codepath = argv[1];
struct Machine *m;
if (argc < 2) {
fputs("Usage: ", stderr);
fputs(argv[0], stderr);
fputs(" PROG [ARGS...]\n", stderr);
return EX_USAGE;
}
m->cr3 = MallocPage();
m->mode = XED_MACHINE_MODE_LONG_64;
InitMachine(m);
m = NewMachine();
LoadProgram(m, argv[1], argv + 2, environ, &elf);
m->fds.i = 3;
m->fds.n = 8;

View file

@ -279,7 +279,9 @@ void ProcessFile(struct ElfWriter *elf, const char *path) {
map = NULL;
}
EmitZip(elf, path, pathlen, map, &st);
CHECK_NE(-1, munmap(map, st.st_size));
if (st.st_size) {
CHECK_NE(-1, munmap(map, st.st_size));
}
}
void PullEndOfCentralDirectoryIntoLinkage(struct ElfWriter *elf) {

View file

@ -368,6 +368,11 @@ static long double FnBsr(struct Numbers *a) {
return bsr(a->x);
}
static long double FnBsrl(struct Numbers *a) {
if (!a) MissingArgumentError();
return bsrl(a->x);
}
static long double FnBsfl(struct Numbers *a) {
if (!a) MissingArgumentError();
return bsfl(a->x);
@ -610,7 +615,7 @@ static const struct Fn {
{"bsfl", FnBsfl},
{"bsfl", FnBsfl},
{"bsr", FnBsr},
{"bsr", FnBsr},
{"bsrl", FnBsrl},
{"cbrt", FnCbrt},
{"ceil", FnCeil},
{"copysign", FnCopysign},

View file

@ -143,7 +143,14 @@
"IM_FEELING_NAUGHTY"
"__REAL_MODE__"
"__x86__"
"__i386__"))
"__i386__"
"__W__"
"__PG__"
"__MFENTRY__"
"__MNO_VZEROUPPER__"
"__FSANITIZE_UNDEFINED__"
"__MNOP_MCOUNT__"
"__MRECORD_MCOUNT__"))
(defconst cosmo-cpp-constants
(append cosmo-cpp-constants-c11

View file

@ -62,6 +62,7 @@
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/consts/sol.h"
#include "libc/sysv/consts/tcp.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/struct/tm.h"
#include "libc/time/time.h"
@ -1136,10 +1137,13 @@ void ProcessConnection(void) {
}
}
static void SetReusePortAndAllowMultipleProcesses(void) {
static void TuneServerSocket(void) {
int yes = 1;
LOGIFNEG1(setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)));
LOGIFNEG1(setsockopt(server, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)));
LOGIFNEG1(setsockopt(server, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)));
LOGIFNEG1(setsockopt(server, IPPROTO_TCP, TCP_FASTOPEN, &yes, sizeof(yes)));
LOGIFNEG1(setsockopt(server, IPPROTO_TCP, TCP_QUICKACK, &yes, sizeof(yes)));
}
void RedBean(void) {
@ -1147,6 +1151,7 @@ void RedBean(void) {
programfile = (const char *)getauxval(AT_EXECFN);
CHECK(OpenZip(programfile));
xsigaction(SIGINT, OnTerminate, 0, 0, 0);
xsigaction(SIGHUP, OnTerminate, 0, 0, 0);
xsigaction(SIGTERM, OnTerminate, 0, 0, 0);
xsigaction(SIGCHLD, SIG_IGN, 0, 0, 0);
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
@ -1154,7 +1159,7 @@ void RedBean(void) {
xsigaction(SIGALRM, OnAlarm, 0, 0, 0);
if (setitimer(ITIMER_REAL, &kHeartbeat, NULL) == -1) notimer = true;
CHECK_NE(-1, (server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)));
SetReusePortAndAllowMultipleProcesses();
TuneServerSocket();
CHECK_NE(-1, bind(server, &serveraddr, sizeof(serveraddr)));
CHECK_NE(-1, listen(server, 10));
DescribeAddress(serveraddrstr, &serveraddr);

View file

@ -35,8 +35,8 @@ const char *kShades[] = {
jmp_buf jb_;
double light_[3] = {-50, 0, 50};
struct Sphere pos_ = {20, 20, 20, 20};
struct Sphere neg_ = {1, 1, -6, 20};
struct Sphere pos_ = {11, 11, 11, 11};
struct Sphere neg_ = {1, 1, -4, 11};
static void OnCtrlC(int sig) {
longjmp(jb_, 1);
@ -128,7 +128,7 @@ int main() {
double ang;
struct termios old;
if (cancolor()) {
ttyhidecursor(fileno(stdout));
WRITE("\e[?25l");
if (!setjmp(jb_)) {
xsigaction(SIGINT, OnCtrlC, 0, 0, NULL);
ang = 0;
@ -143,7 +143,7 @@ int main() {
usleep(1. / FRAMERATE * 1e6);
}
}
ttyshowcursor(fileno(stdout));
WRITE("\e[0m\e[H\e[J\e[?25h");
return 0;
} else {
return 1;

View file

@ -144,10 +144,7 @@ Effects Shortcuts:\n\
H +Hue ALT+H -Hue\n\
S +Saturation ALT+S -Saturation\n\
L +Lightness ALT+L -Lightness\n\
F1 {Unsharp,Sharp}\n\
F2 {Gaussian,Boxblur}\n\
F3 Sobel\n\
F4 Emboss\n\
CTRL-G {Unsharp,Sharp}\n\
\n\
Environment Variables:\n\
SOX overrides location of SoX executable\n\
@ -1157,8 +1154,6 @@ static optimizesize void ReadKeyboard(void) {
case CTRL('G'):
sharp_ = (sharp_ + 1) % kSharpMAX;
break;
case CTRL('B'):
longjmp(jb_, 1);
case CTRL('\\'):
raise(SIGQUIT);
break;

102
tool/viz/tailf.c Normal file
View file

@ -0,0 +1,102 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
/**
* @fileoverview tail -f with lower poll rate
* @see busybox not having interval flag
*/
int fd;
bool exited;
struct stat st;
char buf[FRAMESIZE];
int WriteString(const char *s) {
return write(1, s, strlen(s));
}
void HideCursor(void) {
WriteString("\e[?25l");
}
void ShowCursor(void) {
WriteString("\e[?25h");
}
void OnInt(void) {
exited = true;
}
void OnExit(void) {
ShowCursor();
}
int main(int argc, char *argv[]) {
char *p;
ssize_t n;
size_t i, j;
bool chopped;
if (argc < 2) return 1;
if ((fd = open(argv[1], O_RDONLY)) == -1) return 2;
if (fstat(fd, &st) == -1) return 3;
n = st.st_size - MIN(st.st_size, sizeof(buf));
if ((n = pread(fd, buf, sizeof(buf), n)) == -1) return 4;
for (p = buf + n, i = 0; i < 10; ++i) {
p = firstnonnull(memrchr(buf, '\n', p - buf), buf);
}
chopped = false;
if (buf + n - p) ++p;
i = st.st_size - (buf + n - p);
atexit(OnExit);
HideCursor();
xsigaction(SIGINT, OnInt, 0, 0, 0);
xsigaction(SIGTERM, OnInt, 0, 0, 0);
while (!exited) {
if (fstat(fd, &st) == -1) return 5;
if (i > st.st_size) i = 0;
for (; i < st.st_size; i += n) {
if ((n = pread(fd, buf, sizeof(buf), i)) == -1) return 6;
j = n;
while (j && (buf[j - 1] == '\n' || buf[j - 1] == '\r')) --j;
if (j) {
if (chopped) {
WriteString("\r\n");
}
write(1, buf, j);
}
chopped = j != n;
}
dsleep(.01);
}
close(fd);
WriteString("\r\n");
return 0;
}

92
tool/viz/unicode.c Normal file
View file

@ -0,0 +1,92 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/unicode/unicode.h"
#include "libc/x/x.h"
int a, b, w, i;
char name[512];
void DisplayUnicodeCharacter(void) {
int c, cw;
c = i;
cw = wcwidth(c);
if (cw < 1) {
c = '?';
cw = 1;
}
if (w) {
if (w + 1 + cw > 80) {
printf("\n");
w = 0;
} else {
fputc(' ', stdout);
w += 1 + cw;
}
}
if (!w) {
printf("%08x ", i);
w = 9 + cw;
}
fputwc(c, stdout);
}
void DisplayUnicodeBlock(void) {
if (a == 0x10000) {
printf("\n\n\n\n\n\n\n "
"ASTRAL PLANES\n\n\n\n\n");
}
if (a == 0x0590 /* hebrew */) return;
if (a == 0x0600 /* arabic */) return;
if (a == 0x08a0 /* arabic */) return;
if (a == 0x0750 /* arabic */) return;
if (a == 0x0700 /* syriac */) return;
if (a == 0x10800 /* cypriot */) return;
printf("\n\n%-60s%20s\n"
"──────────────────────────────────────────────"
"──────────────────────────────────\n",
name, gc(xasprintf("%04x .. %04x", a, b)));
w = 0;
for (i = a; i <= b; ++i) {
DisplayUnicodeCharacter();
}
}
int main(int argc, char *argv[]) {
FILE *f;
char *line;
size_t linesize;
printf("\n\n\n\n\n UNICODE PLANES\n\n\n\n");
f = fopen("libc/unicode/blocks.txt", "r");
line = NULL;
linesize = 0;
while (!feof(f)) {
if (getline(&line, &linesize, f) == -1) break;
if (sscanf(line, "%x..%x; %s", &a, &b, name) != 3) continue;
DisplayUnicodeBlock();
}
free(line);
fclose(f);
return 0;
}