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/* | dependencies/* | ||||||
| toolchain/* | toolchain/* | ||||||
| 
 | 
 | ||||||
| .setup-complete | euler/build/* | ||||||
| .setup-started | 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/framebuffer.hpp> | ||||||
| #include <daguerre/ppm.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; |   trans_color = euler::syscall::encode_color(0xff, 0x00, 0xff); | ||||||
|   euler::syscall::create_socket_listener("hilbert.compositor", listener); |  | ||||||
| 
 | 
 | ||||||
|   r = new renderer( |   daguerre::image<daguerre::hilbert_color> framebuffer = | ||||||
|     daguerre::get_hilbert_framebuffer(), |     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)); |  | ||||||
| 
 | 
 | ||||||
|   euler::syscall::start_thread([]() { r->render_thread_main(); }); |   int fw = framebuffer.width; | ||||||
|   euler::syscall::start_thread(input_thread_main); |   int fh = framebuffer.height; | ||||||
| 
 | 
 | ||||||
|   r->dispatch_render(); |   daguerre::image<daguerre::hilbert_color> double_buffer(fw, fh); | ||||||
| 
 | 
 | ||||||
|   euler::syscall::set_thread_name("socket listener thread"); |   std::optional<daguerre::image<daguerre::hilbert_color>> | ||||||
|  |     background_original = daguerre::try_load_ppm("/assets/background.ppm"); | ||||||
| 
 | 
 | ||||||
|   while (true) { |   daguerre::image<daguerre::hilbert_color> background; | ||||||
|     euler::syscall::stream_handle socket; | 
 | ||||||
|     euler::syscall::accept_socket_connection(listener, socket); |   if (background_original.has_value()) | ||||||
|     euler::syscall::start_thread(socket_thread_main, socket); |     background = background_original->stretch(fw, fh); | ||||||
|  |   else { | ||||||
|  |     background = daguerre::image<daguerre::hilbert_color>(fw, fh); | ||||||
|  |     background.fill(euler::syscall::encode_color(0, 0, 0)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   std::optional<daguerre::image<daguerre::hilbert_color>> | ||||||
|  |     pointer_original = daguerre::try_load_ppm("/assets/pointer.ppm"); | ||||||
|  | 
 | ||||||
|  |   if (!pointer_original.has_value()) | ||||||
|  |     //TODO
 | ||||||
|  |     while (1) | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|  |   daguerre::image<daguerre::hilbert_color> | ||||||
|  |     pointer = std::move(*pointer_original); | ||||||
|  | 
 | ||||||
|  |   int mouse_x = fw / 2; | ||||||
|  |   int mouse_y = fh / 2; | ||||||
|  | 
 | ||||||
|  |   while (true) { | ||||||
|  | 
 | ||||||
|  |     double_buffer.copy_from(background, 0, 0); | ||||||
|  |     double_buffer.convert_from(pointer, mouse_x, mouse_y, 0, 0, | ||||||
|  |       std::min(pointer. width, double_buffer. width - mouse_x), | ||||||
|  |       std::min(pointer.height, double_buffer.height - mouse_y), | ||||||
|  |       &convert_pointer); | ||||||
|  | 
 | ||||||
|  |     framebuffer.copy_from(double_buffer, 0, 0); | ||||||
|  | 
 | ||||||
|  |     auto result = euler::syscall::get_input_packet(); | ||||||
|  |     if (std::holds_alternative<euler::syscall::mouse_packet>(result)) { | ||||||
|  |       const auto &packet = std::get<euler::syscall::mouse_packet>(result); | ||||||
|  |       mouse_x += packet.x_changed; | ||||||
|  |       mouse_y += packet.y_changed; | ||||||
|  |       if (mouse_x < 0) | ||||||
|  |         mouse_x = 0; | ||||||
|  |       else if (mouse_x >= fw) | ||||||
|  |         mouse_x = fw - 1; | ||||||
|  |       if (mouse_y < 0) | ||||||
|  |         mouse_y = 0; | ||||||
|  |       else if (mouse_y >= fh) | ||||||
|  |         mouse_y = fh - 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return 0; | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +0,0 @@ | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include "renderer.hpp" |  | ||||||
| 
 |  | ||||||
| extern renderer *r; |  | ||||||
|  | @ -1,124 +0,0 @@ | ||||||
| #include "renderer.hpp" |  | ||||||
| 
 |  | ||||||
| renderer::renderer( |  | ||||||
|   daguerre::image<daguerre::hilbert_color> &&fb, |  | ||||||
|   daguerre::image<daguerre::hilbert_color> &&bg, |  | ||||||
|   daguerre::hilbert_color bgc, |  | ||||||
|   daguerre::image<daguerre::hilbert_color> &&c, |  | ||||||
|   daguerre::hilbert_color cbg) |  | ||||||
| 
 |  | ||||||
| : framebuffer(std::move(fb)), |  | ||||||
|   double_buffer(framebuffer.width, framebuffer.height), |  | ||||||
|   background(std::move(bg)), cursor(std::move(c)), cursor_background(cbg), |  | ||||||
|   cursor_x(framebuffer.width / 2), cursor_y(framebuffer.height / 2) { |  | ||||||
| 
 |  | ||||||
|   euler::syscall::create_private_socket(dispatcher_handle_1, dispatcher_handle_2); |  | ||||||
| 
 |  | ||||||
|   if (background.width != framebuffer.width || |  | ||||||
|       background.height != framebuffer.height) { |  | ||||||
| 
 |  | ||||||
|     daguerre::image<daguerre::hilbert_color> |  | ||||||
|       new_background(framebuffer.width, framebuffer.height); |  | ||||||
| 
 |  | ||||||
|     new_background.fill(bgc); |  | ||||||
| 
 |  | ||||||
|     int from_x = 0; |  | ||||||
|     int from_y = 0; |  | ||||||
|     int to_x = framebuffer.width / 2 - background.width / 2; |  | ||||||
|     int to_y = framebuffer.height / 2 - background.height / 2; |  | ||||||
|     int width = background.width; |  | ||||||
|     int height = background.height; |  | ||||||
| 
 |  | ||||||
|     daguerre::make_safe(to_x, from_x, width, 0, framebuffer.width); |  | ||||||
|     daguerre::make_safe(to_y, from_y, height, 0, framebuffer.height); |  | ||||||
| 
 |  | ||||||
|     new_background.copy_from(background, to_x, to_y, from_x, from_y, width, height); |  | ||||||
|     background = std::move(new_background); |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template <class color_t> |  | ||||||
| void overlay_trans(color_t &to, const color_t &from, const color_t ¶m) { |  | ||||||
|   if (from != param) |  | ||||||
|     to = from; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void renderer::do_render() { |  | ||||||
| 
 |  | ||||||
|   double_buffer.copy_from(background, 0, 0); |  | ||||||
| 
 |  | ||||||
|   for (auto it = windows.begin(); it != windows.end(); ++it) { |  | ||||||
|     int tx = (*it)->x, ty = (*it)->y, fx = 0, fy = 0; |  | ||||||
|     int w = (*it)->contents_with_decorations.width; |  | ||||||
|     int h = (*it)->contents_with_decorations.height; |  | ||||||
|     daguerre::make_safe(tx, fx, w, 0, double_buffer.width); |  | ||||||
|     daguerre::make_safe(ty, fy, h, 0, double_buffer.height); |  | ||||||
|     double_buffer.copy_from( |  | ||||||
|       (*it)->contents_with_decorations, tx, ty, fx, fy, w, h); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   double_buffer.convert_from( |  | ||||||
|     cursor_background, cursor, cursor_x, cursor_y, 0, 0, |  | ||||||
|     std::min(cursor.width, framebuffer.width - cursor_x), |  | ||||||
|     std::min(cursor.height, framebuffer.height - cursor_y), |  | ||||||
|     &overlay_trans); |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| [[noreturn]] void renderer::render_thread_main() { |  | ||||||
|   euler::syscall::set_thread_name("render thread"); |  | ||||||
|   while (true) { |  | ||||||
|     uint8_t byte; |  | ||||||
|     euler::syscall::read_from_stream(dispatcher_handle_2, 1, &byte); |  | ||||||
|     mut.lock(); |  | ||||||
|     euler::syscall::clear_socket_read_queue(dispatcher_handle_2); |  | ||||||
|     do_render(); |  | ||||||
|     mut.unlock(); |  | ||||||
|     framebuffer.copy_from(double_buffer, 0, 0); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void renderer::get_cursor(int &x_out, int &y_out) { |  | ||||||
|   x_out = cursor_x; |  | ||||||
|   y_out = cursor_y; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void renderer::bump_cursor(int x_offset, int y_offset) { |  | ||||||
| 
 |  | ||||||
|   cursor_x += x_offset; |  | ||||||
|   if (cursor_x < 0) |  | ||||||
|     cursor_x = 0; |  | ||||||
|   else if (cursor_x >= framebuffer.width) |  | ||||||
|     cursor_x = framebuffer.width - 1; |  | ||||||
| 
 |  | ||||||
|   cursor_y += y_offset; |  | ||||||
|   if (cursor_y < 0) |  | ||||||
|     cursor_y = 0; |  | ||||||
|   else if (cursor_y >= framebuffer.height) |  | ||||||
|     cursor_y = framebuffer.height - 1; |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void renderer::move_window_to_front(std::list<window *>::iterator w) { |  | ||||||
|   window *wp = *w; |  | ||||||
|   windows.erase(w); |  | ||||||
|   if (windows.size() != 0) |  | ||||||
|     windows.back()->draw_decorations(false); |  | ||||||
|   windows.push_back(wp); |  | ||||||
|   wp->draw_decorations(true); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void renderer::add_window(window *w) { |  | ||||||
|   if (windows.size() != 0) |  | ||||||
|     windows.back()->draw_decorations(false); |  | ||||||
|   w->draw_decorations(true); |  | ||||||
|   windows.push_back(w); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void renderer::remove_window(window *w) { |  | ||||||
|   windows.remove(w); |  | ||||||
|   if (windows.size() != 0) |  | ||||||
|     windows.back()->draw_decorations(true); |  | ||||||
| } |  | ||||||
|  | @ -1,79 +0,0 @@ | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <daguerre/image.hpp> |  | ||||||
| #include "window.hpp" |  | ||||||
| #include <mutex> |  | ||||||
| #include <list> |  | ||||||
| 
 |  | ||||||
| class renderer { |  | ||||||
| 
 |  | ||||||
|   daguerre::image<daguerre::hilbert_color> framebuffer; |  | ||||||
|   daguerre::image<daguerre::hilbert_color> double_buffer; |  | ||||||
| 
 |  | ||||||
|   daguerre::image<daguerre::hilbert_color> background; |  | ||||||
|   daguerre::image<daguerre::hilbert_color> cursor; |  | ||||||
|   daguerre::hilbert_color cursor_background; |  | ||||||
| 
 |  | ||||||
|   int cursor_x; |  | ||||||
|   int cursor_y; |  | ||||||
| 
 |  | ||||||
|   std::mutex mut; |  | ||||||
| 
 |  | ||||||
|   euler::syscall::stream_handle |  | ||||||
|     dispatcher_handle_1, dispatcher_handle_2; |  | ||||||
| 
 |  | ||||||
|   void do_render(); |  | ||||||
| 
 |  | ||||||
| public: |  | ||||||
|   //all of the shown windows, sorted from furthest back to furthest front.
 |  | ||||||
|   //while the renderer is not locked, the contents of this can change and
 |  | ||||||
|   //iterators can be invalided. this should not be reordered, added to, or
 |  | ||||||
|   //have elements removed from outside the renderer.
 |  | ||||||
|   std::list<window *> windows; |  | ||||||
| 
 |  | ||||||
|   renderer( |  | ||||||
|     daguerre::image<daguerre::hilbert_color> &&framebuffer, |  | ||||||
|     daguerre::image<daguerre::hilbert_color> &&background, |  | ||||||
|     daguerre::hilbert_color background_color, |  | ||||||
|     daguerre::image<daguerre::hilbert_color> &&cursor, |  | ||||||
|     daguerre::hilbert_color cursor_background); |  | ||||||
| 
 |  | ||||||
|   inline ~renderer() { |  | ||||||
|     euler::syscall::close_stream(dispatcher_handle_1); |  | ||||||
|     euler::syscall::close_stream(dispatcher_handle_2); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   renderer(const renderer &) = delete; |  | ||||||
|   renderer &operator =(const renderer &) = delete; |  | ||||||
| 
 |  | ||||||
|   [[noreturn]] void render_thread_main(); |  | ||||||
| 
 |  | ||||||
|   inline void lock()   { mut.lock();   } |  | ||||||
|   inline void unlock() { mut.unlock(); } |  | ||||||
| 
 |  | ||||||
|   inline void dispatch_render() { |  | ||||||
|     uint8_t byte = 0; |  | ||||||
|     euler::syscall::write_to_stream(dispatcher_handle_1, 1, &byte); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   //gets the current position of the cursor. this should
 |  | ||||||
|   //only be called while the renderer is locked.
 |  | ||||||
|   void get_cursor(int &x_out, int &y_out); |  | ||||||
| 
 |  | ||||||
|   //this adds x_offset and y_offset to the current cursor position, and then
 |  | ||||||
|   //clamps the cursor position to have its top-left pixel inside the frame.
 |  | ||||||
|   //this should only be called while the renderer is locked.
 |  | ||||||
|   void bump_cursor(int x_offset, int y_offset); |  | ||||||
| 
 |  | ||||||
|   //moves the pointed to window to the front of the window stack.
 |  | ||||||
|   //this should only be called while the renderer is locked.
 |  | ||||||
|   void move_window_to_front(std::list<window *>::iterator w); |  | ||||||
| 
 |  | ||||||
|   void    add_window(window *w); |  | ||||||
|   void remove_window(window *w); |  | ||||||
| 
 |  | ||||||
|   inline bool is_top(window *w) { |  | ||||||
|     return windows.size() != 0 && w == windows.back(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| }; |  | ||||||
|  | @ -1,152 +0,0 @@ | ||||||
| #include <daguerre/image.hpp> |  | ||||||
| #include "socket.hpp" |  | ||||||
| #include "window.hpp" |  | ||||||
| #include "main.hpp" |  | ||||||
| #include <memory> |  | ||||||
| #include <vector> |  | ||||||
| 
 |  | ||||||
| struct socket_state { |  | ||||||
| 
 |  | ||||||
|   euler::syscall::stream_handle socket; |  | ||||||
|   window *w; |  | ||||||
| 
 |  | ||||||
|   bool try_show_window() { |  | ||||||
| 
 |  | ||||||
|     if (w->is_shown) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     r->lock(); |  | ||||||
|     r->add_window(w); |  | ||||||
|     r->unlock(); |  | ||||||
|     r->dispatch_render(); |  | ||||||
|     return true; |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   bool try_hide_window() { |  | ||||||
| 
 |  | ||||||
|     if (!w->is_shown) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     r->lock(); |  | ||||||
|     r->remove_window(w); |  | ||||||
|     r->unlock(); |  | ||||||
|     r->dispatch_render(); |  | ||||||
|     return true; |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   bool try_set_window_dimensions() { |  | ||||||
| 
 |  | ||||||
|     struct [[gnu::packed]] { uint32_t width; uint32_t height; } packet; |  | ||||||
|     if (euler::syscall::read_from_stream(socket, sizeof(packet), &packet) != |  | ||||||
|         euler::syscall::stream_result::success) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     if (packet. width > __INT_MAX__ - window::decorations_extra_width || |  | ||||||
|         packet.height > __INT_MAX__ - window::decorations_extra_height) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     r->lock(); |  | ||||||
|     w->set_size(packet.width, packet.height); |  | ||||||
|     w->draw_decorations(r->is_top(w)); |  | ||||||
|     r->unlock(); |  | ||||||
|     return true; |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   bool try_set_window_title() { |  | ||||||
| 
 |  | ||||||
|     uint32_t length; |  | ||||||
|     if (euler::syscall::read_from_stream(socket, 4, &length) != |  | ||||||
|         euler::syscall::stream_result::success) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     std::string title; |  | ||||||
|     title.resize(length); |  | ||||||
|     if (euler::syscall::read_from_stream(socket, length, title.data()) != |  | ||||||
|         euler::syscall::stream_result::success) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     r->lock(); |  | ||||||
|     w->title = std::move(title); |  | ||||||
|     w->draw_decorations(r->is_top(w)); |  | ||||||
|     r->unlock(); |  | ||||||
|     r->dispatch_render(); |  | ||||||
|     return true; |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   bool try_update_window_region() { |  | ||||||
| 
 |  | ||||||
|     struct [[gnu::packed]] { |  | ||||||
|       uint32_t start_x; uint32_t start_y; uint32_t width; uint32_t height; |  | ||||||
|     } packet; |  | ||||||
|     if (euler::syscall::read_from_stream(socket, sizeof(packet), &packet) != |  | ||||||
|         euler::syscall::stream_result::success) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     static_assert(__INT_MAX__ <= __UINT64_MAX__); |  | ||||||
|     if ((uint64_t)packet.start_x + packet. width > (uint64_t)w->contents. width || |  | ||||||
|         (uint64_t)packet.start_y + packet.height > (uint64_t)w->contents.height) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     daguerre::image<daguerre::hilbert_color> content(packet.width, packet.height); |  | ||||||
|     if (euler::syscall::read_from_stream( |  | ||||||
|           socket, packet.width * packet.height * 4, content.buffer) != |  | ||||||
|         euler::syscall::stream_result::success) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     r->lock(); |  | ||||||
|     w->contents.copy_from(content, packet.start_x, packet.start_y); |  | ||||||
|     r->unlock(); |  | ||||||
|     r->dispatch_render(); |  | ||||||
|     return true; |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   bool try_process_request() { |  | ||||||
| 
 |  | ||||||
|     uint8_t type; |  | ||||||
|     if (euler::syscall::read_from_stream(socket, 1, &type) != |  | ||||||
|         euler::syscall::stream_result::success) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     switch (type) { |  | ||||||
|     case 0x00: return try_show_window(); |  | ||||||
|     case 0x01: return try_hide_window(); |  | ||||||
|     case 0x02: return try_set_window_dimensions(); |  | ||||||
|     case 0x03: return try_set_window_title(); |  | ||||||
|     case 0x04: return try_update_window_region(); |  | ||||||
|     default: return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| [[noreturn]] void socket_thread_main(euler::syscall::stream_handle socket) { |  | ||||||
| 
 |  | ||||||
|   euler::syscall::set_thread_name("socket thread"); |  | ||||||
| 
 |  | ||||||
|   int x, y; |  | ||||||
|   r->get_cursor(x, y); |  | ||||||
| 
 |  | ||||||
|   window *w = new window(x, y); |  | ||||||
|   socket_state *state = new socket_state { |  | ||||||
|     .socket = socket, .w = w }; |  | ||||||
| 
 |  | ||||||
|   while (state->try_process_request()) ; |  | ||||||
| 
 |  | ||||||
|   if (w->is_shown) { |  | ||||||
|     r->lock(); |  | ||||||
|     r->remove_window(w); |  | ||||||
|     r->unlock(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   delete state; |  | ||||||
|   delete w; |  | ||||||
|   euler::syscall::close_stream(socket); |  | ||||||
|   euler::syscall::end_this_thread(0); |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,5 +0,0 @@ | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <euler/syscall.hpp> |  | ||||||
| 
 |  | ||||||
| [[noreturn]] void socket_thread_main(euler::syscall::stream_handle socket); |  | ||||||
|  | @ -1,83 +0,0 @@ | ||||||
| #include <daguerre/psf.hpp> |  | ||||||
| #include "renderer.hpp" |  | ||||||
| #include "window.hpp" |  | ||||||
| #include <cassert> |  | ||||||
| 
 |  | ||||||
| //TODO: make these statically intialized once that is implemented
 |  | ||||||
| bool have_initialized_decoration_stuff; |  | ||||||
| daguerre::fixed_font<bool> *title_font; |  | ||||||
| daguerre::hilbert_color border_color_top; |  | ||||||
| daguerre::hilbert_color border_color_not_top; |  | ||||||
| daguerre::hilbert_color title_color; |  | ||||||
| 
 |  | ||||||
| void window::set_size(int width, int height) { |  | ||||||
|   int center_x = x + contents_with_decorations. width / 2; |  | ||||||
|   int center_y = y + contents_with_decorations.height / 2; |  | ||||||
|   contents_with_decorations = |  | ||||||
|     daguerre::image<daguerre::hilbert_color>(width + 4, height + 18); |  | ||||||
|   contents = daguerre::image<daguerre::hilbert_color>( |  | ||||||
|     width, height, |  | ||||||
|     &contents_with_decorations.at(2, 16), |  | ||||||
|     contents_with_decorations.buffer_pitch, false); |  | ||||||
|   x = center_x - contents_with_decorations. width / 2; |  | ||||||
|   y = center_y - contents_with_decorations.height / 2; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void title_converter( |  | ||||||
|   daguerre::hilbert_color &out, const bool &in, const bool &top) { |  | ||||||
|   out = in ? title_color : top ? border_color_top : border_color_not_top; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void window::draw_decorations(bool top) { |  | ||||||
| 
 |  | ||||||
|   //TODO: handle error loading font.
 |  | ||||||
|   //see also comment on title_font declaration.
 |  | ||||||
|   if (!have_initialized_decoration_stuff) { |  | ||||||
|     title_font = new daguerre::fixed_font<bool>( |  | ||||||
|       *daguerre::try_load_psf("/assets/terminus/6x12.psf")); |  | ||||||
|     assert(title_font->glyph_height == 12); |  | ||||||
|     border_color_top     = euler::syscall::encode_color(0x00, 0x3f, 0xff); |  | ||||||
|     border_color_not_top = euler::syscall::encode_color(0x22, 0x22, 0x22); |  | ||||||
|     title_color          = euler::syscall::encode_color(0xff, 0xff, 0xff); |  | ||||||
|     have_initialized_decoration_stuff = true; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   static_assert( decorations_extra_width ==  4); |  | ||||||
|   static_assert(decorations_extra_height == 18); |  | ||||||
|   static_assert(            title_height == 16); |  | ||||||
| 
 |  | ||||||
|   auto border_color = top ? border_color_top : border_color_not_top; |  | ||||||
| 
 |  | ||||||
|   contents_with_decorations.fill(border_color, 0, 0, |  | ||||||
|     contents_with_decorations.width, 16); |  | ||||||
|   contents_with_decorations.fill( |  | ||||||
|     border_color, 0, contents_with_decorations.height - 2, |  | ||||||
|     contents_with_decorations.width, 2); |  | ||||||
|   contents_with_decorations.fill(border_color, 0, 16, |  | ||||||
|     2, contents_with_decorations.height - 18); |  | ||||||
|   contents_with_decorations.fill(border_color, |  | ||||||
|     contents_with_decorations.width - 2, 16, |  | ||||||
|     2, contents_with_decorations.height - 18); |  | ||||||
| 
 |  | ||||||
|   //TODO: make UTF-8--safe
 |  | ||||||
|   unsigned max_title_length = |  | ||||||
|     contents_with_decorations.width / title_font->glyph_width; |  | ||||||
|   std::string *title_to_draw; |  | ||||||
|   std::string shortened_title; |  | ||||||
|   if (title.size() > max_title_length) { |  | ||||||
|     shortened_title.resize(max_title_length - 3); |  | ||||||
|     memcpy(shortened_title.data(), title.data(), max_title_length - 3); |  | ||||||
|     shortened_title[max_title_length - 3] = '.'; |  | ||||||
|     shortened_title[max_title_length - 2] = '.'; |  | ||||||
|     shortened_title[max_title_length - 1] = '.'; |  | ||||||
|     title_to_draw = &shortened_title; |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     title_to_draw = &title; |  | ||||||
| 
 |  | ||||||
|   contents_with_decorations.render_text(*title_font, top, |  | ||||||
|     contents_with_decorations.width / 2 - |  | ||||||
|       (title_to_draw->size() * title_font->glyph_width) / 2, |  | ||||||
|     2, title_to_draw->data(), title_converter); |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,32 +0,0 @@ | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <daguerre/image.hpp> |  | ||||||
| 
 |  | ||||||
| struct window { |  | ||||||
| 
 |  | ||||||
|   static constexpr int decorations_extra_width  =  4; |  | ||||||
|   static constexpr int decorations_extra_height = 18; |  | ||||||
|   static constexpr int title_height = 16; |  | ||||||
| 
 |  | ||||||
|   daguerre::image<daguerre::hilbert_color> contents_with_decorations; |  | ||||||
|   daguerre::image<daguerre::hilbert_color> contents; |  | ||||||
| 
 |  | ||||||
|   int x; |  | ||||||
|   int y; |  | ||||||
| 
 |  | ||||||
|   bool is_shown; |  | ||||||
| 
 |  | ||||||
|   std::string title; |  | ||||||
| 
 |  | ||||||
|   void set_size(int width, int height); |  | ||||||
|   void draw_decorations(bool top); |  | ||||||
| 
 |  | ||||||
|   inline window(int center_x, int center_y) |  | ||||||
|   : x(center_x - decorations_extra_width / 2), |  | ||||||
|     y(center_y - decorations_extra_height / 2), |  | ||||||
|     is_shown(false) { |  | ||||||
|     set_size(0, 0); |  | ||||||
|     draw_decorations(false); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| }; |  | ||||||
|  | @ -1,42 +0,0 @@ | ||||||
| #include <pake/widgets/fixed-text.hpp> |  | ||||||
| #include <daguerre/psf.hpp> |  | ||||||
| #include <pake/window.hpp> |  | ||||||
| 
 |  | ||||||
| daguerre::fixed_font<bool> *font; |  | ||||||
| 
 |  | ||||||
| int main() { |  | ||||||
| 
 |  | ||||||
|   font = new daguerre::fixed_font<bool>( |  | ||||||
|     daguerre::try_load_psf("/assets/terminus/10x18-bold.psf").value()); |  | ||||||
| 
 |  | ||||||
|   pake::widgets::fixed_text *text = |  | ||||||
|     new pake::widgets::fixed_text("Hello, world!", font, |  | ||||||
|       euler::syscall::encode_color(0xaa, 0xaa, 0xaa), |  | ||||||
|       euler::syscall::encode_color(0x00, 0x00, 0x00), |  | ||||||
|       pake::halign::center, pake::valign::center); |  | ||||||
| 
 |  | ||||||
|   pake::window w(300, 200, "Hello"); |  | ||||||
|   w.set_root(std::unique_ptr<pake::widget>(text)); |  | ||||||
|   w.render_and_send_to_compositor(); |  | ||||||
|   w.show(); |  | ||||||
| 
 |  | ||||||
|   pake::widgets::fixed_text *text2 = |  | ||||||
|     new pake::widgets::fixed_text("H!", font, |  | ||||||
|       euler::syscall::encode_color(0xaa, 0xaa, 0xaa), |  | ||||||
|       euler::syscall::encode_color(0x00, 0x00, 0x00), |  | ||||||
|       pake::halign::center, pake::valign::center); |  | ||||||
| 
 |  | ||||||
|   pake::window w2(100, 50, "Hello 2"); |  | ||||||
|   w2.set_root(std::unique_ptr<pake::widget>(text2)); |  | ||||||
|   w2.render_and_send_to_compositor(); |  | ||||||
|   w2.show(); |  | ||||||
| 
 |  | ||||||
|   //TODO: call event loop
 |  | ||||||
| 
 |  | ||||||
|   euler::syscall::stream_handle h1, h2; |  | ||||||
|   euler::syscall::create_private_socket(h1, h2); |  | ||||||
|   uint8_t byte; |  | ||||||
|   while (1) |  | ||||||
|     euler::syscall::read_from_stream(h1, 1, &byte); |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
							
								
								
									
										12
									
								
								applications/init/makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								applications/init/makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | SOURCES = \
 | ||||||
|  |   main.cpp | ||||||
|  | 
 | ||||||
|  | build/%.cpp.o: source/%.cpp | ||||||
|  | 	@mkdir -p $(@D) | ||||||
|  | 	$(HILBERT_CC) -c $^ -o $@ | ||||||
|  | 
 | ||||||
|  | build/init.elf: $(SOURCES:%=build/%.o) | ||||||
|  | 	$(HILBERT_CC) $^ -o $@ | ||||||
|  | 
 | ||||||
|  | clean: | ||||||
|  | 	rm -rf build | ||||||
|  | @ -1,8 +1,11 @@ | ||||||
| #include <euler/syscall.hpp> | #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::process_handle dummy; | ||||||
|   euler::syscall::start_process("/bin/compositor", {}, {}, dummy); |   euler::syscall::start_process("/bin/compositor", {}, {}, dummy); | ||||||
|   euler::syscall::start_process("/bin/clock", {}, {}, dummy); |   euler::syscall::start_process("/bin/hello", {}, {}, dummy); | ||||||
|   return 0; |   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". | compositors listen on the socket id "hilbert.compositor". | ||||||
| 
 | 
 | ||||||
| there is a one-to-one correspondence between sockets to the compositor and | when a window is opened by an application, that window can only be referred to | ||||||
| windows. when a socket is opened, a window is created, and when a socket is | on that stream. the opaque value given in the "window opened" message refers to | ||||||
| closed, its window is destroyed. this socket can be gifted to another process, | that window in future messages on that stream. it is guaranteed to be distinct | ||||||
| and the other process then becomes the window's owner. | 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: | data types: | ||||||
| 
 | 
 | ||||||
|  | @ -14,28 +18,27 @@ data types: | ||||||
|   color rectangle: |   color rectangle: | ||||||
|     multiple hilbert colors, top to bottom by row, left to right within row |     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: | messages from applications to compositor: | ||||||
| 
 | 
 | ||||||
|   show window: |   open window: | ||||||
|     byte: 0x00 |     byte: 0x00 | ||||||
| 
 |     dword: window width | ||||||
|   hide window: |     dword: window height | ||||||
|     byte: 0x01 |  | ||||||
| 
 |  | ||||||
|   set window dimensions: |  | ||||||
|     byte: 0x02 |  | ||||||
|     dword: width |  | ||||||
|     dword: height |  | ||||||
| 
 |  | ||||||
|   set window title: |  | ||||||
|     byte: 0x03 |  | ||||||
|     dword: length in bytes |  | ||||||
|     bytes: title |  | ||||||
| 
 | 
 | ||||||
|   update window region: |   update window region: | ||||||
|     byte: 0x04 |     byte: 0x01 | ||||||
|  |     window: the window | ||||||
|     dword: start x |     dword: start x | ||||||
|     dword: start y |     dword: start y | ||||||
|     dword: width |     dword: width | ||||||
|     dword: height |     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. | interrupts (including the timer!) are disabled during system calls. | ||||||
| 
 | 
 | ||||||
| a "mibisecond" is a 1024th of a second |  | ||||||
| 
 |  | ||||||
| stream result: | stream result: | ||||||
|    0 = success |    0 = success | ||||||
|    1 = bad handle |    1 = bad handle | ||||||
|  | @ -157,10 +155,7 @@ start process: | ||||||
|     qword: stream handle here |     qword: stream handle here | ||||||
|     qword: new stream handle in child |     qword: new stream handle in child | ||||||
|       new handle must be < 65536 |       new handle must be < 65536 | ||||||
|   any gifted streams must not have threads waiting to read from our end. |   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. |  | ||||||
| 
 | 
 | ||||||
| end this process: | end this process: | ||||||
|   rax in: 17 |   rax in: 17 | ||||||
|  | @ -203,16 +198,3 @@ get environment variable value: | ||||||
|   rdi in: pointer to variable name |   rdi in: pointer to variable name | ||||||
|   rsi in: variable name length |   rsi in: variable name length | ||||||
|   rdx in: pointer to buffer for variable value |   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 | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <std/fwd/string.hpp> |  | ||||||
| #include <std/fwd/vector.hpp> |  | ||||||
| #include <optional> | #include <optional> | ||||||
| #include <cstdint> | #include <cstdint> | ||||||
| #include <utility> | #include <utility> | ||||||
| #include <variant> | #include <variant> | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
| 
 | 
 | ||||||
| namespace euler::syscall { | namespace euler::syscall { | ||||||
| 
 | 
 | ||||||
|  | @ -124,30 +124,6 @@ namespace euler::syscall { | ||||||
|   //entry_point must not return
 |   //entry_point must not return
 | ||||||
|   void start_thread(void (*entry_point)(uint64_t), uint64_t arg); |   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
 |   //entry_point must not return
 | ||||||
|   void start_thread(void (*entry_point)()); |   void start_thread(void (*entry_point)()); | ||||||
| 
 | 
 | ||||||
|  | @ -157,14 +133,4 @@ namespace euler::syscall { | ||||||
|   std::optional<std::string> try_get_environment_variable( |   std::optional<std::string> try_get_environment_variable( | ||||||
|     const std::string &name); |     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 | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <std/fwd/allocator.hpp> |  | ||||||
| 
 |  | ||||||
| #include <euler/heap.hpp> | #include <euler/heap.hpp> | ||||||
| 
 | 
 | ||||||
| namespace std { | 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 | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <std/fwd/string.hpp> |  | ||||||
| 
 |  | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
|  | @ -12,15 +10,15 @@ namespace std { | ||||||
|     std::vector<char> characters; |     std::vector<char> characters; | ||||||
| 
 | 
 | ||||||
|   public: |   public: | ||||||
|     static const size_t npos = (size_t)-1; |  | ||||||
| 
 |  | ||||||
|     constexpr string() : characters({'\0'}) {} |     constexpr string() : characters({'\0'}) {} | ||||||
| 
 | 
 | ||||||
|     constexpr string(const string &other) |     constexpr string(const string &other) | ||||||
|     : characters(other.characters) {} |     : characters(other.characters) {} | ||||||
| 
 | 
 | ||||||
|     constexpr string(string &&other) noexcept |     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) { |     constexpr string(const char *s) { | ||||||
|       size_t count = 0; |       size_t count = 0; | ||||||
|  | @ -40,6 +38,7 @@ namespace std { | ||||||
| 
 | 
 | ||||||
|     constexpr string &operator =(string &&str) noexcept { |     constexpr string &operator =(string &&str) noexcept { | ||||||
|       characters = std::move(str.characters); |       characters = std::move(str.characters); | ||||||
|  |       str.characters.push_back('\0'); | ||||||
|       return *this; |       return *this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -76,14 +75,6 @@ namespace std { | ||||||
|       return characters[pos]; |       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 | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <std/fwd/vector.hpp> |  | ||||||
| 
 |  | ||||||
| #include <memory> | #include <memory> | ||||||
| 
 | 
 | ||||||
| namespace std { | namespace std { | ||||||
| 
 | 
 | ||||||
|   template <class T, class Allocator> |   template <class T, class Allocator = std::allocator<T>> | ||||||
|   class vector { |   class vector { | ||||||
| 
 | 
 | ||||||
|   public: |   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 { |     constexpr size_type size() const noexcept { | ||||||
|       return _size; |       return _size; | ||||||
|     } |     } | ||||||
|  | @ -194,18 +186,6 @@ namespace std { | ||||||
|       ++_size; |       ++_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 <cstdlib> | ||||||
| #include <string> | #include <string> | ||||||
| 
 | 
 | ||||||
| int main(); | int main(int argc, char **argv); | ||||||
| 
 | 
 | ||||||
| extern "C" [[noreturn]] void _start() { | 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); |   euler::syscall::end_this_process(exit_code); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| #include <cstdio> | #include <cstdio> | ||||||
| #include <string> |  | ||||||
| 
 | 
 | ||||||
| extern "C" FILE *fopen(const char *filename, const char *mode) { | 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; |         value = value * base + c - 'A' + 10; | ||||||
|       else |       else | ||||||
|         break; |         break; | ||||||
|       ++i; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (pos != 0) |     if (pos != 0) | ||||||
|  | @ -76,11 +75,10 @@ namespace std { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   std::string operator +(std::string &&lhs, std::string &&rhs) { |   std::string operator +(std::string &&lhs, std::string &&rhs) { | ||||||
|     size_t og_lhs_s = lhs.size(); |  | ||||||
|     std::string s = std::move(lhs); |     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) |     for (size_t i = 0; i < rhs.size(); ++i) | ||||||
|       s[og_lhs_s + i] = rhs[i]; |       s[lhs.size() + i] = rhs[i]; | ||||||
|     rhs.clear(); |     rhs.clear(); | ||||||
|     return s; |     return s; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| #include <euler/stream.hpp> | #include <euler/stream.hpp> | ||||||
| #include <algorithm> |  | ||||||
| #include <cstring> | #include <cstring> | ||||||
| 
 | 
 | ||||||
| namespace euler { | namespace euler { | ||||||
|  |  | ||||||
|  | @ -1,6 +1,4 @@ | ||||||
| #include <euler/syscall.hpp> | #include <euler/syscall.hpp> | ||||||
| #include <string> |  | ||||||
| #include <vector> |  | ||||||
| 
 | 
 | ||||||
| extern "C" void __euler_do_syscall( | extern "C" void __euler_do_syscall( | ||||||
|   uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx); |   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<generic_stream_ptr> open_streams; | ||||||
|     utility::id_allocator<socket_listener *> running_socket_listeners; |     utility::id_allocator<socket_listener *> running_socket_listeners; | ||||||
| 
 | 
 | ||||||
|   public: |  | ||||||
|     struct string_pair { |     struct string_pair { | ||||||
|       utility::string a; |       utility::string a; | ||||||
|       utility::string b; |       utility::string b; | ||||||
|  | @ -112,12 +111,7 @@ namespace hilbert::kernel::application { | ||||||
| 
 | 
 | ||||||
|     utility::list<string_pair> environment_variables; |     utility::list<string_pair> environment_variables; | ||||||
| 
 | 
 | ||||||
|   private: |  | ||||||
|     string_pair *find_environment_variable(const utility::string &name); |  | ||||||
| 
 |  | ||||||
|   public: |   public: | ||||||
|     utility::string name; |  | ||||||
| 
 |  | ||||||
|     app_memory *memory; |     app_memory *memory; | ||||||
| 
 | 
 | ||||||
|     //set in get_framebuffer syscall
 |     //set in get_framebuffer syscall
 | ||||||
|  | @ -127,18 +121,13 @@ namespace hilbert::kernel::application { | ||||||
|     uint64_t id; |     uint64_t id; | ||||||
| 
 | 
 | ||||||
|     //this class takes ownership of memory
 |     //this class takes ownership of memory
 | ||||||
|     process(app_memory *memory, const utility::string &name); |     process(app_memory *memory); | ||||||
|     ~process(); |     ~process(); | ||||||
| 
 | 
 | ||||||
|     void set_environment_variable( |     //arguments are utility::move'd
 | ||||||
|  |     void add_environment_variable( | ||||||
|       utility::string &&name, utility::string &&value); |       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 add_thread(thread *t); | ||||||
|     void notify_thread_ended(thread *t, int exit_code); |     void notify_thread_ended(thread *t, int exit_code); | ||||||
|     void on_end_process(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; |     utility::maybe<unsigned> new_socket_stream_id; | ||||||
| 
 | 
 | ||||||
|   public: |   public: | ||||||
|     utility::string name; |  | ||||||
| 
 |  | ||||||
|     process *owner; |     process *owner; | ||||||
| 
 | 
 | ||||||
|     //the cpu state is saved here when the thread is not running.
 |     //the cpu state is saved here when the thread is not running.
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <hilbert/kernel/utility.hpp> |  | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| 
 | 
 | ||||||
| namespace hilbert::kernel { | 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> |   template <int digits, int dot_every = 4> | ||||||
|   static inline void serial_puthex(uint64_t n) { |   static inline void serial_puthex(uint64_t n) { | ||||||
|     for (int d = digits - 1; d >= 0; --d) { |     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->value = value; | ||||||
|       n->next = 0; |       n->next = 0; | ||||||
|       n->prev = last; |       n->prev = last; | ||||||
|       if (last) |  | ||||||
|         last->next = n; |  | ||||||
|       else |  | ||||||
|         first = n; |  | ||||||
|       last = n; |       last = n; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -119,38 +115,12 @@ namespace hilbert::kernel::utility { | ||||||
|       n->value = value; |       n->value = value; | ||||||
|       n->next = 0; |       n->next = 0; | ||||||
|       n->prev = last; |       n->prev = last; | ||||||
|       if (last) |  | ||||||
|         last->next = n; |  | ||||||
|       else |  | ||||||
|         first = n; |  | ||||||
|       last = 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() { |     void clear() { | ||||||
|       if (first) { |       for (node *n = first; n; n = n->next) | ||||||
|         for (node *n = first->next; n; n = n->next) |         delete n; | ||||||
|           delete n->prev; |  | ||||||
|         delete last; |  | ||||||
|       } |  | ||||||
|       first = 0; |       first = 0; | ||||||
|       last = 0; |       last = 0; | ||||||
|     } |     } | ||||||
|  | @ -212,12 +182,7 @@ namespace hilbert::kernel::utility { | ||||||
|         buffer[i] = other.buffer[i]; |         buffer[i] = other.buffer[i]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     vector(vector &&other) |     vector(vector &&other) = delete; | ||||||
|       : buffer(other.buffer), |  | ||||||
|         buffer_len(other.buffer_len), |  | ||||||
|         count(other.count) { |  | ||||||
|       other.buffer = 0; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     ~vector() { |     ~vector() { | ||||||
|       if (buffer) |       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); |     resume_thread(t->saved_state); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   process::process(app_memory *memory, const utility::string &name) |   process::process(app_memory *memory) : memory(memory) {} | ||||||
|   : name(name), memory(memory) {} |  | ||||||
| 
 | 
 | ||||||
|   process::~process() { |   process::~process() { | ||||||
|     delete memory; //:p
 |     delete memory; //:p
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   process::string_pair *process::find_environment_variable( |   void process::add_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( |  | ||||||
|     utility::string &&name, utility::string &&value) { |     utility::string &&name, utility::string &&value) { | ||||||
| 
 |     environment_variables.insert_end({.a = name, .b = 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; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void process::add_thread(thread *t) { |   void process::add_thread(thread *t) { | ||||||
|  | @ -239,8 +197,8 @@ namespace hilbert::kernel::application { | ||||||
| 
 | 
 | ||||||
|   thread::thread(process *owner, uint64_t entry) |   thread::thread(process *owner, uint64_t entry) | ||||||
|   : stack_top(owner->memory->map_new_stack()), waiting_for_socket_stream(0), |   : 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), |     waiting_to_accept_from(0), waiting_to_connect_to(0), | ||||||
|     name(utility::string("main", 4)), owner(owner) { |     waiting_for_input(false), owner(owner) { | ||||||
| 
 | 
 | ||||||
|     saved_state.rax = 0; |     saved_state.rax = 0; | ||||||
|     saved_state.rbx = 0; |     saved_state.rbx = 0; | ||||||
|  |  | ||||||
|  | @ -7,7 +7,6 @@ | ||||||
| #include <hilbert/kernel/serial.hpp> | #include <hilbert/kernel/serial.hpp> | ||||||
| #include <hilbert/kernel/input.hpp> | #include <hilbert/kernel/input.hpp> | ||||||
| #include <hilbert/kernel/panic.hpp> | #include <hilbert/kernel/panic.hpp> | ||||||
| #include <hilbert/kernel/timer.hpp> |  | ||||||
| #include <hilbert/kernel/vfile.hpp> | #include <hilbert/kernel/vfile.hpp> | ||||||
| #include <limine.h> | #include <limine.h> | ||||||
| 
 | 
 | ||||||
|  | @ -180,7 +179,6 @@ extern "C" [[noreturn]] void entry() { | ||||||
|   if (!have_initfs) |   if (!have_initfs) | ||||||
|     panic(0x5f8860); |     panic(0x5f8860); | ||||||
| 
 | 
 | ||||||
|   timer::init_timer(); |  | ||||||
|   input::init_input(); |   input::init_input(); | ||||||
|   application::init_applications(); |   application::init_applications(); | ||||||
| 
 | 
 | ||||||
|  | @ -216,8 +214,11 @@ extern "C" [[noreturn]] void entry() { | ||||||
|   if (load_init_result != load_app_result::success) |   if (load_init_result != load_app_result::success) | ||||||
|     panic(0xc39db3); |     panic(0xc39db3); | ||||||
| 
 | 
 | ||||||
|   application::process *init_process = |   application::process *init_process = new application::process(init_memory); | ||||||
|     new application::process(init_memory, utility::string("init", 4)); |   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::add_process(init_process); | ||||||
| 
 | 
 | ||||||
|   application::thread *init_thread = |   application::thread *init_thread = | ||||||
|  |  | ||||||
|  | @ -267,22 +267,6 @@ isr_end: | ||||||
| 
 | 
 | ||||||
|   ret |   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 | extern on_keyboard_interrupt | ||||||
| 
 | 
 | ||||||
| keyboard_isr: | keyboard_isr: | ||||||
|  | @ -359,7 +343,7 @@ load_gdt_and_idt: | ||||||
|   out 0x21, al |   out 0x21, al | ||||||
|   mov al, 0x01 |   mov al, 0x01 | ||||||
|   out 0x21, al |   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 |   out 0x21, al | ||||||
| 
 | 
 | ||||||
|   mov al, 0x11 |   mov al, 0x11 | ||||||
|  | @ -370,15 +354,9 @@ load_gdt_and_idt: | ||||||
|   out 0xa1, al |   out 0xa1, al | ||||||
|   mov al, 0x01 |   mov al, 0x01 | ||||||
|   out 0xa1, al |   out 0xa1, al | ||||||
|   mov al, 0xee ;mask all but irqs 8 and 12 |   mov al, 0xef ;mask all but irq 12 | ||||||
|   out 0xa1, al |   out 0xa1, al | ||||||
| 
 | 
 | ||||||
|   ;register rtc interrupt |  | ||||||
| 
 |  | ||||||
|   mov rdi, 0x28 |  | ||||||
|   mov rsi, rtc_isr |  | ||||||
|   call set_isr |  | ||||||
| 
 |  | ||||||
|   ;register keyboard and mouse interrupts |   ;register keyboard and mouse interrupts | ||||||
| 
 | 
 | ||||||
|   mov rdi, 0x21 |   mov rdi, 0x21 | ||||||
|  |  | ||||||
|  | @ -79,11 +79,6 @@ extern "C" [[noreturn]] void print_exception() { | ||||||
|   print_reg("r14", exception_info.r14); |   print_reg("r14", exception_info.r14); | ||||||
|   print_reg("r15", exception_info.r15); |   print_reg("r15", exception_info.r15); | ||||||
| 
 | 
 | ||||||
|   if (application::running_thread != 0) { |  | ||||||
|     serial_putstr("running app = "); |  | ||||||
|     serial_putstr(application::running_thread->owner->name); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   panic(0xba40bb); |   panic(0xba40bb); | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,7 +4,6 @@ | ||||||
| #include <hilbert/kernel/paging.hpp> | #include <hilbert/kernel/paging.hpp> | ||||||
| #include <hilbert/kernel/input.hpp> | #include <hilbert/kernel/input.hpp> | ||||||
| #include <hilbert/kernel/panic.hpp> | #include <hilbert/kernel/panic.hpp> | ||||||
| #include <hilbert/kernel/timer.hpp> |  | ||||||
| #include <hilbert/kernel/vfile.hpp> | #include <hilbert/kernel/vfile.hpp> | ||||||
| 
 | 
 | ||||||
| namespace hilbert::kernel::syscall { | namespace hilbert::kernel::syscall { | ||||||
|  | @ -184,7 +183,7 @@ namespace hilbert::kernel::syscall { | ||||||
|       .waiting_to_read = utility::queue<application::thread *>(), |       .waiting_to_read = utility::queue<application::thread *>(), | ||||||
|       .is_other_side_open = true, .other_process = p2, .other_end = 0 }; |       .is_other_side_open = true, .other_process = p2, .other_end = 0 }; | ||||||
|     se2_out = new application::socket_stream_end { |     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 *>(), |       .waiting_to_read = utility::queue<application::thread *>(), | ||||||
|       .is_other_side_open = true, .other_process = p1, .other_end = se1_out }; |       .is_other_side_open = true, .other_process = p1, .other_end = se1_out }; | ||||||
|     se1_out->other_end = se2_out; |     se1_out->other_end = se2_out; | ||||||
|  | @ -495,12 +494,8 @@ namespace hilbert::kernel::syscall { | ||||||
|         rax = (uint64_t)application::stream_result::other_end_closed; |         rax = (uint64_t)application::stream_result::other_end_closed; | ||||||
|         return; |         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]); |         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; |       rax = (uint64_t)application::stream_result::success; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -622,14 +617,10 @@ namespace hilbert::kernel::syscall { | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     application::process *p = |     application::process *p = new application::process(memory); | ||||||
|       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); |  | ||||||
| 
 | 
 | ||||||
|     for (uint64_t i = 0; i < psi->env_var_count; ++i) |     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].name, psi->env_vars[i].name_len), | ||||||
|         utility::string(psi->env_vars[i].value, psi->env_vars[i].value_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[])( |   void (*handlers[])( | ||||||
|     uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) = { |     uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) = { | ||||||
| 
 | 
 | ||||||
|  | @ -851,16 +759,11 @@ namespace hilbert::kernel::syscall { | ||||||
|     &set_stream_length_syscall, |     &set_stream_length_syscall, | ||||||
|     &get_other_end_process_handle_syscall, |     &get_other_end_process_handle_syscall, | ||||||
|     &start_thread_syscall, |     &start_thread_syscall, | ||||||
|     &clear_socket_read_queue_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 |  | ||||||
| 
 | 
 | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   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(); |     ~image(); | ||||||
| 
 | 
 | ||||||
|     void fill(const color_t &color); |     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
 |     //does not check bounds
 | ||||||
|     color_t &at(int x, int y); |     color_t &at(int x, int y); | ||||||
|  | @ -110,13 +108,6 @@ namespace daguerre { | ||||||
|       param_converter_t<color_t, font_color_t, param_t> *conversion = |       param_converter_t<color_t, font_color_t, param_t> *conversion = | ||||||
|         &default_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> |   template <class color_t> | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ namespace daguerre { | ||||||
|   template <class color_t> |   template <class color_t> | ||||||
|   fixed_font<color_t>::fixed_font(fixed_font<color_t> &&other) |   fixed_font<color_t>::fixed_font(fixed_font<color_t> &&other) | ||||||
|     : glyph_width(other.glyph_width), glyph_height(other.glyph_height) { |     : 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]); |         glyphs[i] = std::move(other.glyphs[i]); | ||||||
|       other.glyph_width = 0; |       other.glyph_width = 0; | ||||||
|       other.glyph_height = 0; |       other.glyph_height = 0; | ||||||
|  | @ -31,11 +31,10 @@ namespace daguerre { | ||||||
|     fixed_font<color_t> &&other) { |     fixed_font<color_t> &&other) { | ||||||
|     glyph_width = other.glyph_width; |     glyph_width = other.glyph_width; | ||||||
|     glyph_height = other.glyph_height; |     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]); |       glyphs[i] = std::move(other.glyphs[i]); | ||||||
|     other.glyph_width = 0; |     other.glyph_width = 0; | ||||||
|     other.glyph_height = 0; |     other.glyph_height = 0; | ||||||
|     return *this; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   template <class color_t> |   template <class color_t> | ||||||
|  |  | ||||||
|  | @ -103,14 +103,6 @@ namespace daguerre { | ||||||
|         buffer[y * buffer_pitch + x] = color; |         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> |   template <class color_t> | ||||||
|   color_t &image<color_t>::at(int x, int y) { |   color_t &image<color_t>::at(int x, int y) { | ||||||
|     return buffer[y * buffer_pitch + x]; |     return buffer[y * buffer_pitch + x]; | ||||||
|  | @ -170,7 +162,7 @@ namespace daguerre { | ||||||
|   void image<color_t>::convert_from( |   void image<color_t>::convert_from( | ||||||
|     const image<other_color_t> &other, int to_x, int to_y, |     const image<other_color_t> &other, int to_x, int to_y, | ||||||
|     converter_t<color_t, other_color_t> *conversion) { |     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> |   template <class color_t> | ||||||
|  | @ -193,7 +185,7 @@ namespace daguerre { | ||||||
|     const param_t ¶m, const image<other_color_t> &other, int to_x, |     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) { |     int to_y, param_converter_t<color_t, other_color_t, param_t> *conversion) { | ||||||
|     convert_from( |     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> |   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> |   template <class color_t> | ||||||
|   void swap(image<color_t> &a, image<color_t> &b) { |   void swap(image<color_t> &a, image<color_t> &b) { | ||||||
|     std::swap(a.delete_buffer_on_destruct, b.delete_buffer_on_destruct); |     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 | default: build/disk.iso | ||||||
| 
 | 
 | ||||||
| # command and arguments that you should be careful about changing
 | run: build/disk.iso | ||||||
|  | 	gdb -x qemu.gdb | ||||||
| 
 | 
 | ||||||
| NASM = nasm | clean: | ||||||
| CC = toolchain/usr/bin/x86_64-elf-c++ | 	rm -rf build ${EULER_DEP} ${DAGUERRE_DEP} | ||||||
| AR = toolchain/usr/bin/x86_64-elf-ar | 	make -C euler clean | ||||||
| LD = toolchain/usr/bin/x86_64-elf-ld | 	make -C kernel clean | ||||||
|  | 	make -C applications/init clean | ||||||
|  | 	make -C applications/goldman clean | ||||||
|  | 	make -C libraries/daguerre clean | ||||||
| 
 | 
 | ||||||
| KERNEL_INCLUDES = \
 | clean-dependencies: clean | ||||||
|   dependencies/limine \
 | 	rm -rf toolchain dependencies | ||||||
|   dependencies/mintsuki-headers \
 |  | ||||||
|   kernel/include |  | ||||||
| 
 | 
 | ||||||
| USER_INCLUDES = \
 | ${LIMINE_DEP}: | ||||||
|   dependencies/mintsuki-headers \
 | 	mkdir -p dependencies | ||||||
|   euler/include \
 | 	test -e dependencies/limine || git clone --depth 1 -b v7.5.1 https://github.com/limine-bootloader/limine dependencies/limine | ||||||
|   $(wildcard libraries/*/include) | 	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} | ${BINUTILS_DEP}: | ||||||
| CC_ARGS_KERNEL = \
 | 	mkdir -p dependencies toolchain/usr | ||||||
