ipc and thread spawning
This commit is contained in:
parent
02e855c066
commit
4f9bf8afef
18 changed files with 681 additions and 32 deletions
1
disk/calcite/init.rc
Normal file
1
disk/calcite/init.rc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
root://calcite/apps/hello/hello.elf
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include <kernel-public/framebuffer.h>
|
#include <kernel-public/framebuffer.h>
|
||||||
#include <kernel-public/files.h>
|
#include <kernel-public/files.h>
|
||||||
#include <kernel-public/input.h>
|
#include <kernel-public/input.h>
|
||||||
|
#include <kernel-public/ipc.h>
|
||||||
|
|
||||||
[[noreturn]] void end_thread();
|
[[noreturn]] void end_thread();
|
||||||
|
|
||||||
|
|
@ -38,3 +39,20 @@ void wait_for_mouse_packet(struct mouse_packet *packet_out);
|
||||||
void *map_pages(uint64_t count);
|
void *map_pages(uint64_t count);
|
||||||
|
|
||||||
void sleep_ms(uint64_t ms_to_sleep);
|
void sleep_ms(uint64_t ms_to_sleep);
|
||||||
|
|
||||||
|
//1 on success, 0 on failure.
|
||||||
|
int start_elf(const char *path);
|
||||||
|
|
||||||
|
enum ipc_dgram_result ipc_create_dgram_receiver(const char *address, ipc_dgram_receiver_handle_t *handle_out);
|
||||||
|
enum ipc_dgram_result ipc_create_dgram_sender(const char *address, ipc_dgram_sender_handle_t *handle_out);
|
||||||
|
|
||||||
|
//on entry, bytes is maximum accepted packet length.
|
||||||
|
//on exit, if result was IPR_SUCCESS or IPR_TOO_BIG, bytes is actual packet length.
|
||||||
|
//actual packet length will always be positive.
|
||||||
|
enum ipc_dgram_result ipc_receive_dgram(ipc_dgram_receiver_handle_t handle, void *buffer, int *bytes);
|
||||||
|
|
||||||
|
//bytes must be positive.
|
||||||
|
enum ipc_dgram_result ipc_send_dgram(ipc_dgram_sender_handle_t handle, const void *data, int bytes);
|
||||||
|
|
||||||
|
//f should not return
|
||||||
|
void create_thread(void (*f)(uint64_t x), uint64_t x);
|
||||||
|
|
|
||||||
38
include/kernel-public/ipc.h
Normal file
38
include/kernel-public/ipc.h
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
/* Calcite, include/kernel-public/ipc.h
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum ipc_dgram_result {
|
||||||
|
|
||||||
|
IPR_SUCCESS,
|
||||||
|
|
||||||
|
//on write, packet is bigger than kernel data structure.
|
||||||
|
//on read, packet is bigger than max requested size.
|
||||||
|
IPR_TOO_BIG,
|
||||||
|
|
||||||
|
IPR_BAD_HANDLE,
|
||||||
|
|
||||||
|
//on create receiver, someone is already receiving at that address.
|
||||||
|
IPR_IN_USE
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef uint64_t ipc_dgram_receiver_handle_t;
|
||||||
|
typedef uint64_t ipc_dgram_sender_handle_t;
|
||||||
|
|
@ -26,5 +26,11 @@ enum {
|
||||||
SYSCALL_READ_FILE,
|
SYSCALL_READ_FILE,
|
||||||
SYSCALL_WAIT_FOR_MOUSE_PACKET,
|
SYSCALL_WAIT_FOR_MOUSE_PACKET,
|
||||||
SYSCALL_MAP_PAGES,
|
SYSCALL_MAP_PAGES,
|
||||||
SYSCALL_SLEEP_MS
|
SYSCALL_SLEEP_MS,
|
||||||
|
SYSCALL_START_ELF,
|
||||||
|
SYSCALL_IPC_CREATE_DGRAM_RECEIVER,
|
||||||
|
SYSCALL_IPC_CREATE_DGRAM_SENDER,
|
||||||
|
SYSCALL_IPC_RECEIVE_DGRAM,
|
||||||
|
SYSCALL_IPC_SEND_DGRAM,
|
||||||
|
SYSCALL_CREATE_THREAD
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,12 @@ static const char *cmdline_look_up(const char *key) {
|
||||||
register_syscall(SYSCALL_WAIT_FOR_MOUSE_PACKET, (void *)&syscall_wait_for_mouse_packet);
|
register_syscall(SYSCALL_WAIT_FOR_MOUSE_PACKET, (void *)&syscall_wait_for_mouse_packet);
|
||||||
register_syscall(SYSCALL_MAP_PAGES, (void *)&syscall_map_pages);
|
register_syscall(SYSCALL_MAP_PAGES, (void *)&syscall_map_pages);
|
||||||
register_syscall(SYSCALL_SLEEP_MS, (void *)&syscall_sleep_ms);
|
register_syscall(SYSCALL_SLEEP_MS, (void *)&syscall_sleep_ms);
|
||||||
|
register_syscall(SYSCALL_START_ELF, (void *)&syscall_start_elf);
|
||||||
|
register_syscall(SYSCALL_IPC_CREATE_DGRAM_RECEIVER, (void *)&syscall_ipc_create_dgram_receiver);
|
||||||
|
register_syscall(SYSCALL_IPC_CREATE_DGRAM_SENDER, (void *)&syscall_ipc_create_dgram_sender);
|
||||||
|
register_syscall(SYSCALL_IPC_RECEIVE_DGRAM, (void *)&syscall_ipc_receive_dgram);
|
||||||
|
register_syscall(SYSCALL_IPC_SEND_DGRAM, (void *)&syscall_ipc_send_dgram);
|
||||||
|
register_syscall(SYSCALL_CREATE_THREAD, (void *)&syscall_create_thread);
|
||||||
|
|
||||||
//probe for drives
|
//probe for drives
|
||||||
|
|
||||||
|
|
@ -288,12 +294,12 @@ static const char *cmdline_look_up(const char *key) {
|
||||||
|
|
||||||
set_fs("root", root_fs);
|
set_fs("root", root_fs);
|
||||||
|
|
||||||
//load hello and start it
|
//load init and start it
|
||||||
|
|
||||||
init_scheduler();
|
init_scheduler();
|
||||||
|
|
||||||
if (!start_elf("root://calcite/apps/hello/hello.elf"))
|
if (!start_elf("root://calcite/apps/init/init.elf"))
|
||||||
panic("could not start hello.elf")
|
panic("could not start init.elf")
|
||||||
|
|
||||||
resume_next_continuation();
|
resume_next_continuation();
|
||||||
|
|
||||||
|
|
|
||||||
147
src/kernel/ipc-dgram.c
Normal file
147
src/kernel/ipc-dgram.c
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
/* Calcite, src/kernel/ipc-dgram.c
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ipc-dgram.h"
|
||||||
|
#include "scheduler.h"
|
||||||
|
#include "utility.h"
|
||||||
|
#include "panic.h"
|
||||||
|
#include "heap.h"
|
||||||
|
|
||||||
|
#include <kernel-public/ipc.h>
|
||||||
|
|
||||||
|
struct ipc_dgram_address_book {
|
||||||
|
const char *address;
|
||||||
|
struct ipc_dgram_box box;
|
||||||
|
struct ipc_dgram_address_book *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ipc_dgram_address_book *last = 0;
|
||||||
|
|
||||||
|
#define INITIAL_SEND_BACKLOG 4
|
||||||
|
|
||||||
|
struct ipc_dgram_box *get_ipc_dgram_box(const char *address) {
|
||||||
|
|
||||||
|
for (struct ipc_dgram_address_book *book = last; book != 0; book = book->prev)
|
||||||
|
if (strequ(book->address, address))
|
||||||
|
return &book->box;
|
||||||
|
|
||||||
|
struct ipc_dgram_address_book *new = heap_alloc(sizeof(struct ipc_dgram_address_book));
|
||||||
|
|
||||||
|
int address_length = 0;
|
||||||
|
while (address[address_length] != 0)
|
||||||
|
++address_length;
|
||||||
|
|
||||||
|
char *new_address = heap_alloc(address_length + 1);
|
||||||
|
memcpy(new_address, address, address_length);
|
||||||
|
new_address[address_length] = 0;
|
||||||
|
new->address = new_address;
|
||||||
|
|
||||||
|
new->box.is_receiver_held = 0;
|
||||||
|
new->box.is_someone_waiting_to_receive = 0;
|
||||||
|
create_queue(&new->box.waiting_to_send, INITIAL_SEND_BACKLOG);
|
||||||
|
new->box.buffer_read_pointer = 0;
|
||||||
|
new->box.buffer_read_available = 0;
|
||||||
|
|
||||||
|
new->prev = last;
|
||||||
|
last = new;
|
||||||
|
return &new->box;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_ipc_dgram_size(struct ipc_dgram_box *box) {
|
||||||
|
|
||||||
|
if (box->is_someone_waiting_to_receive)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while (box->buffer_read_available == 0) {
|
||||||
|
box->is_someone_waiting_to_receive = 1;
|
||||||
|
yield(&box->waiting_to_receive);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(box->buffer_read_available >= 4)
|
||||||
|
return *(int *)&box->buffer[box->buffer_read_pointer];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void receive_ipc_dgram(struct ipc_dgram_box *box, void *buffer) {
|
||||||
|
|
||||||
|
assert(box->is_someone_waiting_to_receive == 0)
|
||||||
|
assert(box->buffer_read_available >= 4)
|
||||||
|
|
||||||
|
int size = *(int *)&box->buffer[box->buffer_read_pointer];
|
||||||
|
|
||||||
|
box->buffer_read_available -= 4;
|
||||||
|
box->buffer_read_pointer = (box->buffer_read_pointer + 4) % IPC_DGRAM_BOX_BUFFER_LENGTH;
|
||||||
|
|
||||||
|
int size_rounded_up = ((size - 1) / 4 + 1) * 4;
|
||||||
|
|
||||||
|
assert(box->buffer_read_available >= size_rounded_up)
|
||||||
|
|
||||||
|
int first_block = IPC_DGRAM_BOX_BUFFER_LENGTH - box->buffer_read_pointer;
|
||||||
|
if (size < first_block)
|
||||||
|
first_block = size;
|
||||||
|
|
||||||
|
memcpy(buffer, &box->buffer[box->buffer_read_pointer], first_block);
|
||||||
|
if (first_block != size)
|
||||||
|
memcpy(buffer + first_block, box->buffer, size - first_block);
|
||||||
|
|
||||||
|
box->buffer_read_available -= size_rounded_up;
|
||||||
|
box->buffer_read_pointer = (box->buffer_read_pointer + size_rounded_up) % IPC_DGRAM_BOX_BUFFER_LENGTH;
|
||||||
|
|
||||||
|
struct continuation_info ci;
|
||||||
|
while (take_from_queue(&box->waiting_to_send, &ci))
|
||||||
|
add_to_queue(&ready_continuations, &ci);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ipc_dgram_result send_ipc_dgram(struct ipc_dgram_box *box, const void *data, int bytes) {
|
||||||
|
|
||||||
|
assert(bytes > 0)
|
||||||
|
|
||||||
|
int bytes_round_up = ((bytes - 1) / 4 + 1) * 4;
|
||||||
|
|
||||||
|
if (4 + bytes_round_up > IPC_DGRAM_BOX_BUFFER_LENGTH)
|
||||||
|
return IPR_TOO_BIG;
|
||||||
|
|
||||||
|
while (IPC_DGRAM_BOX_BUFFER_LENGTH - box->buffer_read_available < 4 + bytes_round_up)
|
||||||
|
yield_to_queue(&box->waiting_to_send);
|
||||||
|
|
||||||
|
int write_pointer = (box->buffer_read_pointer + box->buffer_read_available) % IPC_DGRAM_BOX_BUFFER_LENGTH;
|
||||||
|
assert(write_pointer + 4 <= IPC_DGRAM_BOX_BUFFER_LENGTH)
|
||||||
|
|
||||||
|
*(int *)&box->buffer[write_pointer] = bytes;
|
||||||
|
|
||||||
|
write_pointer = (write_pointer + 4) % IPC_DGRAM_BOX_BUFFER_LENGTH;
|
||||||
|
|
||||||
|
int first_block = IPC_DGRAM_BOX_BUFFER_LENGTH - write_pointer;
|
||||||
|
if (bytes < first_block)
|
||||||
|
first_block = bytes;
|
||||||
|
|
||||||
|
memcpy(&box->buffer[write_pointer], data, first_block);
|
||||||
|
if (first_block != bytes)
|
||||||
|
memcpy(box->buffer, data + first_block, bytes - first_block);
|
||||||
|
|
||||||
|
box->buffer_read_available += 4 + bytes_round_up;
|
||||||
|
|
||||||
|
if (box->is_someone_waiting_to_receive) {
|
||||||
|
box->is_someone_waiting_to_receive = 0;
|
||||||
|
add_to_queue(&ready_continuations, &box->waiting_to_receive);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IPR_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
58
src/kernel/ipc-dgram.h
Normal file
58
src/kernel/ipc-dgram.h
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* Calcite, src/kernel/ipc-dgram.h
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "scheduler.h"
|
||||||
|
|
||||||
|
#include <kernel-public/ipc.h>
|
||||||
|
|
||||||
|
//must be a multiple of 4
|
||||||
|
#define IPC_DGRAM_BOX_BUFFER_LENGTH 1024
|
||||||
|
|
||||||
|
struct ipc_dgram_box {
|
||||||
|
|
||||||
|
int is_receiver_held;
|
||||||
|
|
||||||
|
int is_someone_waiting_to_receive;
|
||||||
|
struct continuation_info waiting_to_receive;
|
||||||
|
|
||||||
|
struct continuation_queue waiting_to_send;
|
||||||
|
|
||||||
|
int buffer_read_pointer;
|
||||||
|
int buffer_read_available;
|
||||||
|
|
||||||
|
//packets are of the form:
|
||||||
|
// int size;
|
||||||
|
// uint8_t packet[size];
|
||||||
|
// uint8_t padding[size % 4 == 0 ? 0 : 4 - size % 4];
|
||||||
|
uint8_t buffer[IPC_DGRAM_BOX_BUFFER_LENGTH];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipc_dgram_box *get_ipc_dgram_box(const char *address);
|
||||||
|
|
||||||
|
//waits until a packet is available, then returns the size of that packet.
|
||||||
|
//returns -1 if someone is already waiting.
|
||||||
|
int get_ipc_dgram_size(struct ipc_dgram_box *box);
|
||||||
|
|
||||||
|
//should only be called just after get_ipc_dgram_size
|
||||||
|
//(i.e. with no intervening continuation resumptions)
|
||||||
|
void receive_ipc_dgram(struct ipc_dgram_box *box, void *buffer);
|
||||||
|
|
||||||
|
//only returns IPR_SUCCESS or IPR_TOO_BIG
|
||||||
|
enum ipc_dgram_result send_ipc_dgram(struct ipc_dgram_box *box, const void *data, int bytes);
|
||||||
|
|
@ -18,28 +18,19 @@
|
||||||
bits 64
|
bits 64
|
||||||
default rel
|
default rel
|
||||||
|
|
||||||
extern running_thread
|
|
||||||
|
|
||||||
section .text
|
section .text
|
||||||
|
|
||||||
;referenced in process.c
|
;referenced in process.c
|
||||||
global thread_start
|
global thread_start
|
||||||
thread_start:
|
thread_start:
|
||||||
|
|
||||||
mov rax, qword [running_thread]
|
|
||||||
test rax, rax
|
|
||||||
jnz .assert_fail
|
|
||||||
|
|
||||||
mov qword [running_thread], rbx
|
|
||||||
|
|
||||||
mov cr3, rbp
|
mov cr3, rbp
|
||||||
mov rcx, r12
|
mov rcx, r12
|
||||||
mov r11, 0x200
|
mov r11, 0x200
|
||||||
|
mov rdi, r13
|
||||||
|
|
||||||
xor rax, rax
|
xor rax, rax
|
||||||
xor rbx, rbx
|
xor rbx, rbx
|
||||||
xor rdx, rdx
|
xor rdx, rdx
|
||||||
xor rdi, rdi
|
|
||||||
xor rsi, rsi
|
xor rsi, rsi
|
||||||
xor rbp, rbp
|
xor rbp, rbp
|
||||||
xor r8, r8
|
xor r8, r8
|
||||||
|
|
@ -51,7 +42,3 @@ thread_start:
|
||||||
xor r15, r15
|
xor r15, r15
|
||||||
|
|
||||||
o64 sysret
|
o64 sysret
|
||||||
|
|
||||||
.assert_fail:
|
|
||||||
;could be nice to handle this more gracefully in the future
|
|
||||||
ud2
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
|
#include "ipc-dgram.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "syscalls.h"
|
#include "syscalls.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
|
|
@ -26,6 +27,7 @@
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
|
||||||
#include <kernel-public/files.h>
|
#include <kernel-public/files.h>
|
||||||
|
#include <kernel-public/ipc.h>
|
||||||
|
|
||||||
struct process_file_info *get_file_info(struct process *process, file_handle_t handle) {
|
struct process_file_info *get_file_info(struct process *process, file_handle_t handle) {
|
||||||
if (handle > (uint64_t)process->files_buffer_size || process->files[handle].fs == 0)
|
if (handle > (uint64_t)process->files_buffer_size || process->files[handle].fs == 0)
|
||||||
|
|
@ -63,6 +65,7 @@ void create_process(struct process *process_out) {
|
||||||
|
|
||||||
process_out->n_threads = 0;
|
process_out->n_threads = 0;
|
||||||
process_out->files = 0;
|
process_out->files = 0;
|
||||||
|
process_out->ipc_dgram_handles = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,11 +337,11 @@ int load_elf(
|
||||||
}
|
}
|
||||||
|
|
||||||
//defined in process.asm. enters user mode with:
|
//defined in process.asm. enters user mode with:
|
||||||
// running_thread = value of rbx when we jump here
|
|
||||||
// cr3 = value of rbp when we jump here
|
// cr3 = value of rbp when we jump here
|
||||||
// rsp = value of rsp when we jump here
|
// rsp = value of rsp when we jump here
|
||||||
// rip = rcx = value of r12 when we jump here
|
// rip = rcx = value of r12 when we jump here
|
||||||
// rflags = r11 = 0x200 (IF)
|
// rflags = r11 = 0x200 (IF)
|
||||||
|
// rdi = value of r13 when we jump here
|
||||||
// all other registers zeroed
|
// all other registers zeroed
|
||||||
extern uint8_t thread_start;
|
extern uint8_t thread_start;
|
||||||
|
|
||||||
|
|
@ -365,10 +368,11 @@ int start_elf(const char *uri) {
|
||||||
|
|
||||||
struct continuation_info ci;
|
struct continuation_info ci;
|
||||||
ci.rip = (uint64_t)&thread_start;
|
ci.rip = (uint64_t)&thread_start;
|
||||||
ci.rbx = (uint64_t)thread;
|
|
||||||
ci.rbp = thread->process->p4_physical_base;
|
ci.rbp = thread->process->p4_physical_base;
|
||||||
ci.rsp = (uint64_t)thread->stack_top;
|
ci.rsp = (uint64_t)thread->stack_top;
|
||||||
ci.r12 = entry;
|
ci.r12 = entry;
|
||||||
|
ci.r13 = 0;
|
||||||
|
ci.running_thread = thread;
|
||||||
|
|
||||||
add_to_queue(&ready_continuations, &ci);
|
add_to_queue(&ready_continuations, &ci);
|
||||||
|
|
||||||
|
|
@ -376,6 +380,36 @@ int start_elf(const char *uri) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void syscall_create_thread(void (*f)(uint64_t), uint64_t x) {
|
||||||
|
|
||||||
|
assert(running_thread != 0)
|
||||||
|
|
||||||
|
struct thread *thread = heap_alloc(sizeof(struct thread));
|
||||||
|
create_thread(running_thread->process, thread);
|
||||||
|
|
||||||
|
struct continuation_info ci;
|
||||||
|
ci.rip = (uint64_t)&thread_start;
|
||||||
|
ci.rbp = thread->process->p4_physical_base;
|
||||||
|
ci.rsp = (uint64_t)thread->stack_top;
|
||||||
|
ci.r12 = (uint64_t)f;
|
||||||
|
ci.r13 = x;
|
||||||
|
ci.running_thread = thread;
|
||||||
|
|
||||||
|
add_to_queue(&ready_continuations, &ci);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int syscall_start_elf(const char *uri) {
|
||||||
|
|
||||||
|
assert(running_thread != 0)
|
||||||
|
|
||||||
|
if (!is_mapped_readable_string(running_thread->process, uri))
|
||||||
|
syscall_illegal_args();
|
||||||
|
|
||||||
|
return start_elf(uri);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void destroy_process(struct process *process) {
|
void destroy_process(struct process *process) {
|
||||||
|
|
||||||
if (process->files) {
|
if (process->files) {
|
||||||
|
|
@ -385,6 +419,15 @@ void destroy_process(struct process *process) {
|
||||||
heap_dealloc(process->files, process->files_buffer_size * sizeof(struct process_file_info));
|
heap_dealloc(process->files, process->files_buffer_size * sizeof(struct process_file_info));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process->ipc_dgram_handles) {
|
||||||
|
for (int i = 0; i < process->ipc_dgram_handles_buffer_size; ++i)
|
||||||
|
if (process->ipc_dgram_handles[i].box != 0 && process->ipc_dgram_handles[i].is_receiver == 1)
|
||||||
|
process->ipc_dgram_handles[i].box->is_receiver_held = 0;
|
||||||
|
heap_dealloc(
|
||||||
|
process->ipc_dgram_handles,
|
||||||
|
process->ipc_dgram_handles_buffer_size * sizeof(struct process_ipc_dgram_handle_info));
|
||||||
|
}
|
||||||
|
|
||||||
for (int p3i = 0; p3i < 512; ++p3i)
|
for (int p3i = 0; p3i < 512; ++p3i)
|
||||||
if (process->p3_virtual_base[p3i]) {
|
if (process->p3_virtual_base[p3i]) {
|
||||||
for (int p2i = 0; p2i < 512; ++p2i)
|
for (int p2i = 0; p2i < 512; ++p2i)
|
||||||
|
|
@ -441,7 +484,9 @@ void create_thread(struct process *process, struct thread *thread_out) {
|
||||||
|
|
||||||
uint64_t pma = take_free_physical_page();
|
uint64_t pma = take_free_physical_page();
|
||||||
map_page_for_process(
|
map_page_for_process(
|
||||||
process, pma, stack_bottom_vma + i * 4096, 1, 0, 1);
|
process, pma,
|
||||||
|
stack_bottom_vma + i * 4096,
|
||||||
|
1, 0, 1);
|
||||||
|
|
||||||
void *kvma = find_free_kernel_region(4096);
|
void *kvma = find_free_kernel_region(4096);
|
||||||
map_in_kernel_page_table(pma, kvma, 1, 0);
|
map_in_kernel_page_table(pma, kvma, 1, 0);
|
||||||
|
|
@ -458,7 +503,7 @@ void create_thread(struct process *process, struct thread *thread_out) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] static void syscall_illegal_args() {
|
[[noreturn]] void syscall_illegal_args() {
|
||||||
panic("bad syscall")
|
panic("bad syscall")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -626,3 +671,136 @@ void *syscall_map_pages(uint64_t count) {
|
||||||
return vma;
|
return vma;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define INITIAL_IPC_DGRAM_HANDLE_COUNT 16
|
||||||
|
|
||||||
|
static uint64_t get_free_ipc_dgram_handle(struct process *process) {
|
||||||
|
|
||||||
|
if (process->ipc_dgram_handles == 0) {
|
||||||
|
process->ipc_dgram_handles =
|
||||||
|
heap_alloc(INITIAL_IPC_DGRAM_HANDLE_COUNT * sizeof(struct process_ipc_dgram_handle_info));
|
||||||
|
process->ipc_dgram_handles_buffer_size = INITIAL_IPC_DGRAM_HANDLE_COUNT;
|
||||||
|
for (int i = 0; i < INITIAL_IPC_DGRAM_HANDLE_COUNT; ++i)
|
||||||
|
process->ipc_dgram_handles[i].box = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < process->ipc_dgram_handles_buffer_size; ++i)
|
||||||
|
if (process->ipc_dgram_handles[i].box == 0)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
int old_size = process->ipc_dgram_handles_buffer_size;
|
||||||
|
int new_size = old_size * 2;
|
||||||
|
struct process_ipc_dgram_handle_info *new_buffer =
|
||||||
|
heap_alloc(new_size * sizeof(struct process_ipc_dgram_handle_info));
|
||||||
|
|
||||||
|
memcpy(
|
||||||
|
new_buffer, process->ipc_dgram_handles,
|
||||||
|
old_size * sizeof(struct process_ipc_dgram_handle_info));
|
||||||
|
|
||||||
|
heap_dealloc(
|
||||||
|
process->ipc_dgram_handles,
|
||||||
|
old_size * sizeof(struct process_ipc_dgram_handle_info));
|
||||||
|
|
||||||
|
process->ipc_dgram_handles = new_buffer;
|
||||||
|
process->ipc_dgram_handles_buffer_size = new_size;
|
||||||
|
|
||||||
|
for (int i = old_size; i < new_size; ++i)
|
||||||
|
new_buffer[i].box = 0;
|
||||||
|
|
||||||
|
return old_size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ipc_dgram_result syscall_ipc_create_dgram_receiver(
|
||||||
|
const char *address, ipc_dgram_receiver_handle_t *handle_out) {
|
||||||
|
|
||||||
|
assert(running_thread != 0)
|
||||||
|
|
||||||
|
if (!is_mapped_readable_string(running_thread->process, address) ||
|
||||||
|
!is_mapped_writable(
|
||||||
|
running_thread->process, handle_out, sizeof(ipc_dgram_receiver_handle_t)))
|
||||||
|
syscall_illegal_args();
|
||||||
|
|
||||||
|
struct ipc_dgram_box *box = get_ipc_dgram_box(address);
|
||||||
|
if (box->is_receiver_held)
|
||||||
|
return IPR_IN_USE;
|
||||||
|
|
||||||
|
box->is_receiver_held = 1;
|
||||||
|
|
||||||
|
*handle_out = get_free_ipc_dgram_handle(running_thread->process);
|
||||||
|
struct process_ipc_dgram_handle_info *info = &running_thread->process->ipc_dgram_handles[*handle_out];
|
||||||
|
info->box = box;
|
||||||
|
info->is_receiver = 1;
|
||||||
|
return IPR_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ipc_dgram_result syscall_ipc_create_dgram_sender(
|
||||||
|
const char *address, ipc_dgram_sender_handle_t *handle_out) {
|
||||||
|
|
||||||
|
assert(running_thread != 0)
|
||||||
|
|
||||||
|
if (!is_mapped_readable_string(running_thread->process, address) ||
|
||||||
|
!is_mapped_writable(
|
||||||
|
running_thread->process, handle_out, sizeof(ipc_dgram_receiver_handle_t)))
|
||||||
|
syscall_illegal_args();
|
||||||
|
|
||||||
|
struct ipc_dgram_box *box = get_ipc_dgram_box(address);
|
||||||
|
|
||||||
|
*handle_out = get_free_ipc_dgram_handle(running_thread->process);
|
||||||
|
struct process_ipc_dgram_handle_info *info = &running_thread->process->ipc_dgram_handles[*handle_out];
|
||||||
|
info->box = box;
|
||||||
|
info->is_receiver = 0;
|
||||||
|
return IPR_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ipc_dgram_result syscall_ipc_receive_dgram(
|
||||||
|
ipc_dgram_receiver_handle_t handle, void *buffer, int *bytes) {
|
||||||
|
|
||||||
|
assert(running_thread != 0)
|
||||||
|
|
||||||
|
if (!is_mapped_writable(running_thread->process, bytes, sizeof(uint64_t)) ||
|
||||||
|
!is_mapped_writable(running_thread->process, buffer, *bytes))
|
||||||
|
syscall_illegal_args();
|
||||||
|
|
||||||
|
if (running_thread->process->ipc_dgram_handles == 0 ||
|
||||||
|
handle >= (uint64_t)running_thread->process->ipc_dgram_handles_buffer_size ||
|
||||||
|
running_thread->process->ipc_dgram_handles[handle].box == 0 ||
|
||||||
|
running_thread->process->ipc_dgram_handles[handle].is_receiver != 1)
|
||||||
|
return IPR_BAD_HANDLE;
|
||||||
|
|
||||||
|
struct ipc_dgram_box *box = running_thread->process->ipc_dgram_handles[handle].box;
|
||||||
|
int actual_bytes = get_ipc_dgram_size(box);
|
||||||
|
assert(actual_bytes > 0);
|
||||||
|
|
||||||
|
if (actual_bytes > *bytes) {
|
||||||
|
*bytes = actual_bytes;
|
||||||
|
return IPR_TOO_BIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
receive_ipc_dgram(box, buffer);
|
||||||
|
*bytes = actual_bytes;
|
||||||
|
return IPR_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ipc_dgram_result syscall_ipc_send_dgram(
|
||||||
|
ipc_dgram_sender_handle_t handle, const void *data, int bytes) {
|
||||||
|
|
||||||
|
assert(running_thread != 0)
|
||||||
|
|
||||||
|
if (bytes <= 0 || !is_mapped_readable(running_thread->process, data, bytes))
|
||||||
|
syscall_illegal_args();
|
||||||
|
|
||||||
|
if (running_thread->process->ipc_dgram_handles == 0 ||
|
||||||
|
handle >= (uint64_t)running_thread->process->ipc_dgram_handles_buffer_size ||
|
||||||
|
running_thread->process->ipc_dgram_handles[handle].box == 0 ||
|
||||||
|
running_thread->process->ipc_dgram_handles[handle].is_receiver != 0)
|
||||||
|
return IPR_BAD_HANDLE;
|
||||||
|
|
||||||
|
struct ipc_dgram_box *box = running_thread->process->ipc_dgram_handles[handle].box;
|
||||||
|
return send_ipc_dgram(box, data, bytes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,9 @@
|
||||||
|
|
||||||
#include <kernel-public/framebuffer.h>
|
#include <kernel-public/framebuffer.h>
|
||||||
#include <kernel-public/files.h>
|
#include <kernel-public/files.h>
|
||||||
|
#include <kernel-public/ipc.h>
|
||||||
|
|
||||||
|
struct ipc_dgram_box;
|
||||||
|
|
||||||
struct process_file_info {
|
struct process_file_info {
|
||||||
const struct fs_info *fs;
|
const struct fs_info *fs;
|
||||||
|
|
@ -28,6 +31,13 @@ struct process_file_info {
|
||||||
struct fs_stat stat;
|
struct fs_stat stat;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct process_ipc_dgram_handle_info {
|
||||||
|
//0 if this handle number is not used.
|
||||||
|
struct ipc_dgram_box *box;
|
||||||
|
//1 if this is a receiver handle, 0 if this is a sender handle.
|
||||||
|
int is_receiver;
|
||||||
|
};
|
||||||
|
|
||||||
struct process {
|
struct process {
|
||||||
|
|
||||||
uint64_t p4_physical_base;
|
uint64_t p4_physical_base;
|
||||||
|
|
@ -42,6 +52,9 @@ struct process {
|
||||||
struct process_file_info *files;
|
struct process_file_info *files;
|
||||||
int files_buffer_size;
|
int files_buffer_size;
|
||||||
|
|
||||||
|
struct process_ipc_dgram_handle_info *ipc_dgram_handles;
|
||||||
|
int ipc_dgram_handles_buffer_size;
|
||||||
|
|
||||||
//0 for missing levels. just bottom p3 of address space.
|
//0 for missing levels. just bottom p3 of address space.
|
||||||
uint64_t *p2_virtual_bases[512];
|
uint64_t *p2_virtual_bases[512];
|
||||||
uint64_t **p1_virtual_bases[512];
|
uint64_t **p1_virtual_bases[512];
|
||||||
|
|
@ -97,9 +110,13 @@ int load_elf(
|
||||||
//starts user mode at the elf's entry point.
|
//starts user mode at the elf's entry point.
|
||||||
int start_elf(const char *uri);
|
int start_elf(const char *uri);
|
||||||
|
|
||||||
|
int syscall_start_elf(const char *uri);
|
||||||
|
|
||||||
void destroy_process(struct process *process);
|
void destroy_process(struct process *process);
|
||||||
void destroy_thread(struct thread *thread);
|
void destroy_thread(struct thread *thread);
|
||||||
|
|
||||||
|
[[noreturn]] void syscall_illegal_args();
|
||||||
|
|
||||||
//returs 1 if [start, start + length) is writable by process, otherwise 0.
|
//returs 1 if [start, start + length) is writable by process, otherwise 0.
|
||||||
int is_mapped_writable(struct process *process, const void *start, uint64_t length);
|
int is_mapped_writable(struct process *process, const void *start, uint64_t length);
|
||||||
|
|
||||||
|
|
@ -119,3 +136,22 @@ enum fs_access_result syscall_get_file_size(file_handle_t handle, uint64_t *byte
|
||||||
enum fs_access_result syscall_read_file(struct read_file_parameter *parameter);
|
enum fs_access_result syscall_read_file(struct read_file_parameter *parameter);
|
||||||
|
|
||||||
void *syscall_map_pages(uint64_t count);
|
void *syscall_map_pages(uint64_t count);
|
||||||
|
|
||||||
|
enum ipc_dgram_result syscall_ipc_create_dgram_receiver(
|
||||||
|
const char *address, ipc_dgram_receiver_handle_t *handle_out);
|
||||||
|
|
||||||
|
enum ipc_dgram_result syscall_ipc_create_dgram_sender(
|
||||||
|
const char *address, ipc_dgram_sender_handle_t *handle_out);
|
||||||
|
|
||||||
|
//on entry, bytes is maximum accepted packet length.
|
||||||
|
//on exit, if result was IPR_SUCCESS or IPR_TOO_BIG, bytes is actual packet length.
|
||||||
|
//actual packet length will always be positive.
|
||||||
|
enum ipc_dgram_result syscall_ipc_receive_dgram(
|
||||||
|
ipc_dgram_receiver_handle_t handle, void *buffer, int *bytes);
|
||||||
|
|
||||||
|
//bytes must be positive.
|
||||||
|
enum ipc_dgram_result syscall_ipc_send_dgram(
|
||||||
|
ipc_dgram_sender_handle_t handle, const void *data, int bytes);
|
||||||
|
|
||||||
|
//f should not return.
|
||||||
|
void syscall_create_thread(void (*f)(uint64_t x), uint64_t x);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ bits 64
|
||||||
default rel
|
default rel
|
||||||
|
|
||||||
extern resume_next_continuation
|
extern resume_next_continuation
|
||||||
|
extern running_thread
|
||||||
|
extern add_to_queue
|
||||||
|
|
||||||
;referenced in scheduler.c
|
;referenced in scheduler.c
|
||||||
global resume_continuation
|
global resume_continuation
|
||||||
|
|
@ -32,15 +34,14 @@ resume_continuation:
|
||||||
mov r13, qword [rdi + 40]
|
mov r13, qword [rdi + 40]
|
||||||
mov r14, qword [rdi + 48]
|
mov r14, qword [rdi + 48]
|
||||||
mov r15, qword [rdi + 56]
|
mov r15, qword [rdi + 56]
|
||||||
|
mov rdi, qword [rdi + 64]
|
||||||
|
mov qword [running_thread], rdi
|
||||||
|
|
||||||
jmp rax
|
jmp rax
|
||||||
|
|
||||||
ret:
|
|
||||||
ret
|
|
||||||
|
|
||||||
global yield
|
global yield
|
||||||
yield:
|
yield:
|
||||||
mov qword [rdi], ret
|
mov qword [rdi], .ret
|
||||||
mov qword [rdi + 8], rbx
|
mov qword [rdi + 8], rbx
|
||||||
mov qword [rdi + 16], rbp
|
mov qword [rdi + 16], rbp
|
||||||
mov qword [rdi + 24], rsp
|
mov qword [rdi + 24], rsp
|
||||||
|
|
@ -48,6 +49,8 @@ yield:
|
||||||
mov qword [rdi + 40], r13
|
mov qword [rdi + 40], r13
|
||||||
mov qword [rdi + 48], r14
|
mov qword [rdi + 48], r14
|
||||||
mov qword [rdi + 56], r15
|
mov qword [rdi + 56], r15
|
||||||
|
mov qword rsi, qword [running_thread]
|
||||||
|
mov qword [rdi + 64], rsi
|
||||||
|
|
||||||
jmp resume_next_continuation
|
jmp resume_next_continuation
|
||||||
|
|
||||||
|
|
@ -56,7 +59,7 @@ yield:
|
||||||
|
|
||||||
global yield_sti
|
global yield_sti
|
||||||
yield_sti:
|
yield_sti:
|
||||||
mov qword [rdi], ret
|
mov qword [rdi], .ret
|
||||||
mov qword [rdi + 8], rbx
|
mov qword [rdi + 8], rbx
|
||||||
mov qword [rdi + 16], rbp
|
mov qword [rdi + 16], rbp
|
||||||
mov qword [rdi + 24], rsp
|
mov qword [rdi + 24], rsp
|
||||||
|
|
@ -64,6 +67,8 @@ yield_sti:
|
||||||
mov qword [rdi + 40], r13
|
mov qword [rdi + 40], r13
|
||||||
mov qword [rdi + 48], r14
|
mov qword [rdi + 48], r14
|
||||||
mov qword [rdi + 56], r15
|
mov qword [rdi + 56], r15
|
||||||
|
mov qword rsi, qword [running_thread]
|
||||||
|
mov qword [rdi + 64], rsi
|
||||||
|
|
||||||
sti
|
sti
|
||||||
|
|
||||||
|
|
@ -71,3 +76,24 @@ yield_sti:
|
||||||
|
|
||||||
.ret:
|
.ret:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
global yield_to_queue
|
||||||
|
yield_to_queue:
|
||||||
|
mov qword [rsp - 72], .ret
|
||||||
|
mov qword [rsp - 64], rbx
|
||||||
|
mov qword [rsp - 56], rbp
|
||||||
|
mov qword [rsp - 48], rsp
|
||||||
|
mov qword [rsp - 40], r12
|
||||||
|
mov qword [rsp - 32], r13
|
||||||
|
mov qword [rsp - 24], r14
|
||||||
|
mov qword [rsp - 16], r15
|
||||||
|
mov rdx, qword [running_thread]
|
||||||
|
mov qword [rsp - 8], rdx
|
||||||
|
|
||||||
|
sub rsp, 72
|
||||||
|
mov rsi, rsp
|
||||||
|
call add_to_queue
|
||||||
|
jmp resume_continuation
|
||||||
|
|
||||||
|
.ret:
|
||||||
|
ret
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
|
#include "process.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
#include "panic.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
|
|
||||||
struct continuation_queue ready_continuations;
|
struct continuation_queue ready_continuations;
|
||||||
|
|
@ -30,11 +32,14 @@ void init_scheduler() {
|
||||||
|
|
||||||
[[noreturn]] void resume_next_continuation() {
|
[[noreturn]] void resume_next_continuation() {
|
||||||
|
|
||||||
struct continuation_info ci;
|
running_thread = 0;
|
||||||
|
|
||||||
|
struct continuation_info ci;
|
||||||
while (!take_from_queue(&ready_continuations, &ci))
|
while (!take_from_queue(&ready_continuations, &ci))
|
||||||
__asm__ ("hlt");
|
__asm__ ("hlt");
|
||||||
|
|
||||||
|
assert(running_thread == 0)
|
||||||
|
assert(ci.running_thread != 0)
|
||||||
resume_continuation(&ci);
|
resume_continuation(&ci);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "process.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct continuation_info {
|
struct continuation_info {
|
||||||
|
|
@ -28,6 +30,7 @@ struct continuation_info {
|
||||||
uint64_t r13;
|
uint64_t r13;
|
||||||
uint64_t r14;
|
uint64_t r14;
|
||||||
uint64_t r15;
|
uint64_t r15;
|
||||||
|
struct thread *running_thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_scheduler();
|
void init_scheduler();
|
||||||
|
|
@ -57,3 +60,6 @@ void yield(struct continuation_info *save_current_continuation_to);
|
||||||
|
|
||||||
//save as yield but enables interrupts between saving this continuation and resuming next ready one.
|
//save as yield but enables interrupts between saving this continuation and resuming next ready one.
|
||||||
void yield_sti(struct continuation_info *save_current_continuation_to);
|
void yield_sti(struct continuation_info *save_current_continuation_to);
|
||||||
|
|
||||||
|
//same as yield, but instead of saving continuation to a pointer, saves it to the end of the queue.
|
||||||
|
void yield_to_queue(struct continuation_queue *queue);
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,8 @@ void register_syscall(
|
||||||
uint64_t (*handler)(uint64_t arg1, uint64_t arg2, uint64_t arg3));
|
uint64_t (*handler)(uint64_t arg1, uint64_t arg2, uint64_t arg3));
|
||||||
|
|
||||||
//the top of the syscall stack of the most recently started syscall.
|
//the top of the syscall stack of the most recently started syscall.
|
||||||
//kind of a hack, used in the end_thread syscall to deallocate that stack.
|
//kind of a hack, used in the end_thread syscall to deallocate that stack
|
||||||
|
//and in the fork_thread syscall to copy the stack.
|
||||||
extern void *most_recent_syscall_stack;
|
extern void *most_recent_syscall_stack;
|
||||||
|
|
||||||
//also kind of a hack. switches to temporary stack and runs f with that stack.
|
//also kind of a hack. switches to temporary stack and runs f with that stack.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "kernel-public/ipc.h"
|
||||||
#include <calcite/syscalls.h>
|
#include <calcite/syscalls.h>
|
||||||
#include <silver/pam.h>
|
#include <silver/pam.h>
|
||||||
|
|
||||||
|
|
@ -59,14 +60,37 @@ static void copy_frame() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
[[noreturn]] static void panic() {
|
||||||
|
for (int y = 0; y < fbb->height; ++y)
|
||||||
|
for (int x = 0; x < fbb->width; ++x) {
|
||||||
|
struct pixel *pixel = &fbb->pixels[y * fbb->width + x];
|
||||||
|
pixel->r = (x + y) * 256 / (fbb->height + fbb->width);
|
||||||
|
pixel->g = 0;
|
||||||
|
pixel->b = 0;
|
||||||
|
}
|
||||||
|
copy_frame();
|
||||||
|
end_thread();
|
||||||
|
}
|
||||||
|
|
||||||
if (!load_pam("root://calcite/apps/hello/pointer.pam", &cursor_image))
|
void main() {
|
||||||
return;
|
|
||||||
|
|
||||||
map_framebuffer(&fb_info);
|
map_framebuffer(&fb_info);
|
||||||
create_image(fb_info.fb_width, fb_info.fb_height, &fbb);
|
create_image(fb_info.fb_width, fb_info.fb_height, &fbb);
|
||||||
|
|
||||||
|
ipc_dgram_receiver_handle_t receiver;
|
||||||
|
if (ipc_create_dgram_receiver("calcite-test", &receiver) != IPR_SUCCESS)
|
||||||
|
panic();
|
||||||
|
|
||||||
|
char buffer[5];
|
||||||
|
int bytes = 5;
|
||||||
|
if (ipc_receive_dgram(receiver, buffer, &bytes) != IPR_SUCCESS ||
|
||||||
|
bytes != 5 ||
|
||||||
|
buffer[0] != 'h' || buffer[1] != 'e' || buffer[2] != 'l' || buffer[3] != 'l' || buffer[4] != 'o')
|
||||||
|
panic();
|
||||||
|
|
||||||
|
if (!load_pam("root://calcite/apps/hello/pointer.pam", &cursor_image))
|
||||||
|
panic();
|
||||||
|
|
||||||
int cursor_x = fb_info.fb_width / 2;
|
int cursor_x = fb_info.fb_width / 2;
|
||||||
int cursor_y = fb_info.fb_height / 2;
|
int cursor_y = fb_info.fb_height / 2;
|
||||||
|
|
||||||
|
|
|
||||||
83
src/user-apps/init/init.c
Normal file
83
src/user-apps/init/init.c
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
/* Calcite, src/user-apps/init/init.c
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <calcite/file-streams.h>
|
||||||
|
#include <kernel-public/files.h>
|
||||||
|
#include <kernel-public/ipc.h>
|
||||||
|
#include <calcite/syscalls.h>
|
||||||
|
|
||||||
|
const char *hello = "hello";
|
||||||
|
|
||||||
|
[[noreturn]] void test(const char *message) {
|
||||||
|
|
||||||
|
ipc_dgram_sender_handle_t handle;
|
||||||
|
if (ipc_create_dgram_sender("calcite-test", &handle) == IPR_SUCCESS)
|
||||||
|
ipc_send_dgram(handle, message, 5);
|
||||||
|
|
||||||
|
end_thread();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_LINE_LENGTH 1023
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
create_thread((void *)&test, (uint64_t)hello);
|
||||||
|
|
||||||
|
struct file_stream *rc;
|
||||||
|
if (open_file_stream("root://calcite/init.rc", &rc) != FAR_SUCCESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int at_file_end = 0;
|
||||||
|
|
||||||
|
while (!at_file_end) {
|
||||||
|
|
||||||
|
char line[MAX_LINE_LENGTH + 1];
|
||||||
|
int line_length = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
char ch = read_file_stream_byte(rc);
|
||||||
|
|
||||||
|
if (ch == -1) {
|
||||||
|
at_file_end = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ch == '\n')
|
||||||
|
break;
|
||||||
|
if (line_length == MAX_LINE_LENGTH) {
|
||||||
|
while (1) {
|
||||||
|
ch = read_file_stream_byte(rc);
|
||||||
|
if (ch == -1 || ch == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
line[line_length++] = ch;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line_length == 0 || line[0] == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
line[line_length] = 0;
|
||||||
|
start_elf(line);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
1
src/user-apps/init/libraries.txt
Normal file
1
src/user-apps/init/libraries.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
calcite
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <kernel-public/syscall-numbers.h>
|
#include <kernel-public/syscall-numbers.h>
|
||||||
#include <kernel-public/files.h>
|
#include <kernel-public/files.h>
|
||||||
|
#include <kernel-public/ipc.h>
|
||||||
#include <calcite/syscalls.h>
|
#include <calcite/syscalls.h>
|
||||||
|
|
||||||
//defined in syscalls.asm
|
//defined in syscalls.asm
|
||||||
|
|
@ -64,3 +65,30 @@ void *map_pages(uint64_t count) {
|
||||||
void sleep_ms(uint64_t ms_to_sleep) {
|
void sleep_ms(uint64_t ms_to_sleep) {
|
||||||
do_syscall(ms_to_sleep, 0, 0, SYSCALL_SLEEP_MS);
|
do_syscall(ms_to_sleep, 0, 0, SYSCALL_SLEEP_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int start_elf(const char *uri) {
|
||||||
|
return do_syscall((uint64_t)uri, 0, 0, SYSCALL_START_ELF);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ipc_dgram_result ipc_create_dgram_receiver(const char *address, ipc_dgram_receiver_handle_t *handle_out) {
|
||||||
|
return do_syscall(
|
||||||
|
(uint64_t)address, (uint64_t)handle_out, 0, SYSCALL_IPC_CREATE_DGRAM_RECEIVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ipc_dgram_result ipc_create_dgram_sender(const char *address, ipc_dgram_sender_handle_t *handle_out) {
|
||||||
|
return do_syscall(
|
||||||
|
(uint64_t)address, (uint64_t)handle_out, 0, SYSCALL_IPC_CREATE_DGRAM_SENDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ipc_dgram_result ipc_receive_dgram(ipc_dgram_receiver_handle_t handle, void *buffer, int *bytes) {
|
||||||
|
return do_syscall(
|
||||||
|
handle, (uint64_t)buffer, (uint64_t)bytes, SYSCALL_IPC_RECEIVE_DGRAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ipc_dgram_result ipc_send_dgram(ipc_dgram_sender_handle_t handle, const void *data, int bytes) {
|
||||||
|
return do_syscall(handle, (uint64_t)data, bytes, SYSCALL_IPC_SEND_DGRAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_thread(void (*f)(uint64_t x), uint64_t x) {
|
||||||
|
do_syscall((uint64_t)f, x, 0, SYSCALL_CREATE_THREAD);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue