Add files to repository

This commit is contained in:
Alec Murphy
2025-10-07 10:51:07 -04:00
parent 1dddf4c455
commit dc242f36ef
59 changed files with 20523 additions and 0 deletions

14
.clang-format Normal file
View File

@@ -0,0 +1,14 @@
---
Language: Cpp
BasedOnStyle: WebKit
SpaceAfterTemplateKeyword: false
AlignEscapedNewlines: Left
AlignTrailingComments: true
BreakBeforeInheritanceComma: true
BreakConstructorInitializers: BeforeComma
IndentPPDirectives: AfterHash
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: true
NamespaceIndentation: None
QualifierAlignment: Right

16
.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
build/
src/openlibm/*.o
src/openlibm/*~
src/openlibm/*.a
src/openlibm/*.dll*
src/openlibm/*.so*
src/openlibm/*.dylib*
src/openlibm/*.pc
src/openlibm/openlibm-test
src/openlibm/cov-html/
src/openlibm/*.gcda
src/openlibm/*.gcno
src/openlibm/amd64/*.o
src/openlibm/bsdsrc/*.o
src/openlibm/ld80/*.o
src/openlibm/src/*.o

10
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,10 @@
{
"jaktLanguageServer.compiler.executablePath": "/home/alec/cloned/jakt/build/bin/jakt",
"git.ignoreLimitWarning": true,
"pmd-cpd.language": [
"cpp"
],
"pmd-cpd.onStartBehavior": "Show",
"pmd-cpd.sourceDirectory": "/home/alec/repos/erythros",
"terminal.integrated.shellIntegration.history": 0
}

1
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1 @@
{"version":"2.0.0","tasks":[{"label":"Build All","type":"shell","command":"${workspaceFolder}/scripts/build-all ${workspaceFolder}","group":{"kind":"build","isDefault":true},"runOptions":{"instanceLimit":1,"instancePolicy":"terminateOldest"},"problemMatcher":[]}]}

254
NeinTerm.HC Normal file
View File

@@ -0,0 +1,254 @@
#define @nt_process_debug Print
Bool @nt_window_is_hovered(CTask* task)
{
return (task == sys_focus_task && ms.pos.x >= task->pix_left && ms.pos.x <= task->pix_right && ms.pos.y >= task->pix_top && ms.pos.y <= task->pix_bottom);
}
U0 @nt_draw_it(CTask* task, CDC* dc)
{
GrBlot(dc, 0, 0, task->user_data(@nt*)->screen);
@nt* nt = task->user_data;
if (@nt_window_is_hovered(task)) {
gr.fp_draw_ms = NULL;
GrBlot(dc, ms.pos.x - task->pix_left, ms.pos.y - task->pix_top, nt->cursor);
} else {
gr.fp_draw_ms = &DrawStdMs;
}
}
U0 @nt_rx_loop(@nt* nt)
{
// Make tcp connection to cpu server and send the connect script
nt->s = @tcp_socket_create(nt->host, nt->port);
while (nt->s->state != TCP_SOCKET_STATE_ESTABLISHED) {
Sleep(1);
}
nt->s->send(nt->connect_script, StrLen(nt->connect_script));
U8* request = NULL;
@9p_msg * msg = NULL;
U8* buf = CAlloc(NT_BUF_SIZE, nt->main_task);
I64 len = 0;
I64 pos = 0;
I64 base = 0;
U32 request_length = 0;
// Export 9P filesystem, loop and receive Trequests
while (1) {
pos = 0;
base = 0;
len = nt->s->receive(buf + base, 1024);
nt_rx_queue_next_request:
msg = buf + base;
// If request length > data received length, keep receiving
while (msg->length > len) {
pos = len;
len += nt->s->receive(buf + base + pos, 1024);
}
// Insert request into rx_fifo
request = CAlloc(msg->length, nt->main_task);
// @nt_rx_dbg(nt, "fifo ins: len: %04d\ttype: %s\ttag: 0x%04x", msg->length, @nt_msg_type_string(msg->type), msg->tag);
MemCpy(request, buf + base, msg->length);
FifoI64Ins(nt->rx_fifo, request);
// If we have more data, queue next request
if (msg->length < len) {
base += msg->length;
len -= msg->length;
pos = 0;
goto nt_rx_queue_next_request;
}
Sleep(1);
}
}
U0 @nt_dbg_loop(@nt* nt)
{
@nt_dbg_msg* msg = NULL;
while (1) {
while (FifoI64Cnt(nt->rx_dbg_fifo)) {
FifoI64Rem(nt->rx_dbg_fifo, &msg);
@nt_dbg_out(msg);
}
while (FifoI64Cnt(nt->tx_dbg_fifo)) {
FifoI64Rem(nt->tx_dbg_fifo, &msg);
@nt_dbg_out(msg);
}
Sleep(1);
}
}
U0 @nt_process_one(@nt* nt)
{
if (!FifoI64Cnt(nt->rx_fifo))
return;
U8* request = NULL;
FifoI64Rem(nt->rx_fifo, &request);
@9p_msg * msg = request;
@9p_debug_dump(msg, msg->length, 0);
//@nt_tx_dbg(nt, "fifo rem: len: %04d\ttype: %s\ttag: 0x%04x", msg->length, @nt_msg_type_string(msg->type), msg->tag);
switch (msg->type) {
case TVERSION:
@nt_Tversion(nt, msg);
break;
case TATTACH:
@nt_Tattach(nt, msg);
break;
case TWALK:
@nt_Twalk(nt, msg);
break;
case TOPEN:
@nt_Topen(nt, msg);
break;
case TCLUNK:
@nt_Tclunk(nt, msg);
break;
case TREAD:
@nt_Tread(nt, msg);
break;
case TWRITE:
@nt_Twrite(nt, msg);
break;
case TFLUSH:
@nt_Tflush(nt, msg);
break;
case TSTAT:
@nt_Tstat(nt, msg);
break;
default:
@nt_tx_dbg(nt, "unimplemented request -");
PressAKey;
break;
}
Free(request);
}
U0 @nt_process_kbd(@nt* nt)
{
// Process keyboard events
if (!nt->kbd_read_tag)
return;
if (cnts.jiffies < nt->kbd_last_jiffies + 80)
return;
if (!FifoI64Cnt(nt->kbd_fifo))
return;
U8* ev = NULL;
FifoI64Rem(nt->kbd_fifo, &ev);
@9p_msg * Rmsg = nt->out;
if (ev) {
Rmsg->length = 0x0e;
Rmsg->type = TREAD + 1; // RREAD
Rmsg->tag = nt->kbd_read_tag;
MemCpy(nt->out + (4 + 1 + 2), ev, 7);
// nt->kbd_read_tag = NULL;
nt->kbd_last_jiffies = cnts.jiffies;
nt->s->send(Rmsg, Rmsg->length);
Free(ev);
}
}
U0 @nt_tx_loop(@nt* nt)
{
while (1) {
@nt_process_one(nt);
@nt_process_kbd(nt);
Sleep(1);
}
}
U0 @nt_create_qids(@nt* nt)
{
@nt_qid_create(nt, "/", NT_IS_DIR);
@nt_qid_create(nt, "/dev", NT_IS_DIR);
@nt_qid_create(nt, "/dev/cons", NT_IS_FILE);
@nt_qid_create(nt, "/dev/draw", NT_IS_DIR);
@nt_qid_create(nt, "/dev/draw/new", NT_IS_FILE);
@nt_qid_create(nt, "/dev/kbd", NT_IS_FILE);
@nt_qid_create(nt, "/dev/cursor", NT_IS_FILE);
@nt_qid_create(nt, "/dev/mouse", NT_IS_FILE);
//@nt_qid_create(nt, "/dev/mousectl", NT_IS_FILE);
//@nt_qid_create(nt, "/dev/mousein", NT_IS_FILE);
}
@nt* @nt_new(U8* host, I64 port)
{
@nt* nt = CAlloc(sizeof(@nt));
nt->cursor = @nt_cursor;
nt->screen = DCNew(GR_WIDTH, GR_HEIGHT);
DCFill(nt->screen, TRANSPARENT);
nt->main_task = Fs;
nt->main_task->user_data = nt;
nt->host = StrNew(host);
nt->out = CAlloc(NT_BUF_SIZE);
nt->rx_fifo = FifoI64New(NT_FIFO_SIZE);
nt->rx_dbg_fifo = FifoI64New(NT_FIFO_SIZE);
nt->tx_dbg_fifo = FifoI64New(NT_FIFO_SIZE);
nt->kbd_fifo = FifoI64New(NT_FIFO_SIZE);
nt->port = port;
nt->drawobjs = Json.CreateObject(nt->main_task);
nt->fids = Json.CreateObject(nt->main_task);
nt->qids = Json.CreateObject(nt->main_task);
nt->connect_script = FileRead("M:/script.rc");
StrCpy(nt->main_task->task_title, "NeinTerm");
nt->dbg_task = Spawn(&@nt_dbg_loop, nt, "NeinTerm DbgTask");
nt->rx_task = Spawn(&@nt_rx_loop, nt, "NeinTerm RxTask");
nt->tx_task = Spawn(&@nt_tx_loop, nt, "NeinTerm TxTask");
nt->main_task->draw_it = &@nt_draw_it;
@nt_create_qids(nt);
return nt;
}
U0 NeinTerm(U8* host, I64 port)
{
@nt* nt = @nt_new(host, port);
I64 ch, sc, code;
U8* ev;
while (1) {
code = ScanMsg(&ch, &sc);
if (!ch) {
switch (sc & 0xff) {
case SC_DELETE:
ch = 0x7f;
break;
default:
break;
}
}
if (ch) {
switch (code) {
case MSG_KEY_DOWN:
ev = CAlloc(8, nt->main_task);
ev[0] = 3;
ev[4] = 0x72;
ev[5] = ch;
FifoI64Ins(nt->kbd_fifo, ev);
break;
case MSG_KEY_UP:
ev = CAlloc(8, nt->main_task);
ev[0] = 3;
ev[4] = 0x52;
ev[5] = ch;
FifoI64Ins(nt->kbd_fifo, ev);
break;
}
}
Sleep(10);
}
}

4
Run.HC Normal file
View File

@@ -0,0 +1,4 @@
// Compile System in Adam task
Adam("Cd(\"M:/System/\");\n");
AdamFile("M:/System/MakeSystem");
XTalkWait(Fs, "WinMax;\nNeinTerm(\"10.20.0.254\", 9999);\n");

133
System/9P/Debug.HC Normal file
View File

@@ -0,0 +1,133 @@
// debugging drawterm
#define _TVERSION 100
#define _TAUTH 102
#define _TATTACH 104
#define _TERROR 106
#define _TFLUSH 108
#define _TWALK 110
#define _TOPEN 112
#define _TCREATE 114
#define _TREAD 116
#define _TWRITE 118
#define _TCLUNK 120
#define _TREMOVE 122
#define _TSTAT 124
#define _TWSTAT 126
U0 @9p_debug_printf(U8* fmt, ...)
{
U8* buf;
if (argc) {
buf = StrPrintJoin(NULL, fmt, argc, argv);
} else {
buf = StrNew(fmt);
}
U8* s = buf;
while (*s) {
OutU8(0xe9, *s++);
}
Free(buf);
}
U8* @9p_debug_get_code_str(I64 code)
{
switch (code) {
case _TVERSION:
return "Tversion";
case _TAUTH:
return "Tauth";
case _TATTACH:
return "Tattach";
case _TERROR:
return "Terror";
case _TFLUSH:
return "Tflush";
case _TWALK:
return "Twalk";
case _TOPEN:
return "Topen";
case _TCREATE:
return "Tcreate";
case _TREAD:
return "Tread";
case _TWRITE:
return "Twrite";
case _TCLUNK:
return "Tclunk";
case _TREMOVE:
return "Tremove";
case _TSTAT:
return "Tstat";
case _TWSTAT:
return "Twstat";
case 1 + _TVERSION:
return "Rversion";
case 1 + _TAUTH:
return "Rauth";
case 1 + _TATTACH:
return "Rattach";
case 1 + _TERROR:
return "Rerror";
case 1 + _TFLUSH:
return "Rflush";
case 1 + _TWALK:
return "Rwalk";
case 1 + _TOPEN:
return "Ropen";
case 1 + _TCREATE:
return "Rcreate";
case 1 + _TREAD:
return "Rread";
case 1 + _TWRITE:
return "Rwrite";
case 1 + _TCLUNK:
return "Rclunk";
case 1 + _TREMOVE:
return "Rremove";
case 1 + _TSTAT:
return "Rstat";
case 1 + _TWSTAT:
return "Rwstat";
default:
return "(unimplemented)";
}
}
U0 @9p_debug_dump(U8* dat, U64 ndat, I64 mode)
{
I64 i, j, step;
U8 buf[17];
buf[16] = 0;
@9p_debug_printf("dump: ptr=%p, length=%d, code: %s, mode=%s\n", dat, ndat, @9p_debug_get_code_str(dat[4]), @t(mode == 1, "tx", "rx"));
for (i = 0; i < 32; i++)
@9p_debug_printf("=");
@9p_debug_printf("\n");
i = 0;
while (i < ndat) {
@9p_debug_printf("%08x: ", i);
step = @t(ndat - i > 16, 16, ndat - i);
for (j = 0; j < 16; j++) {
if (j > step - 1) {
@9p_debug_printf(" ");
buf[j] = 0;
} else {
@9p_debug_printf("%02x ", dat[i + j]);
switch (dat[i + j]) {
case ' ' ... 'z':
buf[j] = dat[i + j];
break;
default:
buf[j] = '.';
break;
}
}
}
@9p_debug_printf("%s\n", buf);
i += step;
}
@9p_debug_printf("\n");
}

293
System/9P/Defs.HC Normal file
View File

@@ -0,0 +1,293 @@
#define TVERSION 100
#define TAUTH 102
#define TATTACH 104
#define TERROR 106
#define TFLUSH 108
#define TWALK 110
#define TOPEN 112
#define TCREATE 114
#define TREAD 116
#define TWRITE 118
#define TCLUNK 120
#define TREMOVE 122
#define TSTAT 124
#define TWSTAT 126
#define NT_BUF_SIZE 65536
#define NT_FIFO_SIZE 128
#define SET_REQUEST_SIZE U32 request_size = *(data)(U32*);
#define NT_IS_DIR 0x80
#define NT_IS_FILE 0x0
// #define SET_RESPONSE_SIZE *(nt->out)(U32*) = response_size;
// #define CLEAR_RESPONSE_BUFFER MemSet(nt->out, NULL, response_size);
// #define SEND_RESPONSE_BUFFER nt->s->send(nt->out, response_size);
#define SET_RESPONSE_CMD nt->out[4] = data[4] + 1;
#define SET_RESPONSE_TAG \
nt->out[5] = data[5]; \
nt->out[6] = data[6];
#define SET_MSGS \
@9p_msg * Tmsg = data; \
@9p_msg * Rmsg = nt->out;
#define SEND_RMSG \
SET_RESPONSE_CMD SET_RESPONSE_TAG @9p_debug_dump(Rmsg, Rmsg->length, 1); \
nt->s->send(Rmsg, Rmsg->length);
#define CLEAR_RMSG MemSet(Rmsg(U64) + 4, NULL, Rmsg->length - 4);
U8* @nt_msg_type_string(I64 req)
{
switch (req) {
case TVERSION:
return "Tversion";
case TAUTH:
return "Tauth";
case TATTACH:
return "Tattach";
case TERROR:
return "Terror";
case TFLUSH:
return "Tflush";
case TWALK:
return "Twalk";
case TOPEN:
return "Topen";
case TCREATE:
return "Tcreate";
case TREAD:
return "Tread";
case TWRITE:
return "Twrite";
case TCLUNK:
return "Tclunk";
case TREMOVE:
return "Tremove";
case TSTAT:
return "Tstat";
case TWSTAT:
return "Twstat";
default:
return "(unimplemented)";
}
}
class @9p_qid
{
U8 type;
U32 version;
U64 path;
};
class @9p_str
{
U8 length;
U8 data;
};
class @9p_msg
{
U32 length;
U8 type;
U16 tag;
U32 fid;
};
class @9p_twalk : @9p_msg
{
U32 newfid;
U16 nwname;
U8 wname; // mem location for nwname*(wname[s])
};
class @9p_stat
{
U16 size;
U16 type;
U32 dev;
@9p_qid qid;
U32 mode;
U32 atime;
U32 mtime;
U64 length;
U8 name;
};
class @9p_direntry
{
U16 type;
U32 dev;
@9p_qid qid;
U32 mode;
U32 atime;
U32 mtime;
U64 length;
U8 name;
};
// The reply will contain a machine-independent directory entry, stat, laid out as follows:
// size[2]total byte count of the following data
// type[2]for kernel use
// dev[4]for kernel use
// qid.type[1]
// the type of the file (directory, etc.), represented as a bit vector corresponding to the high 8 bits of the files mode word.
// qid.vers[4]
// version number for given path
// qid.path[8]
// the file servers unique identification for the file
// mode[4]
// permissions and flags
// atime[4]
// last access time
// mtime[4]
// last modification time
// length[8]
// length of file in bytes
// name[ s ]
// file name; must be / if the file is the root directory of the server
// uid[ s ]owner name
// gid[ s ]group name
// muid[ s ]
// name of the user who last modified the file
U64 EndianU64(U64 s)
{
U64 d;
d.u8[0] = s.u8[7];
d.u8[1] = s.u8[6];
d.u8[2] = s.u8[5];
d.u8[3] = s.u8[4];
d.u8[4] = s.u8[3];
d.u8[5] = s.u8[2];
d.u8[6] = s.u8[1];
d.u8[7] = s.u8[0];
return d;
}
// Mouse Cursor
CDC* @nt_cursor = DCNew(16, 16);
Free(@nt_cursor->body);
U8 @nt_cursor_data[16 * 16] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@nt_cursor->body = @nt_cursor_data;
class @nt
{
CDC* cursor;
CTask* dbg_task;
CTask* main_task;
CTask* rx_task;
CTask* tx_task;
TcpSocket* s;
U8* host;
I64 port;
U8* out;
CFifoI64* rx_fifo;
CFifoI64* rx_dbg_fifo;
CFifoI64* tx_dbg_fifo;
CFifoI64* kbd_fifo;
I64 kbd_last_jiffies;
U8* connect_script;
U16 kbd_read_tag;
// U8 last_kbd_read_request[23];
JsonObject* fids;
JsonObject* qids;
JsonObject* drawobjs;
CDC* screen;
I64 attach_fid;
};
class @nt_dbg_msg
{
I64 ts;
U8* s;
I64 dir;
};
U0 @nt_dbg_out(@nt_dbg_msg* msg)
{
U8 ts[16];
StrPrint(ts, "[%8d] %c ", msg->ts, @t(msg->dir, 'TX', 'RX'));
U8* s = ts;
while (*s) {
OutU8(0xe9, *s++);
}
s = msg->s;
while (*s) {
OutU8(0xe9, *s++);
}
OutU8(0xe9, '\n');
// Free(msg->s);
// Free(msg);
}
@9p_qid * @nt_qid_create(@nt* nt, U8* path, I64 type)
{
@9p_qid * qid = CAlloc(sizeof(@9p_qid), nt->main_task);
qid->type = type;
qid->path = StrNew(path, nt->main_task);
nt->qids->set(path, qid, JSON_NUMBER);
return qid;
}
@9p_qid * @nt_lookup_qid_by_path(@nt* nt, U8* path)
{
return nt->qids->@(path);
}
U0 @nt_pascal_to_c_strings(@nt* nt, U8** wname, U8* data, I64 nwname)
{
I64 i, j = 0;
I64 len = 0;
for (i = 0; i < nwname; i++) {
len = *(data + j)(U16*);
j += 2;
wname[i] = CAlloc(len + 1, nt->main_task);
MemCpy(wname[i], data + j, len);
j += len;
}
}
U0 @nt_rx_dbg(@nt* nt, U8* fmt, ...)
{
U8* buf;
if (argc) {
buf = StrPrintJoin(NULL, fmt, argc, argv);
} else {
buf = StrNew(fmt);
}
@nt_dbg_msg* msg = CAlloc(sizeof(@nt_dbg_msg), nt->main_task);
msg->ts = cnts.jiffies;
msg->s = buf;
msg->dir = 0;
FifoI64Ins(nt->rx_dbg_fifo, msg);
}
U0 @nt_tx_dbg(@nt* nt, U8* fmt, ...)
{
U8* buf;
if (argc) {
buf = StrPrintJoin(NULL, fmt, argc, argv);
} else {
buf = StrNew(fmt);
}
@nt_dbg_msg* msg = CAlloc(sizeof(@nt_dbg_msg), nt->main_task);
msg->ts = cnts.jiffies;
msg->s = buf;
msg->dir = 1;
FifoI64Ins(nt->tx_dbg_fifo, msg);
}
U0 @nt_zrmsg(@nt* nt, I64 length)
{
// Zero Rmsg to length and set length
@9p_msg * Rmsg = nt->out;
MemSet(Rmsg, NULL, length);
Rmsg->length = length;
}
U0 @nt_fid_set(@nt* nt, U8* fidbuf, @9p_qid * qid)
{
JsonObject* fid = Json.CreateObject(nt->main_task);
fid->set("qid", qid, JSON_NUMBER);
nt->fids->set(fidbuf, fid, JSON_OBJECT);
}

503
System/9P/Draw.HC Normal file
View File

@@ -0,0 +1,503 @@
class @Rect
{
U32 x0;
U32 y0;
U32 x1;
U32 y1;
};
class @Point
{
U32 x;
U32 y;
}
class @draw_A
{
U32 id;
U32 imageid;
U32 fillid;
U8 public;
};
class @draw_P
{
U32 dstid;
U16 n;
U32 wind;
@Point ignore;
U32 srcid;
@Point sp;
// U16 sp[4];
// dp[2*2*(n+1)];
};
class @draw_b
{
U32 id;
U32 screenid;
U8 refresh;
U32 chan;
U8 repl;
@Rect r;
@Rect clipr;
U32 color;
};
class @draw_d
{
U32 dstid;
U32 srcid;
U32 maskid;
@Rect dstr;
@Point srcp;
@Point maskp;
};
class @draw_y
{
U32 id;
@Rect r;
};
I64 @image_cbgr24_to_4_bit(CBGR24* ptr, Bool dither_probability)
{
I64 res, k;
if (dither_probability) {
k = RandU32;
if (SqrI64(ptr->r) + SqrI64(ptr->g) + SqrI64(ptr->b) >= 3 * SqrI64(k.u8[0]))
res = 8;
else
res = 0;
if (ptr->r >= k.u8[1])
res |= RED;
if (ptr->g >= k.u8[2])
res |= GREEN;
if (ptr->b >= k.u8[3])
res |= BLUE;
} else {
if (SqrI64(ptr->r) + SqrI64(ptr->g) + SqrI64(ptr->b) >= SqrI64(0x80)) {
res = 8;
if (ptr->r >= 0x80)
res |= RED;
if (ptr->g >= 0x80)
res |= GREEN;
if (ptr->b >= 0x80)
res |= BLUE;
} else {
res = 0;
if (ptr->r >= 0x40)
res |= RED;
if (ptr->g >= 0x40)
res |= GREEN;
if (ptr->b >= 0x40)
res |= BLUE;
}
}
return res;
}
I64 @nt_draw_A(@nt* nt, @draw_A* d, JsonObject* dobj)
{
// FIXME: Implement this.
@nt_tx_dbg(nt, "id: %d, imageid: %d, fillid: %d, public: %d",
d->id, d->imageid, d->fillid, d->public);
// PressAKey;
return sizeof(@draw_A);
}
I64 @nt_draw_b(@nt* nt, @draw_b* d, JsonObject* dobj)
{
// Allocate an image with a given id on the screen named by screenid.
// b id[4] screenid[4] refresh[1] chan[4] repl[1] r[4 * 4] clipr[4 * 4] color[4]
@nt_tx_dbg(nt, "id: %d, screenid: %d, refresh: %d, chan: %d, repl: %d",
d->id, d->screenid, d->refresh, d->chan, d->repl);
@nt_tx_dbg(nt, "rect: x0: %d, y0: %d, x1: %d, y1: %d",
d->r.x0, d->r.y0, d->r.x1, d->r.y1);
@nt_tx_dbg(nt, "clip rect: x0: %d, y0: %d, x1: %d, y1: %d",
d->clipr.x0, d->clipr.y0, d->clipr.x1, d->clipr.y1);
@nt_tx_dbg(nt, "color: %08x",
d->color);
U8 intbuf[16];
StrPrint(intbuf, "%d", d->id);
if (dobj->o("imgs")->@(intbuf)) {
@nt_tx_dbg(nt, "error: image id already exists");
PressAKey;
}
CDC* dc = NULL;
if (!d->repl) {
dc = DCNew(d->r.x1 - d->r.x0, d->r.y1 - d->r.y0);
}
JsonObject* iobj = Json.CreateObject(nt->main_task);
JsonObject* tmpr = NULL;
iobj->set("id", d->id, JSON_NUMBER);
iobj->set("screenid", d->screenid, JSON_NUMBER);
iobj->set("refresh", d->refresh, JSON_NUMBER);
iobj->set("chan", d->chan, JSON_NUMBER);
iobj->set("repl", d->repl, JSON_NUMBER);
iobj->set("dc", dc, JSON_NUMBER);
iobj->set("r", Json.CreateObject(nt->main_task), JSON_OBJECT);
iobj->set("clipr", Json.CreateObject(nt->main_task), JSON_OBJECT);
tmpr = iobj->o("r");
tmpr->set("x0", d->r.x0, JSON_NUMBER);
tmpr->set("y0", d->r.x1, JSON_NUMBER);
tmpr->set("x1", d->r.y0, JSON_NUMBER);
tmpr->set("y1", d->r.y1, JSON_NUMBER);
tmpr = iobj->o("clipr");
tmpr->set("x0", d->clipr.x0, JSON_NUMBER);
tmpr->set("y0", d->clipr.x1, JSON_NUMBER);
tmpr->set("x1", d->clipr.y0, JSON_NUMBER);
tmpr->set("y1", d->clipr.y1, JSON_NUMBER);
if (dc) {
CBGR24 bgr;
bgr.b = d->color.u8[0];
bgr.g = d->color.u8[1];
bgr.r = d->color.u8[2];
DCFill(dc, @image_cbgr24_to_4_bit(&bgr, 0));
}
StrPrint(intbuf, "%d", d->id);
dobj->o("imgs")->set(intbuf, iobj, JSON_OBJECT);
return sizeof(@draw_b);
}
U0 @nt_draw_y_mono_1bit(CDC* dc, @draw_y* d)
{
U8* _c = d;
I64 x = 0;
I64 y = 0;
I64 sx = 0;
_c += sizeof(@draw_y);
for (y = 0; y < d->r.y1; y++) {
for (x = 0; x < d->r.x1; x++) {
dc->color = @t((reverse_bits(*_c) >> sx) & 1, 15, 0);
GrPlot(dc, x, y);
sx++;
if (sx > 7) {
sx = 0;
_c++;
}
}
if (sx) {
sx = 0;
_c++;
}
}
}
I64 @nt_draw_y(@nt* nt, @draw_y* d, JsonObject* dobj)
{
// y id[4] r[4*4] buf[x*1]
// Replace the rectangle r of pixels in image id with the pixel data in buf.
@nt_tx_dbg(nt, "id: %d", d->id);
@nt_tx_dbg(nt, "rect: x0: %d, y0: %d, x1: %d, y1: %d",
d->r.x0, d->r.y0, d->r.x1, d->r.y1);
U32 int_w;
U8 intbuf[16];
StrPrint(intbuf, "%d", d->id);
JsonObject* iobj = dobj->o("imgs")->@(intbuf);
if (!iobj) {
@nt_tx_dbg(nt, "imageid %d does not exist\n", d->id);
PressAKey;
}
CDC* dc = iobj->@("dc");
if (!dc) {
@nt_tx_dbg(nt, "no device context for imageid %d\n", d->id);
PressAKey;
}
switch (iobj->@("chan")) {
case 0x31:
@nt_draw_y_mono_1bit(dc, d);
int_w = d->r.x1;
while (int_w % 8) {
int_w++;
}
return sizeof(@draw_y) + ((int_w * d->r.y1) / 8);
default:
@nt_tx_dbg(nt, "unsupported chan value: 0x%04x", iobj->@("chan"));
PressAKey;
break;
}
}
// drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
U8* @nt_drawcoord(@nt* nt, U8* p, U8* maxp, U32 oldx, U32* newx)
{
U32 b, x;
if (p >= maxp) {
@nt_tx_dbg(nt, "error: Eshortdraw1: p = 0x%08x, maxp = 0x%08x", p, maxp);
PressAKey;
}
b = *p++;
x = b & 0x7F;
if (b & 0x80) {
if (p + 1 >= maxp) {
@nt_tx_dbg(nt, "error: Eshortdraw2: p = 0x%08x", p);
PressAKey;
}
x |= *p++ << 7;
x |= *p++ << 15;
if (x & (1 << 22))
x |= ~0 << 23;
} else {
if (b & 0x40)
x |= ~0 << 7;
x += oldx;
}
*newx = x;
return p;
}
I64 @nt_draw_P(@nt* nt, @draw_P* d, JsonObject* dobj)
{
// P dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] dp[2*2*(n+1)]
// Draw a polygon as the p message, but fill it rather than outlining it.
@nt_tx_dbg(nt, "dstid: %d, n: %d, srcid: %d",
d->dstid, d->n, d->srcid);
// FIXME: Implement this.
JsonObject* iobj;
U8 idbuf[16];
I64 dx, dy;
CDC* dst = NULL;
CDC* src = NULL;
StrPrint(idbuf, "%d", d->dstid);
iobj = dobj->o("imgs")->o(idbuf);
if (iobj) {
dst = iobj->@("dc");
}
// StrPrint(idbuf, "%d", d->srcid);
// iobj = dobj->o("imgs")->o(idbuf);
// if (iobj) {
// src = iobj->@("dc");
// }
if (dst) {
dx = 0 + d->sp.x;
dy = 0 + d->sp.y;
// dy = d->sp.y;
// dst->color = BLUE;
//@nt_tx_dbg(nt, "plot dst pixel: dx: %d, dy: %d", dx, dy);
// GrPlot(dst, dx, dy);
}
I64 i; //, j;
I64 dp_length = 0;
U8* dp_ptr = d;
U8* maxp = 0x80000000000000;
dp_ptr += 4 + 2 + 4 + 4 + 4 + 4 + 2 * 4;
// d += sizeof(@draw_P);
I64 b = 0;
// m = 1+4+2+4 +4+4 +4 +2*4
// U32 ox = 0;
// U32 oy = 0;
// p.x = d->sp.x;
// p.y = d->sp.y;
U64 __p = d;
__p += sizeof(@draw_P);
@Point p;
p.x = (__p)(U32*)[0];
p.y = (__p)(U32*)[1];
U32 ox = p.x;
U32 oy = p.y;
for (i = 0; i < d->n + 1; i++) {
dp_ptr = @nt_drawcoord(nt, dp_ptr, maxp, ox, &p.x);
dp_ptr = @nt_drawcoord(nt, dp_ptr, maxp, oy, &p.y);
if (dst) {
dst->color = BLACK;
@nt_tx_dbg(nt, "plot line: x0: %d, y0: %d, x1: %d, y1: %d", ox, oy, p.x, p.y);
if (!(ox > dst->width || oy > dst->height || p.x > dst->width || p.y > dst->height)) {
GrLine(dst, ox, oy, p.x, p.y);
}
// GrPlot(dst, dx + p.x, dy + p.y);
}
ox = p.x;
oy = p.y;
// for (j = 0; j < 2; j++) {
// b = dp_ptr[dp_length++];
// if (b & 0x80) {
// dp_length += 2;
// }
// }
}
// Sleep(5000);
// PressAKey;
return sizeof(@draw_P) + dp_length - d(U8*);
}
I64 @nt_draw_d(@nt* nt, @draw_d* d, JsonObject* dobj)
{
// m = 1+4+4+4+4*4+2*4+2*4;
// d dstid[4] srcid[4] maskid[4] dstr[4*4] srcp[2*4] maskp[2*4]
// Use the draw operator to combine the rectangle dstr of image dstid with a rectangle of image srcid ...
// res = 4 + 4 + 4 + sizeof(@Rect) + sizeof(@Point) + sizeof(@Point);
I64 res = 4 + 4 + 4 + sizeof(@Rect) + sizeof(@Point) + sizeof(@Point);
@nt_tx_dbg(nt, "dstid: %d, srcid: %d, maskid: %d, dstr: (%d,%d, %d,%d), srcp: (%d,%d) maskp: (%d,%d)",
d->dstid, d->srcid, d->maskid, d->dstr.x0, d->dstr.y0, d->dstr.x1, d->dstr.y1,
d->srcp.x, d->srcp.y, d->maskp.x, d->maskp.y);
JsonObject* iobj;
U8 idbuf[16];
I64 dx, dy;
CDC* dst;
CDC* src;
StrPrint(idbuf, "%d", d->dstid);
iobj = dobj->o("imgs")->o(idbuf);
if (!iobj) {
return res;
}
dst = iobj->@("dc");
if (!dst) {
return res;
}
StrPrint(idbuf, "%d", d->srcid);
iobj = dobj->o("imgs")->o(idbuf);
if (!iobj) {
return res;
}
src = iobj->@("dc");
if (!src) {
return res;
}
dx = U32_MAX - d->srcp.x;
dy = U32_MAX - d->srcp.y;
GrBlot(dst, dx, dy, src);
return res;
// if (dobj->o("imgs")->o(idbuf)) {
// @nt_tx_dbg(nt, "image id %d exists for srcid", d->srcid);
// src = dobj->o("imgs")->o(idbuf)->@("dc");
//
// if (src) {
// @nt_tx_dbg(nt, "src dc: width: %d, height: %d", src->width, src->height);
// if (d->dstr.x1 == 640 && d->dstr.y1 == 480 && src->width != 640) {
// dx = U32_MAX - d->srcp.x;
// dy = U32_MAX - d->srcp.y;
// GrBlot(gr.dc, dx, dy, src);
// }
// }
// }
//
// return 4 + 4 + 4 + sizeof(@Rect) + sizeof(@Point) + sizeof(@Point);
}
I64 @nt_draw_cmd(@nt* nt, U8* data, JsonObject* dobj, U8* data_ptr, I64 i)
{
I64 cmd = data_ptr[i++];
I64 res = 0;
// size[4] Twrite tag[2] fid[4] offset[8] count[4]
@nt_tx_dbg(nt, "draw cmd: %c, offset: 0x%04x", cmd, i - 1 + (4 + 1 + 2 + 4 + 8 + 4));
JsonKey* k;
JsonObject* o;
CDC* dc;
switch (cmd) {
case 0:
@nt_tx_dbg(nt, "ERROR: draw cmd is NULL, i: 0x%04x", i - 1 + (4 + 1 + 2 + 4 + 8 + 4));
PressAKey;
break;
case 'A':
res = @nt_draw_A(nt, data_ptr + i, dobj);
break;
case 'p':
case 'P':
res = @nt_draw_P(nt, data_ptr + i, dobj);
break;
case 'b':
res = @nt_draw_b(nt, data_ptr + i, dobj);
break;
case 'v':
k = dobj->o("imgs")->keys;
while (k) {
o = k->value;
if (o && o->@("dc")) {
dc = o->@("dc");
if (dc->width == 640 && dc->height == 480) {
GrBlot(nt->screen, 0, 0, dc);
}
}
k = k->next;
}
// FIXME: update display buffer
break;
case 'y':
res = @nt_draw_y(nt, data_ptr + i, dobj);
break;
case 'c':
// c dstid[4] repl[1] clipr[4*4]
// Change the replicate bit and clipping rectangle of the image dstid.
res = 4 + 1 + sizeof(@Rect);
break;
case 'd':
res = @nt_draw_d(nt, data_ptr + i, dobj);
break;
default:
// Sleep(5000);
@nt_tx_dbg(nt, "ERROR: unimplemented draw cmd: %c, offset: 0x%04x", cmd, i - 1 + (4 + 1 + 2 + 4 + 8 + 4));
// Sleep(5000);
PressAKey;
break;
}
return ++res;
}
U0 @nt_draw(@nt* nt, U8* data, @9p_qid * qid)
{
SET_MSGS
// size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count]
U8 dobjbuf[32];
StrCpy(dobjbuf, StrFind("/dev/draw/", qid->path) + 10);
StrFind("/data", dobjbuf)[0] = NULL;
JsonObject* dobj = nt->drawobjs->@(dobjbuf);
U64 draw_ptr = data + (4 + 1 + 2 + 4 + 8 + 4);
U32 length = *(data + (4 + 1 + 2 + 4 + 8))(U32*);
I64 i = 0;
while (i < length) {
i += @nt_draw_cmd(nt, data, dobj, draw_ptr, i);
}
}

557
System/9P/Requests.HC Normal file
View File

@@ -0,0 +1,557 @@
U0 @nt_Rerror(@nt* nt, U8* data, U8* errormsg)
{
// size[4] Rerror tag[2] ename[s]
SET_MSGS
Rmsg->length = (4 + 1 + 2 + 2);
nt->out[4] = TERROR + 1; // RERROR
MemCpy(nt->out + (4 + 1 + 2 + 2), errormsg, StrLen(errormsg));
*(nt->out + (4 + 1 + 2))(U16*) = StrLen(errormsg);
SET_RESPONSE_TAG
Rmsg->length += StrLen(errormsg);
@9p_debug_dump(Rmsg, Rmsg->length, 1);
nt->s->send(Rmsg, Rmsg->length);
}
U0 @nt_Tversion(@nt* nt, U8* data)
{
SET_MSGS
// Special case; just increment Tmsg tag to Rmsg and echo back to client
data[4]++;
@9p_debug_dump(data, Tmsg->length, 1);
nt->s->send(data, Tmsg->length);
}
U0 @nt_Tattach(@nt* nt, U8* data)
{
SET_MSGS
@nt_zrmsg(nt, 20);
//@nt_tx_dbg(nt, "Tattach fid: %d", Tmsg->fid);
nt->attach_fid = Tmsg->fid;
// Map fid to qid
U8 fidbuf[16];
@9p_qid * qid = @nt_lookup_qid_by_path(nt, "/");
StrPrint(fidbuf, "%d", Tmsg->fid);
// nt->fids->set(fidbuf, qid, JSON_NUMBER);
@nt_fid_set(nt, fidbuf, qid);
MemCpy(nt->out + 7, qid, sizeof(@9p_qid));
SEND_RMSG
}
U0 @nt_Twalk(@nt* nt, U8* data)
{
// https://9fans.github.io/plan9port/man/man9/walk.html
// size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s])
// size[4] Rwalk tag[2] nwqid[2] nwqid*(qid[13])
// The fid must be valid in the current session and must not have been opened for I/O by an open or create message.
// If the full sequence of nwname elements is walked successfully, newfid will represent the file that results.
// If not, newfid (and fid) will be unaffected. However, if newfid is in use or otherwise illegal, an Rerror is returned.
// If the first element cannot be walked for any reason, Rerror is returned.
// Otherwise, the walk will return an Rwalk message containing:
// nwqid qids corresponding, in order, to the files that are visited by the nwqid successful elementwise walks;
// nwqid is therefore either nwname or the index of the first elementwise walk that failed.
// size[4] Rwalk tag[2] nwqid[2] nwqid*(qid[13])
// The value of nwqid cannot be zero unless nwname is zero.
// Also, nwqid will always be less than or equal to nwname.
// Only if it is equal, however, will newfid be affected, in which case newfid will represent:
// the file reached by the final elementwise walk requested in the message.
SET_MSGS
@9p_twalk * Twalk = data;
U8** wname = NULL;
I64 i, j;
U16 fid = Twalk->fid;
U16 newfid = Twalk->newfid;
U16 nwname = Twalk->nwname;
U16 nwqid = 0;
@9p_qid * qid = NULL;
U8 basepath[512];
U8 pathbuf[512];
U8 fidbuf[16];
Rmsg->length = (4 + 1 + 2 + 2);
//@nt_tx_dbg(nt, "Twalk fid: %d, newfid: %d, nwname: %d", fid, newfid, nwname);
if (fid != nt->attach_fid) {
// FIXME: Lookup base path from fid
StrPrint(fidbuf, "%d", fid);
qid = nt->fids->o(fidbuf)->@("qid");
if (!qid) {
@nt_tx_dbg(nt, "ERROR: !qid");
PressAKey;
}
StrCpy(basepath, qid->path);
if (qid->type != NT_IS_DIR) {
StrLastOcc(basepath, "/")[0] = NULL;
}
} else {
StrCpy(basepath, "");
}
if (nwname) {
wname = CAlloc(sizeof(U8*) * nwname, nt->main_task);
@nt_pascal_to_c_strings(nt, wname, &Twalk->wname, nwname);
for (i = 0; i < nwname; i++) {
StrCpy(pathbuf, basepath);
for (j = 0; j <= i; j++) {
StrPrint(pathbuf + StrLen(pathbuf), "/%s", wname[j]);
}
qid = @nt_lookup_qid_by_path(nt, pathbuf);
if (qid) {
// Copy the qid to Rwalk and increment nwqid, Rwalk length
MemCpy(nt->out + (4 + 1 + 2 + 2 + (nwqid * sizeof(@9p_qid))), qid, sizeof(@9p_qid));
nwqid++;
Rmsg->length += sizeof(@9p_qid);
} else {
// Rerror
Rmsg->length = (4 + 1 + 2 + 2);
Rmsg->type = 0x6b; // Rerror
SET_RESPONSE_TAG
StrPrint(nt->out + (4 + 1 + 2 + 2), "file does not exist: '.%s'", pathbuf);
//@nt_tx_dbg(nt, "newfid: %d, %s", newfid, nt->out + (4 + 1 + 2 + 2));
*(nt->out + (4 + 1 + 2))(U16*) = StrLen(nt->out + (4 + 1 + 2 + 2));
Rmsg->length += StrLen(nt->out + (4 + 1 + 2 + 2));
@9p_debug_dump(Rmsg, Rmsg->length, 1);
nt->s->send(Rmsg, Rmsg->length);
return;
break;
}
}
}
// Map newfid to qid
StrPrint(fidbuf, "%d", newfid);
// nt->fids->set(fidbuf, qid, JSON_NUMBER);
@nt_fid_set(nt, fidbuf, qid);
// Set nwqid
*(nt->out + (4 + 1 + 2))(U16*) = nwqid;
//@nt_tx_dbg(nt, "newfid: %d, walked: %s", newfid, pathbuf);
SEND_RMSG
}
U0 @nt_Topen(@nt* nt, U8* data)
{
// https://9fans.github.io/plan9port/man/man9/open.html
// size[4] Topen tag[2] fid[4] mode[1]
// size[4] Ropen tag[2] qid[13] iounit[4]
SET_MSGS
U32 fid = *(data + (4 + 1 + 2))(U32*);
I64 mode = data[4 + 1 + 2 + 4];
U8 fidbuf[16];
StrPrint(fidbuf, "%d", fid);
Rmsg->length = (4 + 1 + 2 + 13 + 4);
//@nt_tx_dbg(nt, "Topen fid: %d, mode: %d", fid, mode);
@9p_qid * qid = nt->fids->o(fidbuf)->@("qid");
if (!qid) {
@nt_tx_dbg("ERROR: no qid for fid %d", fid);
PressAKey;
}
MemCpy(nt->out + 7, qid, sizeof(@9p_qid));
*(nt->out + (4 + 1 + 2 + 13))(U32*) = NULL; // set iounit to NULL for now
SEND_RMSG
}
U0 @nt_Tclunk(@nt* nt, U8* data)
{
// https://9fans.github.io/plan9port/man/man9/clunk.html
// size[4] Tclunk tag[2] fid[4]
// size[4] Rclunk tag[2]
SET_MSGS
U32 fid = *(data + (4 + 1 + 2))(U32*);
U8 fidbuf[16];
StrPrint(fidbuf, "%d", fid);
Rmsg->length = (4 + 1 + 2);
//@nt_tx_dbg(nt, "Tclunk fid: %d", fid);
nt->fids->unset(fidbuf);
SEND_RMSG
}
// I64 test_read_cnt = 0;
I64 test_read_cnt = 0;
// I64 test_entry_size = 0x45;
I64 test_entry_size = 0x41;
// U8 test_entry[test_entry_size] = { 0x3e, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x27, 0xab, 0xe2, 0x68, 0x1b, 0xab, 0xe2, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x64, 0x72, 0x61, 0x04, 0x00, 0x61, 0x6c, 0x65, 0x63, 0x04, 0x00, 0x61, 0x6c, 0x65, 0x63, 0x04, 0x00, 0x61, 0x6c, 0x65, 0x63 };
U8 test_entry[test_entry_size] = { 0x3f, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x80, 0x27, 0xab, 0xe2, 0x68, 0x1b, 0xab, 0xe2, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x64, 0x72, 0x61, 0x77, 0x04, 0x00, 0x61, 0x6c, 0x65, 0x63, 0x04, 0x00, 0x61, 0x6c, 0x65, 0x63, 0x04, 0x00, 0x61, 0x6c, 0x65, 0x63 };
// U8 test_entry[test_entry_size] = { 0x3f, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x80, 0x4d, 0xb2, 0xe2, 0x68, 0x47, 0xb2, 0xe2, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x64, 0x72, 0x61, 0x77, 0x04, 0x00, 0x61, 0x6c, 0x65, 0x63, 0x04, 0x00, 0x61, 0x6c, 0x65, 0x63, 0x04, 0x00, 0x61, 0x6c, 0x65, 0x63, 0x42, 0x00, 0x69, 0x00 };
U0 @dev_draw_new_read(@nt* nt, U8* data)
{
SET_MSGS
U32 read_size = 144;
I64 i;
U8 newbuf[144];
U8 intbuf[16];
U8 pathbuf[128];
U8* chanstr = "x8r8g8b8";
JsonObject* tmpr;
I64 conn = nt->drawobjs->length + 1;
JsonObject* dobj = Json.CreateObject(nt->main_task);
dobj->set("conn", conn, JSON_NUMBER);
dobj->set("imageid", 0, JSON_NUMBER);
dobj->set("chan", chanstr, JSON_STRING);
dobj->set("r", Json.CreateObject(nt->main_task), JSON_OBJECT);
dobj->set("clipr", Json.CreateObject(nt->main_task), JSON_OBJECT);
tmpr = dobj->o("r");
tmpr->set("x0", 0, JSON_NUMBER);
tmpr->set("y0", 0, JSON_NUMBER);
tmpr->set("x1", GR_WIDTH, JSON_NUMBER);
tmpr->set("y1", GR_HEIGHT, JSON_NUMBER);
tmpr = dobj->o("clipr");
tmpr->set("x0", 0, JSON_NUMBER);
tmpr->set("y0", 0, JSON_NUMBER);
tmpr->set("x1", GR_WIDTH, JSON_NUMBER);
tmpr->set("y1", GR_HEIGHT, JSON_NUMBER);
dobj->set("imgs", Json.CreateObject(nt->main_task), JSON_OBJECT);
// Insert new draw object [/dev/draw/[conn#] to nt->drawobjs]
StrPrint(intbuf, "%d", conn);
nt->drawobjs->set(intbuf, dobj, JSON_OBJECT);
// Create path objects
StrPrint(pathbuf, "/dev/draw/%d", conn);
@nt_qid_create(nt, pathbuf, NT_IS_DIR);
StrPrint(pathbuf, "/dev/draw/%d/data", conn);
@nt_qid_create(nt, pathbuf, NT_IS_FILE);
StrPrint(pathbuf, "/dev/draw/%d/refresh", conn);
@nt_qid_create(nt, pathbuf, NT_IS_FILE);
// ** not yet implemented
// StrPrint(pathbuf, "/dev/draw/%d/colormap", conn);
// @nt_qid_create(nt, pathbuf, NT_IS_FILE);
// StrPrint(pathbuf, "/dev/draw/%d/ctl", conn);
// @nt_qid_create(nt, pathbuf, NT_IS_FILE);
// *** Build payload for Rread
// Default; set all fields to 0
MemSet(newbuf, ' ', read_size);
for (i = 0; i < 12; i++) {
newbuf[10 + (12 * i)] = '0';
}
// Set connection number
StrPrint(intbuf, "%d", conn);
MemCpy(newbuf + 11 - StrLen(intbuf), intbuf, StrLen(intbuf));
// Set chan string
MemCpy(newbuf + 11 - StrLen(chanstr) + (12 * 2), chanstr, StrLen(chanstr));
// Set max.x of display image and clipping rect
StrPrint(intbuf, "%d", GR_WIDTH);
MemCpy(newbuf + 11 - StrLen(intbuf) + (12 * 6), intbuf, StrLen(intbuf));
MemCpy(newbuf + 11 - StrLen(intbuf) + (12 * 10), intbuf, StrLen(intbuf));
// Set max.y of display image and clipping rect
StrPrint(intbuf, "%d", GR_HEIGHT);
MemCpy(newbuf + 11 - StrLen(intbuf) + (12 * 7), intbuf, StrLen(intbuf));
MemCpy(newbuf + 11 - StrLen(intbuf) + (12 * 11), intbuf, StrLen(intbuf));
Rmsg->length = (4 + 1 + 2 + 4);
MemCpy(nt->out + (4 + 1 + 2 + 4), newbuf, read_size);
*(nt->out + (4 + 1 + 2))(U32*) = read_size;
Rmsg->length += read_size;
SEND_RMSG
}
U0 @nt_Rread_dir(@nt* nt, U8* data, @9p_qid * qid)
{
SET_MSGS
Rmsg->length = (4 + 1 + 2 + 4);
if (test_read_cnt) {
*(nt->out + (4 + 1 + 2))(U32*) = 0;
SEND_RMSG
return;
}
U32 read_size = test_entry_size;
MemCpy(nt->out + (4 + 1 + 2 + 4), test_entry, read_size);
*(nt->out + (4 + 1 + 2))(U32*) = read_size;
Rmsg->length += read_size;
SEND_RMSG
test_read_cnt++;
}
// @9p_msg * Rmsg = nt->out;
//
// if (ev) {
// Rmsg->length = 0x0e;
// Rmsg->type = TREAD + 1; // RREAD
// Rmsg->tag = nt->kbd_read_tag;
// MemCpy(nt->out + (4 + 1 + 2), ev, 7);
// // nt->kbd_read_tag = NULL;
// nt->kbd_last_jiffies = cnts.jiffies;
// nt->s->send(Rmsg, Rmsg->length);
// Free(ev);
// }
U0 @nt_Tread(@nt* nt, U8* data)
{
// https://9fans.github.io/plan9port/man/man9/read.html
// size[4] Tread tag[2] fid[4] offset[8] count[4]
// size[4] Rread tag[2] count[4] data[count]
SET_MSGS
U32 _fid = *(data + (4 + 1 + 2))(U32*);
U64 offset = *(data + (4 + 1 + 2 + 4))(U64*);
U32 count = *(data + (4 + 1 + 2 + 4 + 8))(U32*);
//@nt_tx_dbg(nt, "Tread fid: %d, offset: %d, count: %d", fid, offset, count);
U8 fidbuf[16];
StrPrint(fidbuf, "%d", _fid);
JsonObject* fid = nt->fids->o(fidbuf);
if (!fid)
return;
@9p_qid * qid = fid->@("qid");
if (!qid)
return;
I64 read_count = fid->@("read_count");
if (qid) {
switch (qid->type) {
case NT_IS_DIR:
if (!StrCmp(qid->path, "/dev")) {
@nt_Rread_dir(nt, data, qid);
return;
}
//@nt_tx_dbg(nt, "got read on dir: %s", qid->path);
break;
default:
if (!StrCmp(qid->path, "/dev/kbd")) {
nt->kbd_read_tag = Tmsg->tag;
//@nt_tx_dbg(nt, "Set nt->kbd_read_tag: 0x%04x", Tmsg->tag);
}
if (!StrCmp(qid->path, "/dev/draw/new")) {
if (read_count) {
@nt_Rerror(nt, data, "unknown id for draw image");
} else {
@dev_draw_new_read(nt, data);
}
}
break;
}
}
read_count++;
fid->set("read_count", read_count, JSON_NUMBER);
}
U0 @nt_Twrite(@nt* nt, U8* data)
{
// https://9fans.github.io/plan9port/man/man9/read.html
// size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count]
// size[4] Rwrite tag[2] count[4]
SET_MSGS
U32 fid = *(data + (4 + 1 + 2))(U32*);
U64 offset = *(data + (4 + 1 + 2 + 4))(U64*);
U32 count = *(data + (4 + 1 + 2 + 4 + 8))(U32*);
U8* p = data + (4 + 1 + 2 + 4 + 8 + 4);
Rmsg->length = (4 + 1 + 2 + 4);
//@nt_tx_dbg(nt, "Twrite fid: %d, offset: %d, count: %d", fid, offset, count);
U8 fidbuf[16];
U8 errmsgbuf[256];
StrPrint(fidbuf, "%d", fid);
@9p_qid * qid = nt->fids->o(fidbuf)->@("qid");
I64 i;
if (qid) {
if (String.BeginsWith("/dev/draw", qid->path) && String.EndsWith("/data", qid->path)) {
}
if (!StrCmp(qid->path, "/dev/draw/1/data")) {
@nt_draw(nt, data, qid);
}
if (!StrCmp(qid->path, "/dev/cons")) {
for (i = 0; i < count; i++) {
DocPrint(nt->main_task->put_doc, "%c", p[i]);
}
}
if (!StrCmp(qid->path, "/dev/mousectl")) {
p[count] = NULL;
StrPrint(errmsgbuf, "unknown control message \"%s\"", p);
@nt_Rerror(nt, data, errmsgbuf);
return;
}
//@nt_tx_dbg(nt, "got write for path: %s", qid->path);
}
*(nt->out + (4 + 1 + 2))(U32*) = count;
SEND_RMSG
}
U0 @nt_Tflush(@nt* nt, U8* data)
{
// https://9fans.github.io/plan9port/man/man9/flush.html
// size[4] Tflush tag[2] oldtag[2]
// size[4] Rflush tag[2]
SET_MSGS
Rmsg->length = (4 + 1 + 2);
SEND_RMSG
}
U0 @nt_Tstat(@nt* nt, U8* data)
{
// https://9fans.github.io/plan9port/man/man9/stat.html
// size[4] Tstat tag[2] fid[4]
// size[4] Rstat tag[2] stat[n]
// The reply will contain a machine-independent directory entry, stat, laid out as follows:
// size[2]total byte count of the following data
// type[2]for kernel use
// dev[4]for kernel use
// qid.type[1]
// the type of the file (directory, etc.), represented as a bit vector corresponding to the high 8 bits of the files mode word.
// qid.vers[4]
// version number for given path
// qid.path[8]
// the file servers unique identification for the file
// mode[4]
// permissions and flags
// atime[4]
// last access time
// mtime[4]
// last modification time
// length[8]
// length of file in bytes
// name[ s ]
// file name; must be / if the file is the root directory of the server
// uid[ s ]owner name
// gid[ s ]group name
// muid[ s ]
// name of the user who last modified the file
SET_MSGS
U32 fid = *(data + (4 + 1 + 2))(U32*);
Rmsg->length = (4 + 1 + 2 + sizeof(@9p_stat)); // set initial Rmsg length
//@nt_tx_dbg(nt, "Tstat fid: %d", fid);
// PressAKey;
U8 fidbuf[16];
StrPrint(fidbuf, "%d", fid);
@9p_qid * qid = nt->fids->o(fidbuf)->@("qid");
@9p_stat * stat = nt->out + (4 + 1 + 2);
stat->size = sizeof(@9p_stat) - 2;
stat->type = 0;
stat->dev = 0;
MemCpy(&stat->qid, qid, sizeof(@9p_qid));
stat->atime = 0;
stat->mtime = 0;
stat->length = 1024;
// add strings
U8* p = NULL;
U8* user = "alec";
// name[ s ]
p = nt->out + Rmsg->length;
U8* path = qid->path;
if (StrCmp(path, "/")) {
path = StrLastOcc(path, "/") + 1;
}
*(p)(U16*) = StrLen(path);
p += 2;
MemCpy(p, path, StrLen(path));
p += StrLen(path);
stat->size += StrLen(path) + 2;
Rmsg->length += StrLen(path) + 2;
// uid[ s ]owner name
p = nt->out + Rmsg->length;
*(p)(U16*) = StrLen(user);
p += 2;
MemCpy(p, user, StrLen(user));
p += StrLen(user);
stat->size += StrLen(user) + 2;
Rmsg->length += StrLen(user) + 2;
// uid[ s ]group name
p = nt->out + Rmsg->length;
*(p)(U16*) = StrLen(user);
p += 2;
MemCpy(p, user, StrLen(user));
p += StrLen(user);
stat->size += StrLen(user) + 2;
Rmsg->length += StrLen(user) + 2;
// muid[ s ]
p = nt->out + Rmsg->length;
*(p)(U16*) = StrLen(user);
p += 2;
MemCpy(p, user, StrLen(user));
p += StrLen(user);
stat->size += StrLen(user) + 2;
Rmsg->length += StrLen(user) + 2;
SEND_RMSG
}

25
System/Api/Dns.HC Normal file
View File

@@ -0,0 +1,25 @@
#define DNS_REQUEST_PTR 0x300010
MemSet(DNS_REQUEST_PTR, NULL, sizeof(U64));
class DnsRequest {
U64 host;
U64 pointer_to_u32;
};
U32 @dns_query(U8* host)
{
U32 res = 0;
if (!host)
return U32_MAX;
DnsRequest* request = CAlloc(sizeof(DnsRequest), Fs->code_heap);
request->host = StrNew(host, adam_task);
request->pointer_to_u32 = &res;
U64* request_ptr = DNS_REQUEST_PTR;
while (*request_ptr)
Sleep(1);
LXchgU32(request_ptr, request);
while (!res)
Sleep(1);
return res;
}

32
System/Api/Icmp.HC Normal file
View File

@@ -0,0 +1,32 @@
#define ICMP_REQUEST_PTR 0x300020
MemSet(ICMP_REQUEST_PTR, NULL, sizeof(U64));
class IcmpRequest {
U64 addr;
U64 iden;
U64 seq;
U64 pointer_to_u32;
};
U32 @icmp_echo_request(U32 addr, U16 iden, U16 seq, IcmpRequest* request, I64 count)
{
U32 res = 0; // low 16 = ttl, hi 16 = payload size
request->addr = addr;
request->iden = iden;
request->seq = seq;
request->pointer_to_u32 = &res;
I64 start_jiffies = cnts.jiffies;
U64* request_ptr = ICMP_REQUEST_PTR;
if (!count)
*request_ptr = NULL;
while (*request_ptr) {
if (!(cnts.jiffies < start_jiffies + 1000))
return res;
Sleep(1);
}
LXchgU32(request_ptr, request);
while (!res && cnts.jiffies < start_jiffies + 1000)
Sleep(1);
return res;
}

9
System/Api/Ipv4.HC Normal file
View File

@@ -0,0 +1,9 @@
U32 @ipv4_address(I64 o3, I64 o2, I64 o1, I64 o0)
{
U32 addr = NULL;
addr.u8[3] = o3;
addr.u8[2] = o2;
addr.u8[1] = o1;
addr.u8[0] = o0;
return addr;
}

144
System/Api/MD5.HC Normal file
View File

@@ -0,0 +1,144 @@
/*
* Simple MD5 implementation
*
* https://gist.github.com/creationix/4710780
*/
U32 md5_r[64] = { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 };
// Use binary integer part of the sines of integers (in radians) as constants//
// Initialize variables:
U32 md5_k[64] = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
};
// leftrotate function
U32 LEFTROTATE(U32 x, U32 c) { return (((x) << (c)) | ((x) >> (32 - (c)))); }
U0 md5(U8* initial_msg, U32 initial_len, U32* md5_h)
{
// These vars will contain the hash
U32 md5_h0, md5_h1, md5_h2, md5_h3;
// Message (to prepare)
U8* msg = NULL;
// Note: All variables are unsigned 32 bit and wrap modulo 2^32 when
// calculating
// r specifies the per-round shift amounts
md5_h0 = 0x67452301;
md5_h1 = 0xefcdab89;
md5_h2 = 0x98badcfe;
md5_h3 = 0x10325476;
// Pre-processing: adding a single 1 bit
// append "1" bit to message
/* Notice: the input bytes are considered as bits strings,
where the first bit is the most significant bit of the byte.[37] */
// Pre-processing: padding with zeros
// append "0" bit until message length in bit ≡ 448 (mod 512)
// append length mod (2 pow 64) to message
U32 new_len;
for (new_len = initial_len * 8 + 1; new_len % 512 != 448; new_len++)
;
new_len /= 8;
msg = CAlloc(new_len + 64, adam_task); // also appends "0" bits
// (we alloc also 64 extra bytes...)
MemCpy(msg, initial_msg, initial_len);
msg[initial_len] = 128; // write the "1" bit
U32 bits_len = 8 * initial_len; // note, we append the len
MemCpy(msg + new_len, &bits_len, 4); // in bits at the end of the buffer
// Process the message in successive 512-bit chunks:
// for each 512-bit chunk of message:
U32 offset;
for (offset = 0; offset < new_len; offset += (512 / 8)) {
// break chunk into sixteen 32-bit words w[j], 0 ≤ j ≤ 15
U32* w = (msg + offset)(U32*);
// Initialize hash value for this chunk:
U32 a = md5_h0;
U32 b = md5_h1;
U32 c = md5_h2;
U32 d = md5_h3;
// Main loop:
U32 i;
for (i = 0; i < 64; i++) {
U32 f, g;
if (i < 16) {
f = (b & c) | ((~b) & d);
g = i;
} else if (i < 32) {
f = (d & b) | ((~d) & c);
g = (5 * i + 1) % 16;
} else if (i < 48) {
f = b ^ c ^ d;
g = (3 * i + 5) % 16;
} else {
f = c ^ (b | (~d));
g = (7 * i) % 16;
}
U32 temp = d;
d = c;
c = b;
// printf("rotateLeft(%x + %x + %x + %x, %d)\n", a, f, k[i], w[g], r[i]);
b = b + LEFTROTATE((a + f + md5_k[i] + w[g]), md5_r[i]);
a = temp;
}
// Add this chunk's hash to result so far:
md5_h0 += a;
md5_h1 += b;
md5_h2 += c;
md5_h3 += d;
}
md5_h[0] = md5_h0;
md5_h[1] = md5_h1;
md5_h[2] = md5_h2;
md5_h[3] = md5_h3;
// cleanup
Free(msg);
}
U8* md5_string(U8* buf, I64 size)
{
U32 md5_h[4];
md5(buf, size, &md5_h[0]);
U8* str = CAlloc(33, adam_task);
StrPrint(str + StrLen(str), "%02x%02x%02x%02x", md5_h[0].u8[0],
md5_h[0].u8[1], md5_h[0].u8[2], md5_h[0].u8[3]);
StrPrint(str + StrLen(str), "%02x%02x%02x%02x", md5_h[1].u8[0],
md5_h[1].u8[1], md5_h[1].u8[2], md5_h[1].u8[3]);
StrPrint(str + StrLen(str), "%02x%02x%02x%02x", md5_h[2].u8[0],
md5_h[2].u8[1], md5_h[2].u8[2], md5_h[2].u8[3]);
StrPrint(str + StrLen(str), "%02x%02x%02x%02x", md5_h[3].u8[0],
md5_h[3].u8[1], md5_h[3].u8[2], md5_h[3].u8[3]);
return str;
}

