Meta: Add files to repository
This commit is contained in:
parent
6d27d43268
commit
52cb92f587
120 changed files with 71820 additions and 0 deletions
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;
|
||||
}
|
210
System/Api/Tcp.HC
Normal file
210
System/Api/Tcp.HC
Normal file
|
@ -0,0 +1,210 @@
|
|||
#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
|
||||
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->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;
|
||||
}
|
99
System/Api/Tls.HC
Normal file
99
System/Api/Tls.HC
Normal file
|
@ -0,0 +1,99 @@
|
|||
#define TLS_CONNECT_TASK_STACK_SIZE 524288
|
||||
#define TLS_CLIENT_MESSAGE_BUFFER_SIZE 0xFFFF
|
||||
|
||||
class TlsSocket : TcpSocket {
|
||||
U64 ctx;
|
||||
U8 client_message[TLS_CLIENT_MESSAGE_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
U0 @tls_send_pending(TlsSocket* s)
|
||||
{
|
||||
U32 out_buffer_len = 0;
|
||||
U8* out_buffer = @tls_get_write_buffer(s->ctx, &out_buffer_len);
|
||||
if (out_buffer && out_buffer_len) {
|
||||
@tcp_socket_send(s, out_buffer, out_buffer_len);
|
||||
@tls_buffer_clear(s->ctx);
|
||||
}
|
||||
}
|
||||
|
||||
U0 @tls_socket_send(TlsSocket* s, U64 buf, U64 size)
|
||||
{
|
||||
@tls_write(s->ctx, buf, size);
|
||||
@tls_send_pending(s);
|
||||
}
|
||||
|
||||
U64 @tls_socket_receive(TlsSocket* s, U8* buf, I64 size)
|
||||
{
|
||||
I64 len = @tcp_socket_receive(s, s->client_message, TLS_CLIENT_MESSAGE_BUFFER_SIZE);
|
||||
if (len) {
|
||||
@tls_consume_stream(s->ctx, s->client_message, len, NULL);
|
||||
@tls_send_pending(s);
|
||||
}
|
||||
return @tls_read(s->ctx, buf, size);
|
||||
}
|
||||
|
||||
U0 @tls12_connect(TlsSocket* s)
|
||||
{
|
||||
I64 len;
|
||||
@tls_client_connect(s->ctx);
|
||||
@tls_send_pending(s);
|
||||
while (!@tls_established(s->ctx)) {
|
||||
len = @tcp_socket_receive(s, &s->client_message, TLS_CLIENT_MESSAGE_BUFFER_SIZE);
|
||||
if (len) {
|
||||
@tls_consume_stream(s->ctx, &s->client_message, len, NULL);
|
||||
@tls_send_pending(s);
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
TlsSocket* @tls_socket_create(U8* server_name, U64 port = 443)
|
||||
{
|
||||
U64 addr = @dns_query(server_name);
|
||||
TlsSocket* s = CAlloc(sizeof(TlsSocket), 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, &@tls_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, &@tls_socket_send);
|
||||
|
||||
U64* request_ptr = TCP_SOCKET_REQUEST_PTR;
|
||||
while (*request_ptr)
|
||||
Sleep(1);
|
||||
LXchgU32(request_ptr, s);
|
||||
|
||||
while (s->state != TCP_SOCKET_STATE_ESTABLISHED)
|
||||
Sleep(1);
|
||||
|
||||
s->ctx = @tls_create_context(0, TLS_V12);
|
||||
@tls_sni_set(s->ctx, StrNew(server_name, adam_task->code_heap));
|
||||
Spawn(&@tls12_connect, s, , , , TLS_CONNECT_TASK_STACK_SIZE);
|
||||
|
||||
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"
|
||||
}
|
473
System/Drivers/Virtio-blk.HC
Normal file
473
System/Drivers/Virtio-blk.HC
Normal file
|
@ -0,0 +1,473 @@
|
|||
// Virtio.HC
|
||||
|
||||
//
|
||||
// PCI virtio I/O registers.
|
||||
//
|
||||
|
||||
#define VIRTIO_PCI_HOST_FEATURES 0 // Features supported by the host
|
||||
#define VIRTIO_PCI_GUEST_FEATURES 4 // Features activated by the guest
|
||||
#define VIRTIO_PCI_QUEUE_PFN 8 // PFN for the currently selected queue
|
||||
#define VIRTIO_PCI_QUEUE_SIZE 12 // Queue size for the currently selected queue
|
||||
#define VIRTIO_PCI_QUEUE_SEL 14 // Queue selector
|
||||
#define VIRTIO_PCI_QUEUE_NOTIFY 16 // Queue notifier
|
||||
#define VIRTIO_PCI_STATUS 18 // Device status register
|
||||
#define VIRTIO_PCI_ISR 19 // Interrupt status register
|
||||
#define VIRTIO_PCI_CONFIG 20 // Configuration data block
|
||||
|
||||
//
|
||||
// PCI virtio status register bits
|
||||
//
|
||||
|
||||
#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
|
||||
#define VIRTIO_CONFIG_S_DRIVER 2
|
||||
#define VIRTIO_CONFIG_S_DRIVER_OK 4
|
||||
#define VIRTIO_CONFIG_S_FAILED 0x80
|
||||
|
||||
//
|
||||
// Ring descriptor flags
|
||||
//
|
||||
|
||||
#define VRING_DESC_F_NEXT 1 // Buffer continues via the next field
|
||||
#define VRING_DESC_F_WRITE 2 // Buffer is write-only (otherwise read-only)
|
||||
#define VRING_DESC_F_INDIRECT 4 // Buffer contains a list of buffer descriptors
|
||||
|
||||
class @virtio_queue_buf
|
||||
{
|
||||
U64 address;
|
||||
U32 length;
|
||||
U16 flags;
|
||||
U16 next;
|
||||
};
|
||||
class @virtio_avail
|
||||
{
|
||||
U16 flags;
|
||||
U16 index;
|
||||
U16 ring[256];
|
||||
U16 int_index;
|
||||
};
|
||||
class @virtio_used_item
|
||||
{
|
||||
U32 index;
|
||||
U32 length;
|
||||
};
|
||||
class @virtio_used
|
||||
{
|
||||
U16 flags;
|
||||
U16 index;
|
||||
@virtio_used_item ring[256];
|
||||
U16 int_index;
|
||||
};
|
||||
class @virtio_queue
|
||||
{
|
||||
@virtio_queue_buf buffers[256];
|
||||
@virtio_avail available;
|
||||
U8 padding[3578];
|
||||
@virtio_used used;
|
||||
};
|
||||
|
||||
class @virtio_avail_buf
|
||||
{
|
||||
U32 index;
|
||||
U64 address;
|
||||
U32 length;
|
||||
};
|
||||
|
||||
class @virtio_buf_info
|
||||
{
|
||||
U8* buffer;
|
||||
U64 size;
|
||||
U8 flags;
|
||||
|
||||
// If the user wants to keep same buffer as passed in this struct, use "true".
|
||||
// otherwise, the supplied buffer will be copied in the queues' buffer
|
||||
Bool copy;
|
||||
};
|
||||
|
||||
// Virtio-blk.HC
|
||||
|
||||
#define BDT_VIRTIO_BLK 10
|
||||
|
||||
#define VIRTIO_BLK_T_IN 0
|
||||
#define VIRTIO_BLK_T_OUT 1
|
||||
#define VIRTIO_BLK_T_FLUSH 4
|
||||
|
||||
#define VIRTIO_BLK_MAX_BLK 0x400000 // Limit blkdev to 2G max, set to NULL to use entire disk (not recommended for RedSea)
|
||||
|
||||
class @virtio_blk
|
||||
{
|
||||
U16 port;
|
||||
U32 blks;
|
||||
@virtio_queue* vq;
|
||||
I64 vq_size;
|
||||
I64 vq_index;
|
||||
U8 status;
|
||||
};
|
||||
|
||||
class @virtio_blk_request
|
||||
{
|
||||
U32 type;
|
||||
U32 priority;
|
||||
U64 sector;
|
||||
};
|
||||
|
||||
@virtio_blk virtio_blk;
|
||||
MemSet(&virtio_blk, 0, sizeof(@virtio_blk));
|
||||
|
||||
I64 VirtioBlkInit()
|
||||
{
|
||||
I64 j;
|
||||
|
||||
// Scan for device
|
||||
j = PCIClassFind(0x010000, 0);
|
||||
if (j < 0) {
|
||||
"\n[virtio-blk] No device found\n";
|
||||
return -1;
|
||||
}
|
||||
virtio_blk.port = PCIReadU32(j.u8[2],
|
||||
j.u8[1], j.u8[0], 0x10)
|
||||
& 0xFFFFFFFC;
|
||||
|
||||
virtio_blk.blks = InU32(virtio_blk.port + VIRTIO_PCI_CONFIG);
|
||||
|
||||
// Reset Device
|
||||
OutU8(virtio_blk.port + VIRTIO_PCI_STATUS, 0);
|
||||
|
||||
// Found Driver
|
||||
OutU8(virtio_blk.port + VIRTIO_PCI_STATUS, InU8(virtio_blk.port + VIRTIO_PCI_STATUS) | VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER);
|
||||
|
||||
// Set up virt queue
|
||||
OutU16(virtio_blk.port + VIRTIO_PCI_QUEUE_SEL, 0);
|
||||
virtio_blk.vq_size = InU16(virtio_blk.port + VIRTIO_PCI_QUEUE_SIZE); // 256
|
||||
virtio_blk.vq = CAllocAligned(sizeof(@virtio_queue), 4096, adam_task->code_heap);
|
||||
OutU32(virtio_blk.port + VIRTIO_PCI_QUEUE_PFN, virtio_blk.vq / 4096);
|
||||
|
||||
// Init OK
|
||||
OutU8(virtio_blk.port + VIRTIO_PCI_STATUS, InU8(virtio_blk.port + VIRTIO_PCI_STATUS) | VIRTIO_CONFIG_S_DRIVER_OK);
|
||||
virtio_blk.vq_index = 0;
|
||||
}
|
||||
|
||||
// DskVIO.HC
|
||||
|
||||
U0 VIOFlush()
|
||||
{
|
||||
I64 j;
|
||||
I64 vq_idx;
|
||||
@virtio_blk_request* brq = CAlloc(sizeof(@virtio_blk_request), adam_task);
|
||||
brq->type = VIRTIO_BLK_T_FLUSH;
|
||||
brq->sector = NULL;
|
||||
vq_idx = virtio_blk.vq->available.index % 256;
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].address = brq;
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].length = sizeof(@virtio_blk_request);
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].flags = VRING_DESC_F_NEXT;
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].next = (virtio_blk.vq_index + 1) % 256;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].address = &virtio_blk.status;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].length = 1;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].flags = VRING_DESC_F_WRITE;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].next = 0;
|
||||
virtio_blk.vq->available.ring[vq_idx] = virtio_blk.vq_index % 256;
|
||||
virtio_blk.vq_index += 2;
|
||||
j = virtio_blk.vq->used.index;
|
||||
virtio_blk.vq->available.index++;
|
||||
OutU16(virtio_blk.port + VIRTIO_PCI_QUEUE_NOTIFY, 0);
|
||||
while (j == virtio_blk.vq->used.index) {
|
||||
Yield;
|
||||
}
|
||||
Free(brq);
|
||||
}
|
||||
|
||||
Bool VIORBlks(CDrv* dv, U8* buf, I64 blk, I64 cnt)
|
||||
{
|
||||
no_warn dv;
|
||||
I64 i, j;
|
||||
I64 vq_idx;
|
||||
U64 addr;
|
||||
@virtio_blk_request* brq = CAlloc(sizeof(@virtio_blk_request), adam_task);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
brq->type = VIRTIO_BLK_T_IN;
|
||||
brq->sector = blk + i;
|
||||
vq_idx = virtio_blk.vq->available.index % 256;
|
||||
addr = buf + (BLK_SIZE * i);
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].address = brq;
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].length = sizeof(@virtio_blk_request);
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].flags = VRING_DESC_F_NEXT;
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].next = (virtio_blk.vq_index + 1) % 256;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].address = addr;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].length = BLK_SIZE;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].flags = VRING_DESC_F_WRITE | VRING_DESC_F_NEXT;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].next = (virtio_blk.vq_index + 2) % 256;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].address = &virtio_blk.status;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].length = 1;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].flags = VRING_DESC_F_WRITE;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].next = 0;
|
||||
virtio_blk.vq->available.ring[vq_idx] = virtio_blk.vq_index % 256;
|
||||
virtio_blk.vq_index += 3;
|
||||
j = virtio_blk.vq->used.index;
|
||||
virtio_blk.vq->available.index++;
|
||||
OutU16(virtio_blk.port + VIRTIO_PCI_QUEUE_NOTIFY, 0);
|
||||
while (j == virtio_blk.vq->used.index) {
|
||||
Yield;
|
||||
}
|
||||
}
|
||||
Free(brq);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool VIOWBlks(CDrv* dv, U8* buf, I64 blk, I64 cnt)
|
||||
{
|
||||
no_warn dv;
|
||||
I64 i, j;
|
||||
I64 vq_idx;
|
||||
U64 addr;
|
||||
@virtio_blk_request* brq = CAlloc(sizeof(@virtio_blk_request), adam_task);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
brq->type = VIRTIO_BLK_T_OUT;
|
||||
brq->sector = blk + i;
|
||||
vq_idx = virtio_blk.vq->available.index % 256;
|
||||
addr = buf + (BLK_SIZE * i);
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].address = brq;
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].length = sizeof(@virtio_blk_request);
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].flags = VRING_DESC_F_NEXT;
|
||||
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].next = (virtio_blk.vq_index + 1) % 256;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].address = addr;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].length = BLK_SIZE;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].flags = VRING_DESC_F_NEXT;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].next = (virtio_blk.vq_index + 2) % 256;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].address = &virtio_blk.status;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].length = 1;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].flags = VRING_DESC_F_WRITE;
|
||||
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].next = 0;
|
||||
virtio_blk.vq->available.ring[vq_idx] = virtio_blk.vq_index % 256;
|
||||
virtio_blk.vq_index += 3;
|
||||
j = virtio_blk.vq->used.index;
|
||||
virtio_blk.vq->available.index++;
|
||||
OutU16(virtio_blk.port + VIRTIO_PCI_QUEUE_NOTIFY, 0);
|
||||
while (j == virtio_blk.vq->used.index) {
|
||||
Yield;
|
||||
}
|
||||
}
|
||||
Free(brq);
|
||||
VIOFlush;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
U0 RedSeaTryInit(CDrv* dv)
|
||||
{
|
||||
CRedSeaBoot br;
|
||||
Bool unlock;
|
||||
try {
|
||||
unlock = DrvLock(dv);
|
||||
BlkRead(dv, &br, dv->drv_offset, 1);
|
||||
if (br.signature != MBR_PT_REDSEA || br.signature2 != 0xAA55)
|
||||
return;
|
||||
dv->fs_type = FSt_REDSEA;
|
||||
CallExtStr("RedSeaFreeFreeLst", dv);
|
||||
dv->spc = 1;
|
||||
dv->size = br.sects;
|
||||
dv->data_area = dv->drv_offset + br.bitmap_sects;
|
||||
dv->root_clus = br.root_clus;
|
||||
dv->fat1 = dv->fat2 = dv->drv_offset + 1;
|
||||
CallExtStr("DrvFATBlkAlloc", dv);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
|
||||
U8 MountVirtioBlk()
|
||||
{ // Mount Virtio-blk device
|
||||
CDrv* dv = DrvMakeFreeSlot(DrvNextFreeLet('A'));
|
||||
CBlkDev* bd = BlkDevNextFreeSlot(dv->drv_let, BDT_RAM);
|
||||
CRedSeaBoot* bs = CAlloc(BLK_SIZE, adam_task);
|
||||
bd->max_blk = 512;
|
||||
BlkDevAdd(bd, , TRUE, TRUE);
|
||||
bd->type = BDT_VIRTIO_BLK;
|
||||
if (VIRTIO_BLK_MAX_BLK) {
|
||||
bd->max_blk = Min(VIRTIO_BLK_MAX_BLK, virtio_blk.blks);
|
||||
} else {
|
||||
bd->max_blk = virtio_blk.blks;
|
||||
}
|
||||
Free(bd->RAM_dsk);
|
||||
dv->size = bd->max_blk + 1 - bd->drv_offset;
|
||||
VIORBlks(dv, bs, 0, 1);
|
||||
dv->root_clus = bs->root_clus;
|
||||
dv->data_area = bs->bitmap_sects;
|
||||
dv->next_free = NULL;
|
||||
dv->last_free = NULL;
|
||||
Free(bs);
|
||||
RedSeaTryInit(dv);
|
||||
return dv->drv_let;
|
||||
}
|
||||
|
||||
// DskBlk2.HC
|
||||
|
||||
Bool BlkRead2(CDrv* dv, U8* buf, I64 blk, I64 cnt)
|
||||
{ // Read blk cnt from Drv to buf.
|
||||
Bool res = TRUE, unlock;
|
||||
CBlkDev* bd = dv->bd;
|
||||
if (cnt <= 0)
|
||||
return TRUE;
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock = DrvLock(dv);
|
||||
CallExtStr("BlkDevInit", bd);
|
||||
if (dv->drv_offset && blk < dv->drv_offset || blk + cnt > dv->drv_offset + dv->size)
|
||||
throw('Drv');
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
CallExtStr("RCache", dv, &buf, &blk, &cnt);
|
||||
if (cnt > 0) {
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
MemCpy(buf, bd->RAM_dsk + blk << BLK_SIZE_BITS, cnt << BLK_SIZE_BITS);
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
FBlkRead(bd->file_dsk, buf, blk, cnt);
|
||||
break;
|
||||
case BDT_ATA:
|
||||
case BDT_ATAPI:
|
||||
res = CallExtStr("ATARBlks", dv, buf, blk, cnt);
|
||||
break;
|
||||
case BDT_VIRTIO_BLK:
|
||||
res = VIORBlks(dv, buf, blk, cnt);
|
||||
break;
|
||||
}
|
||||
bd->last_time = tS;
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
CallExtStr("DskCacheAdd", dv, buf, blk, cnt);
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool BlkWrite2(CDrv* dv, U8* buf, I64 blk, I64 cnt)
|
||||
{ // Write blk cnt from buf to Drv.
|
||||
Bool res = TRUE, unlock;
|
||||
CBlkDev* bd = dv->bd;
|
||||
if (cnt <= 0)
|
||||
return TRUE;
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock = DrvLock(dv);
|
||||
CallExtStr("BlkDevInit", bd);
|
||||
if (bd->flags & BDF_READ_ONLY && !(bd->flags & BDF_READ_ONLY_OVERRIDE))
|
||||
throw('BlkDev');
|
||||
if (dv->drv_offset && blk < dv->drv_offset || blk + cnt > dv->drv_offset + dv->size)
|
||||
throw('Drv');
|
||||
if (cnt > 0) {
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
MemCpy(bd->RAM_dsk + blk << BLK_SIZE_BITS, buf, cnt << BLK_SIZE_BITS);
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
FBlkWrite(bd->file_dsk, buf, blk, cnt);
|
||||
break;
|
||||
case BDT_ATA:
|
||||
case BDT_ATAPI:
|
||||
res = CallExtStr("ATAWBlks", dv, buf, blk, cnt);
|
||||
break;
|
||||
case BDT_VIRTIO_BLK:
|
||||
res = VIOWBlks(dv, buf, blk, cnt);
|
||||
break;
|
||||
}
|
||||
bd->last_time = tS;
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
CallExtStr("DskCacheAdd", dv, buf, blk, cnt);
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
@patch_jmp_rel32(&BlkRead, &BlkRead2);
|
||||
@patch_jmp_rel32(&BlkWrite, &BlkWrite2);
|
||||
|
||||
// DskBlkDev2.HC
|
||||
|
||||
CBlkDev* BlkDevChk2(CBlkDev* bd, Bool except = TRUE)
|
||||
{ // Check for valid BlkDev. Throw exception.
|
||||
if (bd->type == BDT_VIRTIO_BLK)
|
||||
return bd;
|
||||
if (!bd || bd->bd_signature != BD_SIGNATURE_VAL || !(BDT_NULL < bd->type < BDT_TYPES_NUM)) {
|
||||
if (except)
|
||||
throw('BlkDev');
|
||||
else
|
||||
return NULL;
|
||||
} else
|
||||
return bd;
|
||||
}
|
||||
|
||||
@patch_jmp_rel32(&BlkDevChk, &BlkDevChk2);
|
||||
|
||||
// DskDrv2.HC
|
||||
|
||||
DefineLstLoad("ST_BLKDEV_TYPES2",
|
||||
"NULL\0RAM\0ATA\0FILE_READ\0FILE_WRITE\0ATAPI\0NULL\0NULL\0NULL\0NULL\0VIRTIO\0");
|
||||
|
||||
U8 DrvTextAttrGet2(U8 drv_let = 0)
|
||||
{ // Get color of drive.
|
||||
U8* blkdev_text_attr2 = blkdev_text_attr;
|
||||
U8* drv_text_attr2 = drv_text_attr;
|
||||
I64 dta_size = 3;
|
||||
drv_let = Let2Let(drv_let);
|
||||
if (drv_let == 'A')
|
||||
return BLACK << 4 | WHITE;
|
||||
if ('A' <= drv_let <= 'Z')
|
||||
return blkdev_text_attr2[Let2BlkDevType(drv_let)] << 4 | drv_text_attr2[drv_let % dta_size];
|
||||
else
|
||||
return BLACK << 4 | WHITE;
|
||||
}
|
||||
|
||||
U0 DrvRep2()
|
||||
{ // Drive report.
|
||||
CDrv* dv;
|
||||
CBlkDev* bd;
|
||||
I64 ch, i, drv_let, attr;
|
||||
U8* st;
|
||||
"\nDefined Drives:\n";
|
||||
for (i = 0, dv = blkdev.drvs; i < DRVS_NUM; i++, dv++) {
|
||||
if (dv->dv_signature == DRV_SIGNATURE_VAL) {
|
||||
bd = dv->bd;
|
||||
drv_let = Drv2Let(dv);
|
||||
if (Bt(&dv->fs_type, FStf_DISABLE))
|
||||
ch = '-';
|
||||
else if (drv_let == blkdev.boot_drv_let)
|
||||
ch = ':';
|
||||
else
|
||||
ch = '+';
|
||||
attr = DrvTextAttrGet(drv_let);
|
||||
"\dFG,%d\d\dBG,%d\d%C %-8Z %-10Z %04X %04X %02X\n",
|
||||
attr & 15, attr >> 4, drv_let, dv->fs_type &FSG_TYPE_MASK, "ST_DRV_TYPES",
|
||||
bd->type, "ST_BLKDEV_TYPES2", bd->base0, bd->base1, bd->unit;
|
||||
if (st = DrvModelNum(drv_let)) {
|
||||
"Model#:%s\n", st;
|
||||
Free(st);
|
||||
}
|
||||
if (st = DrvSerialNum(drv_let)) {
|
||||
"Serial#:%s\n", st;
|
||||
Free(st);
|
||||
}
|
||||
if (bd->type == BDT_ISO_FILE_READ || bd->type == BDT_ISO_FILE_WRITE)
|
||||
"File=\"%s\"\n", bd->file_dsk_name;
|
||||
"%016X-%016X\n\dFG\d\dBG\d", dv->drv_offset, dv->drv_offset + dv->size - 1;
|
||||
}
|
||||
}
|
||||
"Home Dir:\"%s\"\n", blkdev.home_dir;
|
||||
}
|
||||
|
||||
@patch_jmp_rel32(&DrvTextAttrGet, &DrvTextAttrGet2);
|
||||
@patch_jmp_rel32(&DrvRep, &DrvRep2);
|
||||
|
||||
VirtioBlkInit;
|
||||
MountVirtioBlk;
|
||||
|
||||
if (Let2Drv('A', 0) && !Let2Drv('A')->root_clus) {
|
||||
"[virtio-blk] RedSea filesystem not initialized, formatting.\n";
|
||||
Fmt('A', , FALSE, FSt_REDSEA);
|
||||
Cd("M:/System/");
|
||||
}
|
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; }
|
301
System/FFI/ELF64.HC
Normal file
301
System/FFI/ELF64.HC
Normal file
|
@ -0,0 +1,301 @@
|
|||
#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;
|
||||
}
|
317
System/FFI/LibC.HC
Normal file
317
System/FFI/LibC.HC
Normal file
|
@ -0,0 +1,317 @@
|
|||
#define stdin 0
|
||||
#define stdout 1
|
||||
#define stderr 2
|
||||
|
||||
U0 bcmp()
|
||||
{
|
||||
PUSH_SYSV_REGS
|
||||
GET_SYSV_ARGS
|
||||
MemCmp(p0, p1, p2);
|
||||
POP_SYSV_REGS
|
||||
}
|
||||
|
||||
U0 calloc()
|
||||
{
|
||||
PUSH_SYSV_REGS
|
||||
GET_SYSV_ARGS
|
||||
CAlloc(p0 * p1, adam_task->code_heap);
|
||||
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
|
||||
}
|
||||
|
||||
U0 malloc()
|
||||
{
|
||||
PUSH_SYSV_REGS
|
||||
GET_SYSV_ARGS
|
||||
MAlloc(p0, adam_task->code_heap);
|
||||
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
|
||||
}
|
289
System/Jakt/OS.HC
Normal file
289
System/Jakt/OS.HC
Normal file
|
@ -0,0 +1,289 @@
|
|||
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(U8* function_name, U64 arg)
|
||||
{
|
||||
if (!function_name)
|
||||
return NULL;
|
||||
if (!StrLen(function_name))
|
||||
return NULL;
|
||||
CHash* h = HashFind(function_name, Fs->hash_table, Fs->hash_table->mask);
|
||||
if (!h)
|
||||
return NULL;
|
||||
if (h->type & HTT_FUN == HTT_FUN) {
|
||||
CallInd(h(CHashFun*)->exe_addr, arg);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
88
System/Libraries/Base64.HC
Normal file
88
System/Libraries/Base64.HC
Normal file
|
@ -0,0 +1,88 @@
|
|||
|
||||
U8* @base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
U8* @base64_decode(U8* input, I64* output_length)
|
||||
{
|
||||
I64 input_length = StrLen(input);
|
||||
if (input_length % 4 != 0) {
|
||||
return NULL; // Invalid Base64 input length
|
||||
}
|
||||
|
||||
// Calculate the expected output length
|
||||
*output_length = (3 * input_length) / 4;
|
||||
if (input[input_length - 1] == '=') {
|
||||
(*output_length)--;
|
||||
}
|
||||
if (input[input_length - 2] == '=') {
|
||||
(*output_length)--;
|
||||
}
|
||||
|
||||
// Allocate memory for the decoded data
|
||||
U8* decoded_data = CAlloc(*output_length, adam_task);
|
||||
if (decoded_data == NULL) {
|
||||
return NULL; // Memory allocation failed
|
||||
}
|
||||
|
||||
// Initialize variables for decoding process
|
||||
I32 i, j = 0;
|
||||
U32 sextet_bits = 0;
|
||||
I64 sextet_count = 0;
|
||||
U32 base64_value;
|
||||
U8* char_pointer;
|
||||
U8 input_find_buf[2];
|
||||
input_find_buf[1] = NULL;
|
||||
|
||||
// Loop through the Base64 input and decode it
|
||||
for (i = 0; i < input_length; i++) {
|
||||
// Convert Base64 character to a 6-bit value
|
||||
base64_value = 0;
|
||||
if (input[i] == '=') {
|
||||
base64_value = 0;
|
||||
} else {
|
||||
input_find_buf[0] = input[i];
|
||||
char_pointer = StrFirstOcc(@base64_chars, input_find_buf);
|
||||
if (char_pointer == NULL) {
|
||||
Free(decoded_data);
|
||||
return NULL; // Invalid Base64 character
|
||||
}
|
||||
base64_value = char_pointer - @base64_chars;
|
||||
}
|
||||
|
||||
// Combine 6-bit values into a 24-bit sextet
|
||||
sextet_bits = (sextet_bits << 6) | base64_value;
|
||||
sextet_count++;
|
||||
|
||||
// When a sextet is complete, decode it into three bytes
|
||||
if (sextet_count == 4) {
|
||||
decoded_data[j++] = (sextet_bits >> 16) & 0xFF;
|
||||
decoded_data[j++] = (sextet_bits >> 8) & 0xFF;
|
||||
decoded_data[j++] = sextet_bits & 0xFF;
|
||||
sextet_bits = 0;
|
||||
sextet_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return decoded_data;
|
||||
}
|
||||
|
||||
U8* @base64_encode(U8* input, I64 input_length)
|
||||
{
|
||||
I64 i;
|
||||
U8 buf[3];
|
||||
I64 c = 0;
|
||||
U8* output = CAlloc(input_length * 2, adam_task);
|
||||
|
||||
for (i = 0; i < input_length; i += 3) {
|
||||
buf[0] = input[i];
|
||||
buf[1] = @t((i + 1 < input_length), input[i + 1], 0);
|
||||
buf[2] = @t((i + 2 < input_length), input[i + 2], 0);
|
||||
|
||||
output[c++] = @base64_chars[(buf[0] & 0xfc) >> 2];
|
||||
output[c++] = @base64_chars[((buf[0] & 0x03) << 4) + ((buf[1] & 0xf0) >> 4)];
|
||||
output[c++] = @t((i + 1 < input_length), @base64_chars[((buf[1] & 0x0f) << 2) + ((buf[2] & 0xc0) >> 6)], '=');
|
||||
output[c++] = @t((i + 2 < input_length), @base64_chars[buf[2] & 0x3f], '=');
|
||||
}
|
||||
|
||||
output[c] = '\0';
|
||||
return output;
|
||||
}
|
628
System/Libraries/Http.HC
Normal file
628
System/Libraries/Http.HC
Normal file
|
@ -0,0 +1,628 @@
|
|||
#define HTTP_TMP_DIRECTORY "B:/Tmp"
|
||||
#define HTTP_CACHE_DIRECTORY "B:/Tmp/Cache"
|
||||
#define HTTP_FETCH_BUFFER_SIZE 1024 << 15
|
||||
|
||||
#define SEDECIM_USER_AGENT_STRING "Mozilla/5.0 (compatible; Sedecim/1.0; TempleOS) (KHTML, like Gecko)"
|
||||
|
||||
class @http_buffer
|
||||
{
|
||||
I64 length;
|
||||
U8* data;
|
||||
};
|
||||
|
||||
class @http_status
|
||||
{
|
||||
U8* protocol;
|
||||
I64 code;
|
||||
U8* text;
|
||||
};
|
||||
|
||||
class @http_response
|
||||
{
|
||||
I64 state;
|
||||
TlsSocket* s;
|
||||
@http_status status;
|
||||
JsonObject* headers;
|
||||
@http_buffer body;
|
||||
Bool headers_parsed;
|
||||
};
|
||||
|
||||
class @http_url
|
||||
{
|
||||
U8* scheme;
|
||||
U8* host;
|
||||
I64 port;
|
||||
U8* path;
|
||||
U8* query;
|
||||
U8* fragment;
|
||||
};
|
||||
|
||||
class @http_request
|
||||
{
|
||||
@http_url* url;
|
||||
U8* buf;
|
||||
U8* data;
|
||||
I64 type;
|
||||
JsonObject* headers;
|
||||
@http_response* response;
|
||||
};
|
||||
|
||||
#define HttpResponse @http_response
|
||||
#define HttpUrl @http_url
|
||||
|
||||
#define HTTP_FETCH_BUFFER_SIZE 16777216
|
||||
|
||||
#define HTTP_PARSE_SCHEME 0
|
||||
#define HTTP_PARSE_SCHEME_FS 1
|
||||
#define HTTP_PARSE_HOST 2
|
||||
#define HTTP_PARSE_PORT 3
|
||||
#define HTTP_PARSE_PATH 4
|
||||
#define HTTP_PARSE_QUERY 5
|
||||
#define HTTP_PARSE_FRAGMENT 6
|
||||
|
||||
#define HTTP_MIN_REQUEST_BUFFER_SIZE 16384
|
||||
#define HTTP_PARSE_URL_FIFO_SIZE 1024
|
||||
|
||||
#define HTTP_REQ_GET 0
|
||||
#define HTTP_REQ_HEAD 1
|
||||
#define HTTP_REQ_POST 2
|
||||
#define HTTP_REQ_PUT 3
|
||||
|
||||
#define HTTP_STATE_UNSENT 0
|
||||
#define HTTP_STATE_OPENED 1
|
||||
#define HTTP_STATE_HEADERS_RECEIVED 2
|
||||
#define HTTP_STATE_LOADING 3
|
||||
#define HTTP_STATE_DONE 4
|
||||
|
||||
U8* @http_string_from_fifo(CFifoU8* f)
|
||||
{
|
||||
U8 ch;
|
||||
I64 i = 0;
|
||||
U8* str = CAlloc(FifoU8Cnt(f) + 1, adam_task);
|
||||
while (FifoU8Cnt(f)) {
|
||||
FifoU8Rem(f, &ch);
|
||||
str[i] = ch;
|
||||
i++;
|
||||
}
|
||||
FifoU8Flush(f);
|
||||
return str;
|
||||
}
|
||||
|
||||
U0 @http_free_url(@http_url* url)
|
||||
{
|
||||
if (!url)
|
||||
return;
|
||||
if (url->scheme)
|
||||
Free(url->scheme);
|
||||
if (url->host)
|
||||
Free(url->host);
|
||||
if (url->path)
|
||||
Free(url->path);
|
||||
if (url->query)
|
||||
Free(url->query);
|
||||
if (url->fragment)
|
||||
Free(url->fragment);
|
||||
Free(url);
|
||||
}
|
||||
|
||||
U0 @http_free_response(@http_response* resp)
|
||||
{
|
||||
if (!resp)
|
||||
return;
|
||||
// FIXME: Free response headers JSON object
|
||||
Free(resp);
|
||||
}
|
||||
|
||||
@http_url* @http_parse_url(U8* str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
U8* buf = NULL;
|
||||
U8 hex[3];
|
||||
I64 i = 0;
|
||||
I64 state = HTTP_PARSE_SCHEME;
|
||||
CFifoU8* consume_fifo = FifoU8New(HTTP_PARSE_URL_FIFO_SIZE, adam_task);
|
||||
@http_url* url = CAlloc(sizeof(@http_url), adam_task);
|
||||
while (1) {
|
||||
switch (str[i]) {
|
||||
case 0:
|
||||
switch (state) {
|
||||
case HTTP_PARSE_HOST:
|
||||
url->host = @http_string_from_fifo(consume_fifo);
|
||||
url->path = StrNew("/", adam_task);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_PORT:
|
||||
buf = @http_string_from_fifo(consume_fifo);
|
||||
url->port = Str2I64(buf);
|
||||
Free(buf);
|
||||
url->path = StrNew("/", adam_task);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_PATH:
|
||||
url->path = @http_string_from_fifo(consume_fifo);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_QUERY:
|
||||
url->query = @http_string_from_fifo(consume_fifo);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_FRAGMENT:
|
||||
url->fragment = @http_string_from_fifo(consume_fifo);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
default:
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_PATH:
|
||||
url->path = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_FRAGMENT;
|
||||
break;
|
||||
case HTTP_PARSE_QUERY:
|
||||
url->query = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_FRAGMENT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_PATH:
|
||||
url->path = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_QUERY;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_SCHEME:
|
||||
state = HTTP_PARSE_SCHEME_FS;
|
||||
goto keep_consuming_url_chars;
|
||||
break;
|
||||
case HTTP_PARSE_SCHEME_FS:
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
url->scheme = @http_string_from_fifo(consume_fifo);
|
||||
if (!StrCmp(url->scheme, "http://"))
|
||||
url->port = 80;
|
||||
if (!StrCmp(url->scheme, "https://"))
|
||||
url->port = 443;
|
||||
state = HTTP_PARSE_HOST;
|
||||
break;
|
||||
case HTTP_PARSE_HOST:
|
||||
url->host = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_PATH;
|
||||
break;
|
||||
case HTTP_PARSE_PORT:
|
||||
buf = @http_string_from_fifo(consume_fifo);
|
||||
url->port = Str2I64(buf);
|
||||
Free(buf);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_PATH;
|
||||
break;
|
||||
case HTTP_PARSE_PATH:
|
||||
goto keep_consuming_url_chars;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_SCHEME:
|
||||
case HTTP_PARSE_PATH:
|
||||
case HTTP_PARSE_QUERY:
|
||||
case HTTP_PARSE_FRAGMENT:
|
||||
goto keep_consuming_url_chars;
|
||||
break;
|
||||
case HTTP_PARSE_HOST:
|
||||
url->host = @http_string_from_fifo(consume_fifo);
|
||||
state = HTTP_PARSE_PORT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
keep_consuming_url_chars:
|
||||
switch (state) {
|
||||
case HTTP_PARSE_PATH:
|
||||
case HTTP_PARSE_QUERY:
|
||||
switch (str[i]) {
|
||||
case '0' ... '9':
|
||||
case 'A' ... 'Z':
|
||||
case 'a' ... 'z':
|
||||
case '?':
|
||||
case '&':
|
||||
case '/':
|
||||
case '=':
|
||||
// !'()*-._~
|
||||
case '!':
|
||||
case '\'':
|
||||
case '(':
|
||||
case ')':
|
||||
case '*':
|
||||
case '-':
|
||||
case '.':
|
||||
case '_':
|
||||
case '~':
|
||||
case '%':
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
break;
|
||||
default:
|
||||
FifoU8Ins(consume_fifo, '%');
|
||||
StrPrint(hex, "%02X", str[i]);
|
||||
FifoU8Ins(consume_fifo, hex[0]);
|
||||
FifoU8Ins(consume_fifo, hex[1]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
done_parsing_url:
|
||||
FifoU8Flush(consume_fifo);
|
||||
FifoU8Del(consume_fifo);
|
||||
return url;
|
||||
}
|
||||
|
||||
U0 @http_parse_response_headers(@http_response* resp, U8* buffer, I64 length)
|
||||
{
|
||||
if (!resp || !buffer || !length)
|
||||
return;
|
||||
U64 response_data_ptr = StrFind("\r\n\r\n", buffer);
|
||||
if (!response_data_ptr)
|
||||
return;
|
||||
resp->body.data = response_data_ptr + 4;
|
||||
resp->body.data[-4] = NULL;
|
||||
JsonObject* headers = Json.CreateObject();
|
||||
U8** lines = NULL;
|
||||
I64 lines_count = 0;
|
||||
I64 i;
|
||||
I64 j;
|
||||
U8* key_ptr = NULL;
|
||||
U8* value_ptr = NULL;
|
||||
lines = String.Split(buffer, '\n', &lines_count);
|
||||
|
||||
U8* resp_protocol = lines[0];
|
||||
U8* resp_status_code = StrFind(" ", resp_protocol) + 1;
|
||||
U8* resp_text = StrFind(" ", resp_status_code + 1);
|
||||
(*StrFind(" ", resp_protocol)) = NULL;
|
||||
(*StrFind(" ", resp_status_code)) = NULL;
|
||||
|
||||
resp->status.protocol = StrNew(resp_protocol, adam_task);
|
||||
resp->status.code = Str2I64(resp_status_code);
|
||||
resp->status.text = StrNew(resp_text, adam_task);
|
||||
|
||||
for (i = 1; i < lines_count; i++) {
|
||||
for (j = 0; j < StrLen(lines[i]); j++) {
|
||||
if (lines[i][j] == ':' && lines[i][j + 1] == ' ') {
|
||||
lines[i][j] = NULL;
|
||||
key_ptr = lines[i];
|
||||
value_ptr = lines[i] + j + 2;
|
||||
(*StrFind("\r", value_ptr)) = NULL;
|
||||
Json.Set(headers, key_ptr, StrNew(value_ptr, adam_task), JSON_STRING);
|
||||
goto @http_next_header_line;
|
||||
}
|
||||
}
|
||||
@http_next_header_line:
|
||||
}
|
||||
resp->headers = headers;
|
||||
resp->headers_parsed = TRUE;
|
||||
}
|
||||
|
||||
Bool @http_detect_response_headers(U8* buf, I64 len)
|
||||
{
|
||||
if (len < 4)
|
||||
return FALSE;
|
||||
I64 i;
|
||||
for (i = 0; i < len - 4; i++) {
|
||||
if (!MemCmp(buf + i, "\r\n\r\n", 4))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 @http_req(@http_request* req)
|
||||
{
|
||||
if (!req)
|
||||
return NULL;
|
||||
if (!req->url || !req->buf || !req->response)
|
||||
return NULL;
|
||||
if (!req->url->scheme || !req->url->host || !req->url->path)
|
||||
return NULL;
|
||||
if (req->type == HTTP_REQ_POST && !req->data)
|
||||
return NULL;
|
||||
if (req->type == HTTP_REQ_PUT && !req->data)
|
||||
return NULL;
|
||||
|
||||
@http_response* resp = req->response;
|
||||
|
||||
U8* buf = NULL;
|
||||
U8* headers_buf = "";
|
||||
I64 cnt = 1;
|
||||
I64 len = NULL;
|
||||
|
||||
buf = CAlloc(HTTP_MIN_REQUEST_BUFFER_SIZE, adam_task);
|
||||
if (req->headers) {
|
||||
headers_buf = CAlloc(HTTP_MIN_REQUEST_BUFFER_SIZE, adam_task);
|
||||
JsonKey* key = req->headers->keys;
|
||||
while (key) {
|
||||
StrPrint(headers_buf + StrLen(headers_buf), "%s: %s\r\n", key->name, key->value);
|
||||
key = key->next;
|
||||
}
|
||||
}
|
||||
|
||||
switch (req->type) {
|
||||
case HTTP_REQ_GET:
|
||||
StrPrint(buf,
|
||||
"GET %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf);
|
||||
break;
|
||||
case HTTP_REQ_HEAD:
|
||||
StrPrint(buf,
|
||||
"HEAD %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf);
|
||||
break;
|
||||
case HTTP_REQ_POST:
|
||||
StrPrint(buf,
|
||||
"POST %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n"
|
||||
"Content-Length: %d\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf,
|
||||
StrLen(req->data));
|
||||
StrPrint(buf + StrLen(buf), req->data);
|
||||
break;
|
||||
case HTTP_REQ_PUT:
|
||||
StrPrint(buf,
|
||||
"PUT %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n"
|
||||
"Content-Length: %d\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf,
|
||||
StrLen(req->data));
|
||||
StrPrint(buf + StrLen(buf), req->data);
|
||||
break;
|
||||
}
|
||||
|
||||
TlsSocket* s = NULL;
|
||||
resp->s = NULL;
|
||||
|
||||
if (!StrCmp(req->url->scheme, "http://")) {
|
||||
s = @tcp_socket_create(req->url->host, req->url->port);
|
||||
resp->s = s;
|
||||
while (s->state != TCP_SOCKET_STATE_ESTABLISHED)
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
if (!StrCmp(req->url->scheme, "https://")) {
|
||||
s = @tls_socket_create(req->url->host, req->url->port);
|
||||
resp->s = s;
|
||||
while (!@tls_established(s->ctx))
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
resp->state = HTTP_STATE_OPENED;
|
||||
s->send(buf, StrLen(buf));
|
||||
while (cnt || s->state != TCP_SOCKET_STATE_CLOSED) {
|
||||
cnt = s->receive(req->buf + len, 1024);
|
||||
len += cnt;
|
||||
switch (resp->state) {
|
||||
case HTTP_STATE_LOADING:
|
||||
resp->body.length += cnt;
|
||||
break;
|
||||
case HTTP_STATE_HEADERS_RECEIVED:
|
||||
resp->body.length = (req->buf + len) - resp->body.data;
|
||||
resp->state = HTTP_STATE_LOADING;
|
||||
break;
|
||||
case HTTP_STATE_OPENED:
|
||||
if (@http_detect_response_headers(req->buf, len)) {
|
||||
@http_parse_response_headers(resp, req->buf, len);
|
||||
resp->state = HTTP_STATE_HEADERS_RECEIVED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
if (!resp->headers_parsed)
|
||||
@http_parse_response_headers(resp, req->buf, len);
|
||||
resp->state = HTTP_STATE_DONE;
|
||||
req->buf[len] = NULL;
|
||||
Free(buf);
|
||||
if (StrLen(headers_buf) > 0) {
|
||||
Free(headers_buf);
|
||||
}
|
||||
s->close();
|
||||
resp->s = NULL;
|
||||
Free(req);
|
||||
return len;
|
||||
}
|
||||
|
||||
Bool @http_scheme_is_https(@http_url* url)
|
||||
{
|
||||
if (!url || !url->scheme)
|
||||
return FALSE;
|
||||
return !MemCmp(url->scheme, "https", 5);
|
||||
}
|
||||
|
||||
@http_response* @http_get(@http_url* url, U8* buf, U64 return_req = NULL, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), adam_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), adam_task);
|
||||
if (return_req)
|
||||
MemCpy(return_req, &req, sizeof(U64));
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_GET;
|
||||
req->headers = headers;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPGetRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
@http_response* @http_head(@http_url* url, U8* buf, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), adam_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), adam_task);
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_HEAD;
|
||||
req->headers = headers;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPHeadRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
@http_response* @http_post(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), adam_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), adam_task);
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_POST;
|
||||
req->headers = headers;
|
||||
req->data = data;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPPostRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
@http_response* @http_put(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), adam_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), adam_task);
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_PUT;
|
||||
req->headers = headers;
|
||||
req->data = data;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPPutRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
class @http
|
||||
{
|
||||
@http_response* (*Get)(@http_url* url, U8* buf, U64* req = NULL, JsonObject* headers = NULL);
|
||||
@http_response* (*Head)(@http_url* url, U8* buf, JsonObject* headers = NULL);
|
||||
@http_response* (*Post)(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL);
|
||||
@http_response* (*Put)(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL);
|
||||
};
|
||||
|
||||
@http Http;
|
||||
|
||||
Http.Get = &@http_get;
|
||||
Http.Head = &@http_head;
|
||||
Http.Post = &@http_post;
|
||||
Http.Put = &@http_put;
|
||||
|
||||
Bool @http_is_resource_cached(U8* src, U8* cache_directory = HTTP_CACHE_DIRECTORY)
|
||||
{
|
||||
U8 buf[512];
|
||||
U8* src_md5 = md5_string(src, StrLen(src));
|
||||
StrCpy(buf, cache_directory);
|
||||
StrPrint(buf + StrLen(buf), "/%s", src_md5);
|
||||
Free(src_md5);
|
||||
return FileFind(buf);
|
||||
}
|
||||
|
||||
U0 @http_cache_resource(U8* src, U8* data, I64 size, U8* cache_directory = HTTP_CACHE_DIRECTORY)
|
||||
{
|
||||
U8 buf[512];
|
||||
U8* src_md5 = md5_string(src, StrLen(src));
|
||||
StrCpy(buf, cache_directory);
|
||||
StrPrint(buf + StrLen(buf), "/%s", src_md5);
|
||||
Free(src_md5);
|
||||
FileWrite(buf, data, size);
|
||||
}
|
||||
|
||||
U8* @http_get_cached_resource_filename(U8* src, U8* cache_directory = HTTP_CACHE_DIRECTORY)
|
||||
{
|
||||
U8* buf = CAlloc(512, adam_task);
|
||||
U8* src_md5 = md5_string(src, StrLen(src));
|
||||
StrCpy(buf, cache_directory);
|
||||
StrPrint(buf + StrLen(buf), "/%s", src_md5);
|
||||
Free(src_md5);
|
||||
return buf;
|
||||
}
|
||||
|
||||
U0 @http_init_tmp_and_cache_directories()
|
||||
{
|
||||
if (!FileFind(HTTP_TMP_DIRECTORY))
|
||||
DirMk(HTTP_TMP_DIRECTORY);
|
||||
if (!FileFind(HTTP_CACHE_DIRECTORY))
|
||||
DirMk(HTTP_CACHE_DIRECTORY);
|
||||
}
|
||||
|
||||
@http_response* fetch(U8* url_string, U8* fetch_buffer)
|
||||
{
|
||||
if (!url_string || !fetch_buffer)
|
||||
return NULL;
|
||||
HttpUrl* url = @http_parse_url(url_string);
|
||||
if (!url)
|
||||
return NULL;
|
||||
@http_response* resp = Http.Get(url, fetch_buffer);
|
||||
while (resp->state != HTTP_STATE_DONE)
|
||||
Sleep(1);
|
||||
return resp;
|
||||
}
|
||||
|
||||
I64 curl(U8* url_string)
|
||||
{
|
||||
if (!url_string)
|
||||
return 0;
|
||||
U8* fetch_buffer = CAlloc(HTTP_FETCH_BUFFER_SIZE, adam_task);
|
||||
@http_response* resp = fetch(url_string, fetch_buffer);
|
||||
if (!resp)
|
||||
return 0;
|
||||
if (resp->body.length) {
|
||||
U8* buf = resp->body.data;
|
||||
while (*buf) {
|
||||
if (*buf == '\d')
|
||||
"\d\d";
|
||||
else
|
||||
"%c", *buf;
|
||||
++buf;
|
||||
}
|
||||
"\n";
|
||||
}
|
||||
Free(fetch_buffer);
|
||||
return resp->body.length;
|
||||
}
|
||||
|
||||
I64 download(U8* path, U8* url_string)
|
||||
{
|
||||
if (!path || !url_string)
|
||||
return 0;
|
||||
U8* fetch_buffer = CAlloc(HTTP_FETCH_BUFFER_SIZE, adam_task);
|
||||
@http_response* resp = fetch(url_string, fetch_buffer);
|
||||
if (!resp)
|
||||
return 0;
|
||||
if (resp->body.length) {
|
||||
FileWrite(path, resp->body.data, resp->body.length);
|
||||
}
|
||||
Free(fetch_buffer);
|
||||
return resp->body.length;
|
||||
}
|
||||
|
||||
@http_init_tmp_and_cache_directories;
|
1354
System/Libraries/Json.HC
Normal file
1354
System/Libraries/Json.HC
Normal file
File diff suppressed because it is too large
Load diff
44
System/Libraries/Rsa.HC
Normal file
44
System/Libraries/Rsa.HC
Normal file
|
@ -0,0 +1,44 @@
|
|||
Silent(1); // This is needed to suppress "Function should return val" warnings for wrappers to non-HolyC functions
|
||||
|
||||
I64 @rsa_import(U8* der_bytes, I64 der_len, U64 key)
|
||||
{
|
||||
U64 reg RDI rdi = der_bytes;
|
||||
U64 reg RSI rsi = der_len;
|
||||
U64 reg RDX rdx = key;
|
||||
no_warn rdi, rsi, rdx;
|
||||
asm {
|
||||
MOV RAX, RSA_IMPORT
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I64 @rsa_create_signature(U8* sig, I64* siglen, U8* hash, I64 hashlen, U64 key)
|
||||
{
|
||||
U64 reg RDI rdi = sig;
|
||||
U64 reg RSI rsi = siglen;
|
||||
U64 reg RDX rdx = hash;
|
||||
U64 reg RCX rcx = hashlen;
|
||||
U64 reg R8 r8 = key;
|
||||
no_warn rdi, rsi, rdx, rcx, r8;
|
||||
asm {
|
||||
MOV RAX, RSA_CREATE_SIGNATURE
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I64 @rsa_verify_signature(U8* sig, I64 siglen, U8* hash, I64 hashlen, I32* stat, U64 key)
|
||||
{
|
||||
U64 reg RDI rdi = sig;
|
||||
U64 reg RSI rsi = siglen;
|
||||
U64 reg RDX rdx = hash;
|
||||
U64 reg RCX rcx = hashlen;
|
||||
U64 reg R8 r8 = stat;
|
||||
U64 reg R9 r9 = key;
|
||||
no_warn rdi, rsi, rdx, rcx, r8, r9;
|
||||
asm {
|
||||
MOV RAX, RSA_VERIFY_SIGNATURE
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
Silent(0);
|
233
System/Libraries/Sha256.HC
Normal file
233
System/Libraries/Sha256.HC
Normal file
|
@ -0,0 +1,233 @@
|
|||
#define CHUNK_SIZE 64
|
||||
#define TOTAL_LEN_LEN 8
|
||||
|
||||
/*
|
||||
* ABOUT bool: this file does not use bool in order to be as pre-C99 compatible
|
||||
* as possible.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Comments from pseudo-code at https://en.wikipedia.org/wiki/SHA-2 are
|
||||
* reproduced here. When useful for clarification, portions of the pseudo-code
|
||||
* are reproduced here too.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize array of round constants:
|
||||
* (first 32 bits of the fractional parts of the cube roots of the first 64
|
||||
* primes 2..311):
|
||||
*/
|
||||
U32 k[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
U32 _h[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
|
||||
|
||||
class buffer_state {
|
||||
U8* p;
|
||||
I32 len;
|
||||
I32 total_len;
|
||||
I32 single_one_delivered; /* bool */
|
||||
I32 total_len_delivered; /* bool */
|
||||
};
|
||||
|
||||
U32 right_rot(U32 value, U32 count)
|
||||
{
|
||||
/*
|
||||
* Defined behaviour in standard C for all count where 0 < count < 32,
|
||||
* which is what we need here.
|
||||
*/
|
||||
return value >> count | value << (32 - count);
|
||||
}
|
||||
|
||||
U0 init_buf_state(buffer_state* state, U8* input, I32 len)
|
||||
{
|
||||
state->p = input;
|
||||
state->len = len;
|
||||
state->total_len = len;
|
||||
state->single_one_delivered = 0;
|
||||
state->total_len_delivered = 0;
|
||||
}
|
||||
|
||||
/* Return value: bool */
|
||||
I32 calc_chunk(U8* chunk, buffer_state* state)
|
||||
{
|
||||
I32 space_in_chunk;
|
||||
|
||||
if (state->total_len_delivered) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state->len >= CHUNK_SIZE) {
|
||||
MemCpy(chunk, state->p, CHUNK_SIZE);
|
||||
state->p += CHUNK_SIZE;
|
||||
state->len -= CHUNK_SIZE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
MemCpy(chunk, state->p, state->len);
|
||||
chunk += state->len;
|
||||
space_in_chunk = CHUNK_SIZE - state->len;
|
||||
state->p += state->len;
|
||||
state->len = 0;
|
||||
|
||||
/* If we are here, space_in_chunk is one at minimum. */
|
||||
if (!state->single_one_delivered) {
|
||||
*chunk++ = 0x80;
|
||||
space_in_chunk -= 1;
|
||||
state->single_one_delivered = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now:
|
||||
* - either there is enough space left for the total length, and we can
|
||||
* conclude,
|
||||
* - or there is too little space left, and we have to pad the rest of this
|
||||
* chunk with zeroes. In the latter case, we will conclude at the next
|
||||
* invokation of this function.
|
||||
*/
|
||||
if (space_in_chunk >= TOTAL_LEN_LEN) {
|
||||
I32 left = space_in_chunk - TOTAL_LEN_LEN;
|
||||
I32 len = state->total_len;
|
||||
I32 i;
|
||||
MemSet(chunk, 0x00, left);
|
||||
chunk += left;
|
||||
|
||||
/* Storing of len * 8 as a big endian 64-bit without overflow. */
|
||||
chunk[7] = (len << 3);
|
||||
len >>= 5;
|
||||
for (i = 6; i >= 0; i--) {
|
||||
chunk[i] = len;
|
||||
len >>= 8;
|
||||
}
|
||||
state->total_len_delivered = 1;
|
||||
} else {
|
||||
MemSet(chunk, 0x00, space_in_chunk);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Limitations:
|
||||
* - Since input is a pointer in RAM, the data to hash should be in RAM, which
|
||||
* could be a problem for large data sizes.
|
||||
* - SHA algorithms theoretically operate on bit strings. However, this
|
||||
* implementation has no support for bit string lengths that are not multiples
|
||||
* of eight, and it really operates on arrays of bytes. In particular, the len
|
||||
* parameter is a number of bytes.
|
||||
*/
|
||||
U0 calc_sha_256(U8* hash, U8* input, I32 len)
|
||||
{
|
||||
/*
|
||||
* Note 1: All integers (expect indexes) are 32-bit U32 integers and addition
|
||||
* is calculated modulo 2^32. Note 2: For each round, there is one round
|
||||
* constant k[i] and one entry in the message schedule array w[i], 0 = i = 63
|
||||
* Note 3: The compression function uses 8 working variables, a through h
|
||||
* Note 4: Big-endian convention is used when expressing the constants in this
|
||||
* pseudocode, and when parsing message block data from bytes to words, for
|
||||
* example, the first word of the input message "abc" after padding is
|
||||
* 0x61626380
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize hash values:
|
||||
* (first 32 bits of the fractional parts of the square roots of the first 8
|
||||
* primes 2..19):
|
||||
*/
|
||||
|
||||
U32 h[8];
|
||||
U32 i, j;
|
||||
MemCpy(h, _h, sizeof(U32) * 8);
|
||||
|
||||
/* 512-bit chunks is what we will operate on. */
|
||||
U8 chunk[64];
|
||||
|
||||
buffer_state state;
|
||||
|
||||
init_buf_state(&state, input, len);
|
||||
|
||||
while (calc_chunk(chunk, &state)) {
|
||||
U32 ah[8];
|
||||
|
||||
U8* p = chunk;
|
||||
|
||||
/* Initialize working variables to current hash value: */
|
||||
for (i = 0; i < 8; i++)
|
||||
ah[i] = h[i];
|
||||
|
||||
/* Compression function main loop: */
|
||||
for (i = 0; i < 4; i++) {
|
||||
/*
|
||||
* The w-array is really w[64], but since we only need
|
||||
* 16 of them at a time, we save stack by calculating
|
||||
* 16 at a time.
|
||||
*
|
||||
* This optimization was not there initially and the
|
||||
* rest of the comments about w[64] are kept in their
|
||||
* initial state.
|
||||
*/
|
||||
|
||||
/*
|
||||
* create a 64-entry message schedule array w[0..63] of 32-bit words
|
||||
* (The initial values in w[0..63] don't matter, so many implementations
|
||||
* zero them here) copy chunk into first 16 words w[0..15] of the message
|
||||
* schedule array
|
||||
*/
|
||||
U32 w[16];
|
||||
|
||||
U32 s0, s1;
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (i == 0) {
|
||||
w[j] = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
|
||||
p += 4;
|
||||
} else {
|
||||
/* Extend the first 16 words into the remaining 48 words w[16..63] of
|
||||
* the message schedule array: */
|
||||
s0 = right_rot(w[(j + 1) & 0xf], 7) ^ right_rot(w[(j + 1) & 0xf], 18) ^ (w[(j + 1) & 0xf] >> 3);
|
||||
s1 = right_rot(w[(j + 14) & 0xf], 17) ^ right_rot(w[(j + 14) & 0xf], 19) ^ (w[(j + 14) & 0xf] >> 10);
|
||||
w[j] = w[j] + s0 + w[(j + 9) & 0xf] + s1;
|
||||
}
|
||||
s1 = right_rot(ah[4], 6) ^ right_rot(ah[4], 11) ^ right_rot(ah[4], 25);
|
||||
U32 ch = (ah[4] & ah[5]) ^ (~ah[4] & ah[6]);
|
||||
U32 temp1 = ah[7] + s1 + ch + k[i << 4 | j] + w[j];
|
||||
s0 = right_rot(ah[0], 2) ^ right_rot(ah[0], 13) ^ right_rot(ah[0], 22);
|
||||
U32 maj = (ah[0] & ah[1]) ^ (ah[0] & ah[2]) ^ (ah[1] & ah[2]);
|
||||
U32 temp2 = s0 + maj;
|
||||
|
||||
ah[7] = ah[6];
|
||||
ah[6] = ah[5];
|
||||
ah[5] = ah[4];
|
||||
ah[4] = ah[3] + temp1;
|
||||
ah[3] = ah[2];
|
||||
ah[2] = ah[1];
|
||||
ah[1] = ah[0];
|
||||
ah[0] = temp1 + temp2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the compressed chunk to the current hash value: */
|
||||
for (i = 0; i < 8; i++)
|
||||
h[i] += ah[i];
|
||||
}
|
||||
|
||||
/* Produce the final hash value (big-endian): */
|
||||
for (i = 0, j = 0; i < 8; i++) {
|
||||
hash[j++] = (h[i] >> 24);
|
||||
hash[j++] = (h[i] >> 16);
|
||||
hash[j++] = (h[i] >> 8);
|
||||
hash[j++] = h[i];
|
||||
}
|
||||
}
|
133
System/Libraries/String.HC
Normal file
133
System/Libraries/String.HC
Normal file
|
@ -0,0 +1,133 @@
|
|||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
class @string
|
||||
{
|
||||
U0(*Append)
|
||||
(U8 * dst, U8 * fmt, ...);
|
||||
Bool (*BeginsWith)(U8* fragment, U8* str);
|
||||
Bool (*EndsWith)(U8* fragment, U8* str);
|
||||
Bool (*IsNumber)(U8* s);
|
||||
U8* (*Replace)(U8* s, U8* oldW, U8* newW);
|
||||
U8** (*Split)(U8* s, U8 ch = '\n', I64 * cnt);
|
||||
};
|
||||
|
||||
@string String;
|
||||
String.Append = &@string_append;
|
||||
String.BeginsWith = &@string_begins_with;
|
||||
String.EndsWith = &@string_ends_with;
|
||||
String.IsNumber = &@string_is_number;
|
||||
String.Replace = &@string_replace;
|
||||
String.Split = &@string_split;
|
115
System/Libraries/Tlse.HC
Normal file
115
System/Libraries/Tlse.HC
Normal file
|
@ -0,0 +1,115 @@
|
|||
#define TLS_V12 0x0303
|
||||
|
||||
Silent(1); // This is needed to suppress "Function should return val" warnings for wrappers to non-HolyC functions
|
||||
|
||||
U64 @tls_create_context(U8 is_server, U16 version)
|
||||
{
|
||||
U64 reg RDI rdi = is_server;
|
||||
U64 reg RSI rsi = version;
|
||||
no_warn rdi, rsi;
|
||||
asm {
|
||||
MOV RAX, TLS_CREATE_CONTEXT
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_sni_set(U64 context, U8* sni)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = sni;
|
||||
no_warn rdi, rsi;
|
||||
asm {
|
||||
MOV RAX, TLS_SNI_SET
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_client_connect(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_CLIENT_CONNECT
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
U8* @tls_get_write_buffer(U64 context, U32* outlen)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = outlen;
|
||||
no_warn rdi, rsi;
|
||||
asm {
|
||||
MOV RAX, TLS_GET_WRITE_BUFFER
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
U0 @tls_buffer_clear(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_BUFFER_CLEAR
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_connection_status(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_CONNECTION_STATUS
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
U0 @tls_consume_stream(U64 context, U8* buf, I32 buf_len, U64 certificate_verify)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = buf;
|
||||
U64 reg RDX rdx = buf_len;
|
||||
U64 reg RCX rcx = certificate_verify;
|
||||
no_warn rdi, rsi, rdx, rcx;
|
||||
asm {
|
||||
MOV RAX, TLS_CONSUME_STREAM
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_read(U64 context, U8* buf, U32 size)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = buf;
|
||||
U64 reg RDX rdx = size;
|
||||
no_warn rdi, rsi, rdx;
|
||||
asm {
|
||||
MOV RAX, TLS_READ
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_write(U64 context, U8* data, U32 len)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = data;
|
||||
U64 reg RDX rdx = len;
|
||||
no_warn rdi, rsi, rdx;
|
||||
asm {
|
||||
MOV RAX, TLS_WRITE
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_established(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_ESTABLISHED
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
Silent(0);
|
56
System/MakeSystem.HC
Normal file
56
System/MakeSystem.HC
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* clang-format off */
|
||||
|
||||
DocMax(adam_task);
|
||||
WinMax(adam_task);
|
||||
WinToTop(adam_task);
|
||||
|
||||
#include "Setup/Environment";
|
||||
#include "Drivers/Virtio-blk";
|
||||
|
||||
// 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";
|
||||
|
||||
#include "Libraries/Tlse";
|
||||
load_elf("M:/build/bin/tlse");
|
||||
|
||||
// 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";
|
||||
|
||||
// Libraries
|
||||
#include "Libraries/Base64";
|
||||
#include "Libraries/Json";
|
||||
#include "Libraries/Rsa";
|
||||
#include "Libraries/Sha256";
|
||||
#include "Libraries/String";
|
||||
#include "Libraries/Http";
|
||||
|
||||
load_elf("M:/build/bin/net");
|
||||
|
||||
// Networking Utilities
|
||||
#include "Utilities/Dns";
|
||||
#include "Utilities/NetRep";
|
||||
#include "Utilities/Ping";
|
||||
#include "Utilities/Time";
|
||||
|
||||
Spawn(_start, , "Net Task");
|
||||
|
||||
/* clang-format on */
|
98
System/Setup/Environment.HC
Normal file
98
System/Setup/Environment.HC
Normal file
|
@ -0,0 +1,98 @@
|
|||
AutoComplete(0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
I64 @t(Bool _condition, I64 _true, I64 _false)
|
||||
{
|
||||
if (_condition)
|
||||
return _true;
|
||||
return _false;
|
||||
}
|
||||
|
||||
// Before doing anything else, 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);
|
||||
|
||||
// 3. Enable SSE
|
||||
@sse_enable;
|
||||
|
||||
U0 dd() { DocDump(adam_task->put_doc); }
|
||||
//@patch_jmp_rel32(&Dbg2, &Reboot); // Reboot instead of crashing to the debugger
|
||||
U0 NoBeep(I8, Bool) {};
|
||||
@patch_jmp_rel32(&Beep, &NoBeep); // Don't delay on beep when entering debugger
|
||||
|
||||
Bool BlkDevLock2(CBlkDev* bd)
|
||||
{
|
||||
BlkDevChk(bd);
|
||||
while (bd->lock_fwding)
|
||||
bd = bd->lock_fwding;
|
||||
if (!Bt(&bd->locked_flags, BDlf_LOCKED) || bd->owning_task != Fs) {
|
||||
while (LBts(&bd->locked_flags, BDlf_LOCKED))
|
||||
Sleep(Rand * 10);
|
||||
bd->owning_task = Fs;
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool DrvLock2(CDrv* dv)
|
||||
{
|
||||
DrvChk(dv);
|
||||
BlkDevLock2(dv->bd);
|
||||
if (!Bt(&dv->locked_flags, DVlf_LOCKED) || dv->owning_task != Fs) {
|
||||
while (LBts(&dv->locked_flags, DVlf_LOCKED))
|
||||
Sleep(Rand * 10);
|
||||
dv->owning_task = Fs;
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@patch_jmp_rel32(&BlkDevLock, &BlkDevLock2); // Patch BlkDevLock so we don't deadlock on multiple tasks reading from virtio disk
|
||||
@patch_jmp_rel32(&DrvLock, &DrvLock2); // Patch DrvLock so we don't deadlock on multiple tasks reading from virtio disk
|
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;
|
||||
}
|
112
System/Utilities/Time.HC
Normal file
112
System/Utilities/Time.HC
Normal file
|
@ -0,0 +1,112 @@
|
|||
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);
|
||||
}
|
||||
|
||||
Bool @time_in_dst()
|
||||
{
|
||||
CDateStruct ds;
|
||||
Date2Struct(&ds, Now);
|
||||
if (ds.mon > 3 && ds.mon < 11)
|
||||
return TRUE;
|
||||
if (ds.mon < 3 || ds.mon > 11)
|
||||
return FALSE;
|
||||
if (ds.mon == 3 && ds.day_of_mon != 8)
|
||||
return ds.day_of_mon > 8;
|
||||
if (ds.mon == 3)
|
||||
return ds.hour > 1;
|
||||
if (ds.mon == 11 && ds.day_of_mon != 1)
|
||||
return FALSE;
|
||||
if (ds.mon == 11)
|
||||
return ds.hour < 2;
|
||||
}
|
||||
|
||||
I64 @time_tz_offset()
|
||||
{
|
||||
if (@time_in_dst)
|
||||
return -4;
|
||||
return -5;
|
||||
}
|
||||
|
||||
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 ", Json.Get(resp->headers, "Date");
|
||||
if (!set)
|
||||
set = YorN;
|
||||
else
|
||||
"\n";
|
||||
if (set)
|
||||
@time_update(Json.Get(resp->headers, "Date"), mS_delta, @time_tz_offset);
|
||||
}
|
||||
|
||||
U0 TimeSync()
|
||||
{
|
||||
Sleep(500);
|
||||
@time_query(1);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue