Compare commits
No commits in common. "573bf7aa71a900d3e4fc204300ceea2230b89ec2" and "3636fd21e079c47bd8d62e773e178f68fe9c2052" have entirely different histories.
573bf7aa71
...
3636fd21e0
77 changed files with 362 additions and 2538 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -4,5 +4,7 @@ build/*
|
|||
dependencies/*
|
||||
toolchain/*
|
||||
|
||||
.setup-complete
|
||||
.setup-started
|
||||
euler/build/*
|
||||
kernel/build/*
|
||||
applications/*/build/*
|
||||
libraries/*/build/*
|
||||
|
|
10
0bsd.txt
10
0bsd.txt
|
@ -1,10 +0,0 @@
|
|||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
|
||||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
|
||||
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
@ -1,64 +0,0 @@
|
|||
#include <pake/widgets/fixed-text.hpp>
|
||||
#include <daguerre/psf.hpp>
|
||||
#include <pake/window.hpp>
|
||||
#include <ctime>
|
||||
|
||||
static daguerre::fixed_font<bool> *font;
|
||||
|
||||
std::string time_to_string(time_t t) {
|
||||
|
||||
//convert to edt - TODO: timezones in euler
|
||||
t -= 4 * 3600 * 1024;
|
||||
|
||||
tm *gt = gmtime(&t);
|
||||
|
||||
int hour = (gt->tm_hour - 1) % 12 + 1;
|
||||
int min = gt->tm_min;
|
||||
int sec = gt->tm_sec;
|
||||
bool pm = gt->tm_hour >= 12;
|
||||
|
||||
std::string s;
|
||||
s.resize(8);
|
||||
|
||||
s[0] = hour / 10 + '0'; s[1] = hour % 10 + '0';
|
||||
s[3] = min / 10 + '0'; s[4] = min % 10 + '0';
|
||||
|
||||
s[2] = sec % 2 == 0 ? ':' : ' ';
|
||||
|
||||
s[5] = ' ';
|
||||
s[6] = pm ? 'p' : 'a';
|
||||
s[7] = 'm';
|
||||
|
||||
if (s[0] == '0')
|
||||
s.erase(0, 1);
|
||||
|
||||
return s;
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
font = new daguerre::fixed_font<bool>(
|
||||
daguerre::try_load_psf("/assets/terminus/10x18-bold.psf").value());
|
||||
|
||||
time_t t = euler::syscall::get_time();
|
||||
|
||||
pake::widgets::fixed_text *text =
|
||||
new pake::widgets::fixed_text(time_to_string(t), font,
|
||||
euler::syscall::encode_color(0xaa, 0xaa, 0xaa),
|
||||
euler::syscall::encode_color(0x00, 0x00, 0x00),
|
||||
pake::halign::center, pake::valign::center);
|
||||
|
||||
pake::window w(90, 28, "Clock");
|
||||
w.set_root(std::unique_ptr<pake::widget>(text));
|
||||
w.render_and_send_to_compositor();
|
||||
w.show();
|
||||
|
||||
while (1) {
|
||||
euler::syscall::sleep(1024 - t % 1024);
|
||||
t = euler::syscall::get_time();
|
||||
text->set_text(time_to_string(t));
|
||||
w.render_and_send_to_compositor();
|
||||
}
|
||||
|
||||
}
|
12
applications/goldman/makefile
Normal file
12
applications/goldman/makefile
Normal file
|
@ -0,0 +1,12 @@
|
|||
SOURCES = \
|
||||
main.cpp
|
||||
|
||||
build/%.cpp.o: source/%.cpp
|
||||
@mkdir -p $(@D)
|
||||
$(HILBERT_CC) -c $^ -o $@
|
||||
|
||||
build/goldman.elf: $(SOURCES:%=build/%.o)
|
||||
$(HILBERT_CC) $^ -ldaguerre -o $@
|
||||
|
||||
clean:
|
||||
rm -rf build
|
|
@ -1,57 +0,0 @@
|
|||
#include "input.hpp"
|
||||
#include "main.hpp"
|
||||
|
||||
[[noreturn]] void input_thread_main() {
|
||||
|
||||
euler::syscall::set_thread_name("input thread");
|
||||
|
||||
window *window_being_moved = 0;
|
||||
bool was_mouse_down_before = false;
|
||||
|
||||
while (true) {
|
||||
|
||||
auto result = euler::syscall::get_input_packet();
|
||||
if (std::holds_alternative<euler::syscall::mouse_packet>(result)) {
|
||||
auto packet = std::get<euler::syscall::mouse_packet>(result);
|
||||
|
||||
r->lock();
|
||||
|
||||
int old_x, old_y;
|
||||
r->get_cursor(old_x, old_y);
|
||||
r->bump_cursor(packet.x_changed, packet.y_changed);
|
||||
int new_x, new_y;
|
||||
r->get_cursor(new_x, new_y);
|
||||
|
||||
if (window_being_moved != 0) {
|
||||
if (r->windows.size() == 0 || r->windows.back() != window_being_moved)
|
||||
window_being_moved = 0;
|
||||
else {
|
||||
r->windows.back()->x += new_x - old_x;
|
||||
r->windows.back()->y += new_y - old_y;
|
||||
if (!packet.left_button_down)
|
||||
window_being_moved = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else if (packet.left_button_down && !was_mouse_down_before)
|
||||
for (auto it = r->windows.rbegin(); it != r->windows.rend(); ++it)
|
||||
if (new_x >= (*it)->x && new_y >= (*it)->y &&
|
||||
new_x < (*it)->x + (*it)->contents_with_decorations. width &&
|
||||
new_y < (*it)->y + (*it)->contents_with_decorations.height) {
|
||||
r->move_window_to_front(--it.base());
|
||||
//it is now invalidated, but our window is now r->windows.back()
|
||||
if (new_y < r->windows.back()->y + window::title_height)
|
||||
window_being_moved = r->windows.back();
|
||||
break;
|
||||
}
|
||||
|
||||
r->unlock();
|
||||
r->dispatch_render();
|
||||
|
||||
was_mouse_down_before = packet.left_button_down;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
[[noreturn]] void input_thread_main();
|
|
@ -1,37 +1,79 @@
|
|||
#include <daguerre/framebuffer.hpp>
|
||||
#include <daguerre/ppm.hpp>
|
||||
#include "renderer.hpp"
|
||||
#include "socket.hpp"
|
||||
#include "input.hpp"
|
||||
#include "main.hpp"
|
||||
|
||||
//TODO: handle errors
|
||||
daguerre::hilbert_color trans_color;
|
||||
|
||||
renderer *r;
|
||||
void convert_pointer(
|
||||
daguerre::hilbert_color &dest, const daguerre::hilbert_color &src) {
|
||||
if (src != trans_color)
|
||||
dest = src;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int main(int, char **) {
|
||||
|
||||
euler::syscall::listener_handle listener;
|
||||
euler::syscall::create_socket_listener("hilbert.compositor", listener);
|
||||
trans_color = euler::syscall::encode_color(0xff, 0x00, 0xff);
|
||||
|
||||
r = new renderer(
|
||||
daguerre::get_hilbert_framebuffer(),
|
||||
*daguerre::try_load_ppm("/assets/background.ppm"),
|
||||
euler::syscall::encode_color(0x00, 0x00, 0x00),
|
||||
*daguerre::try_load_ppm("/assets/pointer.ppm"),
|
||||
euler::syscall::encode_color(0xff, 0x00, 0xff));
|
||||
daguerre::image<daguerre::hilbert_color> framebuffer =
|
||||
daguerre::get_hilbert_framebuffer();
|
||||
|
||||
euler::syscall::start_thread([]() { r->render_thread_main(); });
|
||||
euler::syscall::start_thread(input_thread_main);
|
||||
int fw = framebuffer.width;
|
||||
int fh = framebuffer.height;
|
||||
|
||||
r->dispatch_render();
|
||||
daguerre::image<daguerre::hilbert_color> double_buffer(fw, fh);
|
||||
|
||||
euler::syscall::set_thread_name("socket listener thread");
|
||||
std::optional<daguerre::image<daguerre::hilbert_color>>
|
||||
background_original = daguerre::try_load_ppm("/assets/background.ppm");
|
||||
|
||||
while (true) {
|
||||
euler::syscall::stream_handle socket;
|
||||
euler::syscall::accept_socket_connection(listener, socket);
|
||||
euler::syscall::start_thread(socket_thread_main, socket);
|
||||
daguerre::image<daguerre::hilbert_color> background;
|
||||
|
||||
if (background_original.has_value())
|
||||
background = background_original->stretch(fw, fh);
|
||||
else {
|
||||
background = daguerre::image<daguerre::hilbert_color>(fw, fh);
|
||||
background.fill(euler::syscall::encode_color(0, 0, 0));
|
||||
}
|
||||
|
||||
std::optional<daguerre::image<daguerre::hilbert_color>>
|
||||
pointer_original = daguerre::try_load_ppm("/assets/pointer.ppm");
|
||||
|
||||
if (!pointer_original.has_value())
|
||||
//TODO
|
||||
while (1)
|
||||
;
|
||||
|
||||
daguerre::image<daguerre::hilbert_color>
|
||||
pointer = std::move(*pointer_original);
|
||||
|
||||
int mouse_x = fw / 2;
|
||||
int mouse_y = fh / 2;
|
||||
|
||||
while (true) {
|
||||
|
||||
double_buffer.copy_from(background, 0, 0);
|
||||
double_buffer.convert_from(pointer, mouse_x, mouse_y, 0, 0,
|
||||
std::min(pointer. width, double_buffer. width - mouse_x),
|
||||
std::min(pointer.height, double_buffer.height - mouse_y),
|
||||
&convert_pointer);
|
||||
|
||||
framebuffer.copy_from(double_buffer, 0, 0);
|
||||
|
||||
auto result = euler::syscall::get_input_packet();
|
||||
if (std::holds_alternative<euler::syscall::mouse_packet>(result)) {
|
||||
const auto &packet = std::get<euler::syscall::mouse_packet>(result);
|
||||
mouse_x += packet.x_changed;
|
||||
mouse_y += packet.y_changed;
|
||||
if (mouse_x < 0)
|
||||
mouse_x = 0;
|
||||
else if (mouse_x >= fw)
|
||||
mouse_x = fw - 1;
|
||||
if (mouse_y < 0)
|
||||
mouse_y = 0;
|
||||
else if (mouse_y >= fh)
|
||||
mouse_y = fh - 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "renderer.hpp"
|
||||
|
||||
extern renderer *r;
|
|
@ -1,124 +0,0 @@
|
|||
#include "renderer.hpp"
|
||||
|
||||
renderer::renderer(
|
||||
daguerre::image<daguerre::hilbert_color> &&fb,
|
||||
daguerre::image<daguerre::hilbert_color> &&bg,
|
||||
daguerre::hilbert_color bgc,
|
||||
daguerre::image<daguerre::hilbert_color> &&c,
|
||||
daguerre::hilbert_color cbg)
|
||||
|
||||
: framebuffer(std::move(fb)),
|
||||
double_buffer(framebuffer.width, framebuffer.height),
|
||||
background(std::move(bg)), cursor(std::move(c)), cursor_background(cbg),
|
||||
cursor_x(framebuffer.width / 2), cursor_y(framebuffer.height / 2) {
|
||||
|
||||
euler::syscall::create_private_socket(dispatcher_handle_1, dispatcher_handle_2);
|
||||
|
||||
if (background.width != framebuffer.width ||
|
||||
background.height != framebuffer.height) {
|
||||
|
||||
daguerre::image<daguerre::hilbert_color>
|
||||
new_background(framebuffer.width, framebuffer.height);
|
||||
|
||||
new_background.fill(bgc);
|
||||
|
||||
int from_x = 0;
|
||||
int from_y = 0;
|
||||
int to_x = framebuffer.width / 2 - background.width / 2;
|
||||
int to_y = framebuffer.height / 2 - background.height / 2;
|
||||
int width = background.width;
|
||||
int height = background.height;
|
||||
|
||||
daguerre::make_safe(to_x, from_x, width, 0, framebuffer.width);
|
||||
daguerre::make_safe(to_y, from_y, height, 0, framebuffer.height);
|
||||
|
||||
new_background.copy_from(background, to_x, to_y, from_x, from_y, width, height);
|
||||
background = std::move(new_background);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class color_t>
|
||||
void overlay_trans(color_t &to, const color_t &from, const color_t ¶m) {
|
||||
if (from != param)
|
||||
to = from;
|
||||
}
|
||||
|
||||
void renderer::do_render() {
|
||||
|
||||
double_buffer.copy_from(background, 0, 0);
|
||||
|
||||
for (auto it = windows.begin(); it != windows.end(); ++it) {
|
||||
int tx = (*it)->x, ty = (*it)->y, fx = 0, fy = 0;
|
||||
int w = (*it)->contents_with_decorations.width;
|
||||
int h = (*it)->contents_with_decorations.height;
|
||||
daguerre::make_safe(tx, fx, w, 0, double_buffer.width);
|
||||
daguerre::make_safe(ty, fy, h, 0, double_buffer.height);
|
||||
double_buffer.copy_from(
|
||||
(*it)->contents_with_decorations, tx, ty, fx, fy, w, h);
|
||||
}
|
||||
|
||||
double_buffer.convert_from(
|
||||
cursor_background, cursor, cursor_x, cursor_y, 0, 0,
|
||||
std::min(cursor.width, framebuffer.width - cursor_x),
|
||||
std::min(cursor.height, framebuffer.height - cursor_y),
|
||||
&overlay_trans);
|
||||
|
||||
}
|
||||
|
||||
[[noreturn]] void renderer::render_thread_main() {
|
||||
euler::syscall::set_thread_name("render thread");
|
||||
while (true) {
|
||||
uint8_t byte;
|
||||
euler::syscall::read_from_stream(dispatcher_handle_2, 1, &byte);
|
||||
mut.lock();
|
||||
euler::syscall::clear_socket_read_queue(dispatcher_handle_2);
|
||||
do_render();
|
||||
mut.unlock();
|
||||
framebuffer.copy_from(double_buffer, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void renderer::get_cursor(int &x_out, int &y_out) {
|
||||
x_out = cursor_x;
|
||||
y_out = cursor_y;
|
||||
}
|
||||
|
||||
void renderer::bump_cursor(int x_offset, int y_offset) {
|
||||
|
||||
cursor_x += x_offset;
|
||||
if (cursor_x < 0)
|
||||
cursor_x = 0;
|
||||
else if (cursor_x >= framebuffer.width)
|
||||
cursor_x = framebuffer.width - 1;
|
||||
|
||||
cursor_y += y_offset;
|
||||
if (cursor_y < 0)
|
||||
cursor_y = 0;
|
||||
else if (cursor_y >= framebuffer.height)
|
||||
cursor_y = framebuffer.height - 1;
|
||||
|
||||
}
|
||||
|
||||
void renderer::move_window_to_front(std::list<window *>::iterator w) {
|
||||
window *wp = *w;
|
||||
windows.erase(w);
|
||||
if (windows.size() != 0)
|
||||
windows.back()->draw_decorations(false);
|
||||
windows.push_back(wp);
|
||||
wp->draw_decorations(true);
|
||||
}
|
||||
|
||||
void renderer::add_window(window *w) {
|
||||
if (windows.size() != 0)
|
||||
windows.back()->draw_decorations(false);
|
||||
w->draw_decorations(true);
|
||||
windows.push_back(w);
|
||||
}
|
||||
|
||||
void renderer::remove_window(window *w) {
|
||||
windows.remove(w);
|
||||
if (windows.size() != 0)
|
||||
windows.back()->draw_decorations(true);
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <daguerre/image.hpp>
|
||||
#include "window.hpp"
|
||||
#include <mutex>
|
||||
#include <list>
|
||||
|
||||
class renderer {
|
||||
|
||||
daguerre::image<daguerre::hilbert_color> framebuffer;
|
||||
daguerre::image<daguerre::hilbert_color> double_buffer;
|
||||
|
||||
daguerre::image<daguerre::hilbert_color> background;
|
||||
daguerre::image<daguerre::hilbert_color> cursor;
|
||||
daguerre::hilbert_color cursor_background;
|
||||
|
||||
int cursor_x;
|
||||
int cursor_y;
|
||||
|
||||
std::mutex mut;
|
||||
|
||||
euler::syscall::stream_handle
|
||||
dispatcher_handle_1, dispatcher_handle_2;
|
||||
|
||||
void do_render();
|
||||
|
||||
public:
|
||||
//all of the shown windows, sorted from furthest back to furthest front.
|
||||
//while the renderer is not locked, the contents of this can change and
|
||||
//iterators can be invalided. this should not be reordered, added to, or
|
||||
//have elements removed from outside the renderer.
|
||||
std::list<window *> windows;
|
||||
|
||||
renderer(
|
||||
daguerre::image<daguerre::hilbert_color> &&framebuffer,
|
||||
daguerre::image<daguerre::hilbert_color> &&background,
|
||||
daguerre::hilbert_color background_color,
|
||||
daguerre::image<daguerre::hilbert_color> &&cursor,
|
||||
daguerre::hilbert_color cursor_background);
|
||||
|
||||
inline ~renderer() {
|
||||
euler::syscall::close_stream(dispatcher_handle_1);
|
||||
euler::syscall::close_stream(dispatcher_handle_2);
|
||||
}
|
||||
|
||||
renderer(const renderer &) = delete;
|
||||
renderer &operator =(const renderer &) = delete;
|
||||
|
||||
[[noreturn]] void render_thread_main();
|
||||
|
||||
inline void lock() { mut.lock(); }
|
||||
inline void unlock() { mut.unlock(); }
|
||||
|
||||
inline void dispatch_render() {
|
||||
uint8_t byte = 0;
|
||||
euler::syscall::write_to_stream(dispatcher_handle_1, 1, &byte);
|
||||
}
|
||||
|
||||
//gets the current position of the cursor. this should
|
||||
//only be called while the renderer is locked.
|
||||
void get_cursor(int &x_out, int &y_out);
|
||||
|
||||
//this adds x_offset and y_offset to the current cursor position, and then
|
||||
//clamps the cursor position to have its top-left pixel inside the frame.
|
||||
//this should only be called while the renderer is locked.
|
||||
void bump_cursor(int x_offset, int y_offset);
|
||||
|
||||
//moves the pointed to window to the front of the window stack.
|
||||
//this should only be called while the renderer is locked.
|
||||
void move_window_to_front(std::list<window *>::iterator w);
|
||||
|
||||
void add_window(window *w);
|
||||
void remove_window(window *w);
|
||||
|
||||
inline bool is_top(window *w) {
|
||||
return windows.size() != 0 && w == windows.back();
|
||||
}
|
||||
|
||||
};
|
|
@ -1,152 +0,0 @@
|
|||
#include <daguerre/image.hpp>
|
||||
#include "socket.hpp"
|
||||
#include "window.hpp"
|
||||
#include "main.hpp"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
struct socket_state {
|
||||
|
||||
euler::syscall::stream_handle socket;
|
||||
window *w;
|
||||
|
||||
bool try_show_window() {
|
||||
|
||||
if (w->is_shown)
|
||||
return false;
|
||||
|
||||
r->lock();
|
||||
r->add_window(w);
|
||||
r->unlock();
|
||||
r->dispatch_render();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool try_hide_window() {
|
||||
|
||||
if (!w->is_shown)
|
||||
return false;
|
||||
|
||||
r->lock();
|
||||
r->remove_window(w);
|
||||
r->unlock();
|
||||
r->dispatch_render();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool try_set_window_dimensions() {
|
||||
|
||||
struct [[gnu::packed]] { uint32_t width; uint32_t height; } packet;
|
||||
if (euler::syscall::read_from_stream(socket, sizeof(packet), &packet) !=
|
||||
euler::syscall::stream_result::success)
|
||||
return false;
|
||||
|
||||
if (packet. width > __INT_MAX__ - window::decorations_extra_width ||
|
||||
packet.height > __INT_MAX__ - window::decorations_extra_height)
|
||||
return false;
|
||||
|
||||
r->lock();
|
||||
w->set_size(packet.width, packet.height);
|
||||
w->draw_decorations(r->is_top(w));
|
||||
r->unlock();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool try_set_window_title() {
|
||||
|
||||
uint32_t length;
|
||||
if (euler::syscall::read_from_stream(socket, 4, &length) !=
|
||||
euler::syscall::stream_result::success)
|
||||
return false;
|
||||
|
||||
std::string title;
|
||||
title.resize(length);
|
||||
if (euler::syscall::read_from_stream(socket, length, title.data()) !=
|
||||
euler::syscall::stream_result::success)
|
||||
return false;
|
||||
|
||||
r->lock();
|
||||
w->title = std::move(title);
|
||||
w->draw_decorations(r->is_top(w));
|
||||
r->unlock();
|
||||
r->dispatch_render();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool try_update_window_region() {
|
||||
|
||||
struct [[gnu::packed]] {
|
||||
uint32_t start_x; uint32_t start_y; uint32_t width; uint32_t height;
|
||||
} packet;
|
||||
if (euler::syscall::read_from_stream(socket, sizeof(packet), &packet) !=
|
||||
euler::syscall::stream_result::success)
|
||||
return false;
|
||||
|
||||
static_assert(__INT_MAX__ <= __UINT64_MAX__);
|
||||
if ((uint64_t)packet.start_x + packet. width > (uint64_t)w->contents. width ||
|
||||
(uint64_t)packet.start_y + packet.height > (uint64_t)w->contents.height)
|
||||
return false;
|
||||
|
||||
daguerre::image<daguerre::hilbert_color> content(packet.width, packet.height);
|
||||
if (euler::syscall::read_from_stream(
|
||||
socket, packet.width * packet.height * 4, content.buffer) !=
|
||||
euler::syscall::stream_result::success)
|
||||
return false;
|
||||
|
||||
r->lock();
|
||||
w->contents.copy_from(content, packet.start_x, packet.start_y);
|
||||
r->unlock();
|
||||
r->dispatch_render();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool try_process_request() {
|
||||
|
||||
uint8_t type;
|
||||
if (euler::syscall::read_from_stream(socket, 1, &type) !=
|
||||
euler::syscall::stream_result::success)
|
||||
return false;
|
||||
|
||||
switch (type) {
|
||||
case 0x00: return try_show_window();
|
||||
case 0x01: return try_hide_window();
|
||||
case 0x02: return try_set_window_dimensions();
|
||||
case 0x03: return try_set_window_title();
|
||||
case 0x04: return try_update_window_region();
|
||||
default: return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
[[noreturn]] void socket_thread_main(euler::syscall::stream_handle socket) {
|
||||
|
||||
euler::syscall::set_thread_name("socket thread");
|
||||
|
||||
int x, y;
|
||||
r->get_cursor(x, y);
|
||||
|
||||
window *w = new window(x, y);
|
||||
socket_state *state = new socket_state {
|
||||
.socket = socket, .w = w };
|
||||
|
||||
while (state->try_process_request()) ;
|
||||
|
||||
if (w->is_shown) {
|
||||
r->lock();
|
||||
r->remove_window(w);
|
||||
r->unlock();
|
||||
}
|
||||
|
||||
delete state;
|
||||
delete w;
|
||||
euler::syscall::close_stream(socket);
|
||||
euler::syscall::end_this_thread(0);
|
||||
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <euler/syscall.hpp>
|
||||
|
||||
[[noreturn]] void socket_thread_main(euler::syscall::stream_handle socket);
|
|
@ -1,83 +0,0 @@
|
|||
#include <daguerre/psf.hpp>
|
||||
#include "renderer.hpp"
|
||||
#include "window.hpp"
|
||||
#include <cassert>
|
||||
|
||||
//TODO: make these statically intialized once that is implemented
|
||||
bool have_initialized_decoration_stuff;
|
||||
daguerre::fixed_font<bool> *title_font;
|
||||
daguerre::hilbert_color border_color_top;
|
||||
daguerre::hilbert_color border_color_not_top;
|
||||
daguerre::hilbert_color title_color;
|
||||
|
||||
void window::set_size(int width, int height) {
|
||||
int center_x = x + contents_with_decorations. width / 2;
|
||||
int center_y = y + contents_with_decorations.height / 2;
|
||||
contents_with_decorations =
|
||||
daguerre::image<daguerre::hilbert_color>(width + 4, height + 18);
|
||||
contents = daguerre::image<daguerre::hilbert_color>(
|
||||
width, height,
|
||||
&contents_with_decorations.at(2, 16),
|
||||
contents_with_decorations.buffer_pitch, false);
|
||||
x = center_x - contents_with_decorations. width / 2;
|
||||
y = center_y - contents_with_decorations.height / 2;
|
||||
}
|
||||
|
||||
void title_converter(
|
||||
daguerre::hilbert_color &out, const bool &in, const bool &top) {
|
||||
out = in ? title_color : top ? border_color_top : border_color_not_top;
|
||||
}
|
||||
|
||||
void window::draw_decorations(bool top) {
|
||||
|
||||
//TODO: handle error loading font.
|
||||
//see also comment on title_font declaration.
|
||||
if (!have_initialized_decoration_stuff) {
|
||||
title_font = new daguerre::fixed_font<bool>(
|
||||
*daguerre::try_load_psf("/assets/terminus/6x12.psf"));
|
||||
assert(title_font->glyph_height == 12);
|
||||
border_color_top = euler::syscall::encode_color(0x00, 0x3f, 0xff);
|
||||
border_color_not_top = euler::syscall::encode_color(0x22, 0x22, 0x22);
|
||||
title_color = euler::syscall::encode_color(0xff, 0xff, 0xff);
|
||||
have_initialized_decoration_stuff = true;
|
||||
}
|
||||
|
||||
static_assert( decorations_extra_width == 4);
|
||||
static_assert(decorations_extra_height == 18);
|
||||
static_assert( title_height == 16);
|
||||
|
||||
auto border_color = top ? border_color_top : border_color_not_top;
|
||||
|
||||
contents_with_decorations.fill(border_color, 0, 0,
|
||||
contents_with_decorations.width, 16);
|
||||
contents_with_decorations.fill(
|
||||
border_color, 0, contents_with_decorations.height - 2,
|
||||
contents_with_decorations.width, 2);
|
||||
contents_with_decorations.fill(border_color, 0, 16,
|
||||
2, contents_with_decorations.height - 18);
|
||||
contents_with_decorations.fill(border_color,
|
||||
contents_with_decorations.width - 2, 16,
|
||||
2, contents_with_decorations.height - 18);
|
||||
|
||||
//TODO: make UTF-8--safe
|
||||
unsigned max_title_length =
|
||||
contents_with_decorations.width / title_font->glyph_width;
|
||||
std::string *title_to_draw;
|
||||
std::string shortened_title;
|
||||
if (title.size() > max_title_length) {
|
||||
shortened_title.resize(max_title_length - 3);
|
||||
memcpy(shortened_title.data(), title.data(), max_title_length - 3);
|
||||
shortened_title[max_title_length - 3] = '.';
|
||||
shortened_title[max_title_length - 2] = '.';
|
||||
shortened_title[max_title_length - 1] = '.';
|
||||
title_to_draw = &shortened_title;
|
||||
}
|
||||
else
|
||||
title_to_draw = &title;
|
||||
|
||||
contents_with_decorations.render_text(*title_font, top,
|
||||
contents_with_decorations.width / 2 -
|
||||
(title_to_draw->size() * title_font->glyph_width) / 2,
|
||||
2, title_to_draw->data(), title_converter);
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <daguerre/image.hpp>
|
||||
|
||||
struct window {
|
||||
|
||||
static constexpr int decorations_extra_width = 4;
|
||||
static constexpr int decorations_extra_height = 18;
|
||||
static constexpr int title_height = 16;
|
||||
|
||||
daguerre::image<daguerre::hilbert_color> contents_with_decorations;
|
||||
daguerre::image<daguerre::hilbert_color> contents;
|
||||
|
||||
int x;
|
||||
int y;
|
||||
|
||||
bool is_shown;
|
||||
|
||||
std::string title;
|
||||
|
||||
void set_size(int width, int height);
|
||||
void draw_decorations(bool top);
|
||||
|
||||
inline window(int center_x, int center_y)
|
||||
: x(center_x - decorations_extra_width / 2),
|
||||
y(center_y - decorations_extra_height / 2),
|
||||
is_shown(false) {
|
||||
set_size(0, 0);
|
||||
draw_decorations(false);
|
||||
}
|
||||
|
||||
};
|
|
@ -1,42 +0,0 @@
|
|||
#include <pake/widgets/fixed-text.hpp>
|
||||
#include <daguerre/psf.hpp>
|
||||
#include <pake/window.hpp>
|
||||
|
||||
daguerre::fixed_font<bool> *font;
|
||||
|
||||
int main() {
|
||||
|
||||
font = new daguerre::fixed_font<bool>(
|
||||
daguerre::try_load_psf("/assets/terminus/10x18-bold.psf").value());
|
||||
|
||||
pake::widgets::fixed_text *text =
|
||||
new pake::widgets::fixed_text("Hello, world!", font,
|
||||
euler::syscall::encode_color(0xaa, 0xaa, 0xaa),
|
||||
euler::syscall::encode_color(0x00, 0x00, 0x00),
|
||||
pake::halign::center, pake::valign::center);
|
||||
|
||||
pake::window w(300, 200, "Hello");
|
||||
w.set_root(std::unique_ptr<pake::widget>(text));
|
||||
w.render_and_send_to_compositor();
|
||||
w.show();
|
||||
|
||||
pake::widgets::fixed_text *text2 =
|
||||
new pake::widgets::fixed_text("H!", font,
|
||||
euler::syscall::encode_color(0xaa, 0xaa, 0xaa),
|
||||
euler::syscall::encode_color(0x00, 0x00, 0x00),
|
||||
pake::halign::center, pake::valign::center);
|
||||
|
||||
pake::window w2(100, 50, "Hello 2");
|
||||
w2.set_root(std::unique_ptr<pake::widget>(text2));
|
||||
w2.render_and_send_to_compositor();
|
||||
w2.show();
|
||||
|
||||
//TODO: call event loop
|
||||
|
||||
euler::syscall::stream_handle h1, h2;
|
||||
euler::syscall::create_private_socket(h1, h2);
|
||||
uint8_t byte;
|
||||
while (1)
|
||||
euler::syscall::read_from_stream(h1, 1, &byte);
|
||||
|
||||
}
|
12
applications/init/makefile
Normal file
12
applications/init/makefile
Normal file
|
@ -0,0 +1,12 @@
|
|||
SOURCES = \
|
||||
main.cpp
|
||||
|
||||
build/%.cpp.o: source/%.cpp
|
||||
@mkdir -p $(@D)
|
||||
$(HILBERT_CC) -c $^ -o $@
|
||||
|
||||
build/init.elf: $(SOURCES:%=build/%.o)
|
||||
$(HILBERT_CC) $^ -o $@
|
||||
|
||||
clean:
|
||||
rm -rf build
|
|
@ -1,8 +1,11 @@
|
|||
#include <euler/syscall.hpp>
|
||||
|
||||
int main() {
|
||||
//this does not keep track of the processes or whether they have started
|
||||
//successfully, nor does it set their argc, argv, stdin, stdout, or stderr.
|
||||
|
||||
int main(int, char **) {
|
||||
euler::syscall::process_handle dummy;
|
||||
euler::syscall::start_process("/bin/compositor", {}, {}, dummy);
|
||||
euler::syscall::start_process("/bin/clock", {}, {}, dummy);
|
||||
euler::syscall::start_process("/bin/hello", {}, {}, dummy);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
rm -rf dependencies toolchain .setup-started .setup-complete
|
|
@ -1,9 +1,13 @@
|
|||
compositors listen on the socket id "hilbert.compositor".
|
||||
|
||||
there is a one-to-one correspondence between sockets to the compositor and
|
||||
windows. when a socket is opened, a window is created, and when a socket is
|
||||
closed, its window is destroyed. this socket can be gifted to another process,
|
||||
and the other process then becomes the window's owner.
|
||||
when a window is opened by an application, that window can only be referred to
|
||||
on that stream. the opaque value given in the "window opened" message refers to
|
||||
that window in future messages on that stream. it is guaranteed to be distinct
|
||||
for different windows on the same stream, and in no way guaranteed to be
|
||||
distinct for different windows on different streams. the window is bound
|
||||
just to the stream, not to the application. if the stream where a window
|
||||
was created is gifted to a new process, the new process has complete control
|
||||
over the window, and the compositor does not need to be informed.
|
||||
|
||||
data types:
|
||||
|
||||
|
@ -14,28 +18,27 @@ data types:
|
|||
color rectangle:
|
||||
multiple hilbert colors, top to bottom by row, left to right within row
|
||||
|
||||
window:
|
||||
opaque word (given in "window opened" message after "open window" message)
|
||||
|
||||
messages from applications to compositor:
|
||||
|
||||
show window:
|
||||
open window:
|
||||
byte: 0x00
|
||||
|
||||
hide window:
|
||||
byte: 0x01
|
||||
|
||||
set window dimensions:
|
||||
byte: 0x02
|
||||
dword: width
|
||||
dword: height
|
||||
|
||||
set window title:
|
||||
byte: 0x03
|
||||
dword: length in bytes
|
||||
bytes: title
|
||||
dword: window width
|
||||
dword: window height
|
||||
|
||||
update window region:
|
||||
byte: 0x04
|
||||
byte: 0x01
|
||||
window: the window
|
||||
dword: start x
|
||||
dword: start y
|
||||
dword: width
|
||||
dword: height
|
||||
color rectangle: new content
|
||||
color rectangle: the data
|
||||
|
||||
messages from compositor to application:
|
||||
|
||||
window opened:
|
||||
byte: 0x00
|
||||
window: the window
|
||||
|
|
3
documentation/kernel-interfaces/app-entry.txt
Normal file
3
documentation/kernel-interfaces/app-entry.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
on entry, the stack is set up, and all registers other than rsp are set to 0.
|
||||
the ARGC environment variable holds the number of arguments to main.
|
||||
the ARGV0, ARGV1, ARGV2, etc environment variables hold those arguments.
|
|
@ -4,8 +4,6 @@ rcx, rflags, r8-r11 are clobbered.
|
|||
|
||||
interrupts (including the timer!) are disabled during system calls.
|
||||
|
||||
a "mibisecond" is a 1024th of a second
|
||||
|
||||
stream result:
|
||||
0 = success
|
||||
1 = bad handle
|
||||
|
@ -157,10 +155,7 @@ start process:
|
|||
qword: stream handle here
|
||||
qword: new stream handle in child
|
||||
new handle must be < 65536
|
||||
any gifted streams must not have threads waiting to read from our end.
|
||||
any environment variables in the current process whose names do not begin
|
||||
with an underscore are also set in the child process. the environment
|
||||
variables in the process start info override any with the same name.
|
||||
any gifted streams must not have threads waiting to read from our end
|
||||
|
||||
end this process:
|
||||
rax in: 17
|
||||
|
@ -203,16 +198,3 @@ get environment variable value:
|
|||
rdi in: pointer to variable name
|
||||
rsi in: variable name length
|
||||
rdx in: pointer to buffer for variable value
|
||||
|
||||
set thread name:
|
||||
rax in: 24
|
||||
rdi in: pointer to thread name
|
||||
rsi in: thread name length
|
||||
|
||||
sleep:
|
||||
rax in: 25
|
||||
rdi in: "mibiseconds" to sleep for
|
||||
|
||||
get time:
|
||||
rax in: 26
|
||||
rax out: "mibiseconds" since january 1st 2000
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace euler {
|
||||
|
||||
[[noreturn]] inline void assert_failed() {
|
||||
//TODO: log error and abort
|
||||
while (1) ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define assert(cond) ((cond) ? (void)0 : ::euler::assert_failed());
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <std/condition-variable.hpp>
|
|
@ -1,20 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
typedef uint64_t time_t;
|
||||
|
||||
struct tm {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
};
|
||||
|
||||
time_t time(time_t *arg);
|
||||
tm *gmtime(const time_t *time);
|
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <std/fwd/string.hpp>
|
||||
#include <std/fwd/vector.hpp>
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace euler::syscall {
|
||||
|
||||
|
@ -124,30 +124,6 @@ namespace euler::syscall {
|
|||
//entry_point must not return
|
||||
void start_thread(void (*entry_point)(uint64_t), uint64_t arg);
|
||||
|
||||
//entry_point must not return
|
||||
template <class obj_t>
|
||||
void start_thread(void (*entry_point)(obj_t *), obj_t *arg) {
|
||||
start_thread((void (*)(uint64_t))entry_point, (uint64_t)arg);
|
||||
}
|
||||
|
||||
//entry_point must not return
|
||||
template <class obj_t>
|
||||
void start_thread(void (*entry_point)(const obj_t *), const obj_t *arg) {
|
||||
start_thread((void (*)(uint64_t))entry_point, (uint64_t)arg);
|
||||
}
|
||||
|
||||
//entry_point must not return
|
||||
template <class obj_t>
|
||||
void start_thread(void (*entry_point)(obj_t &), obj_t &arg) {
|
||||
start_thread((void (*)(uint64_t))entry_point, (uint64_t)&arg);
|
||||
}
|
||||
|
||||
//entry_point must not return
|
||||
template <class obj_t>
|
||||
void start_thread(void (*entry_point)(const obj_t &), const obj_t &arg) {
|
||||
start_thread((void (*)(uint64_t))entry_point, (uint64_t)&arg);
|
||||
}
|
||||
|
||||
//entry_point must not return
|
||||
void start_thread(void (*entry_point)());
|
||||
|
||||
|
@ -157,14 +133,4 @@ namespace euler::syscall {
|
|||
std::optional<std::string> try_get_environment_variable(
|
||||
const std::string &name);
|
||||
|
||||
void set_thread_name(const std::string &name);
|
||||
|
||||
void sleep(uint64_t mibiseconds);
|
||||
|
||||
//out is mibiseconds since january 1st 2000
|
||||
uint64_t get_time();
|
||||
|
||||
}
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <std/list.hpp>
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <std/unique-lock.hpp>
|
||||
#include <std/mutex.hpp>
|
|
@ -1,7 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <std/fwd/allocator.hpp>
|
||||
|
||||
#include <euler/heap.hpp>
|
||||
|
||||
namespace std {
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace std {
|
||||
|
||||
class condition_variable {
|
||||
|
||||
//TODO
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace std {
|
||||
template <class T>
|
||||
struct allocator;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace std {
|
||||
class string;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <std/fwd/allocator.hpp>
|
||||
|
||||
namespace std {
|
||||
template <class T, class Allocator = std::allocator<T>>
|
||||
class vector;
|
||||
}
|
|
@ -1,275 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
namespace std {
|
||||
|
||||
template <class T>
|
||||
class list {
|
||||
|
||||
public:
|
||||
struct node {
|
||||
T value;
|
||||
node *prev;
|
||||
node *next;
|
||||
};
|
||||
|
||||
template <class V>
|
||||
struct generic_iterator {
|
||||
|
||||
node *the_node;
|
||||
node *last_node;
|
||||
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using reference = V &;
|
||||
using pointer = V *;
|
||||
using value_type = V;
|
||||
using difference_type = size_t;
|
||||
|
||||
bool operator ==(const generic_iterator &other) const {
|
||||
return the_node == other.the_node;
|
||||
}
|
||||
|
||||
bool operator !=(const generic_iterator &other) const {
|
||||
return the_node != other.the_node;
|
||||
}
|
||||
|
||||
V &operator *() {
|
||||
return the_node->value;
|
||||
}
|
||||
|
||||
V *operator ->() {
|
||||
return &the_node->value;
|
||||
}
|
||||
|
||||
generic_iterator &operator ++() {
|
||||
the_node = the_node->next;
|
||||
return *this;
|
||||
}
|
||||
|
||||
generic_iterator &operator --() {
|
||||
if (the_node == 0)
|
||||
the_node = last_node;
|
||||
else
|
||||
the_node = the_node->prev;
|
||||
return *this;
|
||||
}
|
||||
|
||||
generic_iterator operator -(size_t count) const {
|
||||
generic_iterator it = { .the_node = the_node };
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
--it;
|
||||
return it;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using iterator = generic_iterator< T>;
|
||||
using const_iterator = generic_iterator<const T>;
|
||||
|
||||
using reverse_iterator = std::reverse_iterator< iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
private:
|
||||
node *first_node;
|
||||
node *last_node;
|
||||
size_t count;
|
||||
|
||||
public:
|
||||
void push_back(const T &value) {
|
||||
node *n = new node { .value = value,
|
||||
.prev = last_node, .next = 0 };
|
||||
if (last_node) last_node->next = n;
|
||||
else first_node = n;
|
||||
last_node = n;
|
||||
++count;
|
||||
}
|
||||
|
||||
void push_back(T &&value) {
|
||||
node *n = new node {
|
||||
.value = std::move(value),
|
||||
.prev = last_node, .next = 0 };
|
||||
if (last_node) last_node->next = n;
|
||||
else first_node = n;
|
||||
last_node = n;
|
||||
++count;
|
||||
}
|
||||
|
||||
iterator erase(iterator pos) {
|
||||
--count;
|
||||
auto *n = pos.the_node;
|
||||
auto *r = n->next;
|
||||
if (n->prev) n->prev->next = n->next;
|
||||
else first_node = n->next;
|
||||
if (n->next) n->next->prev = n->prev;
|
||||
else last_node = n->prev;
|
||||
delete n;
|
||||
return iterator {
|
||||
.the_node = r,
|
||||
.last_node = last_node
|
||||
};
|
||||
}
|
||||
|
||||
iterator begin() noexcept {
|
||||
return iterator {
|
||||
.the_node = first_node,
|
||||
.last_node = last_node
|
||||
};
|
||||
}
|
||||
|
||||
iterator end() noexcept {
|
||||
return iterator {
|
||||
.the_node = 0,
|
||||
.last_node = last_node
|
||||
};
|
||||
}
|
||||
|
||||
const_iterator begin() const noexcept {
|
||||
return iterator {
|
||||
.the_node = first_node,
|
||||
.last_node = last_node
|
||||
};
|
||||
}
|
||||
|
||||
const_iterator end() const noexcept {
|
||||
return iterator {
|
||||
.the_node = 0,
|
||||
.last_node = last_node
|
||||
};
|
||||
}
|
||||
|
||||
const_iterator cbegin() const noexcept {
|
||||
return iterator {
|
||||
.the_node = first_node,
|
||||
.last_node = last_node
|
||||
};
|
||||
}
|
||||
|
||||
const_iterator cend() const noexcept {
|
||||
return iterator {
|
||||
.the_node = 0,
|
||||
.last_node = last_node
|
||||
};
|
||||
}
|
||||
|
||||
reverse_iterator rbegin() noexcept {
|
||||
return reverse_iterator(
|
||||
iterator {
|
||||
.the_node = 0,
|
||||
.last_node = last_node
|
||||
});
|
||||
}
|
||||
|
||||
reverse_iterator rend() noexcept {
|
||||
return reverse_iterator(
|
||||
iterator {
|
||||
.the_node = first_node,
|
||||
.last_node = last_node
|
||||
});
|
||||
}
|
||||
|
||||
const_reverse_iterator rbegin() const noexcept {
|
||||
return const_reverse_iterator(
|
||||
iterator {
|
||||
.the_node = 0,
|
||||
.last_node = last_node
|
||||
});
|
||||
}
|
||||
|
||||
const_reverse_iterator rend() const noexcept {
|
||||
return const_reverse_iterator(
|
||||
iterator {
|
||||
.the_node = first_node,
|
||||
.last_node = last_node
|
||||
});
|
||||
}
|
||||
|
||||
const_reverse_iterator crbegin() const noexcept {
|
||||
return const_reverse_iterator(
|
||||
iterator {
|
||||
.the_node = 0,
|
||||
.last_node = last_node
|
||||
});
|
||||
}
|
||||
|
||||
const_reverse_iterator crend() const noexcept {
|
||||
return const_reverse_iterator(
|
||||
iterator {
|
||||
.the_node = first_node,
|
||||
.last_node = last_node
|
||||
});
|
||||
}
|
||||
|
||||
size_t remove(const T &value) {
|
||||
size_t removed = 0;
|
||||
auto it = begin();
|
||||
while (it != end())
|
||||
if (*it == value) {
|
||||
it = erase(it);
|
||||
++removed;
|
||||
}
|
||||
else
|
||||
++it;
|
||||
count -= removed;
|
||||
return removed;
|
||||
}
|
||||
|
||||
list() : first_node(0), last_node(0), count(0) {}
|
||||
|
||||
list(const list &other) : first_node(0), last_node(0), count(0) {
|
||||
for (node *n = other.first_node; n; n = n->next)
|
||||
push_back(n->value);
|
||||
}
|
||||
|
||||
list(list &&other) : first_node(other.first_node),
|
||||
last_node(other.last_node), count(other.count) {
|
||||
other.first_node = 0;
|
||||
other.last_node = 0;
|
||||
other.count = 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
|
||||
if (count == 0) return;
|
||||
|
||||
for (node *n = first_node->next; n; n = n->next)
|
||||
delete n->prev;
|
||||
delete last_node;
|
||||
|
||||
first_node = 0;
|
||||
last_node = 0;
|
||||
count = 0;
|
||||
|
||||
}
|
||||
|
||||
~list() {
|
||||
clear();
|
||||
}
|
||||
|
||||
list &operator =(const list &other) {
|
||||
clear();
|
||||
for (node *n = other.first_node; n; n = n->next)
|
||||
push_back(n->value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
list &operator =(list &&other) {
|
||||
clear();
|
||||
first_node = other.first_node;
|
||||
last_node = other.last_node;
|
||||
count = other.count;
|
||||
other.first_node = 0;
|
||||
other.last_node = 0;
|
||||
other.count = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T &back() { return last_node->value; }
|
||||
const T &back() const { return last_node->value; }
|
||||
|
||||
size_t size() const noexcept { return count; }
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <euler/syscall.hpp>
|
||||
|
||||
namespace std {
|
||||
|
||||
class mutex {
|
||||
|
||||
euler::syscall::stream_handle in_handle;
|
||||
euler::syscall::stream_handle out_handle;
|
||||
|
||||
public:
|
||||
inline mutex() noexcept {
|
||||
euler::syscall::create_private_socket(in_handle, out_handle);
|
||||
uint8_t byte = 0;
|
||||
euler::syscall::write_to_stream(in_handle, 1, &byte);
|
||||
}
|
||||
|
||||
mutex(const mutex &) = delete;
|
||||
|
||||
inline ~mutex() {
|
||||
euler::syscall::close_stream(in_handle);
|
||||
euler::syscall::close_stream(out_handle);
|
||||
}
|
||||
|
||||
mutex &operator =(const mutex &) = delete;
|
||||
|
||||
inline void lock() {
|
||||
uint8_t byte;
|
||||
euler::syscall::read_from_stream(out_handle, 1, &byte);
|
||||
}
|
||||
|
||||
inline void unlock() {
|
||||
uint8_t byte = 0;
|
||||
euler::syscall::write_to_stream(in_handle, 1, &byte);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <std/fwd/string.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
|
@ -12,15 +10,15 @@ namespace std {
|
|||
std::vector<char> characters;
|
||||
|
||||
public:
|
||||
static const size_t npos = (size_t)-1;
|
||||
|
||||
constexpr string() : characters({'\0'}) {}
|
||||
|
||||
constexpr string(const string &other)
|
||||
: characters(other.characters) {}
|
||||
|
||||
constexpr string(string &&other) noexcept
|
||||
: characters(std::move(other.characters)) {}
|
||||
: characters(std::move(other.characters)) {
|
||||
other.characters.push_back('\0');
|
||||
}
|
||||
|
||||
constexpr string(const char *s) {
|
||||
size_t count = 0;
|
||||
|
@ -40,6 +38,7 @@ namespace std {
|
|||
|
||||
constexpr string &operator =(string &&str) noexcept {
|
||||
characters = std::move(str.characters);
|
||||
str.characters.push_back('\0');
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -76,14 +75,6 @@ namespace std {
|
|||
return characters[pos];
|
||||
}
|
||||
|
||||
constexpr string &erase(size_t index = 0, size_t count = npos) {
|
||||
count = std::min(count, size() - index);
|
||||
for (size_t i = index; i + count < size(); ++i)
|
||||
characters[i] = characters[i + count];
|
||||
resize(size() - count);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace std {
|
||||
|
||||
template <class Mutex>
|
||||
class unique_lock {
|
||||
|
||||
Mutex *the_mutex;
|
||||
bool has_locked;
|
||||
|
||||
public:
|
||||
inline unique_lock() noexcept : the_mutex(0) {}
|
||||
|
||||
unique_lock(const unique_lock &other) = delete;
|
||||
|
||||
inline unique_lock(unique_lock &&other) noexcept
|
||||
: the_mutex(other.the_mutex), has_locked(other.has_locked) {
|
||||
other.the_mutex = 0;
|
||||
}
|
||||
|
||||
inline explicit unique_lock(Mutex &m)
|
||||
: the_mutex(&m), has_locked(true) {
|
||||
the_mutex->lock();
|
||||
}
|
||||
|
||||
inline ~unique_lock() {
|
||||
if (the_mutex && has_locked)
|
||||
the_mutex->unlock();
|
||||
}
|
||||
|
||||
unique_lock &operator =(const unique_lock &other) = delete;
|
||||
|
||||
inline unique_lock &operator =(unique_lock &&other) {
|
||||
if (the_mutex && has_locked)
|
||||
the_mutex->unlock();
|
||||
the_mutex = other.the_mutex;
|
||||
has_locked = other.has_locked;
|
||||
other.the_mutex = 0;
|
||||
}
|
||||
|
||||
inline void lock() {
|
||||
the_mutex->lock();
|
||||
has_locked = true;
|
||||
}
|
||||
|
||||
inline void unlock() {
|
||||
the_mutex->unlock();
|
||||
has_locked = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,12 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <std/fwd/vector.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace std {
|
||||
|
||||
template <class T, class Allocator>
|
||||
template <class T, class Allocator = std::allocator<T>>
|
||||
class vector {
|
||||
|
||||
public:
|
||||
|
@ -131,12 +129,6 @@ namespace std {
|
|||
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (size_type i = 0; i < _size; ++i)
|
||||
std::destroy_at(_data + i);
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
constexpr size_type size() const noexcept {
|
||||
return _size;
|
||||
}
|
||||
|
@ -194,18 +186,6 @@ namespace std {
|
|||
++_size;
|
||||
}
|
||||
|
||||
using iterator = T *;
|
||||
using const_iterator = const T *;
|
||||
|
||||
iterator begin() noexcept { return _data; }
|
||||
iterator end() noexcept { return _data + _size; }
|
||||
|
||||
const_iterator begin() const noexcept { return _data; }
|
||||
const_iterator end() const noexcept { return _data + _size; }
|
||||
|
||||
const_iterator cbegin() const noexcept { return _data; }
|
||||
const_iterator cend() const noexcept { return _data + _size; }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
26
euler/makefile
Normal file
26
euler/makefile
Normal file
|
@ -0,0 +1,26 @@
|
|||
LIBC_SOURCES = \
|
||||
entry.cpp std/string.cpp std/cstring.cpp syscall.cpp std/cstdlib.cpp \
|
||||
heap.cpp syscall.asm std/cctype.cpp std/cstdio.cpp stream.cpp
|
||||
|
||||
clean:
|
||||
rm -rf build
|
||||
|
||||
build/%.asm.o: source/%.asm
|
||||
@mkdir -p $(@D)
|
||||
$(HILBERT_NASM) $^ -o $@
|
||||
|
||||
build/%.cpp.o: source/%.cpp
|
||||
@mkdir -p $(@D)
|
||||
$(HILBERT_CC) -ffreestanding -c $^ -o $@
|
||||
|
||||
build/crt0.o: build/empty.asm.o
|
||||
cp $^ $@
|
||||
|
||||
build/libc.a: ${LIBC_SOURCES:%=build/%.o}
|
||||
$(HILBERT_AR) rcs $@ $^
|
||||
|
||||
build/libg.a: build/empty.asm.o
|
||||
$(HILBERT_AR) rcs $@ $^
|
||||
|
||||
build/libm.a: build/empty.asm.o
|
||||
$(HILBERT_AR) rcs $@ $^
|
0
euler/source/empty.asm
Normal file
0
euler/source/empty.asm
Normal file
|
@ -2,15 +2,26 @@
|
|||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
int main();
|
||||
int main(int argc, char **argv);
|
||||
|
||||
extern "C" [[noreturn]] void _start() {
|
||||
|
||||
//TODO: call static initializers
|
||||
auto argc_raw = euler::syscall::try_get_environment_variable("ARGC");
|
||||
int argc = argc_raw.has_value() ? std::stoi(argc_raw.value()) : 0;
|
||||
|
||||
int exit_code = main();
|
||||
std::vector<std::string> argv;
|
||||
|
||||
//TODO: call at_exit stuff
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
std::string arg_name = std::string("ARGV") + std::to_string(i);
|
||||
auto arg_raw = euler::syscall::try_get_environment_variable(arg_name);
|
||||
argv.push_back(arg_raw.has_value() ? arg_raw.value() : "");
|
||||
}
|
||||
|
||||
std::vector<char *> c_argv(argc);
|
||||
for (int i = 0; i < argc; ++i)
|
||||
c_argv[i] = argv[i].data();
|
||||
|
||||
int exit_code = main(argc, c_argv.data());
|
||||
|
||||
euler::syscall::end_this_process(exit_code);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
extern "C" FILE *fopen(const char *filename, const char *mode) {
|
||||
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
#include <euler/syscall.hpp>
|
||||
#include <ctime>
|
||||
|
||||
time_t time(time_t *arg) {
|
||||
time_t t = euler::syscall::get_time();
|
||||
if (arg) *arg = t;
|
||||
return t;
|
||||
}
|
||||
|
||||
static tm static_tm;
|
||||
|
||||
static int days_per_month[] = {
|
||||
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
tm *gmtime(const time_t *time) {
|
||||
|
||||
time_t t = *time / 1024;
|
||||
|
||||
static_tm.tm_isdst = 0;
|
||||
|
||||
static_tm.tm_sec = t % 60; t /= 60;
|
||||
static_tm.tm_min = t % 60; t /= 60;
|
||||
static_tm.tm_hour = t % 24; t /= 24;
|
||||
static_tm.tm_wday = (t + 5) % 7 + 1;
|
||||
static_tm.tm_year = (t / 1461) * 4 + 100;
|
||||
|
||||
int days_into_quadyear = t % 1461;
|
||||
|
||||
static_tm.tm_yday = 0;
|
||||
static_tm.tm_mon = 0;
|
||||
static_tm.tm_mday = 1;
|
||||
|
||||
for (int i = 0; i < 48; ++i) {
|
||||
if (days_into_quadyear >= days_per_month[i]) {
|
||||
days_into_quadyear -= days_per_month[i];
|
||||
if (static_tm.tm_mon == 11) {
|
||||
static_tm.tm_mon = 0;
|
||||
static_tm.tm_yday = 0;
|
||||
}
|
||||
else {
|
||||
++static_tm.tm_mon;
|
||||
static_tm.tm_yday += days_per_month[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
static_tm.tm_yday += days_into_quadyear;
|
||||
static_tm.tm_mday += days_into_quadyear;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return &static_tm;
|
||||
|
||||
}
|
|
@ -44,7 +44,6 @@ namespace std {
|
|||
value = value * base + c - 'A' + 10;
|
||||
else
|
||||
break;
|
||||
++i;
|
||||
}
|
||||
|
||||
if (pos != 0)
|
||||
|
@ -76,11 +75,10 @@ namespace std {
|
|||
}
|
||||
|
||||
std::string operator +(std::string &&lhs, std::string &&rhs) {
|
||||
size_t og_lhs_s = lhs.size();
|
||||
std::string s = std::move(lhs);
|
||||
s.resize(og_lhs_s + rhs.size());
|
||||
s.resize(lhs.size() + rhs.size());
|
||||
for (size_t i = 0; i < rhs.size(); ++i)
|
||||
s[og_lhs_s + i] = rhs[i];
|
||||
s[lhs.size() + i] = rhs[i];
|
||||
rhs.clear();
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <euler/stream.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace euler {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#include <euler/syscall.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
extern "C" void __euler_do_syscall(
|
||||
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx);
|
||||
|
@ -396,38 +394,4 @@ namespace euler::syscall {
|
|||
|
||||
}
|
||||
|
||||
void set_thread_name(const std::string &name) {
|
||||
|
||||
uint64_t rax = 24;
|
||||
uint64_t rdi = (uint64_t)name.data();
|
||||
uint64_t rsi = name.size();
|
||||
uint64_t rdx;
|
||||
|
||||
__euler_do_syscall(rax, rdi, rsi, rdx);
|
||||
|
||||
}
|
||||
|
||||
void sleep(uint64_t mibiseconds) {
|
||||
|
||||
uint64_t rax = 25;
|
||||
uint64_t rdi = mibiseconds;
|
||||
uint64_t rsi;
|
||||
uint64_t rdx;
|
||||
|
||||
__euler_do_syscall(rax, rdi, rsi, rdx);
|
||||
|
||||
}
|
||||
|
||||
uint64_t get_time() {
|
||||
|
||||
uint64_t rax = 26;
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rdx;
|
||||
|
||||
__euler_do_syscall(rax, rdi, rsi, rdx);
|
||||
return rax;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -104,7 +104,6 @@ namespace hilbert::kernel::application {
|
|||
utility::id_allocator<generic_stream_ptr> open_streams;
|
||||
utility::id_allocator<socket_listener *> running_socket_listeners;
|
||||
|
||||
public:
|
||||
struct string_pair {
|
||||
utility::string a;
|
||||
utility::string b;
|
||||
|
@ -112,12 +111,7 @@ namespace hilbert::kernel::application {
|
|||
|
||||
utility::list<string_pair> environment_variables;
|
||||
|
||||
private:
|
||||
string_pair *find_environment_variable(const utility::string &name);
|
||||
|
||||
public:
|
||||
utility::string name;
|
||||
|
||||
app_memory *memory;
|
||||
|
||||
//set in get_framebuffer syscall
|
||||
|
@ -127,18 +121,13 @@ namespace hilbert::kernel::application {
|
|||
uint64_t id;
|
||||
|
||||
//this class takes ownership of memory
|
||||
process(app_memory *memory, const utility::string &name);
|
||||
process(app_memory *memory);
|
||||
~process();
|
||||
|
||||
void set_environment_variable(
|
||||
//arguments are utility::move'd
|
||||
void add_environment_variable(
|
||||
utility::string &&name, utility::string &&value);
|
||||
|
||||
void set_environment_variable(
|
||||
const utility::string &name, const utility::string &value);
|
||||
|
||||
//null if unset
|
||||
utility::string *get_environment_variable(const utility::string &name);
|
||||
|
||||
void add_thread(thread *t);
|
||||
void notify_thread_ended(thread *t, int exit_code);
|
||||
void on_end_process(int exit_code);
|
||||
|
@ -191,8 +180,6 @@ namespace hilbert::kernel::application {
|
|||
utility::maybe<unsigned> new_socket_stream_id;
|
||||
|
||||
public:
|
||||
utility::string name;
|
||||
|
||||
process *owner;
|
||||
|
||||
//the cpu state is saved here when the thread is not running.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <hilbert/kernel/utility.hpp>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace hilbert::kernel {
|
||||
|
@ -16,11 +15,6 @@ namespace hilbert::kernel {
|
|||
}
|
||||
}
|
||||
|
||||
static inline void serial_putstr(const utility::string &str) {
|
||||
for (unsigned i = 0; i < str.count; ++i)
|
||||
serial_putchar(str.buffer[i]);
|
||||
}
|
||||
|
||||
template <int digits, int dot_every = 4>
|
||||
static inline void serial_puthex(uint64_t n) {
|
||||
for (int d = digits - 1; d >= 0; --d) {
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <hilbert/kernel/application.hpp>
|
||||
|
||||
namespace hilbert::kernel::timer {
|
||||
|
||||
void init_timer();
|
||||
|
||||
//"mibiseconds" (1 second / 1024) since january 1st 2000
|
||||
extern uint64_t current_time;
|
||||
|
||||
//when current_time >= sleeping_until, puts thread into paused threads
|
||||
void register_sleeping_thread(
|
||||
uint64_t sleeping_until, application::thread *thread);
|
||||
|
||||
void on_timer_interrupt();
|
||||
|
||||
}
|
|
@ -107,10 +107,6 @@ namespace hilbert::kernel::utility {
|
|||
n->value = value;
|
||||
n->next = 0;
|
||||
n->prev = last;
|
||||
if (last)
|
||||
last->next = n;
|
||||
else
|
||||
first = n;
|
||||
last = n;
|
||||
}
|
||||
|
||||
|
@ -119,38 +115,12 @@ namespace hilbert::kernel::utility {
|
|||
n->value = value;
|
||||
n->next = 0;
|
||||
n->prev = last;
|
||||
if (last)
|
||||
last->next = n;
|
||||
else
|
||||
first = n;
|
||||
last = n;
|
||||
}
|
||||
|
||||
//if other == 0, then insert at the end
|
||||
void insert_before(value_t &&value, node *other) {
|
||||
node *n = new node {};
|
||||
n->value = value;
|
||||
n->next = other;
|
||||
if (other) {
|
||||
n->prev = other->prev;
|
||||
other->prev = n;
|
||||
}
|
||||
else {
|
||||
n->prev = last;
|
||||
last = n;
|
||||
}
|
||||
if (n->prev)
|
||||
n->prev->next = n;
|
||||
else
|
||||
first = n;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (first) {
|
||||
for (node *n = first->next; n; n = n->next)
|
||||
delete n->prev;
|
||||
delete last;
|
||||
}
|
||||
for (node *n = first; n; n = n->next)
|
||||
delete n;
|
||||
first = 0;
|
||||
last = 0;
|
||||
}
|
||||
|
@ -212,12 +182,7 @@ namespace hilbert::kernel::utility {
|
|||
buffer[i] = other.buffer[i];
|
||||
}
|
||||
|
||||
vector(vector &&other)
|
||||
: buffer(other.buffer),
|
||||
buffer_len(other.buffer_len),
|
||||
count(other.count) {
|
||||
other.buffer = 0;
|
||||
}
|
||||
vector(vector &&other) = delete;
|
||||
|
||||
~vector() {
|
||||
if (buffer)
|
||||
|
|
20
kernel/makefile
Normal file
20
kernel/makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
SOURCES = \
|
||||
storage/bd/memory.cpp storage/fs/tarfs.cpp application.asm application.cpp \
|
||||
framebuffer.cpp interrupts.asm interrupts.cpp allocator.cpp storage.cpp \
|
||||
syscall.cpp utility.cpp paging.asm paging.cpp entry.cpp input.cpp panic.cpp \
|
||||
vfile.cpp serial.asm app-memory.cpp load-app.cpp
|
||||
|
||||
build/%.asm.o: source/%.asm
|
||||
@mkdir -p $(@D)
|
||||
$(HILBERT_NASM) $^ -o $@
|
||||
|
||||
build/%.cpp.o: source/%.cpp
|
||||
@mkdir -p $(@D)
|
||||
$(HILBERT_CC) -c -ffreestanding -fno-exceptions -fno-rtti \
|
||||
-mcmodel=kernel -I ${LIMINE_DIR} -I ${MINTSUKI_HEADERS_DIR} $^ -o $@
|
||||
|
||||
build/kernel.elf: $(SOURCES:%=build/%.o)
|
||||
$(HILBERT_LD) -T link.ld $^ -o $@
|
||||
|
||||
clean:
|
||||
rm -rf build
|
|
@ -83,57 +83,15 @@ namespace hilbert::kernel::application {
|
|||
resume_thread(t->saved_state);
|
||||
}
|
||||
|
||||
process::process(app_memory *memory, const utility::string &name)
|
||||
: name(name), memory(memory) {}
|
||||
process::process(app_memory *memory) : memory(memory) {}
|
||||
|
||||
process::~process() {
|
||||
delete memory; //:p
|
||||
}
|
||||
|
||||
process::string_pair *process::find_environment_variable(
|
||||
const utility::string &name) {
|
||||
|
||||
for (auto *n = environment_variables.first; n; n = n->next)
|
||||
if (n->value.a == name)
|
||||
return &n->value;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void process::set_environment_variable(
|
||||
void process::add_environment_variable(
|
||||
utility::string &&name, utility::string &&value) {
|
||||
|
||||
auto *sp = find_environment_variable(name);
|
||||
if (sp)
|
||||
sp->b = utility::move(value);
|
||||
else
|
||||
environment_variables.insert_end({
|
||||
.a = utility::move(name),
|
||||
.b = utility::move(value)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void process::set_environment_variable(
|
||||
const utility::string &name, const utility::string &value) {
|
||||
|
||||
auto *sp = find_environment_variable(name);
|
||||
if (sp)
|
||||
sp->b = value;
|
||||
else
|
||||
environment_variables.insert_end({
|
||||
.a = name, .b = value
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
utility::string *process::get_environment_variable(
|
||||
const utility::string &name) {
|
||||
for (auto *i = environment_variables.first; i; i = i->next)
|
||||
if (i->value.a == name)
|
||||
return &i->value.b;
|
||||
return 0;
|
||||
environment_variables.insert_end({.a = name, .b = value});
|
||||
}
|
||||
|
||||
void process::add_thread(thread *t) {
|
||||
|
@ -239,8 +197,8 @@ namespace hilbert::kernel::application {
|
|||
|
||||
thread::thread(process *owner, uint64_t entry)
|
||||
: stack_top(owner->memory->map_new_stack()), waiting_for_socket_stream(0),
|
||||
waiting_to_accept_from(0), waiting_to_connect_to(0), waiting_for_input(false),
|
||||
name(utility::string("main", 4)), owner(owner) {
|
||||
waiting_to_accept_from(0), waiting_to_connect_to(0),
|
||||
waiting_for_input(false), owner(owner) {
|
||||
|
||||
saved_state.rax = 0;
|
||||
saved_state.rbx = 0;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <hilbert/kernel/serial.hpp>
|
||||
#include <hilbert/kernel/input.hpp>
|
||||
#include <hilbert/kernel/panic.hpp>
|
||||
#include <hilbert/kernel/timer.hpp>
|
||||
#include <hilbert/kernel/vfile.hpp>
|
||||
#include <limine.h>
|
||||
|
||||
|
@ -180,7 +179,6 @@ extern "C" [[noreturn]] void entry() {
|
|||
if (!have_initfs)
|
||||
panic(0x5f8860);
|
||||
|
||||
timer::init_timer();
|
||||
input::init_input();
|
||||
application::init_applications();
|
||||
|
||||
|
@ -216,8 +214,11 @@ extern "C" [[noreturn]] void entry() {
|
|||
if (load_init_result != load_app_result::success)
|
||||
panic(0xc39db3);
|
||||
|
||||
application::process *init_process =
|
||||
new application::process(init_memory, utility::string("init", 4));
|
||||
application::process *init_process = new application::process(init_memory);
|
||||
init_process->add_environment_variable(
|
||||
utility::string("ARGC", 4), utility::string("1", 1));
|
||||
init_process->add_environment_variable(
|
||||
utility::string("ARGV0", 5), utility::string("/bin/init", 9));
|
||||
application::add_process(init_process);
|
||||
|
||||
application::thread *init_thread =
|
||||
|
|
|
@ -267,22 +267,6 @@ isr_end:
|
|||
|
||||
ret
|
||||
|
||||
extern on_rtc_interrupt
|
||||
|
||||
rtc_isr:
|
||||
|
||||
call isr_start
|
||||
|
||||
call on_rtc_interrupt
|
||||
|
||||
mov al, 0x20
|
||||
out 0x20, al
|
||||
out 0xa0, al
|
||||
|
||||
call isr_end
|
||||
|
||||
iretq
|
||||
|
||||
extern on_keyboard_interrupt
|
||||
|
||||
keyboard_isr:
|
||||
|
@ -359,7 +343,7 @@ load_gdt_and_idt:
|
|||
out 0x21, al
|
||||
mov al, 0x01
|
||||
out 0x21, al
|
||||
mov al, 0xf9 ;mask all but irqs 1 and 2
|
||||
mov al, 0xf9 ;mask all but irq 1 and 2
|
||||
out 0x21, al
|
||||
|
||||
mov al, 0x11
|
||||
|
@ -370,15 +354,9 @@ load_gdt_and_idt:
|
|||
out 0xa1, al
|
||||
mov al, 0x01
|
||||
out 0xa1, al
|
||||
mov al, 0xee ;mask all but irqs 8 and 12
|
||||
mov al, 0xef ;mask all but irq 12
|
||||
out 0xa1, al
|
||||
|
||||
;register rtc interrupt
|
||||
|
||||
mov rdi, 0x28
|
||||
mov rsi, rtc_isr
|
||||
call set_isr
|
||||
|
||||
;register keyboard and mouse interrupts
|
||||
|
||||
mov rdi, 0x21
|
||||
|
|
|
@ -79,11 +79,6 @@ extern "C" [[noreturn]] void print_exception() {
|
|||
print_reg("r14", exception_info.r14);
|
||||
print_reg("r15", exception_info.r15);
|
||||
|
||||
if (application::running_thread != 0) {
|
||||
serial_putstr("running app = ");
|
||||
serial_putstr(application::running_thread->owner->name);
|
||||
}
|
||||
|
||||
panic(0xba40bb);
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <hilbert/kernel/paging.hpp>
|
||||
#include <hilbert/kernel/input.hpp>
|
||||
#include <hilbert/kernel/panic.hpp>
|
||||
#include <hilbert/kernel/timer.hpp>
|
||||
#include <hilbert/kernel/vfile.hpp>
|
||||
|
||||
namespace hilbert::kernel::syscall {
|
||||
|
@ -184,7 +183,7 @@ namespace hilbert::kernel::syscall {
|
|||
.waiting_to_read = utility::queue<application::thread *>(),
|
||||
.is_other_side_open = true, .other_process = p2, .other_end = 0 };
|
||||
se2_out = new application::socket_stream_end {
|
||||
.the_socket = s, .read_queue = s->queue_2, .write_queue = s->queue_1,
|
||||
.the_socket = s, .read_queue = s->queue_2, .write_queue = s->queue_2,
|
||||
.waiting_to_read = utility::queue<application::thread *>(),
|
||||
.is_other_side_open = true, .other_process = p1, .other_end = se1_out };
|
||||
se1_out->other_end = se2_out;
|
||||
|
@ -495,12 +494,8 @@ namespace hilbert::kernel::syscall {
|
|||
rax = (uint64_t)application::stream_result::other_end_closed;
|
||||
return;
|
||||
}
|
||||
auto &wtr_queue = ss->other_end->waiting_to_read;
|
||||
for (uint64_t i = 0; i < count; ++i) {
|
||||
for (uint64_t i = 0; i < count; ++i)
|
||||
ss->write_queue.insert(buffer[i]);
|
||||
if (wtr_queue.count > 0)
|
||||
application::paused_threads->insert(wtr_queue.take());
|
||||
}
|
||||
rax = (uint64_t)application::stream_result::success;
|
||||
}
|
||||
|
||||
|
@ -622,14 +617,10 @@ namespace hilbert::kernel::syscall {
|
|||
break;
|
||||
}
|
||||
|
||||
application::process *p =
|
||||
new application::process(memory, file.dir_entry.name);
|
||||
|
||||
for (auto *n = owner->environment_variables.first; n; n = n->next)
|
||||
p->set_environment_variable(n->value.a, n->value.b);
|
||||
application::process *p = new application::process(memory);
|
||||
|
||||
for (uint64_t i = 0; i < psi->env_var_count; ++i)
|
||||
p->set_environment_variable(
|
||||
p->add_environment_variable(
|
||||
utility::string(psi->env_vars[i].name, psi->env_vars[i].name_len),
|
||||
utility::string(psi->env_vars[i].value, psi->env_vars[i].value_len));
|
||||
|
||||
|
@ -744,89 +735,6 @@ namespace hilbert::kernel::syscall {
|
|||
|
||||
}
|
||||
|
||||
void get_environment_variable_length_syscall(
|
||||
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
|
||||
|
||||
const char *name = (const char *)rdi;
|
||||
uint64_t name_len = rsi;
|
||||
set_zero(rax, rdi, rsi, rdx);
|
||||
|
||||
auto *app = application::running_thread->owner;
|
||||
|
||||
if (!app->memory->valid_to_read(name, name + name_len, false))
|
||||
return;
|
||||
|
||||
utility::string name_string(name, name_len);
|
||||
utility::string *value = app->get_environment_variable(name_string);
|
||||
rax = value == 0 ? (uint64_t)-1 : value->count;
|
||||
|
||||
}
|
||||
|
||||
void get_environment_variable_value_syscall(
|
||||
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
|
||||
|
||||
const char *name = (const char *)rdi;
|
||||
uint64_t name_len = rsi;
|
||||
char *buffer = (char *)rdx;
|
||||
set_zero(rax, rdi, rsi, rdx);
|
||||
|
||||
auto *app = application::running_thread->owner;
|
||||
|
||||
if (!app->memory->valid_to_read(name, name + name_len, false))
|
||||
return;
|
||||
|
||||
utility::string name_string(name, name_len);
|
||||
utility::string *value = app->get_environment_variable(name_string);
|
||||
if (value == 0)
|
||||
return;
|
||||
|
||||
if (!app->memory->valid_to_read(buffer, buffer + value->count, true))
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < value->count; ++i)
|
||||
buffer[i] = value->buffer[i];
|
||||
|
||||
}
|
||||
|
||||
void set_thread_name_syscall(
|
||||
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
|
||||
|
||||
const char *name = (const char *)rdi;
|
||||
uint64_t name_len = rsi;
|
||||
set_zero(rax, rdi, rsi, rdx);
|
||||
|
||||
auto *t = application::running_thread;
|
||||
|
||||
if (!t->owner->memory->valid_to_read(name, name + name_len, false))
|
||||
return;
|
||||
|
||||
t->name = utility::string(name, name_len);
|
||||
|
||||
}
|
||||
|
||||
void sleep_syscall(
|
||||
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
|
||||
|
||||
uint64_t mis = rdi;
|
||||
set_zero(rax, rdi, rsi, rdx);
|
||||
|
||||
auto *t = application::running_thread;
|
||||
|
||||
timer::register_sleeping_thread(
|
||||
timer::current_time + mis, t);
|
||||
|
||||
application::yield(t->saved_state);
|
||||
|
||||
}
|
||||
|
||||
void get_time_syscall(
|
||||
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
|
||||
|
||||
set_zero(rax, rdi, rsi, rdx);
|
||||
rax = timer::current_time;
|
||||
|
||||
}
|
||||
|
||||
void (*handlers[])(
|
||||
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) = {
|
||||
|
||||
|
@ -851,16 +759,11 @@ namespace hilbert::kernel::syscall {
|
|||
&set_stream_length_syscall,
|
||||
&get_other_end_process_handle_syscall,
|
||||
&start_thread_syscall,
|
||||
&clear_socket_read_queue_syscall,
|
||||
&get_environment_variable_length_syscall,
|
||||
&get_environment_variable_value_syscall,
|
||||
&set_thread_name_syscall,
|
||||
&sleep_syscall,
|
||||
&get_time_syscall
|
||||
&clear_socket_read_queue_syscall
|
||||
|
||||
};
|
||||
|
||||
static constexpr int max_syscall_number = 26;
|
||||
static constexpr int max_syscall_number = 20;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,162 +0,0 @@
|
|||
bits 64
|
||||
|
||||
section .rodata
|
||||
|
||||
section .text
|
||||
|
||||
read_cmos_byte:
|
||||
;dil in = register number
|
||||
;al out = value
|
||||
;rdx and rcx are not touched
|
||||
|
||||
mov al, dil
|
||||
out 0x70, al
|
||||
in al, 0x71
|
||||
ret
|
||||
|
||||
global enable_rtc_interrupts
|
||||
enable_rtc_interrupts:
|
||||
|
||||
;secondary status register
|
||||
mov dil, 11
|
||||
call read_cmos_byte
|
||||
|
||||
;enable interrupts
|
||||
or al, 0x40
|
||||
mov cl, al
|
||||
|
||||
;do cmos write
|
||||
mov al, 11
|
||||
out 0x70, al
|
||||
mov al, cl
|
||||
out 0x71, al
|
||||
|
||||
ret
|
||||
|
||||
global acknowledge_rtc_interrupt
|
||||
acknowledge_rtc_interrupt:
|
||||
mov dil, 12
|
||||
jmp read_cmos_byte
|
||||
|
||||
convert_bcd:
|
||||
;al in = byte (possibly bcd)
|
||||
;al out = byte (not bcd)
|
||||
;sil 0x02 = bcd
|
||||
;does not touch rdx, rcx, sil
|
||||
test sil, 0x02
|
||||
jz .no_convert
|
||||
|
||||
mov dil, al
|
||||
and dil, 0xf0
|
||||
and al, 0x0f
|
||||
shr dil, 3
|
||||
add al, dil
|
||||
shl dil, 2
|
||||
add al, dil
|
||||
|
||||
.no_convert:
|
||||
ret
|
||||
|
||||
convert_hours:
|
||||
;al in = byte (possibly bcd and 12 hour)
|
||||
;al out = byte (not bcd or 12 hour)
|
||||
;sil 0x02 = bcd, sil 0x01 = 12 hour
|
||||
;does not touch rdx, rcx, sil
|
||||
test sil, 0x01
|
||||
jz convert_bcd
|
||||
|
||||
test al, 0x80
|
||||
jz .am
|
||||
|
||||
and al, 0x7f
|
||||
call convert_bcd
|
||||
cmp al, 12
|
||||
je .noon
|
||||
|
||||
add al, 12
|
||||
ret
|
||||
|
||||
.noon:
|
||||
ret
|
||||
|
||||
.am:
|
||||
call convert_bcd
|
||||
cmp al, 12
|
||||
je .midnight
|
||||
|
||||
ret
|
||||
|
||||
.midnight:
|
||||
xor al, al
|
||||
ret
|
||||
|
||||
global get_time_from_rtc
|
||||
get_time_from_rtc:
|
||||
;rax out = time (see timer.cpp for encoding)
|
||||
;we assume the year is 20xx (sorry)
|
||||
|
||||
mov dil, 11
|
||||
call read_cmos_byte
|
||||
|
||||
shr al, 1
|
||||
not al
|
||||
and al, 3
|
||||
mov sil, al
|
||||
|
||||
xor rdx, rdx
|
||||
|
||||
.outer_loop:
|
||||
mov rcx, rdx
|
||||
|
||||
.wait_for_update_loop:
|
||||
;status register - 0x80 is update in progress
|
||||
mov dil, 10
|
||||
call read_cmos_byte
|
||||
test al, 0x80
|
||||
jnz .wait_for_update_loop
|
||||
|
||||
;years
|
||||
mov dil, 9
|
||||
call read_cmos_byte
|
||||
call convert_bcd
|
||||
mov dh, al
|
||||
|
||||
;months
|
||||
mov dil, 8
|
||||
call read_cmos_byte
|
||||
call convert_bcd
|
||||
mov dl, al
|
||||
|
||||
shl edx, 16
|
||||
|
||||
;days
|
||||
mov dil, 7
|
||||
call read_cmos_byte
|
||||
call convert_bcd
|
||||
mov dh, al
|
||||
|
||||
;hours
|
||||
mov dil, 4
|
||||
call read_cmos_byte
|
||||
call convert_hours
|
||||
mov dl, al
|
||||
|
||||
shl rdx, 16
|
||||
|
||||
;minutes
|
||||
mov dil, 2
|
||||
call read_cmos_byte
|
||||
call convert_bcd
|
||||
mov dh, al
|
||||
|
||||
;seconds
|
||||
xor dil, dil
|
||||
call read_cmos_byte
|
||||
call convert_bcd
|
||||
mov dl, al
|
||||
|
||||
cmp rdx, rcx
|
||||
jne .outer_loop
|
||||
|
||||
mov rax, rdx
|
||||
ret
|
|
@ -1,117 +0,0 @@
|
|||
#include <hilbert/kernel/timer.hpp>
|
||||
|
||||
namespace hilbert::kernel::timer {
|
||||
|
||||
struct sleeping_thread {
|
||||
uint64_t sleeping_until;
|
||||
application::thread *thread;
|
||||
};
|
||||
|
||||
//sorted ascending by sleeping_until
|
||||
static utility::list<sleeping_thread> *sleeping_threads;
|
||||
|
||||
uint64_t current_time;
|
||||
|
||||
//output is
|
||||
// seconds | (minutes << 8) | (hours << 16) |
|
||||
// (days << 24) | ( months << 32) | (years << 40)
|
||||
extern "C" uint64_t get_time_from_rtc();
|
||||
|
||||
//index is (year % 4) * 12 + month - 1;
|
||||
//output is days from january 1st 2000 to [month] 1st [year]
|
||||
static uint16_t month_table[] {
|
||||
0, 31, 60, 91, 121, 152,
|
||||
182, 213, 244, 274, 305, 335,
|
||||
366, 397, 425, 456, 486, 517,
|
||||
547, 578, 609, 639, 670, 700,
|
||||
731, 762, 790, 821, 851, 882,
|
||||
912, 943, 974, 1004, 1035, 1065,
|
||||
1096, 1127, 1155, 1186, 1216, 1247,
|
||||
1277, 1308, 1339, 1369, 1400, 1430
|
||||
};
|
||||
|
||||
//index is (year % 4) * 12 + month - 1;
|
||||
//output is days in that month
|
||||
static uint8_t month_table_2[] = {
|
||||
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
void clamp(uint8_t &value, uint8_t min, uint8_t max) {
|
||||
if (value < min)
|
||||
value = min;
|
||||
else if (value > max)
|
||||
value = max;
|
||||
}
|
||||
|
||||
extern "C" void enable_rtc_interrupts();
|
||||
|
||||
void init_timer() {
|
||||
|
||||
sleeping_threads = new utility::list<sleeping_thread>();
|
||||
|
||||
uint64_t rtc_time = get_time_from_rtc();
|
||||
|
||||
uint8_t years = rtc_time >> 40;
|
||||
uint8_t months = (rtc_time >> 32) & 0xff;
|
||||
uint8_t days = (rtc_time >> 24) & 0xff;
|
||||
uint8_t hours = (rtc_time >> 16) & 0xff;
|
||||
uint8_t minutes = (rtc_time >> 8) & 0xff;
|
||||
uint8_t seconds = rtc_time & 0xff;
|
||||
|
||||
uint8_t month_table_index =
|
||||
(years % 4) * 12 + months - 1;
|
||||
|
||||
clamp( years, 0, 99);
|
||||
clamp( months, 1, 12);
|
||||
clamp( days, 1, month_table_2[month_table_index]);
|
||||
clamp( hours, 0, 23);
|
||||
clamp(minutes, 0, 59);
|
||||
clamp(seconds, 0, 59);
|
||||
|
||||
current_time = 1461 * (years / 4);
|
||||
current_time += month_table[month_table_index];
|
||||
current_time += days - 1;
|
||||
current_time *= 86400;
|
||||
current_time += hours * 3600;
|
||||
current_time += minutes * 60;
|
||||
current_time += seconds;
|
||||
current_time *= 1024;
|
||||
|
||||
enable_rtc_interrupts();
|
||||
|
||||
}
|
||||
|
||||
void register_sleeping_thread(
|
||||
uint64_t sleeping_until, application::thread *thread) {
|
||||
|
||||
auto *after = sleeping_threads->first;
|
||||
while (after && after->value.sleeping_until < sleeping_until)
|
||||
after = after->next;
|
||||
|
||||
sleeping_threads->insert_before(
|
||||
{ .sleeping_until = sleeping_until, .thread = thread }, after);
|
||||
|
||||
}
|
||||
|
||||
extern "C" void acknowledge_rtc_interrupt();
|
||||
|
||||
extern "C" void on_rtc_interrupt() {
|
||||
|
||||
++current_time;
|
||||
|
||||
while (sleeping_threads->first &&
|
||||
sleeping_threads->first->value.sleeping_until <=
|
||||
current_time) {
|
||||
application::paused_threads->insert(
|
||||
sleeping_threads->first->value.thread);
|
||||
sleeping_threads->remove(sleeping_threads->first);
|
||||
}
|
||||
|
||||
acknowledge_rtc_interrupt();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -55,8 +55,6 @@ namespace daguerre {
|
|||
~image();
|
||||
|
||||
void fill(const color_t &color);
|
||||
void fill(
|
||||
const color_t &color, int start_x, int start_y, int width, int height);
|
||||
|
||||
//does not check bounds
|
||||
color_t &at(int x, int y);
|
||||
|
@ -110,13 +108,6 @@ namespace daguerre {
|
|||
param_converter_t<color_t, font_color_t, param_t> *conversion =
|
||||
&default_conversion);
|
||||
|
||||
//does not check bounds or wrap text
|
||||
template <class font_color_t>
|
||||
void render_text(
|
||||
const fixed_font<font_color_t> &font, int x, int y, const char *text,
|
||||
converter_t<color_t, font_color_t> *conversion =
|
||||
&default_conversion);
|
||||
|
||||
};
|
||||
|
||||
template <class color_t>
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace daguerre {
|
|||
template <class color_t>
|
||||
fixed_font<color_t>::fixed_font(fixed_font<color_t> &&other)
|
||||
: glyph_width(other.glyph_width), glyph_height(other.glyph_height) {
|
||||
for (int i = 0; i < 128; ++i)
|
||||
for (int i = 0; 0 < 128; ++i)
|
||||
glyphs[i] = std::move(other.glyphs[i]);
|
||||
other.glyph_width = 0;
|
||||
other.glyph_height = 0;
|
||||
|
@ -31,11 +31,10 @@ namespace daguerre {
|
|||
fixed_font<color_t> &&other) {
|
||||
glyph_width = other.glyph_width;
|
||||
glyph_height = other.glyph_height;
|
||||
for (int i = 0; i < 128; ++i)
|
||||
for (int i = 0; 0 < 128; ++i)
|
||||
glyphs[i] = std::move(other.glyphs[i]);
|
||||
other.glyph_width = 0;
|
||||
other.glyph_height = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class color_t>
|
||||
|
|
|
@ -103,14 +103,6 @@ namespace daguerre {
|
|||
buffer[y * buffer_pitch + x] = color;
|
||||
}
|
||||
|
||||
template <class color_t>
|
||||
void image<color_t>::fill(
|
||||
const color_t &color, int start_x, int start_y, int width, int height) {
|
||||
for (int y = start_y; y < start_y + height; ++y)
|
||||
for (int x = start_x; x < start_x + width; ++x)
|
||||
buffer[y * buffer_pitch + x] = color;
|
||||
}
|
||||
|
||||
template <class color_t>
|
||||
color_t &image<color_t>::at(int x, int y) {
|
||||
return buffer[y * buffer_pitch + x];
|
||||
|
@ -170,7 +162,7 @@ namespace daguerre {
|
|||
void image<color_t>::convert_from(
|
||||
const image<other_color_t> &other, int to_x, int to_y,
|
||||
converter_t<color_t, other_color_t> *conversion) {
|
||||
convert_from(other, to_x, to_y, 0, 0, other.width, other.height, conversion);
|
||||
convert_from(other, to_x, to_y, 0, 0, other.width, other.y, conversion);
|
||||
}
|
||||
|
||||
template <class color_t>
|
||||
|
@ -193,7 +185,7 @@ namespace daguerre {
|
|||
const param_t ¶m, const image<other_color_t> &other, int to_x,
|
||||
int to_y, param_converter_t<color_t, other_color_t, param_t> *conversion) {
|
||||
convert_from(
|
||||
param, other, to_x, to_y, 0, 0, other.width, other.height, conversion);
|
||||
param, other, to_x, to_y, 0, 0, other.width, other.y, conversion);
|
||||
}
|
||||
|
||||
template <class color_t>
|
||||
|
@ -213,22 +205,6 @@ namespace daguerre {
|
|||
|
||||
}
|
||||
|
||||
template <class color_t>
|
||||
template <class font_color_t>
|
||||
void image<color_t>::render_text(
|
||||
const fixed_font<font_color_t> &font, int x, int y, const char *text,
|
||||
converter_t<color_t, font_color_t> *conversion) {
|
||||
|
||||
while (*text) {
|
||||
int ch = *text;
|
||||
if (ch >= 0 && ch < 128)
|
||||
convert_from(font.glyphs[ch], x, y, conversion);
|
||||
++text;
|
||||
x += font.glyph_width;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class color_t>
|
||||
void swap(image<color_t> &a, image<color_t> &b) {
|
||||
std::swap(a.delete_buffer_on_destruct, b.delete_buffer_on_destruct);
|
||||
|
|
12
libraries/daguerre/makefile
Normal file
12
libraries/daguerre/makefile
Normal file
|
@ -0,0 +1,12 @@
|
|||
SOURCES = \
|
||||
framebuffer.cpp ppm.cpp psf.cpp
|
||||
|
||||
build/%.cpp.o: source/%.cpp
|
||||
@mkdir -p $(@D)
|
||||
$(HILBERT_CC) -c $^ -o $@
|
||||
|
||||
build/libdaguerre.a: $(SOURCES:%=build/%.o)
|
||||
$(HILBERT_AR) rcs $@ $^
|
||||
|
||||
clean:
|
||||
rm -rf build
|
|
@ -1,27 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <daguerre/image.hpp>
|
||||
#include <list>
|
||||
|
||||
namespace pake {
|
||||
|
||||
struct region {
|
||||
int start_x;
|
||||
int start_y;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct dirtiable_image {
|
||||
|
||||
daguerre::image<daguerre::hilbert_color> image;
|
||||
daguerre::image<bool> dirty;
|
||||
|
||||
std::vector<region> get_dirty_regions();
|
||||
void clear_dirty();
|
||||
|
||||
dirtiable_image(int width, int height);
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <pake/dirtiable-image.hpp>
|
||||
|
||||
namespace pake {
|
||||
|
||||
enum class halign {
|
||||
left, center, right
|
||||
};
|
||||
|
||||
enum class valign {
|
||||
top, center, bottom
|
||||
};
|
||||
|
||||
class widget {
|
||||
|
||||
public:
|
||||
virtual ~widget() {}
|
||||
|
||||
virtual void render(
|
||||
dirtiable_image &onto, int x_off, int y_off, bool force) = 0;
|
||||
|
||||
virtual void notify_size(int width, int height) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <daguerre/fixed-font.hpp>
|
||||
#include <pake/widget.hpp>
|
||||
|
||||
namespace pake::widgets {
|
||||
|
||||
//a widget that draws text with a daguerre::fixed_font<bool>
|
||||
class fixed_text : public widget {
|
||||
|
||||
//the font to use
|
||||
const daguerre::fixed_font<bool> *font;
|
||||
|
||||
//background color of the widget
|
||||
daguerre::hilbert_color bg;
|
||||
|
||||
//color of the text
|
||||
daguerre::hilbert_color fg;
|
||||
|
||||
//the text to draw
|
||||
std::string text;
|
||||
|
||||
//has the text changed since the last draw to render
|
||||
bool text_changed;
|
||||
|
||||
//the width and height of this widget, as set by notify_size
|
||||
int width, height;
|
||||
|
||||
//the alignment of the text within the region
|
||||
halign ha;
|
||||
valign va;
|
||||
|
||||
public:
|
||||
//text: the text to draw. this can be changed later by set_text.
|
||||
//font: the font to use. TODO: pass a string and look up the font with that name
|
||||
//bg: the background color of the widget. fg: the color of the text.
|
||||
//ha, va: the alignment of the text within the widget
|
||||
fixed_text(
|
||||
std::string &&text,
|
||||
const daguerre::fixed_font<bool> *font,
|
||||
daguerre::hilbert_color bg,
|
||||
daguerre::hilbert_color fg,
|
||||
halign ha, valign va);
|
||||
|
||||
//change the text to draw
|
||||
void set_text(std::string &&text);
|
||||
|
||||
virtual void render(
|
||||
dirtiable_image &onto, int x_off, int y_off, bool force) override;
|
||||
|
||||
virtual void notify_size(int width, int height) override;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <pake/dirtiable-image.hpp>
|
||||
#include <pake/widget.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace pake {
|
||||
|
||||
//a window / a connection to the compositor.
|
||||
class window {
|
||||
|
||||
//the socket that connects us to the compositor
|
||||
euler::syscall::stream_handle socket;
|
||||
|
||||
//the size of the window
|
||||
int width;
|
||||
int height;
|
||||
|
||||
//the rendered contents of the window. pixels are dirty when
|
||||
//the compositor has not been informed of them changing.
|
||||
dirtiable_image contents;
|
||||
|
||||
//the root widget, or an unset pointer if there is no root widget set
|
||||
std::unique_ptr<widget> root;
|
||||
|
||||
public:
|
||||
//create a new window / connection to the compositor
|
||||
window(int width, int height, const std::string &title);
|
||||
|
||||
//destroy the window / connection to the compositor
|
||||
~window();
|
||||
|
||||
//tell the compositor to show this window. you probably want to call
|
||||
//set_root and render_and_send_to_compositor before calling this.
|
||||
void show();
|
||||
|
||||
//tell the compositor to hide this window
|
||||
void hide();
|
||||
|
||||
//set the root widget. the widget is notified that its size is the
|
||||
//size of the window, and then it is rendered with force = true.
|
||||
void set_root(std::unique_ptr<widget> &&w);
|
||||
|
||||
//get the root widget (assumes there is one)
|
||||
widget *get_root();
|
||||
|
||||
//renders the root widget with force = false and
|
||||
//then sends the new contents to the compositor.
|
||||
void render_and_send_to_compositor();
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
#include <pake/dirtiable-image.hpp>
|
||||
|
||||
namespace pake {
|
||||
|
||||
struct dirty_region_builder {
|
||||
|
||||
std::vector<region> regions_not_on_bottom;
|
||||
std::list<region> regions_on_bottom;
|
||||
|
||||
void add_row(const std::vector<region> &row) {
|
||||
|
||||
std::list<region> new_regions_on_bottom;
|
||||
|
||||
for (auto i = row.begin(); i < row.end(); ++i) {
|
||||
bool expanded = false;
|
||||
for (auto j = regions_on_bottom.begin(); j != regions_on_bottom.end(); ++j)
|
||||
if (i->start_x == j->start_x && i->width == j->width) {
|
||||
j->height += i->height;
|
||||
new_regions_on_bottom.push_back(*j);
|
||||
regions_on_bottom.erase(j);
|
||||
expanded = true;
|
||||
break;
|
||||
}
|
||||
if (!expanded)
|
||||
new_regions_on_bottom.push_back(*i);
|
||||
}
|
||||
|
||||
for (auto i = regions_on_bottom.begin(); i != regions_on_bottom.end(); ++i)
|
||||
regions_not_on_bottom.push_back(*i);
|
||||
|
||||
regions_on_bottom = std::move(new_regions_on_bottom);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
std::vector<region> dirtiable_image::get_dirty_regions() {
|
||||
|
||||
dirty_region_builder builder;
|
||||
|
||||
std::vector<region> row;
|
||||
|
||||
for (int y = 0; y < dirty.height; ++y) {
|
||||
|
||||
int r = 0;
|
||||
for (int x = 0; x < dirty.width; ++x)
|
||||
if (!dirty.at(x, y)) {
|
||||
if (r != x)
|
||||
row.push_back({
|
||||
.start_x = r, .start_y = y,
|
||||
.width = x - r, .height = 1
|
||||
});
|
||||
r = x + 1;
|
||||
}
|
||||
if (r != dirty.width)
|
||||
row.push_back({
|
||||
.start_x = r, .start_y = y,
|
||||
.width = dirty.width - r, .height = 1
|
||||
});
|
||||
|
||||
builder.add_row(row);
|
||||
row.clear();
|
||||
|
||||
}
|
||||
|
||||
builder.add_row(row);
|
||||
return builder.regions_not_on_bottom;
|
||||
|
||||
}
|
||||
|
||||
void dirtiable_image::clear_dirty() {
|
||||
dirty.fill(false);
|
||||
}
|
||||
|
||||
dirtiable_image::dirtiable_image(int width, int height)
|
||||
: image(width, height), dirty(width, height) {
|
||||
dirty.fill(false);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
#include <pake/widgets/fixed-text.hpp>
|
||||
|
||||
static void draw_if_true(
|
||||
daguerre::hilbert_color &out, const bool &in,
|
||||
const daguerre::hilbert_color ¶m) {
|
||||
if (in) out = param;
|
||||
}
|
||||
|
||||
namespace pake::widgets {
|
||||
|
||||
fixed_text::fixed_text(
|
||||
std::string &&text,
|
||||
const daguerre::fixed_font<bool> *font,
|
||||
daguerre::hilbert_color bg,
|
||||
daguerre::hilbert_color fg,
|
||||
halign ha, valign va)
|
||||
: font(font), bg(bg), fg(fg),
|
||||
text(std::move(text)),
|
||||
ha(ha), va(va) {}
|
||||
|
||||
void fixed_text::set_text(std::string &&text) {
|
||||
this->text = std::move(text);
|
||||
text_changed = true;
|
||||
}
|
||||
|
||||
void fixed_text::render(
|
||||
dirtiable_image &onto, int x_off, int y_off, bool force) {
|
||||
|
||||
if (force || text_changed) {
|
||||
|
||||
//TODO: check overflow
|
||||
|
||||
onto.dirty.fill(true, x_off, y_off, width, height);
|
||||
|
||||
onto.image.fill( bg, x_off, y_off, width, height);
|
||||
|
||||
switch (ha) {
|
||||
case halign::left:
|
||||
break;
|
||||
case halign::center:
|
||||
x_off = width / 2 - text.size() * font->glyph_width / 2;
|
||||
break;
|
||||
case halign::right:
|
||||
x_off = width - text.size() * font->glyph_width;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (va) {
|
||||
case valign::top:
|
||||
break;
|
||||
case valign::center:
|
||||
y_off = height / 2 - font->glyph_height / 2;
|
||||
break;
|
||||
case valign::bottom:
|
||||
y_off = height - font->glyph_width;
|
||||
break;
|
||||
}
|
||||
|
||||
onto.image.render_text(
|
||||
*font, fg, x_off, y_off,
|
||||
text.data(), draw_if_true);
|
||||
|
||||
text_changed = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void fixed_text::notify_size(int width, int height) {
|
||||
this->width = width; this->height = height;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
#include <pake/window.hpp>
|
||||
#include <cassert>
|
||||
|
||||
//TODO: handle errors on socket connection, read, and write
|
||||
|
||||
namespace pake {
|
||||
|
||||
window::window(int width, int height, const std::string &title)
|
||||
: width(width), height(height), contents(width, height), root() {
|
||||
|
||||
euler::syscall::connect_to_socket("hilbert.compositor", socket);
|
||||
|
||||
assert(width >= 0 && height >= 0);
|
||||
|
||||
struct [[gnu::packed]] { uint8_t type; uint32_t width; uint32_t height; }
|
||||
dimensions_pkt = {.type = 0x02, .width = (uint32_t)width, .height = (uint32_t)height };
|
||||
euler::syscall::write_to_stream(socket, sizeof(dimensions_pkt), &dimensions_pkt);
|
||||
|
||||
assert(title.size() <= UINT32_MAX);
|
||||
|
||||
struct [[gnu::packed]] { uint8_t type; uint32_t length; }
|
||||
title_pkt = {.type = 0x03, .length = (uint32_t)title.size() };
|
||||
euler::syscall::write_to_stream(socket, sizeof(title_pkt), &title_pkt);
|
||||
euler::syscall::write_to_stream(socket, title.size(), title.data());
|
||||
|
||||
}
|
||||
|
||||
window::~window() {
|
||||
euler::syscall::close_stream(socket);
|
||||
}
|
||||
|
||||
void window::show() {
|
||||
uint8_t packet = 0;
|
||||
euler::syscall::write_to_stream(socket, 1, &packet);
|
||||
}
|
||||
|
||||
void window::hide() {
|
||||
uint8_t packet = 1;
|
||||
euler::syscall::write_to_stream(socket, 1, &packet);
|
||||
}
|
||||
|
||||
void window::set_root(std::unique_ptr<widget> &&w) {
|
||||
root = std::move(w);
|
||||
root->notify_size(width, height);
|
||||
root->render(contents, 0, 0, true);
|
||||
}
|
||||
|
||||
void window::render_and_send_to_compositor() {
|
||||
|
||||
root->render(contents, 0, 0, false);
|
||||
auto dirties = contents.get_dirty_regions();
|
||||
|
||||
for (auto it = dirties.cbegin(); it != dirties.cend(); ++it) {
|
||||
|
||||
struct [[gnu::packed]] {
|
||||
uint8_t type;
|
||||
uint32_t start_x; uint32_t start_y;
|
||||
uint32_t width; uint32_t height;
|
||||
} update_pkt = {
|
||||
.type = 0x04,
|
||||
.start_x = (uint32_t)it->start_x, .start_y = (uint32_t)it->start_y,
|
||||
. width = (uint32_t)it-> width, . height = (uint32_t)it-> height
|
||||
};
|
||||
|
||||
euler::syscall::write_to_stream(socket, sizeof(update_pkt), &update_pkt);
|
||||
|
||||
for (int y = it->start_y; y < it->start_y + it->height; ++y)
|
||||
euler::syscall::write_to_stream(socket,
|
||||
it->width * sizeof(daguerre::hilbert_color),
|
||||
&contents.image.at(it->start_x, y));
|
||||
|
||||
}
|
||||
|
||||
contents.clear_dirty();
|
||||
|
||||
}
|
||||
|
||||
}
|
211
makefile
211
makefile
|
@ -1,118 +1,137 @@
|
|||
# arguments are not strictly necessary to build
|
||||
LIMINE_DIR = $(abspath dependencies/limine)
|
||||
MINTSUKI_HEADERS_DIR = $(abspath dependencies/mintsuki-headers)
|
||||
TOOLCHAIN_DIR = $(abspath toolchain)
|
||||
|
||||
CC_EXTRA_ARGS = -Wall -Wextra -O3 -ggdb
|
||||
EXTRA_CC_ARGS = -Wall -Wextra -Og -ggdb -fno-exceptions
|
||||
|
||||
HILBERT_NASM = nasm -f elf64
|
||||
HILBERT_CC = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-c++ -std=c++20 \
|
||||
${EXTRA_CC_ARGS} -static -mno-sse -I include -I $(abspath euler/include) \
|
||||
-I $(abspath libraries/daguerre/include) -I ${MINTSUKI_HEADERS_DIR}
|
||||
HILBERT_AR = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-ar
|
||||
HILBERT_LD = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-ld -z noexecstack
|
||||
|
||||
.EXPORT_ALL_VARIABLES:
|
||||
|
||||
LIB_DIR = ${TOOLCHAIN_DIR}/usr/x86_64-elf/lib
|
||||
|
||||
LIMINE_DEP = dependencies/.limine-done
|
||||
MINTSUKI_HEADERS_DEP = dependencies/.mintsuki-headers-done
|
||||
BINUTILS_DEP = toolchain/.binutils-done
|
||||
GCC_DEP = toolchain/.gcc-done
|
||||
LIBGCC_DEP = toolchain/.libgcc-done
|
||||
LIBSTDCPP_DEP = toolchain/.libstdcpp-done
|
||||
|
||||
EULER_DEP = toolchain/.euler-done
|
||||
DAGUERRE_DEP = toolchain/.daguerre-done
|
||||
|
||||
APP_DEPS = ${GCC_DEP} ${LIBGCC_DEP} ${LIBSTDCPP_DEP} ${EULER_DEP}
|
||||
LIBRARY_DEPS = ${GCC_DEP} ${LIBSTDCPP_DEP}
|
||||
|
||||
.PHONY: default run clean clean-dependencies
|
||||
|
||||
.PHONY: default
|
||||
default: build/disk.iso
|
||||
|
||||
# command and arguments that you should be careful about changing
|
||||
run: build/disk.iso
|
||||
gdb -x qemu.gdb
|
||||
|
||||
NASM = nasm
|
||||
CC = toolchain/usr/bin/x86_64-elf-c++
|
||||
AR = toolchain/usr/bin/x86_64-elf-ar
|
||||
LD = toolchain/usr/bin/x86_64-elf-ld
|
||||
clean:
|
||||
rm -rf build ${EULER_DEP} ${DAGUERRE_DEP}
|
||||
make -C euler clean
|
||||
make -C kernel clean
|
||||
make -C applications/init clean
|
||||
make -C applications/goldman clean
|
||||
make -C libraries/daguerre clean
|
||||
|
||||
KERNEL_INCLUDES = \
|
||||
dependencies/limine \
|
||||
dependencies/mintsuki-headers \
|
||||
kernel/include
|
||||
clean-dependencies: clean
|
||||
rm -rf toolchain dependencies
|
||||
|
||||
USER_INCLUDES = \
|
||||
dependencies/mintsuki-headers \
|
||||
euler/include \
|
||||
$(wildcard libraries/*/include)
|
||||
${LIMINE_DEP}:
|
||||
mkdir -p dependencies
|
||||
test -e dependencies/limine || git clone --depth 1 -b v7.5.1 https://github.com/limine-bootloader/limine dependencies/limine
|
||||
cd ${LIMINE_DIR} && ./bootstrap
|
||||
cd ${LIMINE_DIR} && ./configure --enable-bios --enable-bios-cd
|
||||
+make -C ${LIMINE_DIR}
|
||||
touch $@
|
||||
|
||||
NASM_ARGS = -f elf64
|
||||
${MINTSUKI_HEADERS_DEP}:
|
||||
mkdir -p dependencies
|
||||
test -e dependencies/mintsuki-headers || git clone --depth 1 https://github.com/osdev0/freestanding-headers dependencies/mintsuki-headers
|
||||
cd dependencies/mintsuki-headers && git fetch --depth=1 origin dd3abd2d7147efc4170dff478d3b7730bed14147
|
||||
cd dependencies/mintsuki-headers && git checkout dd3abd2d7147efc4170dff478d3b7730bed14147
|
||||
patch dependencies/mintsuki-headers/stddef.h patches/mintsuki-stddef.patch
|
||||
touch $@
|
||||
|
||||
CC_ARGS_COMMON = -std=c++20 -static -mno-sse -Iinclude ${CC_EXTRA_ARGS}
|
||||
CC_ARGS_KERNEL = \
|
||||
${CC_ARGS_COMMON} -ffreestanding -fno-exceptions \
|
||||
-fno-rtti -mcmodel=kernel ${KERNEL_INCLUDES:%=-I%}
|
||||
CC_ARGS_USER = ${CC_ARGS_COMMON} ${USER_INCLUDES:%=-I%}
|
||||
${BINUTILS_DEP}:
|
||||
mkdir -p dependencies toolchain/usr
|
||||
test -e dependencies/binutils || git clone --depth 1 -b binutils-2_42 https://sourceware.org/git/binutils-gdb dependencies/binutils
|
||||
mkdir -p dependencies/binutils/build
|
||||
cd dependencies/binutils/build && ../configure --disable-gdb \
|
||||
--target=x86_64-elf --prefix=${TOOLCHAIN_DIR}/usr
|
||||
+make -C dependencies/binutils/build
|
||||
+make -C dependencies/binutils/build install
|
||||
touch $@
|
||||
|
||||
LD_ARGS = -z noexecstack
|
||||
${GCC_DEP}: ${BINUTILS_DEP}
|
||||
mkdir -p toolchain/usr/include
|
||||
test -e dependencies/gcc || git clone --depth 1 -b releases/gcc-14.1.0 https://gcc.gnu.org/git/gcc dependencies/gcc
|
||||
mkdir -p dependencies/gcc/build
|
||||
cd dependencies/gcc/build && ../configure --disable-fixed-point \
|
||||
--disable-gcov --disable-multilib --disable-shared \
|
||||
--disable-hosted-libstdcxx \
|
||||
--enable-languages=c++ --target=x86_64-elf --enable-cstdio=stdio_pure \
|
||||
--prefix=${TOOLCHAIN_DIR}/usr --without-headers --enable-cxx-flags=-mno-sse
|
||||
+make -C dependencies/gcc/build all-gcc
|
||||
+make -C dependencies/gcc/build install-gcc
|
||||
touch $@
|
||||
|
||||
LIBDIR = toolchain/usr/x86_64-elf/lib
|
||||
${LIBGCC_DEP}: ${GCC_DEP}
|
||||
+make -C dependencies/gcc/build all-target-libgcc
|
||||
+make -C dependencies/gcc/build install-target-libgcc
|
||||
touch $@
|
||||
|
||||
SOURCES_FIND = -type f -regex '.*\.\(asm\|cpp\)'
|
||||
${LIBSTDCPP_DEP}: ${GCC_DEP}
|
||||
+make -C dependencies/gcc/build all-target-libstdc++-v3
|
||||
+make -C dependencies/gcc/build install-target-libstdc++-v3
|
||||
patch toolchain/usr/x86_64-elf/include/c++/14.1.0/memory patches/gcc-memory.patch
|
||||
touch $@
|
||||
|
||||
# kernel section
|
||||
${EULER_DEP}: ${LIBRARY_DEPS}
|
||||
+make -C euler build/crt0.o build/libc.a build/libg.a build/libm.a
|
||||
mkdir -p ${LIB_DIR}
|
||||
cp euler/build/crt0.o euler/build/libc.a \
|
||||
euler/build/libg.a euler/build/libm.a ${LIB_DIR}/
|
||||
touch $@
|
||||
|
||||
build/kernel/%.asm.o: kernel/%.asm
|
||||
@mkdir -p ${@D}
|
||||
${NASM} ${NASM_ARGS} $^ -o $@
|
||||
${DAGUERRE_DEP}: ${LIBRARY_DEPS}
|
||||
+make -C libraries/daguerre build/libdaguerre.a
|
||||
cp libraries/daguerre/build/libdaguerre.a ${LIB_DIR}/
|
||||
touch $@
|
||||
|
||||
build/kernel/%.cpp.o: kernel/%.cpp
|
||||
@mkdir -p ${@D}
|
||||
${CC} -c ${CC_ARGS_KERNEL} $^ -o $@
|
||||
kernel/build/kernel.elf: ${GCC_DEP} ${MINTSUKI_HEADERS_DEP} ${LIMINE_DEP}
|
||||
+make -C kernel build/kernel.elf
|
||||
|
||||
KERNEL_SOURCES = $(shell find kernel/source ${SOURCES_FIND})
|
||||
build/kernel.elf: ${KERNEL_SOURCES:%=build/%.o}
|
||||
${LD} ${LD_ARGS} -T kernel/link.ld $^ -o $@
|
||||
applications/init/build/init.elf: ${APP_DEPS}
|
||||
+make -C applications/init build/init.elf
|
||||
|
||||
# euler section
|
||||
applications/goldman/build/goldman.elf: ${APP_DEPS} ${DAGUERRE_DEP}
|
||||
+make -C applications/goldman build/goldman.elf
|
||||
|
||||
build/euler/%.asm.o: euler/%.asm
|
||||
@mkdir -p ${@D}
|
||||
${NASM} ${NASM_ARGS} $^ -o $@
|
||||
|
||||
build/euler/%.cpp.o: euler/%.cpp
|
||||
@mkdir -p ${@D}
|
||||
${CC} -c ${CC_ARGS_USER} -ffreestanding $^ -o $@
|
||||
|
||||
EULER_SOURCES = $(shell find euler/source ${SOURCES_FIND})
|
||||
${LIBDIR}/crt0.o ${LIBDIR}/libc.a ${LIBDIR}/libg.a ${LIBDIR}/libm.a build/euler.a&: ${EULER_SOURCES:%=build/%.o}
|
||||
${AR} rcs build/euler.a $^
|
||||
cp build/euler.a ${LIBDIR}/libc.a
|
||||
${NASM} ${NASM_ARGS} /dev/null -o ${LIBDIR}/crt0.o
|
||||
${AR} rcs ${LIBDIR}/libg.a ${LIBDIR}/crt0.o
|
||||
${AR} rcs ${LIBDIR}/libm.a ${LIBDIR}/crt0.o
|
||||
|
||||
# libraries and applications section
|
||||
|
||||
ALL_LIBRARIES = daguerre pake
|
||||
ALL_APPLICATIONS = clock goldman hello init
|
||||
|
||||
clock_LIBRARIES = daguerre pake
|
||||
goldman_LIBRARIES = daguerre
|
||||
hello_LIBRARIES = daguerre pake
|
||||
init_LIBRARIES =
|
||||
|
||||
build/%.cpp.o: %.cpp
|
||||
@mkdir -p ${@D}
|
||||
${CC} -c ${CC_ARGS_USER} $^ -o $@
|
||||
|
||||
# ${1} = library name
|
||||
define LIBRARY_TEMPLATE =
|
||||
${1}_SOURCES = $$(shell find libraries/${1}/source $${SOURCES_FIND})
|
||||
$${LIBDIR}/lib${1}.a build/libraries/lib${1}.a&: $${${1}_SOURCES:%=build/%.o}
|
||||
$${AR} rcs build/libraries/lib${1}.a $$^
|
||||
cp build/libraries/lib${1}.a $${LIBDIR}/lib${1}.a
|
||||
endef
|
||||
|
||||
# ${1} = application name
|
||||
define APPLICATION_TEMPLATE =
|
||||
${1}_SOURCES = $$(shell find applications/${1}/source $${SOURCES_FIND})
|
||||
build/applications/${1}.elf: $${${1}_SOURCES:%=build/%.o} $${${1}_LIBRARIES:%=$${LIBDIR}/lib%.a} $${LIBDIR}/libc.a
|
||||
$${CC} ${CC_ARGS_USER} $${${1}_SOURCES:%=build/%.o} $$(patsubst %,-l%,$${${1}_LIBRARIES}) -o $$@
|
||||
endef
|
||||
|
||||
$(foreach library,${ALL_LIBRARIES},$(eval $(call LIBRARY_TEMPLATE,${library})))
|
||||
$(foreach application,${ALL_APPLICATIONS},$(eval $(call APPLICATION_TEMPLATE,${application})))
|
||||
|
||||
# initfs and disk section
|
||||
|
||||
build/initfs.tgz: ${ALL_APPLICATIONS:%=build/applications/%.elf}
|
||||
build/initfs.tgz: applications/init/build/init.elf \
|
||||
applications/goldman/build/goldman.elf
|
||||
@mkdir -p build
|
||||
rm -rf build/initfs
|
||||
cp -r skeleton build/initfs
|
||||
$(foreach application,${ALL_APPLICATIONS},cp build/applications/${application}.elf build/initfs/bin/${application}; )
|
||||
cp applications/init/build/init.elf build/initfs/bin/init
|
||||
cp applications/goldman/build/goldman.elf build/initfs/bin/goldman
|
||||
cd build/initfs && tar czf ../initfs.tgz .
|
||||
|
||||
build/disk.iso: build/kernel.elf build/initfs.tgz
|
||||
build/disk.iso: kernel/build/kernel.elf build/initfs.tgz ${LIMINE_DEP}
|
||||
@mkdir -p build
|
||||
rm -rf build/iso
|
||||
mkdir build/iso
|
||||
cp dependencies/limine/bin/limine-bios.sys dependencies/limine/bin/limine-bios-cd.bin \
|
||||
build/kernel.elf build/initfs.tgz build/iso/
|
||||
cp kernel/build/kernel.elf ${LIMINE_DIR}/bin/limine-bios.sys \
|
||||
${LIMINE_DIR}/bin/limine-bios-cd.bin build/initfs.tgz build/iso/
|
||||
echo 'TIMEOUT=0' > build/iso/limine.cfg
|
||||
echo ':Hilbert OS' >> build/iso/limine.cfg
|
||||
echo 'PROTOCOL=limine' >> build/iso/limine.cfg
|
||||
|
@ -121,13 +140,3 @@ build/disk.iso: build/kernel.elf build/initfs.tgz
|
|||
echo 'MODULE_CMDLINE=initfs' >> build/iso/limine.cfg
|
||||
xorriso -as mkisofs -b limine-bios-cd.bin -no-emul-boot -boot-load-size 4 \
|
||||
-boot-info-table --protective-msdos-label build/iso -o $@
|
||||
|
||||
# phony targets
|
||||
|
||||
.PHONY: run
|
||||
run: build/disk.iso
|
||||
gdb -x qemu.gdb
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf build ${LIBDIR}/crt0.o ${LIBDIR}/libc.a ${LIBDIR}/libg.a ${LIBDIR}/libm.a $(foreach library,${ALL_LIBRARIES},${LIBDIR}/lib${library}.a)
|
||||
|
|
3
qemu.gdb
3
qemu.gdb
|
@ -1,5 +1,6 @@
|
|||
target remote | qemu-system-x86_64 -gdb stdio -cdrom build/disk.iso -boot d
|
||||
symbol-file build/kernel.elf
|
||||
symbol-file kernel/build/kernel.elf
|
||||
add-symbol-file applications/goldman/build/goldman.elf
|
||||
set disassembly-flavor intel
|
||||
set print asm-demangle on
|
||||
layout src
|
||||
|
|
54
readme.txt
54
readme.txt
|
@ -1,32 +1,13 @@
|
|||
hilbert os is a 64-bit hobby operating system, which is not very mature yet. to
|
||||
build and test it, you will need some software installed. on debian, i believe
|
||||
the packages listed below are sufficient.
|
||||
running command [1] below as root (e.g. with sudo) is sufficient. the default
|
||||
makefile target builds a disk image at build/disk.iso that can be booted on a
|
||||
64-bit bios system. you can use command [2] to build that. finally, use
|
||||
command [3] to run the disk in qemu with gdb attached.
|
||||
|
||||
- bison
|
||||
- flex
|
||||
- g++
|
||||
- gdb
|
||||
- git
|
||||
- libgmp-dev
|
||||
- libmpfr-dev
|
||||
- libmpc-dev
|
||||
- make
|
||||
- nasm
|
||||
- qemu-system-x86
|
||||
- texinfo
|
||||
- xorriso
|
||||
|
||||
next, you will need to download and compile some dependencies. the script in
|
||||
setup.sh will do this for you. if it sees an environment variables MAKEOPTS, it
|
||||
will pass the contents of that as arguments to invocations of make. otherwise,
|
||||
it defaults to "-j$(nproc)".
|
||||
|
||||
now that we have all the dependencies, just run "make". the default target is
|
||||
build/disk.iso, a bios-bootable disk image. you can run "make debug" to start
|
||||
qemu with that disk, and attach gdb to it. you will have to run "continue" (or
|
||||
"c" for short) in gdb to let qemu start. consider temporarily changing -O3 to
|
||||
-Og in the CC_EXTRA_ARGS variable of the makefile temporarily if you want to
|
||||
do any serious debugging.
|
||||
[1] apt install bison flex g++ gdb git libgmp-dev libmpfr-dev libmpc-dev make nasm qemu-system-x86 texinfo xorriso
|
||||
[2] make -j$(nproc)
|
||||
[3] make run
|
||||
|
||||
acknowledgements (any under "dependencies" are downloaded during build):
|
||||
|
||||
|
@ -63,7 +44,7 @@ acknowledgements (any under "dependencies" are downloaded during build):
|
|||
license: https://unsplash.com/license
|
||||
source: https://unsplash.com/photos/selective-focus-photography-snowflakes-9yhy1FXlKwI
|
||||
|
||||
- skeleton/assets/terminus/*.psf (terminus font)
|
||||
- skeleton/assets/terminus-bold-18x10.psf (terminus font, bold, 18x10)
|
||||
copyright 2020 dimitar toshkov zhekov
|
||||
license: skeleton/assets/terminus-ofl.txt (sil open font license v1.1)
|
||||
homepage: https://terminus-font.sourceforge.net/
|
||||
|
@ -77,12 +58,6 @@ license in isc.txt (isc license):
|
|||
- libraries
|
||||
- makefile
|
||||
|
||||
the following file are released under the text in 0bsd.txt (zero-clause bsd):
|
||||
|
||||
- clean-setup.sh
|
||||
- makefile
|
||||
- setup.sh
|
||||
|
||||
the following directories and files are released under the text in cc0.txt
|
||||
(creative commons cc0 1.0 universal public domain dedication):
|
||||
|
||||
|
@ -91,16 +66,12 @@ the following directories and files are released under the text in cc0.txt
|
|||
|
||||
project structure:
|
||||
|
||||
- applications/clock:
|
||||
a simple application that displays the current time in EDT.
|
||||
|
||||
- applications/goldman:
|
||||
the default compositor.
|
||||
in the future, this will be the default compositor.
|
||||
|
||||
- applications/init:
|
||||
the initial program loaded by the kernel. currently it just starts the
|
||||
compositor and the clock, but in the future it will read some kind of
|
||||
configuration file and decide what to do based on that.
|
||||
the initial program loaded by the kernel. currently it just
|
||||
(attempts to) start /bin/compositor and then /bin/hello.
|
||||
|
||||
- documentation:
|
||||
documentation. currently this directory is a bit disorganized, and has
|
||||
|
@ -116,9 +87,6 @@ project structure:
|
|||
- libraries/daguerre:
|
||||
an image loading / rendering library.
|
||||
|
||||
- libraries/pake:
|
||||
a widget library for windowed applications
|
||||
|
||||
- patches:
|
||||
a couple patches that are applied to dependencies
|
||||
|
||||
|
|
76
setup.sh
76
setup.sh
|
@ -1,76 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
LIMINE_TAG=v7.5.1
|
||||
MINTSUKI_HEADERS_COMMIT=dd3abd2d7147efc4170dff478d3b7730bed14147
|
||||
BINUTILS_TAG=binutils-2_42
|
||||
GCC_TAG=releases/gcc-14.1.0
|
||||
|
||||
PROJECT_ROOT="$(pwd)"
|
||||
|
||||
if [ -e .setup-complete ]; then
|
||||
echo setup has already completed. refusing to run again.
|
||||
echo to run again anyway, delete .setup-complete
|
||||
echo to undo any previous setup, run clean-setup.sh
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -e .setup-started ]; then
|
||||
echo setup has already been started, but failed. refusing to run again.
|
||||
echo to run again anyway, delete .setup-started
|
||||
echo to undo any previous setup, run clean-setup.sh
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$MAKEOPTS" ]; then
|
||||
MAKEOPTS=-j$(nproc)
|
||||
fi
|
||||
|
||||
touch .setup-started
|
||||
|
||||
set -e
|
||||
|
||||
mkdir -p dependencies toolchain/usr
|
||||
cd dependencies
|
||||
|
||||
git clone --depth 1 -b "$LIMINE_TAG" https://github.com/limine-bootloader/limine limine
|
||||
cd limine
|
||||
./bootstrap
|
||||
./configure --enable-bios --enable-bios-cd
|
||||
make $MAKEOPTS
|
||||
cd ..
|
||||
|
||||
git clone --depth 1 https://github.com/osdev0/freestanding-headers mintsuki-headers
|
||||
cd mintsuki-headers
|
||||
git fetch --depth=1 origin "$MINTSUKI_HEADERS_COMMIT"
|
||||
git checkout "$MINTSUKI_HEADERS_COMMIT"
|
||||
patch stddef.h "$PROJECT_ROOT"/patches/mintsuki-stddef.patch
|
||||
cd ..
|
||||
|
||||
git clone --depth 1 -b "$BINUTILS_TAG" https://sourceware.org/git/binutils-gdb binutils
|
||||
mkdir binutils/build
|
||||
cd binutils/build
|
||||
../configure --disable-gdb --target=x86_64-elf --prefix="$PROJECT_ROOT"/toolchain/usr
|
||||
make $MAKEOPTS
|
||||
make $MAKEOPTS install
|
||||
cd ../..
|
||||
|
||||
git clone --depth 1 -b "$GCC_TAG" https://gcc.gnu.org/git/gcc gcc
|
||||
mkdir gcc/build
|
||||
cd gcc/build
|
||||
../configure --disable-fixed-point --disable-gcov --disable-multilib \
|
||||
--disable-shared --disable-hosted-libstdcxx --enable-languages=c++ \
|
||||
--target=x86_64-elf --enable-cstdio=stdio_pure \
|
||||
--prefix="$PROJECT_ROOT"/toolchain/usr --without-headers \
|
||||
--enable-cxx-flags=-mno-sse
|
||||
make $MAKEOPTS all-gcc
|
||||
make $MAKEOPTS install-gcc
|
||||
make $MAKEOPTS all-target-libgcc
|
||||
make $MAKEOPTS install-target-libgcc
|
||||
make $MAKEOPTS all-target-libstdc++-v3
|
||||
make $MAKEOPTS install-target-libstdc++-v3
|
||||
patch "$PROJECT_ROOT"/toolchain/usr/x86_64-elf/include/c++/14.1.0/memory \
|
||||
"$PROJECT_ROOT"/patches/gcc-memory.patch
|
||||
cd ../..
|
||||
|
||||
cd ..
|
||||
touch .setup-complete
|
|
@ -5,3 +5,7 @@ its license can be found online at https://unsplash.com/license.
|
|||
|
||||
the icon in pointer.ppm is released under the cc0 1.0 universal public
|
||||
domain dedication (https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
|
||||
the font in terminus-bold-18x10.psf is the "terminus" font, in bold weight, at
|
||||
18x10. it can be found only at https://terminus-font.sourceforge.net/ and is
|
||||
under the license in terminus-ofl.txt (the sil open font license v1.1).
|
||||
|
|
Binary file not shown.
|
@ -1,3 +0,0 @@
|
|||
this directory contains the "terminus" font, at a couple weights and sizes.
|
||||
terminus can be found only at https://terminus-font.sourceforge.net/ and is
|
||||
under the license in terminus-ofl.txt (the sil open font license v1.1).
|
Reference in a new issue