32
System/Api/NetInfo.HC Normal file
View File

@@ -0,0 +1,32 @@
#define NETINFO_REQUEST_PTR 0x300030
MemSet(NETINFO_REQUEST_PTR, NULL, sizeof(U64));
class NetInfoRequest {
U64 mac_address;
U64 ipv4_address;
U64 ipv4_netmask;
U64 ipv4_network;
U64 ipv4_gateway;
U64 dns_server_address;
U64 dns_server_port;
U64 rx_bytes;
U64 rx_frames;
U64 tx_bytes;
U64 tx_frames;
U64 pointer_to_u32;
};
NetInfoRequest* @net_info_request()
{
U32 res = 0;
NetInfoRequest* req = CAlloc(sizeof(NetInfoRequest), Fs->code_heap);
req->pointer_to_u32 = &res;
U64* request_ptr = NETINFO_REQUEST_PTR;
while (*request_ptr)
Sleep(1);
LXchgU32(request_ptr, req);
while (!res)
Sleep(1);
return req;
}

209
System/Api/Tcp.HC Normal file
View File

@@ -0,0 +1,209 @@
#define TCP_SOCKET_REQUEST_PTR 0x300000
#define TCP_BIND_REQUEST_PTR 0x300040
#define TCP_ACCEPT_REQUEST_PTR 0x300050
MemSet(TCP_SOCKET_REQUEST_PTR, NULL, sizeof(U64));
// TcpSocket states
#define TCP_SOCKET_STATE_IDLE 0
#define TCP_SOCKET_STATE_ESTABLISHED 1
#define TCP_SOCKET_STATE_CLOSED 2
#define TCP_SOCKET_STATE_CONNECTING 4
class TcpSocket {
U64 remote_addr;
U64 remote_port;
U64 state;
U64 receive_buffer_ptr; // Pointer to receive buffer in physical memory
U64 receive_buffer_size;
U64 receive_buffer_filled; // Number of bytes Net has put into buffer
U64 receive_buffer_kick; // Net sets this to 1 when it has data available for
// us, we set back to 0 when ready to receive
U64 send_buffer_ptr;
U64 send_buffer_size;
U64 send_buffer_filled;
U64 send_buffer_kick; // We set this to 1 when we have data available to net,
// Net sets back to 0 when ready to receive
U64 close_kick; // We set this to 1 to force close the connection
U0 (*close)();
U64 (*receive)(U64 buf, U64 length);
U0 (*send)(U64 buf, U64 length);
};
class TcpBind {
U64 port;
U64 function;
U64 response_code;
};
U8 @tcp_close_wrapper_function[16]
= { 0x55, 0x48, 0x8B, 0xEC, 0x68, 0x78,
0x56, 0x34, 0x12, 0xE8, 0x02, 0x6D,
0x02, 0x00, 0x5D, 0xC3 };
U8 @tcp_receive_wrapper_function[32] = {
0x55, 0x48, 0x8B, 0xEC, 0x56, 0x57, 0x48, 0x8B, 0x75, 0x18, 0x48,
0x8B, 0x7D, 0x10, 0x56, 0x57, 0x68, 0x78, 0x56, 0x34, 0x12, 0xE8,
0x5E, 0x62, 0x02, 0x00, 0x5F, 0x5E, 0x5D, 0xC2, 0x10, 0x00
};
U8 @tcp_send_wrapper_function[32] = {
0x55, 0x48, 0x8B, 0xEC, 0x56, 0x57, 0x48, 0x8B, 0x75, 0x18, 0x48,
0x8B, 0x7D, 0x10, 0x56, 0x57, 0x68, 0x78, 0x56, 0x34, 0x12, 0xE8,
0x5E, 0x62, 0x02, 0x00, 0x5F, 0x5E, 0x5D, 0xC2, 0x10, 0x00
};
U0 @tcp_socket_send(TcpSocket* s, U64 buf, U64 length)
{
while (s->send_buffer_kick)
Sleep(1);
U64 pos = 0;
U64 bytes_to_send = 0;
while (pos < length) {
if ((length - pos) > s->send_buffer_size)
bytes_to_send = s->send_buffer_size;
else
bytes_to_send = length - pos;
MemCpy(s->send_buffer_ptr, buf + pos, bytes_to_send);
s->send_buffer_filled = bytes_to_send;
s->send_buffer_kick = 1;
pos += bytes_to_send;
while (s->send_buffer_kick)
Sleep(1);
}
}
U64 @tcp_socket_receive(TcpSocket* s, U64 buf, U64 size)
{
s->receive_buffer_size = size;
s->receive_buffer_kick = 0;
while (!s->receive_buffer_kick) {
if (s->state == TCP_SOCKET_STATE_CLOSED)
return NULL;
Sleep(1);
}
U64 bytes_received = s->receive_buffer_filled;
if (bytes_received > 0) {
MemCpy(buf, s->receive_buffer_ptr, bytes_received);
}
return bytes_received;
}
U0 @tcp_wait_for_connection_established(TcpSocket* s)
{
while (s->state != TCP_SOCKET_STATE_ESTABLISHED)
Sleep(1);
}
U0 @tcp_socket_close(TcpSocket* s)
{
if (s->close)
Free(s->close);
if (s->receive)
Free(s->receive);
if (s->send)
Free(s->send);
s->close_kick = 1;
s->state = TCP_SOCKET_STATE_CLOSED;
}
TcpSocket* @tcp_socket_create(U8* host, U64 port)
{
U64 addr = @dns_query(host);
TcpSocket* s = CAlloc(sizeof(TcpSocket), adam_task->code_heap);
s->remote_addr = addr;
s->remote_port = port;
U64 a;
s->close = MAlloc(16, adam_task->code_heap);
MemCpy(s->close, @tcp_close_wrapper_function, 16);
a = s->close;
a += 0x05;
MemSetU32(a, s, 1);
a = s->close;
a += 0x09;
@patch_call_rel32(a, &@tcp_socket_close);
s->receive = MAlloc(25, adam_task->code_heap);
MemCpy(s->receive, @tcp_receive_wrapper_function, 32);
a = s->receive;
a += 0x11;
MemSetU32(a, s, 1);
a = s->receive;
a += 0x15;
@patch_call_rel32(a, &@tcp_socket_receive);
s->send = MAlloc(32, adam_task->code_heap);
MemCpy(s->send, @tcp_send_wrapper_function, 32);
a = s->send;
a += 0x11;
MemSetU32(a, s, 1);
a = s->send;
a += 0x15;
@patch_call_rel32(a, &@tcp_socket_send);
U64* request_ptr = TCP_SOCKET_REQUEST_PTR;
while (*request_ptr)
Sleep(1);
LXchgU32(request_ptr, s);
return s;
}
U64 @tcp_socket_bind(U64 port, U64 function)
{
if (!port || !function)
return NULL;
TcpBind* b = CAlloc(sizeof(TcpBind), adam_task->code_heap);
b->port = port;
b->function = function; // U0 my_spawn_wrapper_function(TcpSocket* s)
U64* request_ptr = TCP_BIND_REQUEST_PTR;
while (*request_ptr)
Sleep(1);
LXchgU32(request_ptr, b);
while (*request_ptr)
Sleep(1);
U64 res = b->response_code;
Free(b);
return res;
}
TcpSocket* @tcp_socket_accept(TcpSocket* s)
{
if (!s || !s->remote_addr || !s->remote_port)
return NULL;
U64 a;
s->close = MAlloc(16, adam_task->code_heap);
MemCpy(s->close, @tcp_close_wrapper_function, 16);
a = s->close;
a += 0x05;
MemSetU32(a, s, 1);
a = s->close;
a += 0x09;
@patch_call_rel32(a, &@tcp_socket_close);
s->receive = MAlloc(25, adam_task->code_heap);
MemCpy(s->receive, @tcp_receive_wrapper_function, 32);
a = s->receive;
a += 0x11;
MemSetU32(a, s, 1);
a = s->receive;
a += 0x15;
@patch_call_rel32(a, &@tcp_socket_receive);
s->send = MAlloc(32, adam_task->code_heap);
MemCpy(s->send, @tcp_send_wrapper_function, 32);
a = s->send;
a += 0x11;
MemSetU32(a, s, 1);
a = s->send;
a += 0x15;
@patch_call_rel32(a, &@tcp_socket_send);
return s;
}