|   ${CC_ARGS_COMMON} -ffreestanding -fno-exceptions \
 | 	test -e dependencies/binutils || git clone --depth 1 -b binutils-2_42 https://sourceware.org/git/binutils-gdb dependencies/binutils | ||||||
|   -fno-rtti -mcmodel=kernel ${KERNEL_INCLUDES:%=-I%} | 	mkdir -p dependencies/binutils/build | ||||||
| CC_ARGS_USER = ${CC_ARGS_COMMON} ${USER_INCLUDES:%=-I%} | 	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 | ${DAGUERRE_DEP}: ${LIBRARY_DEPS} | ||||||
| 	@mkdir -p ${@D} | 	+make -C libraries/daguerre build/libdaguerre.a | ||||||
| 	${NASM} ${NASM_ARGS} $^ -o $@ | 	cp libraries/daguerre/build/libdaguerre.a ${LIB_DIR}/ | ||||||
|  | 	touch $@ | ||||||
| 
 | 
 | ||||||
| build/kernel/%.cpp.o: kernel/%.cpp | kernel/build/kernel.elf: ${GCC_DEP} ${MINTSUKI_HEADERS_DEP} ${LIMINE_DEP} | ||||||
| 	@mkdir -p ${@D} | 	+make -C kernel build/kernel.elf | ||||||
| 	${CC} -c ${CC_ARGS_KERNEL} $^ -o $@ |  | ||||||
| 
 | 
 | ||||||
