mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-04-21 12:27:27 +03:00
add license; reorganize arch
This commit is contained in:
47
boot-programs/init.S
Normal file
47
boot-programs/init.S
Normal file
@@ -0,0 +1,47 @@
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// init.S: Startup code for initial Threads.
|
||||
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
.globl __start
|
||||
.set noreorder
|
||||
|
||||
__start:
|
||||
bal 1f
|
||||
.word _gp
|
||||
1:
|
||||
lw $gp, 0($ra)
|
||||
la $v0, __my_receiver
|
||||
sw $a0, ($v0)
|
||||
la $v0, __my_thread
|
||||
sw $a1, ($v0)
|
||||
la $v0, __my_memory
|
||||
sw $a2, ($v0)
|
||||
la $v0, __my_call
|
||||
sw $a3, ($v0)
|
||||
la $t9, main
|
||||
la $ra, 1f
|
||||
jr $t9
|
||||
nop
|
||||
|
||||
1:
|
||||
// This should not be reached: generate an address fault.
|
||||
b 1b
|
||||
lw $a0, -4($zero)
|
||||
|
||||
.comm __my_receiver, 4
|
||||
.comm __my_thread, 4
|
||||
.comm __my_memory, 4
|
||||
.comm __my_call, 4
|
||||
@@ -1,460 +0,0 @@
|
||||
#ifndef __SOS_H
|
||||
#define __SOS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define KERNEL_MASK 0xfff
|
||||
#define CAPTYPE_MASK 0xe00
|
||||
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
|
||||
#define CAPTYPE_RECEIVER 0x000
|
||||
#define CAPTYPE_MEMORY 0x200
|
||||
#define CAPTYPE_THREAD 0x400
|
||||
#define CAPTYPE_PAGE 0x600
|
||||
#define CAPTYPE_CAPABILITY 0x800
|
||||
#define CAPTYPE_CAPPAGE 0xa00
|
||||
/*#define CAPTYPE_??? 0xc00*/
|
||||
/*#define CAPTYPE_??? 0xe00*/
|
||||
|
||||
/* This works on all kernel capabilities. */
|
||||
#define CAP_DEGRADE 0
|
||||
|
||||
/* Operations */
|
||||
#define CAP_RECEIVER_SET_OWNER 1
|
||||
#define CAP_RECEIVER_CREATE_CAPABILITY 2
|
||||
#define CAP_RECEIVER_CREATE_CALL_CAPABILITY 3
|
||||
#define CAP_RECEIVER_GET_REPLY_PROTECTED_DATA 4
|
||||
#define CAP_RECEIVER_SET_REPLY_PROTECTED_DATA 5
|
||||
#define CAP_RECEIVER_ALL_RIGHTS 0x7f
|
||||
/* Not an operation; a capability with this bit set is a call capability. */
|
||||
#define CAP_RECEIVER_CALL 7
|
||||
/* Same thing for reply capability. */
|
||||
#define CAP_RECEIVER_REPLY 8
|
||||
/* If set on a call capability, waiting for only this reply is disabled. */
|
||||
#define CAP_RECEIVER_CALL_ASYNC 1
|
||||
|
||||
#define CAP_MEMORY_CREATE 1
|
||||
#define CAP_MEMORY_DESTROY 2
|
||||
#define CAP_MEMORY_LIST 3
|
||||
#define CAP_MEMORY_MAP 4
|
||||
#define CAP_MEMORY_MAPPING 5
|
||||
#define CAP_MEMORY_SET_LIMIT 6
|
||||
#define CAP_MEMORY_GET_LIMIT 7
|
||||
#define CAP_MEMORY_DROP 8
|
||||
#define CAP_MEMORY_ALL_RIGHTS 0x1ff
|
||||
|
||||
#define CAP_THREAD_INFO 1 /* Details of this are arch-specific. */
|
||||
#define CAP_THREAD_SCHEDULE 2
|
||||
#define CAP_THREAD_MAKE_PRIV 6
|
||||
#define CAP_THREAD_GET_TOP_MEMORY 7
|
||||
#define CAP_THREAD_REGISTER_INTERRUPT 8
|
||||
#define CAP_THREAD_ALL_RIGHTS 0x3f
|
||||
#define CAP_THREAD_ALL_PRIV_RIGHTS (CAP_THREAD_ALL_RIGHTS | (1 << CAP_THREAD_REGISTER_INTERRUPT) | (1 << CAP_THREAD_GET_TOP_MEMORY) | (1 << CAP_THREAD_MAKE_PRIV))
|
||||
|
||||
/* These get/set_info are not arch-specific. */
|
||||
#define CAP_THREAD_INFO_PC ~0
|
||||
#define CAP_THREAD_INFO_SP ~1
|
||||
#define CAP_THREAD_INFO_FLAGS ~2
|
||||
/* Flag values for processor state */
|
||||
#define THREAD_FLAG_PRIV 0x80000000
|
||||
#define THREAD_FLAG_WAITING 0x40000000
|
||||
#define THREAD_FLAG_RUNNING 0x20000000
|
||||
#define THREAD_FLAG_USER 0x1fffffff
|
||||
|
||||
#define CAP_PAGE_SHARE 1
|
||||
#define CAP_PAGE_FLAGS 2
|
||||
/* Not an operation; a capability without this bit cannot write to the page. */
|
||||
#define CAP_PAGE_WRITE 3
|
||||
#define CAP_PAGE_ALL_RIGHTS 0x1ff
|
||||
|
||||
/* Operation details for PAGE_SHARE */
|
||||
/* Forget the source page during the operation. This makes it a move. */
|
||||
#define PAGE_SHARE_FORGET 0x10000
|
||||
/* Make the target unwritable. */
|
||||
#define PAGE_SHARE_READONLY 0x20000
|
||||
/* Make the target independent of the source (make a copy if needed). */
|
||||
#define PAGE_SHARE_COPY 0x40000
|
||||
|
||||
/* Flag values for Page and Cappage objects. */
|
||||
/* A writable page can be written to. This flag can not be set while the frame is shared. */
|
||||
#define PAGE_FLAG_WRITABLE 1
|
||||
/* When paying, the memory's use is incremented if the page holds a frame. It cannot be lost. Frames are lost when the last payer forgets them. */
|
||||
#define PAGE_FLAG_PAYING 2
|
||||
/* Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems. */
|
||||
#define PAGE_FLAG_FRAME 4
|
||||
/* This is a read-only flag, which is set if the Page is shared. */
|
||||
#define PAGE_FLAG_SHARED 8
|
||||
|
||||
#define CAP_CAPABILITY_GET 1
|
||||
#define CAP_CAPABILITY_ALL_RIGHTS 0x1ff
|
||||
|
||||
#define CAPPAGE_SIZE 102
|
||||
/* Cappage has Page's operations as well. */
|
||||
#define CAP_CAPPAGE_SET 4
|
||||
#define CAP_CAPPAGE_ALL_RIGHTS 0x1ff
|
||||
|
||||
#ifndef __KERNEL
|
||||
typedef unsigned Capability;
|
||||
|
||||
extern Capability my_receiver;
|
||||
extern Capability my_thread;
|
||||
extern Capability my_memory;
|
||||
extern Capability my_call;
|
||||
|
||||
Capability cap_copy (Capability src)
|
||||
{
|
||||
return src | 2;
|
||||
}
|
||||
|
||||
typedef struct Message
|
||||
{
|
||||
unsigned data[4];
|
||||
Capability cap[4];
|
||||
} Message;
|
||||
|
||||
static int invoke (Capability target, Message *msg)
|
||||
{
|
||||
register int ret __asm__ ("v0");
|
||||
register unsigned v0 __asm__ ("v0") = target;
|
||||
register unsigned a0 __asm__ ("a0") = msg->cap[0];
|
||||
register unsigned a1 __asm__ ("a1") = msg->cap[1];
|
||||
register unsigned a2 __asm__ ("a2") = msg->cap[2];
|
||||
register unsigned a3 __asm__ ("a3") = msg->cap[3];
|
||||
register unsigned t0 __asm__ ("t0") = msg->data[0];
|
||||
register unsigned t1 __asm__ ("t1") = msg->data[1];
|
||||
register unsigned t2 __asm__ ("t2") = msg->data[2];
|
||||
register unsigned t3 __asm__ ("t3") = msg->data[3];
|
||||
__asm__ volatile ("syscall" : "+r" (v0), "=r" (a0), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (t0), "=r" (t1), "=r" (t2), "=r" (t3));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int call (Capability target, Message *msg)
|
||||
{
|
||||
register int ret __asm__ ("v0");
|
||||
register unsigned v0 __asm__ ("v0") = target;
|
||||
register unsigned a0 __asm__ ("a0") = msg->cap[0];
|
||||
register unsigned a1 __asm__ ("a1") = msg->cap[1];
|
||||
register unsigned a2 __asm__ ("a2") = msg->cap[2];
|
||||
register unsigned a3 __asm__ ("a3") = msg->cap[3];
|
||||
register unsigned t0 __asm__ ("t0") = msg->data[0];
|
||||
register unsigned t1 __asm__ ("t1") = msg->data[1];
|
||||
register unsigned t2 __asm__ ("t2") = msg->data[2];
|
||||
register unsigned t3 __asm__ ("t3") = msg->data[3];
|
||||
__asm__ volatile ("syscall" : "+r" (v0), "+r" (a0), "+r" (a1), "+r" (a2), "+r" (a3), "+r" (t0), "+r" (t1), "+r" (t2), "+r" (t3));
|
||||
msg->cap[0] = a0;
|
||||
msg->cap[1] = a1;
|
||||
msg->cap[2] = a2;
|
||||
msg->cap[3] = a3;
|
||||
msg->data[0] = t0;
|
||||
msg->data[1] = t1;
|
||||
msg->data[2] = t2;
|
||||
msg->data[3] = t3;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int invoke_01 (Capability t, unsigned d)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.data[0] = d;
|
||||
return invoke (t, &msg);
|
||||
}
|
||||
|
||||
static int invoke_02 (Capability t, unsigned d0, unsigned d1)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.data[0] = d0;
|
||||
msg.data[1] = d1;
|
||||
return invoke (t, &msg);
|
||||
}
|
||||
|
||||
static int invoke_04 (Capability t, unsigned d0, unsigned d1, unsigned d2, unsigned d3)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.data[0] = d0;
|
||||
msg.data[1] = d1;
|
||||
msg.data[2] = d2;
|
||||
msg.data[3] = d3;
|
||||
return invoke (t, &msg);
|
||||
}
|
||||
|
||||
static int invoke_11 (Capability t, Capability c, unsigned d)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.cap[0] = c;
|
||||
msg.data[0] = d;
|
||||
return invoke (t, &msg);
|
||||
}
|
||||
|
||||
static int invoke_12 (Capability t, Capability c, unsigned d0, unsigned d1)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.cap[0] = c;
|
||||
msg.data[0] = d0;
|
||||
msg.data[1] = d1;
|
||||
return invoke (t, &msg);
|
||||
}
|
||||
|
||||
static Capability call_c01 (Capability c, unsigned d)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.cap[0] = c;
|
||||
msg.data[0] = d;
|
||||
ret = call (my_call, &msg);
|
||||
return ret ? msg.cap[0] : 0;
|
||||
}
|
||||
|
||||
static Capability call_c02 (Capability c, unsigned d0, unsigned d1)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.cap[0] = c;
|
||||
msg.data[0] = d0;
|
||||
msg.data[1] = d1;
|
||||
ret = call (my_call, &msg);
|
||||
return ret ? msg.cap[0] : 0;
|
||||
}
|
||||
|
||||
static Capability call_c12 (Capability c, Capability c1, unsigned d0, unsigned d1)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.cap[0] = c;
|
||||
msg.cap[1] = c1;
|
||||
msg.data[0] = d0;
|
||||
msg.data[1] = d1;
|
||||
ret = call (my_call, &msg);
|
||||
return ret ? msg.cap[0] : 0;
|
||||
}
|
||||
|
||||
static unsigned call_n01 (Capability c, unsigned d)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.cap[0] = c;
|
||||
msg.data[0] = d;
|
||||
ret = call (my_call, &msg);
|
||||
return ret ? msg.data[0] : 0;
|
||||
}
|
||||
|
||||
static unsigned call_n02 (Capability c, unsigned d0, unsigned d1)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.cap[0] = c;
|
||||
msg.data[0] = d0;
|
||||
msg.data[1] = d1;
|
||||
ret = call (my_call, &msg);
|
||||
return ret ? msg.data[0] : 0;
|
||||
}
|
||||
|
||||
static unsigned call_n03 (Capability c, unsigned d0, unsigned d1, unsigned d2)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.cap[0] = c;
|
||||
msg.data[0] = d0;
|
||||
msg.data[1] = d1;
|
||||
msg.data[2] = d2;
|
||||
ret = call (my_call, &msg);
|
||||
return ret ? msg.data[0] : 0;
|
||||
}
|
||||
|
||||
static unsigned call_n04 (Capability c, unsigned d0, unsigned d1, unsigned d2, unsigned d3)
|
||||
{
|
||||
Message msg;
|
||||
int ret;
|
||||
msg.cap[0] = c;
|
||||
msg.data[0] = d0;
|
||||
msg.data[1] = d1;
|
||||
msg.data[2] = d2;
|
||||
msg.data[3] = d3;
|
||||
ret = call (my_call, &msg);
|
||||
return ret ? msg.data[0] : 0;
|
||||
}
|
||||
|
||||
static Capability degrade (Capability src, unsigned mask)
|
||||
{
|
||||
return call_c02 (src, CAP_DEGRADE, mask);
|
||||
}
|
||||
|
||||
static void schedule ()
|
||||
{
|
||||
invoke_01 (my_thread, CAP_THREAD_SCHEDULE);
|
||||
}
|
||||
|
||||
static void register_interrupt (unsigned num)
|
||||
{
|
||||
invoke_12 (my_thread, my_receiver, CAP_THREAD_REGISTER_INTERRUPT, num);
|
||||
}
|
||||
|
||||
static Capability get_top_memory ()
|
||||
{
|
||||
return call_c01 (my_thread, CAP_THREAD_GET_TOP_MEMORY);
|
||||
}
|
||||
|
||||
static void unregister_interrupt (unsigned num)
|
||||
{
|
||||
invoke_02 (my_thread, CAP_THREAD_REGISTER_INTERRUPT, num);
|
||||
}
|
||||
|
||||
static int receiver_set_owner (Capability receiver, Capability owner)
|
||||
{
|
||||
return invoke_11 (receiver, owner, CAP_RECEIVER_SET_OWNER);
|
||||
}
|
||||
|
||||
static Capability receiver_create_capability (Capability receiver, unsigned protected_data)
|
||||
{
|
||||
return call_c02 (receiver, CAP_RECEIVER_CREATE_CAPABILITY, protected_data);
|
||||
}
|
||||
|
||||
static int receiver_get_reply_protected_data (Capability receiver, unsigned data)
|
||||
{
|
||||
return call_n01 (receiver, CAP_RECEIVER_GET_REPLY_PROTECTED_DATA);
|
||||
}
|
||||
|
||||
static int receiver_set_reply_protected_data (Capability receiver, unsigned data)
|
||||
{
|
||||
return invoke_02 (receiver, CAP_RECEIVER_SET_REPLY_PROTECTED_DATA, data);
|
||||
}
|
||||
|
||||
static Capability receiver_create_call_capability (Capability receiver)
|
||||
{
|
||||
return call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 0);
|
||||
}
|
||||
|
||||
static Capability receiver_create_async_call_capability (Capability receiver)
|
||||
{
|
||||
return call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 1);
|
||||
}
|
||||
|
||||
static Capability memory_create (Capability memory, unsigned type)
|
||||
{
|
||||
return call_c02 (memory, CAP_MEMORY_CREATE, type);
|
||||
}
|
||||
|
||||
static Capability memory_create_page (Capability memory)
|
||||
{
|
||||
return memory_create (memory, CAPTYPE_PAGE);
|
||||
}
|
||||
|
||||
static Capability memory_create_thread (Capability memory)
|
||||
{
|
||||
return memory_create (memory, CAPTYPE_THREAD);
|
||||
}
|
||||
|
||||
static Capability memory_create_receiver (Capability memory)
|
||||
{
|
||||
return memory_create (memory, CAPTYPE_RECEIVER);
|
||||
}
|
||||
|
||||
static Capability memory_create_memory (Capability memory)
|
||||
{
|
||||
return memory_create (memory, CAPTYPE_MEMORY);
|
||||
}
|
||||
|
||||
static Capability memory_create_cappage (Capability memory)
|
||||
{
|
||||
return memory_create (memory, CAPTYPE_CAPPAGE);
|
||||
}
|
||||
|
||||
static int memory_destroy (Capability memory, Capability target)
|
||||
{
|
||||
return invoke_11 (memory, target, CAP_MEMORY_DESTROY);
|
||||
}
|
||||
|
||||
/* TODO: #define CAP_MEMORY_LIST 3 */
|
||||
|
||||
static int memory_map (Capability memory, Capability page, unsigned address)
|
||||
{
|
||||
return invoke_12 (memory, page, CAP_MEMORY_MAP, address);
|
||||
}
|
||||
|
||||
static Capability memory_mapping (Capability memory, unsigned address)
|
||||
{
|
||||
return call_c02 (memory, CAP_MEMORY_MAPPING, address);
|
||||
}
|
||||
|
||||
static void drop (Capability cap)
|
||||
{
|
||||
invoke_11 (my_memory, cap, CAP_MEMORY_DROP);
|
||||
}
|
||||
|
||||
static Capability thread_make_priv (Capability thread)
|
||||
{
|
||||
return call_c12 (my_thread, thread, CAP_THREAD_MAKE_PRIV, ~0);
|
||||
}
|
||||
|
||||
static unsigned thread_info (Capability thread, unsigned info, unsigned value, unsigned mask)
|
||||
{
|
||||
return call_n04 (thread, CAP_THREAD_INFO, info, value, mask);
|
||||
}
|
||||
|
||||
static unsigned thread_set_pc (Capability thread, unsigned pc)
|
||||
{
|
||||
return thread_info (thread, CAP_THREAD_INFO_PC, pc, ~0);
|
||||
}
|
||||
|
||||
static unsigned thread_set_sp (Capability thread, unsigned sp)
|
||||
{
|
||||
return thread_info (thread, CAP_THREAD_INFO_SP, sp, ~0);
|
||||
}
|
||||
|
||||
static unsigned thread_flags (Capability thread, unsigned value, unsigned mask)
|
||||
{
|
||||
return thread_info (thread, CAP_THREAD_INFO_FLAGS, value, mask);
|
||||
}
|
||||
|
||||
static unsigned thread_run (Capability thread, int run)
|
||||
{
|
||||
return thread_flags (thread, run ? THREAD_FLAG_RUNNING : 0, THREAD_FLAG_RUNNING);
|
||||
}
|
||||
|
||||
static unsigned thread_wait (Capability thread, int wait)
|
||||
{
|
||||
return thread_flags (thread, wait ? THREAD_FLAG_WAITING : 0, THREAD_FLAG_WAITING);
|
||||
}
|
||||
|
||||
static unsigned thread_get_pc (Capability thread)
|
||||
{
|
||||
return thread_info (thread, CAP_THREAD_INFO_PC, 0, 0);
|
||||
}
|
||||
|
||||
static unsigned thread_get_sp (Capability thread)
|
||||
{
|
||||
return thread_info (thread, CAP_THREAD_INFO_SP, 0, 0);
|
||||
}
|
||||
|
||||
static int page_share (Capability page, Capability target, unsigned flags)
|
||||
{
|
||||
return invoke_12 (page, target, CAP_PAGE_SHARE, flags);
|
||||
}
|
||||
|
||||
static unsigned page_flags (Capability page, unsigned new_flags, unsigned mask)
|
||||
{
|
||||
return call_n03 (page, CAP_PAGE_FLAGS, new_flags, mask);
|
||||
}
|
||||
|
||||
static Capability capability_get (Capability cap)
|
||||
{
|
||||
return call_c01 (cap, CAP_CAPABILITY_GET);
|
||||
}
|
||||
|
||||
static int cappage_set (Capability page, Capability cap, unsigned index)
|
||||
{
|
||||
return invoke_12 (page, cap, CAP_CAPPAGE_SET, index);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,22 @@
|
||||
#pypp 0
|
||||
#include "sos.h"
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// thread0.ccp: Testing userspace thread.
|
||||
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "iris.h"
|
||||
|
||||
int main ():
|
||||
while true:
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
#pypp 0
|
||||
#include "sos.h"
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// thread1.ccp: Testing userspace thread.
|
||||
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "iris.h"
|
||||
|
||||
int main ():
|
||||
while true:
|
||||
|
||||
Reference in New Issue
Block a user