10
System/Config/Net.json Normal file
View File

@@ -0,0 +1,10 @@
{
"tcpip.ipv4_address": "10.20.0.10",
"tcpip.ipv4_netmask": "255.255.255.0",
"tcpip.ipv4_network": "10.20.0.0",
"tcpip.ipv4_gateway": "10.20.0.254",
"tcpip.ipv4_dns_server_address": "8.8.8.8",
"tcpip.ipv4_dns_server_port": "53",
"tcpip.mss_size": "1360",
"eof": "eof"
}

51
System/FFI/Base.HC Normal file
View File

@@ -0,0 +1,51 @@
#define PUSH_SYSV_REGS \
asm {PUSH RCX PUSH RDX PUSH RBX PUSH RBP PUSH RSI PUSH RDI PUSH R8 PUSH R9 PUSH \
R10 PUSH R11 PUSH R12 PUSH R13 PUSH R14 PUSH R15}
#define POP_SYSV_REGS \
p0 = p0; \
p1 = p1; \
p2 = p2; \
p3 = p3; \
p4 = p4; \
p5 = p5; \
asm {POP R15 POP R14 POP R13 POP R12 POP R11 POP R10 POP R9 POP R8 POP RDI POP \
RSI POP RBP POP RBX POP RDX POP RCX}
#define GET_SYSV_ARGS \
asm {PUSH R9 PUSH R8 PUSH RCX PUSH RDX PUSH RSI PUSH RDI} \
I64 reg RDI p0; \
I64 reg RSI p1; \
I64 reg RDX p2; \
I64 reg RCX p3; \
I64 reg R8 p4; \
I64 reg R9 p5; \
asm {POP RDI POP RSI POP RDX POP RCX POP R8 POP R9}
#define MOV_ANS_RAX asm { MOV[&ans], RAX }
#define MOV_PARAM0_RDI asm {MOV [&param0], RDI}
I64 param0;
I64 elf_argc;
U8** elf_argv;
asm {
_ELF_CALL::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RDI,U64 SF_ARG2[RBP]
MOV RSI,U64 SF_ARG3[RBP]
TEST RAX,RAX
JZ @@05
CALL RAX
@@05: POP RBP
RET1 8
}
U0 _main()
{
MOV_PARAM0_RDI
CallInd(_ELF_CALL, param0, elf_argc, elf_argv);
UserTaskCont;
}
U0 _exit() { UserTaskCont; }

300
System/FFI/ELF64.HC Normal file
View File