| KERNEL_SOURCES = $(shell find kernel/source ${SOURCES_FIND}) | applications/init/build/init.elf: ${APP_DEPS} | ||||||
| build/kernel.elf: ${KERNEL_SOURCES:%=build/%.o} | 	+make -C applications/init build/init.elf | ||||||
| 	${LD} ${LD_ARGS} -T kernel/link.ld $^ -o $@ |  | ||||||
| 
 | 
 | ||||||
| # euler section
 | applications/goldman/build/goldman.elf: ${APP_DEPS} ${DAGUERRE_DEP} | ||||||
|  | 	+make -C applications/goldman build/goldman.elf | ||||||
| 
 | 
 | ||||||
| build/euler/%.asm.o: euler/%.asm | build/initfs.tgz: applications/init/build/init.elf \ | ||||||
| 	@mkdir -p ${@D} |                   applications/goldman/build/goldman.elf | ||||||
| 	${NASM} ${NASM_ARGS} $^ -o $@ | 	@mkdir -p build | ||||||
| 
 |  | ||||||
| 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} |  | ||||||
| 	rm -rf build/initfs | 	rm -rf build/initfs | ||||||
| 	cp -r skeleton 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 . | 	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 | 	rm -rf build/iso | ||||||
| 	mkdir build/iso | 	mkdir build/iso | ||||||
| 	cp dependencies/limine/bin/limine-bios.sys dependencies/limine/bin/limine-bios-cd.bin \
 | 	cp kernel/build/kernel.elf ${LIMINE_DIR}/bin/limine-bios.sys \
 | ||||||
