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"); | ||||
| 
 | ||||
|   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) { | ||||
|     euler::syscall::stream_handle socket; | ||||
|     euler::syscall::accept_socket_connection(listener, socket); | ||||
|     euler::syscall::start_thread(socket_thread_main, socket); | ||||
| 
 | ||||
|     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