@@ -0,0 +1,300 @@
#define EI_NIDENT 16
#define EM_X86_64 0x3E
#define ET_EXEC 2
#define ET_DYN 3
U0 @elf64_debug_print(U8 fmt, ...)
{
// FIXME: Remove unnecessary debug_print statements and PrintErr for errors.
no_warn fmt, argc, argv;
}
class Elf64_Ehdr {
U8 e_ident[EI_NIDENT]; /* Magic number and other info */
U16 e_type; /* Object file type */
U16 e_machine; /* Architecture */
U32 e_version; /* Object file version */
U64 e_entry; /* Entry point virtual address */
U64 e_phoff; /* Program header table file offset */
U64 e_shoff; /* Section header table file offset */
U32 e_flags; /* Processor-specific flags */
U16 e_ehsize; /* ELF header size in bytes */
U16 e_phentsize; /* Program header table entry size */
U16 e_phnum; /* Program header table entry count */
U16 e_shentsize; /* Section header table entry size */
U16 e_shnum; /* Section header table entry count */
U16 e_shstrndx; /* Section header string table index */
};
class Elf64_Shdr {
U32 sh_name; /* Section name (string tbl index) */
U32 sh_type; /* Section type */
U64 sh_flags; /* Section flags */
U64 sh_addr; /* Section virtual addr at execution */
U64 sh_offset; /* Section file offset */
U64 sh_size; /* Section size in bytes */
U32 sh_link; /* Link to another section */
U32 sh_info; /* Additional section information */
U64 sh_addralign; /* Section alignment */
U64 sh_entsize; /* Entry size if section holds table */
};
class Elf64_Sym {
U32 st_name; /* Symbol name (string tbl index) */
U8 st_info; /* Symbol type and binding */
U8 st_other; /* Symbol visibility */
U16 st_shndx; /* Section index */
U64 st_value; /* Symbol value */
U64 st_size; /* Symbol size */
};
class PLT_entry {
U8 pad[0x10];
};
class RELA_entry {
U64 r_offset;
U64 r_info;
I64 r_addend;
};
class Elf {
union {
U8* u8;
Elf64_Ehdr* ehdr;
} I64 size;
U8* dynstr;
Elf64_Sym* dynsym;
PLT_entry* plt;
RELA_entry* rela_dyn;
RELA_entry* rela_plt;
Elf64_Sym* strtab;
Elf64_Sym* symtab;
I64 rela_dyn_size;
I64 rela_plt_size;
I64 strtab_size;
I64 symtab_size;
};
U0 (*_start)();
U0 unimplemented_symbol()
{
I32 s = 0xDEADF00D;
PrintWarn("Unimplemented symbol: %s\n", s);
Dbg;
while (1)
Sleep(1);
}
Bool is_valid_elf(Elf* elf)
{
Bool res = TRUE;
if (MemCmp(elf->u8 + 1, "ELF", 3)) {
@elf64_debug_print("Invalid signature (not ELF).\n");
res = FALSE;
}
if (elf->ehdr->e_type != ET_EXEC && elf->ehdr->e_type != ET_DYN) {
@elf64_debug_print("Invalid object file type.\n");
res = FALSE;
}
if (elf->ehdr->e_machine != EM_X86_64) {
@elf64_debug_print("Invalid architecture.\n");
res = FALSE;
}
return res;
}
U0 process_elf_section_header_table(Elf* elf)
{
Elf64_Shdr* shdr = elf->u8 + elf->ehdr->e_shoff;
Elf64_Shdr* shdr_shstrtab = shdr + elf->ehdr->e_shstrndx;
U8* shstrtab = elf->u8 + shdr_shstrtab->sh_offset;
I64 i = 0;
while (i < elf->ehdr->e_shnum) {
if (!StrCmp(shstrtab + shdr->sh_name, ".symtab")) {
@elf64_debug_print("found symtab at 0x%08x, size = %d\n", shdr->sh_offset,
shdr->sh_size);
elf->symtab = elf->u8 + shdr->sh_offset;
elf->symtab_size = shdr->sh_size;
}
if (!StrCmp(shstrtab + shdr->sh_name, ".strtab")) {
@elf64_debug_print("found strtab at 0x%08x, size = %d\n", shdr->sh_offset,
shdr->sh_size);
elf->strtab = elf->u8 + shdr->sh_offset;
elf->strtab_size = shdr->sh_size;
}
if (shdr->sh_addr) {
MemCpy(shdr->sh_addr, elf->u8 + shdr->sh_offset, shdr->sh_size);
if (!StrCmp(shstrtab + shdr->sh_name, ".dynstr"))
elf->dynstr = shdr->sh_addr;
if (!StrCmp(shstrtab + shdr->sh_name, ".dynsym"))
elf->dynsym = shdr->sh_addr;
if (!StrCmp(shstrtab + shdr->sh_name, ".plt"))
elf->plt = shdr->sh_addr;
if (!StrCmp(shstrtab + shdr->sh_name, ".rela.dyn")) {
elf->rela_dyn = shdr->sh_addr;
elf->rela_dyn_size = shdr->sh_size / shdr->sh_entsize;
}
if (!StrCmp(shstrtab + shdr->sh_name, ".rela.plt")) {
elf->rela_plt = shdr->sh_addr;
elf->rela_plt_size = shdr->sh_size / shdr->sh_entsize;
}
if (!StrCmp(shstrtab + shdr->sh_name, ".bss") || !StrCmp(shstrtab + shdr->sh_name, ".tbss")) {
MemSet(shdr->sh_addr, NULL, shdr->sh_size);
@elf64_debug_print(
"Zeroed out section '%s' at physical address 0x%06x, size = %d bytes\n",
shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size);
} else
@elf64_debug_print(
"MemCpy section '%s' to physical address 0x%06x, size = %d bytes\n",
shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size);
if (!StrCmp(shstrtab + shdr->sh_name, ".bss")) {
MemSet(shdr->sh_addr, NULL, shdr->sh_size);
@elf64_debug_print("MemSet section '%s' at physical address 0x%06x to NULL, "
"size = %d bytes\n",
shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size);
}
}
shdr++;
i++;
}
}
U0 process_elf_rela_dyn_entries(Elf* elf)
{
I64 i;
U8* entry_name;
RELA_entry* rela_dyn = elf->rela_dyn;
for (i = 0; i < elf->rela_dyn_size; i++) {
entry_name = elf->dynstr + elf->dynsym[(rela_dyn->r_info >> 32)].st_name;
@elf64_debug_print("rela_dyn->r_offset = %08x\n", rela_dyn->r_offset);
@elf64_debug_print("entry name = '%s'\n", entry_name);
if (!StrCmp(entry_name, "__libc_start_main")) {
*(rela_dyn->r_offset)(U64*) = &_main;
@elf64_debug_print("Set value for .rela.dyn entry '%s' to: &_main\n",
entry_name);
}
if (!StrCmp(entry_name, "stdin")) {
*(rela_dyn->r_offset)(U64*) = 0;
@elf64_debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 0);
}
if (!StrCmp(entry_name, "stdout")) {
*(rela_dyn->r_offset)(U64*) = 1;
@elf64_debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 1);
}
if (!StrCmp(entry_name, "stderr")) {
*(rela_dyn->r_offset)(U64*) = 2;
@elf64_debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 2);
}
rela_dyn++;
}
}
CHashClass* get_symbol_hash_entry(U8* entry_name)
{
I64 i;
CHashSrcSym* sym;
CHashTable* tbl = Fs->hash_table;
while (tbl) {
for (i = 0; i < tbl->mask; i++) {
sym = tbl->body[i];
while (sym) {
if (sym->type == HTT_CLASS)
if (!StrCmp(sym->str, entry_name))
return sym;
sym = sym->next;
}
}
tbl = tbl->next;
}
return NULL;
}
U64 get_symbol_address(U8* entry_name)
{
CHash* h = HashFind(entry_name, Fs->hash_table, Fs->hash_table->mask);
if (!h)
return NULL;
switch (h->type) {
case HTT_GLBL_VAR:
return h(CHashGlblVar*)->data_addr;
break;
case HTT_FUN:
return h(CHashFun*)->exe_addr;
break;
default:
return NULL;
break;
}
return NULL;
}
U0 process_elf_rela_plt_entries(Elf* elf)
{
I64 i;
U32 handler;
U32* patch;
U8* entry_name;
Bool symbol_exists;
PLT_entry* plt = elf->plt;
RELA_entry* rela_plt = elf->rela_plt;
plt++;
for (i = 0; i < elf->rela_plt_size; i++) {
symbol_exists = FALSE;
entry_name = elf->dynstr + elf->dynsym[(rela_plt->r_info >> 32)].st_name;
handler = MAlloc(sizeof(unimplemented_symbol), adam_task->code_heap);
MemCpy(handler, &unimplemented_symbol, sizeof(unimplemented_symbol));
patch = handler + 0x0A;
*patch = entry_name;
@patch_jmp_rel32(plt, handler);
@patch_call_rel32(handler + 0x16, &PrintErr);
//@patch_call_rel32(handler + 0x21, &_exit);
if (!StrCmp(entry_name, "__libc_start_main")) {
symbol_exists = TRUE;
@patch_jmp_rel32(plt, &_main);
@elf64_debug_print("Set value for .rela.plt entry '%s' to &_main\n", entry_name);
}
if (get_symbol_address(entry_name)) {
symbol_exists = TRUE;
@patch_jmp_rel32(plt, get_symbol_address(entry_name));
@elf64_debug_print("Set value for .rela.plt entry '%s' to &%s\n", entry_name,
entry_name);
}
if (!symbol_exists)
@elf64_debug_print(
"Set value for .rela.plt entry '%s' to &unimplemented_symbol\n",
entry_name);
rela_plt++;
plt++;
}
}
U0 load_elf(...)
{
if (argc < 1) {
PrintErr("Not enough arguments.\n");
return;
}
if (!FileFind(argv[0])) {
PrintErr("File not found: %s\n", argv[0]);
return;
}
Elf elf;
elf.u8 = FileRead(argv[0], &elf.size);
@elf64_debug_print("Load file '%s', size = %d bytes\n", argv[0], elf.size);
if (!is_valid_elf(&elf)) {
PrintErr("File is not a valid ELF x86-64 executable.\n");
return;
}
process_elf_section_header_table(&elf);
process_elf_rela_dyn_entries(&elf);
process_elf_rela_plt_entries(&elf);
_start = elf.ehdr->e_entry;
elf_argc = argc;
elf_argv = argv;
}

327
System/FFI/LibC.HC Normal file
View File

@@ -0,0 +1,327 @@
#define stdin 0
#define stdout 1
#define stderr 2
U0 bcmp()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
MemCmp(p0, p1, p2);
POP_SYSV_REGS
}
U64 @calloc(I64 size)
{
return CAlloc(size, adam_task->code_heap);
}
U0 calloc()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@calloc(p0 * p1);
POP_SYSV_REGS
}
U0 free()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
Free(p0);
POP_SYSV_REGS
}
I64 @isatty()
{
return 0;
}
U0 isatty()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
// Dbg;
@isatty;
POP_SYSV_REGS
}
I64 @fwrite(U8* ptr, I64 size, I64 nmemb, U64 stream)
{
U8* tmp;
switch (stream) {
case stdout:
case stderr:
tmp = CAlloc((size * nmemb) + 1, adam_task->code_heap);
MemCpy(tmp, ptr, (size * nmemb));
#ifdef QEMU_RUN_TESTS
QemuDebugMsg(tmp);
#endif
DocPutS(adam_task->put_doc, tmp);
Free(tmp);
// if (!MemCmp(tmp, "VERIFICATION FAILED", 19))
// Break;
break;
default:
break;
}
return size * nmemb;
}
U0 fwrite()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@fwrite(p0, p1, p2, p3);
POP_SYSV_REGS
}
U64 @getentropy(U8* buffer, U64 length)
{
I64 i;
for (i = 0; i < length; i++)
buffer[i] = RandU64;
return 0;
}
U0 getentropy()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@getentropy(p0, p1);
POP_SYSV_REGS
}
U0 htonl()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
EndianU32(p0);
POP_SYSV_REGS
}
U0 ntohl()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
EndianU32(p0);
POP_SYSV_REGS
}
U0 htons()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
EndianU16(p0);
POP_SYSV_REGS
}
U0 ntohs()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
EndianU16(p0);
POP_SYSV_REGS
}
U64 @malloc(I64 size)
{
return MAlloc(size, adam_task->code_heap);
}
U0 malloc()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@malloc(p0);
POP_SYSV_REGS
}
U0 memcmp()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
MemCmp(p0, p1, p2);
POP_SYSV_REGS
}
U0 memcpy()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
MemCpy(p0, p1, p2);
POP_SYSV_REGS
}
U8* @memmove(U8* dest, U8* src, I64 n)
{
I64 i;
U8* from = src;
U8* to = dest;
if (from == to || n == 0)
return dest;
if (to > from && to - from < n) {
/* to overlaps with from */
/* <from......> */
/* <to........> */
/* copy in reverse, to avoid overwriting from */
for (i = n - 1; i >= 0; i--)
to[i] = from[i];
return dest;
}
if (from > to && from - to < n) {
/* to overlaps with from */
/* <from......> */
/* <to........> */
/* copy forwards, to avoid overwriting from */
for (i = 0; i < n; i++)
to[i] = from[i];
return dest;
}
MemCpy(dest, src, n);
return dest;
}
U0 memmove()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@memmove(p0, p1, p2);
POP_SYSV_REGS
}
U0 memset()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
MemSet(p0, p1, p2);
POP_SYSV_REGS
}
U0 putc()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
PutChars(p0);
POP_SYSV_REGS
}
U0 rand()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
RandU64;
POP_SYSV_REGS
}
U8* @realloc(U8* ptr, I64 size)
{
U8* new;
if (!ptr) {
new = MAlloc(size, adam_task->code_heap);
} else {
new = MAlloc(size, adam_task->code_heap);
MemCpy(new, ptr, size);
Free(ptr);
}
return new;
}
U0 realloc()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@realloc(p0, p1);
POP_SYSV_REGS
}
// FIXME: It is non-obvious how to take a [u8] and convert it to a
// formatted string in Jakt, so we have to do this hack for
// now. Hopefully, this will change soon.
U0 sprintf()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
StrPrint(p0, p1, p2, p3, p4, p5);
POP_SYSV_REGS
}
I64 @strncmp(U8* s1, U8* s2, I32 n)
{
U64 u1, u2;
while (n-- > 0) {
u1 = *s1++;
u2 = *s2++;
u1 = u1 & 0xff;
u2 = u2 & 0xff;
if (u1 != u2)
return u1 - u2;
if (u1 == '\0')
return 0;
}
return 0;
}
U0 strncmp()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@strncmp(p0, p1, p2);
POP_SYSV_REGS
}
U0 strcmp()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
StrCmp(p0, p1);
POP_SYSV_REGS
}
U0 strlen()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
StrLen(p0);
POP_SYSV_REGS
}
I64 tos_nist_offset = 5020;
#define NIST_TIME_OFFSET (tos_nist_offset - local_time_offset / CDATE_FREQ)
public
I64 CDate2Unix(CDate dt)
{ // TempleOS datetime to Unix timestamp.
return ToI64((dt - Str2Date("1/1/1970")) / CDATE_FREQ + NIST_TIME_OFFSET);
}
I64 @time(I64* ptr)
{
no_warn ptr;
return CDate2Unix(Now);
}
U0 time()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@time(p0);
POP_SYSV_REGS
}
U0 toupper()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
ToUpper(p0);
POP_SYSV_REGS
}
U0 __assert_fail()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
"%s:%d: %s: %s\n", p1, p2, p3, p0;
Break;
POP_SYSV_REGS
}

35
System/FFI/New.HC Normal file
View File

@@ -0,0 +1,35 @@
U0 _ZdlPv()
{
// operator delete(void*)
PUSH_SYSV_REGS
GET_SYSV_ARGS
Free(p0);
POP_SYSV_REGS
}
U0 _ZdlPvm()
{
// operator delete(void*, unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
Free(p0);
POP_SYSV_REGS
}
U0 _Znwm()
{
// operator new(unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
MAlloc(p0, adam_task);
POP_SYSV_REGS
}
U0 _ZnwmRKSt9nothrow_t()
{
// operator new(unsigned long, std::nothrow_t const&)
PUSH_SYSV_REGS
GET_SYSV_ARGS
MAlloc(p0, adam_task);
POP_SYSV_REGS
}

288
System/Jakt/DC.HC Normal file
View File

@@ -0,0 +1,288 @@
U0 _Z8dc_aliasm()
{
// dc_alias(unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
DCAlias(p0);
POP_SYSV_REGS
}
U0 _Z7dc_blotmmmm()
{
// dc_blot(unsigned long, unsigned long, unsigned long, unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
GrBlot(p0, p1, p2, p3);
POP_SYSV_REGS
}
U8* @dc_buffer(CDC* dc) { return dc->body; }
U0 _Z9dc_bufferm()
{
// dc_buffer(unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@dc_buffer(p0);
POP_SYSV_REGS
}
I64 @dc_color(CDC* dc) { return dc->color; }
U0 _Z8dc_colorm()
{
// dc_color(unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@dc_color(p0);
POP_SYSV_REGS
}
U0 @dc_copy(CDC* dest, I64 x, I64 y, CDC* src)
{
// If position is off-screen, return
if (x > dest->width - 1 || y > dest->height - 1)
return;
// If device context dimensions match, MemCpy and return
if (dest->width_internal == src->width_internal && dest->height == src->height) {
MemCpy(dest->body, src->body, dest->width_internal * dest->height);
return;
}
CDC* dc1 = DCAlias(dest);
CDC* dc2 = DCAlias(src);
I64 src_line = 0;
I64 src_row = 0;
I64 clip_y = 0;
// Handle horizontal clipping left
while (x < 0) {
dc2->x0++;
x++;
}
// Handle vertical clipping top
while (y < 0) {
dc2->body += src->width_internal;
dc2->y0++;
y++;
}
// default, clip line to copy as width-left off screen
src_line = src->width - dc2->x0;
if (-dc2->x0 + x + src->width >= dest->width) {
src_line -= ((-dc2->x0 + x + src->width) - dest->width);
}
dc2->body += dc2->x0;
clip_y = y;
while (src_row < (src->height - dc2->y0) && clip_y < dest->height) {
MemCpy(dc1->body + (y * dest->width) + x, dc2->body, src_line);
dc2->body += src->width_internal;
dc1->body += dest->width_internal;
clip_y++;
src_row++;
}
Free(dc2);
Free(dc1);
}
U0 _Z7dc_copymmmm()
{
// dc_copy(unsigned long, unsigned long, unsigned long, unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@dc_copy(p0, p1, p2, p3);
POP_SYSV_REGS
}
U0 _Z10dc_destroym()
{
// dc_destroy(unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
DCDel(p0);
POP_SYSV_REGS
}
U0 _Z14dc_draw_circlemlll()
{
// dc_draw_circle(unsigned long, long, long, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
GrCircle3(p0, p1, p2, 0, p3);
POP_SYSV_REGS
}
U0 _Z19dc_draw_filled_rectmllll()
{
// dc_draw_filled_rect(unsigned long, long, long, long, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
GrRect(p0, p1, p2, p3, p4);
POP_SYSV_REGS
}
U0 _Z12dc_draw_linemllll()
{
// dc_draw_line(unsigned long, long, long, long, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
GrLine3(p0, p1, p2, 0, p3, p4, 0);
POP_SYSV_REGS
}
U0 _Z13dc_draw_pixelmll()
{
// dc_draw_pixel(unsigned long, long, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
GrPlot(p0, p1, p2);
POP_SYSV_REGS
}
U0 _Z7dc_fillmm()
{
// dc_fill(unsigned long, unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
DCFill(p0, p1);
POP_SYSV_REGS
}
CDC* @dc_gr_dc() { return gr.dc; }
U0 _Z8dc_gr_dcv()
{
// dc_gr_dc()
PUSH_SYSV_REGS
GET_SYSV_ARGS
@dc_gr_dc();
POP_SYSV_REGS
}
I64 @dc_height(CDC* dc) { return dc->height; }
U0 _Z9dc_heightm()
{
// dc_height(unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@dc_height(p0);
POP_SYSV_REGS
}
U0 _Z17dc_load_from_filePKc()
{
// dc_load_from_file(char const*)
PUSH_SYSV_REGS
GET_SYSV_ARGS
GRRead(p0);
POP_SYSV_REGS
}
U0 _Z6dc_newmm()
{
// dc_new(unsigned long, unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
DCNew(p0, p1);
POP_SYSV_REGS
}
U0 _Z11dc_pixel_atmll()
{
// dc_pixel_at(unsigned long, long, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
GrPeek(p0, p1, p2);
POP_SYSV_REGS
}
U0 _Z16dc_replace_colormmm()
{
// dc_replace_color(unsigned long, unsigned long, unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
DCColorChg(p0, p1, p2);
POP_SYSV_REGS
}
U0 _Z13dc_screenshotv()
{
// dc_screenshot()
PUSH_SYSV_REGS
GET_SYSV_ARGS
DCScrnCapture(1);
POP_SYSV_REGS
}
U0 _Z15dc_save_to_filePKcm()
{
// dc_save_to_file(char const*, unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
GRWrite(p0, p1);
POP_SYSV_REGS
}
U0 @dc_set_color(CDC* dc, I64 color) { dc->color = color; }
U0 _Z12dc_set_colorml()
{
// dc_set_color(unsigned long, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@dc_set_color(p0, p1);
POP_SYSV_REGS
}
U0 @dc_set_thickness(CDC* dc, I64 thickness) { dc->thick = thickness; }
U0 _Z16dc_set_thicknessml()
{
// dc_set_thickness(unsigned long, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@dc_set_thickness(p0, p1);
POP_SYSV_REGS
}
I64 @dc_thickness(CDC* dc) { return dc->thick; }
U0 _Z12dc_thicknessm()
{
// dc_thickness(unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@dc_thickness(p0);
POP_SYSV_REGS
}
I64 @dc_width(CDC* dc) { return dc->width; }
U0 _Z8dc_widthm()
{
// dc_width(unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@dc_width(p0);
POP_SYSV_REGS
}
I64 @dc_width_internal(CDC* dc) { return dc->width_internal; }
U0 _Z17dc_width_internalm()
{
// dc_width_internal(unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@dc_width_internal(p0);
POP_SYSV_REGS
}

53
System/Jakt/IOPort.HC Normal file
View File

@@ -0,0 +1,53 @@
U0 _Z14ioport_read_u8t()
{
// ioport_read_u8(unsigned short)
PUSH_SYSV_REGS
GET_SYSV_ARGS
InU8(p0);
POP_SYSV_REGS
}
U0 _Z15ioport_read_u16t()
{
// ioport_read_u16(unsigned short)
PUSH_SYSV_REGS
GET_SYSV_ARGS
InU16(p0);
POP_SYSV_REGS
}
U0 _Z15ioport_read_u32t()
{
// ioport_read_u32(unsigned short)
PUSH_SYSV_REGS
GET_SYSV_ARGS
InU32(p0);
POP_SYSV_REGS
}
U0 _Z15ioport_write_u8th()
{
// ioport_write_u8(unsigned short, unsigned char)
PUSH_SYSV_REGS
GET_SYSV_ARGS
OutU8(p0, p1);
POP_SYSV_REGS
}
U0 _Z16ioport_write_u16tt()
{
// ioport_write_u16(unsigned short, unsigned short)
PUSH_SYSV_REGS
GET_SYSV_ARGS
OutU16(p0, p1);
POP_SYSV_REGS
}
U0 _Z16ioport_write_u32tj()
{
// ioport_write_u32(unsigned short, unsigned int)
PUSH_SYSV_REGS
GET_SYSV_ARGS
OutU32(p0, p1);
POP_SYSV_REGS
}

72
System/Jakt/Input.HC Normal file
View File

@@ -0,0 +1,72 @@
U0 _Z16input_get_stringPKc()
{
// input_get_string(char const*)
PUSH_SYSV_REGS
GET_SYSV_ARGS
GetStr(p0);
POP_SYSV_REGS
}
Bool @input_key_down(U8 scancode) { return Bt(kbd.down_bitmap, scancode); }
U0 _Z14input_key_downh()
{
// input_key_down(unsigned char)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@input_key_down(p0);
POP_SYSV_REGS
}
Bool @input_mouse_left() { return ms.lb; }
U0 _Z16input_mouse_leftv()
{
// input_mouse_left()
PUSH_SYSV_REGS
GET_SYSV_ARGS
@input_mouse_left();
POP_SYSV_REGS
}
Bool @input_mouse_right() { return ms.rb; }
U0 _Z17input_mouse_rightv()
{
// input_mouse_right()
PUSH_SYSV_REGS
GET_SYSV_ARGS
@input_mouse_right();
POP_SYSV_REGS
}
I64 @input_mouse_x() { return ms.pos.x; }
U0 _Z13input_mouse_xv()
{
// input_mouse_x()
PUSH_SYSV_REGS
GET_SYSV_ARGS
@input_mouse_x();
POP_SYSV_REGS
}
I64 @input_mouse_y() { return ms.pos.y; }
U0 _Z13input_mouse_yv()
{
// input_mouse_y()
PUSH_SYSV_REGS
GET_SYSV_ARGS
@input_mouse_y();
POP_SYSV_REGS
}
U0 _Z17input_press_a_keyv()
{
// input_press_a_key()
PUSH_SYSV_REGS
GET_SYSV_ARGS
PressAKey;
POP_SYSV_REGS
}

282
System/Jakt/OS.HC Normal file
View File