| 	  build/kernel.elf build/initfs.tgz build/iso/ | 	  ${LIMINE_DIR}/bin/limine-bios-cd.bin build/initfs.tgz build/iso/ | ||||||
| 	echo 'TIMEOUT=0' > build/iso/limine.cfg | 	echo 'TIMEOUT=0' > build/iso/limine.cfg | ||||||
| 	echo ':Hilbert OS' >> build/iso/limine.cfg | 	echo ':Hilbert OS' >> build/iso/limine.cfg | ||||||
| 	echo 'PROTOCOL=limine' >> 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 | 	echo 'MODULE_CMDLINE=initfs' >> build/iso/limine.cfg | ||||||
| 	xorriso -as mkisofs -b limine-bios-cd.bin -no-emul-boot -boot-load-size 4 \
 | 	xorriso -as mkisofs -b limine-bios-cd.bin -no-emul-boot -boot-load-size 4 \
 | ||||||
| 	  -boot-info-table --protective-msdos-label build/iso -o $@ | 	  -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 | 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 disassembly-flavor intel | ||||||
| set print asm-demangle on | set print asm-demangle on | ||||||
| layout src | 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 | 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 | 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 |   [1] apt install bison flex g++ gdb git libgmp-dev libmpfr-dev libmpc-dev make nasm qemu-system-x86 texinfo xorriso | ||||||
|   - flex |   [2] make -j$(nproc) | ||||||
|   - g++ |   [3] make run | ||||||
|   - 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. |  | ||||||
| 
 | 
 | ||||||
