mirror of
https://git.checksum.fail/alec/neinterm.git
synced 2025-12-08 03:59:53 +02:00
Add files to repository
This commit is contained in:
14
.clang-format
Normal file
14
.clang-format
Normal 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
16
.gitignore
vendored
Normal 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
10
.vscode/settings.json
vendored
Normal 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
1
.vscode/tasks.json
vendored
Normal 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
254
NeinTerm.HC
Normal 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
4
Run.HC
Normal 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
133
System/9P/Debug.HC
Normal 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
293
System/9P/Defs.HC
Normal 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 file’s mode word.
|
||||
// qid.vers[4]
|
||||
// version number for given path
|
||||
// qid.path[8]
|
||||
// the file server’s 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
503
System/9P/Draw.HC
Normal 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
557
System/9P/Requests.HC
Normal 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 file’s mode word.
|
||||
// qid.vers[4]
|
||||
// version number for given path
|
||||
// qid.path[8]
|
||||
// the file server’s 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
25
System/Api/Dns.HC
Normal 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
32
System/Api/Icmp.HC
Normal 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
9
System/Api/Ipv4.HC
Normal 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
144
System/Api/MD5.HC
Normal 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
32
System/Api/NetInfo.HC
Normal 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
209
System/Api/Tcp.HC
Normal 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
10
System/Config/Net.json
Normal 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
51
System/FFI/Base.HC
Normal 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 [¶m0], 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
300
System/FFI/ELF64.HC
Normal 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
327
System/FFI/LibC.HC
Normal 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
35
System/FFI/New.HC
Normal 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
288
System/Jakt/DC.HC
Normal 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
53
System/Jakt/IOPort.HC
Normal 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
72
System/Jakt/Input.HC
Normal 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
282
System/Jakt/OS.HC
Normal 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
62
System/Jakt/PCI.HC
Normal 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
37
System/Jakt/Time.HC
Normal 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
94
System/Jakt/Window.HC
Normal 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
1573
System/Libraries/Json.HC
Normal file
File diff suppressed because it is too large
Load Diff
196
System/Libraries/String.HC
Normal file
196
System/Libraries/String.HC
Normal 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
56
System/MakeSystem.HC
Normal 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 */
|
||||
23
System/Setup/Environment.HC
Normal file
23
System/Setup/Environment.HC
Normal 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
180
System/Setup/Util.HC
Normal 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
10
System/Utilities/Dns.HC
Normal 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
414
System/Utilities/Image.HC
Normal 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);
|
||||
22
System/Utilities/NetRep.HC
Normal file
22
System/Utilities/NetRep.HC
Normal 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
72
System/Utilities/Ping.HC
Normal 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
92
System/Utilities/Time.HC
Normal 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);
|
||||
}
|
||||
80
System/Utilities/TrueType.HC
Normal file
80
System/Utilities/TrueType.HC
Normal 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
9
script.rc
Normal 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
207
scripts/build-all
Executable 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
209
src/image/image.c
Normal 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
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
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
6
src/libtemple/ioport.h
Normal 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);
|
||||
81
src/libtemple/libtemple.cpp
Normal file
81
src/libtemple/libtemple.cpp
Normal 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
15
src/libtemple/os.h
Normal 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
10
src/libtemple/pci.h
Normal 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
4
src/libtemple/time.h
Normal 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
28
src/net/devices/virtio.h
Normal 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
143
src/net/devices/virtio.jakt
Normal 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
350
src/net/lib/json.jakt
Normal 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
147
src/net/lib/util.jakt
Normal 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
173
src/net/net.jakt
Normal 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
29
src/net/os/ioport.jakt
Normal 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
154
src/net/os/os.jakt
Normal 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
103
src/net/os/pci.jakt
Normal 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
94
src/net/os/time.jakt
Normal 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
1755
src/net/tcpip.jakt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user