@@ -0,0 +1,282 @@
U0 _Z8os_blinkPKc()
{
// os_blink(char const*)
PUSH_SYSV_REGS
GET_SYSV_ARGS
F64 frequency = Str2F64(p0);
Print("called os_blink(%.1f)\n", frequency);
Blink(frequency);
POP_SYSV_REGS
}
U64 @os_call(U64 addr, U64 val)
{
if (!addr || !val)
return NULL;
U64 (*func)(U64 arg);
func = addr;
return func(val);
}
U0 _Z7os_callmm()
{
// os_call(unsigned long, unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@os_call(p0, p1);
POP_SYSV_REGS
}
U0 _Z16os_device_callocj()
{
// os_device_calloc(unsigned int)
PUSH_SYSV_REGS
GET_SYSV_ARGS
CAllocAligned(p0, 4096, adam_task->code_heap);
POP_SYSV_REGS
}
U0 _Z7os_exitv()
{
// os_exit()
PUSH_SYSV_REGS
GET_SYSV_ARGS
UserTaskCont;
POP_SYSV_REGS
}
U8* @os_file_picker(U8* path, U8* glob)
{
U8* full_path = CAlloc(StrLen(path) + StrLen(glob) + 4, adam_task);
CatPrint(full_path, "%s/%s", path, glob);
CDirEntry* de = FilesFind(full_path);
Free(full_path);
CDirEntry* tmpde;
U8* file_list = NULL;
U8* selected_file = NULL;
I64 list_pos = 0;
I64 list_size = 0;
tmpde = de;
while (tmpde) {
list_size += StrLen(tmpde->name) + 2;
tmpde = tmpde->next;
}
file_list = CAlloc(list_size, adam_task);
tmpde = de;
while (tmpde) {
StrCpy(file_list + list_pos, tmpde->name);
list_pos += StrLen(tmpde->name) + 1;
tmpde = tmpde->next;
}
I64 list_index = Adam("PopUpPickLst(0x%08x);\n", file_list);
Free(file_list);
list_pos = 0;
if (list_index < 0) {
DirTreeDel(de);
return StrNew("", adam_task);
}
tmpde = de;
while (tmpde) {
if (list_index == list_pos) {
selected_file = CAlloc(StrLen(path) + StrLen(tmpde->name) + 4, adam_task);
CatPrint(selected_file, "%s/%s", path, tmpde->name);
break;
}
StrCpy(file_list + list_pos, tmpde->name);
list_pos++;
tmpde = tmpde->next;
}
DirTreeDel(de);
return selected_file;
}
U0 _Z14os_file_pickerPKcS0_()
{
// os_file_picker(char const*, char const*)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@os_file_picker(p0, p1);
POP_SYSV_REGS
}
U8* @os_files_list(U8* path)
{
U8* full_path = CAlloc(StrLen(path) + 4, adam_task);
CatPrint(full_path, "%s", path);
CDirEntry* de = FilesFind(full_path);
Free(full_path);
CDateStruct ds;
CDirEntry* tmpde;
U8* file_list = NULL;
I64 list_size = 0;
tmpde = de;
while (tmpde) {
list_size += StrLen(tmpde->name) + 48; // Should be enough for filename, date,
// filesize + semicolon separators
tmpde = tmpde->next;
}
if (!list_size)
return NULL;
file_list = CAlloc(list_size, adam_task);
tmpde = de;
I64 counter = 0;
while (tmpde) {
if (counter > 0) {
StrCpy(file_list + StrLen(file_list), "|");
}
StrCpy(file_list + StrLen(file_list), tmpde->name);
if (tmpde->attr & RS_ATTR_DIR)
StrCpy(file_list + StrLen(file_list), "/");
StrCpy(file_list + StrLen(file_list), ";");
Date2Struct(&ds, tmpde->datetime);
StrPrint(file_list + StrLen(file_list), "%04d-%02d-%02d %02d:%02d", ds.year,
ds.mon, ds.day_of_mon, ds.hour, ds.min);
StrCpy(file_list + StrLen(file_list), ";");
StrPrint(file_list + StrLen(file_list), "%d", tmpde->size);
tmpde = tmpde->next;
counter++;
}
DirTreeDel(de);
return file_list;
}
U0 _Z14os_path_existsPKc()
{
// os_path_exists(char const*)
PUSH_SYSV_REGS
GET_SYSV_ARGS
FileFind(p0);
POP_SYSV_REGS
}
U0 _Z13os_files_listPKc()
{
// os_files_list(char const*)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@os_files_list(p0);
POP_SYSV_REGS
}
Bool @os_is_vm()
{
CRAXRBCRCXRDX res;
CPUId(0x40000000, &res);
if (res.rbx == 0x4B4D564B)
return TRUE;
return FALSE;
}
U0 _Z8os_is_vmv()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@os_is_vm;
POP_SYSV_REGS
}
U0 @os_pc_speaker(F64 frequency)
{
I64 period;
if (!frequency)
OutU8(0x61, InU8(0x61) & ~3);
else {
period = ClampI64(SYS_TIMER_FREQ / frequency, 1, U16_MAX);
OutU8(0x43, 0xB6);
OutU8(0x42, period);
OutU8(0x42, period.u8[1]);
OutU8(0x61, 3 | InU8(0x61));
}
}
U0 _Z13os_pc_speakerPKc()
{
// os_pc_speaker(char const*)
PUSH_SYSV_REGS
GET_SYSV_ARGS
F64 frequency = Str2F64(p0);
@os_pc_speaker(frequency);
POP_SYSV_REGS
}
U0 _Z9os_randomv()
{
// os_random()
PUSH_SYSV_REGS
GET_SYSV_ARGS
RandU64;
POP_SYSV_REGS
}
U0 _Z19os_read_entire_filePKcPl()
{
// os_read_entire_file(char const*, long*)
PUSH_SYSV_REGS
GET_SYSV_ARGS
FileRead(p0, p1);
POP_SYSV_REGS
}
U0 @os_screenshot()
{
CDC* dc = DCScrnCapture(, adam_task);
// Image.Write("B:/screenshot.png", dc);
DCDel(dc);
}
U0 _Z13os_screenshotv()
{
// os_screenshot()
PUSH_SYSV_REGS
GET_SYSV_ARGS
@os_screenshot;
POP_SYSV_REGS
}
U8* @os_to_uppercase(U8* instr)
{
if (!instr)
return NULL;
if (!StrLen(instr))
return NULL;
U8* outstr = CAlloc(StrLen(instr) + 1, adam_task);
I64 i;
for (i = 0; i < StrLen(instr); i++)
outstr[i] = ToUpper(instr[i]);
return outstr;
}
U0 _Z15os_to_uppercasePKc()
{
// os_to_uppercase(char const*)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@os_to_uppercase(p0);
POP_SYSV_REGS
}
U0 _Z20os_write_entire_filePKcPhl()
{
// os_write_entire_file(char const*, unsigned char*, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
FileWrite(p0, p1, p2);
POP_SYSV_REGS
}

62
System/Jakt/PCI.HC Normal file
View File

@@ -0,0 +1,62 @@
U0 _Z8pci_findl()
{
// pci_find(long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
PCIClassFind(p0, 0);
POP_SYSV_REGS
}
U0 _Z11pci_read_u8llll()
{
// pci_read_u8(long, long, long, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
PCIReadU8(p0, p1, p2, p3);
POP_SYSV_REGS
}
U0 _Z12pci_read_u16llll()
{
// pci_read_u16(long, long, long, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
PCIReadU16(p0, p1, p2, p3);
POP_SYSV_REGS
}
U0 _Z12pci_read_u32llll()
{
// pci_read_u32(long, long, long, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
PCIReadU32(p0, p1, p2, p3);
POP_SYSV_REGS
}
U0 _Z12pci_write_u8llllh()
{
// pci_write_u8(long, long, long, long, unsigned char)
PUSH_SYSV_REGS
GET_SYSV_ARGS
PCIWriteU8(p0, p1, p2, p3, p4);
POP_SYSV_REGS
}
U0 _Z13pci_write_u16llllt()
{
// pci_write_u16(long, long, long, long, unsigned short)
PUSH_SYSV_REGS
GET_SYSV_ARGS
PCIWriteU16(p0, p1, p2, p3, p4);
POP_SYSV_REGS
}
U0 _Z13pci_write_u32llllj()
{
// pci_write_u32(long, long, long, long, unsigned int)
PUSH_SYSV_REGS
GET_SYSV_ARGS
PCIWriteU32(p0, p1, p2, p3, p4);
POP_SYSV_REGS
}

37
System/Jakt/Time.HC Normal file
View File

@@ -0,0 +1,37 @@
U0 _Z9time_busyl()
{
// time_busy(long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
Busy(p0);
POP_SYSV_REGS
}
I64 @time_jiffies() { return cnts.jiffies; }
U0 _Z12time_jiffiesv()
{
// time_jiffies()
PUSH_SYSV_REGS
GET_SYSV_ARGS
@time_jiffies;
POP_SYSV_REGS
}
U0 _Z8time_nowv()
{
// time_now()
PUSH_SYSV_REGS
GET_SYSV_ARGS
Now;
POP_SYSV_REGS
}
U0 _Z10time_sleepl()
{
// time_sleep(long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
Sleep(p0);
POP_SYSV_REGS
}

94
System/Jakt/Window.HC Normal file
View File

@@ -0,0 +1,94 @@
U0 @window_draw_it(CTask* task, CDC* dc)
{
if (task->user_data)
@dc_copy(dc, task->pix_left, task->pix_top, task->user_data);
}
CTask* @window_user()
{
CTask* task = Spawn(&UserCmdLine, , , 0);
TaskWait(task);
XTalk(task,
"while (1) { StrCpy(Fs->task_title, Fs->task_name); Sleep(1); };\n");
return task;
}
CTask* @window_create()
{
CTask* task = @window_user;
task->draw_it = &@window_draw_it;
return task;
}
U0 _Z13window_createv()
{
// window_create()
PUSH_SYSV_REGS
GET_SYSV_ARGS
@window_create();
POP_SYSV_REGS
}
U0 _Z14window_destroym()
{
// window_destroy(unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
Kill(p0);
POP_SYSV_REGS
}
Bool @window_is_focused(CTask* task) { return task == sys_focus_task; }
U0 _Z17window_is_focusedm()
{
// window_is_focused(unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@window_is_focused(p0);
POP_SYSV_REGS
}
U0 @window_set_coordinates(CTask* task, I64 top, I64 left, I64 bottom,
I64 right)
{
task->win_top = top;
task->win_left = left;
task->win_bottom = bottom;
task->win_right = right;
}
U0 _Z22window_set_coordinatesmllll()
{
// window_set_coordinates(unsigned long, long, long, long, long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@window_set_coordinates(p0, p1, p2, p3, p4);
POP_SYSV_REGS
}
U0 @window_set_context(CTask* task, CDC* dc) { task->user_data = dc; }
U0 _Z18window_set_contextmm()
{
// window_set_context(unsigned long, unsigned long)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@window_set_context(p0, p1);
POP_SYSV_REGS
}
U0 @window_set_title(CTask* task, U8* title)
{
StrCpy(task->task_name, title);
StrCpy(task->task_title, title);
}
U0 _Z16window_set_titlemPKc()
{
// window_set_title(unsigned long, char const*)
PUSH_SYSV_REGS
GET_SYSV_ARGS
@window_set_title(p0, p1);
POP_SYSV_REGS
}

1573
System/Libraries/Json.HC Normal file

File diff suppressed because it is too large Load Diff

196
System/Libraries/String.HC Normal file
View File

@@ -0,0 +1,196 @@
#define TRIM_BOTH 0
#define TRIM_LEFT 1
#define TRIM_RIGHT 2
I64 StrLenI32(I32* str)
{
I64 res = 0;
while (*str) {
++res;
++str;
}
return res;
}
U0 @string_append(U8* dst, U8* fmt, ...)
{
U8* buf;
if (argc) {
buf = StrPrintJoin(NULL, fmt, argc, argv);
} else {
buf = StrNew(fmt, adam_task);
}
U8* src = buf;
StrCpy(dst + StrLen(dst), src);
Free(buf);
}
Bool @string_is_number(U8* s)
{
while (*s) {
switch (*s) {
case '-':
case '.':
case '0' ... '9':
break;
default:
return FALSE;
break;
}
s++;
}
return TRUE;
}
Bool @string_begins_with(U8* fragment, U8* str)
{
if (!fragment || !str)
return FALSE;
if (StrLen(fragment) > StrLen(str))
return FALSE;
return !MemCmp(fragment, str, StrLen(fragment));
}
Bool @string_ends_with(U8* fragment, U8* str)
{
if (!fragment || !str)
return FALSE;
if (StrLen(fragment) > StrLen(str))
return FALSE;
return !MemCmp(fragment, str + StrLen(str) - StrLen(fragment), StrLen(fragment));
}
U0 @string_lower(U8* s)
{
while (*s) {
switch (*s) {
case 'A' ... 'Z':
*s += 32;
break;
default:
break;
}
++s;
}
}
U8* @string_replace(U8* s, U8* oldW, U8* newW)
{
if (!StrFind(oldW, s)) {
return StrNew(s, adam_task);
}
U8* result;
I64 i, cnt = 0;
I64 newWlen = StrLen(newW);
I64 oldWlen = StrLen(oldW);
for (i = 0; s[i] != NULL; i++) {
if (StrFind(oldW, &s[i]) == &s[i]) {
cnt++;
i += oldWlen - 1;
}
}
result = MAlloc(i + cnt * (newWlen - oldWlen) + 1, adam_task);
i = 0;
while (*s) {
if (StrFind(oldW, s) == s) {
StrCpy(&result[i], newW);
i += newWlen;
s += oldWlen;
} else
result[i++] = *s++;
}
result[i] = NULL;
return result;
}
U8** @string_split(U8* s, U8 ch = '\n', I64* cnt)
{
U8 check_buf[4];
StrPrint(check_buf, "%c", ch);
if (!StrFind(check_buf, s)) {
U8** same_arr = CAlloc(sizeof(U8*) * 1, adam_task);
same_arr[0] = s;
*cnt = 1;
return same_arr;
}
U8* p = s;
cnt[0] = 0;
while (*p) {
if (*p == ch)
cnt[0]++;
p++;
}
if (!(cnt[0]))
return NULL;
cnt[0]++;
I64 i = -1;
U8** arr = CAlloc(sizeof(U8*) * cnt[0], adam_task);
p = s;
while (*p) {
if (*p == ch || i < 0) {
i++;
arr[i] = p;
if (*p == ch) {
arr[i]++;
*p = NULL;
}
}
p++;
}
return arr;
}
Bool @string_trim_ch(U8 s_ch, U8 trim_ch)
{
if (!s_ch) {
return FALSE;
}
if (!trim_ch) {
return (s_ch == ' ' || s_ch == '\r' || s_ch == '\n' || s_ch == '\t');
} else {
return (s_ch == trim_ch);
}
}
U0 @string_trim(U8* s, U8 ch = NULL, I64 mode = TRIM_BOTH)
{
Bool trim_ch = @string_trim_ch(*s, ch);
if (mode == TRIM_BOTH || mode == TRIM_LEFT) {
while (trim_ch) {
StrCpy(s, s + 1);
trim_ch = @string_trim_ch(*s, ch);
}
}
trim_ch = @string_trim_ch(s[StrLen(s) - 1], ch);
if (mode == TRIM_BOTH || mode == TRIM_RIGHT) {
while (trim_ch) {
s[StrLen(s) - 1] = NULL;
trim_ch = @string_trim_ch(s[StrLen(s) - 1], ch);
}
}
}
class @string
{
U0 (*Append)(U8* dst, U8* fmt, ...);
Bool (*BeginsWith)(U8* fragment, U8* str);
Bool (*EndsWith)(U8* fragment, U8* str);
Bool (*IsNumber)(U8* s);
U0 (*Lower)(U8* s);
U8* (*Replace)(U8* s, U8* oldW, U8* newW);
U8** (*Split)(U8* s, U8 ch = '\n', I64 * cnt);
U0 (*Trim)(U8* s, U8 ch = NULL, I64 mode = TRIM_BOTH);
};
@string String;
String.Append = &@string_append;
String.BeginsWith = &@string_begins_with;
String.EndsWith = &@string_ends_with;
String.IsNumber = &@string_is_number;
String.Lower = &@string_lower;
String.Replace = &@string_replace;
String.Split = &@string_split;
String.Trim = &@string_trim;
"string ";

56
System/MakeSystem.HC Normal file
View File

@@ -0,0 +1,56 @@
/* clang-format off */
#include "Setup/Util";
//#include "Setup/MAlloc";
#include "Setup/Environment";
// FFI support files
#include "FFI/Base";
#include "FFI/LibC";
#include "FFI/New";
#include "FFI/ELF64";
// stb_image library
#include "Utilities/Image";
load_elf("M:/build/bin/image");
// Jakt support files
#include "Jakt/OS";
#include "Jakt/IOPort";
#include "Jakt/PCI";
#include "Jakt/Time";
// Networking APIs
#include "Api/Dns.HC";
#include "Api/Icmp.HC";
#include "Api/Ipv4.HC";
#include "Api/MD5.HC";
#include "Api/NetInfo.HC";
#include "Api/Tcp.HC";
//#include "Api/Tls.HC";
#include "Libraries/Json";
#include "Libraries/String";
load_elf("M:/build/bin/net");
// Networking Utilities
#include "Utilities/Dns";
#include "Utilities/NetRep";
#include "Utilities/Ping";
//#include "Utilities/Time";
Spawn(_start, , "Net Task", NET_TASK_CPU);
#include "9P/Debug";
#include "9P/Defs";
#include "9P/Draw";
#include "9P/Requests";
#include "NeinTerm";
//#include "NeinTask";
//TimeSync;
/* clang-format on */

View File

@@ -0,0 +1,23 @@
#define NET_TASK_CPU 3
// Before continuing, we:
// 1. Mark memory in code heap below 0x1000000 as used.
sys_code_bp->mem_free_lst->next->pags = 0;
// 2. Free up 64MB at bottom of code heap for non-HolyC programs
sys_code_bp->mem_free_lst = ShrinkMemBlkByPags(sys_code_bp->mem_free_lst, 131072);
U0 NoBeep(I8, Bool) {};
@patch_jmp_rel32(&Beep, &NoBeep); // Don't delay on beep when entering debugger
//@patch_jmp_rel32(&Fault2, &Reboot); // Reboot instead of crashing to the debugger
// 4. Disable exclusive access to BlkDev and Drv
Bool FakeLock(U64)
{
return TRUE;
}
@patch_jmp_rel32(&BlkDevLock, &FakeLock);
@patch_jmp_rel32(&DrvLock, &FakeLock);

180
System/Setup/Util.HC Normal file
View File

@@ -0,0 +1,180 @@
AutoComplete(0);
U0 @sse_enable()
{
/* clang-format off */
asm
{
MOV_EAX_CR0
AND AX, 0xFFFB // clear coprocessor emulation CR0.EM
OR AX, 0x2 // set coprocessor monitoring CR0.MP
MOV_CR0_EAX
MOV_EAX_CR4
OR AX, 3 << 9 // set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
MOV_CR4_EAX
}
/* clang-format on */
}
U0 @sse_enable_on_all_cores()
{
I64 i;
for (i = 1; i < mp_cnt; i++)
Spawn(&@sse_enable, , , i);
}
// Enable SSE
@sse_enable;
@sse_enable_on_all_cores;
U0 @patch_call_rel32(U32 from, U32 to)
{
*(from(U8*)) = 0xE8;
*((from + 1)(I32*)) = to - from - 5;
}
U0 @patch_jmp_rel32(U32 from, U32 to)
{
*(from(U8*)) = 0xE9;
*((from + 1)(I32*)) = to - from - 5;
}
I64 tos_nist_offset = 5603; // UTC -4
#define NIST_TIME_OFFSET (tos_nist_offset - local_time_offset / CDATE_FREQ)
public
I64 CDate2Unix(CDate dt)
{ // TempleOS datetime to Unix timestamp.
return ToI64((dt - Str2Date("1/1/1970")) / CDATE_FREQ + NIST_TIME_OFFSET);
}
public
CDate Unix2CDate(I64 timestamp)
{ // Unix timestamp to TempleOS datetime.
return (timestamp - NIST_TIME_OFFSET) * CDATE_FREQ + Str2Date("1/1/1970");
}
// FIXME: Put these in a "Builtin" library?
U0 FifoU8Cpy(CFifoU8* f, U8* s)
{
if (!f || !s)
return;
while (*s)
FifoU8Ins(f, *s++);
}
Bool KeyDown(I64 sc) return Bt(kbd.down_bitmap, sc);
I64 T(Bool _condition, I64 _true, I64 _false)
{
if (_condition)
return _true;
return _false;
}
asm
{
_MEMCPY_U16::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
CLD
MOV RDI,U64 SF_ARG1[RBP]
MOV RSI,U64 SF_ARG2[RBP]
MOV RCX,U64 SF_ARG3[RBP]
REP_MOVSW
MOV RAX,RDI
POP RDI
POP RSI
POP RBP
RET1 24
_MEMCPY_U32::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
CLD
MOV RDI,U64 SF_ARG1[RBP]
MOV RSI,U64 SF_ARG2[RBP]
MOV RCX,U64 SF_ARG3[RBP]
REP_MOVSD
MOV RAX,RDI
POP RDI
POP RSI
POP RBP
RET1 24
_MEMCPY_U64::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
CLD
MOV RDI,U64 SF_ARG1[RBP]
MOV RSI,U64 SF_ARG2[RBP]
MOV RCX,U64 SF_ARG3[RBP]
REP_MOVSQ
MOV RAX,RDI
POP RDI
POP RSI
POP RBP
RET1 24
}
public _extern _MEMCPY_U16 U16* MemCpyU16(U16* dst, U16* src, I64 cnt);
public
_extern _MEMCPY_U32 U32* MemCpyU32(U32* dst, U32* src, I64 cnt);
public
_extern _MEMCPY_U64 U64* MemCpyU64(U64* dst, U64* src, I64 cnt);
I64 @lerp(U32 val, U32 mx1, U32 mx2)
{
F64 r = (val & mx1) / ToF64(mx1);
return ToI64(r * mx2);
}
CMemBlk* ShrinkMemBlkByPags(CMemBlk* from, I64 count)
{
from->pags -= count;
U64 to = from;
to += count * MEM_PAG_SIZE;
MemCpy(to, from, MEM_PAG_SIZE);
return to;
}
I64 @t(Bool _condition, I64 _true, I64 _false)
{
if (_condition)
return _true;
return _false;
}
U0 dd() { DocDump(adam_task->put_doc); }
Bool FifoU8Last(CFifoU8* f, U8* _b)
{ // Peek at back of fifo and don't remove.
PUSHFD
CLI if (f->in_ptr == f->out_ptr)
{
POPFD
return FALSE;
}
else
{
I64 last_ptr = f->in_ptr - 1;
if (last_ptr < 0)
last_ptr = FifoU8Cnt(f) - 1;
*_b = f->buf[last_ptr];
POPFD
return TRUE;
}
}
U8 reverse_bits(U8 n)
{
// Swap nibbles
n = ((n >> 4) & 0x0F) | ((n & 0x0F) << 4);
// Swap adjacent pairs
n = ((n >> 2) & 0x33) | ((n & 0x33) << 2);
// Swap adjacent bits
n = ((n >> 1) & 0x55) | ((n & 0x55) << 1);
return n;
}

10
System/Utilities/Dns.HC Normal file
View File

@@ -0,0 +1,10 @@
U0 DnsQuery(U8* host)
{
U32 result = @dns_query(host);
if (result == U32_MAX) {
"Error looking up host %s\n", host;
return;
}
"Query for %s: %d.%d.%d.%d\n", host, result.u8[3], result.u8[2], result.u8[1],
result.u8[0];
}

414
System/Utilities/Image.HC Normal file
View File