| acknowledgements (any under "dependencies" are downloaded during build): | 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 |       license: https://unsplash.com/license | ||||||
|       source: https://unsplash.com/photos/selective-focus-photography-snowflakes-9yhy1FXlKwI |       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 |       copyright 2020 dimitar toshkov zhekov | ||||||
|       license: skeleton/assets/terminus-ofl.txt (sil open font license v1.1) |       license: skeleton/assets/terminus-ofl.txt (sil open font license v1.1) | ||||||
|       homepage: https://terminus-font.sourceforge.net/ |       homepage: https://terminus-font.sourceforge.net/ | ||||||
|  | @ -77,12 +58,6 @@ license in isc.txt (isc license): | ||||||
|   - libraries |   - libraries | ||||||
|   - makefile |   - 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 | the following directories and files are released under the text in cc0.txt | ||||||
| (creative commons cc0 1.0 universal public domain dedication): | (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: | project structure: | ||||||
| 
 | 
 | ||||||
|   - applications/clock: |  | ||||||
|       a simple application that displays the current time in EDT. |  | ||||||
| 
 |  | ||||||
|   - applications/goldman: |   - applications/goldman: | ||||||
|       the default compositor. |       in the future, this will be the default compositor. | ||||||
| 
 | 
 | ||||||
|   - applications/init: |   - applications/init: | ||||||
|       the initial program loaded by the kernel. currently it just starts the |       the initial program loaded by the kernel. currently it just | ||||||
|       compositor and the clock, but in the future it will read some kind of |       (attempts to) start /bin/compositor and then /bin/hello. | ||||||
|       configuration file and decide what to do based on that. |  | ||||||
| 
 | 
 | ||||||
|   - documentation: |   - documentation: | ||||||
|       documentation. currently this directory is a bit disorganized, and has |       documentation. currently this directory is a bit disorganized, and has | ||||||
|  | @ -116,9 +87,6 @@ project structure: | ||||||
|   - libraries/daguerre: |   - libraries/daguerre: | ||||||
|       an image loading / rendering library. |       an image loading / rendering library. | ||||||
| 
 | 
 | ||||||
|   - libraries/pake: |  | ||||||
|       a widget library for windowed applications |  | ||||||
| 
 |  | ||||||
|   - patches: |   - patches: | ||||||
|       a couple patches that are applied to dependencies |       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 | the icon in pointer.ppm is released under the cc0 1.0 universal public | ||||||
| domain dedication (https://creativecommons.org/publicdomain/zero/1.0/). | 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