@@ -0,0 +1,414 @@
Silent(1); // This is needed to suppress "Function should return val" warnings for wrappers to non-HolyC functions
// class @image
// {
// CDC* (*FromBuffer)(U8* buffer, I64 len);
// CDC* (*Load)(U8* filename);
// CDC* (*Write)(U8* filename, CDC* dc);
// };
//
// @image Image;
class @image_frame
{
CDC* dc;
CSprite* sprite;
I64 delay;
};
class @image_collection
{
@image_frame** frames;
I64 count;
I64 current;
I64 jiffies;
I64 index;
@image_collection* next;
};
I64 @image_cbgr24_to_4_bit(CBGR24* ptr, Bool dither_probability)
{
I64 res, k;
if (dither_probability) {
k = RandU32;
if (SqrI64(ptr->r) + SqrI64(ptr->g) + SqrI64(ptr->b) >= 3 * SqrI64(k.u8[0]))
res = 8;
else
res = 0;
if (ptr->r >= k.u8[1])
res |= RED;
if (ptr->g >= k.u8[2])
res |= GREEN;
if (ptr->b >= k.u8[3])
res |= BLUE;
} else {
if (SqrI64(ptr->r) + SqrI64(ptr->g) + SqrI64(ptr->b) >= SqrI64(0x80)) {
res = 8;
if (ptr->r >= 0x80)
res |= RED;
if (ptr->g >= 0x80)
res |= GREEN;
if (ptr->b >= 0x80)
res |= BLUE;
} else {
res = 0;
if (ptr->r >= 0x40)
res |= RED;
if (ptr->g >= 0x40)
res |= GREEN;
if (ptr->b >= 0x40)
res |= BLUE;
}
}
return res;
}
#define IMAGE_DITHER_NONE 0
#define IMAGE_DITHER_NATIVE 1
#define IMAGE_DITHER_FLOYDSTEINBERG 2
U0 @image_render_4bit_floydstein(U8* buffer, I32 width, I32 height)
{
U64 reg RDI rdi = buffer;
U64 reg RSI rsi = width;
U64 reg RDX rdx = height;
no_warn rdi, rsi, rdx;
asm {
MOV RAX, RENDER_4BIT_FLOYDSTEIN
CALL RAX
}
}
CDC* @image_render_16color_native(U8* pixels, I32 x, I32 y, Bool dither)
{
I64 i;
I64 j;
I64 cnt = 0;
CBGR24 cbgr24;
CDC* dc = DCNew(x, y);
for (i = 0; i < y; i++)
for (j = 0; j < x; j++) {
cbgr24.r = pixels[cnt];
cbgr24.g = pixels[cnt + 1];
cbgr24.b = pixels[cnt + 2];
if (!pixels[cnt + 3])
dc->color = TRANSPARENT;
else
dc->color = @image_cbgr24_to_4_bit(&cbgr24, dither);
GrPlot(dc, j, y - i - 1);
cnt += 4;
}
return dc;
}
CBGR24 @image_palette_std[COLORS_NUM] = {
0x000000, 0x0000AA, 0x00AA00, 0x00AAAA,
0xAA0000, 0xAA00AA, 0xAA5500, 0xAAAAAA,
0x555555, 0x5555FF, 0x55FF55, 0x55FFFF,
0xFF5555, 0xFF55FF, 0xFFFF55, 0xFFFFFF
};
CBGR24 @image_dif_rgb(CBGR24 from, CBGR24 to)
{
CBGR24 dif;
dif.r = to.r - from.r;
dif.g = to.g - from.g;
dif.b = to.b - from.b;
return dif;
}
F64 @image_dist_rgb(CBGR24 from, CBGR24 to)
{
CBGR24 dif = @image_dif_rgb(from, to);
F64 dist = dif.r * dif.r + dif.g * dif.g + dif.b * dif.b;
return dist;
}
I64 @image_get_4bit_color(CBGR24* cbgr24)
{
F64 dist = -1, tempDist;
I64 i;
I64 color = TRANSPARENT;
for (i = 0; i < COLORS_NUM; i++) {
tempDist = @image_dist_rgb(*cbgr24, @image_palette_std[i]);
if (tempDist < dist || dist < 0) {
dist = tempDist;
color = i;
}
}
return color;
}
CDC* @image_render_16color_floydsteinberg(U8* pixels, I32 width, I32 height)
{
@image_render_4bit_floydstein(pixels, width, height);
I64 i;
I64 j;
I64 cnt = 0;
CBGR24 cbgr24;
CDC* dc = DCNew(width, height);
for (i = 0; i < height; i++)
for (j = 0; j < width; j++) {
cbgr24.r = pixels[cnt];
cbgr24.g = pixels[cnt + 1];
cbgr24.b = pixels[cnt + 2];
if (!pixels[cnt + 3])
dc->color = TRANSPARENT;
else
dc->color = @image_get_4bit_color(&cbgr24);
GrPlot(dc, j, height - i - 1);
cnt += 4;
}
return dc;
}
CDC* @image_generate_dc_from_pixels(U8* pixels, I32 width, I32 height, Bool dither = IMAGE_DITHER_FLOYDSTEINBERG)
{
switch (dither) {
case IMAGE_DITHER_NONE:
case IMAGE_DITHER_NATIVE:
return @image_render_16color_native(pixels, width, height, dither);
break;
case IMAGE_DITHER_FLOYDSTEINBERG:
return @image_render_16color_floydsteinberg(pixels, width, height);
break;
default:
break;
}
return NULL;
}
U8* @image_load_gif_from_memory(U8* buffer, I64 len, I64** delays, I64* x, I64* y,
I64* z)
{
U64 reg RDI rdi = buffer;
U64 reg RSI rsi = len;
U64 reg RDX rdx = delays;
U64 reg RCX rcx = x;
U64 reg R8 r8 = y;
U64 reg R9 r9 = z;
no_warn rdi, rsi, rdx, rcx, r8, r9;
asm {
MOV RAX, IMAGE_LOAD_GIF_FROM_MEMORY
CALL RAX
}
}
U8* @stbi_failure_reason()
{
asm {
MOV RAX, STBI_FAILURE_REASON
CALL RAX
}
}
I32 @stbi_info_from_memory(U8* buffer, I64 len, I64* x, I64* y, I64* comp)
{
U64 reg RDI rdi = buffer;
U64 reg RSI rsi = len;
U64 reg RDX rdx = x;
U64 reg RCX rcx = y;
U64 reg R8 r8 = comp;
no_warn rdi, rsi, rdx, rcx, r8;
asm {
MOV RAX, STBI_INFO_FROM_MEMORY
CALL RAX
}
}
U8* @stbi_load_from_memory(U8* buffer, I64 len, I64* x, I64* y,
I64* channels_in_file, I64 desired_channels)
{
U64 reg RDI rdi = buffer;
U64 reg RSI rsi = len;
U64 reg RDX rdx = x;
U64 reg RCX rcx = y;
U64 reg R8 r8 = channels_in_file;
U64 reg R9 r9 = desired_channels;
no_warn rdi, rsi, rdx, rcx, r8, r9;
asm {
MOV RAX, STBI_LOAD_FROM_MEMORY
CALL RAX
}
}
U32* @stbi_write_png_to_mem(U32* pixels, I32 stride_bytes, I32 x, I32 y, I32 n, I32* out_len)
{
U64 reg RDI rdi = pixels;
U64 reg RSI rsi = stride_bytes;
U64 reg RDX rdx = x;
U64 reg RCX rcx = y;
U64 reg R8 r8 = n;
U64 reg R9 r9 = out_len;
no_warn rdi, rsi, rdx, rcx, r8, r9;
asm {
MOV RAX, STBI_WRITE_PNG_TO_MEM
CALL RAX
}
}
CDC* @image_load(U8* filename)
{
if (!filename || !FileFind(filename)) {
// PrintErr("Image file not found.\n");
return NULL;
}
I64 len;
I32 x;
I32 y;
I32 comp;
U8* buffer = FileRead(filename, &len);
I32 code = @stbi_info_from_memory(buffer, len, &x, &y, &comp);
if (code != 1) {
Free(buffer);
return NULL;
}
U8* pixels = @stbi_load_from_memory(buffer, len, &x, &y, &comp, 4);
Free(buffer);
CDC* dc = @image_generate_dc_from_pixels(pixels, x, y);
Free(pixels);
return dc;
}
U32 @image_rgba_color_table[16] = {
0xff000000, 0xffaa0000, 0xff00aa00, 0xffaaaa00,
0xff0000aa, 0xffaa00aa, 0xff0055aa, 0xffaaaaaa,
0xff555555, 0xffff5555, 0xff55ff55, 0xffffff55,
0xff5555ff, 0xffff55ff, 0xff55ffff, 0xffffffff
};
U32 @image_get_rgba_color(I64 color)
{
if (color > 15)
return 0;
return @image_rgba_color_table[color];
}
U32* @image_get_rgba_buffer_from_dc_body(CDC* dc)
{
if (!dc)
return NULL;
U32* pixels = CAlloc((dc->width * dc->height) * 4, adam_task);
I64 x;
I64 y;
I64 p = 0;
for (y = 0; y < dc->height; y++)
for (x = 0; x < dc->width; x++)
pixels[p++] = @image_get_rgba_color(GrPeek(dc, x, y));
return pixels;
}
U0 @image_write(U8* filename, CDC* dc)
{
if (!dc) {
PrintErr("Device context is NULL.\n");
return;
}
I32 out_len;
U32* rgba_buffer = @image_get_rgba_buffer_from_dc_body(dc);
if (!rgba_buffer) {
PrintErr("RGBA buffer is NULL.\n");
return;
}
U8* png_buffer = @stbi_write_png_to_mem(rgba_buffer, dc->width * 4, dc->width, dc->height, 4, &out_len);
if (!png_buffer) {
PrintErr("PNG buffer is NULL.\n");
Free(rgba_buffer);
return;
}
FileWrite(filename, png_buffer, out_len);
Free(rgba_buffer);
Free(png_buffer);
}
U32 @image_pixel_flip_rgb_bgr(U32 src)
{
U32 dst;
dst.u8[0] = src.u8[2];
dst.u8[1] = src.u8[1];
dst.u8[2] = src.u8[0];
dst.u8[3] = src.u8[3];
return dst;
}
CDC* @image_from_buffer(U8* buffer, I64 len)
{
I32 x = 0;
I32 y = 0;
U8* pixels = NULL;
CDC* dc = NULL;
I32 comp;
I32 code = @stbi_info_from_memory(buffer, len, &x, &y, &comp);
if (code != 1) {
return NULL;
}
pixels = @stbi_load_from_memory(buffer, len, &x, &y, &comp, 4);
if (!pixels)
PopUpOk(@stbi_failure_reason);
dc = @image_generate_dc_from_pixels(pixels, x, y);
Free(pixels);
return dc;
}
@image_collection* @image_collection_from_buffer(U8* buffer, I64 len)
{
I64 i;
I32* delays;
I32 x;
I32 y;
I32 z;
I32 comp;
I32 code = @stbi_info_from_memory(buffer, len, &x, &y, &comp);
if (code != 1) {
return NULL;
}
U64 pixels = @image_load_gif_from_memory(buffer, len, &delays, &x, &y, &z);
if (!pixels)
PopUpOk(@stbi_failure_reason);
if (!z)
return NULL; // no frames?
@image_collection* collection = CAlloc(sizeof(@image_collection), adam_task);
@image_frame* frame;
collection->frames = CAlloc(sizeof(@image_frame*) * z, adam_task);
collection->count = z;
for (i = 0; i < z; i++) {
frame = CAlloc(sizeof(@image_frame), adam_task);
frame->dc = @image_generate_dc_from_pixels(pixels, x, y);
frame->sprite = DC2Sprite(frame->dc);
frame->delay = delays[i];
collection->frames[i] = frame;
pixels += (x * y) * 4;
}
return collection;
}
// Image.FromBuffer = &@image_from_buffer;
// Image.Load = &@image_load;
// Image.Write = &@image_write;
Silent(0);
U0 Screenshot(U8* custom_filename = NULL, Bool output_filename_to_focus_task = FALSE)
{
CDC* dc = DCScrnCapture;
U8 filename[256];
CDateStruct ds;
if (custom_filename)
StrCpy(filename, custom_filename);
else {
Date2Struct(&ds, Now);
StrPrint(filename, "C:/Tmp/ScrnShots/%04d-%02d-%02d-%02d-%02d-%02d.png", ds.year, ds.mon, ds.day_of_mon, ds.hour, ds.min, ds.sec);
}
@image_write(filename, dc);
DCDel(dc);
if (output_filename_to_focus_task)
XTalk(sys_focus_task, filename);
};
U0 @screenshot_hotkey(I64)
{
Screenshot("C:/Home/Screenshot.png", TRUE);
}
CtrlAltCBSet('S', &@screenshot_hotkey, "", , FALSE);

View File

@@ -0,0 +1,22 @@
U0 NetRep()
{
NetInfoRequest* req = @net_info_request;
"MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n", req->mac_address.u8[5], req->mac_address.u8[4],
req->mac_address.u8[3], req->mac_address.u8[2],
req->mac_address.u8[1], req->mac_address.u8[0];
"IPv4 address : %d.%d.%d.%d\n", req->ipv4_address.u8[3], req->ipv4_address.u8[2],
req->ipv4_address.u8[1], req->ipv4_address.u8[0];
"IPv4 netmask : %d.%d.%d.%d\n", req->ipv4_netmask.u8[3], req->ipv4_netmask.u8[2],
req->ipv4_netmask.u8[1], req->ipv4_netmask.u8[0];
"IPv4 network : %d.%d.%d.%d\n", req->ipv4_network.u8[3], req->ipv4_network.u8[2],
req->ipv4_network.u8[1], req->ipv4_network.u8[0];
"IPv4 gateway : %d.%d.%d.%d\n", req->ipv4_gateway.u8[3], req->ipv4_gateway.u8[2],
req->ipv4_gateway.u8[1], req->ipv4_gateway.u8[0];
"DNS server (port) : %d.%d.%d.%d (%d)\n", req->dns_server_address.u8[3], req->dns_server_address.u8[2],
req->dns_server_address.u8[1], req->dns_server_address.u8[0], req->dns_server_port;
"RX bytes : %d\n", req->rx_bytes;
"RX frames : %d\n", req->rx_frames;
"TX bytes : %d\n", req->tx_bytes;
"TX frames : %d\n", req->tx_frames;
Free(req);
}

72
System/Utilities/Ping.HC Normal file
View File

@@ -0,0 +1,72 @@
#define PING_ERR_INVALID_HOST 1
#define PING_ERR_HOST_NOT_FOUND 2
#define PING_PAYLOAD_SIZE 56
I64 @ping_err(I64 code)
{
switch (code) {
case PING_ERR_INVALID_HOST:
"Invalid host specified\n";
return 1;
break;
case PING_ERR_HOST_NOT_FOUND:
"Host not found\n";
return 2;
break;
default:
"Unspecified error\n";
return -1;
}
}
I64 Ping(U8* host, I64 count = 4)
{
if (!host)
return @ping_err(PING_ERR_INVALID_HOST);
if (!StrLen(host))
return @ping_err(PING_ERR_INVALID_HOST);
U32 addr = @dns_query(host);
if (addr == U32_MAX)
return @ping_err(PING_ERR_HOST_NOT_FOUND);
U16 iden = (RandU16 * SysTimerRead) & 0xFFFF;
I64 start_jiffies;
U32 reply = NULL;
I64 res = 0;
U16 seq = 0;
I64 loss = 0;
IcmpRequest* request = CAlloc(sizeof(IcmpRequest), Fs->code_heap);
"PING %s (%d.%d.%d.%d): %d data bytes\n",
host, addr.u8[3], addr.u8[2], addr.u8[1], addr.u8[0], PING_PAYLOAD_SIZE;
I64 i;
for (i = 0; i < count; i++) {
start_jiffies = cnts.jiffies;
reply = @icmp_echo_request(addr, iden, seq, request, i);
if (!reply) {
"Request timeout for icmp_seq %d\n", seq;
++loss;
res = 1;
} else {
"%d bytes from %d.%d.%d.%d: icmp_seq=%d ttl=%d time=%d ms\n",
reply.u16[1], addr.u8[3], addr.u8[2], addr.u8[1], addr.u8[0], seq, reply.u16[0], cnts.jiffies - start_jiffies;
}
while (cnts.jiffies < start_jiffies + 1000 && i < (count - 1))
Sleep(1);
++seq;
}
Free(request);
"--- %d.%d.%d.%d ping statistics ---\n", addr.u8[3], addr.u8[2], addr.u8[1], addr.u8[0];
"%d packets transmitted, %d packets received, %0f",
seq, seq - loss, (loss * 1.0 / seq * 1.0) * 100;
PutChars(37);
" packet loss\n";
return res;
}

92
System/Utilities/Time.HC Normal file
View File

@@ -0,0 +1,92 @@
U0 @time_cmos_update_byte(I64 time_reg, I64 val)
{
OutU8(0x70, time_reg);
OutU8(0x71, val);
}
I64 @time_dec_to_bcd(I64 val)
{
return (((val / 10) << 4) | (val % 10));
}
U0 @time_update(U8* date_str, I64 mS_delta, I64 hour_offset)
{
no_warn mS_delta;
Bool is_bcd;
OutU8(0x70, 0x0B);
if (InU8(0x71) & 4)
is_bcd = FALSE;
else
is_bcd = TRUE;
I64 date_argc;
U8** date_argv = String.Split(date_str, ' ', &date_argc);
I64 month = DefineMatch(date_argv[2], "ST_MONTHS") + 1;
I64 day = Str2I64(date_argv[1]);
I64 year = Str2I64(date_argv[3] + 2);
I64 century = 20;
date_argv[4][2] = NULL;
date_argv[4][5] = NULL;
I64 hour = Str2I64(date_argv[4]);
I64 minute = Str2I64(date_argv[4] + 3);
I64 second = Str2I64(date_argv[4] + 6);
// FIXME: Handle month boundaries, and 12 hour time
hour += hour_offset;
if (hour < 0) {
hour += 24;
--day;
} else if (hour > 23) {
hour -= 24;
++day;
}
if (is_bcd) {
century = @time_dec_to_bcd(century);
year = @time_dec_to_bcd(year);
month = @time_dec_to_bcd(month);
day = @time_dec_to_bcd(day);
hour = @time_dec_to_bcd(hour);
minute = @time_dec_to_bcd(minute);
second = @time_dec_to_bcd(second);
}
@time_cmos_update_byte(0x32, century);
@time_cmos_update_byte(0x09, year);
@time_cmos_update_byte(0x08, month);
@time_cmos_update_byte(0x07, day);
@time_cmos_update_byte(0x04, hour);
@time_cmos_update_byte(0x02, minute);
@time_cmos_update_byte(0x00, second);
}
I64 @time_tz_offset()
{
return -4;
}
U0 @time_query(Bool set = FALSE)
{
U8 buf[1024];
@http_url* url = @http_parse_url("http://time.google.com");
@http_response* resp = Http.Head(url, &buf);
while (resp->state != HTTP_STATE_DONE)
Sleep(1);
I64 mS_delta = cnts.jiffies;
"Set current date and time to %s ", resp->headers->@("Date");
if (!set)
set = YorN;
else
"\n";
if (set)
@time_update(resp->headers->@("Date"), mS_delta, @time_tz_offset);
}
U0 TimeSync()
{
Sleep(500);
@time_query(1);
}

View File

@@ -0,0 +1,80 @@
Silent(1); // This is needed to suppress "Function should return val" warnings for wrappers to non-HolyC functions
class stbtt__buf {
U8* data;
I32 cursor;
I32 size;
};
class stbtt_fontinfo {
U8* userdata;
U8* data; // pointer to .ttf file
I32 fontstart; // offset of start of font
I32 numGlyphs; // number of glyphs, needed for range checking
I32 loca, head, glyf, hhea, hmtx, kern, gpos, svg; // table locations as offset from start of .ttf
I32 index_map; // a cmap mapping for our chosen character encoding
I32 indexToLocFormat; // format needed to map from glyph index to glyph
stbtt__buf cff; // cff font data
stbtt__buf charstrings; // the charstring index
stbtt__buf gsubrs; // global charstring subroutines index
stbtt__buf subrs; // private charstring subroutines index
stbtt__buf fontdicts; // array of font dicts
stbtt__buf fdselect; // map from glyph to fontdict
};
I32 @stbtt_InitFont(stbtt_fontinfo* info, U8* data, I32 offset)
{
U64 reg RDI rdi = info;
U64 reg RSI rsi = data;
U64 reg RDX rdx = offset;
no_warn rdi, rsi, rdx;
asm {
MOV RAX, STBTT_INITFONT
CALL RAX
}
}
U8* @stbtt_RenderText(stbtt_fontinfo* info, I32 b_w, I32 b_h, I32 l_h, I32* word, I32* advance = NULL)
{
U64 reg RDI rdi = info;
U64 reg RSI rsi = b_w;
U64 reg RDX rdx = b_h;
U64 reg RCX rcx = l_h;
U64 reg R8 r8 = word;
U64 reg R9 r9 = advance;
no_warn rdi, rsi, rdx, rcx, r8, r9;
stbtt_pos = 0;
asm {
MOV RAX, STBTT_RENDERTEXT
CALL RAX
}
}
I32 @stbtt_GetTextWidth(stbtt_fontinfo* info, I32 l_h, I32* word, I32* advance = NULL)
{
U64 reg RDI rdi = info;
U64 reg RSI rsi = l_h;
U64 reg RDX rdx = word;
U64 reg RCX rcx = advance;
no_warn rdi, rsi, rdx, rcx;
asm {
MOV RAX, STBTT_GETTEXTWIDTH
CALL RAX
}
}
U8* @stbtt_GetFontNameDefault(stbtt_fontinfo* font, I32* length)
{
U64 reg RDI rdi = font;
U64 reg RSI rsi = length;
no_warn rdi, rsi;
asm {
MOV RAX, STBTT_GETFONTNAMEDEFAULT
CALL RAX
}
}
Silent(0);
"truetype ";

9
script.rc Normal file
View File

@@ -0,0 +1,9 @@
mount -nc /fd/0 /mnt/term || exit
bind -q /mnt/term/dev/cons /dev/cons
if(test -r /mnt/term/dev/kbd){
</dev/cons >/dev/cons >[2=1] aux/kbdfs -dq -m /mnt/term/dev
bind -q /mnt/term/dev/cons /dev/cons
}
</dev/cons >/dev/cons >[2=1] service=neinterm rc -li
echo -n $status >/mnt/term/env/rstatus >[2]/dev/null"
echo -n hangup >/proc/$pid/notepg

207
scripts/build-all Executable file
View File

@@ -0,0 +1,207 @@
#!/usr/bin/python3 -u
from pathlib import Path
import glob
import json
import os
import subprocess
import sys
import time
if len(sys.argv) < 2:
raise ValueError('wrong number of arguments')
home_path = str(Path.home()) + '/'
project_path = sys.argv[1] + '/'
project_name = project_path.rsplit('/')[-2]
build_options_file = project_path + 'build_options.json'
try:
build_options = json.loads(open(build_options_file, "rb").read())
except:
build_options = {}
# Default settings
default_settings = {
'isoc_file': project_path + 'build/isoc/NeinTerm.ISO.C',
'redsea_path': project_path + 'build/redsea',
'jakt_compiler_path': home_path + 'cloned/jakt/build/bin/jakt',
'jakt_runtime_path': home_path + 'cloned/jakt/runtime',
'jakt_lib_path': home_path + 'cloned/jakt/build/lib/x86_64-unknown-linux-unknown/',
'qemu_bin_path': 'qemu-system-x86_64',
'qemu_slipstream_iso_file': project_path + 'build/isoc/bootable.iso',
'templeos_iso_file': home_path + 'iso/TempleOS.ISO'
}
isoc_file = build_options['isoc_file'] if 'isoc_file' in build_options else default_settings['isoc_file']
redsea_path = build_options['redsea_path'] if 'redsea_path' in build_options else default_settings['redsea_path']
jakt_compiler_path = build_options['jakt_compiler_path'] if 'jakt_compiler_path' in build_options else default_settings['jakt_compiler_path']
jakt_runtime_path = build_options['jakt_runtime_path'] if 'jakt_runtime_path' in build_options else default_settings['jakt_runtime_path']
jakt_lib_path = build_options['jakt_lib_path'] if 'jakt_lib_path' in build_options else default_settings['jakt_lib_path']
qemu_bin_path = build_options['qemu_bin_path'] if 'qemu_bin_path' in build_options else default_settings['qemu_bin_path']
qemu_slipstream_iso_file = build_options['qemu_slipstream_iso_file'] if 'qemu_slipstream_iso_file' in build_options else default_settings['qemu_slipstream_iso_file']
templeos_iso_file = build_options['templeos_iso_file'] if 'templeos_iso_file' in build_options else default_settings['templeos_iso_file']
qemu_args = build_options['qemu_args'] if 'qemu_args' in build_options else [
'-display sdl,grab-mod=rctrl',
'-enable-kvm',
'-machine vmport=on',
'-smp cores=4',
'-m 4096',
'-netdev tap,id=mynet0,ifname=tap0,script=no,downscript=no',
'-device ac97',
'-device virtio-net,netdev=mynet0',
'-device vmware-svga',
'-cdrom ' + qemu_slipstream_iso_file,
'-debugcon stdio',
'-boot d'
]
qemu_run_cmd = ' '.join([qemu_bin_path] + qemu_args)
def build_options_bool(key):
if key not in build_options:
return False
return build_options[key] == True
def clang_format_src_files():
print("build-all: clang-format-src-files")
exclude_paths = ["stb_", "openlibm", "tlse", ".iso.c"]
format_file_extensions = [".c", ".cpp", ".h", ".hc"]
for src_file in glob.glob(project_path + "**", recursive=True):
exclude_file = False
for exclude_path in exclude_paths:
if src_file.lower().find(exclude_path) > 0:
exclude_file = True
if exclude_file:
continue
for format_file_extension in format_file_extensions:
if src_file.lower().endswith(format_file_extension):
print(src_file)
res = os.system('clang-format -i --style=file:' + project_path + '.clang-format ' + src_file)
if res:
raise ValueError("build-all: step 'clang-format-src-files' failed, error code " + str(res))
def refresh_build_path():
print("build-all: refresh-build-path")
res = os.system('rm -rf ' + project_path + 'build && mkdir -p ' + project_path + 'build/bin && mkdir -p ' + project_path + 'build/isoc && mkdir -p ' + project_path + 'build/lib && mkdir -p ' + project_path + 'build/redsea')
if res:
raise ValueError("build-all: step 'refresh-build-path' failed, error code " + str(res))
def build_image():
print("build-all: build-image")
build_specific_options = '-Wl,--section-start=.text=0x1004000 -Wl,--section-start=.plt=0x1002020 -no-pie'
res = os.system('cd ' + project_path + '&& cd src/image && gcc -o ../../build/bin/image ' + build_specific_options + ' -O0 -mno-mmx -mno-red-zone image.c')
if res:
raise ValueError("build-all: step 'build-image' failed, error code " + str(res))
def build_libtemple():
print("build-all: build-libtemple")
res = os.system('cd ' + project_path + 'src/libtemple && g++ -c -o ../../build/libtemple.o libtemple.cpp && gcc -shared -o ../../build/lib/libtemple.so ../../build/libtemple.o && rm ' + project_path + 'build/libtemple.o')
if res:
raise ValueError("build-all: step 'build-libtemple' failed, error code " + str(res))
def transpile_net_to_sepples():
print("build-all: transpile-net-to-sepples")
res = os.system('cd ' + project_path + 'src/net && ' + jakt_compiler_path + ' -S -R ' + jakt_runtime_path + ' -B ' + project_path + 'build/net -O net.jakt')
if res:
raise ValueError("build-all: step 'transpile-net-to-sepples' failed, error code " + str(res))
def build_net():
print("build-all: build-net")
build_specific_options = '-Wno-invalid-offsetof -Wl,--section-start=.text=0x1404000 -Wl,--section-start=.plt=0x1402020 -no-pie'
res = os.system('cd ' + project_path + 'build/net && clang++-20 ' + build_specific_options + ' -O3 -I ' + jakt_runtime_path + ' -I ' + project_path + '/src/libtemple -fcolor-diagnostics -std=c++20 -fno-exceptions -Wno-user-defined-literals -Wno-deprecated-declarations -Wno-parentheses-equality -Wno-unqualified-std-cast-call -Wno-unknown-warning-option -Wno-int-to-pointer-cast -mno-red-zone -o ../bin/net *.cpp ../lib/libtemple.so ' + jakt_lib_path + 'libjakt_runtime_x86_64-unknown-linux-unknown.a ' + jakt_lib_path + 'libjakt_main_x86_64-unknown-linux-unknown.a && cd .. && rm -rf net')
if res:
raise ValueError("build-all: step 'build-net' failed, error code " + str(res))
def address_string_for_symbol(file, symbol):
p = subprocess.Popen('readelf -s --wide "' + file + '" | grep \'' + symbol + '$\' | awk \'{sub("000000000", "0x", $2); print $2}\'', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
return str(p.communicate()[0][:-1].decode(encoding='utf-8'))
def image_hc_fixup(macro, symbol, image_bin_path, image_hc_path):
os.system('echo -e "#define ' + macro + ' ' + address_string_for_symbol(image_bin_path, symbol) + '\n" | cat - ' + image_hc_path + ' | sponge ' + image_hc_path)
return
def generate_iso_c_file():
print("build-all: generate-iso-c-file")
step_error_message = "build-all: step 'generate-iso-c-file' failed, error code "
try:
os.remove(isoc_file)
except:
pass
res = os.system('isoc-mount --rw ' + isoc_file + ' ' + redsea_path)
if res:
raise ValueError(step_error_message + str(res))
time.sleep(0.25)
copy_files_cmd_line = 'rsync -av --inplace --progress ' + project_path + ' ' + redsea_path
copy_files_cmd_line += ' --exclude .clang-format'
copy_files_cmd_line += ' --exclude .git'
copy_files_cmd_line += ' --exclude .gitignore'
copy_files_cmd_line += ' --exclude .vscode'
copy_files_cmd_line += ' --exclude build/isoc'
copy_files_cmd_line += ' --exclude build/lib'
copy_files_cmd_line += ' --exclude build/redsea'
copy_files_cmd_line += ' --exclude scripts'
copy_files_cmd_line += ' --exclude src'
res = os.system(copy_files_cmd_line)
if res:
raise ValueError(step_error_message + str(res))
if 'custom_files_path' in build_options:
copy_custom_files_cmd_line = 'rsync -av --inplace --progress ' + build_options['custom_files_path'] + ' ' + redsea_path
res = os.system(copy_custom_files_cmd_line)
if res:
raise ValueError(step_error_message + str(res))
# Fixup addresses for Image.HC
image_bin_path = redsea_path + '/build/bin/image'
image_hc_path = redsea_path + '/System/Utilities/Image.HC'
image_hc_fixup('IMAGE_LOAD_GIF_FROM_MEMORY', 'image_load_gif_from_memory', image_bin_path, image_hc_path)
image_hc_fixup('STBI_WRITE_PNG_TO_MEM', 'stbi_write_png_to_mem', image_bin_path, image_hc_path)
image_hc_fixup('STBI_LOAD_FROM_MEMORY', 'stbi_load_from_memory', image_bin_path, image_hc_path)
image_hc_fixup('STBI_INFO_FROM_MEMORY', 'stbi_info_from_memory', image_bin_path, image_hc_path)
image_hc_fixup('STBI_FAILURE_REASON', 'stbi_failure_reason', image_bin_path, image_hc_path)
image_hc_fixup('RENDER_4BIT_FLOYDSTEIN', 'render_4bit_floydstein', image_bin_path, image_hc_path)
time.sleep(0.25)
res = os.system('sync && fusermount -u ' + redsea_path)
if res:
raise ValueError(step_error_message + str(res))
time.sleep(0.25)
def generate_slipstream_iso_file():
print("build-all: generate-slipstream-iso-file")
res = os.system('templeos-slipstream ' + templeos_iso_file + ' ' + isoc_file + ' ' + qemu_slipstream_iso_file)
if res:
raise ValueError("build-all: step 'generate-slipstream-iso-file' failed, error code " + str(res))
def run():
print("build-all: run")
res = os.system(qemu_run_cmd)
if res:
raise ValueError("build-all: step 'run' failed, error code " + str(res))
def build_all():
if not build_options_bool('skip_clang_format'):
clang_format_src_files()
#if not build_options_bool('skip_rebuild'):
if 2==3:
refresh_build_path()
build_image()
build_libtemple()
transpile_net_to_sepples()
build_net()
generate_iso_c_file()
generate_slipstream_iso_file()
run()
build_all()

209
src/image/image.c Normal file
View File

@@ -0,0 +1,209 @@
#define STBI_WRITE_NO_STDIO
#define STB_IMAGE_WRITE_STATIC
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_LINEAR
#define STBI_NO_STDIO
#define STBI_NO_SIMD
#define STBI_NO_HDR
#include "stb_image.h"
#include "stb_image_write.h"
int main() { return 0; }
STBIDEF stbi_uc* image_load_gif_from_memory(stbi_uc const* buffer, int len,
int** delays, int* x, int* y,
int* z)
{
int comp;
return stbi_load_gif_from_memory(buffer, len, delays, x, y, z, &comp, 4);
}
/* dither.c: MIT License
Copyright (c) 2016 jonmortiboy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
typedef struct RGB {
int r;
int g;
int b;
} RGB;
int imgw, imgh;
// Define the 4bit colour palette
int numCols = 16;
RGB cols4bit[] = {
{ 0, 0, 0 }, { 0, 0, 170 }, { 0, 170, 0 }, { 0, 170, 170 },
{ 170, 0, 0 }, { 170, 0, 170 }, { 170, 85, 0 }, { 170, 170, 170 },
{ 85, 85, 85 }, { 85, 85, 255 }, { 85, 255, 85 }, { 85, 255, 255 },
{ 255, 85, 85 }, { 255, 85, 255 }, { 255, 255, 85 }, { 255, 255, 255 }
};
RGB* cols = cols4bit;
RGB getRGB(uint32_t* pixels, int x, int y);
void setRGB(uint32_t* pixels, int x, int y, RGB rgb);
RGB difRGB(RGB from, RGB to);
RGB addRGB(RGB a, RGB b);
RGB divRGB(RGB rgb, double d);
RGB mulRGB(RGB rgb, double d);
RGB nearestRGB(RGB rgb, RGB* rgbs, int numRGBs);
double distRGB(RGB from, RGB to);
void render_4bit_floydstein(uint32_t* pixels, int width, int height);
RGB getRGB(uint32_t* pixels, int x, int y)
{
RGB rgb;
rgb.r = 0;
rgb.g = 0;
rgb.b = 0;
if (x < 0 || x >= imgw || y < 0 || y >= imgh)
return rgb;
rgb.r = (pixels[y * imgw + x] & 0xff);
rgb.g = (pixels[y * imgw + x] & 0xff00) >> 8;
rgb.b = (pixels[y * imgw + x] & 0xff0000) >> 16;
return rgb;
}
void setRGB(uint32_t* pixels, int x, int y, RGB rgb)
{
if (x < 0 || x >= imgw || y < 0 || y >= imgh)
return;
uint32_t alpha = pixels[y * imgw + x] & 0xff000000;
pixels[y * imgw + x] = alpha + (rgb.r) + (rgb.g << 8) + (rgb.b << 16);
}
RGB difRGB(RGB from, RGB to)
{
RGB dif;
dif.r = to.r - from.r;
dif.g = to.g - from.g;
dif.b = to.b - from.b;
return dif;
}
RGB addRGB(RGB a, RGB b)
{
RGB sum;
sum.r = a.r + b.r;
sum.g = a.g + b.g;
sum.b = a.b + b.b;
if (sum.r > 255)
sum.r = 255;
if (sum.r < 0)
sum.r = 0;
if (sum.g > 255)
sum.g = 255;
if (sum.g < 0)
sum.g = 0;
if (sum.b > 255)
sum.b = 255;
if (sum.b < 0)
sum.b = 0;
return sum;
}
RGB divRGB(RGB rgb, double d)
{
RGB div;
div.r = (int)((double)rgb.r / d);
div.g = (int)((double)rgb.g / d);
div.b = (int)((double)rgb.b / d);
return div;
}
RGB mulRGB(RGB rgb, double d)
{
RGB mul;
mul.r = (int)((double)rgb.r * d);
mul.g = (int)((double)rgb.g * d);
mul.b = (int)((double)rgb.b * d);
return mul;
}
double distRGB(RGB from, RGB to)
{
RGB dif = difRGB(from, to);
double dist = dif.r * dif.r + dif.g * dif.g + dif.b * dif.b;
return dist;
}
RGB nearestRGB(RGB rgb, RGB rgbs[], int numRGBs)
{
double dist = -1, tempDist;
RGB nearest;
int i;
for (i = 0; i < numRGBs; i++) {
tempDist = distRGB(rgb, rgbs[i]);
if (tempDist < dist || dist < 0) {
dist = tempDist;
nearest = rgbs[i];
}
}
return nearest;
}
void render_4bit_floydstein(uint32_t* pixels, int width, int height)
{
int i, x, y;
imgw = width;
imgh = height;
RGB rgb, nearest, rgberror;
for (i = 0; i < imgw * imgh; i++) {
rgb = getRGB(pixels, i % imgw, i / imgw);
nearest = nearestRGB(rgb, cols, numCols);
rgberror = difRGB(nearest, rgb);
rgberror = divRGB(rgberror, 16);
x = i % imgw;
y = i / imgw;
setRGB(pixels, x + 1, y,
addRGB(getRGB(pixels, x + 1, y), mulRGB(rgberror, 7)));
setRGB(pixels, x - 1, y + 1,
addRGB(getRGB(pixels, x - 1, y + 1), mulRGB(rgberror, 3)));
setRGB(pixels, x, y + 1,
addRGB(getRGB(pixels, x, y + 1), mulRGB(rgberror, 5)));
setRGB(pixels, x + 1, y + 1,
addRGB(getRGB(pixels, x + 1, y + 1), rgberror));
setRGB(pixels, i % imgw, i / imgw, nearest);
}
}

8634
src/image/stb_image.h Normal file

File diff suppressed because it is too large Load Diff

1807
src/image/stb_image_write.h Normal file

File diff suppressed because it is too large Load Diff

6
src/libtemple/ioport.h Normal file
View File

@@ -0,0 +1,6 @@
u8 ioport_read_u8(u16 address);
u16 ioport_read_u16(u16 address);
u32 ioport_read_u32(u16 address);
void ioport_write_u8(u16 address, u8 value);
void ioport_write_u16(u16 address, u16 value);
void ioport_write_u32(u16 address, u32 value);

View File

@@ -0,0 +1,81 @@
unsigned long ioport_read_u8(unsigned short address) { return 0; }
unsigned long ioport_read_u16(unsigned short address) { return 0; }
unsigned long ioport_read_u32(unsigned short address) { return 0; }
void ioport_write_u8(unsigned short address, unsigned char value) { }
void ioport_write_u16(unsigned short address, unsigned short value) { }
void ioport_write_u32(unsigned short address, unsigned int value) { }
bool os_blink(char const* frequency_as_string) { return 0; }
unsigned long os_call(unsigned long function_name, unsigned long arg) { return 0; }
unsigned int os_device_calloc(unsigned int size) { return 0; }
void os_exit() { }
char const* os_file_picker(char const* path, char const* glob) { return 0; }
char const* os_files_list(char const* path) { return 0; }
bool os_is_vm() { return 0; }
bool os_path_exists(char const* path) { return 0; }
void os_pc_speaker(char const* frequency_as_string) { }
unsigned long os_random() { return 0; }
unsigned long os_read_entire_file(char const* filename, long* size)
{
return 0;
}
void os_screenshot() { }
char const* os_to_uppercase(char const* input_string) { return 0; }
void os_write_entire_file(char const* filename, unsigned char* buffer,
long size) { }
long pci_find(long class_code) { return 0; }
unsigned long pci_read_u8(long bus, long device, long fun, long offset)
{
return 0;
}
unsigned long pci_read_u16(long bus, long device, long fun, long offset)
{
return 0;
}
unsigned long pci_read_u32(long bus, long device, long fun, long offset)
{
return 0;
}
void pci_write_u8(long bus, long device, long fun, long offset,
unsigned char value) { }
void pci_write_u16(long bus, long device, long fun, long offset,
unsigned short value) { }
void pci_write_u32(long bus, long device, long fun, long offset,
unsigned int value) { }
void time_busy(long duration) { }
long time_jiffies() { return 0; }
long time_now() { return 0; }
void time_sleep(long duration) { }
void* truetype_malloc(int size) { return 0; }
void truetype_free(void* ptr) { }

15
src/libtemple/os.h Normal file
View File

@@ -0,0 +1,15 @@
bool os_blink(char const* frequency_as_string);
unsigned long os_call(unsigned long function_name, unsigned long arg);
unsigned int os_device_calloc(unsigned int size);
void os_exit();
char const* os_file_picker(char const* path, char const* glob);
char const* os_files_list(char const* path);
bool os_is_vm();
bool os_path_exists(char const* path);
void os_pc_speaker(char const* frequency_as_string);
unsigned long os_random();
u8* os_read_entire_file(char const* filename, i64* size);
void os_screenshot();
char const* os_to_uppercase(char const* input_string);
void os_write_entire_file(char const* filename, unsigned char* buffer,
i64 size);

10
src/libtemple/pci.h Normal file
View File

@@ -0,0 +1,10 @@
long pci_find(long class_code);
unsigned long pci_read_u8(long bus, long device, long fun, long offset);
unsigned long pci_read_u16(long bus, long device, long fun, long offset);
unsigned long pci_read_u32(long bus, long device, long fun, long offset);
void pci_write_u8(long bus, long device, long fun, long offset,
unsigned char value);
void pci_write_u16(long bus, long device, long fun, long offset,
unsigned short value);
void pci_write_u32(long bus, long device, long fun, long offset,
unsigned int value);

4
src/libtemple/time.h Normal file
View File

@@ -0,0 +1,4 @@
void time_busy(i64 duration);
i64 time_jiffies();
i64 time_now();
void time_sleep(i64 duration);

28
src/net/devices/virtio.h Normal file
View File

@@ -0,0 +1,28 @@
struct virtio_queue_buf {
u64 address;
u32 length;
u16 flags;
u16 next;
};
struct virtio_avail {
u16 flags;
u16 index;
u16 ring[256];
u16 int_index;
};
struct virtio_used_item {
u32 index;
u32 length;
};
struct virtio_used {
u16 flags;
u16 index;
virtio_used_item ring[256];
u16 int_index;
};
struct virtio_queue {
virtio_queue_buf buffers[256];
virtio_avail available;
u8 padding[3578];
virtio_used used;
};

143
src/net/devices/virtio.jakt Normal file
View File

@@ -0,0 +1,143 @@
import relative parent::os::os { OS }
import relative parent::os::pci { PCI, PCIDevice }
enum VirtIOConfig: u8 {
acknowledge = 1
driver = 2
driver_ok = 4
}
enum VirtIOReg: u16 {
host_features = 0
guest_features = 4
queue_page_frame_number = 8
queue_size = 12
queue_select = 14
queue_notify = 16
status = 18
isr = 19
config = 20
}
class VirtIO {
public pci_device: PCIDevice
public rq_index: i64
public rq_size: u16
public rq: u32
public tq_size: u16
public tq: u32
public fn rx_frame(mut this) throws -> [u8] {
mut frame: [u8] = []
mut queue_notify: bool = false
unsafe {
cpp {
"
#include <../../src/net/devices/virtio.h>
virtio_queue *rq = (virtio_queue*)this->rq;
i64 i = this->rq_index;
i64 used_index = rq->used.index;
if (used_index < i)
used_index += 0x10000;
if (used_index && i != used_index) {
virtio_used_item* item = rq->used.ring;
u8* buffer = (u8*)rq->buffers[item[i % 256].index + 1].address;
i64 length = item[i % 256].length - 10;
for (i64 j = 0; j < length; j++)
frame.push(buffer[j]);
this->rq_index = used_index % 0x10000;
rq->available.index++;
queue_notify = true;
}
"
}
}
if queue_notify {
.pci_device.io_write_u16(offset: VirtIOReg::queue_notify as! u16, value: 0)
}
return frame
}
public fn tx_frame(mut this, anon mut data: [u8]) throws {
mut size = data.size()
unsafe {
cpp {
"
#include <../../src/net/devices/virtio.h>
virtio_queue *tq = (virtio_queue*)this->tq;
int tq_idx = tq->available.index % 256;
int tq_idx2 = tq_idx % 128;
memset((u8*)tq->buffers[tq_idx2 * 2].address, 0, 10);
u8 *buffer = (u8*)tq->buffers[(tq_idx2 * 2) + 1].address;
for (int i = 0; i < size; i++)
buffer[i] = data[i];
tq->buffers[tq_idx2 * 2].length = 10;
tq->buffers[tq_idx2 * 2].flags = 1;
tq->buffers[tq_idx2 * 2].next = (tq_idx2 * 2) + 1;
tq->buffers[(tq_idx2 * 2) + 1].length = size;
tq->buffers[(tq_idx2 * 2) + 1].flags = 0;
tq->buffers[(tq_idx2 * 2) + 1].next = 0;
tq->available.ring[tq_idx] = tq_idx2 * 2;
tq->available.index++;
"
}
}
.pci_device.io_write_u16(offset: VirtIOReg::queue_notify as! u16, value: 1)
}
fn reset_device(this) {
.pci_device.io_write_u8(offset: VirtIOReg::status as! u16, value: 0)
}
fn found_driver(this) throws {
.pci_device.io_write_u8(offset: VirtIOReg::status as! u16,
value: .pci_device.io_read_u8(VirtIOReg::status as! u16) | VirtIOConfig::acknowledge as! u8 | VirtIOConfig::driver as! u8)
}
fn setup_rx_queue(mut this) throws {
.pci_device.io_write_u16(offset: VirtIOReg::queue_select as! u16, value: 0)
.rq_size = .pci_device.io_read_u16(VirtIOReg::queue_size as! u16)
.rq = OS::device_calloc(16384)
.pci_device.io_write_u32(offset: VirtIOReg::queue_page_frame_number as! u16, value: .rq / 4096)
}
fn setup_tx_queue(mut this) throws {
.pci_device.io_write_u16(offset: VirtIOReg::queue_select as! u16, value: 1)
.tq_size = .pci_device.io_read_u16(VirtIOReg::queue_size as! u16)
.tq = OS::device_calloc(16384)
.pci_device.io_write_u32(offset: VirtIOReg::queue_page_frame_number as! u16, value: .tq / 4096)
}
fn init_queue_buffers(this) {
unsafe {
cpp {
"
#include <../../src/net/devices/virtio.h>
virtio_queue *rq = (virtio_queue*)this->rq;
virtio_queue *tq = (virtio_queue*)this->tq;
for (int i = 0; i < 128; i++) {
rq->buffers[i * 2].address = (u64)calloc(1, 16);
rq->buffers[i * 2].length = 10;
rq->buffers[i * 2].flags = 3;
rq->buffers[i * 2].next = (i * 2) + 1;
rq->buffers[(i * 2) + 1].address = (u64)calloc(1, 2048);
rq->buffers[(i * 2) + 1].length = 2048;
rq->buffers[(i * 2) + 1].flags = 2;
rq->buffers[(i * 2) + 1].next = 0;
rq->available.ring[i] = i * 2;
rq->available.ring[i + 128] = i * 2;
tq->buffers[i * 2].address = (u64)calloc(1, 16);
tq->buffers[(i * 2) + 1].address = (u64)calloc(1, 2048);
}
rq->available.index = 1;
"
}
}
}
fn init_ok(this) throws {
.pci_device.io_write_u8(offset: VirtIOReg::status as! u16,
value: .pci_device.io_read_u8(VirtIOReg::status as! u16) | VirtIOConfig::driver_ok as! u8)
.pci_device.io_write_u16(offset: VirtIOReg::queue_notify as! u16, value: 0)
}
public fn init(mut this) throws {
.reset_device()
.found_driver()
.setup_rx_queue()
.setup_tx_queue()
.init_queue_buffers()
.init_ok()
}
}

350
src/net/lib/json.jakt Normal file
View File

@@ -0,0 +1,350 @@
/// Expect:
/// - output: "JsonValue::JsonArray([JsonValue::Object([\"id\": JsonValue::Number(0.5), \"displayName\": JsonValue::JsonString(\"Air\"), \"name\": JsonValue::JsonString(\"air\"), \"hardness\": JsonValue::Number(3.9), \"resistance\": JsonValue::Number(0), \"minStateId\": JsonValue::Number(0), \"maxStateId\": JsonValue::Number(0), \"states\": JsonValue::JsonArray([])])])\n"
enum JsonValue {
Null
Bool(bool)
Number(f64)
// FIXME: This variant should be called String
JsonString(String)
// FIXME: This variant should be called Array
JsonArray([JsonValue])
Object([String:JsonValue])
}
fn is_whitespace(anon c: u8) -> bool {
return match c {
b'\t' | b'\n' | b'\r' | b' ' => true
else => false
}
}
class JsonParser {
input: String
index: usize
public fn construct(input: String) throws -> JsonParser {
return JsonParser(input, index: 0)
}
fn eof(this) -> bool {
return .index >= .input.length()
}
public fn parse(mut this) throws -> JsonValue {
// FIXME: Jakt::JsonParser ignores trailing whitespace for some reason.
let value = .parse_helper()
if not .eof() {
// FIXME: "Didn't consume all input"
throw Error::from_errno(9000)
}
return value
}
fn skip_whitespace(mut this) {
while not .eof() {
if not is_whitespace(.input.byte_at(.index)) {
break
}
.index++
}
}
fn consume_and_unescape_string(mut this) throws -> String {
if not .consume_specific(b'"') {
// FIXME: "Expected '"'
throw Error::from_errno(9007)
}
mut builder = StringBuilder::create()
loop {
mut ch = 0u8
mut peek_index = .index
while peek_index < .input.length() {
ch = .input.byte_at(peek_index)
if ch == b'"' or ch == b'\\' {
break
}
// FIXME: This is is_ascii_c0_control()
if ch < 0x20 {
// FIXME: "Error while parsing string"
throw Error::from_errno(9008)
}
peek_index++
}
while peek_index != .index {
builder.append(.input.byte_at(.index))
.index++
}
if .eof() {
break
}
if ch == b'"' {
break
}
if ch != b'\\' {
builder.append(.consume())
continue
}
.ignore()
match .peek() {
b'"' | b'/' | b'\\' | b'n' | b'r' | b't' | b'b' | b'f' => {
let ch = .consume()
builder.append(match ch {
b'n' => b'\n'
b'r' => b'\r'
b't' => b'\t'
b'b' => b'\b'
b'f' => b'\f'
else => ch
})
}
b'u' => {
eprintln("FIXME: Implement unicode literals")
abort()
}
else => {
// FIXME: "Error while parsing string"
throw Error::from_errno(9009)
}
}
}
if not .consume_specific(b'"') {
// FIXME: "Expected '"'"
throw Error::from_errno(9010)
}
return builder.to_string()
}
fn ignore(mut this) {
.index++
}
fn peek(this) -> u8 {
if .eof() {
return 0
}
return .input.byte_at(.index)
}
fn consume(mut this) -> u8 {
let ch = .peek()
.index++
return ch
}
fn consume_specific(mut this, anon expected: u8) -> bool {
if .peek() != expected {
return false
}
.index++
return true
}
fn parse_helper(mut this) throws -> JsonValue {
.skip_whitespace()
return match .peek() {
b'{' => .parse_object()
b'[' => .parse_array()
b'"' => .parse_string()
b'-' => .parse_number()
b'0' | b'1' | b'2' | b'3' | b'4' | b'5' | b'6' | b'7' | b'8' | b'9' => .parse_number()
b'f' => .parse_false()
b't' => .parse_true()
b'n' => .parse_null()
else => .parse_failure(error_message: "Unexpected character")
}
}
fn parse_failure(this, error_message: String) throws -> JsonValue {
throw Error::from_errno(9001)
}
fn parse_array(mut this) throws -> JsonValue {
mut array: [JsonValue] = []
if (not .consume_specific(b'[')) {
// Expected '['
throw Error::from_errno(9014)
}
loop {
.skip_whitespace()
if .peek() == b']' {
break
}
array.push(.parse_helper())
.skip_whitespace()
if .peek() == b']' {
break
}
if not .consume_specific(b',') {
// Expected ','
throw Error::from_errno(9014)
}
.skip_whitespace()
if .peek() == b']' {
// Unexpected ']'
throw Error::from_errno(9014)
}
}
if not .consume_specific(b']') {
// Expected ']'
throw Error::from_errno(9015)
}
return JsonValue::JsonArray(array)
}
fn parse_object(mut this) throws -> JsonValue {
if not .consume_specific(b'{') {
// FIXME: "Expected '{'"
throw Error::from_errno(9002)
}
mut values: [String:JsonValue] = [:]
loop {
.skip_whitespace()
if .peek() == b'}' {
break
}
.skip_whitespace()
let key = .consume_and_unescape_string()
.skip_whitespace()
if not .consume_specific(b':') {
// FIXME: "Expected ':'"
throw Error::from_errno(9003)
}
.skip_whitespace()
let value = .parse_helper()
// FIXME: This should say `values[key] = value`, but the compiler doesn't wrap it in TRY()
values.set(key, value)
.skip_whitespace()
if .peek() == b'}' {
break
}
if not .consume_specific(b',') {
// FIXME: "Expected ','"
throw Error::from_errno(9004)
}
.skip_whitespace()
if .peek() == b'}' {
// FIXME: "Unexpected '}'"
throw Error::from_errno(9005)
}
}
if not .consume_specific(b'}') {
// FIXME: "Expected '}'"
throw Error::from_errno(9006)
}
return JsonValue::Object(values)
}
fn char_to_f64(anon num: u8) throws -> f64 {
// FIXME 1: Shouldn't need this function at all
// FIXME 2: Shouldn't need return in else branch
return match num {
0u8 => 0.0
1u8 => 1.0
2u8 => 2.0
3u8 => 3.0
4u8 => 4.0
5u8 => 5.0
6u8 => 6.0
7u8 => 7.0
8u8 => 8.0
9u8 => 9.0
else => {
// FIXME: "Unexpected number"
throw Error::from_errno(9017)
}
}
}
fn parse_number(mut this) throws -> JsonValue {
// FIXME: This implementation doesn't match JsonParser.cpp
let is_negative = .consume_specific(b'-')
mut decimal_start_index: usize? = None
mut value = 0.0
while not .eof() {
let ch = .peek()
if ch == b'.' {
if decimal_start_index.has_value() {
// FIXME: "Unexpected '.'"
throw Error::from_errno(9016)
}
decimal_start_index = .index++
continue
} else if not (ch >= b'0' and ch <= b'9') {
break
}
if not decimal_start_index.has_value() {
value *= 10.0
value += char_to_f64(ch - b'0')
} else {
mut num = char_to_f64(ch - b'0')
// FIXME: This should really be: `value += pow(10, -decimal_place)*num`, but: there's no pow function and you can't multiply float by usize
let decimal_place = .index - decimal_start_index.value()
for i in 0..decimal_place {
num /= 10.0
}
value += num
}
.index++
}
if is_negative {
value *= -1.0
}
return JsonValue::Number(value)
}
fn parse_string(mut this) throws -> JsonValue {
return JsonValue::JsonString(.consume_and_unescape_string())
}
fn parse_false(mut this) throws -> JsonValue {
if (.consume() != b'f' or .consume() != b'a' or .consume() != b'l' or .consume() != b's' or .consume() != b'e') {
// FIXME: "Expected 'false'"
throw Error::from_errno(9011)
}
return JsonValue::Bool(false)
}
fn parse_true(mut this) throws -> JsonValue {
if (.consume() != b't' or .consume() != b'r' or .consume() != b'u' or .consume() != b'e') {
// FIXME: "Expected 'true'"
throw Error::from_errno(9012)
}
return JsonValue::Bool(true)
}
fn parse_null(mut this) throws -> JsonValue {
if (.consume() != b'n' or .consume() != b'u' or .consume() != b'l' or .consume() != b'l') {
// FIXME: "Expected 'null'"
throw Error::from_errno(9013)
}
return JsonValue::Null
}
}
// fn parse_json(input: String) throws -> JsonValue {
// mut parser = JsonParser::construct(input)
// return parser.parse()
// }
//
// fn main() {
// let value = parse_json(input: "[{\"id\":0.5,\"displayName\":\"Air\",\"name\":\"air\",\"hardness\":3.9,\"resistance\":0,\"minStateId\":0,\"maxStateId\":0,\"states\":[]}]")
// println("{}", value)
// }

147
src/net/lib/util.jakt Normal file
View File

@@ -0,0 +1,147 @@
import relative parent::os::os { OS }
struct Util {
fn get_address_u32_from_ipv4_u8_array(anon array: [u8]) -> u32 {
if array.size() != 4 {
return 0
}
mut address: u32 = (array[3] as! u32 & 0xff) as! u32
address += ((array[2] as! u32 & 0xff) << 8) as! u32
address += ((array[1] as! u32 & 0xff) << 16) as! u32
address += ((array[0] as! u32 & 0xff) << 24) as! u32
return address
}
fn get_hexadecimal_string_from_ipv4_u8_array(anon array: [u8]) throws -> String {
mut s = StringBuilder::create()
unsafe {
cpp {
"char *chars = (char*)calloc(32, 1);
sprintf(chars, \"%02x%02x%02x%02x\", array[0], array[1], array[2], array[3]);
s.append_c_string(chars);
delete(chars);"
}
}
return s.to_string()
}
fn get_md5_string_from_string(anon s: String) throws -> String {
mut sb = StringBuilder::create()
unsafe {
cpp {
"
char* md5 = (char*)os_call((u64)\"@saubari_get_md5_string_from_string\", (u64)s.characters());
sb.append_c_string(md5);
delete(md5);
"
}
}
return sb.to_string()
}
fn get_ipv4_u8_array_from_address_string(anon s: String) throws -> [u8] {
mut address: [u8] = []
let octet_strings = s.split(c'.')
for octet_string in octet_strings {
unsafe {
cpp {
"auto value = octet_string.to_number<u32>();
if (value.has_value()) {
auto result = value.release_value();
address.push(result & 0xff);
}"
}
}
}
return address
}
fn get_ipv4_u8_array_from_address_u32(anon addr: u32) throws -> [u8] {
mut address: [u8] = []
// let source_address: [u8] = [ipv4_packet[12], ipv4_packet[13], ipv4_packet[14], ipv4_packet[15]]
address.push(((addr >> 24) & 0xff) as! u8)
address.push(((addr >> 16) & 0xff) as! u8)
address.push(((addr >> 8) & 0xff) as! u8)
address.push((addr & 0xff) as! u8)
return address
}
fn get_string_from_u8_array(anon array: [u8]) throws -> String {
mut s = StringBuilder::create()
unsafe {
cpp {
"for (int i = 0; i < array.size(); i++) {
s.append(array[i]);
}"
}
}
return s.to_string()
}
fn get_u16_from_u8_array(anon array: [u8], anon offset: i64) -> u16{
return (array[offset] as! u16 << 8) + array[offset + 1] as! u16
}
fn get_u16_from_u8_arrayslice(anon array: ArraySlice<u8>, anon offset: i64) -> u16{
return (array[offset] as! u16 << 8) + array[offset + 1] as! u16
}
fn push_string_to_u8_array(anon mut array: [u8], anon s: String) throws {
for i in 0..s.length() {
unsafe {
cpp {
"array.push(s.characters()[i]);"
}
}
}
}
fn push_u16_to_u8_array(anon mut array: [u8], anon value: u16) throws {
array.push((value >> 8) as! u8)
array.push((value & 0xff) as! u8)
}
fn push_u32_to_u8_array(anon mut array: [u8], anon value: u32) throws {
mut val_u32_to_u8: u32 = 0
val_u32_to_u8 = (value >> 24) & 0xff
array.push(val_u32_to_u8 as! u8)
val_u32_to_u8 = (value >> 16) & 0xff
array.push(val_u32_to_u8 as! u8)
val_u32_to_u8 = (value >> 8) & 0xff
array.push(val_u32_to_u8 as! u8)
array.push((value & 0xff) as! u8)
}
fn get_dictionary_from_json_file(anon json_file: String) throws -> [String:String] {
mut dictionary: [String:String] = Dictionary()
let json_bytes = OS::read_entire_file(json_file)
let json_string = get_string_from_u8_array(json_bytes)
unsafe {
cpp {
"auto json = JsonValue::from_string(json_string).value();
auto const& object = json.as_object();
object.for_each_member([&]([[maybe_unused]] auto& property_name, [[maybe_unused]] const JsonValue& property_value) {
dictionary.set(property_name, property_value.deprecated_to_byte_string());
});"
}
}
return dictionary
}
fn get_dictionary_from_string(anon s: String) throws -> [String:String] {
mut dictionary: [String:String] = Dictionary()
unsafe {
cpp {
"auto json = JsonValue::from_string(s).value();
auto const& object = json.as_object();
object.for_each_member([&]([[maybe_unused]] auto& property_name, [[maybe_unused]] const JsonValue& property_value) {
dictionary.set(property_name, property_value.deprecated_to_byte_string());
});"
}
}
return dictionary
}
fn string_from_file(anon filepath: String) throws -> String {
if filepath.is_empty() or not OS::path_exists(filepath) {
return ""
}
let array = OS::read_entire_file(filepath)
mut s = StringBuilder::create()
unsafe {
cpp {
"for (int i = 0; i < array.size(); i++) {
s.append(array[i]);
}"
}
}
return s.to_string()
}
}

173
src/net/net.jakt Normal file
View File

@@ -0,0 +1,173 @@
import devices::virtio { VirtIO, VirtIOReg }
import lib::util { Util }
import os::os { OS }
import os::pci { PCI, PCIDevice }
import os::time { Time }
import tcpip { TCPIP }
class NetDevices {
public virtio: VirtIO
public fn create(pci_device: PCIDevice) throws -> NetDevices {
return NetDevices(
virtio: VirtIO(pci_device, rq_index: 0, rq_size: 0, rq: 0, tq_size: 0, tq: 0)
)
}
}
class Net {
public device: NetDevices
public mac_address: [u8]
public tcpip: TCPIP
public pci_device: PCIDevice
public fn init(config: [String:String]) throws -> Net {
let pci_device = PCI::find_device_by_class_code(0x020000)
mut net = Net(
device: NetDevices::create(pci_device)
mac_address: []
tcpip: TCPIP(
ipv4_address: Util::get_ipv4_u8_array_from_address_string(config["tcpip.ipv4_address"])
ipv4_netmask: Util::get_ipv4_u8_array_from_address_string(config["tcpip.ipv4_netmask"])
ipv4_network: Util::get_ipv4_u8_array_from_address_string(config["tcpip.ipv4_network"])
ipv4_gateway: Util::get_ipv4_u8_array_from_address_string(config["tcpip.ipv4_gateway"])
dns_server_address: Util::get_ipv4_u8_array_from_address_string(config["tcpip.ipv4_dns_server_address"])
dns_server_port: config["tcpip.ipv4_dns_server_port"].to_number<u32>().value() as! u16
mss_size: config["tcpip.mss_size"].to_number<u32>().value() as! u16
tx_queue: []
ttl: 64
arp_cache: Dictionary()
bound_sockets: Dictionary()
dns_cache: Dictionary()
tcp_sessions: []
pending_dns_lookups: Dictionary()
pending_dns_cached_entries: Dictionary()
pending_icmp_requests: Dictionary()
timestamp_last_arp_request: 0
rx_bytes: 0
rx_frames: 0
tx_bytes: 0
tx_frames: 0
)
pci_device
)
if net.pci_device.vendor_id() == 0x1af4 and net.pci_device.device_id() == 0x1000 {
println("[net] Found device: virtio-net, QEMU")
for i in 0u16..6u16 {
net.mac_address.push(net.pci_device.io_read_u8(VirtIOReg::config as! u16 + i))
}
net.device.virtio.init()
return net
}
println("[net] No supported vendor ids found")
OS::exit()
return net
}
fn process_ethernet_frame(mut this, anon frame: [u8]) throws {
let ethertype: u16 = (frame[12] as! u16 * 256) + frame[13] as! u16
match ethertype {
0x0806 => {
//println("ARP")
.tcpip.process_arp_packet(.mac_address, frame)
}
0x0800 => {
//println("IPv4")
.tcpip.process_ipv4_packet(.mac_address, frame)
}
0x86dd => {
//.tcpip.process_ipv6_packet(frame)
}
0x8035 => {
//.tcpip.process_rarp_packet(frame)
}
else => {
// unsupported
}
}
}
public fn process_events(mut this) throws {
mut received_frame = .rx_frame()
if received_frame.size() > 0 {
.tcpip.rx_bytes += received_frame.size() as! u64
.tcpip.rx_frames++
.process_ethernet_frame(received_frame)
}
.tcpip.tcp_transmit_pending_data_for_existing_sessions()
for frame in .tcpip.tx_queue {
.tx_frame(frame)
}
if .tcpip.tx_queue.size() > 0 {
.tcpip.tx_queue.shrink(0)
}
.tcpip.tcp_process_bind_request()
.tcpip.tcp_process_client_socket_request(.mac_address)
.tcpip.tcp_process_client_received_data()
.tcpip.tcp_process_client_send_requests(.mac_address)
.tcpip.dns_process_client_request(.mac_address)
.tcpip.icmp_process_client_request(.mac_address)
.tcpip.netinfo_process_client_request(.mac_address)
}
fn rx_frame(mut this) throws -> [u8] {
mut frame: [u8] = []
if .pci_device.vendor_id() == 0x1af4 and .pci_device.device_id() == 0x1000 {
frame = .device.virtio.rx_frame()
}
return frame
}
fn tx_frame(mut this, anon mut data: [u8]) throws {
if data.size() < 1 {
return
}
while data.size() < 60 {
data.push(0u8)
}
.tcpip.tx_bytes += data.size() as! u64
.tcpip.tx_frames++
if .pci_device.vendor_id() == 0x1af4 and .pci_device.device_id() == 0x1000 {
.device.virtio.tx_frame(data)
}
}
}
fn main() {
println("$WW,1$")
mut config = Util::get_dictionary_from_json_file("M:/System/Config/Net.json")
mut net = Net::init(config)
println("[net] PCI device is {}", net.pci_device)
print("[net] MAC address is ")
for i in 0u16..5u16 {
print("{:0>2x}:", net.mac_address[i])
}
println("{:0>2x}", net.mac_address[5])
print("[net] IPv4 address is ")
for i in 0u16..3u16 {
print("{:d}.", net.tcpip.ipv4_address[i])
}
println("{:d}", net.tcpip.ipv4_address[3])
println(" ")
// Update the ARP cache entry for IPv4 gateway address
net.tcpip.send_arp_request(net.mac_address, net.tcpip.ipv4_gateway)
mut prev_rx_frames = net.tcpip.rx_frames
mut prev_tx_frames = net.tcpip.tx_frames
mut prev_jiffies = Time::jiffies()
while true {
net.process_events()
if (prev_rx_frames != net.tcpip.rx_frames) or (prev_tx_frames != net.tcpip.tx_frames) {
prev_rx_frames = net.tcpip.rx_frames
prev_tx_frames = net.tcpip.tx_frames
prev_jiffies = Time::jiffies()
}
if Time::jiffies() < prev_jiffies + 250 {
Time::sleep(0)
} else {
Time::sleep(1)
}
}
OS::exit()
}

29
src/net/os/ioport.jakt Normal file
View File

@@ -0,0 +1,29 @@
import extern c "ioport.h" {
extern fn ioport_read_u8(address: u16) -> u8
extern fn ioport_read_u16(address: u16) -> u16
extern fn ioport_read_u32(address: u16) -> u32
extern fn ioport_write_u8(address: u16, value: u8)
extern fn ioport_write_u16(address: u16, value: u16)
extern fn ioport_write_u32(address: u16, value: u32)
}
struct IOPort {
fn read_u8(anon address: u16) throws -> u8 {
return ioport_read_u8(address)
}
fn read_u16(anon address: u16) throws -> u16 {
return ioport_read_u16(address)
}
fn read_u32(anon address: u16) throws -> u32 {
return ioport_read_u32(address)
}
fn write_u8(address: u16, value: u8) {
return ioport_write_u8(address, value)
}
fn write_u16(address: u16, value: u16) {
return ioport_write_u16(address, value)
}
fn write_u32(address: u16, value: u32) {
return ioport_write_u32(address, value)
}
}

154
src/net/os/os.jakt Normal file
View File

@@ -0,0 +1,154 @@
import extern c "os.h" {
extern fn os_blink(frequency: raw c_char) -> bool
extern fn os_call(function_name: u64, arg: u64) -> u64
extern fn os_device_calloc(size: u32) -> u32
extern fn os_exit()
extern fn os_file_picker(path: raw c_char, glob: raw c_char)
extern fn os_files_list(path: raw c_char)
extern fn os_is_vm() -> bool
extern fn os_path_exists(anon path: raw c_char) -> bool
extern fn os_pc_speaker(frequency: raw c_char)
extern fn os_random() -> u64
extern fn os_screenshot()
extern fn os_to_uppercase(anon input_string: raw c_char) -> raw c_char
}
struct OS {
fn blink(frequency: f64 = 2.5) throws -> bool {
let frequency_as_string = format("{}", frequency)
return os_blink(frequency: frequency_as_string.c_string())
}
fn call(anon function_name: String, anon arg: String) throws -> u64 {
mut res: u64 = 0
unsafe {
cpp {
"
res = os_call((u64)function_name.characters(), (u64)arg.characters());
"
}
}
return res
}
fn device_calloc(anon size: u32) throws -> u32 {
return os_device_calloc(size)
}
fn device_copy_buffer(anon buffer: [u8]) -> u32 {
mut address: u32 = 0
mut size = buffer.size()
unsafe {
cpp {
"u8 *data = (u8*)os_device_calloc(size);
for (int i = 0; i < size; i++)
data[i] = buffer[i];
address = (uintptr_t)data;"
}
}
return address
}
fn exit() {
os_exit()
}
fn file_picker(path: String, glob: String) throws -> String {
mut s = StringBuilder::create()
unsafe {
cpp {
"char const *chars = os_file_picker(path.characters(), glob.characters());
s.append_c_string(chars);
delete(chars);"
}
}
return s.to_string()
}
fn files_list(path: String) throws -> [String] {
mut s = StringBuilder::create()
unsafe {
cpp {
"char const *chars = os_files_list(path.characters());
if (chars) {
s.append_c_string(chars);
delete(chars);
}"
}
}
return s.to_string().split(c'|')
}
fn path_exists(anon path: String) -> bool {
return os_path_exists(path.c_string())
}
fn is_vm() -> bool {
return os_is_vm()
}
fn pc_speaker(frequency: f64) throws {
let frequency_as_string = format("{}", frequency)
os_pc_speaker(frequency: frequency_as_string.c_string())
}
fn put_char(ch: u8) {
unsafe {
cpp {
"putchar(ch);"
}
}
}
fn random() -> u64 {
return os_random()
}
fn read_entire_file(anon filename: String) throws -> [u8] {
mut size = 0
mut buffer: [u8] = []
unsafe {
cpp {
"u8 *data = os_read_entire_file(filename.characters(), &size);
for (int i = 0; i < size; i++)
buffer.push(data[i]);
free(data);"
}
}
return buffer
}
fn read_device_memory(address: u32, size: i64) throws -> [u8] {
mut buffer: [u8] = [];
unsafe {
cpp {
"u8 *device_memory = (u8*)address;
for (int i = 0; i < size; i++)
buffer.push(device_memory[i]);"
}
}
return buffer
}
fn read_u16_from_device_memory(anon address: u32) throws -> u16 {
mut value: u16 = 0
unsafe {
cpp {
"value = *(u16*)address;"
}
}
return value
}
fn screenshot() {
os_screenshot()
}
fn to_uppercase(anon input_string: String) throws -> String {
mut s = StringBuilder::create()
unsafe {
cpp {
"char const *chars = os_to_uppercase(input_string.characters());
s.append_c_string(chars);
delete(chars);"
}
}
return s.to_string()
}
fn write_entire_file(filename: String, buffer: [u8]) {
mut size = buffer.size()
unsafe {
cpp {
"unsigned char *data = (unsigned char *)malloc(size);
for (int i = 0; i < size; i++)
data[i] = buffer[i];
os_write_entire_file(filename.characters(), data, size);
free(data);"
}
}
}
}

103
src/net/os/pci.jakt Normal file
View File

@@ -0,0 +1,103 @@
import ioport { IOPort }
import extern c "pci.h" {
extern fn pci_find(anon class_code: i64) -> i64
extern fn pci_read_u8(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64) -> u8
extern fn pci_read_u16(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64) -> u16
extern fn pci_read_u32(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64) -> u32
extern fn pci_write_u8(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64, anon value: u8)
extern fn pci_write_u16(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64, anon value: u16)
extern fn pci_write_u32(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64, anon value: u32)
}
struct PCIDevice {
bus: i64
device: i64
fun: i64
pci_vendor_id: u16
pci_device_id: u16
bar: [u32]
public fn enable_bus_master(mut this) {
.set_command(.command() | 0x4)
}
public fn read_u8(this, anon offset: i64) -> u8 {
return pci_read_u8(.bus, .device, .fun, offset)
}
public fn read_u16(this, anon offset: i64) -> u16 {
return pci_read_u16(.bus, .device, .fun, offset)
}
public fn read_u32(this, anon offset: i64) -> u32 {
return pci_read_u32(.bus, .device, .fun, offset)
}
public fn write_u8(this, offset: i64, value: u8) {
pci_write_u8(.bus, .device, .fun, offset, value)
}
public fn write_u16(this, offset: i64, value: u16) {
pci_write_u16(.bus, .device, .fun, offset, value)
}
public fn write_u32(this, offset: i64, value: u32) {
pci_write_u32(.bus, .device, .fun, offset, value)
}
public fn io_read_u8(this, anon offset: u16) throws -> u8 {
return IOPort::read_u8(.bar[0] as! u16 + offset)
}
public fn io_read_u16(this, anon offset: u16) throws -> u16 {
return IOPort::read_u16(.bar[0] as! u16 + offset)
}
public fn io_read_u32(this, anon offset: u16) throws -> u32 {
return IOPort::read_u32(.bar[0] as! u16 + offset)
}
public fn io_write_u8(this, offset: u16, value: u8) {
IOPort::write_u8(address: .bar[0] as! u16 + offset, value)
}
public fn io_write_u16(this, offset: u16, value: u16) {
IOPort::write_u16(address: .bar[0] as! u16 + offset, value)
}
public fn io_write_u32(this, offset: u16, value: u32) {
IOPort::write_u32(address: .bar[0] as! u16 + offset, value)
}
public fn vendor_id(this) -> u16 {
return .pci_vendor_id
}
public fn device_id(this) -> u16 {
return .pci_device_id
}
public fn command(this) -> u16 {
return pci_read_u16(.bus, .device, .fun, 0x4)
}
public fn set_command(this, anon value: u16) {
pci_write_u16(.bus, .device, .fun, offset: 0x4, value)
}
public fn status(this) -> u16 {
return pci_read_u16(.bus, .device, .fun, 0x6)
}
}
fn lookup_bar(bus: i64, device: i64, fun: i64, anon index: i64) -> u32 {
if index < 0 or index > 5 {
return 0xFFFFFFFF
}
return pci_read_u32(bus, device, fun, 0x10 + (index * 4)) & 0xFFFFFFFC
}
struct PCI {
public fn find_device_by_class_code(anon class_code: i64) throws -> PCIDevice {
let result = pci_find(class_code)
if result < 0 {
eprintln("error: device not found")
throw Error::from_errno(1)
}
let bus = (result >> 16) & 0xff
let device = (result >> 8) & 0xff
let fun = result & 0xff
let pci_vendor_id = pci_read_u16(bus, device, fun, 0x0)
let pci_device_id = pci_read_u16(bus, device, fun, 0x2)
mut bar: [u32] = []
for i in 0..5 {
bar.push(lookup_bar(bus, device, fun, i))
}
return PCIDevice(bus, device, fun, pci_vendor_id, pci_device_id, bar)
}
}

94
src/net/os/time.jakt Normal file
View File

@@ -0,0 +1,94 @@
import extern c "time.h" {
extern fn time_busy(anon duration: i64)
extern fn time_jiffies() -> i64
extern fn time_now() -> i64
extern fn time_sleep(anon duration: i64)
}
struct Time {
fn busy(anon duration: i64) {
time_busy(duration)
}
fn jiffies() throws -> i64 {
return time_jiffies()
}
fn now() throws -> i64 {
return time_now()
}
fn cdate_to_unix(anon cdate: i64) -> i64 {
// (cdate - Str2Date("1/1/1970") / CDATE_FREQ + NIST_TIME_OFFSET
return (cdate - 3090344933588992) / 49710 + 8575
}
fn unix_to_cdate(anon unix: i64) -> i64 {
// (unix - NIST_TIME_OFFSET) * CDATE_FREQ + Str2Date("1/1/1970")
return (unix - 8575) * 49710 + 3090344933588992
}
fn sleep(anon duration: i64) {
time_sleep(duration)
}
fn timestamp_from_unix(anon timestamp: i64) -> String {
let SECS_PER_DAY = 86400
let DAYS_PER_YEAR = 365
let DAYS_PER_LYEAR = 366
let DAYS_PER_LYEAR_PERIOD = 146097
let YEARS_PER_LYEAR_PERIOD = 400
mut days = timestamp / SECS_PER_DAY
mut remainder = timestamp - (days * SECS_PER_DAY)
if timestamp < 0 and remainder == 0 {
days++
remainder -= SECS_PER_DAY
}
mut cur_year = 0
mut months: [i64] = []
mut tmp_days = 0
let month_tab = [ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ]
let month_tab_leap = [ -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ]
tmp_days = days;
if tmp_days >= DAYS_PER_LYEAR_PERIOD or tmp_days <= -DAYS_PER_LYEAR_PERIOD {
cur_year += YEARS_PER_LYEAR_PERIOD * (tmp_days / DAYS_PER_LYEAR_PERIOD);
tmp_days -= DAYS_PER_LYEAR_PERIOD * (tmp_days / DAYS_PER_LYEAR_PERIOD);
}
while tmp_days >= DAYS_PER_LYEAR {
cur_year++;
if cur_year % 4 == 0 {
tmp_days -= DAYS_PER_LYEAR;
} else {
tmp_days -= DAYS_PER_YEAR;
}
}
if cur_year % 4 == 0 {
months = month_tab_leap
} else {
months = month_tab
}
mut i = 11
while i > 0 {
if tmp_days > months[i] {
break;
}
i--
}
let year = 1970 + cur_year
let month = i + 1
let day = tmp_days - months[i]
let hours = remainder / 3600
let minutes = (remainder - hours * 3600) / 60
let seconds = remainder % 60
mut sb = StringBuilder::create()
sb.clear()
sb.appendff("{:0>4d}-{:0>2d}-{:0>2d}T{:0>2d}:{:0>2d}:{:0>2d}.000Z", year, month, day, hours, minutes, seconds)
return sb.to_string()
}
fn timestamp_from_cdate(anon cdate: i64) -> String {
return timestamp_from_unix(cdate_to_unix(cdate))
}
}

1755
src/net/tcpip.jakt Normal file

File diff suppressed because it is too large Load Diff