From 1367197aad39424a4f3635d9e15a7128f5d1d175 Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Fri, 26 Jan 2024 15:46:22 +0100 Subject: [PATCH 01/23] krealloc and prep for terminal editor --- include/memory.h | 1 + kernel/edit.c | 36 + kernel/memory.c | 99 +-- rootfs/symbols.map | 1754 ++++++++++++++++++++++---------------------- 4 files changed, 969 insertions(+), 921 deletions(-) create mode 100644 kernel/edit.c diff --git a/include/memory.h b/include/memory.h index 86074dd..bc5ce4f 100644 --- a/include/memory.h +++ b/include/memory.h @@ -114,6 +114,7 @@ void vmem_init(); /* Kernel memory*/ void* kalloc(int size); void* kcalloc(int size); +void* krealloc(void* ptr, int new_size); void kfree(void* ptr); int kmemory_used(); int kmemory_total(); diff --git a/kernel/edit.c b/kernel/edit.c new file mode 100644 index 0000000..3dd21f1 --- /dev/null +++ b/kernel/edit.c @@ -0,0 +1,36 @@ +#include +#include +#include + +#define MAX_LINES 512 + +struct line { + char *text; + size_t length; + size_t capacity; +}; + +struct textbuffer { + struct line **lines; + size_t line_count; +}; + +static struct textbuffer *textbuffer_create(void) +{ + struct textbuffer *buffer = create(struct textbuffer); + buffer->lines = malloc(sizeof(struct line*) * MAX_LINES); + buffer->line_count = 0; + return buffer; +} + +static void textbuffer_destroy(struct textbuffer *buffer) +{ + for (size_t i = 0; i < buffer->line_count; i++) { + if (buffer->lines[i]->text) { + free(buffer->lines[i]->text); + } + free(buffer->lines[i]); + } + free(buffer->lines); + free(buffer); +} diff --git a/kernel/memory.c b/kernel/memory.c index 3ce45bb..1613772 100644 --- a/kernel/memory.c +++ b/kernel/memory.c @@ -21,6 +21,31 @@ #define KB(kb) (kb*1024) static struct memory_map kernel_memory_map = {0}; +static int memory_test(){ + for (int i = 0; i < (15 * 1024*1024)+(1*1024*1024); i++){ + volatile char value = *(volatile char *)i; + *(volatile char *)i = value; + + if (i % (1024*1024) == 0){ + dbgprintf("[KERNEL] 0x%x MB tested\n", i); + } + } + return 0; +} + +error_t get_mem_info(struct mem_info* info) +{ + *info = (struct mem_info) { + .kernel.total = memory_map_get()->kernel.total, + .kernel.used = kmemory_used(), + .permanent.total = memory_map_get()->permanent.total, + .permanent.used = pmemory_used(), + .virtual_memory.total = memory_map_get()->virtual_memory.total, + .virtual_memory.used = vmem_total_usage(), + }; + return 0; +} + int memory_map_init(int total_memory, int extended_memory) { @@ -34,47 +59,31 @@ int memory_map_init(int total_memory, int extended_memory) int remaining_memory = total_memory - permanent - kernel; int virtual = ALIGN_DOWN(remaining_memory, 4096); - /* Ensure the total of aligned segments does not exceed total_memory */ if (permanent + kernel + virtual > total_memory) { - /* Adjust virtual to fit within the total_memory */ virtual = total_memory - permanent - kernel; - /* Re-align after adjustment */ virtual = ALIGN_DOWN(virtual, 4096); } - struct memory_map map = { - .kernel.from = start, - .kernel.to = start + kernel, - .kernel.total = kernel, + kernel_memory_map = (struct memory_map) { + .kernel.from = start, + .kernel.to = start + kernel, + .kernel.total = kernel, - .permanent.from = start + kernel, - .permanent.to = start + kernel + permanent, - .permanent.total = permanent, + .permanent.from = start + kernel, + .permanent.to = start + kernel + permanent, + .permanent.total = permanent, - .virtual_memory.from = start + kernel + permanent, + .virtual_memory.from = start + kernel + permanent, .virtual_memory.to = start + kernel + permanent + virtual, - .virtual_memory.total = virtual, + .virtual_memory.total = virtual, - .total = permanent+kernel+virtual, - .initialized = true + .total = permanent+kernel+virtual, + .initialized = true }; - kernel_memory_map = map; return 0; } -static int memory_test(){ - for (int i = 0; i < (15 * 1024*1024)+(1*1024*1024); i++){ - volatile char value = *(volatile char *)i; - *(volatile char *)i = value; - - if (i % (1024*1024) == 0){ - dbgprintf("[KERNEL] 0x%x MB tested\n", i); - } - } - return 0; -} - struct memory_map* memory_map_get() { return &kernel_memory_map; @@ -95,14 +104,11 @@ void kfree(void* ptr); */ void free(void* ptr) { - dbgprintf("Freeing %x\n", ptr); if(ptr == NULL)return; /* lock on free as multiple threads can free at the same time */ - spin_lock(&$process->current->allocations->spinlock); - + spin_lock(&$process->current->allocations->spinlock); vmem_stack_free($process->current, ptr); - spin_unlock(&$process->current->allocations->spinlock); } @@ -123,8 +129,6 @@ void* malloc(unsigned int size) return NULL; } - //vmem_dump_heap($process->current->allocations->head); - dbgprintf("Allocated %d bytes at %x\n", size, ptr); spin_unlock(&$process->current->allocations->spinlock); @@ -140,19 +144,26 @@ void* calloc(int size, int val) return m; } -error_t get_mem_info(struct mem_info* info) +void* krealloc(void* ptr, int new_size) { - struct mem_info inf = { - .kernel.total = memory_map_get()->kernel.total, - .kernel.used = kmemory_used(), - .permanent.total = memory_map_get()->permanent.total, - .permanent.used = pmemory_used(), - .virtual_memory.total = memory_map_get()->virtual_memory.total, - .virtual_memory.used = vmem_total_usage(), - }; + if (new_size == 0) { + kfree(ptr); + return NULL; + } - *info = inf; - return 0; + if (ptr == NULL) { + return kalloc(new_size); + } + + void *new_ptr = kalloc(new_size); + if (new_ptr == NULL) { + return NULL; + } + + memcpy(new_ptr, ptr, new_size); + + kfree(ptr); + return new_ptr; } /** diff --git a/rootfs/symbols.map b/rootfs/symbols.map index eeaaee5..4419425 100644 --- a/rootfs/symbols.map +++ b/rootfs/symbols.map @@ -8,880 +8,880 @@ 00010058 gdt_end 00010058 kernel_boot_printf 000100b7 init_kctors -00010109 kernel -000105a7 kernel_get_context -000105b1 hexdump -00010801 __terminal_set_ops -000108ce __terminal_scanf -000108d8 __terminal_write -00010926 __terminal_getchar_graphics -00010973 __terminal_scan_graphics -00010a55 __terminal_reset -00010a9d __terminal_detach -00010ae4 __terminal_attach -00010b33 __terminal_remove_line -00010b73 __terminal_putchar_graphics -00010c40 __terminal_writef -00010f4f __terminal_getchar_textmode -00010f7b __terminal_scan_textmode -00011043 __terminal_commit_textmode -000110ff __terminal_putchar_textmode -0001114f scan -0001118c terminal_set_color -000111a8 __terminal_commit_graphics -00011309 terminal_attach -0001132e terminal_commit -00011351 terminal_putchar -00011387 terminal_create -000114b0 terminal_destroy -000114ec tlb_flush_addr -000114f4 load_page_directory -00011504 enable_paging -00011516 pcb_save_context -00011542 pcb_restore_context -0001156b _start_pcb -0001159d _start_pcb_skip -000115b8 __ksymbol_lspci -000115d6 pci_get_class_name -000115ed pci_get_device_name -00011662 pci_get_vendor_name -000116b4 lspci -00011805 pci_get_devices -0001180f pci_read_word -0001186c pci_write_dword -000118bf pci_enable_device_busmaster -00011918 pci_register_device -0001199d init_pci -00011b61 pci_find_device -00011bfb virtual_read -00011c2a virtual_write -00011c59 virtual_disk_attach -00011c7c wm_default_changes -00011d28 wm_default_workspace -00011d8e wm_default_draw -00011e30 wm_default_add -00011edb init_windowmanager -00012027 wm_default_mouse_event -00012245 wm_default_push_back -0001233b wm_default_push_front -0001242e wm_default_remove -00012543 wm_destroy -00012625 wm_new -00012690 screen_set_cursor -000126f0 scrcolor_set -00012708 scrput -00012734 scrwrite -00012781 scr_clear -000127d7 scr_scroll -00012823 scrprintf -00012aa3 strlen -00012ac9 strcpy -00012aff strncmp -00012b3c strcmp -00012b80 memcmp -00012bbd parse_arguments -00012ca6 strchr -00012cd9 getopt -00012e24 memcpy -00012e95 strtok -00012f51 xmemcpy -00012fda memset -00013058 isdigit -00013070 isspace -00013083 tolower -0001309b isxdigit -000130c3 htoi -0001316b atoi -000131fd itoa -000132ad itohex -0001332d rdtsc -00013334 rand -00013354 general_protection_fault -000133e8 interrupt_get_count -000133fb print_page_fault_info -000134d8 page_fault_interrupt -0001356e interrupt_install_handler -00013584 load_data_segments -00013594 isr_handler -0001368b init_interrupts -00013808 idt_flush -00013810 isr0 -0001381d isr1 -0001382a isr2 -00013837 isr3 -00013844 isr4 -00013851 isr5 -0001385e isr6 -0001386b isr7 -00013878 isr8 -00013885 isr9 -00013892 isr10 -0001389f isr11 -000138ac isr12 -000138b9 isr13 -000138c6 isr14 -000138d3 isr15 -000138e0 isr16 -000138ed isr17 -000138fa isr18 -00013907 isr19 -00013914 isr20 -00013921 isr21 -0001392e isr22 -0001393b isr23 -00013948 isr24 -00013955 isr25 -00013962 isr26 -0001396f isr27 -0001397c isr28 -00013989 isr29 -00013996 isr30 -000139a3 isr31 -000139b0 isr32 -000139bd isr33 -000139ca isr34 -000139d7 isr35 -000139e1 isr36 -000139eb isr37 -000139f5 isr38 -000139ff isr39 -00013a09 isr40 -00013a13 isr41 -00013a1d isr42 -00013a27 isr43 -00013a31 isr44 -00013a3b isr45 -00013a45 isr46 -00013a4f isr47 -00013a59 isr_entry -00013a74 syscall_return_value -00013a78 _syscall_entry -00013ab5 page_fault_save -00013ab9 page_fault_error -00013abd _page_fault_entry -00013aef timer_callback -00013b2b timer_get_tick -00013b35 time_get_difference -00013b7a init_pit -00013be2 gdt_set_segment -00013c2d init_gdt -00013d3f rc -00013f32 __ksymbol_rc -00013f50 __ksymbol_as -00013f6e __ksymbol_cc -00013f8c as -00014352 cc -000143b2 __cc -000146ab vm_print -000148ac eval -00014d4b vm_setup -00014d90 vm_init -00014def vm_free -00014e22 vm_setup_stack -00014e80 lex_get_error -00014e91 next -000154ac match -000154fe expression -00016919 statement -00016b26 function_parameter -00016cec function_body -00016eff function_declaration -00016f8c enum_declaration -000170a2 global_declaration -000172d3 lex_init -00017372 program -00017417 find_mp_floating_ptr -00017457 smp_parse -000175a1 kb_get_char -000175ef kb_add_char -0001762e kb_callback -0001785f init_keyboard -000178da pcb_await -00017908 __pcb_get_free -000179ce __add_systemcall_pcb_await -000179e9 __pcb_free -00017a38 __pcb_init_kernel_stack -00017a99 __pcb_init_process -00017b5e init_pcbs -00017bb3 pcb_total_usage -00017bd4 pcb_get_info -00017cba pcb_kill -00017cdb Genesis -00017ce1 idletask -00017d00 pcb_get_by_pid -00017d15 pcb_get_by_name -00017d72 pcb_dbg_print -00017df0 pcb_cleanup_routine -00018005 pcb_create_thread -00018101 pcb_create_process -0001839a pcb_create_kthread -00018680 start_pcb -000186bc __pcb_queue_peek -000186ff __pcb_queue_pop -0001875f __pcb_queue_remove -000187d5 __pcb_queue_add -00018852 __pcb_queue_push -000188ef pcb_new_queue -00018924 memory_map_init -000189f0 memory_map_get -000189fa free -00018a68 malloc -00018b08 calloc -00018b3f get_mem_info -00018b9b init_memory -00018c31 vmem_free -00018ca5 vmem_alloc -00018d16 vmem_free_page_region -00018e7f vmem_page_region_alloc -00018eba vmem_create_page_region -00018ffd vmem_free_allocations -00019125 vmem_continious_allocation_map -0001912f vmem_free_allocation -00019134 vmem_stack_free -000191e9 vmem_stack_alloc -00019593 vmem_dump_heap -0001962c vmem_init_process_thread -00019721 vmem_init_process -00019a4e vmem_cleanup_process_thead -00019ac9 vmem_cleanup_process -00019cb9 vmem_init_kernel -00019e7a vmem_allocator_create -00019ee4 vmem_map_driver_region -00019f66 vmem_total_usage -00019f7d vmem_init -0001a0b5 kalloc -0001a250 kcalloc -0001a286 kfree -0001a320 palloc -0001a370 pmemory_used -0001a391 kmemory_used -0001a39b kmemory_total -0001a3ab kmem_init -0001a44c e1000_receive -0001a528 e1000_transmit -0001a5ee e1000_callback -0001a619 _e1000_tx_init -0001a6c1 _e1000_rx_init -0001a75f e1000_attach -0001a9b2 display_get_info -0001aa20 kenv_init -0001aa3b kenv_set -0001aa77 config_list -0001ab5d kernel_config_load -0001af2b config_get_value -0001afee spin_lock -0001b012 spin_unlock -0001b024 mutex_init -0001b046 acquire -0001b0e7 release -0001b18d kthread_entry -0001b1eb kthread_list -0001b256 register_kthread -0001b333 start -0001b3d9 ata_primary -0001b3de ata_secondary -0001b3e3 ata_wait -0001b45d ata_write -0001b5cf ata_read -0001b74d ata_ide_init -0001b921 set_bitmap -0001b947 unset_bitmap -0001b96f get_bitmap -0001b995 get_bitmap_size -0001b9ad create_bitmap -0001b9e5 destroy_bitmap -0001b9fc bitmap_unset_continous -0001ba39 bitmap_get_continous -0001bad3 get_free_bitmap -0001bb2c __rtc_check_in_progress -0001bb53 __rtc_get_register -0001bb77 get_current_time -0001bcc0 get_time -0001bcee init_tss -0001bd20 exec_cmd -0001be79 __ksymbol_exec_cmd -0001be97 system_reboot -0001becf align_to_pointer_size -0001bee1 calculate_size_unit -0001bf41 advanced_hash -0001bf7c kernel_panic -0001bf9e kref_init -0001bfbc kref_get -0001bfe8 kref_put -0001c014 csprintf -0001c212 script_parse -0001c2e4 login -0001c681 __login_create_virt_disk -0001c6af __register_kthread_login -0001c6cd help -0001c972 clear -0001c997 __ksymbol_new -0001c9b5 __ksymbol_list -0001c9d3 __ksymbol_color -0001c9f1 __ksymbol_about -0001ca0f __ksymbol_help -0001ca2d __ksymbol_kevents -0001ca4b __ksymbol_view -0001ca69 __ksymbol_file -0001ca87 __ksymbol_tcp -0001caa5 __ksymbol_conf -0001cac3 __ksymbol_clear -0001cae1 __ksymbol_services -0001caff __ksymbol_reboot -0001cb1d kevents -0001cbfb services -0001ce2d new -0001cf72 list -0001d076 file -0001d248 color -0001d2ed about -0001d32e view -0001d547 tcp -0001d828 __tcp_reader -0001d94d conf -0001dc19 reboot -0001dc56 attach_disk_dev -0001dc7e disk_attached -0001dc8a disk_name -0001dc97 disk_device_get -0001dca1 disk_size -0001dcc1 write_block -0001dd02 write_block_offset -0001dd49 read_block -0001dd8a read_block_offset -0001ddf8 sched_consume -0001de3d sched_add -0001de9b sched_prioritize -0001df54 sched_round_robin -0001e13a sched_exit -0001e1f7 sched_block -0001e319 sched_default -0001e3f4 sched_sleep -0001e49e sched_init_default -0001e523 get_scheduler -0001e52d kernel_sleep -0001e54c kernel_yield -0001e593 kernel_exit -0001e5c9 block -0001e5f6 unblock -0001e5fb work_queue_add -0001e6ff init_worker -0001e71b worker_thread -0001e7be __ring_buffer_add -0001e86a __ring_buffer_read -0001e978 rbuffer_new -0001e9e5 rbuffer_free -0001ea0b error_get_string -0001ea4b kclock -0001ef26 __register_kthread_kclock -0001ef44 tar_extract -0001f194 __ksymbol_tar -0001f1b2 tar_list -0001f2bd tar -0001f54a rgb_to_vga -0001f55e rgb_to_components -0001f589 color_distance_squared -0001f5f9 rgb_init_color_table -0001f684 iface_loopback_write -0001f749 iface_loopback_interrupt -0001f764 iface_loopback_read -0001f80e net_init_loopback -0001f829 serial_put -0001f86d serial_write -0001f8b3 serial_printf -0001fa67 init_serial -0001fb31 inportb -0001fb3e inportw -0001fb4c inportl -0001fb59 outportb -0001fb69 outportw -0001fb7a outportl -0001fb8a sys_create_thread -0001fbad __add_systemcall_sys_create_thread -0001fbbc add_system_call -0001fc00 system_call -0001fc6f hashmap_put -0001fcdb hashmap_get -0001fd63 hashmap_add -0001fdf1 hashmap_free -0001fdf6 reset_vga_palette -0001fe40 vga_set_palette -0001ff2f b8to16 -0001ff45 vesa_put_pixel -0001ff73 vesa_put_box -0001ffed vesa_put_block -00020067 vesa_put_char -000200e1 vesa_put_char16 -00020179 vesa_put_icon16 -000201f4 vesa_write -00020237 vesa_write_str -00020269 vesa_fill -000202ed vesa_fillrect -0002035c vesa_inner_box -00020468 vesa_printf -000206f4 ksyms_init -00020913 ksyms_add_symbol -000209d0 __ksymbol_backtrace -000209ee ksyms_list -00020a54 ksyms_resolve_symbol -00020b0b __backtrace_from -00020c29 backtrace -00020c3e ws_fullscreen -00020dbc ws_remove -00020e70 ws_add -00020f5f ws_destroy -00021009 ws_draw -000212ba ws_raw_wallpaper -000213a4 ws_set_background_file -00021684 ws_init -0002176b ws_set_background -0002181a ws_new -000218ab encode_run_length -00021934 decode_run_length -000219ab __mouse_handler -00021ac3 mouse_wait -00021b0b mouse_write -00021b4d mouse_get_event -00021b92 mouse_init -00021c7b sys_ipc_open -00021ccd __add_systemcall_sys_ipc_open -00021ce8 __add_systemcall_sys_ipc_close -00021d03 __add_systemcall_sys_ipc_send -00021d1e __add_systemcall_sys_ipc_receive -00021d39 sys_ipc_close -00021d86 sys_ipc_send -00021df1 sys_ipc_receive -00021e5b sysinf -00022bc7 __register_kthread_sysinf -00022be5 echo -00022c24 res -00022c69 ifconfig -00022c7a __ksymbol_ifconfig -00022c98 __ksymbol_ps -00022cb6 __ksymbol_tree -00022cd4 __ksymbol_fat16 -00022cf2 __ksymbol_xxd -00022d10 __ksymbol_sh -00022d2e __ksymbol_ed -00022d4c __ksymbol_exec -00022d6a __ksymbol_ths -00022d88 __ksymbol_dns -00022da6 __ksymbol_th -00022dc4 __ksymbol_kill -00022de2 __ksymbol_echo -00022e00 __ksymbol_fdisk -00022e1e __ksymbol_meminfo -00022e3c __ksymbol_res -00022e5a __ksymbol_bg -00022e78 __ksymbol_exit -00022e96 __ksymbol_socks -00022eb4 __ksymbol_reset -00022ed2 exit -00022f0a ps -00023182 print_pcb_tree -00023281 tree -000232c5 fat16 -000232f1 xxd -000233ea sh -000234ee ed -0002353f exec -000236a9 ths -00023719 dns -00023791 th -000237b3 kill -000237d5 fdisk -0002396b meminfo -00023b4e bg -00023bd1 socks -00023e7a __register_kthread_shell -00023e98 __register_kthread_textshell -00023eb6 shell_clear -00023efd reset_shell -00023f72 reset -00023fca shell_put -000241b0 shell -00024415 cleanup_function -00024440 testfn -00024478 draw_box -00024561 __textshell_reset_box -000245f1 textshell -000249c7 __net_find_interface -00024a27 net_drop_packet -00024a48 net_handle_recieve -00024b73 net_get_interfaces -00024b7d net_configure_iface -00024bd3 net_incoming_packet -00024c85 net_get_iface -00024d01 net_iface_up -00024d2c net_iface_down -00024d57 net_list_ifaces -00024e75 net_register_interface -00024eaa net_send_skb -00024f36 net_get_info -00024f61 networking_main -00025141 __dhcp_add_option -000251ab __dhcp_send_discovery -000252ed __dhcp_send_request -0002546a dhcp_get_state -00025476 dhcp_get_dns -00025480 dhcp_get_ip -00025499 dhcp_get_gw -000254b2 dhcpd -00025746 udp_server -000257d5 tcp_server -0002594d __net_terminal_writef -000259b6 __register_kthread_tcp_server -000259d4 __register_kthread_udp_server -000259f2 __register_kthread_udptest -00025a10 udptest -00025a9f tcpd -00025b87 logd -00025bf6 __register_kthread_logd -00025c14 logd_attach_by_pid -00025c5c taskbar_reboot -00025c8c __reboot -00025ca5 taskbar_readme -00025cc2 taskbar_about -00025cdf taskbar_clock -00025cfc taskbar_sysinf -00025d19 taskbar_bg_retro -00025d54 taskbar_bg_lotr2 -00025d6d taskbar_bg_lotr -00025d86 taskbar_bg_default_color_gray -00025d9c taskbar_bg_default_color -00025db2 taskbar_wolfstein -00025df1 taskbar_bg_graph -00025e30 taskbar_bg_calc -00025e6f taskbar_colors -00025eae taskbar_cube -00025eed taskbar_editor -00025f2c taskbar_finder -00025f6b taskbar_terminal -00025fb8 __register_kthread_taskbar -00025fd6 taskbar_hdr_opt_event -00026060 taskbar -0002666d about -0002683c __register_kthread_about -0002685a __register_kthread_readme -00026878 readme -000269de gfx_default_hover -00026b0c gfx_draw_window -00027927 gfx_destory_window -000279b8 gfx_window_resize -00027a65 gfx_window_maximize -00027ae2 gfx_default_mouse_up -00027bb4 gfx_default_mouse_down -00027c7a gfx_default_click -00027e6d gfx_window_set_resizable -00027e86 kernel_gfx_window_border_color -00027eb5 gfx_new_window -0002811c gfx_point_in_rectangle -0002814d gfx_draw_component -00028193 gfx_input_event -000282b4 gfx_input_draw -000283c0 gfx_input_manager_add -00028425 gfx_composition_remove_window -00028453 gfx_composition_add_window -0002849e gfx_set_background_color -000284f3 gfx_raw_background -00028544 gfx_decode_background_image -00028595 gfx_set_taskbar -00028639 gfx_compositor_main -000286b1 kernel_gfx_draw_circle_helper -00028928 gfx_get_window_width -00028941 gfx_get_window_height -0002895a gfx_push_event -00028a21 gfx_put_icon16 -00028b19 gfx_put_icon32 -00028c0f gfx_event_loop -00028d35 kernel_gfx_draw_rectangle -00028e37 kernel_gfx_draw_contoured_box -00028edb kernel_gfx_draw_pixel -00028f84 kernel_gfx_draw_bitmap -000290a9 kernel_gfx_draw_char -00029193 kernel_gfx_set_position -000291b3 gfx_commit -000291d0 kernel_gfx_draw_text -00029287 gfx_button_ext -000293be gfx_button -000293e0 kernel_gfx_set_title -00029450 kernel_gfx_set_header -000294c0 kernel_gfx_draw_line -0002965a kernel_gfx_draw_circle -000296dd kernel_gfx_draw_section -000296e7 kernel_gfx_draw_format_text -00029a39 gfx_syscall_hook -00029bf5 gfx_total_themes -00029bff kernel_gfx_current_theme -00029c09 kernel_gfx_update_theme -00029cdb kernel_gfx_default_theme -00029ce5 kernel_gfx_set_theme -00029d0e kernel_gfx_get_theme -00029d2d gfx_new_ctx -00029d8d gfx_init_framebuffer -00029efd netdev_attach_driver -00029faa is_netdev_attached -00029fbc netdev_transmit -00029fdb netdev_recieve -0002a008 net_ethernet_add_header -0002a0a0 net_ethernet_parse -0002a11b __skb_queue_remove -0002a15d __skb_queue_add -0002a1b1 skb_free_queue -0002a1ed skb_new_queue -0002a258 skb_free -0002a297 skb_new -0002a306 skb_consume -0002a33b __net_arp_send -0002a3fb net_init_arp -0002a44b net_arp_add_entry -0002a4e3 net_arp_find_entry -0002a532 net_arp_respond -0002a5ab net_net_arp_request -0002a635 arp_parse -0002a6e3 net_ipv4_print -0002a6ed net_ipv4_add_header -0002a828 net_is_ipv4 -0002a869 net_ipv4_parse -0002a99a ntohl -0002a9ca htonl -0002a9e1 ntohs -0002a9f2 htons -0002aa03 checksum -0002aa5e transport_checksum -0002aab7 ip_to_int -0002ab59 net_icmp_handle -0002ac22 net_icmp_response -0002ac2c net_icmp_request -0002acf3 ping -0002ad50 net_icmp_parse -0002adc4 net_udp_send -0002aefd net_udp_parse -0002b029 socket_type_to_str -0002b03c socket_domain_to_str -0002b04f socket_protocol_to_str -0002b062 net_sock_bind -0002b0b1 net_get_sockets -0002b0d1 sock_get -0002b0f6 get_total_sockets -0002b100 net_sock_is_established -0002b148 net_sock_awaiting_ack -0002b190 net_sock_data_ready -0002b1eb net_sock_read -0002b2f0 net_sock_add_data -0002b554 sock_find_listen_tcp -0002b59c net_sock_find_tcp -0002b78f net_prepare_tcp_sock -0002b81f net_sock_accept -0002b836 net_socket_find_udp -0002b8a5 kernel_sock_shutdown -0002b8d6 kernel_sock_cleanup -0002b960 kernel_sock_close -0002b998 kernel_socket_create -0002bb1f net_init_sockets -0002bb69 gethostname -0002c097 __add_systemcall_gethostname -0002c0b2 net_init_dns -0002c0e5 route -0002c136 tcb_init -0002c158 tcb_new -0002c2c8 tcp_state_to_str -0002c2e5 tcp_new_connection -0002c371 tcp_free_connection -0002c398 tcp_is_listening -0002c3b2 tcp_set_listening -0002c416 tcp_calculate_checksum -0002c4df __tcp_send -0002c5fb tcp_send_segment -0002c742 tcp_accept_connection -0002c888 tcp_send_ack -0002c9c0 tcp_read -0002c9ca tcp_recv_segment -0002c9d4 tcp_connect -0002ca7b tcp_send_syn -0002ca85 tcp_recv_ack -0002cb0c tcp_recv_fin -0002cb16 tcp_recv_syn -0002cc4c tcp_send_fin -0002cd1c tcp_close_connection -0002cd5f tcp_parse -0002d1fb kernel_bind -0002d234 kernel_recvfrom -0002d23e kernel_recv -0002d2b4 kernel_recv_timeout -0002d2de kernel_connect -0002d3e4 kernel_sendto -0002d4a2 kernel_accept -0002d509 kernel_listen -0002d535 kernel_send -0002d5bf sys_kernel_bind -0002d5f5 __add_systemcall_sys_kernel_bind -0002d610 __add_systemcall_sys_kernel_accept -0002d62b __add_systemcall_sys_kernel_connect -0002d646 __add_systemcall_sys_kernel_listen -0002d661 __add_systemcall_sys_kernel_recv -0002d67c __add_systemcall_sys_kernel_recvfrom -0002d697 __add_systemcall_sys_kernel_recv_timeout -0002d6b2 __add_systemcall_sys_kernel_send -0002d6cd __add_systemcall_sys_kernel_sendto -0002d6e8 __add_systemcall_sys_socket_create -0002d703 __add_systemcall_sys_kernel_sock_close -0002d71e sys_kernel_accept -0002d762 sys_kernel_connect -0002d798 sys_kernel_listen -0002d7cb sys_kernel_recv -0002d807 sys_kernel_recvfrom -0002d84b sys_kernel_recv_timeout -0002d88d sys_kernel_send -0002d8c9 sys_kernel_sendto -0002d90d sys_socket_create -0002d938 sys_kernel_sock_close -0002d97d __iface_send -0002d9b0 __iface_recieve -0002d9e3 __iface_assign -0002d9fa __iface_detach -0002da12 __iface_set_gateway -0002da29 __iface_set_netmask -0002da40 __iface_configure -0002da94 __iface_attach -0002dabd net_interface_create -0002daf9 net_register_netdev -0002dc15 net_interface_destroy -0002dc2e __default_restart -0002dc38 __default_stop -0002dca1 __default_start -0002dd24 nm_new -0002ddb1 nm_free -0002ddfa net_firewall_create -0002de21 fs_file2fd -0002de8a fs_alloc_file -0002ded9 fs_free_file -0002df37 fs_register -0002e00a fs_init -0002e014 fs_unregister -0002e07b fs_get -0002e085 fs_close -0002e0fb fs_open -0002e179 fs_seek -0002e1fa fs_read -0002e313 fs_load_from_file -0002e3a3 fs_write -0002e462 fs_save_to_file -0002e4f2 fat16_rmdir -0002e4fc fat16_stat -0002e506 fat16_close -0002e574 fat16_rename -0002e60d fat16_mkdir -0002e6f6 fat16_remove -0002e76d fat16_open -0002e8bb fat16_read -0002ea1e fat16_write -0002eb51 fat16_list -0002ee23 fat16_init -0002eedb path_next_iter -0002ef49 inode_from_path_recursise -0002efc7 inode_from_path -0002f089 ext_get_root -0002f096 ext_get_current_dir -0002f0a9 ext_get_size -0002f0b3 ext_get_inodes -0002f0bd ext_get_blocks -0002f0c7 ext_sync -0002f13e ext_create -0002f22d ext_read -0002f2ac ext_seek -0002f2f7 ext_write -0002f367 ext_close -0002f3cd ext_open_from_directory -0002f4d5 ext_open -0002f590 ext_size -0002f5bd change_directory -0002f627 ext_create_directory -0002f7c5 ext_create_file_system -0002fa96 init_ext -0002fc36 listdir -0002fd5d __inode_sync -0002fdc0 __inode_cache_insert -0002feb6 __inode_load -0002ff2a inodes_sync -0002ff69 inode_get -0002ffca inode_read -000301ba inode_write -00030421 alloc_inode -000304de mkdir -0003058f sync -000305c7 mkfs -000305d8 fat16_read_data_from_cluster -0003062a fat16_read_data -00030707 fat16_find_cluster_by_offset -00030786 fat16_write_data_to_cluster_with_offset -000307c5 fat16_print_cluster_chain -000307f7 fat16_write_data_to_cluster -0003082e fat16_write_data -00030949 get_fat_start_block -00030955 get_root_directory_start_block -00030968 get_data_start_block -0003097e fat16_get_fat_entry -0003099d fat16_set_fat_entry -000309e1 fat16_sync_fat_table -00030a5d fat16_allocate_cluster -00030a79 fat16_free_cluster -00030a92 fat16_get_free_cluster -00030aeb fat16_sync_directory_entry -00030b72 fat16_read_entry -00030c23 fat16_find_entry -00030d5e fat16_rename_entry -00030dd3 fat16_free_clusters -00030e1e fat16_delete_entry -00030e89 fat16_add_entry -00030ff4 fat16_used_blocks -00031031 fat16_to_upper -00031061 fat16_name_compare -0003117c sstrtok -0003123f fat16_directory_entry_debug -00031316 fat16_get_directory_entry -0003151f fat16_create_directory -00031628 fat16_read_file -0003167d fat16_create_file -000316ff fat16_create_empty_file -000317c7 fat16_directory_entries -000318b2 fat16_mbr_clear -0003197d fat16_mbr_add_entry -00031a72 fat16_print_root_directory_entries -00031a8e fat16_change_directory -00031b1a fat16_bootblock_info -00031c9b fat16_set_time -00031cd3 fat16_set_date -00031d0f fat16_load -00031e92 fat16_format -0003214b mbr_partition_type_string -000321d3 mbr_partitions_parse -000322a1 mbr_get -000322ab mbr_partition_load -000322cd __list_users -00032362 __change_user -00032408 __remove_user -000324b8 __add_user -000325a6 __find_user -00032679 __authenticate_user -0003278c __save_users -00032814 __load_users -00032a1a __ksymbol_admin -00032a38 admin -00032d50 usermanager_create -00032d73 __ksymbol_snakegame -00032d91 init_game -00032de1 draw -00032e41 get_input -00032e64 update -00032ff0 game_loop -0003301a snakegame -00033069 __msgbox -0003347c msgbox_create -000334b3 msgbox_show -000334ff kevents_list -00033675 kevents_init -000336bb kevents_destroy -00033714 kevents_add -000337cf kevents_create -00033856 _code_end +00010103 kernel +0001059d kernel_get_context +000105a3 hexdump +000107f1 __terminal_set_ops +000108ba __terminal_scanf +000108c0 __terminal_write +0001090a __terminal_getchar_graphics +00010953 __terminal_scan_graphics +00010a31 __terminal_reset +00010a75 __terminal_detach +00010ab8 __terminal_attach +00010b03 __terminal_remove_line +00010b43 __terminal_putchar_graphics +00010c0c __terminal_writef +00010f16 __terminal_getchar_textmode +00010f3e __terminal_scan_textmode +00011002 __terminal_commit_textmode +000110ba __terminal_putchar_textmode +00011106 scan +0001113f terminal_set_color +00011157 __terminal_commit_graphics +000112b3 terminal_attach +000112d4 terminal_commit +000112f3 terminal_putchar +00011325 terminal_create +0001144a terminal_destroy +00011480 tlb_flush_addr +00011488 load_page_directory +00011498 enable_paging +000114aa pcb_save_context +000114d6 pcb_restore_context +000114ff _start_pcb +00011531 _start_pcb_skip +0001154c __ksymbol_lspci +00011566 pci_get_class_name +00011579 pci_get_device_name +000115ea pci_get_vendor_name +00011638 lspci +00011785 pci_get_devices +0001178b pci_read_word +000117e5 pci_write_dword +00011834 pci_enable_device_busmaster +00011889 pci_register_device +0001190a init_pci +00011abb pci_find_device +00011b51 virtual_read +00011b7c virtual_write +00011ba7 virtual_disk_attach +00011bc6 wm_default_changes +00011c6e wm_default_workspace +00011cd0 wm_default_draw +00011d6e wm_default_add +00011e15 init_windowmanager +00011f5f wm_default_mouse_event +00012185 wm_default_push_back +00012277 wm_default_push_front +00012366 wm_default_remove +00012477 wm_destroy +00012555 wm_new +000125bc screen_set_cursor +0001261c scrcolor_set +00012630 scrput +00012656 scrwrite +0001269f scr_clear +000126f1 scr_scroll +00012739 scrprintf +0001297d strlen +0001299f strcpy +000129d3 strncmp +00012a0e strcmp +00012a4e memcmp +00012a89 parse_arguments +00012b6c strchr +00012b9b getopt +00012cab memcpy +00012d18 strtok +00012dd0 xmemcpy +00012e57 memset +00012ed7 isdigit +00012eeb isspace +00012efa tolower +00012f0e isxdigit +00012f32 htoi +00012fd6 atoi +00013066 itoa +0001310c itohex +00013188 rdtsc +0001318b rand +000131a7 general_protection_fault +00013237 interrupt_get_count +00013246 print_page_fault_info +00013323 page_fault_interrupt +000133b5 interrupt_install_handler +000133c7 load_data_segments +000133d3 isr_handler +000134c6 init_interrupts +0001363f idt_flush +00013647 isr0 +00013654 isr1 +00013661 isr2 +0001366e isr3 +0001367b isr4 +00013688 isr5 +00013695 isr6 +000136a2 isr7 +000136af isr8 +000136bc isr9 +000136c9 isr10 +000136d6 isr11 +000136e3 isr12 +000136f0 isr13 +000136fd isr14 +0001370a isr15 +00013717 isr16 +00013724 isr17 +00013731 isr18 +0001373e isr19 +0001374b isr20 +00013758 isr21 +00013765 isr22 +00013772 isr23 +0001377f isr24 +0001378c isr25 +00013799 isr26 +000137a6 isr27 +000137b3 isr28 +000137c0 isr29 +000137cd isr30 +000137da isr31 +000137e7 isr32 +000137f4 isr33 +00013801 isr34 +0001380e isr35 +00013818 isr36 +00013822 isr37 +0001382c isr38 +00013836 isr39 +00013840 isr40 +0001384a isr41 +00013854 isr42 +0001385e isr43 +00013868 isr44 +00013872 isr45 +0001387c isr46 +00013886 isr47 +00013890 isr_entry +000138ab syscall_return_value +000138af _syscall_entry +000138ec page_fault_save +000138f0 page_fault_error +000138f4 _page_fault_entry +00013926 timer_callback +0001395e timer_get_tick +00013964 time_get_difference +000139a7 init_pit +00013a0b gdt_set_segment +00013a54 init_gdt +00013b62 rc +00013d51 __ksymbol_rc +00013d6b __ksymbol_as +00013d85 __ksymbol_cc +00013d9f as +00014161 cc +000141bd __cc +000144b1 vm_print +000146ae eval +00014b48 vm_setup +00014b89 vm_init +00014be4 vm_free +00014c13 vm_setup_stack +00014c6f lex_get_error +00014c7c next +00015187 match +000151d5 expression +000164d6 statement +000166df function_parameter +000168a1 function_body +00016ab0 function_declaration +00016b39 enum_declaration +00016c4c global_declaration +00016e79 lex_init +00016f14 program +00016fb5 find_mp_floating_ptr +00016ff1 smp_parse +00017136 kb_get_char +00017182 kb_add_char +000171bd kb_callback +000173ea init_keyboard +00017461 pcb_await +0001748b __pcb_get_free +00017549 __add_systemcall_pcb_await +00017560 __pcb_free +000175af __pcb_init_kernel_stack +00017610 __pcb_init_process +000176d5 init_pcbs +00017726 pcb_total_usage +0001774f pcb_get_info +00017843 pcb_kill +00017860 Genesis +00017862 idletask +0001787d pcb_get_by_pid +0001788e pcb_get_by_name +000178e7 pcb_dbg_print +00017961 pcb_cleanup_routine +00017b71 pcb_create_thread +00017c69 pcb_create_process +00017efb pcb_create_kthread +000181d7 start_pcb +0001820f __pcb_queue_peek +0001824e __pcb_queue_pop +000182aa __pcb_queue_remove +0001831c __pcb_queue_add +00018395 __pcb_queue_push +0001842e pcb_new_queue +0001845f memory_map_init +00018526 memory_map_get +0001852c free +00018596 malloc +00018632 calloc +00018665 get_mem_info +000186bd init_memory +0001874f vmem_free +000187bf vmem_alloc +0001882c vmem_free_page_region +00018992 vmem_page_region_alloc +000189cd vmem_create_page_region +00018b11 vmem_free_allocations +00018c40 vmem_continious_allocation_map +00018c46 vmem_free_allocation +00018c47 vmem_stack_free +00018cf8 vmem_stack_alloc +0001907d vmem_dump_heap +00019112 vmem_init_process_thread +00019203 vmem_init_process +00019531 vmem_cleanup_process_thead +000195a8 vmem_cleanup_process +00019796 vmem_init_kernel +00019957 vmem_allocator_create +000199bb vmem_map_driver_region +00019a39 vmem_total_usage +00019a4c vmem_init +00019b7e kalloc +00019d15 kcalloc +00019d47 kfree +00019ddd palloc +00019e1f pmemory_used +00019e3b kmemory_used +00019e41 kmemory_total +00019e4d kmem_init +00019eea e1000_receive +00019fc5 e1000_transmit +0001a087 e1000_callback +0001a0ae _e1000_tx_init +0001a152 _e1000_rx_init +0001a1ec e1000_attach +0001a41c display_get_info +0001a485 kenv_init +0001a49c kenv_set +0001a4d1 config_list +0001a5a2 kernel_config_load +0001a98d config_get_value +0001aa48 spin_lock +0001aa68 spin_unlock +0001aa76 mutex_init +0001aa93 acquire +0001ab30 release +0001abd2 kthread_entry +0001ac2c kthread_list +0001ac93 register_kthread +0001ad6c start +0001ae0e ata_primary +0001ae0f ata_secondary +0001ae10 ata_wait +0001ae8a ata_write +0001b001 ata_read +0001b191 ata_ide_init +0001b361 set_bitmap +0001b383 unset_bitmap +0001b3a7 get_bitmap +0001b3c9 get_bitmap_size +0001b3dd create_bitmap +0001b411 destroy_bitmap +0001b424 bitmap_unset_continous +0001b45e bitmap_get_continous +0001b4fa get_free_bitmap +0001b54f __rtc_check_in_progress +0001b571 __rtc_get_register +0001b591 get_current_time +0001b6dc get_time +0001b706 init_tss +0001b734 exec_cmd +0001b838 __ksymbol_exec_cmd +0001b852 system_reboot +0001b886 align_to_pointer_size +0001b894 calculate_size_unit +0001b8f6 advanced_hash +0001b92a kernel_panic +0001b948 kref_init +0001b962 kref_get +0001b98a kref_put +0001b9b2 csprintf +0001bbb3 script_parse +0001bc88 login +0001c021 __login_create_virt_disk +0001c04b __register_kthread_login +0001c065 help +0001c306 clear +0001c327 __ksymbol_new +0001c341 __ksymbol_list +0001c35b __ksymbol_color +0001c375 __ksymbol_about +0001c38f __ksymbol_help +0001c3a9 __ksymbol_kevents +0001c3c3 __ksymbol_view +0001c3dd __ksymbol_file +0001c3f7 __ksymbol_tcp +0001c411 __ksymbol_conf +0001c42b __ksymbol_clear +0001c445 __ksymbol_services +0001c45f __ksymbol_reboot +0001c479 kevents +0001c553 services +0001c781 new +0001c8c2 list +0001c9c2 file +0001cb90 color +0001cc31 about +0001cc6e view +0001ce83 tcp +0001d160 __tcp_reader +0001d281 conf +0001d549 reboot +0001d582 attach_disk_dev +0001d5a6 disk_attached +0001d5ae disk_name +0001d5b7 disk_device_get +0001d5bd disk_size +0001d5d9 write_block +0001d616 write_block_offset +0001d659 read_block +0001d696 read_block_offset +0001d700 sched_consume +0001d741 sched_add +0001d79b sched_prioritize +0001d850 sched_round_robin +0001da36 sched_exit +0001daef sched_block +0001dc0d sched_default +0001dce7 sched_sleep +0001dd8d sched_init_default +0001de0e get_scheduler +0001de14 kernel_sleep +0001de2f kernel_yield +0001de72 kernel_exit +0001dea4 block +0001decd unblock +0001dece work_queue_add +0001dfb6 init_worker +0001dfce worker_thread +0001e06d __ring_buffer_add +0001e115 __ring_buffer_read +0001e21f rbuffer_new +0001e288 rbuffer_free +0001e2aa error_get_string +0001e2e6 kclock +0001e7c6 __register_kthread_kclock +0001e7e0 tar_extract +0001ea30 __ksymbol_tar +0001ea4a tar_list +0001eb54 tar +0001eddd rgb_to_vga +0001eded rgb_to_components +0001ee14 color_distance_squared +0001ee7f rgb_init_color_table +0001ef10 iface_loopback_write +0001efd1 iface_loopback_interrupt +0001efe8 iface_loopback_read +0001f08b net_init_loopback +0001f0a2 serial_put +0001f0e2 serial_write +0001f124 serial_printf +0001f2c4 init_serial +0001f38a inportb +0001f393 inportw +0001f39d inportl +0001f3a6 outportb +0001f3b4 outportw +0001f3c3 outportl +0001f3d0 sys_create_thread +0001f3ef __add_systemcall_sys_create_thread +0001f3fa add_system_call +0001f43a system_call +0001f4a5 hashmap_put +0001f50c hashmap_get +0001f590 hashmap_add +0001f61a hashmap_free +0001f61b reset_vga_palette +0001f661 vga_set_palette +0001f74c b8to16 +0001f75c vesa_put_pixel +0001f786 vesa_put_box +0001f801 vesa_put_block +0001f87c vesa_put_char +0001f8f7 vesa_put_char16 +0001f98a vesa_put_icon16 +0001fa03 vesa_write +0001fa42 vesa_write_str +0001fa70 vesa_fill +0001faf2 vesa_fillrect +0001fb64 vesa_inner_box +0001fc6c vesa_printf +0001fed9 ksyms_init +00020100 ksyms_add_symbol +000201b9 __ksymbol_backtrace +000201d3 ksyms_list +00020235 ksyms_resolve_symbol +000202e8 __backtrace_from +00020405 backtrace +00020416 ws_fullscreen +00020590 ws_remove +00020640 ws_add +0002072b ws_destroy +000207d1 ws_draw +00020a7e ws_raw_wallpaper +00020b64 ws_set_background_file +00020e41 ws_init +00020f24 ws_set_background +00020fcf ws_new +0002105c encode_run_length +000210d9 decode_run_length +00021144 __mouse_handler +0002125b mouse_wait +000212a3 mouse_write +000212e5 mouse_get_event +00021326 mouse_init +0002140b sys_ipc_open +00021459 __add_systemcall_sys_ipc_open +00021470 __add_systemcall_sys_ipc_close +00021487 __add_systemcall_sys_ipc_send +0002149e __add_systemcall_sys_ipc_receive +000214b5 sys_ipc_close +000214fe sys_ipc_send +00021565 sys_ipc_receive +000215cb sysinf +0002231d __register_kthread_sysinf +00022337 echo +00022372 res +000223b3 ifconfig +000223c0 __ksymbol_ifconfig +000223da __ksymbol_ps +000223f4 __ksymbol_tree +0002240e __ksymbol_fat16 +00022428 __ksymbol_xxd +00022442 __ksymbol_sh +0002245c __ksymbol_ed +00022476 __ksymbol_exec +00022490 __ksymbol_ths +000224aa __ksymbol_dns +000224c4 __ksymbol_th +000224de __ksymbol_kill +000224f8 __ksymbol_echo +00022512 __ksymbol_fdisk +0002252c __ksymbol_meminfo +00022546 __ksymbol_res +00022560 __ksymbol_bg +0002257a __ksymbol_exit +00022594 __ksymbol_socks +000225ae __ksymbol_reset +000225c8 exit +000225fc ps +00022870 print_pcb_tree +0002296f tree +000229af fat16 +000229d7 xxd +00022acc sh +00022bcc ed +00022c19 exec +00022d7d ths +00022de9 dns +00022e5d th +00022e7b kill +00022e99 fdisk +0002302b meminfo +0002320a bg +00023289 socks +0002352f __register_kthread_shell +00023549 __register_kthread_textshell +00023563 shell_clear +000235a6 reset_shell +00023617 reset +0002366b shell_put +0002384c shell +00023aad cleanup_function +00023ad4 testfn +00023b08 draw_box +00023bed __textshell_reset_box +00023c7d textshell +0002404e __net_find_interface +000240ae net_drop_packet +000240cf net_handle_recieve +000241f6 net_get_interfaces +000241fc net_configure_iface +0002424e net_incoming_packet +000242ff net_get_iface +00024375 net_iface_up +0002439c net_iface_down +000243c3 net_list_ifaces +000244dd net_register_interface +0002450e net_send_skb +00024596 net_get_info +000245bd networking_main +0002479d __dhcp_add_option +0002480d __dhcp_send_discovery +0002494f __dhcp_send_request +00024acc dhcp_get_state +00024ad4 dhcp_get_dns +00024ada dhcp_get_ip +00024aef dhcp_get_gw +00024b04 dhcpd +00024d83 udp_server +00024e0e tcp_server +00024f82 __net_terminal_writef +00024fe7 __register_kthread_tcp_server +00025001 __register_kthread_udp_server +0002501b __register_kthread_udptest +00025035 udptest +000250c0 tcpd +000251a4 logd +0002520f __register_kthread_logd +00025229 logd_attach_by_pid +0002526d taskbar_reboot +00025299 __reboot +000252ae taskbar_readme +000252c7 taskbar_about +000252e0 taskbar_clock +000252f9 taskbar_sysinf +00025312 taskbar_bg_retro +00025349 taskbar_bg_lotr2 +0002535e taskbar_bg_lotr +00025373 taskbar_bg_default_color_gray +00025385 taskbar_bg_default_color +00025397 taskbar_wolfstein +000253d2 taskbar_bg_graph +0002540d taskbar_bg_calc +00025448 taskbar_colors +00025483 taskbar_cube +000254be taskbar_editor +000254f9 taskbar_finder +00025534 taskbar_terminal +0002557d __register_kthread_taskbar +00025597 taskbar_hdr_opt_event +00025621 taskbar +00025bd8 about +00025da3 __register_kthread_about +00025dbd __register_kthread_readme +00025dd7 readme +00025f39 gfx_default_hover +00026058 gfx_destory_window +000260e5 gfx_window_resize +0002618e gfx_window_maximize +00026207 gfx_default_mouse_up +000262d5 gfx_default_mouse_down +00026397 gfx_default_click +00026586 gfx_draw_window +00027372 gfx_window_set_resizable +00027387 kernel_gfx_window_border_color +000273b2 gfx_new_window +00027612 gfx_point_in_rectangle +0002763f gfx_draw_component +00027681 gfx_input_event +000277b3 gfx_input_draw +000278bb gfx_input_manager_add +0002791c gfx_composition_remove_window +00027946 gfx_composition_add_window +0002798d gfx_set_background_color +000279de gfx_raw_background +00027a2b gfx_decode_background_image +00027a78 gfx_set_taskbar +00027b18 gfx_compositor_main +00027b8c kernel_gfx_draw_circle_helper +00027e38 gfx_get_window_width +00027e4d gfx_get_window_height +00027e62 gfx_push_event +00027f1e gfx_put_icon16 +00028016 gfx_put_icon32 +0002810e gfx_event_loop +0002822d kernel_gfx_draw_rectangle +00028327 kernel_gfx_draw_contoured_box +000283c7 kernel_gfx_draw_pixel +00028465 kernel_gfx_draw_bitmap +00028583 kernel_gfx_draw_char +00028683 kernel_gfx_set_position +0002869f gfx_commit +000286b8 kernel_gfx_draw_text +0002876b gfx_button_ext +0002889e gfx_button +000288bc kernel_gfx_set_title +00028928 kernel_gfx_set_header +00028994 kernel_gfx_draw_line +00028b2f kernel_gfx_draw_circle +00028bae kernel_gfx_draw_section +00028bb4 kernel_gfx_draw_format_text +00028f06 gfx_syscall_hook +000290bd gfx_total_themes +000290c3 kernel_gfx_current_theme +000290c9 kernel_gfx_update_theme +00029197 kernel_gfx_default_theme +0002919d kernel_gfx_set_theme +000291c2 kernel_gfx_get_theme +000291dd gfx_new_ctx +00029239 gfx_init_framebuffer +000293a5 netdev_attach_driver +0002944e is_netdev_attached +0002945c netdev_transmit +00029477 netdev_recieve +000294a0 net_ethernet_add_header +00029534 net_ethernet_parse +000295a8 __skb_queue_remove +000295e6 __skb_queue_add +00029636 skb_free_queue +0002966e skb_new_queue +000296d5 skb_free +00029710 skb_new +0002977b skb_consume +000297ac __net_arp_send +0002986c net_init_arp +000298b8 net_arp_add_entry +00029947 net_arp_find_entry +00029992 net_arp_respond +00029a07 net_net_arp_request +00029a8d arp_parse +00029b37 net_ipv4_print +00029b3d net_ipv4_add_header +00029c74 net_is_ipv4 +00029cb1 net_ipv4_parse +00029dde ntohl +00029e0a htonl +00029e1d ntohs +00029e2a htons +00029e37 checksum +00029e8e transport_checksum +00029ee3 ip_to_int +00029f81 net_icmp_handle +0002a046 net_icmp_response +0002a04c net_icmp_request +0002a10f ping +0002a168 net_icmp_parse +0002a1d8 net_udp_send +0002a30d net_udp_parse +0002a435 socket_type_to_str +0002a444 socket_domain_to_str +0002a453 socket_protocol_to_str +0002a462 net_sock_bind +0002a4ad net_get_sockets +0002a4c9 sock_get +0002a4ea get_total_sockets +0002a4f0 net_sock_is_established +0002a534 net_sock_awaiting_ack +0002a578 net_sock_data_ready +0002a5d1 net_sock_read +0002a6d3 net_sock_add_data +0002a933 sock_find_listen_tcp +0002a977 net_sock_find_tcp +0002ab69 net_prepare_tcp_sock +0002abf5 net_sock_accept +0002ac08 net_socket_find_udp +0002ac73 kernel_sock_shutdown +0002aca0 kernel_sock_cleanup +0002ad26 kernel_sock_close +0002ad5a kernel_socket_create +0002aedd net_init_sockets +0002af23 gethostname +0002b43d __add_systemcall_gethostname +0002b454 net_init_dns +0002b483 route +0002b4d0 tcb_init +0002b4ee tcb_new +0002b65a tcp_state_to_str +0002b673 tcp_new_connection +0002b6fb tcp_free_connection +0002b71e tcp_is_listening +0002b734 tcp_set_listening +0002b794 tcp_calculate_checksum +0002b858 __tcp_send +0002b974 tcp_send_segment +0002bab7 tcp_accept_connection +0002bbf9 tcp_send_ack +0002bd2f tcp_read +0002bd35 tcp_recv_segment +0002bd3b tcp_connect +0002bdde tcp_send_syn +0002bde4 tcp_recv_ack +0002be67 tcp_recv_fin +0002be6d tcp_recv_syn +0002bf9f tcp_send_fin +0002c06b tcp_close_connection +0002c0aa tcp_parse +0002c543 kernel_bind +0002c578 kernel_recvfrom +0002c57e kernel_recv +0002c5f0 kernel_recv_timeout +0002c616 kernel_connect +0002c71a kernel_sendto +0002c7d4 kernel_accept +0002c837 kernel_listen +0002c85f kernel_send +0002c8e5 sys_kernel_bind +0002c917 __add_systemcall_sys_kernel_bind +0002c92e __add_systemcall_sys_kernel_accept +0002c945 __add_systemcall_sys_kernel_connect +0002c95c __add_systemcall_sys_kernel_listen +0002c973 __add_systemcall_sys_kernel_recv +0002c98a __add_systemcall_sys_kernel_recvfrom +0002c9a1 __add_systemcall_sys_kernel_recv_timeout +0002c9b8 __add_systemcall_sys_kernel_send +0002c9cf __add_systemcall_sys_kernel_sendto +0002c9e6 __add_systemcall_sys_socket_create +0002c9fd __add_systemcall_sys_kernel_sock_close +0002ca14 sys_kernel_accept +0002ca54 sys_kernel_connect +0002ca86 sys_kernel_listen +0002cab5 sys_kernel_recv +0002caed sys_kernel_recvfrom +0002cb2d sys_kernel_recv_timeout +0002cb6b sys_kernel_send +0002cba3 sys_kernel_sendto +0002cbe3 sys_socket_create +0002cc0a sys_kernel_sock_close +0002cc4b __iface_send +0002cc7a __iface_recieve +0002cca9 __iface_assign +0002ccbc __iface_detach +0002ccd0 __iface_set_gateway +0002cce3 __iface_set_netmask +0002ccf6 __iface_configure +0002cd46 __iface_attach +0002cd6b net_interface_create +0002cda3 net_register_netdev +0002cebb net_interface_destroy +0002ced0 __default_restart +0002ced6 __default_stop +0002cf3b __default_start +0002cfb5 nm_new +0002d03e nm_free +0002d083 net_firewall_create +0002d0a6 fs_file2fd +0002d10d fs_alloc_file +0002d158 fs_free_file +0002d1b2 fs_register +0002d281 fs_init +0002d287 fs_unregister +0002d2ea fs_get +0002d2f0 fs_close +0002d362 fs_open +0002d3dc fs_seek +0002d459 fs_read +0002d56e fs_load_from_file +0002d5fa fs_write +0002d6b5 fs_save_to_file +0002d741 fat16_rmdir +0002d747 fat16_stat +0002d74d fat16_close +0002d7b7 fat16_rename +0002d84c fat16_mkdir +0002d931 fat16_remove +0002d9a4 fat16_open +0002daee fat16_read +0002dc52 fat16_write +0002dd81 fat16_list +0002e04f fat16_init +0002e103 path_next_iter +0002e172 inode_from_path_recursise +0002e1f0 inode_from_path +0002e2ae ext_get_root +0002e2b7 ext_get_current_dir +0002e2c6 ext_get_size +0002e2cc ext_get_inodes +0002e2d2 ext_get_blocks +0002e2d8 ext_sync +0002e34b ext_create +0002e436 ext_read +0002e4b1 ext_seek +0002e4f8 ext_write +0002e564 ext_close +0002e5c6 ext_open_from_directory +0002e6cc ext_open +0002e783 ext_size +0002e7ac change_directory +0002e812 ext_create_directory +0002e9ac ext_create_file_system +0002ec79 init_ext +0002ee15 listdir +0002ef36 __inode_sync +0002ef99 __inode_cache_insert +0002f08f __inode_load +0002f103 inodes_sync +0002f13e inode_get +0002f19b inode_read +0002f383 inode_write +0002f5e1 alloc_inode +0002f69a mkdir +0002f747 sync +0002f77b mkfs +0002f788 fat16_read_data_from_cluster +0002f7d6 fat16_read_data +0002f8b7 fat16_find_cluster_by_offset +0002f932 fat16_write_data_to_cluster_with_offset +0002f96d fat16_print_cluster_chain +0002f99b fat16_write_data_to_cluster +0002f9ce fat16_write_data +0002faea get_fat_start_block +0002faf2 get_root_directory_start_block +0002fb01 get_data_start_block +0002fb13 fat16_get_fat_entry +0002fb2e fat16_set_fat_entry +0002fb6e fat16_sync_fat_table +0002fbe6 fat16_allocate_cluster +0002fbfe fat16_free_cluster +0002fc13 fat16_get_free_cluster +0002fc68 fat16_sync_directory_entry +0002fcea fat16_read_entry +0002fd97 fat16_find_entry +0002fed2 fat16_rename_entry +0002ff43 fat16_free_clusters +0002ff8a fat16_delete_entry +0002fff1 fat16_add_entry +00030158 fat16_used_blocks +00030191 fat16_to_upper +000301bd fat16_name_compare +000302e2 sstrtok +000303a3 fat16_directory_entry_debug +00030473 fat16_get_directory_entry +0003066b fat16_create_directory +00030770 fat16_read_file +000307c1 fat16_create_file +0003083f fat16_create_empty_file +000308ff fat16_directory_entries +000309e5 fat16_mbr_clear +00030a8e fat16_mbr_add_entry +00030b7f fat16_print_root_directory_entries +00030b97 fat16_change_directory +00030c1f fat16_bootblock_info +00030d9c fat16_set_time +00030dd0 fat16_set_date +00030e08 fat16_load +00030f87 fat16_format +0003123c mbr_partition_type_string +000312bf mbr_partitions_parse +00031388 mbr_get +0003138e mbr_partition_load +000313ac __list_users +0003143d __change_user +000314df __remove_user +0003158b __add_user +00031675 __find_user +0003174a __authenticate_user +00031858 __save_users +000318dc __load_users +00031ade __ksymbol_admin +00031af8 admin +00031e0c usermanager_create +00031e2b __ksymbol_snakegame +00031e45 init_game +00031e93 draw +00031eef get_input +00031f0e update +00032095 game_loop +000320bb snakegame +00032106 __msgbox +00032506 msgbox_create +00032539 msgbox_show +00032581 kevents_list +000326f3 kevents_init +00032735 kevents_destroy +0003278a kevents_add +00032841 kevents_create +000328c4 _code_end From 31c78279140add4399b7d728804f47ab5d60a623 Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Sat, 27 Jan 2024 22:37:22 +0100 Subject: [PATCH 02/23] Widget layouts --- apps/libcore.a | Bin 19986 -> 18974 bytes apps/libgraphic.a | Bin 16502 -> 15910 bytes apps/libnet.a | Bin 2520 -> 2288 bytes apps/users/users.cpp | 33 +- apps/utils/Widgets.hpp | 220 +++++-- kernel/kthreads/login.c | 1 + rootfs/symbols.map | 1327 ++++++++++++++++++++------------------- 7 files changed, 862 insertions(+), 719 deletions(-) diff --git a/apps/libcore.a b/apps/libcore.a index 32bc8387fd9cde80a96818d86d611e88336aa51f..04c196e0b8502c1f9076323733fd15738ee4e291 100644 GIT binary patch delta 6497 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 Wl|kb5`N=Vjh*y`XO_0DMiu7O0NfQbH delta 3989 zcmcgveQZ-z6u{bW)}z zaMtQLZ@^ZGIz53?)l;er4b}l;6Y9eT`wn(;_OQY3!rnfPpDY~5&xIcaU)}8WQI~*p zZ5&6>f%CU;G`61>aMDpn4O&r``a=*rsG}^=&-TjrNJl{$HEK2Jjo{GDei&yTI9JE!@Fw>%N#^dd8N9=t&Rw~=iV^uHUg+$lGl@-w z)XpJc2e5YL2+s!A&KKbYz}itFycAeFHiQGf+7ThV7C3$!FrETM9TeKu6CnhwZ8PE5 zfwe6q{5G(*dxYNu)^>{UQDALX2pZDk363M^K!GcxhG#EbHu zTze$KS^cNoZDgyjqZ!0b|3w1{R+)=3wh8lOng)mpE((6?j1R z#|NGJ#k}ve*59ppc2jLn!B&s<2Ls3IUxn0FMGr=_?|^)ABw5(6kD}8Y+I0h5(6u!? z1;AF8l`VA?Rc{IJ2!$Q|YWCWtPH08GgY=^g<aZjDN z0nPk4^tv+&_M-VG4Wzw6PaHHHFh)#<>k@hD6TZ05GKs(H_VC4J>HL`6fh?J-&=njm z265^1Sj(Ytoq?H$7!)<-l#F3I?jK_gRI*XDWEWARO@-{ms9N~xP7o-~Y7?LiCBRyt z4yAnVtQzI{Q1fPn&-VH~tf{_fcYTPl8L-OuQA7(Q;|I%ABoXm;l2#`2E!ipU$!U!B zsQN1;!I!aQ60*$%NEt)rkpyoRN%Wsb5@m%aKo+35yWySf)=MdE;L}}$O6wi>4#WVBo^Xyvl zt75x!j9)7*lsdS`Lr-`z=75_u%3nlh`%IB?T#3B3Nc;x+D;_-XD z#lA4Vo}Gay^S`ne)Y3WBmPWfWr1PSZ)a&RpIudmB+7VaJYXlCE4i__X=wfE%29jxc zs3h}2?~F9+L-%4Pq(f-u`i8Z%I02#EFh* z0)VUe!Fl;fhcMG3#!u(xNm1VH&g3|3YAb2AU5+xIwb~_pM5grB=%qh5-HeBvuB59_ zzd}C%@=RyQ8}D;E>G4D8;-{E+%T4q%p+s!>b+j6Irhi3ePU`(MUK6x=eE!9(d1q*6 z^KOsN=U>7ao9i|=ZrT#wwyk~_H1ij-y6~=D^*cfY7V$&DA39w#ZyRL0#7|rE_|k%` F{{W7xl~e!# diff --git a/apps/libgraphic.a b/apps/libgraphic.a index eb09b6ebaecf606ae3b4aa6a6892ac596c466e92..37daafef2cec2459796cb27816ae5892eb6b3219 100644 GIT binary patch delta 4488 zcmcgv4RBP|6~1rxCG2h%-X;V{Hhogd*#DDi<}fynHjW4XgZCq=gj;O3xpVpB z_L+rA7c-tKjo%tJiA`kOFBb6v(F~7@i_fRvD0eH;l05}hK>u2X@OpSrKq;_D#H#v z7+aI^zw>b>laXS9M_T!e-0Dd~UE{U*!@0iPSy^d+?sQwKm!Hio2|b|&9eUxYFro$y zl28pFP(y|4i|Ui>ZuV!w?l!}yG9V}khjPNB1rE+12*06)55V1_omh|DXcg6<;YLer z_2=BEiVWFJEpqmt<}h4<+pA$+3pjLfq&2(72{9AyHC}}QTB_wBw1!T8iZz10`V!Gd z3xbo5*;;8X92ZB;x$y6VXXrubDgn13e5xjmjOiVMM~XEGyZhuD8(s1njhBUMc~@@f zWa-{^=t{A^Ow}GrZ6FOJgG%{zKYfXKVzi|GfUC z#w?wttnHP?q~avvCCRP-PIMgc9D0wrt)_skI>FDQnk>*t3B1uDkozOgqp|O zJr%ZBM1H1vD*v{}V{_z?e*O()9fSpq$HC8erj-Tpj)|T}CE(NS0UFVK-+2Xs=i46R-#KPlew@ij0=P z-BXWpe_c@|5&x(no+=lT${G92q#9TMsJ#7g{H#r`Qqx+{t(RV{_M}rTrB77)#ra9N zxnO>SoK_oB!&*;z&r|YrU0kG&+JkQ4J>dc=W|xxlq?os%NIti>D3wyv$_dd}cPy7- z2TDYX1U!0&eNUfsO;Qb|AB>+Z7Y50bK_pat4X&uC)l=~^4mCl{<4mYY=c)K#i=1&S zkdD7&lP9U~qtmH*Nhfx`i`aEJ1aztJf@&{u;d z8cJX=+T-v^2l^~Xt$pQjz162&@JdViLkYffb`@VxwASTT)A2K+E;kHvm%pUh2WxK| z*6tXLza=We?soG&;L+vWpQKKxX{!xqW7k5cJGGSVhR*qNod1b^Ic@|doWcahiZG2z-7o2{5b-QxGDJ|#M zdDqyb`UHQ>TYltq@6T;z|E|qnmRm{jHS_iJyzA)IIC`vB*sR#MxlSg~?wjdA^MSU3 z)`1p+F1AeQ-C?L@b@oAYAE*fg)6dNFZg?JV|7=PvWG{i-*nq!*Uo>lWV%u}BMDvr) z1I^U-;fN0^B6QDzW*hqam2&TbavT0HVCWyFr$0Nr1}YuUt3w;PH9Os3QRzAaXdI8o zMa7Ir8%~&e4XJtSv7FgC<_lRm14}PMH+m`E9b>wskh|gGmvLScj@NA+yUf%=z8!Kj z*-c|%Tsx+)3JN{{!ax_~_d#AYeu2*Hd~$XlqLpPNUfJqobyOO5y?XD(% zw!srYD>oiwjS0~Ag8M*GkbrJJ6C9K9mc?^FgYDVNB*rR1bpKgwzEkNEUJh=RDBdyq6wXcMK1#Imj;TW*Bk%Z}7v38DdAF#Dm1rZDkV8Gfe zQg{~F*eGzqFM!iSTab_6SHXQCzk%)SP4Lcfco^@8L1|Dvw)B0%_%bX!3QV?$_*DxF zD_Qq#@@?Ha>in#$d((|w8*d74-MZ!Wy18sq`1aekY?tfia8K1K-qh%dP=B}Kt~3Y5 zOV_^+lRs$k@0@K4E@14mIsT$K{<6tm&GI$uO>=;} zr+cdhoDBF(zR=`V_*QJij4dHvg#TOkIB3C_Og?3;s delta 2071 zcmcgsUrbwN6hHU&-cm~8UJyD2GH}DuIWpPYU@X<)pBgf0!oNDq1}Llq5ZVP=M!TDmcxSARhw-GnDM13(n40TaoG^^`_$qbo7sOQ|?3)R%b7yXiR zf9H4p_MGoaFHSF?$;)?+Pr))0*$ddkS@*n8&Http4w0CbKTaz8-a|NKCJ=)g+ z5){FGY4ZwOHtiNP#Ua#Zlx|^PMw!!SXX@t09* zL&?{A0u`g^Z;ngF`- z^8Sr{g|YS=v3B11&jsGjN_aCzvrZFRs2T`W;XRVjX{3*<$TG`6Qz-gAvk5}Rhg~#Z zL$-f-!+!+rLnsuto*&roPow#r-2N`Dc@&-BqqLx`7ns^8@ClkX?YiS*$N{W0HO@dMHk+{k+M=g*i<3t`dJ!(?k4YiTNxDA+hA5LwwH)uDXD zprHw@f8%*z(=D{S65yaBD?&zn2MYOUcjVuXXzYskLFC46i1#2jR#DQ120t2%*(u-@ za${EF^T>@u4bP((!;}AA24E!MANEdB8vQ=L0N}8WlurC>9UsEQ z5%1FRG+_zAdpiF{$L+XWz6{_1VKKl9gcx^<&<^kxA}59bE|UQRujm2a5n{s6I$zbX z5#KD2`}PuU0(hMe?8e{f0FcO81oOlGS)v392)XYpyi217z|EKczppPP2lrRu@Cs?*q!FH TadYjjCSK;)yu5`~ILiM7^31xv diff --git a/apps/libnet.a b/apps/libnet.a index 13e4460fe89ec566faf0c2e0c94836543e1165e1..bc2a340f99b4a364929ddd4ea950b171cb8b941d 100644 GIT binary patch literal 2288 zcmcIl!D|#}6n`6IUDLEg8#Oiow^BjdX55WIsDw5)tWl^UX%|6-?Cj)Ac9Y#1+4)Aa ziWQ{b61;opK|Fc$AMhZwMLc-(rUx&Aha770;6Ye_znSmLPAF^i;Dh)5-tYb1elzcV zGqYb!xJ|G6L*M?~TFa+s5~tT(t}s4sD$0E#(hq<9A@0?KP)Vic&xz}K>YNrY@O|ZJ zsnRLkuk(N;5S6p-;Vc;z(EelFlgHZc!Ly7oG*J~9guswC_ z<)G_y|BN~!hy+Ddj&7Ns3!7q`54 z({8t~{XOvTuS94^1MR4v($-k|fBuUu`N1`LZXa*6Eu9`(F7~&IE6c@!R`K8E;$W-z zYEf$cPJXly#k6o`3~YR#NsA07M<+sWnd=h;7c ze)?=<=^s=i+Jw=D()zC*{VehYcsKnrv}5nk|AgkkcfeP#|4V28dq`h^f0NedJNi@P zZ^OS$>kA$I4f2oPp^sn=uc3F_e**e$c(?t}LOTxc+CMY}-=4m|ndJVMN*l^ntyf;Q zR|x{Xjr`!ycvf4%2V#~ijCaAQ@m{EZ4YX%N&K~SpkRJed;ha7BA)uW#`H$dsw&X{_ z?JUVl;C6Q8r@`&4$ho(j4S5yZ&Vt;2uslh=iZ%ayu%u?gi=pS%>mTPM$vO4l+2$;W zQwGl%Y#QWqN&SJr{|xeZVSd`+tii}&j&(gElLpHMuNu5%@V>!k200G?E@yDkVApv*9rKX85GZzrf7Oh?!#zsAS=L4Br5x-L)GeG_GaH z^J4vab$Qfq3nGpCeV2ssN{#-#!8nQK36m+a^f+>iaWt_#1-WTOWY`Cd?^U|rqZ>Q@ vZh~g}P4C6uX*Pr;-))Ah<1@;=Y_AAKL(mM2*<08Gp02xt>z=YjKwI|~Lp-*` literal 2520 zcmcIlL1-LR82&e#=$dXdjZtG0bp?fpcDjj+*b+2Yrd1FvwR@33c6R!b-OcVy+<8-s z1T7TB5IqPUJb3Wp$*U*v5Ks@^dlVEzu#kgdZx+_?n|UuYO-)P>{_xNLfB*N-KkvQ& zy*H1~dwsw4!syA$ty0aw)XzUFmDyU&WHd%aqzt`wC+c^@NJ+CDToTXs)tVMR39!-S0_iLNa`IU2hrPsE((RrKV=a-wTYTtHqR?MeT2_>9g^>=to)QU^?zWpwXy>%w zT%I#?n47CTpH8MR`kwph*+QX!siabnqGU*9`>r%zOU#TM#nk`0@6o^Oo4;M%DRrbH zgSgZ=_WRAjU~u*Ou^+$7$U!_dh|8qM6Z+q|`w!qIZsYj5q~rs8smU$3yy@<2xnrB| zA6xFkrhB6!AG{63Po;5@Vf2_Adjxv!wYm(U{frf%6HrRw zoeNUfC>5s4!^0n9qf8@4r98ridvEFep_h)1)PF!m%FP=t$+P^$j9&zQ3c4S^0j_=k z|2ep~pi|J@@4u1N{}$nopiZ7&&iJ1Y{|0(8&#z?sO~kJsz)xcxCZYS)p9gmqx?lZ8 za4~c`|NY$hY=HX&dOXixNXN%eUXZpc!}8}~7r?poWD~QqnG};9kjLimn@~~i&PaGg zDeb`{!po7uy)cfOWGq4HgZ^Vsa-1vqCtz*wiJu0xy(WGZ*!GtAG_dU@@r%H=cf>CP z+g=f~mhBDko4~dg#2&C+d*T+bU29@{x%!gc;O*dYxT=<-^~m?S-T&u8=UE%VLUQi3 zuN%8+><7kvZS1ecj$^pYUobW_cFWi=jjb>rhkL=;hOt+S{leI7V}CK0%fa_5#wOnZ zZWw&USaG8Dp7xrsx}VyX_4=yoX!W)h=aQ#Aahg#ijvw}VDnKjvjcgQ`^1rz@imtg}w_ce2P zA9B|}X|O#(KidL`Q!M0uX8wQWRn0rJ6xMqtb(1ISQF&HuZ4yVY{&}(7D+uzmTDlA; zxnE2&=Rs*e`Hsz-f%BOyg1F6Fgr8rR8@YAi{Or2qYauM#n0N!hBj$bP@g86;yC!g@ Yf_j>c5j%uq!1=t3Xkf=C!P>lk08^&hX#fBK diff --git a/apps/users/users.cpp b/apps/users/users.cpp index ea5e303..868ed05 100644 --- a/apps/users/users.cpp +++ b/apps/users/users.cpp @@ -14,7 +14,13 @@ class UserEditor : public Window { /* Create widgets */ widgets = new WidgetManager(); - widgets->addWidget(new Button(10, 10, 100, 12, "Button", []() { + LayoutHandle main = widgets->addLayout(new Layout( + 10, 10, + 100, 12, + VERTICAL + )); + + widgets->addWidget(main, LEFT, new Button(100, 12, "Button", []() { printf("Button pressed!\n"); })); } @@ -64,6 +70,7 @@ void editorEntry(void* arg) { return; } + class Users : public Window { public: Users(int width, int height) : Window(200, 200, "Users", 1) { @@ -72,27 +79,32 @@ class Users : public Window { /* Create widgets */ widgets = new WidgetManager(); - widgets->addWidget(new Button(10, 10, 100, 12, "Button", []() { + LayoutHandle main = widgets->addLayout(new Layout( + 10, 10, + 180, 180, + VERTICAL + )); + + widgets->addWidget(main, LEFT, new Button(100, 14, "Button", []() { printf("Button pressed!\n"); })); - widgets->addWidget(new Button(10, 30, 100, 12, "Start Edit", []() { + widgets->addWidget(main, RIGHT, new Button(100, 14, "Start Edit", []() { Thread* editor = new Thread(editorEntry, 0); editor->start(0); })); - Input* input = new Input(10, 50, 100, 12, "Input"); - widgets->addWidget(input); + Input* input = new Input(100, 12, "Input"); + widgets->addWidget(main, CENTER, input); - widgets->addWidget(new Checkbox(10, 110, true)); - widgets->addWidget(new Label(30, 110, 100, 12, "Checkbox")); - widgets->addWidget(new Checkbox(10, 130, false)); + widgets->addWidget(main, LEFT, new Checkbox(true)); + widgets->addWidget(main, LEFT, new Label(100, 12, "Checkbox")); + widgets->addWidget(main, LEFT, new Checkbox(false)); } int eventHandler(struct gfx_event* event) { - switch (event->event) - { + switch (event->event){ case GFX_EVENT_RESOLUTION: /* update screensize */ break; @@ -128,6 +140,7 @@ class Users : public Window { int main() { Users t(200, 200); + t.draw(); struct gfx_event e; while (1){ diff --git a/apps/utils/Widgets.hpp b/apps/utils/Widgets.hpp index 9b75591..8beac7f 100644 --- a/apps/utils/Widgets.hpp +++ b/apps/utils/Widgets.hpp @@ -17,6 +17,7 @@ #include #define MAX_WIDGETS 32 +#define MAX_LAYOUTS 32 typedef void (*Callback)(); @@ -42,9 +43,7 @@ class Widget { /* A simple button widget */ class Button : public Widget { public: - Button(int x, int y, int width, int height, char* text, Callback callback) { - this->x = x; - this->y = y; + Button(int width, int height, char* text, Callback callback) { this->width = width; this->height = height; this->text = text; @@ -54,7 +53,10 @@ class Button : public Widget { /* Draws the button */ void draw(Window* window) { window->drawContouredBox(x, y, width, height, focused ? COLOR_VGA_LIGHT_GRAY : 30); - window->drawText(x + 4, y + 4, text, COLOR_BLACK); + /* draw text in center */ + int textWidth = strlen(text) * 8; + int textHeight = 8; + window->drawText(x + width / 2 - textWidth / 2, y + height / 2 - textHeight / 2, text, COLOR_BLACK); } /* Ignores keyboard events */ @@ -73,12 +75,29 @@ class Button : public Widget { Callback callback; }; +class Spacing : public Widget { +public: + Spacing(int width, int height) { + this->width = width; + this->height = height; + } + + void draw(Window* window) {} + + void Keyboard(char c) {} + + void Mouse() {} + + bool focusable() { + return false; + } +}; + + /* A simple input widget */ class Input : public Widget { public: - Input(int x, int y, int width, int height, char* text) { - this->x = x; - this->y = y; + Input(int width, int height, char* text) { this->width = width; this->height = height; this->text = text; @@ -131,9 +150,7 @@ class Input : public Widget { /* A simple label widget */ class Label : public Widget { public: - Label(int x, int y, int width, int height, char* text) { - this->x = x; - this->y = y; + Label(int width, int height, char* text) { this->width = width; this->height = height; this->text = text; @@ -158,9 +175,7 @@ class Label : public Widget { /* A simple list widget */ class List : public Widget { public: - List(int x, int y, int width, int height, char** items, int itemCount) { - this->x = x; - this->y = y; + List(int width, int height, char** items, int itemCount) { this->width = width; this->height = height; this->items = items; @@ -192,9 +207,7 @@ class List : public Widget { /* Simple Checkbox widget */ class Checkbox : public Widget { public: - Checkbox(int x, int y, bool value) { - this->x = x; - this->y = y; + Checkbox(bool value) { this->width = 12; this->height = 12; this->value = value; @@ -221,44 +234,86 @@ class Checkbox : public Widget { bool value; }; -class WidgetManager { -public: - /** - * @brief Adds a widget to the widget manager - * - * @param widget The widget to add - * @return int The index of the widget in the widget manager - */ - int addWidget(Widget* widget) { - if (widgetCount >= MAX_WIDGETS) { - return -1; - } +typedef enum { + HORIZONTAL, + VERTICAL +} LayoutType; - widgets[widgetCount] = widget; - widgetCount++; +typedef enum { + LEFT, + RIGHT, + TOP, + BOTTOM, + CENTER +} LayoutPosition; + +typedef int LayoutHandle; + +class Layout { +public: + Layout(int x, int y, int width, int height, LayoutType type) { + this->x = x; + this->y = y; + this->width = width; + this->height = height; + this->type = type; + } - return widgetCount - 1; + ~Layout() { + for (int i = 0; i < widgetCount; i++) { + delete widgets[i]; + } } void draw(Window* window) { + window->drawContouredBox(x, y, width, height, 30); for (int i = 0; i < widgetCount; i++) { widgets[i]->draw(window); } } void Keyboard(char c) { - if(focusedWidget != -1){ + if (focusedWidget != -1) { widgets[focusedWidget]->Keyboard(c); } } - /** - * @brief Handles mouse events - * - * @param x coordinate - * @param y coordinate - */ - void Mouse(int x, int y) { + int addWidget(Widget* widget, LayoutPosition position) { + widgets[widgetCount] = widget; + widgetCount++; + + switch(type) { + case HORIZONTAL: + widget->x = x + offset + 2; + widget->y = y + 2; + offset += widget->width; + break; + case VERTICAL: + /* switch based on position, put widgets under each other */ + switch (position) { + case LEFT: + widget->x = x + 2; + widget->y = y + offset + 2; + break; + case RIGHT: + widget->x = x + width - widget->width -2; + widget->y = y + offset + 4; + break; + case CENTER: + /* puts widget in the middle but still stacked under last */ + widget->x = x + width / 2 - widget->width / 2; + widget->y = y + offset + 2; + break; + } + offset += widget->height; + break; + } + + + return widgetCount; + } + + void Mouse(int x, int y) { for (int i = 0; i < widgetCount; i++) { Widget* widget = widgets[i]; @@ -286,19 +341,92 @@ class WidgetManager { } } + int x; + int y; + int width; + int height; + +private: + LayoutType type; + Widget* widgets[MAX_WIDGETS]; + int widgetCount = 0; + int focusedWidget = -1; + + int offset = 0; +}; + +class WidgetManager { +public: + + ~WidgetManager() { + for (int i = 0; i < layoutCount; i++) { + delete layouts[i]; + } + } + + int addLayout(Layout* layout) { + layouts[layoutCount] = layout; + layoutCount++; - Widget* getWidget(int index) { - return widgets[index]; + return layoutCount-1; } - int getWidgetCount() { - return widgetCount; + /** + * @brief Adds a widget to the widget manager + * + * @param widget The widget to add + * @return int The index of the widget in the widget manager + */ + int addWidget(LayoutHandle lh, LayoutPosition lp, Widget* widget) { + if (lh >= layoutCount) { + return -1; + } + + layouts[lh]->addWidget(widget, lp); + + return layouts[lh]->addWidget(widget, lp);; + } + + void draw(Window* window) { + for (int i = 0; i < layoutCount; i++) { + layouts[i]->draw(window); + } + } + + void Keyboard(char c) { + if (focusedLayout != -1) { + layouts[focusedLayout]->Keyboard(c); + } + } + + /** + * @brief Handles mouse events + * + * @param x coordinate + * @param y coordinate + */ + void Mouse(int x, int y) { + for (int i = 0; i < layoutCount; i++) { + Layout* layout = layouts[i]; + + /* Check if the widget is focusable and the mouse is within its bounds */ + bool isWithinBounds = + x >= layout->x && x <= layout->x + layout->width && + y >= layout->y && y <= layout->y + layout->height; + + focusedLayout = i; + + if (isWithinBounds) { + layout->Mouse(x, y); + return; + } + } } private: - Widget* widgets[MAX_WIDGETS]; - int widgetCount = 0; - int focusedWidget = -1; + Layout* layouts[MAX_LAYOUTS]; + int layoutCount = 0; + int focusedLayout = -1; }; diff --git a/kernel/kthreads/login.c b/kernel/kthreads/login.c index 5de88a5..83b38d0 100644 --- a/kernel/kthreads/login.c +++ b/kernel/kthreads/login.c @@ -137,6 +137,7 @@ void __kthread_entry login() } gfx_set_taskbar(0); + kernel_exit(); return; } } diff --git a/rootfs/symbols.map b/rootfs/symbols.map index 4419425..73c2862 100644 --- a/rootfs/symbols.map +++ b/rootfs/symbols.map @@ -222,666 +222,667 @@ 0001831c __pcb_queue_add 00018395 __pcb_queue_push 0001842e pcb_new_queue -0001845f memory_map_init -00018526 memory_map_get -0001852c free -00018596 malloc -00018632 calloc -00018665 get_mem_info -000186bd init_memory -0001874f vmem_free -000187bf vmem_alloc -0001882c vmem_free_page_region -00018992 vmem_page_region_alloc -000189cd vmem_create_page_region -00018b11 vmem_free_allocations -00018c40 vmem_continious_allocation_map -00018c46 vmem_free_allocation -00018c47 vmem_stack_free -00018cf8 vmem_stack_alloc -0001907d vmem_dump_heap -00019112 vmem_init_process_thread -00019203 vmem_init_process -00019531 vmem_cleanup_process_thead -000195a8 vmem_cleanup_process -00019796 vmem_init_kernel -00019957 vmem_allocator_create -000199bb vmem_map_driver_region -00019a39 vmem_total_usage -00019a4c vmem_init -00019b7e kalloc -00019d15 kcalloc -00019d47 kfree -00019ddd palloc -00019e1f pmemory_used -00019e3b kmemory_used -00019e41 kmemory_total -00019e4d kmem_init -00019eea e1000_receive -00019fc5 e1000_transmit -0001a087 e1000_callback -0001a0ae _e1000_tx_init -0001a152 _e1000_rx_init -0001a1ec e1000_attach -0001a41c display_get_info -0001a485 kenv_init -0001a49c kenv_set -0001a4d1 config_list -0001a5a2 kernel_config_load -0001a98d config_get_value -0001aa48 spin_lock -0001aa68 spin_unlock -0001aa76 mutex_init -0001aa93 acquire -0001ab30 release -0001abd2 kthread_entry -0001ac2c kthread_list -0001ac93 register_kthread -0001ad6c start -0001ae0e ata_primary -0001ae0f ata_secondary -0001ae10 ata_wait -0001ae8a ata_write -0001b001 ata_read -0001b191 ata_ide_init -0001b361 set_bitmap -0001b383 unset_bitmap -0001b3a7 get_bitmap -0001b3c9 get_bitmap_size -0001b3dd create_bitmap -0001b411 destroy_bitmap -0001b424 bitmap_unset_continous -0001b45e bitmap_get_continous -0001b4fa get_free_bitmap -0001b54f __rtc_check_in_progress -0001b571 __rtc_get_register -0001b591 get_current_time -0001b6dc get_time -0001b706 init_tss -0001b734 exec_cmd -0001b838 __ksymbol_exec_cmd -0001b852 system_reboot -0001b886 align_to_pointer_size -0001b894 calculate_size_unit -0001b8f6 advanced_hash -0001b92a kernel_panic -0001b948 kref_init -0001b962 kref_get -0001b98a kref_put -0001b9b2 csprintf -0001bbb3 script_parse -0001bc88 login -0001c021 __login_create_virt_disk -0001c04b __register_kthread_login -0001c065 help -0001c306 clear -0001c327 __ksymbol_new -0001c341 __ksymbol_list -0001c35b __ksymbol_color -0001c375 __ksymbol_about -0001c38f __ksymbol_help -0001c3a9 __ksymbol_kevents -0001c3c3 __ksymbol_view -0001c3dd __ksymbol_file -0001c3f7 __ksymbol_tcp -0001c411 __ksymbol_conf -0001c42b __ksymbol_clear -0001c445 __ksymbol_services -0001c45f __ksymbol_reboot -0001c479 kevents -0001c553 services -0001c781 new -0001c8c2 list -0001c9c2 file -0001cb90 color -0001cc31 about -0001cc6e view -0001ce83 tcp -0001d160 __tcp_reader -0001d281 conf -0001d549 reboot -0001d582 attach_disk_dev -0001d5a6 disk_attached -0001d5ae disk_name -0001d5b7 disk_device_get -0001d5bd disk_size -0001d5d9 write_block -0001d616 write_block_offset -0001d659 read_block -0001d696 read_block_offset -0001d700 sched_consume -0001d741 sched_add -0001d79b sched_prioritize -0001d850 sched_round_robin -0001da36 sched_exit -0001daef sched_block -0001dc0d sched_default -0001dce7 sched_sleep -0001dd8d sched_init_default -0001de0e get_scheduler -0001de14 kernel_sleep -0001de2f kernel_yield -0001de72 kernel_exit -0001dea4 block -0001decd unblock -0001dece work_queue_add -0001dfb6 init_worker -0001dfce worker_thread -0001e06d __ring_buffer_add -0001e115 __ring_buffer_read -0001e21f rbuffer_new -0001e288 rbuffer_free -0001e2aa error_get_string -0001e2e6 kclock -0001e7c6 __register_kthread_kclock -0001e7e0 tar_extract -0001ea30 __ksymbol_tar -0001ea4a tar_list -0001eb54 tar -0001eddd rgb_to_vga -0001eded rgb_to_components -0001ee14 color_distance_squared -0001ee7f rgb_init_color_table -0001ef10 iface_loopback_write -0001efd1 iface_loopback_interrupt -0001efe8 iface_loopback_read -0001f08b net_init_loopback -0001f0a2 serial_put -0001f0e2 serial_write -0001f124 serial_printf -0001f2c4 init_serial -0001f38a inportb -0001f393 inportw -0001f39d inportl -0001f3a6 outportb -0001f3b4 outportw -0001f3c3 outportl -0001f3d0 sys_create_thread -0001f3ef __add_systemcall_sys_create_thread -0001f3fa add_system_call -0001f43a system_call -0001f4a5 hashmap_put -0001f50c hashmap_get -0001f590 hashmap_add -0001f61a hashmap_free -0001f61b reset_vga_palette -0001f661 vga_set_palette -0001f74c b8to16 -0001f75c vesa_put_pixel -0001f786 vesa_put_box -0001f801 vesa_put_block -0001f87c vesa_put_char -0001f8f7 vesa_put_char16 -0001f98a vesa_put_icon16 -0001fa03 vesa_write -0001fa42 vesa_write_str -0001fa70 vesa_fill -0001faf2 vesa_fillrect -0001fb64 vesa_inner_box -0001fc6c vesa_printf -0001fed9 ksyms_init -00020100 ksyms_add_symbol -000201b9 __ksymbol_backtrace -000201d3 ksyms_list -00020235 ksyms_resolve_symbol -000202e8 __backtrace_from -00020405 backtrace -00020416 ws_fullscreen -00020590 ws_remove -00020640 ws_add -0002072b ws_destroy -000207d1 ws_draw -00020a7e ws_raw_wallpaper -00020b64 ws_set_background_file -00020e41 ws_init -00020f24 ws_set_background -00020fcf ws_new -0002105c encode_run_length -000210d9 decode_run_length -00021144 __mouse_handler -0002125b mouse_wait -000212a3 mouse_write -000212e5 mouse_get_event -00021326 mouse_init -0002140b sys_ipc_open -00021459 __add_systemcall_sys_ipc_open -00021470 __add_systemcall_sys_ipc_close -00021487 __add_systemcall_sys_ipc_send -0002149e __add_systemcall_sys_ipc_receive -000214b5 sys_ipc_close -000214fe sys_ipc_send -00021565 sys_ipc_receive -000215cb sysinf -0002231d __register_kthread_sysinf -00022337 echo -00022372 res -000223b3 ifconfig -000223c0 __ksymbol_ifconfig -000223da __ksymbol_ps -000223f4 __ksymbol_tree -0002240e __ksymbol_fat16 -00022428 __ksymbol_xxd -00022442 __ksymbol_sh -0002245c __ksymbol_ed -00022476 __ksymbol_exec -00022490 __ksymbol_ths -000224aa __ksymbol_dns -000224c4 __ksymbol_th -000224de __ksymbol_kill -000224f8 __ksymbol_echo -00022512 __ksymbol_fdisk -0002252c __ksymbol_meminfo -00022546 __ksymbol_res -00022560 __ksymbol_bg -0002257a __ksymbol_exit -00022594 __ksymbol_socks -000225ae __ksymbol_reset -000225c8 exit -000225fc ps -00022870 print_pcb_tree -0002296f tree -000229af fat16 -000229d7 xxd -00022acc sh -00022bcc ed -00022c19 exec -00022d7d ths -00022de9 dns -00022e5d th -00022e7b kill -00022e99 fdisk -0002302b meminfo -0002320a bg -00023289 socks -0002352f __register_kthread_shell -00023549 __register_kthread_textshell -00023563 shell_clear -000235a6 reset_shell -00023617 reset -0002366b shell_put -0002384c shell -00023aad cleanup_function -00023ad4 testfn -00023b08 draw_box -00023bed __textshell_reset_box -00023c7d textshell -0002404e __net_find_interface -000240ae net_drop_packet -000240cf net_handle_recieve -000241f6 net_get_interfaces -000241fc net_configure_iface -0002424e net_incoming_packet -000242ff net_get_iface -00024375 net_iface_up -0002439c net_iface_down -000243c3 net_list_ifaces -000244dd net_register_interface -0002450e net_send_skb -00024596 net_get_info -000245bd networking_main -0002479d __dhcp_add_option -0002480d __dhcp_send_discovery -0002494f __dhcp_send_request -00024acc dhcp_get_state -00024ad4 dhcp_get_dns -00024ada dhcp_get_ip -00024aef dhcp_get_gw -00024b04 dhcpd -00024d83 udp_server -00024e0e tcp_server -00024f82 __net_terminal_writef -00024fe7 __register_kthread_tcp_server -00025001 __register_kthread_udp_server -0002501b __register_kthread_udptest -00025035 udptest -000250c0 tcpd -000251a4 logd -0002520f __register_kthread_logd -00025229 logd_attach_by_pid -0002526d taskbar_reboot -00025299 __reboot -000252ae taskbar_readme -000252c7 taskbar_about -000252e0 taskbar_clock -000252f9 taskbar_sysinf -00025312 taskbar_bg_retro -00025349 taskbar_bg_lotr2 -0002535e taskbar_bg_lotr -00025373 taskbar_bg_default_color_gray -00025385 taskbar_bg_default_color -00025397 taskbar_wolfstein -000253d2 taskbar_bg_graph -0002540d taskbar_bg_calc -00025448 taskbar_colors -00025483 taskbar_cube -000254be taskbar_editor -000254f9 taskbar_finder -00025534 taskbar_terminal -0002557d __register_kthread_taskbar -00025597 taskbar_hdr_opt_event -00025621 taskbar -00025bd8 about -00025da3 __register_kthread_about -00025dbd __register_kthread_readme -00025dd7 readme -00025f39 gfx_default_hover -00026058 gfx_destory_window -000260e5 gfx_window_resize -0002618e gfx_window_maximize -00026207 gfx_default_mouse_up -000262d5 gfx_default_mouse_down -00026397 gfx_default_click -00026586 gfx_draw_window -00027372 gfx_window_set_resizable -00027387 kernel_gfx_window_border_color -000273b2 gfx_new_window -00027612 gfx_point_in_rectangle -0002763f gfx_draw_component -00027681 gfx_input_event -000277b3 gfx_input_draw -000278bb gfx_input_manager_add -0002791c gfx_composition_remove_window -00027946 gfx_composition_add_window -0002798d gfx_set_background_color -000279de gfx_raw_background -00027a2b gfx_decode_background_image -00027a78 gfx_set_taskbar -00027b18 gfx_compositor_main -00027b8c kernel_gfx_draw_circle_helper -00027e38 gfx_get_window_width -00027e4d gfx_get_window_height -00027e62 gfx_push_event -00027f1e gfx_put_icon16 -00028016 gfx_put_icon32 -0002810e gfx_event_loop -0002822d kernel_gfx_draw_rectangle -00028327 kernel_gfx_draw_contoured_box -000283c7 kernel_gfx_draw_pixel -00028465 kernel_gfx_draw_bitmap -00028583 kernel_gfx_draw_char -00028683 kernel_gfx_set_position -0002869f gfx_commit -000286b8 kernel_gfx_draw_text -0002876b gfx_button_ext -0002889e gfx_button -000288bc kernel_gfx_set_title -00028928 kernel_gfx_set_header -00028994 kernel_gfx_draw_line -00028b2f kernel_gfx_draw_circle -00028bae kernel_gfx_draw_section -00028bb4 kernel_gfx_draw_format_text -00028f06 gfx_syscall_hook -000290bd gfx_total_themes -000290c3 kernel_gfx_current_theme -000290c9 kernel_gfx_update_theme -00029197 kernel_gfx_default_theme -0002919d kernel_gfx_set_theme -000291c2 kernel_gfx_get_theme -000291dd gfx_new_ctx -00029239 gfx_init_framebuffer -000293a5 netdev_attach_driver -0002944e is_netdev_attached -0002945c netdev_transmit -00029477 netdev_recieve -000294a0 net_ethernet_add_header -00029534 net_ethernet_parse -000295a8 __skb_queue_remove -000295e6 __skb_queue_add -00029636 skb_free_queue -0002966e skb_new_queue -000296d5 skb_free -00029710 skb_new -0002977b skb_consume -000297ac __net_arp_send -0002986c net_init_arp -000298b8 net_arp_add_entry -00029947 net_arp_find_entry -00029992 net_arp_respond -00029a07 net_net_arp_request -00029a8d arp_parse -00029b37 net_ipv4_print -00029b3d net_ipv4_add_header -00029c74 net_is_ipv4 -00029cb1 net_ipv4_parse -00029dde ntohl -00029e0a htonl -00029e1d ntohs -00029e2a htons -00029e37 checksum -00029e8e transport_checksum -00029ee3 ip_to_int -00029f81 net_icmp_handle -0002a046 net_icmp_response -0002a04c net_icmp_request -0002a10f ping -0002a168 net_icmp_parse -0002a1d8 net_udp_send -0002a30d net_udp_parse -0002a435 socket_type_to_str -0002a444 socket_domain_to_str -0002a453 socket_protocol_to_str -0002a462 net_sock_bind -0002a4ad net_get_sockets -0002a4c9 sock_get -0002a4ea get_total_sockets -0002a4f0 net_sock_is_established -0002a534 net_sock_awaiting_ack -0002a578 net_sock_data_ready -0002a5d1 net_sock_read -0002a6d3 net_sock_add_data -0002a933 sock_find_listen_tcp -0002a977 net_sock_find_tcp -0002ab69 net_prepare_tcp_sock -0002abf5 net_sock_accept -0002ac08 net_socket_find_udp -0002ac73 kernel_sock_shutdown -0002aca0 kernel_sock_cleanup -0002ad26 kernel_sock_close -0002ad5a kernel_socket_create -0002aedd net_init_sockets -0002af23 gethostname -0002b43d __add_systemcall_gethostname -0002b454 net_init_dns -0002b483 route -0002b4d0 tcb_init -0002b4ee tcb_new -0002b65a tcp_state_to_str -0002b673 tcp_new_connection -0002b6fb tcp_free_connection -0002b71e tcp_is_listening -0002b734 tcp_set_listening -0002b794 tcp_calculate_checksum -0002b858 __tcp_send -0002b974 tcp_send_segment -0002bab7 tcp_accept_connection -0002bbf9 tcp_send_ack -0002bd2f tcp_read -0002bd35 tcp_recv_segment -0002bd3b tcp_connect -0002bdde tcp_send_syn -0002bde4 tcp_recv_ack -0002be67 tcp_recv_fin -0002be6d tcp_recv_syn -0002bf9f tcp_send_fin -0002c06b tcp_close_connection -0002c0aa tcp_parse -0002c543 kernel_bind -0002c578 kernel_recvfrom -0002c57e kernel_recv -0002c5f0 kernel_recv_timeout -0002c616 kernel_connect -0002c71a kernel_sendto -0002c7d4 kernel_accept -0002c837 kernel_listen -0002c85f kernel_send -0002c8e5 sys_kernel_bind -0002c917 __add_systemcall_sys_kernel_bind -0002c92e __add_systemcall_sys_kernel_accept -0002c945 __add_systemcall_sys_kernel_connect -0002c95c __add_systemcall_sys_kernel_listen -0002c973 __add_systemcall_sys_kernel_recv -0002c98a __add_systemcall_sys_kernel_recvfrom -0002c9a1 __add_systemcall_sys_kernel_recv_timeout -0002c9b8 __add_systemcall_sys_kernel_send -0002c9cf __add_systemcall_sys_kernel_sendto -0002c9e6 __add_systemcall_sys_socket_create -0002c9fd __add_systemcall_sys_kernel_sock_close -0002ca14 sys_kernel_accept -0002ca54 sys_kernel_connect -0002ca86 sys_kernel_listen -0002cab5 sys_kernel_recv -0002caed sys_kernel_recvfrom -0002cb2d sys_kernel_recv_timeout -0002cb6b sys_kernel_send -0002cba3 sys_kernel_sendto -0002cbe3 sys_socket_create -0002cc0a sys_kernel_sock_close -0002cc4b __iface_send -0002cc7a __iface_recieve -0002cca9 __iface_assign -0002ccbc __iface_detach -0002ccd0 __iface_set_gateway -0002cce3 __iface_set_netmask -0002ccf6 __iface_configure -0002cd46 __iface_attach -0002cd6b net_interface_create -0002cda3 net_register_netdev -0002cebb net_interface_destroy -0002ced0 __default_restart -0002ced6 __default_stop -0002cf3b __default_start -0002cfb5 nm_new -0002d03e nm_free -0002d083 net_firewall_create -0002d0a6 fs_file2fd -0002d10d fs_alloc_file -0002d158 fs_free_file -0002d1b2 fs_register -0002d281 fs_init -0002d287 fs_unregister -0002d2ea fs_get -0002d2f0 fs_close -0002d362 fs_open -0002d3dc fs_seek -0002d459 fs_read -0002d56e fs_load_from_file -0002d5fa fs_write -0002d6b5 fs_save_to_file -0002d741 fat16_rmdir -0002d747 fat16_stat -0002d74d fat16_close -0002d7b7 fat16_rename -0002d84c fat16_mkdir -0002d931 fat16_remove -0002d9a4 fat16_open -0002daee fat16_read -0002dc52 fat16_write -0002dd81 fat16_list -0002e04f fat16_init -0002e103 path_next_iter -0002e172 inode_from_path_recursise -0002e1f0 inode_from_path -0002e2ae ext_get_root -0002e2b7 ext_get_current_dir -0002e2c6 ext_get_size -0002e2cc ext_get_inodes -0002e2d2 ext_get_blocks -0002e2d8 ext_sync -0002e34b ext_create -0002e436 ext_read -0002e4b1 ext_seek -0002e4f8 ext_write -0002e564 ext_close -0002e5c6 ext_open_from_directory -0002e6cc ext_open -0002e783 ext_size -0002e7ac change_directory -0002e812 ext_create_directory -0002e9ac ext_create_file_system -0002ec79 init_ext -0002ee15 listdir -0002ef36 __inode_sync -0002ef99 __inode_cache_insert -0002f08f __inode_load -0002f103 inodes_sync -0002f13e inode_get -0002f19b inode_read -0002f383 inode_write -0002f5e1 alloc_inode -0002f69a mkdir -0002f747 sync -0002f77b mkfs -0002f788 fat16_read_data_from_cluster -0002f7d6 fat16_read_data -0002f8b7 fat16_find_cluster_by_offset -0002f932 fat16_write_data_to_cluster_with_offset -0002f96d fat16_print_cluster_chain -0002f99b fat16_write_data_to_cluster -0002f9ce fat16_write_data -0002faea get_fat_start_block -0002faf2 get_root_directory_start_block -0002fb01 get_data_start_block -0002fb13 fat16_get_fat_entry -0002fb2e fat16_set_fat_entry -0002fb6e fat16_sync_fat_table -0002fbe6 fat16_allocate_cluster -0002fbfe fat16_free_cluster -0002fc13 fat16_get_free_cluster -0002fc68 fat16_sync_directory_entry -0002fcea fat16_read_entry -0002fd97 fat16_find_entry -0002fed2 fat16_rename_entry -0002ff43 fat16_free_clusters -0002ff8a fat16_delete_entry -0002fff1 fat16_add_entry -00030158 fat16_used_blocks -00030191 fat16_to_upper -000301bd fat16_name_compare -000302e2 sstrtok -000303a3 fat16_directory_entry_debug -00030473 fat16_get_directory_entry -0003066b fat16_create_directory -00030770 fat16_read_file -000307c1 fat16_create_file -0003083f fat16_create_empty_file -000308ff fat16_directory_entries -000309e5 fat16_mbr_clear -00030a8e fat16_mbr_add_entry -00030b7f fat16_print_root_directory_entries -00030b97 fat16_change_directory -00030c1f fat16_bootblock_info -00030d9c fat16_set_time -00030dd0 fat16_set_date -00030e08 fat16_load -00030f87 fat16_format -0003123c mbr_partition_type_string -000312bf mbr_partitions_parse -00031388 mbr_get -0003138e mbr_partition_load -000313ac __list_users -0003143d __change_user -000314df __remove_user -0003158b __add_user -00031675 __find_user -0003174a __authenticate_user -00031858 __save_users -000318dc __load_users -00031ade __ksymbol_admin -00031af8 admin -00031e0c usermanager_create -00031e2b __ksymbol_snakegame -00031e45 init_game -00031e93 draw -00031eef get_input -00031f0e update -00032095 game_loop -000320bb snakegame -00032106 __msgbox -00032506 msgbox_create -00032539 msgbox_show -00032581 kevents_list -000326f3 kevents_init -00032735 kevents_destroy -0003278a kevents_add -00032841 kevents_create -000328c4 _code_end +0001845f get_mem_info +000184b7 memory_map_init +0001857e memory_map_get +00018584 free +000185db malloc +00018677 calloc +000186aa krealloc +00018716 init_memory +000187a8 vmem_free +00018818 vmem_alloc +00018885 vmem_free_page_region +000189eb vmem_page_region_alloc +00018a26 vmem_create_page_region +00018b6a vmem_free_allocations +00018c99 vmem_continious_allocation_map +00018c9f vmem_free_allocation +00018ca0 vmem_stack_free +00018d51 vmem_stack_alloc +000190d6 vmem_dump_heap +0001916b vmem_init_process_thread +0001925c vmem_init_process +0001958a vmem_cleanup_process_thead +00019601 vmem_cleanup_process +000197ef vmem_init_kernel +000199b0 vmem_allocator_create +00019a14 vmem_map_driver_region +00019a92 vmem_total_usage +00019aa5 vmem_init +00019bd7 kalloc +00019d6e kcalloc +00019da0 kfree +00019e36 palloc +00019e78 pmemory_used +00019e94 kmemory_used +00019e9a kmemory_total +00019ea6 kmem_init +00019f43 e1000_receive +0001a01e e1000_transmit +0001a0e0 e1000_callback +0001a107 _e1000_tx_init +0001a1ab _e1000_rx_init +0001a245 e1000_attach +0001a475 display_get_info +0001a4de kenv_init +0001a4f5 kenv_set +0001a52a config_list +0001a5fb kernel_config_load +0001a9e6 config_get_value +0001aaa1 spin_lock +0001aac1 spin_unlock +0001aacf mutex_init +0001aaec acquire +0001ab89 release +0001ac2b kthread_entry +0001ac85 kthread_list +0001acec register_kthread +0001adc5 start +0001ae67 ata_primary +0001ae68 ata_secondary +0001ae69 ata_wait +0001aee3 ata_write +0001b05a ata_read +0001b1ea ata_ide_init +0001b3ba set_bitmap +0001b3dc unset_bitmap +0001b400 get_bitmap +0001b422 get_bitmap_size +0001b436 create_bitmap +0001b46a destroy_bitmap +0001b47d bitmap_unset_continous +0001b4b7 bitmap_get_continous +0001b553 get_free_bitmap +0001b5a8 __rtc_check_in_progress +0001b5ca __rtc_get_register +0001b5ea get_current_time +0001b735 get_time +0001b75f init_tss +0001b78d exec_cmd +0001b891 __ksymbol_exec_cmd +0001b8ab system_reboot +0001b8df align_to_pointer_size +0001b8ed calculate_size_unit +0001b94f advanced_hash +0001b983 kernel_panic +0001b9a1 kref_init +0001b9bb kref_get +0001b9e3 kref_put +0001ba0b csprintf +0001bc0c script_parse +0001bce1 login +0001c07f __login_create_virt_disk +0001c0a9 __register_kthread_login +0001c0c3 help +0001c364 clear +0001c385 __ksymbol_new +0001c39f __ksymbol_list +0001c3b9 __ksymbol_color +0001c3d3 __ksymbol_about +0001c3ed __ksymbol_help +0001c407 __ksymbol_kevents +0001c421 __ksymbol_view +0001c43b __ksymbol_file +0001c455 __ksymbol_tcp +0001c46f __ksymbol_conf +0001c489 __ksymbol_clear +0001c4a3 __ksymbol_services +0001c4bd __ksymbol_reboot +0001c4d7 kevents +0001c5b1 services +0001c7df new +0001c920 list +0001ca20 file +0001cbee color +0001cc8f about +0001cccc view +0001cee1 tcp +0001d1be __tcp_reader +0001d2df conf +0001d5a7 reboot +0001d5e0 attach_disk_dev +0001d604 disk_attached +0001d60c disk_name +0001d615 disk_device_get +0001d61b disk_size +0001d637 write_block +0001d674 write_block_offset +0001d6b7 read_block +0001d6f4 read_block_offset +0001d75e sched_consume +0001d79f sched_add +0001d7f9 sched_prioritize +0001d8ae sched_round_robin +0001da94 sched_exit +0001db4d sched_block +0001dc6b sched_default +0001dd45 sched_sleep +0001ddeb sched_init_default +0001de6c get_scheduler +0001de72 kernel_sleep +0001de8d kernel_yield +0001ded0 kernel_exit +0001df02 block +0001df2b unblock +0001df2c work_queue_add +0001e014 init_worker +0001e02c worker_thread +0001e0cb __ring_buffer_add +0001e173 __ring_buffer_read +0001e27d rbuffer_new +0001e2e6 rbuffer_free +0001e308 error_get_string +0001e344 kclock +0001e824 __register_kthread_kclock +0001e83e tar_extract +0001ea8e __ksymbol_tar +0001eaa8 tar_list +0001ebb2 tar +0001ee3b rgb_to_vga +0001ee4b rgb_to_components +0001ee72 color_distance_squared +0001eedd rgb_init_color_table +0001ef6e iface_loopback_write +0001f02f iface_loopback_interrupt +0001f046 iface_loopback_read +0001f0e9 net_init_loopback +0001f100 serial_put +0001f140 serial_write +0001f182 serial_printf +0001f322 init_serial +0001f3e8 inportb +0001f3f1 inportw +0001f3fb inportl +0001f404 outportb +0001f412 outportw +0001f421 outportl +0001f42e sys_create_thread +0001f44d __add_systemcall_sys_create_thread +0001f458 add_system_call +0001f498 system_call +0001f503 hashmap_put +0001f56a hashmap_get +0001f5ee hashmap_add +0001f678 hashmap_free +0001f679 reset_vga_palette +0001f6bf vga_set_palette +0001f7aa b8to16 +0001f7ba vesa_put_pixel +0001f7e4 vesa_put_box +0001f85f vesa_put_block +0001f8da vesa_put_char +0001f955 vesa_put_char16 +0001f9e8 vesa_put_icon16 +0001fa61 vesa_write +0001faa0 vesa_write_str +0001face vesa_fill +0001fb50 vesa_fillrect +0001fbc2 vesa_inner_box +0001fcca vesa_printf +0001ff37 ksyms_init +0002015e ksyms_add_symbol +00020217 __ksymbol_backtrace +00020231 ksyms_list +00020293 ksyms_resolve_symbol +00020346 __backtrace_from +00020463 backtrace +00020474 ws_fullscreen +000205ee ws_remove +0002069e ws_add +00020789 ws_destroy +0002082f ws_draw +00020adc ws_raw_wallpaper +00020bc2 ws_set_background_file +00020e9f ws_init +00020f82 ws_set_background +0002102d ws_new +000210ba encode_run_length +00021137 decode_run_length +000211a2 __mouse_handler +000212b9 mouse_wait +00021301 mouse_write +00021343 mouse_get_event +00021384 mouse_init +00021469 sys_ipc_open +000214b7 __add_systemcall_sys_ipc_open +000214ce __add_systemcall_sys_ipc_close +000214e5 __add_systemcall_sys_ipc_send +000214fc __add_systemcall_sys_ipc_receive +00021513 sys_ipc_close +0002155c sys_ipc_send +000215c3 sys_ipc_receive +00021629 sysinf +0002237b __register_kthread_sysinf +00022395 echo +000223d0 res +00022411 ifconfig +0002241e __ksymbol_ifconfig +00022438 __ksymbol_ps +00022452 __ksymbol_tree +0002246c __ksymbol_fat16 +00022486 __ksymbol_xxd +000224a0 __ksymbol_sh +000224ba __ksymbol_ed +000224d4 __ksymbol_exec +000224ee __ksymbol_ths +00022508 __ksymbol_dns +00022522 __ksymbol_th +0002253c __ksymbol_kill +00022556 __ksymbol_echo +00022570 __ksymbol_fdisk +0002258a __ksymbol_meminfo +000225a4 __ksymbol_res +000225be __ksymbol_bg +000225d8 __ksymbol_exit +000225f2 __ksymbol_socks +0002260c __ksymbol_reset +00022626 exit +0002265a ps +000228ce print_pcb_tree +000229cd tree +00022a0d fat16 +00022a35 xxd +00022b2a sh +00022c2a ed +00022c77 exec +00022ddb ths +00022e47 dns +00022ebb th +00022ed9 kill +00022ef7 fdisk +00023089 meminfo +00023268 bg +000232e7 socks +0002358d __register_kthread_shell +000235a7 __register_kthread_textshell +000235c1 shell_clear +00023604 reset_shell +00023675 reset +000236c9 shell_put +000238aa shell +00023b0b cleanup_function +00023b32 testfn +00023b66 draw_box +00023c4b __textshell_reset_box +00023cdb textshell +000240ac __net_find_interface +0002410c net_drop_packet +0002412d net_handle_recieve +00024254 net_get_interfaces +0002425a net_configure_iface +000242ac net_incoming_packet +0002435d net_get_iface +000243d3 net_iface_up +000243fa net_iface_down +00024421 net_list_ifaces +0002453b net_register_interface +0002456c net_send_skb +000245f4 net_get_info +0002461b networking_main +000247fb __dhcp_add_option +0002486b __dhcp_send_discovery +000249ad __dhcp_send_request +00024b2a dhcp_get_state +00024b32 dhcp_get_dns +00024b38 dhcp_get_ip +00024b4d dhcp_get_gw +00024b62 dhcpd +00024de1 udp_server +00024e6c tcp_server +00024fe0 __net_terminal_writef +00025045 __register_kthread_tcp_server +0002505f __register_kthread_udp_server +00025079 __register_kthread_udptest +00025093 udptest +0002511e tcpd +00025202 logd +0002526d __register_kthread_logd +00025287 logd_attach_by_pid +000252cb taskbar_reboot +000252f7 __reboot +0002530c taskbar_readme +00025325 taskbar_about +0002533e taskbar_clock +00025357 taskbar_sysinf +00025370 taskbar_bg_retro +000253a7 taskbar_bg_lotr2 +000253bc taskbar_bg_lotr +000253d1 taskbar_bg_default_color_gray +000253e3 taskbar_bg_default_color +000253f5 taskbar_wolfstein +00025430 taskbar_bg_graph +0002546b taskbar_bg_calc +000254a6 taskbar_colors +000254e1 taskbar_cube +0002551c taskbar_editor +00025557 taskbar_finder +00025592 taskbar_terminal +000255db __register_kthread_taskbar +000255f5 taskbar_hdr_opt_event +0002567f taskbar +00025c36 about +00025e01 __register_kthread_about +00025e1b __register_kthread_readme +00025e35 readme +00025f97 gfx_default_hover +000260b6 gfx_destory_window +00026143 gfx_window_resize +000261ec gfx_window_maximize +00026265 gfx_default_mouse_up +00026333 gfx_default_mouse_down +000263f5 gfx_default_click +000265e4 gfx_draw_window +000273d0 gfx_window_set_resizable +000273e5 kernel_gfx_window_border_color +00027410 gfx_new_window +00027670 gfx_point_in_rectangle +0002769d gfx_draw_component +000276df gfx_input_event +00027811 gfx_input_draw +00027919 gfx_input_manager_add +0002797a gfx_composition_remove_window +000279a4 gfx_composition_add_window +000279eb gfx_set_background_color +00027a3c gfx_raw_background +00027a89 gfx_decode_background_image +00027ad6 gfx_set_taskbar +00027b76 gfx_compositor_main +00027bea kernel_gfx_draw_circle_helper +00027e96 gfx_get_window_width +00027eab gfx_get_window_height +00027ec0 gfx_push_event +00027f7c gfx_put_icon16 +00028074 gfx_put_icon32 +0002816c gfx_event_loop +0002828b kernel_gfx_draw_rectangle +00028385 kernel_gfx_draw_contoured_box +00028425 kernel_gfx_draw_pixel +000284c3 kernel_gfx_draw_bitmap +000285e1 kernel_gfx_draw_char +000286e1 kernel_gfx_set_position +000286fd gfx_commit +00028716 kernel_gfx_draw_text +000287c9 gfx_button_ext +000288fc gfx_button +0002891a kernel_gfx_set_title +00028986 kernel_gfx_set_header +000289f2 kernel_gfx_draw_line +00028b8d kernel_gfx_draw_circle +00028c0c kernel_gfx_draw_section +00028c12 kernel_gfx_draw_format_text +00028f64 gfx_syscall_hook +0002911b gfx_total_themes +00029121 kernel_gfx_current_theme +00029127 kernel_gfx_update_theme +000291f5 kernel_gfx_default_theme +000291fb kernel_gfx_set_theme +00029220 kernel_gfx_get_theme +0002923b gfx_new_ctx +00029297 gfx_init_framebuffer +00029403 netdev_attach_driver +000294ac is_netdev_attached +000294ba netdev_transmit +000294d5 netdev_recieve +000294fe net_ethernet_add_header +00029592 net_ethernet_parse +00029606 __skb_queue_remove +00029644 __skb_queue_add +00029694 skb_free_queue +000296cc skb_new_queue +00029733 skb_free +0002976e skb_new +000297d9 skb_consume +0002980a __net_arp_send +000298ca net_init_arp +00029916 net_arp_add_entry +000299a5 net_arp_find_entry +000299f0 net_arp_respond +00029a65 net_net_arp_request +00029aeb arp_parse +00029b95 net_ipv4_print +00029b9b net_ipv4_add_header +00029cd2 net_is_ipv4 +00029d0f net_ipv4_parse +00029e3c ntohl +00029e68 htonl +00029e7b ntohs +00029e88 htons +00029e95 checksum +00029eec transport_checksum +00029f41 ip_to_int +00029fdf net_icmp_handle +0002a0a4 net_icmp_response +0002a0aa net_icmp_request +0002a16d ping +0002a1c6 net_icmp_parse +0002a236 net_udp_send +0002a36b net_udp_parse +0002a493 socket_type_to_str +0002a4a2 socket_domain_to_str +0002a4b1 socket_protocol_to_str +0002a4c0 net_sock_bind +0002a50b net_get_sockets +0002a527 sock_get +0002a548 get_total_sockets +0002a54e net_sock_is_established +0002a592 net_sock_awaiting_ack +0002a5d6 net_sock_data_ready +0002a62f net_sock_read +0002a731 net_sock_add_data +0002a991 sock_find_listen_tcp +0002a9d5 net_sock_find_tcp +0002abc7 net_prepare_tcp_sock +0002ac53 net_sock_accept +0002ac66 net_socket_find_udp +0002acd1 kernel_sock_shutdown +0002acfe kernel_sock_cleanup +0002ad84 kernel_sock_close +0002adb8 kernel_socket_create +0002af3b net_init_sockets +0002af81 gethostname +0002b49b __add_systemcall_gethostname +0002b4b2 net_init_dns +0002b4e1 route +0002b52e tcb_init +0002b54c tcb_new +0002b6b8 tcp_state_to_str +0002b6d1 tcp_new_connection +0002b759 tcp_free_connection +0002b77c tcp_is_listening +0002b792 tcp_set_listening +0002b7f2 tcp_calculate_checksum +0002b8b6 __tcp_send +0002b9d2 tcp_send_segment +0002bb15 tcp_accept_connection +0002bc57 tcp_send_ack +0002bd8d tcp_read +0002bd93 tcp_recv_segment +0002bd99 tcp_connect +0002be3c tcp_send_syn +0002be42 tcp_recv_ack +0002bec5 tcp_recv_fin +0002becb tcp_recv_syn +0002bffd tcp_send_fin +0002c0c9 tcp_close_connection +0002c108 tcp_parse +0002c5a1 kernel_bind +0002c5d6 kernel_recvfrom +0002c5dc kernel_recv +0002c64e kernel_recv_timeout +0002c674 kernel_connect +0002c778 kernel_sendto +0002c832 kernel_accept +0002c895 kernel_listen +0002c8bd kernel_send +0002c943 sys_kernel_bind +0002c975 __add_systemcall_sys_kernel_bind +0002c98c __add_systemcall_sys_kernel_accept +0002c9a3 __add_systemcall_sys_kernel_connect +0002c9ba __add_systemcall_sys_kernel_listen +0002c9d1 __add_systemcall_sys_kernel_recv +0002c9e8 __add_systemcall_sys_kernel_recvfrom +0002c9ff __add_systemcall_sys_kernel_recv_timeout +0002ca16 __add_systemcall_sys_kernel_send +0002ca2d __add_systemcall_sys_kernel_sendto +0002ca44 __add_systemcall_sys_socket_create +0002ca5b __add_systemcall_sys_kernel_sock_close +0002ca72 sys_kernel_accept +0002cab2 sys_kernel_connect +0002cae4 sys_kernel_listen +0002cb13 sys_kernel_recv +0002cb4b sys_kernel_recvfrom +0002cb8b sys_kernel_recv_timeout +0002cbc9 sys_kernel_send +0002cc01 sys_kernel_sendto +0002cc41 sys_socket_create +0002cc68 sys_kernel_sock_close +0002cca9 __iface_send +0002ccd8 __iface_recieve +0002cd07 __iface_assign +0002cd1a __iface_detach +0002cd2e __iface_set_gateway +0002cd41 __iface_set_netmask +0002cd54 __iface_configure +0002cda4 __iface_attach +0002cdc9 net_interface_create +0002ce01 net_register_netdev +0002cf19 net_interface_destroy +0002cf2e __default_restart +0002cf34 __default_stop +0002cf99 __default_start +0002d013 nm_new +0002d09c nm_free +0002d0e1 net_firewall_create +0002d104 fs_file2fd +0002d16b fs_alloc_file +0002d1b6 fs_free_file +0002d210 fs_register +0002d2df fs_init +0002d2e5 fs_unregister +0002d348 fs_get +0002d34e fs_close +0002d3c0 fs_open +0002d43a fs_seek +0002d4b7 fs_read +0002d5cc fs_load_from_file +0002d658 fs_write +0002d713 fs_save_to_file +0002d79f fat16_rmdir +0002d7a5 fat16_stat +0002d7ab fat16_close +0002d815 fat16_rename +0002d8aa fat16_mkdir +0002d98f fat16_remove +0002da02 fat16_open +0002db4c fat16_read +0002dcb0 fat16_write +0002dddf fat16_list +0002e0ad fat16_init +0002e161 path_next_iter +0002e1d0 inode_from_path_recursise +0002e24e inode_from_path +0002e30c ext_get_root +0002e315 ext_get_current_dir +0002e324 ext_get_size +0002e32a ext_get_inodes +0002e330 ext_get_blocks +0002e336 ext_sync +0002e3a9 ext_create +0002e494 ext_read +0002e50f ext_seek +0002e556 ext_write +0002e5c2 ext_close +0002e624 ext_open_from_directory +0002e72a ext_open +0002e7e1 ext_size +0002e80a change_directory +0002e870 ext_create_directory +0002ea0a ext_create_file_system +0002ecd7 init_ext +0002ee73 listdir +0002ef94 __inode_sync +0002eff7 __inode_cache_insert +0002f0ed __inode_load +0002f161 inodes_sync +0002f19c inode_get +0002f1f9 inode_read +0002f3e1 inode_write +0002f63f alloc_inode +0002f6f8 mkdir +0002f7a5 sync +0002f7d9 mkfs +0002f7e6 fat16_read_data_from_cluster +0002f834 fat16_read_data +0002f915 fat16_find_cluster_by_offset +0002f990 fat16_write_data_to_cluster_with_offset +0002f9cb fat16_print_cluster_chain +0002f9f9 fat16_write_data_to_cluster +0002fa2c fat16_write_data +0002fb48 get_fat_start_block +0002fb50 get_root_directory_start_block +0002fb5f get_data_start_block +0002fb71 fat16_get_fat_entry +0002fb8c fat16_set_fat_entry +0002fbcc fat16_sync_fat_table +0002fc44 fat16_allocate_cluster +0002fc5c fat16_free_cluster +0002fc71 fat16_get_free_cluster +0002fcc6 fat16_sync_directory_entry +0002fd48 fat16_read_entry +0002fdf5 fat16_find_entry +0002ff30 fat16_rename_entry +0002ffa1 fat16_free_clusters +0002ffe8 fat16_delete_entry +0003004f fat16_add_entry +000301b6 fat16_used_blocks +000301ef fat16_to_upper +0003021b fat16_name_compare +00030340 sstrtok +00030401 fat16_directory_entry_debug +000304d1 fat16_get_directory_entry +000306c9 fat16_create_directory +000307ce fat16_read_file +0003081f fat16_create_file +0003089d fat16_create_empty_file +0003095d fat16_directory_entries +00030a43 fat16_mbr_clear +00030aec fat16_mbr_add_entry +00030bdd fat16_print_root_directory_entries +00030bf5 fat16_change_directory +00030c7d fat16_bootblock_info +00030dfa fat16_set_time +00030e2e fat16_set_date +00030e66 fat16_load +00030fe5 fat16_format +0003129a mbr_partition_type_string +0003131d mbr_partitions_parse +000313e6 mbr_get +000313ec mbr_partition_load +0003140a __list_users +0003149b __change_user +0003153d __remove_user +000315e9 __add_user +000316d3 __find_user +000317a8 __authenticate_user +000318b6 __save_users +0003193a __load_users +00031b3c __ksymbol_admin +00031b56 admin +00031e6a usermanager_create +00031e89 __ksymbol_snakegame +00031ea3 init_game +00031ef1 draw +00031f4d get_input +00031f6c update +000320f3 game_loop +00032119 snakegame +00032164 __msgbox +00032564 msgbox_create +00032597 msgbox_show +000325df kevents_list +00032751 kevents_init +00032793 kevents_destroy +000327e8 kevents_add +0003289f kevents_create +00032922 _code_end From 867725879f74411921465206879207187d2b834c Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Sun, 28 Jan 2024 14:43:12 +0100 Subject: [PATCH 03/23] Lambdas with *this* capture using function --- apps/users/users.cpp | 64 +- apps/utils/Function.hpp | 78 ++ apps/utils/Widgets.hpp | 47 +- kernel/terminal.c | 1 + rootfs/symbols.map | 1708 +++++++++++++++++++-------------------- 5 files changed, 1018 insertions(+), 880 deletions(-) create mode 100644 apps/utils/Function.hpp diff --git a/apps/users/users.cpp b/apps/users/users.cpp index 868ed05..951ce5d 100644 --- a/apps/users/users.cpp +++ b/apps/users/users.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -16,13 +17,36 @@ class UserEditor : public Window { widgets = new WidgetManager(); LayoutHandle main = widgets->addLayout(new Layout( 10, 10, - 100, 12, - VERTICAL + 180, 160, + VERTICAL, + LAYOUT_FLAG_NONE )); - widgets->addWidget(main, LEFT, new Button(100, 12, "Button", []() { + LayoutHandle bottom = widgets->addLayout(new Layout( + 10, 170, + 180, 24, + HORIZONTAL, + LAYOUT_FLAG_BORDER + )); + + widgets->addWidget(main, CENTER, new Label("Create a new user")); + widgets->addWidget(main, LEFT, new Spacing(0, 8)); + widgets->addWidget(main, LEFT, new Label("Username:")); + widgets->addWidget(main, LEFT, new Input(100, 14, "Input")); + widgets->addWidget(main, LEFT, new Label("Password:")); + widgets->addWidget(main, LEFT, new Input(100, 14, "Input")); + widgets->addWidget(main, LEFT, new Spacing(0, 8)); + widgets->addWidget(main, CENTER, new Label("Permissions:")); + widgets->addWidget(main, LEFT, new Checkbox(false, "Admin")); + widgets->addWidget(main, LEFT, new Checkbox(true, "User")); + widgets->addWidget(main, LEFT, new Checkbox(false, "Guest")); + + widgets->addWidget(bottom, RIGHT, new Button(50, 14, "Cancel", Function([this]() { + printf("Button pressed %d!\n", test); + }))); + widgets->addWidget(bottom, RIGHT, new Button(50, 14, "Create", Function([this]() { printf("Button pressed!\n"); - })); + }))); } int eventHandler(struct gfx_event* event) { @@ -52,6 +76,8 @@ class UserEditor : public Window { widgets->draw(this); } + int test = 1337; + private: int width; int height; @@ -82,24 +108,26 @@ class Users : public Window { LayoutHandle main = widgets->addLayout(new Layout( 10, 10, 180, 180, - VERTICAL + VERTICAL, + 0 + )); - widgets->addWidget(main, LEFT, new Button(100, 14, "Button", []() { + widgets->addWidget(main, LEFT, new Button(100, 14, "Button", Function([this]() { printf("Button pressed!\n"); - })); - widgets->addWidget(main, RIGHT, new Button(100, 14, "Start Edit", []() { + }))); + widgets->addWidget(main, RIGHT, new Button(100, 14, "Start Edit", Function([this]() { Thread* editor = new Thread(editorEntry, 0); editor->start(0); - })); + }))); Input* input = new Input(100, 12, "Input"); widgets->addWidget(main, CENTER, input); widgets->addWidget(main, LEFT, new Checkbox(true)); - widgets->addWidget(main, LEFT, new Label(100, 12, "Checkbox")); + widgets->addWidget(main, LEFT, new Label("Checkbox")); widgets->addWidget(main, LEFT, new Checkbox(false)); } @@ -137,8 +165,24 @@ class Users : public Window { WidgetManager* widgets; }; +class MyClass { +public: + void memberFunction() { + Function f = [this]() { this->anotherFunction(); }; + f(); // Invoke the lambda + } + + void anotherFunction() { + printf("Hello from another function!\n"); + } +}; + + int main() { + MyClass c; + c.memberFunction(); + Users t(200, 200); t.draw(); diff --git a/apps/utils/Function.hpp b/apps/utils/Function.hpp new file mode 100644 index 0000000..ec9670f --- /dev/null +++ b/apps/utils/Function.hpp @@ -0,0 +1,78 @@ +#ifndef __FUNCTION_HPP__ +#define __FUNCTION_HPP__ + +#include +#include + +class BaseCallable { +public: + virtual ~BaseCallable() {} + virtual void call() const = 0; + virtual BaseCallable* clone() const = 0; +}; + + +template +class Callable : public BaseCallable { + T callable; + +public: + Callable(T callable) : callable(callable) {} + + void call() const override { + callable(); + } + + BaseCallable* clone() const override { + return new Callable(callable); + } +}; + + +class Function { + BaseCallable* callable; + +public: + Function() : callable(nullptr) {} + + Function(const Function& other) { + if (other.callable) { + // The challenge is to clone `other.callable`. + // This requires a mechanism in `BaseCallable` and its derived classes + // to clone themselves. + callable = other.callable->clone(); + } else { + callable = nullptr; + } + } + + template + Function(T lambda) : callable(new Callable(lambda)) {} + + ~Function() { + delete callable; + } + Function& operator=(const Function& other) = delete; // Copy assignment + + Function(Function&& other) : callable(other.callable) { + other.callable = nullptr; + } + + Function& operator=(Function&& other) { + if (this != &other) { + delete callable; + callable = other.callable; + other.callable = nullptr; + } + return *this; + } + + void operator()() const { + if (callable) { + callable->call(); + } + } +}; + + +#endif // __FUNCTION_HPP__ diff --git a/apps/utils/Widgets.hpp b/apps/utils/Widgets.hpp index 8beac7f..7e6f4f9 100644 --- a/apps/utils/Widgets.hpp +++ b/apps/utils/Widgets.hpp @@ -14,8 +14,10 @@ #include #include +#include #include + #define MAX_WIDGETS 32 #define MAX_LAYOUTS 32 @@ -43,11 +45,10 @@ class Widget { /* A simple button widget */ class Button : public Widget { public: - Button(int width, int height, char* text, Callback callback) { + Button(int width, int height, char* text, Function callback) : callback(callback) { this->width = width; this->height = height; this->text = text; - this->callback = callback; } /* Draws the button */ @@ -72,7 +73,7 @@ class Button : public Widget { private: char* text; - Callback callback; + Function callback; }; class Spacing : public Widget { @@ -150,9 +151,9 @@ class Input : public Widget { /* A simple label widget */ class Label : public Widget { public: - Label(int width, int height, char* text) { - this->width = width; - this->height = height; + Label(char* text) { + this->width = strlen(text) * 8; + this->height = 8; this->text = text; } @@ -207,14 +208,16 @@ class List : public Widget { /* Simple Checkbox widget */ class Checkbox : public Widget { public: - Checkbox(bool value) { + Checkbox(bool value, char* text = "") { this->width = 12; this->height = 12; this->value = value; + this->text = text; } void draw(Window* window) { window->drawContouredBox(x, y, width, height, 30); + window->drawText(x + 16, y + 4, text, COLOR_BLACK); if (value) { window->drawCircle(x + width - 6, y + 6, 2, COLOR_VGA_LIGHT_GRAY, 1); } @@ -232,6 +235,7 @@ class Checkbox : public Widget { private: bool value; + char* text; }; typedef enum { @@ -249,14 +253,22 @@ typedef enum { typedef int LayoutHandle; +enum { + LAYOUT_FLAG_NONE = 0, + LAYOUT_FLAG_BORDER = 1 +}; + class Layout { public: - Layout(int x, int y, int width, int height, LayoutType type) { + Layout(int x, int y, int width, int height, LayoutType type, int flags) { this->x = x; this->y = y; this->width = width; this->height = height; this->type = type; + this->offset = 0; + this->flags = flags; + memset(widgets, 0, MAX_WIDGETS * sizeof(Widget*)); } ~Layout() { @@ -266,7 +278,9 @@ class Layout { } void draw(Window* window) { - window->drawContouredBox(x, y, width, height, 30); + if (flags & LAYOUT_FLAG_BORDER) + window->drawContouredBox(x, y, width, height, 30); + for (int i = 0; i < widgetCount; i++) { widgets[i]->draw(window); } @@ -286,29 +300,31 @@ class Layout { case HORIZONTAL: widget->x = x + offset + 2; widget->y = y + 2; - offset += widget->width; + offset += widget->width + 4; break; case VERTICAL: /* switch based on position, put widgets under each other */ switch (position) { case LEFT: widget->x = x + 2; - widget->y = y + offset + 2; + widget->y = y + offset; break; case RIGHT: widget->x = x + width - widget->width -2; - widget->y = y + offset + 4; + widget->y = y + offset; break; case CENTER: /* puts widget in the middle but still stacked under last */ widget->x = x + width / 2 - widget->width / 2; - widget->y = y + offset + 2; + widget->y = y + offset; break; } - offset += widget->height; + offset += widget->height + 4; break; } + printf("Added widget, new offset %d\n", offset); + return widgetCount; } @@ -351,6 +367,7 @@ class Layout { Widget* widgets[MAX_WIDGETS]; int widgetCount = 0; int focusedWidget = -1; + int flags = 0; int offset = 0; }; @@ -382,8 +399,6 @@ class WidgetManager { return -1; } - layouts[lh]->addWidget(widget, lp); - return layouts[lh]->addWidget(widget, lp);; } diff --git a/kernel/terminal.c b/kernel/terminal.c index 11d98c5..9982c24 100644 --- a/kernel/terminal.c +++ b/kernel/terminal.c @@ -104,6 +104,7 @@ void terminal_commit() void terminal_putchar(char c) { + serial_put(c); if($process->current == NULL || $process->current->term == NULL) return; $process->current->term->ops->putchar($process->current->term, c); diff --git a/rootfs/symbols.map b/rootfs/symbols.map index 73c2862..f7df4ac 100644 --- a/rootfs/symbols.map +++ b/rootfs/symbols.map @@ -32,857 +32,857 @@ 000112b3 terminal_attach 000112d4 terminal_commit 000112f3 terminal_putchar -00011325 terminal_create -0001144a terminal_destroy -00011480 tlb_flush_addr -00011488 load_page_directory -00011498 enable_paging -000114aa pcb_save_context -000114d6 pcb_restore_context -000114ff _start_pcb -00011531 _start_pcb_skip -0001154c __ksymbol_lspci -00011566 pci_get_class_name -00011579 pci_get_device_name -000115ea pci_get_vendor_name -00011638 lspci -00011785 pci_get_devices -0001178b pci_read_word -000117e5 pci_write_dword -00011834 pci_enable_device_busmaster -00011889 pci_register_device -0001190a init_pci -00011abb pci_find_device -00011b51 virtual_read -00011b7c virtual_write -00011ba7 virtual_disk_attach -00011bc6 wm_default_changes -00011c6e wm_default_workspace -00011cd0 wm_default_draw -00011d6e wm_default_add -00011e15 init_windowmanager -00011f5f wm_default_mouse_event -00012185 wm_default_push_back -00012277 wm_default_push_front -00012366 wm_default_remove -00012477 wm_destroy -00012555 wm_new -000125bc screen_set_cursor -0001261c scrcolor_set -00012630 scrput -00012656 scrwrite -0001269f scr_clear -000126f1 scr_scroll -00012739 scrprintf -0001297d strlen -0001299f strcpy -000129d3 strncmp -00012a0e strcmp -00012a4e memcmp -00012a89 parse_arguments -00012b6c strchr -00012b9b getopt -00012cab memcpy -00012d18 strtok -00012dd0 xmemcpy -00012e57 memset -00012ed7 isdigit -00012eeb isspace -00012efa tolower -00012f0e isxdigit -00012f32 htoi -00012fd6 atoi -00013066 itoa -0001310c itohex -00013188 rdtsc -0001318b rand -000131a7 general_protection_fault -00013237 interrupt_get_count -00013246 print_page_fault_info -00013323 page_fault_interrupt -000133b5 interrupt_install_handler -000133c7 load_data_segments -000133d3 isr_handler -000134c6 init_interrupts -0001363f idt_flush -00013647 isr0 -00013654 isr1 -00013661 isr2 -0001366e isr3 -0001367b isr4 -00013688 isr5 -00013695 isr6 -000136a2 isr7 -000136af isr8 -000136bc isr9 -000136c9 isr10 -000136d6 isr11 -000136e3 isr12 -000136f0 isr13 -000136fd isr14 -0001370a isr15 -00013717 isr16 -00013724 isr17 -00013731 isr18 -0001373e isr19 -0001374b isr20 -00013758 isr21 -00013765 isr22 -00013772 isr23 -0001377f isr24 -0001378c isr25 -00013799 isr26 -000137a6 isr27 -000137b3 isr28 -000137c0 isr29 -000137cd isr30 -000137da isr31 -000137e7 isr32 -000137f4 isr33 -00013801 isr34 -0001380e isr35 -00013818 isr36 -00013822 isr37 -0001382c isr38 -00013836 isr39 -00013840 isr40 -0001384a isr41 -00013854 isr42 -0001385e isr43 -00013868 isr44 -00013872 isr45 -0001387c isr46 -00013886 isr47 -00013890 isr_entry -000138ab syscall_return_value -000138af _syscall_entry -000138ec page_fault_save -000138f0 page_fault_error -000138f4 _page_fault_entry -00013926 timer_callback -0001395e timer_get_tick -00013964 time_get_difference -000139a7 init_pit -00013a0b gdt_set_segment -00013a54 init_gdt -00013b62 rc -00013d51 __ksymbol_rc -00013d6b __ksymbol_as -00013d85 __ksymbol_cc -00013d9f as -00014161 cc -000141bd __cc -000144b1 vm_print -000146ae eval -00014b48 vm_setup -00014b89 vm_init -00014be4 vm_free -00014c13 vm_setup_stack -00014c6f lex_get_error -00014c7c next -00015187 match -000151d5 expression -000164d6 statement -000166df function_parameter -000168a1 function_body -00016ab0 function_declaration -00016b39 enum_declaration -00016c4c global_declaration -00016e79 lex_init -00016f14 program -00016fb5 find_mp_floating_ptr -00016ff1 smp_parse -00017136 kb_get_char -00017182 kb_add_char -000171bd kb_callback -000173ea init_keyboard -00017461 pcb_await -0001748b __pcb_get_free -00017549 __add_systemcall_pcb_await -00017560 __pcb_free -000175af __pcb_init_kernel_stack -00017610 __pcb_init_process -000176d5 init_pcbs -00017726 pcb_total_usage -0001774f pcb_get_info -00017843 pcb_kill -00017860 Genesis -00017862 idletask -0001787d pcb_get_by_pid -0001788e pcb_get_by_name -000178e7 pcb_dbg_print -00017961 pcb_cleanup_routine -00017b71 pcb_create_thread -00017c69 pcb_create_process -00017efb pcb_create_kthread -000181d7 start_pcb -0001820f __pcb_queue_peek -0001824e __pcb_queue_pop -000182aa __pcb_queue_remove -0001831c __pcb_queue_add -00018395 __pcb_queue_push -0001842e pcb_new_queue -0001845f get_mem_info -000184b7 memory_map_init -0001857e memory_map_get -00018584 free -000185db malloc -00018677 calloc -000186aa krealloc -00018716 init_memory -000187a8 vmem_free -00018818 vmem_alloc -00018885 vmem_free_page_region -000189eb vmem_page_region_alloc -00018a26 vmem_create_page_region -00018b6a vmem_free_allocations -00018c99 vmem_continious_allocation_map -00018c9f vmem_free_allocation -00018ca0 vmem_stack_free -00018d51 vmem_stack_alloc -000190d6 vmem_dump_heap -0001916b vmem_init_process_thread -0001925c vmem_init_process -0001958a vmem_cleanup_process_thead -00019601 vmem_cleanup_process -000197ef vmem_init_kernel -000199b0 vmem_allocator_create -00019a14 vmem_map_driver_region -00019a92 vmem_total_usage -00019aa5 vmem_init -00019bd7 kalloc -00019d6e kcalloc -00019da0 kfree -00019e36 palloc -00019e78 pmemory_used -00019e94 kmemory_used -00019e9a kmemory_total -00019ea6 kmem_init -00019f43 e1000_receive -0001a01e e1000_transmit -0001a0e0 e1000_callback -0001a107 _e1000_tx_init -0001a1ab _e1000_rx_init -0001a245 e1000_attach -0001a475 display_get_info -0001a4de kenv_init -0001a4f5 kenv_set -0001a52a config_list -0001a5fb kernel_config_load -0001a9e6 config_get_value -0001aaa1 spin_lock -0001aac1 spin_unlock -0001aacf mutex_init -0001aaec acquire -0001ab89 release -0001ac2b kthread_entry -0001ac85 kthread_list -0001acec register_kthread -0001adc5 start -0001ae67 ata_primary -0001ae68 ata_secondary -0001ae69 ata_wait -0001aee3 ata_write -0001b05a ata_read -0001b1ea ata_ide_init -0001b3ba set_bitmap -0001b3dc unset_bitmap -0001b400 get_bitmap -0001b422 get_bitmap_size -0001b436 create_bitmap -0001b46a destroy_bitmap -0001b47d bitmap_unset_continous -0001b4b7 bitmap_get_continous -0001b553 get_free_bitmap -0001b5a8 __rtc_check_in_progress -0001b5ca __rtc_get_register -0001b5ea get_current_time -0001b735 get_time -0001b75f init_tss -0001b78d exec_cmd -0001b891 __ksymbol_exec_cmd -0001b8ab system_reboot -0001b8df align_to_pointer_size -0001b8ed calculate_size_unit -0001b94f advanced_hash -0001b983 kernel_panic -0001b9a1 kref_init -0001b9bb kref_get -0001b9e3 kref_put -0001ba0b csprintf -0001bc0c script_parse -0001bce1 login -0001c07f __login_create_virt_disk -0001c0a9 __register_kthread_login -0001c0c3 help -0001c364 clear -0001c385 __ksymbol_new -0001c39f __ksymbol_list -0001c3b9 __ksymbol_color -0001c3d3 __ksymbol_about -0001c3ed __ksymbol_help -0001c407 __ksymbol_kevents -0001c421 __ksymbol_view -0001c43b __ksymbol_file -0001c455 __ksymbol_tcp -0001c46f __ksymbol_conf -0001c489 __ksymbol_clear -0001c4a3 __ksymbol_services -0001c4bd __ksymbol_reboot -0001c4d7 kevents -0001c5b1 services -0001c7df new -0001c920 list -0001ca20 file -0001cbee color -0001cc8f about -0001cccc view -0001cee1 tcp -0001d1be __tcp_reader -0001d2df conf -0001d5a7 reboot -0001d5e0 attach_disk_dev -0001d604 disk_attached -0001d60c disk_name -0001d615 disk_device_get -0001d61b disk_size -0001d637 write_block -0001d674 write_block_offset -0001d6b7 read_block -0001d6f4 read_block_offset -0001d75e sched_consume -0001d79f sched_add -0001d7f9 sched_prioritize -0001d8ae sched_round_robin -0001da94 sched_exit -0001db4d sched_block -0001dc6b sched_default -0001dd45 sched_sleep -0001ddeb sched_init_default -0001de6c get_scheduler -0001de72 kernel_sleep -0001de8d kernel_yield -0001ded0 kernel_exit -0001df02 block -0001df2b unblock -0001df2c work_queue_add -0001e014 init_worker -0001e02c worker_thread -0001e0cb __ring_buffer_add -0001e173 __ring_buffer_read -0001e27d rbuffer_new -0001e2e6 rbuffer_free -0001e308 error_get_string -0001e344 kclock -0001e824 __register_kthread_kclock -0001e83e tar_extract -0001ea8e __ksymbol_tar -0001eaa8 tar_list -0001ebb2 tar -0001ee3b rgb_to_vga -0001ee4b rgb_to_components -0001ee72 color_distance_squared -0001eedd rgb_init_color_table -0001ef6e iface_loopback_write -0001f02f iface_loopback_interrupt -0001f046 iface_loopback_read -0001f0e9 net_init_loopback -0001f100 serial_put -0001f140 serial_write -0001f182 serial_printf -0001f322 init_serial -0001f3e8 inportb -0001f3f1 inportw -0001f3fb inportl -0001f404 outportb -0001f412 outportw -0001f421 outportl -0001f42e sys_create_thread -0001f44d __add_systemcall_sys_create_thread -0001f458 add_system_call -0001f498 system_call -0001f503 hashmap_put -0001f56a hashmap_get -0001f5ee hashmap_add -0001f678 hashmap_free -0001f679 reset_vga_palette -0001f6bf vga_set_palette -0001f7aa b8to16 -0001f7ba vesa_put_pixel -0001f7e4 vesa_put_box -0001f85f vesa_put_block -0001f8da vesa_put_char -0001f955 vesa_put_char16 -0001f9e8 vesa_put_icon16 -0001fa61 vesa_write -0001faa0 vesa_write_str -0001face vesa_fill -0001fb50 vesa_fillrect -0001fbc2 vesa_inner_box -0001fcca vesa_printf -0001ff37 ksyms_init -0002015e ksyms_add_symbol -00020217 __ksymbol_backtrace -00020231 ksyms_list -00020293 ksyms_resolve_symbol -00020346 __backtrace_from -00020463 backtrace -00020474 ws_fullscreen -000205ee ws_remove -0002069e ws_add -00020789 ws_destroy -0002082f ws_draw -00020adc ws_raw_wallpaper -00020bc2 ws_set_background_file -00020e9f ws_init -00020f82 ws_set_background -0002102d ws_new -000210ba encode_run_length -00021137 decode_run_length -000211a2 __mouse_handler -000212b9 mouse_wait -00021301 mouse_write -00021343 mouse_get_event -00021384 mouse_init -00021469 sys_ipc_open -000214b7 __add_systemcall_sys_ipc_open -000214ce __add_systemcall_sys_ipc_close -000214e5 __add_systemcall_sys_ipc_send -000214fc __add_systemcall_sys_ipc_receive -00021513 sys_ipc_close -0002155c sys_ipc_send -000215c3 sys_ipc_receive -00021629 sysinf -0002237b __register_kthread_sysinf -00022395 echo -000223d0 res -00022411 ifconfig -0002241e __ksymbol_ifconfig -00022438 __ksymbol_ps -00022452 __ksymbol_tree -0002246c __ksymbol_fat16 -00022486 __ksymbol_xxd -000224a0 __ksymbol_sh -000224ba __ksymbol_ed -000224d4 __ksymbol_exec -000224ee __ksymbol_ths -00022508 __ksymbol_dns -00022522 __ksymbol_th -0002253c __ksymbol_kill -00022556 __ksymbol_echo -00022570 __ksymbol_fdisk -0002258a __ksymbol_meminfo -000225a4 __ksymbol_res -000225be __ksymbol_bg -000225d8 __ksymbol_exit -000225f2 __ksymbol_socks -0002260c __ksymbol_reset -00022626 exit -0002265a ps -000228ce print_pcb_tree -000229cd tree -00022a0d fat16 -00022a35 xxd -00022b2a sh -00022c2a ed -00022c77 exec -00022ddb ths -00022e47 dns -00022ebb th -00022ed9 kill -00022ef7 fdisk -00023089 meminfo -00023268 bg -000232e7 socks -0002358d __register_kthread_shell -000235a7 __register_kthread_textshell -000235c1 shell_clear -00023604 reset_shell -00023675 reset -000236c9 shell_put -000238aa shell -00023b0b cleanup_function -00023b32 testfn -00023b66 draw_box -00023c4b __textshell_reset_box -00023cdb textshell -000240ac __net_find_interface -0002410c net_drop_packet -0002412d net_handle_recieve -00024254 net_get_interfaces -0002425a net_configure_iface -000242ac net_incoming_packet -0002435d net_get_iface -000243d3 net_iface_up -000243fa net_iface_down -00024421 net_list_ifaces -0002453b net_register_interface -0002456c net_send_skb -000245f4 net_get_info -0002461b networking_main -000247fb __dhcp_add_option -0002486b __dhcp_send_discovery -000249ad __dhcp_send_request -00024b2a dhcp_get_state -00024b32 dhcp_get_dns -00024b38 dhcp_get_ip -00024b4d dhcp_get_gw -00024b62 dhcpd -00024de1 udp_server -00024e6c tcp_server -00024fe0 __net_terminal_writef -00025045 __register_kthread_tcp_server -0002505f __register_kthread_udp_server -00025079 __register_kthread_udptest -00025093 udptest -0002511e tcpd -00025202 logd -0002526d __register_kthread_logd -00025287 logd_attach_by_pid -000252cb taskbar_reboot -000252f7 __reboot -0002530c taskbar_readme -00025325 taskbar_about -0002533e taskbar_clock -00025357 taskbar_sysinf -00025370 taskbar_bg_retro -000253a7 taskbar_bg_lotr2 -000253bc taskbar_bg_lotr -000253d1 taskbar_bg_default_color_gray -000253e3 taskbar_bg_default_color -000253f5 taskbar_wolfstein -00025430 taskbar_bg_graph -0002546b taskbar_bg_calc -000254a6 taskbar_colors -000254e1 taskbar_cube -0002551c taskbar_editor -00025557 taskbar_finder -00025592 taskbar_terminal -000255db __register_kthread_taskbar -000255f5 taskbar_hdr_opt_event -0002567f taskbar -00025c36 about -00025e01 __register_kthread_about -00025e1b __register_kthread_readme -00025e35 readme -00025f97 gfx_default_hover -000260b6 gfx_destory_window -00026143 gfx_window_resize -000261ec gfx_window_maximize -00026265 gfx_default_mouse_up -00026333 gfx_default_mouse_down -000263f5 gfx_default_click -000265e4 gfx_draw_window -000273d0 gfx_window_set_resizable -000273e5 kernel_gfx_window_border_color -00027410 gfx_new_window -00027670 gfx_point_in_rectangle -0002769d gfx_draw_component -000276df gfx_input_event -00027811 gfx_input_draw -00027919 gfx_input_manager_add -0002797a gfx_composition_remove_window -000279a4 gfx_composition_add_window -000279eb gfx_set_background_color -00027a3c gfx_raw_background -00027a89 gfx_decode_background_image -00027ad6 gfx_set_taskbar -00027b76 gfx_compositor_main -00027bea kernel_gfx_draw_circle_helper -00027e96 gfx_get_window_width -00027eab gfx_get_window_height -00027ec0 gfx_push_event -00027f7c gfx_put_icon16 -00028074 gfx_put_icon32 -0002816c gfx_event_loop -0002828b kernel_gfx_draw_rectangle -00028385 kernel_gfx_draw_contoured_box -00028425 kernel_gfx_draw_pixel -000284c3 kernel_gfx_draw_bitmap -000285e1 kernel_gfx_draw_char -000286e1 kernel_gfx_set_position -000286fd gfx_commit -00028716 kernel_gfx_draw_text -000287c9 gfx_button_ext -000288fc gfx_button -0002891a kernel_gfx_set_title -00028986 kernel_gfx_set_header -000289f2 kernel_gfx_draw_line -00028b8d kernel_gfx_draw_circle -00028c0c kernel_gfx_draw_section -00028c12 kernel_gfx_draw_format_text -00028f64 gfx_syscall_hook -0002911b gfx_total_themes -00029121 kernel_gfx_current_theme -00029127 kernel_gfx_update_theme -000291f5 kernel_gfx_default_theme -000291fb kernel_gfx_set_theme -00029220 kernel_gfx_get_theme -0002923b gfx_new_ctx -00029297 gfx_init_framebuffer -00029403 netdev_attach_driver -000294ac is_netdev_attached -000294ba netdev_transmit -000294d5 netdev_recieve -000294fe net_ethernet_add_header -00029592 net_ethernet_parse -00029606 __skb_queue_remove -00029644 __skb_queue_add -00029694 skb_free_queue -000296cc skb_new_queue -00029733 skb_free -0002976e skb_new -000297d9 skb_consume -0002980a __net_arp_send -000298ca net_init_arp -00029916 net_arp_add_entry -000299a5 net_arp_find_entry -000299f0 net_arp_respond -00029a65 net_net_arp_request -00029aeb arp_parse -00029b95 net_ipv4_print -00029b9b net_ipv4_add_header -00029cd2 net_is_ipv4 -00029d0f net_ipv4_parse -00029e3c ntohl -00029e68 htonl -00029e7b ntohs -00029e88 htons -00029e95 checksum -00029eec transport_checksum -00029f41 ip_to_int -00029fdf net_icmp_handle -0002a0a4 net_icmp_response -0002a0aa net_icmp_request -0002a16d ping -0002a1c6 net_icmp_parse -0002a236 net_udp_send -0002a36b net_udp_parse -0002a493 socket_type_to_str -0002a4a2 socket_domain_to_str -0002a4b1 socket_protocol_to_str -0002a4c0 net_sock_bind -0002a50b net_get_sockets -0002a527 sock_get -0002a548 get_total_sockets -0002a54e net_sock_is_established -0002a592 net_sock_awaiting_ack -0002a5d6 net_sock_data_ready -0002a62f net_sock_read -0002a731 net_sock_add_data -0002a991 sock_find_listen_tcp -0002a9d5 net_sock_find_tcp -0002abc7 net_prepare_tcp_sock -0002ac53 net_sock_accept -0002ac66 net_socket_find_udp -0002acd1 kernel_sock_shutdown -0002acfe kernel_sock_cleanup -0002ad84 kernel_sock_close -0002adb8 kernel_socket_create -0002af3b net_init_sockets -0002af81 gethostname -0002b49b __add_systemcall_gethostname -0002b4b2 net_init_dns -0002b4e1 route -0002b52e tcb_init -0002b54c tcb_new -0002b6b8 tcp_state_to_str -0002b6d1 tcp_new_connection -0002b759 tcp_free_connection -0002b77c tcp_is_listening -0002b792 tcp_set_listening -0002b7f2 tcp_calculate_checksum -0002b8b6 __tcp_send -0002b9d2 tcp_send_segment -0002bb15 tcp_accept_connection -0002bc57 tcp_send_ack -0002bd8d tcp_read -0002bd93 tcp_recv_segment -0002bd99 tcp_connect -0002be3c tcp_send_syn -0002be42 tcp_recv_ack -0002bec5 tcp_recv_fin -0002becb tcp_recv_syn -0002bffd tcp_send_fin -0002c0c9 tcp_close_connection -0002c108 tcp_parse -0002c5a1 kernel_bind -0002c5d6 kernel_recvfrom -0002c5dc kernel_recv -0002c64e kernel_recv_timeout -0002c674 kernel_connect -0002c778 kernel_sendto -0002c832 kernel_accept -0002c895 kernel_listen -0002c8bd kernel_send -0002c943 sys_kernel_bind -0002c975 __add_systemcall_sys_kernel_bind -0002c98c __add_systemcall_sys_kernel_accept -0002c9a3 __add_systemcall_sys_kernel_connect -0002c9ba __add_systemcall_sys_kernel_listen -0002c9d1 __add_systemcall_sys_kernel_recv -0002c9e8 __add_systemcall_sys_kernel_recvfrom -0002c9ff __add_systemcall_sys_kernel_recv_timeout -0002ca16 __add_systemcall_sys_kernel_send -0002ca2d __add_systemcall_sys_kernel_sendto -0002ca44 __add_systemcall_sys_socket_create -0002ca5b __add_systemcall_sys_kernel_sock_close -0002ca72 sys_kernel_accept -0002cab2 sys_kernel_connect -0002cae4 sys_kernel_listen -0002cb13 sys_kernel_recv -0002cb4b sys_kernel_recvfrom -0002cb8b sys_kernel_recv_timeout -0002cbc9 sys_kernel_send -0002cc01 sys_kernel_sendto -0002cc41 sys_socket_create -0002cc68 sys_kernel_sock_close -0002cca9 __iface_send -0002ccd8 __iface_recieve -0002cd07 __iface_assign -0002cd1a __iface_detach -0002cd2e __iface_set_gateway -0002cd41 __iface_set_netmask -0002cd54 __iface_configure -0002cda4 __iface_attach -0002cdc9 net_interface_create -0002ce01 net_register_netdev -0002cf19 net_interface_destroy -0002cf2e __default_restart -0002cf34 __default_stop -0002cf99 __default_start -0002d013 nm_new -0002d09c nm_free -0002d0e1 net_firewall_create -0002d104 fs_file2fd -0002d16b fs_alloc_file -0002d1b6 fs_free_file -0002d210 fs_register -0002d2df fs_init -0002d2e5 fs_unregister -0002d348 fs_get -0002d34e fs_close -0002d3c0 fs_open -0002d43a fs_seek -0002d4b7 fs_read -0002d5cc fs_load_from_file -0002d658 fs_write -0002d713 fs_save_to_file -0002d79f fat16_rmdir -0002d7a5 fat16_stat -0002d7ab fat16_close -0002d815 fat16_rename -0002d8aa fat16_mkdir -0002d98f fat16_remove -0002da02 fat16_open -0002db4c fat16_read -0002dcb0 fat16_write -0002dddf fat16_list -0002e0ad fat16_init -0002e161 path_next_iter -0002e1d0 inode_from_path_recursise -0002e24e inode_from_path -0002e30c ext_get_root -0002e315 ext_get_current_dir -0002e324 ext_get_size -0002e32a ext_get_inodes -0002e330 ext_get_blocks -0002e336 ext_sync -0002e3a9 ext_create -0002e494 ext_read -0002e50f ext_seek -0002e556 ext_write -0002e5c2 ext_close -0002e624 ext_open_from_directory -0002e72a ext_open -0002e7e1 ext_size -0002e80a change_directory -0002e870 ext_create_directory -0002ea0a ext_create_file_system -0002ecd7 init_ext -0002ee73 listdir -0002ef94 __inode_sync -0002eff7 __inode_cache_insert -0002f0ed __inode_load -0002f161 inodes_sync -0002f19c inode_get -0002f1f9 inode_read -0002f3e1 inode_write -0002f63f alloc_inode -0002f6f8 mkdir -0002f7a5 sync -0002f7d9 mkfs -0002f7e6 fat16_read_data_from_cluster -0002f834 fat16_read_data -0002f915 fat16_find_cluster_by_offset -0002f990 fat16_write_data_to_cluster_with_offset -0002f9cb fat16_print_cluster_chain -0002f9f9 fat16_write_data_to_cluster -0002fa2c fat16_write_data -0002fb48 get_fat_start_block -0002fb50 get_root_directory_start_block -0002fb5f get_data_start_block -0002fb71 fat16_get_fat_entry -0002fb8c fat16_set_fat_entry -0002fbcc fat16_sync_fat_table -0002fc44 fat16_allocate_cluster -0002fc5c fat16_free_cluster -0002fc71 fat16_get_free_cluster -0002fcc6 fat16_sync_directory_entry -0002fd48 fat16_read_entry -0002fdf5 fat16_find_entry -0002ff30 fat16_rename_entry -0002ffa1 fat16_free_clusters -0002ffe8 fat16_delete_entry -0003004f fat16_add_entry -000301b6 fat16_used_blocks -000301ef fat16_to_upper -0003021b fat16_name_compare -00030340 sstrtok -00030401 fat16_directory_entry_debug -000304d1 fat16_get_directory_entry -000306c9 fat16_create_directory -000307ce fat16_read_file -0003081f fat16_create_file -0003089d fat16_create_empty_file -0003095d fat16_directory_entries -00030a43 fat16_mbr_clear -00030aec fat16_mbr_add_entry -00030bdd fat16_print_root_directory_entries -00030bf5 fat16_change_directory -00030c7d fat16_bootblock_info -00030dfa fat16_set_time -00030e2e fat16_set_date -00030e66 fat16_load -00030fe5 fat16_format -0003129a mbr_partition_type_string -0003131d mbr_partitions_parse -000313e6 mbr_get -000313ec mbr_partition_load -0003140a __list_users -0003149b __change_user -0003153d __remove_user -000315e9 __add_user -000316d3 __find_user -000317a8 __authenticate_user -000318b6 __save_users -0003193a __load_users -00031b3c __ksymbol_admin -00031b56 admin -00031e6a usermanager_create -00031e89 __ksymbol_snakegame -00031ea3 init_game -00031ef1 draw -00031f4d get_input -00031f6c update -000320f3 game_loop -00032119 snakegame -00032164 __msgbox -00032564 msgbox_create -00032597 msgbox_show -000325df kevents_list -00032751 kevents_init -00032793 kevents_destroy -000327e8 kevents_add -0003289f kevents_create -00032922 _code_end +0001132f terminal_create +00011454 terminal_destroy +0001148c tlb_flush_addr +00011494 load_page_directory +000114a4 enable_paging +000114b6 pcb_save_context +000114e2 pcb_restore_context +0001150b _start_pcb +0001153d _start_pcb_skip +00011558 __ksymbol_lspci +00011572 pci_get_class_name +00011585 pci_get_device_name +000115f6 pci_get_vendor_name +00011644 lspci +00011791 pci_get_devices +00011797 pci_read_word +000117f1 pci_write_dword +00011840 pci_enable_device_busmaster +00011895 pci_register_device +00011916 init_pci +00011ac7 pci_find_device +00011b5d virtual_read +00011b88 virtual_write +00011bb3 virtual_disk_attach +00011bd2 wm_default_changes +00011c7a wm_default_workspace +00011cdc wm_default_draw +00011d7a wm_default_add +00011e21 init_windowmanager +00011f6b wm_default_mouse_event +00012191 wm_default_push_back +00012283 wm_default_push_front +00012372 wm_default_remove +00012483 wm_destroy +00012561 wm_new +000125c8 screen_set_cursor +00012628 scrcolor_set +0001263c scrput +00012662 scrwrite +000126ab scr_clear +000126fd scr_scroll +00012745 scrprintf +00012989 strlen +000129ab strcpy +000129df strncmp +00012a1a strcmp +00012a5a memcmp +00012a95 parse_arguments +00012b78 strchr +00012ba7 getopt +00012cb7 memcpy +00012d24 strtok +00012ddc xmemcpy +00012e63 memset +00012ee3 isdigit +00012ef7 isspace +00012f06 tolower +00012f1a isxdigit +00012f3e htoi +00012fe2 atoi +00013072 itoa +00013118 itohex +00013194 rdtsc +00013197 rand +000131b3 general_protection_fault +00013243 interrupt_get_count +00013252 print_page_fault_info +0001332f page_fault_interrupt +000133c1 interrupt_install_handler +000133d3 load_data_segments +000133df isr_handler +000134d2 init_interrupts +0001364b idt_flush +00013653 isr0 +00013660 isr1 +0001366d isr2 +0001367a isr3 +00013687 isr4 +00013694 isr5 +000136a1 isr6 +000136ae isr7 +000136bb isr8 +000136c8 isr9 +000136d5 isr10 +000136e2 isr11 +000136ef isr12 +000136fc isr13 +00013709 isr14 +00013716 isr15 +00013723 isr16 +00013730 isr17 +0001373d isr18 +0001374a isr19 +00013757 isr20 +00013764 isr21 +00013771 isr22 +0001377e isr23 +0001378b isr24 +00013798 isr25 +000137a5 isr26 +000137b2 isr27 +000137bf isr28 +000137cc isr29 +000137d9 isr30 +000137e6 isr31 +000137f3 isr32 +00013800 isr33 +0001380d isr34 +0001381a isr35 +00013824 isr36 +0001382e isr37 +00013838 isr38 +00013842 isr39 +0001384c isr40 +00013856 isr41 +00013860 isr42 +0001386a isr43 +00013874 isr44 +0001387e isr45 +00013888 isr46 +00013892 isr47 +0001389c isr_entry +000138b7 syscall_return_value +000138bb _syscall_entry +000138f8 page_fault_save +000138fc page_fault_error +00013900 _page_fault_entry +00013932 timer_callback +0001396a timer_get_tick +00013970 time_get_difference +000139b3 init_pit +00013a17 gdt_set_segment +00013a60 init_gdt +00013b6e rc +00013d5d __ksymbol_rc +00013d77 __ksymbol_as +00013d91 __ksymbol_cc +00013dab as +0001416d cc +000141c9 __cc +000144bd vm_print +000146ba eval +00014b54 vm_setup +00014b95 vm_init +00014bf0 vm_free +00014c1f vm_setup_stack +00014c7b lex_get_error +00014c88 next +00015193 match +000151e1 expression +000164e2 statement +000166eb function_parameter +000168ad function_body +00016abc function_declaration +00016b45 enum_declaration +00016c58 global_declaration +00016e85 lex_init +00016f20 program +00016fc1 find_mp_floating_ptr +00016ffd smp_parse +00017142 kb_get_char +0001718e kb_add_char +000171c9 kb_callback +000173f6 init_keyboard +0001746d pcb_await +00017497 __pcb_get_free +00017555 __add_systemcall_pcb_await +0001756c __pcb_free +000175bb __pcb_init_kernel_stack +0001761c __pcb_init_process +000176e1 init_pcbs +00017732 pcb_total_usage +0001775b pcb_get_info +0001784f pcb_kill +0001786c Genesis +0001786e idletask +00017889 pcb_get_by_pid +0001789a pcb_get_by_name +000178f3 pcb_dbg_print +0001796d pcb_cleanup_routine +00017b7d pcb_create_thread +00017c75 pcb_create_process +00017f07 pcb_create_kthread +000181e3 start_pcb +0001821b __pcb_queue_peek +0001825a __pcb_queue_pop +000182b6 __pcb_queue_remove +00018328 __pcb_queue_add +000183a1 __pcb_queue_push +0001843a pcb_new_queue +0001846b get_mem_info +000184c3 memory_map_init +0001858a memory_map_get +00018590 free +000185e7 malloc +00018683 calloc +000186b6 krealloc +00018722 init_memory +000187b4 vmem_free +00018824 vmem_alloc +00018891 vmem_free_page_region +000189f7 vmem_page_region_alloc +00018a32 vmem_create_page_region +00018b76 vmem_free_allocations +00018ca5 vmem_continious_allocation_map +00018cab vmem_free_allocation +00018cac vmem_stack_free +00018d5d vmem_stack_alloc +000190e2 vmem_dump_heap +00019177 vmem_init_process_thread +00019268 vmem_init_process +00019596 vmem_cleanup_process_thead +0001960d vmem_cleanup_process +000197fb vmem_init_kernel +000199bc vmem_allocator_create +00019a20 vmem_map_driver_region +00019a9e vmem_total_usage +00019ab1 vmem_init +00019be3 kalloc +00019d7a kcalloc +00019dac kfree +00019e42 palloc +00019e84 pmemory_used +00019ea0 kmemory_used +00019ea6 kmemory_total +00019eb2 kmem_init +00019f4f e1000_receive +0001a02a e1000_transmit +0001a0ec e1000_callback +0001a113 _e1000_tx_init +0001a1b7 _e1000_rx_init +0001a251 e1000_attach +0001a481 display_get_info +0001a4ea kenv_init +0001a501 kenv_set +0001a536 config_list +0001a607 kernel_config_load +0001a9f2 config_get_value +0001aaad spin_lock +0001aacd spin_unlock +0001aadb mutex_init +0001aaf8 acquire +0001ab95 release +0001ac37 kthread_entry +0001ac91 kthread_list +0001acf8 register_kthread +0001add1 start +0001ae73 ata_primary +0001ae74 ata_secondary +0001ae75 ata_wait +0001aeef ata_write +0001b066 ata_read +0001b1f6 ata_ide_init +0001b3c6 set_bitmap +0001b3e8 unset_bitmap +0001b40c get_bitmap +0001b42e get_bitmap_size +0001b442 create_bitmap +0001b476 destroy_bitmap +0001b489 bitmap_unset_continous +0001b4c3 bitmap_get_continous +0001b55f get_free_bitmap +0001b5b4 __rtc_check_in_progress +0001b5d6 __rtc_get_register +0001b5f6 get_current_time +0001b741 get_time +0001b76b init_tss +0001b799 exec_cmd +0001b89d __ksymbol_exec_cmd +0001b8b7 system_reboot +0001b8eb align_to_pointer_size +0001b8f9 calculate_size_unit +0001b95b advanced_hash +0001b98f kernel_panic +0001b9ad kref_init +0001b9c7 kref_get +0001b9ef kref_put +0001ba17 csprintf +0001bc18 script_parse +0001bced login +0001c08b __login_create_virt_disk +0001c0b5 __register_kthread_login +0001c0cf help +0001c370 clear +0001c391 __ksymbol_new +0001c3ab __ksymbol_list +0001c3c5 __ksymbol_color +0001c3df __ksymbol_about +0001c3f9 __ksymbol_help +0001c413 __ksymbol_kevents +0001c42d __ksymbol_view +0001c447 __ksymbol_file +0001c461 __ksymbol_tcp +0001c47b __ksymbol_conf +0001c495 __ksymbol_clear +0001c4af __ksymbol_services +0001c4c9 __ksymbol_reboot +0001c4e3 kevents +0001c5bd services +0001c7eb new +0001c92c list +0001ca2c file +0001cbfa color +0001cc9b about +0001ccd8 view +0001ceed tcp +0001d1ca __tcp_reader +0001d2eb conf +0001d5b3 reboot +0001d5ec attach_disk_dev +0001d610 disk_attached +0001d618 disk_name +0001d621 disk_device_get +0001d627 disk_size +0001d643 write_block +0001d680 write_block_offset +0001d6c3 read_block +0001d700 read_block_offset +0001d76a sched_consume +0001d7ab sched_add +0001d805 sched_prioritize +0001d8ba sched_round_robin +0001daa0 sched_exit +0001db59 sched_block +0001dc77 sched_default +0001dd51 sched_sleep +0001ddf7 sched_init_default +0001de78 get_scheduler +0001de7e kernel_sleep +0001de99 kernel_yield +0001dedc kernel_exit +0001df0e block +0001df37 unblock +0001df38 work_queue_add +0001e020 init_worker +0001e038 worker_thread +0001e0d7 __ring_buffer_add +0001e17f __ring_buffer_read +0001e289 rbuffer_new +0001e2f2 rbuffer_free +0001e314 error_get_string +0001e350 kclock +0001e830 __register_kthread_kclock +0001e84a tar_extract +0001ea9a __ksymbol_tar +0001eab4 tar_list +0001ebbe tar +0001ee47 rgb_to_vga +0001ee57 rgb_to_components +0001ee7e color_distance_squared +0001eee9 rgb_init_color_table +0001ef7a iface_loopback_write +0001f03b iface_loopback_interrupt +0001f052 iface_loopback_read +0001f0f5 net_init_loopback +0001f10c serial_put +0001f14c serial_write +0001f18e serial_printf +0001f32e init_serial +0001f3f4 inportb +0001f3fd inportw +0001f407 inportl +0001f410 outportb +0001f41e outportw +0001f42d outportl +0001f43a sys_create_thread +0001f459 __add_systemcall_sys_create_thread +0001f464 add_system_call +0001f4a4 system_call +0001f50f hashmap_put +0001f576 hashmap_get +0001f5fa hashmap_add +0001f684 hashmap_free +0001f685 reset_vga_palette +0001f6cb vga_set_palette +0001f7b6 b8to16 +0001f7c6 vesa_put_pixel +0001f7f0 vesa_put_box +0001f86b vesa_put_block +0001f8e6 vesa_put_char +0001f961 vesa_put_char16 +0001f9f4 vesa_put_icon16 +0001fa6d vesa_write +0001faac vesa_write_str +0001fada vesa_fill +0001fb5c vesa_fillrect +0001fbce vesa_inner_box +0001fcd6 vesa_printf +0001ff43 ksyms_init +0002016a ksyms_add_symbol +00020223 __ksymbol_backtrace +0002023d ksyms_list +0002029f ksyms_resolve_symbol +00020352 __backtrace_from +0002046f backtrace +00020480 ws_fullscreen +000205fa ws_remove +000206aa ws_add +00020795 ws_destroy +0002083b ws_draw +00020ae8 ws_raw_wallpaper +00020bce ws_set_background_file +00020eab ws_init +00020f8e ws_set_background +00021039 ws_new +000210c6 encode_run_length +00021143 decode_run_length +000211ae __mouse_handler +000212c5 mouse_wait +0002130d mouse_write +0002134f mouse_get_event +00021390 mouse_init +00021475 sys_ipc_open +000214c3 __add_systemcall_sys_ipc_open +000214da __add_systemcall_sys_ipc_close +000214f1 __add_systemcall_sys_ipc_send +00021508 __add_systemcall_sys_ipc_receive +0002151f sys_ipc_close +00021568 sys_ipc_send +000215cf sys_ipc_receive +00021635 sysinf +00022387 __register_kthread_sysinf +000223a1 echo +000223dc res +0002241d ifconfig +0002242a __ksymbol_ifconfig +00022444 __ksymbol_ps +0002245e __ksymbol_tree +00022478 __ksymbol_fat16 +00022492 __ksymbol_xxd +000224ac __ksymbol_sh +000224c6 __ksymbol_ed +000224e0 __ksymbol_exec +000224fa __ksymbol_ths +00022514 __ksymbol_dns +0002252e __ksymbol_th +00022548 __ksymbol_kill +00022562 __ksymbol_echo +0002257c __ksymbol_fdisk +00022596 __ksymbol_meminfo +000225b0 __ksymbol_res +000225ca __ksymbol_bg +000225e4 __ksymbol_exit +000225fe __ksymbol_socks +00022618 __ksymbol_reset +00022632 exit +00022666 ps +000228da print_pcb_tree +000229d9 tree +00022a19 fat16 +00022a41 xxd +00022b36 sh +00022c36 ed +00022c83 exec +00022de7 ths +00022e53 dns +00022ec7 th +00022ee5 kill +00022f03 fdisk +00023095 meminfo +00023274 bg +000232f3 socks +00023599 __register_kthread_shell +000235b3 __register_kthread_textshell +000235cd shell_clear +00023610 reset_shell +00023681 reset +000236d5 shell_put +000238b6 shell +00023b17 cleanup_function +00023b3e testfn +00023b72 draw_box +00023c57 __textshell_reset_box +00023ce7 textshell +000240b8 __net_find_interface +00024118 net_drop_packet +00024139 net_handle_recieve +00024260 net_get_interfaces +00024266 net_configure_iface +000242b8 net_incoming_packet +00024369 net_get_iface +000243df net_iface_up +00024406 net_iface_down +0002442d net_list_ifaces +00024547 net_register_interface +00024578 net_send_skb +00024600 net_get_info +00024627 networking_main +00024807 __dhcp_add_option +00024877 __dhcp_send_discovery +000249b9 __dhcp_send_request +00024b36 dhcp_get_state +00024b3e dhcp_get_dns +00024b44 dhcp_get_ip +00024b59 dhcp_get_gw +00024b6e dhcpd +00024ded udp_server +00024e78 tcp_server +00024fec __net_terminal_writef +00025051 __register_kthread_tcp_server +0002506b __register_kthread_udp_server +00025085 __register_kthread_udptest +0002509f udptest +0002512a tcpd +0002520e logd +00025279 __register_kthread_logd +00025293 logd_attach_by_pid +000252d7 taskbar_reboot +00025303 __reboot +00025318 taskbar_readme +00025331 taskbar_about +0002534a taskbar_clock +00025363 taskbar_sysinf +0002537c taskbar_bg_retro +000253b3 taskbar_bg_lotr2 +000253c8 taskbar_bg_lotr +000253dd taskbar_bg_default_color_gray +000253ef taskbar_bg_default_color +00025401 taskbar_wolfstein +0002543c taskbar_bg_graph +00025477 taskbar_bg_calc +000254b2 taskbar_colors +000254ed taskbar_cube +00025528 taskbar_editor +00025563 taskbar_finder +0002559e taskbar_terminal +000255e7 __register_kthread_taskbar +00025601 taskbar_hdr_opt_event +0002568b taskbar +00025c42 about +00025e0d __register_kthread_about +00025e27 __register_kthread_readme +00025e41 readme +00025fa3 gfx_default_hover +000260c2 gfx_destory_window +0002614f gfx_window_resize +000261f8 gfx_window_maximize +00026271 gfx_default_mouse_up +0002633f gfx_default_mouse_down +00026401 gfx_default_click +000265f0 gfx_draw_window +000273dc gfx_window_set_resizable +000273f1 kernel_gfx_window_border_color +0002741c gfx_new_window +0002767c gfx_point_in_rectangle +000276a9 gfx_draw_component +000276eb gfx_input_event +0002781d gfx_input_draw +00027925 gfx_input_manager_add +00027986 gfx_composition_remove_window +000279b0 gfx_composition_add_window +000279f7 gfx_set_background_color +00027a48 gfx_raw_background +00027a95 gfx_decode_background_image +00027ae2 gfx_set_taskbar +00027b82 gfx_compositor_main +00027bf6 kernel_gfx_draw_circle_helper +00027ea2 gfx_get_window_width +00027eb7 gfx_get_window_height +00027ecc gfx_push_event +00027f88 gfx_put_icon16 +00028080 gfx_put_icon32 +00028178 gfx_event_loop +00028297 kernel_gfx_draw_rectangle +00028391 kernel_gfx_draw_contoured_box +00028431 kernel_gfx_draw_pixel +000284cf kernel_gfx_draw_bitmap +000285ed kernel_gfx_draw_char +000286ed kernel_gfx_set_position +00028709 gfx_commit +00028722 kernel_gfx_draw_text +000287d5 gfx_button_ext +00028908 gfx_button +00028926 kernel_gfx_set_title +00028992 kernel_gfx_set_header +000289fe kernel_gfx_draw_line +00028b99 kernel_gfx_draw_circle +00028c18 kernel_gfx_draw_section +00028c1e kernel_gfx_draw_format_text +00028f70 gfx_syscall_hook +00029127 gfx_total_themes +0002912d kernel_gfx_current_theme +00029133 kernel_gfx_update_theme +00029201 kernel_gfx_default_theme +00029207 kernel_gfx_set_theme +0002922c kernel_gfx_get_theme +00029247 gfx_new_ctx +000292a3 gfx_init_framebuffer +0002940f netdev_attach_driver +000294b8 is_netdev_attached +000294c6 netdev_transmit +000294e1 netdev_recieve +0002950a net_ethernet_add_header +0002959e net_ethernet_parse +00029612 __skb_queue_remove +00029650 __skb_queue_add +000296a0 skb_free_queue +000296d8 skb_new_queue +0002973f skb_free +0002977a skb_new +000297e5 skb_consume +00029816 __net_arp_send +000298d6 net_init_arp +00029922 net_arp_add_entry +000299b1 net_arp_find_entry +000299fc net_arp_respond +00029a71 net_net_arp_request +00029af7 arp_parse +00029ba1 net_ipv4_print +00029ba7 net_ipv4_add_header +00029cde net_is_ipv4 +00029d1b net_ipv4_parse +00029e48 ntohl +00029e74 htonl +00029e87 ntohs +00029e94 htons +00029ea1 checksum +00029ef8 transport_checksum +00029f4d ip_to_int +00029feb net_icmp_handle +0002a0b0 net_icmp_response +0002a0b6 net_icmp_request +0002a179 ping +0002a1d2 net_icmp_parse +0002a242 net_udp_send +0002a377 net_udp_parse +0002a49f socket_type_to_str +0002a4ae socket_domain_to_str +0002a4bd socket_protocol_to_str +0002a4cc net_sock_bind +0002a517 net_get_sockets +0002a533 sock_get +0002a554 get_total_sockets +0002a55a net_sock_is_established +0002a59e net_sock_awaiting_ack +0002a5e2 net_sock_data_ready +0002a63b net_sock_read +0002a73d net_sock_add_data +0002a99d sock_find_listen_tcp +0002a9e1 net_sock_find_tcp +0002abd3 net_prepare_tcp_sock +0002ac5f net_sock_accept +0002ac72 net_socket_find_udp +0002acdd kernel_sock_shutdown +0002ad0a kernel_sock_cleanup +0002ad90 kernel_sock_close +0002adc4 kernel_socket_create +0002af47 net_init_sockets +0002af8d gethostname +0002b4a7 __add_systemcall_gethostname +0002b4be net_init_dns +0002b4ed route +0002b53a tcb_init +0002b558 tcb_new +0002b6c4 tcp_state_to_str +0002b6dd tcp_new_connection +0002b765 tcp_free_connection +0002b788 tcp_is_listening +0002b79e tcp_set_listening +0002b7fe tcp_calculate_checksum +0002b8c2 __tcp_send +0002b9de tcp_send_segment +0002bb21 tcp_accept_connection +0002bc63 tcp_send_ack +0002bd99 tcp_read +0002bd9f tcp_recv_segment +0002bda5 tcp_connect +0002be48 tcp_send_syn +0002be4e tcp_recv_ack +0002bed1 tcp_recv_fin +0002bed7 tcp_recv_syn +0002c009 tcp_send_fin +0002c0d5 tcp_close_connection +0002c114 tcp_parse +0002c5ad kernel_bind +0002c5e2 kernel_recvfrom +0002c5e8 kernel_recv +0002c65a kernel_recv_timeout +0002c680 kernel_connect +0002c784 kernel_sendto +0002c83e kernel_accept +0002c8a1 kernel_listen +0002c8c9 kernel_send +0002c94f sys_kernel_bind +0002c981 __add_systemcall_sys_kernel_bind +0002c998 __add_systemcall_sys_kernel_accept +0002c9af __add_systemcall_sys_kernel_connect +0002c9c6 __add_systemcall_sys_kernel_listen +0002c9dd __add_systemcall_sys_kernel_recv +0002c9f4 __add_systemcall_sys_kernel_recvfrom +0002ca0b __add_systemcall_sys_kernel_recv_timeout +0002ca22 __add_systemcall_sys_kernel_send +0002ca39 __add_systemcall_sys_kernel_sendto +0002ca50 __add_systemcall_sys_socket_create +0002ca67 __add_systemcall_sys_kernel_sock_close +0002ca7e sys_kernel_accept +0002cabe sys_kernel_connect +0002caf0 sys_kernel_listen +0002cb1f sys_kernel_recv +0002cb57 sys_kernel_recvfrom +0002cb97 sys_kernel_recv_timeout +0002cbd5 sys_kernel_send +0002cc0d sys_kernel_sendto +0002cc4d sys_socket_create +0002cc74 sys_kernel_sock_close +0002ccb5 __iface_send +0002cce4 __iface_recieve +0002cd13 __iface_assign +0002cd26 __iface_detach +0002cd3a __iface_set_gateway +0002cd4d __iface_set_netmask +0002cd60 __iface_configure +0002cdb0 __iface_attach +0002cdd5 net_interface_create +0002ce0d net_register_netdev +0002cf25 net_interface_destroy +0002cf3a __default_restart +0002cf40 __default_stop +0002cfa5 __default_start +0002d01f nm_new +0002d0a8 nm_free +0002d0ed net_firewall_create +0002d110 fs_file2fd +0002d177 fs_alloc_file +0002d1c2 fs_free_file +0002d21c fs_register +0002d2eb fs_init +0002d2f1 fs_unregister +0002d354 fs_get +0002d35a fs_close +0002d3cc fs_open +0002d446 fs_seek +0002d4c3 fs_read +0002d5d8 fs_load_from_file +0002d664 fs_write +0002d71f fs_save_to_file +0002d7ab fat16_rmdir +0002d7b1 fat16_stat +0002d7b7 fat16_close +0002d821 fat16_rename +0002d8b6 fat16_mkdir +0002d99b fat16_remove +0002da0e fat16_open +0002db58 fat16_read +0002dcbc fat16_write +0002ddeb fat16_list +0002e0b9 fat16_init +0002e16d path_next_iter +0002e1dc inode_from_path_recursise +0002e25a inode_from_path +0002e318 ext_get_root +0002e321 ext_get_current_dir +0002e330 ext_get_size +0002e336 ext_get_inodes +0002e33c ext_get_blocks +0002e342 ext_sync +0002e3b5 ext_create +0002e4a0 ext_read +0002e51b ext_seek +0002e562 ext_write +0002e5ce ext_close +0002e630 ext_open_from_directory +0002e736 ext_open +0002e7ed ext_size +0002e816 change_directory +0002e87c ext_create_directory +0002ea16 ext_create_file_system +0002ece3 init_ext +0002ee7f listdir +0002efa0 __inode_sync +0002f003 __inode_cache_insert +0002f0f9 __inode_load +0002f16d inodes_sync +0002f1a8 inode_get +0002f205 inode_read +0002f3ed inode_write +0002f64b alloc_inode +0002f704 mkdir +0002f7b1 sync +0002f7e5 mkfs +0002f7f2 fat16_read_data_from_cluster +0002f840 fat16_read_data +0002f921 fat16_find_cluster_by_offset +0002f99c fat16_write_data_to_cluster_with_offset +0002f9d7 fat16_print_cluster_chain +0002fa05 fat16_write_data_to_cluster +0002fa38 fat16_write_data +0002fb54 get_fat_start_block +0002fb5c get_root_directory_start_block +0002fb6b get_data_start_block +0002fb7d fat16_get_fat_entry +0002fb98 fat16_set_fat_entry +0002fbd8 fat16_sync_fat_table +0002fc50 fat16_allocate_cluster +0002fc68 fat16_free_cluster +0002fc7d fat16_get_free_cluster +0002fcd2 fat16_sync_directory_entry +0002fd54 fat16_read_entry +0002fe01 fat16_find_entry +0002ff3c fat16_rename_entry +0002ffad fat16_free_clusters +0002fff4 fat16_delete_entry +0003005b fat16_add_entry +000301c2 fat16_used_blocks +000301fb fat16_to_upper +00030227 fat16_name_compare +0003034c sstrtok +0003040d fat16_directory_entry_debug +000304dd fat16_get_directory_entry +000306d5 fat16_create_directory +000307da fat16_read_file +0003082b fat16_create_file +000308a9 fat16_create_empty_file +00030969 fat16_directory_entries +00030a4f fat16_mbr_clear +00030af8 fat16_mbr_add_entry +00030be9 fat16_print_root_directory_entries +00030c01 fat16_change_directory +00030c89 fat16_bootblock_info +00030e06 fat16_set_time +00030e3a fat16_set_date +00030e72 fat16_load +00030ff1 fat16_format +000312a6 mbr_partition_type_string +00031329 mbr_partitions_parse +000313f2 mbr_get +000313f8 mbr_partition_load +00031416 __list_users +000314a7 __change_user +00031549 __remove_user +000315f5 __add_user +000316df __find_user +000317b4 __authenticate_user +000318c2 __save_users +00031946 __load_users +00031b48 __ksymbol_admin +00031b62 admin +00031e76 usermanager_create +00031e95 __ksymbol_snakegame +00031eaf init_game +00031efd draw +00031f59 get_input +00031f78 update +000320ff game_loop +00032125 snakegame +00032170 __msgbox +00032570 msgbox_create +000325a3 msgbox_show +000325eb kevents_list +0003275d kevents_init +0003279f kevents_destroy +000327f4 kevents_add +000328ab kevents_create +0003292e _code_end From 51a4e58ce3889a937f6005332e4aac89bba897b3 Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Sun, 28 Jan 2024 19:31:14 +0100 Subject: [PATCH 04/23] system syscall and user creation --- apps/libcore.a | Bin 18974 -> 20194 bytes apps/users/users.cpp | 17 +- apps/utils/Function.hpp | 3 - apps/utils/Widgets.hpp | 9 + include/lib/printf.h | 2 + include/syscall_helper.h | 2 + kernel/kutils.c | 12 + lib/printf.c | 72 ++- lib/syscall.c | 5 + rootfs/symbols.map | 1176 +++++++++++++++++++------------------- 10 files changed, 703 insertions(+), 595 deletions(-) diff --git a/apps/libcore.a b/apps/libcore.a index 04c196e0b8502c1f9076323733fd15738ee4e291..39a09ad6114eaccc2bac1010ad2a9ea4a104e6c3 100644 GIT binary patch delta 2639 zcmcJRdrVVT7{JfDy|4kb>lZ z;FH9Duw@AI484&HVE`u~j`1vjMjM-HcS^Z&gdAa|(6UK{tYCYfRcR*V3Tv=C>9wY> z?G2;FsWWnNVIdQRKmuz_Q)2w7G}JUf%_km~Z%JQ{0BA1xWC>_&Rl^UY}6cU&`ksF%GhvF=!MMrP>} z%%k5{VmSQV1kqis>fu`$w#`x3CGVdO3Kuae&{~@k$-AAx;}S)HLH&zipn=yk!7zqMpu^7z7E+x zpVuTaQWGB-YlRMdtB9qD6cGBn8W2w1357h2B~rU}9qH=vb$NEd!SDv?-o++379*&y ztNN}Q3{^bdF166n*ABLQtx@mFU)|GSBmh*h(BTb;kz@AcOlU=p@Z>?q0`#@RSbVkE z;k_@)2UZTMF`RCwF(_emJus#AnBV}5iI+?{iZ@7SbyxqYCtD-Mf)qneOxReyW|95F zeO72I@1gmvD5Rl!n2kOWw2L@S2vO+qKLMR2JvrJ+ukGb(uwYcne- zzZuku6w4)%64*rk-lUafNB_t#P&DBgr5Il8PH-EmpZO2=WiY2i4P4+L+Kv(vSOaf} z>ltOXNJ#t;xPMBkt7Va_a7QNDPYp~!_ zL3_cMHc>1{AOtVMb0FJ6mkyzCx=WuJu*tSWR^zIF3vbBxK`_E|aA!@2cJy&TBQM$k zV!t4!zX1Bth+xl(GG`>McdxHJT$@T_LXGF{49FcBc(D?kcs z4q@L$$Xz5{%fBHlgy3B(z?HlRNMWCfu@9g7T}aUX5DEGpAwmBr=UL8fB-kgw(gZsp ziO4uoLdIeP4DurbWIpe&MuNeoNJvnEpqSuzAO_rt1V^WMzX1t;It@0JyJi>XD^91Kf&eNP{I2$=X=4=PtW@&|3#zj6tW=>< zG(O{ZrZ}R_t64_#W>&iSJUFpXX2}MVcsO+e%gIg^+9b9(J6#x%&~jusx&nb6FrERp w=5Di7*-mK!6mBB>D%)wl4yDAbp<+a02kc{|HaIPd@B=Trkh9UOik`NIVk=U3-#O(of{#`5E2z&5PPk;Y&&hK3Qx9{aC;q-AK zG|fM$)RGt*3;?hcKve#Z$Zr6KApW6{hQ!HT0?=P3t_Bz^CHVjYWzAs2|J3oj;Q~Ii zxbY-Ahs!jdutF@-lqh9*P|RaDbv z(21{&HU2=O?SP?Nt56$VkkK+yR3=aA>&vIZJbPf3+PkJ{tv={620Rf{OmmgjJJeRU zBk(@x{aC$j{n{I9uUMnhK+qGb?EV&y$JLu=Q*5@NcCU0<_LrJsZSkB&9@XTD1k1(1 z!id_d4>rWmoi`R;4q1ELmFqi!iyR}FCxSJOg5eF3w~?lWk-#1G`T%;?hJY(4RYLvB zOvk*uT(5CO!g!Hy$N2WZ@-TJK_`q~@9(k|v%0#KL^ab7)$T_tkT=%vokKDial{tF&aiN1!^xRLf>O~@$Vvt;W2hSg9i1f6QKX-Fs>Ib(3fOpi(Kc$*TW9ZPX z|A9RGFG=S2^L_3&PZi`1Bre(K2_fq}Qox;|Z)CG%?c5`p!=kFKHr#M`xNo~}8AZ{Z zj-fOKv$HcWvtZMV$;946!o!Av04|!RhM6X_Qwky1%LnRsx1cnucJH=bzAdoRyK|q{ z2ittRH}b!&-g>}Mh2#BaD1@a0Tp<+bem>&55#Sj|9l$G&bm?`}0;5}7MkvsUPv<&) zv(|AW{uYkJ-^G#m^+^mSv6UmmKjA0?baB+dIOt9iB-(qPAcG?%$mb|UGbb7Z%rCNF zm8}TXB0qDn<{YbJ)&krCbShR>%dk?hb7-5AZJ^I*VvrhE?DVGT*#LGbR_O_a=mq>p zA)vv`VmotcaAvVx>!jtJ$L+;7nLkwvh0}V#fG_0H+Ai{S;iY1m)JB`LIPqi|=%V_P Hr&&J%lc9It diff --git a/apps/users/users.cpp b/apps/users/users.cpp index 951ce5d..e736b72 100644 --- a/apps/users/users.cpp +++ b/apps/users/users.cpp @@ -29,12 +29,15 @@ class UserEditor : public Window { LAYOUT_FLAG_BORDER )); + username = new Input(100, 14, "Username"); + password = new Input(100, 14, "Password"); + widgets->addWidget(main, CENTER, new Label("Create a new user")); widgets->addWidget(main, LEFT, new Spacing(0, 8)); widgets->addWidget(main, LEFT, new Label("Username:")); - widgets->addWidget(main, LEFT, new Input(100, 14, "Input")); + widgets->addWidget(main, LEFT, username); widgets->addWidget(main, LEFT, new Label("Password:")); - widgets->addWidget(main, LEFT, new Input(100, 14, "Input")); + widgets->addWidget(main, LEFT, password); widgets->addWidget(main, LEFT, new Spacing(0, 8)); widgets->addWidget(main, CENTER, new Label("Permissions:")); widgets->addWidget(main, LEFT, new Checkbox(false, "Admin")); @@ -42,10 +45,13 @@ class UserEditor : public Window { widgets->addWidget(main, LEFT, new Checkbox(false, "Guest")); widgets->addWidget(bottom, RIGHT, new Button(50, 14, "Cancel", Function([this]() { - printf("Button pressed %d!\n", test); + delete widgets; + exit(); }))); + widgets->addWidget(bottom, RIGHT, new Button(50, 14, "Create", Function([this]() { - printf("Button pressed!\n"); + printf("Username: %s\n", username->getData()); + printf("Password: %s\n", password->getData()); }))); } @@ -82,6 +88,9 @@ class UserEditor : public Window { int width; int height; WidgetManager* widgets; + + Input* username; + Input* password; }; void editorEntry(void* arg) { diff --git a/apps/utils/Function.hpp b/apps/utils/Function.hpp index ec9670f..d8c4222 100644 --- a/apps/utils/Function.hpp +++ b/apps/utils/Function.hpp @@ -37,9 +37,6 @@ class Function { Function(const Function& other) { if (other.callable) { - // The challenge is to clone `other.callable`. - // This requires a mechanism in `BaseCallable` and its derived classes - // to clone themselves. callable = other.callable->clone(); } else { callable = nullptr; diff --git a/apps/utils/Widgets.hpp b/apps/utils/Widgets.hpp index 7e6f4f9..d12fe31 100644 --- a/apps/utils/Widgets.hpp +++ b/apps/utils/Widgets.hpp @@ -31,6 +31,14 @@ class Widget { virtual void Mouse() = 0; virtual bool focusable() = 0; /* Indicates if the widget can receive focus */ virtual ~Widget() {} + + void disable() { + disabled = true; + } + + void enable() { + disabled = false; + } /* Widget properties */ int x = 0; @@ -38,6 +46,7 @@ class Widget { int width = 0; int height = 0; bool focused = false; + bool disabled = false; protected: }; diff --git a/include/lib/printf.h b/include/lib/printf.h index f3e6cba..3d667c2 100644 --- a/include/lib/printf.h +++ b/include/lib/printf.h @@ -2,6 +2,7 @@ #define __PRINTF_H #include +#include #ifdef __cplusplus extern "C" @@ -12,6 +13,7 @@ void print_write(const char* data, int size); void print(const char* data); void println(const char* data); int printf(const char* fmt, ...); +int sprintf(char *buffer, const char *fmt, va_list args); #ifdef __cplusplus } diff --git a/include/syscall_helper.h b/include/syscall_helper.h index d210c5a..d006562 100644 --- a/include/syscall_helper.h +++ b/include/syscall_helper.h @@ -43,6 +43,8 @@ enum { SYSCALL_YIELD, SYSCALL_JOIN_THREAD, SYSCALL_AWAIT_PROCESS, + + SYSCALL_SYSTEM }; #endif /* __SYSCALL_HELPER_H */ diff --git a/kernel/kutils.c b/kernel/kutils.c index abe8aaf..886c638 100644 --- a/kernel/kutils.c +++ b/kernel/kutils.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include static char *units[] = {"b ", "kb", "mb"}; @@ -45,6 +47,16 @@ int align_to_pointer_size(int size) return aligned_size; } +static int sys_system(const char *command) +{ + int ret = 0; + + ret = exec_cmd(command); + + return ret; +} +EXPORT_SYSCALL(SYSCALL_SYSTEM, sys_system); + int exec_cmd(char* str) { struct args args = { diff --git a/lib/printf.c b/lib/printf.c index f7bbed5..46da6ad 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -45,7 +45,7 @@ void println(const char* data) print_put('\n'); } -#define MAX_FMT_STR_SIZE 50 +#define MAX_FMT_STR_SIZE 256 int printf(const char* fmt, ...) { @@ -126,6 +126,76 @@ int printf(const char* fmt, ...) return written; } +/* Custom sprintf function */ +int sprintf(char *buffer, const char *fmt, va_list args) +{ + int written = 0; /* Number of characters written */ + char str[MAX_FMT_STR_SIZE]; + int num = 0; + + while (*fmt != '\0' && written < MAX_FMT_STR_SIZE) { + if (*fmt == '%') { + memset(str, 0, MAX_FMT_STR_SIZE); /* Clear the buffer */ + fmt++; /* Move to the format specifier */ + + if (written < MAX_FMT_STR_SIZE - 1) { + switch (*fmt) { + case 'd': + case 'i': + num = va_arg(args, int); + itoa(num, str); + break; + case 'x': + case 'X': + num = va_arg(args, unsigned int); + written += itohex(num, str); + break; + case 'p': /* p for padded int */ + num = va_arg(args, int); + itoa(num, str); + + if (strlen(str) < 5) { + int pad = 5 - strlen(str); + for (int i = 0; i < pad; i++) { + buffer[written++] = '0'; + } + } + break; + case 's':{ + char *str_arg = va_arg(args, char*); + while (*str_arg != '\0' && written < MAX_FMT_STR_SIZE - 1) { + buffer[written++] = *str_arg++; + } + } + break; + case 'c': + if (written < MAX_FMT_STR_SIZE - 1) { + buffer[written++] = (char)va_arg(args, int); + } + break; + /* Add additional format specifiers as needed */ + } + + /* Copy formatted string to buffer */ + for (int i = 0; str[i] != '\0'; i++) { + buffer[written++] = str[i]; + } + } + } else { + /* Directly copy characters that are not format specifiers */ + if (written < MAX_FMT_STR_SIZE - 1) { + buffer[written++] = *fmt; + } + } + fmt++; + } + + /* Ensure the buffer is null-terminated */ + buffer[written < MAX_FMT_STR_SIZE ? written : MAX_FMT_STR_SIZE - 1] = '\0'; + + return written; +} + #ifdef __cplusplus } #endif diff --git a/lib/syscall.c b/lib/syscall.c index 292be29..15edb92 100644 --- a/lib/syscall.c +++ b/lib/syscall.c @@ -118,6 +118,11 @@ int fclose(int fd) return invoke_syscall(SYSCALL_CLOSE, fd, 0, 0); } +int system(const char* command) +{ + return invoke_syscall(SYSCALL_SYSTEM, (int)command, 0, 0); +} + #ifdef __cplusplus } #endif diff --git a/rootfs/symbols.map b/rootfs/symbols.map index f7df4ac..1ba3029 100644 --- a/rootfs/symbols.map +++ b/rootfs/symbols.map @@ -299,590 +299,592 @@ 0001b5f6 get_current_time 0001b741 get_time 0001b76b init_tss -0001b799 exec_cmd -0001b89d __ksymbol_exec_cmd -0001b8b7 system_reboot -0001b8eb align_to_pointer_size -0001b8f9 calculate_size_unit -0001b95b advanced_hash -0001b98f kernel_panic -0001b9ad kref_init -0001b9c7 kref_get -0001b9ef kref_put -0001ba17 csprintf -0001bc18 script_parse -0001bced login -0001c08b __login_create_virt_disk -0001c0b5 __register_kthread_login -0001c0cf help -0001c370 clear -0001c391 __ksymbol_new -0001c3ab __ksymbol_list -0001c3c5 __ksymbol_color -0001c3df __ksymbol_about -0001c3f9 __ksymbol_help -0001c413 __ksymbol_kevents -0001c42d __ksymbol_view -0001c447 __ksymbol_file -0001c461 __ksymbol_tcp -0001c47b __ksymbol_conf -0001c495 __ksymbol_clear -0001c4af __ksymbol_services -0001c4c9 __ksymbol_reboot -0001c4e3 kevents -0001c5bd services -0001c7eb new -0001c92c list -0001ca2c file -0001cbfa color -0001cc9b about -0001ccd8 view -0001ceed tcp -0001d1ca __tcp_reader -0001d2eb conf -0001d5b3 reboot -0001d5ec attach_disk_dev -0001d610 disk_attached -0001d618 disk_name -0001d621 disk_device_get -0001d627 disk_size -0001d643 write_block -0001d680 write_block_offset -0001d6c3 read_block -0001d700 read_block_offset -0001d76a sched_consume -0001d7ab sched_add -0001d805 sched_prioritize -0001d8ba sched_round_robin -0001daa0 sched_exit -0001db59 sched_block -0001dc77 sched_default -0001dd51 sched_sleep -0001ddf7 sched_init_default -0001de78 get_scheduler -0001de7e kernel_sleep -0001de99 kernel_yield -0001dedc kernel_exit -0001df0e block -0001df37 unblock -0001df38 work_queue_add -0001e020 init_worker -0001e038 worker_thread -0001e0d7 __ring_buffer_add -0001e17f __ring_buffer_read -0001e289 rbuffer_new -0001e2f2 rbuffer_free -0001e314 error_get_string -0001e350 kclock -0001e830 __register_kthread_kclock -0001e84a tar_extract -0001ea9a __ksymbol_tar -0001eab4 tar_list -0001ebbe tar -0001ee47 rgb_to_vga -0001ee57 rgb_to_components -0001ee7e color_distance_squared -0001eee9 rgb_init_color_table -0001ef7a iface_loopback_write -0001f03b iface_loopback_interrupt -0001f052 iface_loopback_read -0001f0f5 net_init_loopback -0001f10c serial_put -0001f14c serial_write -0001f18e serial_printf -0001f32e init_serial -0001f3f4 inportb -0001f3fd inportw -0001f407 inportl -0001f410 outportb -0001f41e outportw -0001f42d outportl -0001f43a sys_create_thread -0001f459 __add_systemcall_sys_create_thread -0001f464 add_system_call -0001f4a4 system_call -0001f50f hashmap_put -0001f576 hashmap_get -0001f5fa hashmap_add -0001f684 hashmap_free -0001f685 reset_vga_palette -0001f6cb vga_set_palette -0001f7b6 b8to16 -0001f7c6 vesa_put_pixel -0001f7f0 vesa_put_box -0001f86b vesa_put_block -0001f8e6 vesa_put_char -0001f961 vesa_put_char16 -0001f9f4 vesa_put_icon16 -0001fa6d vesa_write -0001faac vesa_write_str -0001fada vesa_fill -0001fb5c vesa_fillrect -0001fbce vesa_inner_box -0001fcd6 vesa_printf -0001ff43 ksyms_init -0002016a ksyms_add_symbol -00020223 __ksymbol_backtrace -0002023d ksyms_list -0002029f ksyms_resolve_symbol -00020352 __backtrace_from -0002046f backtrace -00020480 ws_fullscreen -000205fa ws_remove -000206aa ws_add -00020795 ws_destroy -0002083b ws_draw -00020ae8 ws_raw_wallpaper -00020bce ws_set_background_file -00020eab ws_init -00020f8e ws_set_background -00021039 ws_new -000210c6 encode_run_length -00021143 decode_run_length -000211ae __mouse_handler -000212c5 mouse_wait -0002130d mouse_write -0002134f mouse_get_event -00021390 mouse_init -00021475 sys_ipc_open -000214c3 __add_systemcall_sys_ipc_open -000214da __add_systemcall_sys_ipc_close -000214f1 __add_systemcall_sys_ipc_send -00021508 __add_systemcall_sys_ipc_receive -0002151f sys_ipc_close -00021568 sys_ipc_send -000215cf sys_ipc_receive -00021635 sysinf -00022387 __register_kthread_sysinf -000223a1 echo -000223dc res -0002241d ifconfig -0002242a __ksymbol_ifconfig -00022444 __ksymbol_ps -0002245e __ksymbol_tree -00022478 __ksymbol_fat16 -00022492 __ksymbol_xxd -000224ac __ksymbol_sh -000224c6 __ksymbol_ed -000224e0 __ksymbol_exec -000224fa __ksymbol_ths -00022514 __ksymbol_dns -0002252e __ksymbol_th -00022548 __ksymbol_kill -00022562 __ksymbol_echo -0002257c __ksymbol_fdisk -00022596 __ksymbol_meminfo -000225b0 __ksymbol_res -000225ca __ksymbol_bg -000225e4 __ksymbol_exit -000225fe __ksymbol_socks -00022618 __ksymbol_reset -00022632 exit -00022666 ps -000228da print_pcb_tree -000229d9 tree -00022a19 fat16 -00022a41 xxd -00022b36 sh -00022c36 ed -00022c83 exec -00022de7 ths -00022e53 dns -00022ec7 th -00022ee5 kill -00022f03 fdisk -00023095 meminfo -00023274 bg -000232f3 socks -00023599 __register_kthread_shell -000235b3 __register_kthread_textshell -000235cd shell_clear -00023610 reset_shell -00023681 reset -000236d5 shell_put -000238b6 shell -00023b17 cleanup_function -00023b3e testfn -00023b72 draw_box -00023c57 __textshell_reset_box -00023ce7 textshell -000240b8 __net_find_interface -00024118 net_drop_packet -00024139 net_handle_recieve -00024260 net_get_interfaces -00024266 net_configure_iface -000242b8 net_incoming_packet -00024369 net_get_iface -000243df net_iface_up -00024406 net_iface_down -0002442d net_list_ifaces -00024547 net_register_interface -00024578 net_send_skb -00024600 net_get_info -00024627 networking_main -00024807 __dhcp_add_option -00024877 __dhcp_send_discovery -000249b9 __dhcp_send_request -00024b36 dhcp_get_state -00024b3e dhcp_get_dns -00024b44 dhcp_get_ip -00024b59 dhcp_get_gw -00024b6e dhcpd -00024ded udp_server -00024e78 tcp_server -00024fec __net_terminal_writef -00025051 __register_kthread_tcp_server -0002506b __register_kthread_udp_server -00025085 __register_kthread_udptest -0002509f udptest -0002512a tcpd -0002520e logd -00025279 __register_kthread_logd -00025293 logd_attach_by_pid -000252d7 taskbar_reboot -00025303 __reboot -00025318 taskbar_readme -00025331 taskbar_about -0002534a taskbar_clock -00025363 taskbar_sysinf -0002537c taskbar_bg_retro -000253b3 taskbar_bg_lotr2 -000253c8 taskbar_bg_lotr -000253dd taskbar_bg_default_color_gray -000253ef taskbar_bg_default_color -00025401 taskbar_wolfstein -0002543c taskbar_bg_graph -00025477 taskbar_bg_calc -000254b2 taskbar_colors -000254ed taskbar_cube -00025528 taskbar_editor -00025563 taskbar_finder -0002559e taskbar_terminal -000255e7 __register_kthread_taskbar -00025601 taskbar_hdr_opt_event -0002568b taskbar -00025c42 about -00025e0d __register_kthread_about -00025e27 __register_kthread_readme -00025e41 readme -00025fa3 gfx_default_hover -000260c2 gfx_destory_window -0002614f gfx_window_resize -000261f8 gfx_window_maximize -00026271 gfx_default_mouse_up -0002633f gfx_default_mouse_down -00026401 gfx_default_click -000265f0 gfx_draw_window -000273dc gfx_window_set_resizable -000273f1 kernel_gfx_window_border_color -0002741c gfx_new_window -0002767c gfx_point_in_rectangle -000276a9 gfx_draw_component -000276eb gfx_input_event -0002781d gfx_input_draw -00027925 gfx_input_manager_add -00027986 gfx_composition_remove_window -000279b0 gfx_composition_add_window -000279f7 gfx_set_background_color -00027a48 gfx_raw_background -00027a95 gfx_decode_background_image -00027ae2 gfx_set_taskbar -00027b82 gfx_compositor_main -00027bf6 kernel_gfx_draw_circle_helper -00027ea2 gfx_get_window_width -00027eb7 gfx_get_window_height -00027ecc gfx_push_event -00027f88 gfx_put_icon16 -00028080 gfx_put_icon32 -00028178 gfx_event_loop -00028297 kernel_gfx_draw_rectangle -00028391 kernel_gfx_draw_contoured_box -00028431 kernel_gfx_draw_pixel -000284cf kernel_gfx_draw_bitmap -000285ed kernel_gfx_draw_char -000286ed kernel_gfx_set_position -00028709 gfx_commit -00028722 kernel_gfx_draw_text -000287d5 gfx_button_ext -00028908 gfx_button -00028926 kernel_gfx_set_title -00028992 kernel_gfx_set_header -000289fe kernel_gfx_draw_line -00028b99 kernel_gfx_draw_circle -00028c18 kernel_gfx_draw_section -00028c1e kernel_gfx_draw_format_text -00028f70 gfx_syscall_hook -00029127 gfx_total_themes -0002912d kernel_gfx_current_theme -00029133 kernel_gfx_update_theme -00029201 kernel_gfx_default_theme -00029207 kernel_gfx_set_theme -0002922c kernel_gfx_get_theme -00029247 gfx_new_ctx -000292a3 gfx_init_framebuffer -0002940f netdev_attach_driver -000294b8 is_netdev_attached -000294c6 netdev_transmit -000294e1 netdev_recieve -0002950a net_ethernet_add_header -0002959e net_ethernet_parse -00029612 __skb_queue_remove -00029650 __skb_queue_add -000296a0 skb_free_queue -000296d8 skb_new_queue -0002973f skb_free -0002977a skb_new -000297e5 skb_consume -00029816 __net_arp_send -000298d6 net_init_arp -00029922 net_arp_add_entry -000299b1 net_arp_find_entry -000299fc net_arp_respond -00029a71 net_net_arp_request -00029af7 arp_parse -00029ba1 net_ipv4_print -00029ba7 net_ipv4_add_header -00029cde net_is_ipv4 -00029d1b net_ipv4_parse -00029e48 ntohl -00029e74 htonl -00029e87 ntohs -00029e94 htons -00029ea1 checksum -00029ef8 transport_checksum -00029f4d ip_to_int -00029feb net_icmp_handle -0002a0b0 net_icmp_response -0002a0b6 net_icmp_request -0002a179 ping -0002a1d2 net_icmp_parse -0002a242 net_udp_send -0002a377 net_udp_parse -0002a49f socket_type_to_str -0002a4ae socket_domain_to_str -0002a4bd socket_protocol_to_str -0002a4cc net_sock_bind -0002a517 net_get_sockets -0002a533 sock_get -0002a554 get_total_sockets -0002a55a net_sock_is_established -0002a59e net_sock_awaiting_ack -0002a5e2 net_sock_data_ready -0002a63b net_sock_read -0002a73d net_sock_add_data -0002a99d sock_find_listen_tcp -0002a9e1 net_sock_find_tcp -0002abd3 net_prepare_tcp_sock -0002ac5f net_sock_accept -0002ac72 net_socket_find_udp -0002acdd kernel_sock_shutdown -0002ad0a kernel_sock_cleanup -0002ad90 kernel_sock_close -0002adc4 kernel_socket_create -0002af47 net_init_sockets -0002af8d gethostname -0002b4a7 __add_systemcall_gethostname -0002b4be net_init_dns -0002b4ed route -0002b53a tcb_init -0002b558 tcb_new -0002b6c4 tcp_state_to_str -0002b6dd tcp_new_connection -0002b765 tcp_free_connection -0002b788 tcp_is_listening -0002b79e tcp_set_listening -0002b7fe tcp_calculate_checksum -0002b8c2 __tcp_send -0002b9de tcp_send_segment -0002bb21 tcp_accept_connection -0002bc63 tcp_send_ack -0002bd99 tcp_read -0002bd9f tcp_recv_segment -0002bda5 tcp_connect -0002be48 tcp_send_syn -0002be4e tcp_recv_ack -0002bed1 tcp_recv_fin -0002bed7 tcp_recv_syn -0002c009 tcp_send_fin -0002c0d5 tcp_close_connection -0002c114 tcp_parse -0002c5ad kernel_bind -0002c5e2 kernel_recvfrom -0002c5e8 kernel_recv -0002c65a kernel_recv_timeout -0002c680 kernel_connect -0002c784 kernel_sendto -0002c83e kernel_accept -0002c8a1 kernel_listen -0002c8c9 kernel_send -0002c94f sys_kernel_bind -0002c981 __add_systemcall_sys_kernel_bind -0002c998 __add_systemcall_sys_kernel_accept -0002c9af __add_systemcall_sys_kernel_connect -0002c9c6 __add_systemcall_sys_kernel_listen -0002c9dd __add_systemcall_sys_kernel_recv -0002c9f4 __add_systemcall_sys_kernel_recvfrom -0002ca0b __add_systemcall_sys_kernel_recv_timeout -0002ca22 __add_systemcall_sys_kernel_send -0002ca39 __add_systemcall_sys_kernel_sendto -0002ca50 __add_systemcall_sys_socket_create -0002ca67 __add_systemcall_sys_kernel_sock_close -0002ca7e sys_kernel_accept -0002cabe sys_kernel_connect -0002caf0 sys_kernel_listen -0002cb1f sys_kernel_recv -0002cb57 sys_kernel_recvfrom -0002cb97 sys_kernel_recv_timeout -0002cbd5 sys_kernel_send -0002cc0d sys_kernel_sendto -0002cc4d sys_socket_create -0002cc74 sys_kernel_sock_close -0002ccb5 __iface_send -0002cce4 __iface_recieve -0002cd13 __iface_assign -0002cd26 __iface_detach -0002cd3a __iface_set_gateway -0002cd4d __iface_set_netmask -0002cd60 __iface_configure -0002cdb0 __iface_attach -0002cdd5 net_interface_create -0002ce0d net_register_netdev -0002cf25 net_interface_destroy -0002cf3a __default_restart -0002cf40 __default_stop -0002cfa5 __default_start -0002d01f nm_new -0002d0a8 nm_free -0002d0ed net_firewall_create -0002d110 fs_file2fd -0002d177 fs_alloc_file -0002d1c2 fs_free_file -0002d21c fs_register -0002d2eb fs_init -0002d2f1 fs_unregister -0002d354 fs_get -0002d35a fs_close -0002d3cc fs_open -0002d446 fs_seek -0002d4c3 fs_read -0002d5d8 fs_load_from_file -0002d664 fs_write -0002d71f fs_save_to_file -0002d7ab fat16_rmdir -0002d7b1 fat16_stat -0002d7b7 fat16_close -0002d821 fat16_rename -0002d8b6 fat16_mkdir -0002d99b fat16_remove -0002da0e fat16_open -0002db58 fat16_read -0002dcbc fat16_write -0002ddeb fat16_list -0002e0b9 fat16_init -0002e16d path_next_iter -0002e1dc inode_from_path_recursise -0002e25a inode_from_path -0002e318 ext_get_root -0002e321 ext_get_current_dir -0002e330 ext_get_size -0002e336 ext_get_inodes -0002e33c ext_get_blocks -0002e342 ext_sync -0002e3b5 ext_create -0002e4a0 ext_read -0002e51b ext_seek -0002e562 ext_write -0002e5ce ext_close -0002e630 ext_open_from_directory -0002e736 ext_open -0002e7ed ext_size -0002e816 change_directory -0002e87c ext_create_directory -0002ea16 ext_create_file_system -0002ece3 init_ext -0002ee7f listdir -0002efa0 __inode_sync -0002f003 __inode_cache_insert -0002f0f9 __inode_load -0002f16d inodes_sync -0002f1a8 inode_get -0002f205 inode_read -0002f3ed inode_write -0002f64b alloc_inode -0002f704 mkdir -0002f7b1 sync -0002f7e5 mkfs -0002f7f2 fat16_read_data_from_cluster -0002f840 fat16_read_data -0002f921 fat16_find_cluster_by_offset -0002f99c fat16_write_data_to_cluster_with_offset -0002f9d7 fat16_print_cluster_chain -0002fa05 fat16_write_data_to_cluster -0002fa38 fat16_write_data -0002fb54 get_fat_start_block -0002fb5c get_root_directory_start_block -0002fb6b get_data_start_block -0002fb7d fat16_get_fat_entry -0002fb98 fat16_set_fat_entry -0002fbd8 fat16_sync_fat_table -0002fc50 fat16_allocate_cluster -0002fc68 fat16_free_cluster -0002fc7d fat16_get_free_cluster -0002fcd2 fat16_sync_directory_entry -0002fd54 fat16_read_entry -0002fe01 fat16_find_entry -0002ff3c fat16_rename_entry -0002ffad fat16_free_clusters -0002fff4 fat16_delete_entry -0003005b fat16_add_entry -000301c2 fat16_used_blocks -000301fb fat16_to_upper -00030227 fat16_name_compare -0003034c sstrtok -0003040d fat16_directory_entry_debug -000304dd fat16_get_directory_entry -000306d5 fat16_create_directory -000307da fat16_read_file -0003082b fat16_create_file -000308a9 fat16_create_empty_file -00030969 fat16_directory_entries -00030a4f fat16_mbr_clear -00030af8 fat16_mbr_add_entry -00030be9 fat16_print_root_directory_entries -00030c01 fat16_change_directory -00030c89 fat16_bootblock_info -00030e06 fat16_set_time -00030e3a fat16_set_date -00030e72 fat16_load -00030ff1 fat16_format -000312a6 mbr_partition_type_string -00031329 mbr_partitions_parse -000313f2 mbr_get -000313f8 mbr_partition_load -00031416 __list_users -000314a7 __change_user -00031549 __remove_user -000315f5 __add_user -000316df __find_user -000317b4 __authenticate_user -000318c2 __save_users -00031946 __load_users -00031b48 __ksymbol_admin -00031b62 admin -00031e76 usermanager_create -00031e95 __ksymbol_snakegame -00031eaf init_game -00031efd draw -00031f59 get_input -00031f78 update -000320ff game_loop -00032125 snakegame -00032170 __msgbox -00032570 msgbox_create -000325a3 msgbox_show -000325eb kevents_list -0003275d kevents_init -0003279f kevents_destroy -000327f4 kevents_add -000328ab kevents_create -0003292e _code_end +0001b799 __add_systemcall_sys_system +0001b7b0 exec_cmd +0001b8b4 sys_system +0001b8c4 __ksymbol_exec_cmd +0001b8de system_reboot +0001b912 align_to_pointer_size +0001b920 calculate_size_unit +0001b982 advanced_hash +0001b9b6 kernel_panic +0001b9d4 kref_init +0001b9ee kref_get +0001ba16 kref_put +0001ba3e csprintf +0001bc3f script_parse +0001bd14 login +0001c0b2 __login_create_virt_disk +0001c0dc __register_kthread_login +0001c0f6 help +0001c397 clear +0001c3b8 __ksymbol_new +0001c3d2 __ksymbol_list +0001c3ec __ksymbol_color +0001c406 __ksymbol_about +0001c420 __ksymbol_help +0001c43a __ksymbol_kevents +0001c454 __ksymbol_view +0001c46e __ksymbol_file +0001c488 __ksymbol_tcp +0001c4a2 __ksymbol_conf +0001c4bc __ksymbol_clear +0001c4d6 __ksymbol_services +0001c4f0 __ksymbol_reboot +0001c50a kevents +0001c5e4 services +0001c812 new +0001c953 list +0001ca53 file +0001cc21 color +0001ccc2 about +0001ccff view +0001cf14 tcp +0001d1f1 __tcp_reader +0001d312 conf +0001d5da reboot +0001d613 attach_disk_dev +0001d637 disk_attached +0001d63f disk_name +0001d648 disk_device_get +0001d64e disk_size +0001d66a write_block +0001d6a7 write_block_offset +0001d6ea read_block +0001d727 read_block_offset +0001d791 sched_consume +0001d7d2 sched_add +0001d82c sched_prioritize +0001d8e1 sched_round_robin +0001dac7 sched_exit +0001db80 sched_block +0001dc9e sched_default +0001dd78 sched_sleep +0001de1e sched_init_default +0001de9f get_scheduler +0001dea5 kernel_sleep +0001dec0 kernel_yield +0001df03 kernel_exit +0001df35 block +0001df5e unblock +0001df5f work_queue_add +0001e047 init_worker +0001e05f worker_thread +0001e0fe __ring_buffer_add +0001e1a6 __ring_buffer_read +0001e2b0 rbuffer_new +0001e319 rbuffer_free +0001e33b error_get_string +0001e377 kclock +0001e857 __register_kthread_kclock +0001e871 tar_extract +0001eac1 __ksymbol_tar +0001eadb tar_list +0001ebe5 tar +0001ee6e rgb_to_vga +0001ee7e rgb_to_components +0001eea5 color_distance_squared +0001ef10 rgb_init_color_table +0001efa1 iface_loopback_write +0001f062 iface_loopback_interrupt +0001f079 iface_loopback_read +0001f11c net_init_loopback +0001f133 serial_put +0001f173 serial_write +0001f1b5 serial_printf +0001f355 init_serial +0001f41b inportb +0001f424 inportw +0001f42e inportl +0001f437 outportb +0001f445 outportw +0001f454 outportl +0001f461 sys_create_thread +0001f480 __add_systemcall_sys_create_thread +0001f48b add_system_call +0001f4cb system_call +0001f536 hashmap_put +0001f59d hashmap_get +0001f621 hashmap_add +0001f6ab hashmap_free +0001f6ac reset_vga_palette +0001f6f2 vga_set_palette +0001f7dd b8to16 +0001f7ed vesa_put_pixel +0001f817 vesa_put_box +0001f892 vesa_put_block +0001f90d vesa_put_char +0001f988 vesa_put_char16 +0001fa1b vesa_put_icon16 +0001fa94 vesa_write +0001fad3 vesa_write_str +0001fb01 vesa_fill +0001fb83 vesa_fillrect +0001fbf5 vesa_inner_box +0001fcfd vesa_printf +0001ff6a ksyms_init +00020191 ksyms_add_symbol +0002024a __ksymbol_backtrace +00020264 ksyms_list +000202c6 ksyms_resolve_symbol +00020379 __backtrace_from +00020496 backtrace +000204a7 ws_fullscreen +00020621 ws_remove +000206d1 ws_add +000207bc ws_destroy +00020862 ws_draw +00020b0f ws_raw_wallpaper +00020bf5 ws_set_background_file +00020ed2 ws_init +00020fb5 ws_set_background +00021060 ws_new +000210ed encode_run_length +0002116a decode_run_length +000211d5 __mouse_handler +000212ec mouse_wait +00021334 mouse_write +00021376 mouse_get_event +000213b7 mouse_init +0002149c sys_ipc_open +000214ea __add_systemcall_sys_ipc_open +00021501 __add_systemcall_sys_ipc_close +00021518 __add_systemcall_sys_ipc_send +0002152f __add_systemcall_sys_ipc_receive +00021546 sys_ipc_close +0002158f sys_ipc_send +000215f6 sys_ipc_receive +0002165c sysinf +000223ae __register_kthread_sysinf +000223c8 echo +00022403 res +00022444 ifconfig +00022451 __ksymbol_ifconfig +0002246b __ksymbol_ps +00022485 __ksymbol_tree +0002249f __ksymbol_fat16 +000224b9 __ksymbol_xxd +000224d3 __ksymbol_sh +000224ed __ksymbol_ed +00022507 __ksymbol_exec +00022521 __ksymbol_ths +0002253b __ksymbol_dns +00022555 __ksymbol_th +0002256f __ksymbol_kill +00022589 __ksymbol_echo +000225a3 __ksymbol_fdisk +000225bd __ksymbol_meminfo +000225d7 __ksymbol_res +000225f1 __ksymbol_bg +0002260b __ksymbol_exit +00022625 __ksymbol_socks +0002263f __ksymbol_reset +00022659 exit +0002268d ps +00022901 print_pcb_tree +00022a00 tree +00022a40 fat16 +00022a68 xxd +00022b5d sh +00022c5d ed +00022caa exec +00022e0e ths +00022e7a dns +00022eee th +00022f0c kill +00022f2a fdisk +000230bc meminfo +0002329b bg +0002331a socks +000235c0 __register_kthread_shell +000235da __register_kthread_textshell +000235f4 shell_clear +00023637 reset_shell +000236a8 reset +000236fc shell_put +000238dd shell +00023b3e cleanup_function +00023b65 testfn +00023b99 draw_box +00023c7e __textshell_reset_box +00023d0e textshell +000240df __net_find_interface +0002413f net_drop_packet +00024160 net_handle_recieve +00024287 net_get_interfaces +0002428d net_configure_iface +000242df net_incoming_packet +00024390 net_get_iface +00024406 net_iface_up +0002442d net_iface_down +00024454 net_list_ifaces +0002456e net_register_interface +0002459f net_send_skb +00024627 net_get_info +0002464e networking_main +0002482e __dhcp_add_option +0002489e __dhcp_send_discovery +000249e0 __dhcp_send_request +00024b5d dhcp_get_state +00024b65 dhcp_get_dns +00024b6b dhcp_get_ip +00024b80 dhcp_get_gw +00024b95 dhcpd +00024e14 udp_server +00024e9f tcp_server +00025013 __net_terminal_writef +00025078 __register_kthread_tcp_server +00025092 __register_kthread_udp_server +000250ac __register_kthread_udptest +000250c6 udptest +00025151 tcpd +00025235 logd +000252a0 __register_kthread_logd +000252ba logd_attach_by_pid +000252fe taskbar_reboot +0002532a __reboot +0002533f taskbar_readme +00025358 taskbar_about +00025371 taskbar_clock +0002538a taskbar_sysinf +000253a3 taskbar_bg_retro +000253da taskbar_bg_lotr2 +000253ef taskbar_bg_lotr +00025404 taskbar_bg_default_color_gray +00025416 taskbar_bg_default_color +00025428 taskbar_wolfstein +00025463 taskbar_bg_graph +0002549e taskbar_bg_calc +000254d9 taskbar_colors +00025514 taskbar_cube +0002554f taskbar_editor +0002558a taskbar_finder +000255c5 taskbar_terminal +0002560e __register_kthread_taskbar +00025628 taskbar_hdr_opt_event +000256b2 taskbar +00025c69 about +00025e34 __register_kthread_about +00025e4e __register_kthread_readme +00025e68 readme +00025fca gfx_default_hover +000260e9 gfx_destory_window +00026176 gfx_window_resize +0002621f gfx_window_maximize +00026298 gfx_default_mouse_up +00026366 gfx_default_mouse_down +00026428 gfx_default_click +00026617 gfx_draw_window +00027403 gfx_window_set_resizable +00027418 kernel_gfx_window_border_color +00027443 gfx_new_window +000276a3 gfx_point_in_rectangle +000276d0 gfx_draw_component +00027712 gfx_input_event +00027844 gfx_input_draw +0002794c gfx_input_manager_add +000279ad gfx_composition_remove_window +000279d7 gfx_composition_add_window +00027a1e gfx_set_background_color +00027a6f gfx_raw_background +00027abc gfx_decode_background_image +00027b09 gfx_set_taskbar +00027ba9 gfx_compositor_main +00027c1d kernel_gfx_draw_circle_helper +00027ec9 gfx_get_window_width +00027ede gfx_get_window_height +00027ef3 gfx_push_event +00027faf gfx_put_icon16 +000280a7 gfx_put_icon32 +0002819f gfx_event_loop +000282be kernel_gfx_draw_rectangle +000283b8 kernel_gfx_draw_contoured_box +00028458 kernel_gfx_draw_pixel +000284f6 kernel_gfx_draw_bitmap +00028614 kernel_gfx_draw_char +00028714 kernel_gfx_set_position +00028730 gfx_commit +00028749 kernel_gfx_draw_text +000287fc gfx_button_ext +0002892f gfx_button +0002894d kernel_gfx_set_title +000289b9 kernel_gfx_set_header +00028a25 kernel_gfx_draw_line +00028bc0 kernel_gfx_draw_circle +00028c3f kernel_gfx_draw_section +00028c45 kernel_gfx_draw_format_text +00028f97 gfx_syscall_hook +0002914e gfx_total_themes +00029154 kernel_gfx_current_theme +0002915a kernel_gfx_update_theme +00029228 kernel_gfx_default_theme +0002922e kernel_gfx_set_theme +00029253 kernel_gfx_get_theme +0002926e gfx_new_ctx +000292ca gfx_init_framebuffer +00029436 netdev_attach_driver +000294df is_netdev_attached +000294ed netdev_transmit +00029508 netdev_recieve +00029531 net_ethernet_add_header +000295c5 net_ethernet_parse +00029639 __skb_queue_remove +00029677 __skb_queue_add +000296c7 skb_free_queue +000296ff skb_new_queue +00029766 skb_free +000297a1 skb_new +0002980c skb_consume +0002983d __net_arp_send +000298fd net_init_arp +00029949 net_arp_add_entry +000299d8 net_arp_find_entry +00029a23 net_arp_respond +00029a98 net_net_arp_request +00029b1e arp_parse +00029bc8 net_ipv4_print +00029bce net_ipv4_add_header +00029d05 net_is_ipv4 +00029d42 net_ipv4_parse +00029e6f ntohl +00029e9b htonl +00029eae ntohs +00029ebb htons +00029ec8 checksum +00029f1f transport_checksum +00029f74 ip_to_int +0002a012 net_icmp_handle +0002a0d7 net_icmp_response +0002a0dd net_icmp_request +0002a1a0 ping +0002a1f9 net_icmp_parse +0002a269 net_udp_send +0002a39e net_udp_parse +0002a4c6 socket_type_to_str +0002a4d5 socket_domain_to_str +0002a4e4 socket_protocol_to_str +0002a4f3 net_sock_bind +0002a53e net_get_sockets +0002a55a sock_get +0002a57b get_total_sockets +0002a581 net_sock_is_established +0002a5c5 net_sock_awaiting_ack +0002a609 net_sock_data_ready +0002a662 net_sock_read +0002a764 net_sock_add_data +0002a9c4 sock_find_listen_tcp +0002aa08 net_sock_find_tcp +0002abfa net_prepare_tcp_sock +0002ac86 net_sock_accept +0002ac99 net_socket_find_udp +0002ad04 kernel_sock_shutdown +0002ad31 kernel_sock_cleanup +0002adb7 kernel_sock_close +0002adeb kernel_socket_create +0002af6e net_init_sockets +0002afb4 gethostname +0002b4ce __add_systemcall_gethostname +0002b4e5 net_init_dns +0002b514 route +0002b561 tcb_init +0002b57f tcb_new +0002b6eb tcp_state_to_str +0002b704 tcp_new_connection +0002b78c tcp_free_connection +0002b7af tcp_is_listening +0002b7c5 tcp_set_listening +0002b825 tcp_calculate_checksum +0002b8e9 __tcp_send +0002ba05 tcp_send_segment +0002bb48 tcp_accept_connection +0002bc8a tcp_send_ack +0002bdc0 tcp_read +0002bdc6 tcp_recv_segment +0002bdcc tcp_connect +0002be6f tcp_send_syn +0002be75 tcp_recv_ack +0002bef8 tcp_recv_fin +0002befe tcp_recv_syn +0002c030 tcp_send_fin +0002c0fc tcp_close_connection +0002c13b tcp_parse +0002c5d4 kernel_bind +0002c609 kernel_recvfrom +0002c60f kernel_recv +0002c681 kernel_recv_timeout +0002c6a7 kernel_connect +0002c7ab kernel_sendto +0002c865 kernel_accept +0002c8c8 kernel_listen +0002c8f0 kernel_send +0002c976 sys_kernel_bind +0002c9a8 __add_systemcall_sys_kernel_bind +0002c9bf __add_systemcall_sys_kernel_accept +0002c9d6 __add_systemcall_sys_kernel_connect +0002c9ed __add_systemcall_sys_kernel_listen +0002ca04 __add_systemcall_sys_kernel_recv +0002ca1b __add_systemcall_sys_kernel_recvfrom +0002ca32 __add_systemcall_sys_kernel_recv_timeout +0002ca49 __add_systemcall_sys_kernel_send +0002ca60 __add_systemcall_sys_kernel_sendto +0002ca77 __add_systemcall_sys_socket_create +0002ca8e __add_systemcall_sys_kernel_sock_close +0002caa5 sys_kernel_accept +0002cae5 sys_kernel_connect +0002cb17 sys_kernel_listen +0002cb46 sys_kernel_recv +0002cb7e sys_kernel_recvfrom +0002cbbe sys_kernel_recv_timeout +0002cbfc sys_kernel_send +0002cc34 sys_kernel_sendto +0002cc74 sys_socket_create +0002cc9b sys_kernel_sock_close +0002ccdc __iface_send +0002cd0b __iface_recieve +0002cd3a __iface_assign +0002cd4d __iface_detach +0002cd61 __iface_set_gateway +0002cd74 __iface_set_netmask +0002cd87 __iface_configure +0002cdd7 __iface_attach +0002cdfc net_interface_create +0002ce34 net_register_netdev +0002cf4c net_interface_destroy +0002cf61 __default_restart +0002cf67 __default_stop +0002cfcc __default_start +0002d046 nm_new +0002d0cf nm_free +0002d114 net_firewall_create +0002d137 fs_file2fd +0002d19e fs_alloc_file +0002d1e9 fs_free_file +0002d243 fs_register +0002d312 fs_init +0002d318 fs_unregister +0002d37b fs_get +0002d381 fs_close +0002d3f3 fs_open +0002d46d fs_seek +0002d4ea fs_read +0002d5ff fs_load_from_file +0002d68b fs_write +0002d746 fs_save_to_file +0002d7d2 fat16_rmdir +0002d7d8 fat16_stat +0002d7de fat16_close +0002d848 fat16_rename +0002d8dd fat16_mkdir +0002d9c2 fat16_remove +0002da35 fat16_open +0002db7f fat16_read +0002dce3 fat16_write +0002de12 fat16_list +0002e0e0 fat16_init +0002e194 path_next_iter +0002e203 inode_from_path_recursise +0002e281 inode_from_path +0002e33f ext_get_root +0002e348 ext_get_current_dir +0002e357 ext_get_size +0002e35d ext_get_inodes +0002e363 ext_get_blocks +0002e369 ext_sync +0002e3dc ext_create +0002e4c7 ext_read +0002e542 ext_seek +0002e589 ext_write +0002e5f5 ext_close +0002e657 ext_open_from_directory +0002e75d ext_open +0002e814 ext_size +0002e83d change_directory +0002e8a3 ext_create_directory +0002ea3d ext_create_file_system +0002ed0a init_ext +0002eea6 listdir +0002efc7 __inode_sync +0002f02a __inode_cache_insert +0002f120 __inode_load +0002f194 inodes_sync +0002f1cf inode_get +0002f22c inode_read +0002f414 inode_write +0002f672 alloc_inode +0002f72b mkdir +0002f7d8 sync +0002f80c mkfs +0002f819 fat16_read_data_from_cluster +0002f867 fat16_read_data +0002f948 fat16_find_cluster_by_offset +0002f9c3 fat16_write_data_to_cluster_with_offset +0002f9fe fat16_print_cluster_chain +0002fa2c fat16_write_data_to_cluster +0002fa5f fat16_write_data +0002fb7b get_fat_start_block +0002fb83 get_root_directory_start_block +0002fb92 get_data_start_block +0002fba4 fat16_get_fat_entry +0002fbbf fat16_set_fat_entry +0002fbff fat16_sync_fat_table +0002fc77 fat16_allocate_cluster +0002fc8f fat16_free_cluster +0002fca4 fat16_get_free_cluster +0002fcf9 fat16_sync_directory_entry +0002fd7b fat16_read_entry +0002fe28 fat16_find_entry +0002ff63 fat16_rename_entry +0002ffd4 fat16_free_clusters +0003001b fat16_delete_entry +00030082 fat16_add_entry +000301e9 fat16_used_blocks +00030222 fat16_to_upper +0003024e fat16_name_compare +00030373 sstrtok +00030434 fat16_directory_entry_debug +00030504 fat16_get_directory_entry +000306fc fat16_create_directory +00030801 fat16_read_file +00030852 fat16_create_file +000308d0 fat16_create_empty_file +00030990 fat16_directory_entries +00030a76 fat16_mbr_clear +00030b1f fat16_mbr_add_entry +00030c10 fat16_print_root_directory_entries +00030c28 fat16_change_directory +00030cb0 fat16_bootblock_info +00030e2d fat16_set_time +00030e61 fat16_set_date +00030e99 fat16_load +00031018 fat16_format +000312cd mbr_partition_type_string +00031350 mbr_partitions_parse +00031419 mbr_get +0003141f mbr_partition_load +0003143d __list_users +000314ce __change_user +00031570 __remove_user +0003161c __add_user +00031706 __find_user +000317db __authenticate_user +000318e9 __save_users +0003196d __load_users +00031b6f __ksymbol_admin +00031b89 admin +00031e9d usermanager_create +00031ebc __ksymbol_snakegame +00031ed6 init_game +00031f24 draw +00031f80 get_input +00031f9f update +00032126 game_loop +0003214c snakegame +00032197 __msgbox +00032597 msgbox_create +000325ca msgbox_show +00032612 kevents_list +00032784 kevents_init +000327c6 kevents_destroy +0003281b kevents_add +000328d2 kevents_create +00032955 _code_end From 07990cf976dda2f4a0de3098b0dbcdfe9e766e89 Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Mon, 29 Jan 2024 15:11:15 +0100 Subject: [PATCH 05/23] Improved widget manager --- apps/users/users.cpp | 58 ++++++++++++++++++++---------------------- apps/utils/Widgets.hpp | 37 ++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 33 deletions(-) diff --git a/apps/users/users.cpp b/apps/users/users.cpp index e736b72..9a086f2 100644 --- a/apps/users/users.cpp +++ b/apps/users/users.cpp @@ -14,45 +14,46 @@ class UserEditor : public Window { this->height = height; /* Create widgets */ - widgets = new WidgetManager(); - LayoutHandle main = widgets->addLayout(new Layout( + widgets = new WidgetManager(); + Layout* main = new Layout( 10, 10, 180, 160, VERTICAL, LAYOUT_FLAG_NONE - )); + ); - LayoutHandle bottom = widgets->addLayout(new Layout( + Layout* bottom = new Layout( 10, 170, 180, 24, HORIZONTAL, LAYOUT_FLAG_BORDER - )); - - username = new Input(100, 14, "Username"); - password = new Input(100, 14, "Password"); - - widgets->addWidget(main, CENTER, new Label("Create a new user")); - widgets->addWidget(main, LEFT, new Spacing(0, 8)); - widgets->addWidget(main, LEFT, new Label("Username:")); - widgets->addWidget(main, LEFT, username); - widgets->addWidget(main, LEFT, new Label("Password:")); - widgets->addWidget(main, LEFT, password); - widgets->addWidget(main, LEFT, new Spacing(0, 8)); - widgets->addWidget(main, CENTER, new Label("Permissions:")); - widgets->addWidget(main, LEFT, new Checkbox(false, "Admin")); - widgets->addWidget(main, LEFT, new Checkbox(true, "User")); - widgets->addWidget(main, LEFT, new Checkbox(false, "Guest")); - - widgets->addWidget(bottom, RIGHT, new Button(50, 14, "Cancel", Function([this]() { + ); + + main->addWidget(new Label("Create a new user"), CENTER); + main->addWidget(new Spacing(0, 8), LEFT); + main->addWidget(new Label("Username:"), LEFT); + main->addWidget(new Input(100, 14, "Username", "#username"), LEFT); + main->addWidget(new Label("Password:"), LEFT); + main->addWidget(new Input(100, 14, "Password", "#password"), LEFT); + main->addWidget(new Spacing(0, 8), LEFT); + main->addWidget(new Label("Permissions:"), CENTER); + main->addWidget(new Checkbox(false, "Admin"), LEFT); + main->addWidget(new Checkbox(true, "User"), LEFT); + main->addWidget(new Checkbox(false, "Guest"), LEFT); + + bottom->addWidget(new Button(50, 14, "Cancel", Function([this]() { delete widgets; exit(); - }))); + })), RIGHT); - widgets->addWidget(bottom, RIGHT, new Button(50, 14, "Create", Function([this]() { - printf("Username: %s\n", username->getData()); - printf("Password: %s\n", password->getData()); - }))); + bottom->addWidget(new Button(50, 14, "Create", Function([this]() { + printf("Username: %s\n", ((Input*)widgets->getByTag("#username"))->getData()); + printf("Password: %s\n", ((Input*)widgets->getByTag("#password"))->getData()); + })), RIGHT); + + + widgets->addLayout(main); + widgets->addLayout(bottom); } int eventHandler(struct gfx_event* event) { @@ -88,9 +89,6 @@ class UserEditor : public Window { int width; int height; WidgetManager* widgets; - - Input* username; - Input* password; }; void editorEntry(void* arg) { diff --git a/apps/utils/Widgets.hpp b/apps/utils/Widgets.hpp index d12fe31..6334828 100644 --- a/apps/utils/Widgets.hpp +++ b/apps/utils/Widgets.hpp @@ -39,6 +39,15 @@ class Widget { void enable() { disabled = false; } + + Widget* setTag(char* tag) { + strcpy(this->tag, tag); + return this; + } + + char* getTag() { + return tag; + } /* Widget properties */ int x = 0; @@ -49,6 +58,7 @@ class Widget { bool disabled = false; protected: + char tag[16] = {0}; }; /* A simple button widget */ @@ -107,15 +117,16 @@ class Spacing : public Widget { /* A simple input widget */ class Input : public Widget { public: - Input(int width, int height, char* text) { + Input(int width, int height, char* text, char* tag = "") { this->width = width; this->height = height; this->text = text; + strcpy(this->tag, tag); memset(data, 0, 100); } void draw(Window* window) { - window->drawContouredBox(x, y, width, height, focused ? 28 : 30); + window->drawContouredBox(x, y, width, height, focused ? 31 : 30); if(size == 0){ window->drawText(x + 4, y + 4, text, COLOR_VGA_LIGHT_GRAY); @@ -130,7 +141,6 @@ class Input : public Widget { /* Handles keyboard events */ void Keyboard(char c) { - printf("Input: %c\n", c); if (c == '\b') { if (size > 0) { size--; @@ -286,6 +296,15 @@ class Layout { } } + Widget* getByTag(char* tag) { + for (int i = 0; i < widgetCount; i++) { + if (strlen(widgets[i]->getTag()) > 1 && strcmp(widgets[i]->getTag(), tag) == 0) { + return widgets[i]; + } + } + return nullptr; + } + void draw(Window* window) { if (flags & LAYOUT_FLAG_BORDER) window->drawContouredBox(x, y, width, height, 30); @@ -417,6 +436,18 @@ class WidgetManager { } } + Widget* getByTag(char* tag) { + printf("Searching for widget with tag %s\n", tag); + for (int i = 0; i < layoutCount; i++) { + Widget* widget = layouts[i]->getByTag(tag); + if (widget != nullptr) { + return widget; + } + } + + return nullptr; + } + void Keyboard(char c) { if (focusedLayout != -1) { layouts[focusedLayout]->Keyboard(c); From 9608e357412c59cc5d21e608f7c3bce707a05c09 Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Tue, 30 Jan 2024 15:35:34 +0100 Subject: [PATCH 06/23] Start of HTML parser --- apps/users/Users.hpp | 6 + apps/users/UsersEdit.cpp | 105 ++++++++++++++ apps/users/users.cpp | 98 +------------ apps/utils/Widgets.hpp | 23 ++- tools/experiments/html.cpp | 284 +++++++++++++++++++++++++++++++++++++ 5 files changed, 417 insertions(+), 99 deletions(-) create mode 100644 apps/users/Users.hpp create mode 100644 apps/users/UsersEdit.cpp create mode 100644 tools/experiments/html.cpp diff --git a/apps/users/Users.hpp b/apps/users/Users.hpp new file mode 100644 index 0000000..0c3b211 --- /dev/null +++ b/apps/users/Users.hpp @@ -0,0 +1,6 @@ +#ifndef __USERS_H +#define __USERS_H + +void editorEntry(void* arg); + +#endif // !__USERS_H \ No newline at end of file diff --git a/apps/users/UsersEdit.cpp b/apps/users/UsersEdit.cpp new file mode 100644 index 0000000..5757530 --- /dev/null +++ b/apps/users/UsersEdit.cpp @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include + +class UserEditor : public Window { + +public: + UserEditor(int width, int height) : Window(200, 200, "User Editor", 1) { + this->width = width; + this->height = height; + + /* Create widgets */ + widgets = new WidgetManager(); + Layout* main = new Layout( + 10, 10, + 180, 160, + VERTICAL, + LAYOUT_FLAG_NONE + ); + + Layout* bottom = new Layout( + 10, 170, + 180, 24, + HORIZONTAL, + LAYOUT_FLAG_BORDER + ); + + main->addWidget(new Label("Create a new user"), CENTER); + main->addWidget(new Spacing(0, 8), LEFT); + main->addWidget(new Label("Username:"), LEFT); + main->addWidget(new Input(100, 14, "Username", "#username"), LEFT); + main->addWidget(new Label("Password:"), LEFT); + main->addWidget(new Input(100, 14, "Password", "#password"), LEFT); + main->addWidget(new Spacing(0, 8), LEFT); + main->addWidget(new Label("Permissions:"), CENTER); + main->addWidget(new Checkbox(false, "Admin"), LEFT); + main->addWidget(new Checkbox(true, "User"), LEFT); + main->addWidget(new Checkbox(false, "Guest"), LEFT); + + bottom->addWidget(new Button(50, 14, "Cancel", Function([this]() { + delete widgets; + exit(); + })), RIGHT); + + bottom->addWidget(new Button(50, 14, "Create", Function([this]() { + printf("Username: %s\n", ((Input*)widgets->getByTag("#username"))->getData()); + printf("Password: %s\n", ((Input*)widgets->getByTag("#password"))->getData()); + })), RIGHT); + + + widgets->addLayout(main); + widgets->addLayout(bottom); + } + + int eventHandler(struct gfx_event* event) { + switch (event->event) + { + case GFX_EVENT_RESOLUTION: + /* update screensize */ + break; + case GFX_EVENT_EXIT: + delete widgets; + return -1; + case GFX_EVENT_KEYBOARD: + widgets->Keyboard(event->data); + /* keyboard event in e.data */ + break; + case GFX_EVENT_MOUSE: + widgets->Mouse(event->data, event->data2); + break; + } + return 0; + } + + void draw() { + /* Clear screen */ + drawRect(0, 0, width, height, 30); + /* Draw widgets */ + widgets->draw(this); + } + + int test = 1337; + +private: + int width; + int height; + WidgetManager* widgets; +}; + +void editorEntry(void* arg) { + UserEditor t(200, 200); + t.draw(); + + struct gfx_event e; + while (1){ + gfx_get_event(&e, GFX_EVENT_BLOCKING); /* alt: GFX_EVENT_NONBLOCKING */ + if(t.eventHandler(&e) == -1) break; + t.draw(); + } + return; +} \ No newline at end of file diff --git a/apps/users/users.cpp b/apps/users/users.cpp index 9a086f2..c69c7a4 100644 --- a/apps/users/users.cpp +++ b/apps/users/users.cpp @@ -6,103 +6,7 @@ #include #include -class UserEditor : public Window { - -public: - UserEditor(int width, int height) : Window(200, 200, "User Editor", 1) { - this->width = width; - this->height = height; - - /* Create widgets */ - widgets = new WidgetManager(); - Layout* main = new Layout( - 10, 10, - 180, 160, - VERTICAL, - LAYOUT_FLAG_NONE - ); - - Layout* bottom = new Layout( - 10, 170, - 180, 24, - HORIZONTAL, - LAYOUT_FLAG_BORDER - ); - - main->addWidget(new Label("Create a new user"), CENTER); - main->addWidget(new Spacing(0, 8), LEFT); - main->addWidget(new Label("Username:"), LEFT); - main->addWidget(new Input(100, 14, "Username", "#username"), LEFT); - main->addWidget(new Label("Password:"), LEFT); - main->addWidget(new Input(100, 14, "Password", "#password"), LEFT); - main->addWidget(new Spacing(0, 8), LEFT); - main->addWidget(new Label("Permissions:"), CENTER); - main->addWidget(new Checkbox(false, "Admin"), LEFT); - main->addWidget(new Checkbox(true, "User"), LEFT); - main->addWidget(new Checkbox(false, "Guest"), LEFT); - - bottom->addWidget(new Button(50, 14, "Cancel", Function([this]() { - delete widgets; - exit(); - })), RIGHT); - - bottom->addWidget(new Button(50, 14, "Create", Function([this]() { - printf("Username: %s\n", ((Input*)widgets->getByTag("#username"))->getData()); - printf("Password: %s\n", ((Input*)widgets->getByTag("#password"))->getData()); - })), RIGHT); - - - widgets->addLayout(main); - widgets->addLayout(bottom); - } - - int eventHandler(struct gfx_event* event) { - switch (event->event) - { - case GFX_EVENT_RESOLUTION: - /* update screensize */ - break; - case GFX_EVENT_EXIT: - delete widgets; - return -1; - case GFX_EVENT_KEYBOARD: - widgets->Keyboard(event->data); - /* keyboard event in e.data */ - break; - case GFX_EVENT_MOUSE: - widgets->Mouse(event->data, event->data2); - break; - } - return 0; - } - - void draw() { - /* Clear screen */ - drawRect(0, 0, width, height, 30); - /* Draw widgets */ - widgets->draw(this); - } - - int test = 1337; - -private: - int width; - int height; - WidgetManager* widgets; -}; - -void editorEntry(void* arg) { - UserEditor t(200, 200); - - struct gfx_event e; - while (1){ - gfx_get_event(&e, GFX_EVENT_BLOCKING); /* alt: GFX_EVENT_NONBLOCKING */ - if(t.eventHandler(&e) == -1) break; - t.draw(); - } - return; -} - +#include "Users.hpp" class Users : public Window { public: diff --git a/apps/utils/Widgets.hpp b/apps/utils/Widgets.hpp index 6334828..c1f2767 100644 --- a/apps/utils/Widgets.hpp +++ b/apps/utils/Widgets.hpp @@ -61,7 +61,10 @@ class Widget { char tag[16] = {0}; }; -/* A simple button widget */ +/** + * @brief A simple button widget + * + */ class Button : public Widget { public: Button(int width, int height, char* text, Function callback) : callback(callback) { @@ -95,6 +98,7 @@ class Button : public Widget { Function callback; }; +/* A simple spacing widget */ class Spacing : public Widget { public: Spacing(int width, int height) { @@ -279,6 +283,17 @@ enum { class Layout { public: + Layout(int width, int height, LayoutType type, int flags) { + this->x = 0; + this->y = 0; + this->width = width; + this->height = height; + this->type = type; + this->offset = 0; + this->flags = flags; + memset(widgets, 0, MAX_WIDGETS * sizeof(Widget*)); + } + Layout(int x, int y, int width, int height, LayoutType type, int flags) { this->x = x; this->y = y; @@ -353,7 +368,6 @@ class Layout { printf("Added widget, new offset %d\n", offset); - return widgetCount; } @@ -413,6 +427,8 @@ class WidgetManager { layouts[layoutCount] = layout; layoutCount++; + yOffset += layout->height + 2; + return layoutCount-1; } @@ -477,6 +493,9 @@ class WidgetManager { } } } + + int xOffset = 0; + int yOffset = 0; private: Layout* layouts[MAX_LAYOUTS]; diff --git a/tools/experiments/html.cpp b/tools/experiments/html.cpp new file mode 100644 index 0000000..67fbeaf --- /dev/null +++ b/tools/experiments/html.cpp @@ -0,0 +1,284 @@ +#include + +#define MAX_TAG_NAME_LENGTH 10 +#define MAX_ATTR_NAME_LENGTH 15 +#define MAX_ATTR_VALUE_LENGTH 50 +#define MAX_ATTRIBUTES 5 + +/* Enumeration for HTML tags */ +enum HTMLTag { + Unknown, + Html, + Body, + P, + Input, + Checkbox, + Button, + Label, + Layout, + Spacing +}; + +HTMLTag stringToHTMLTag(const char* str) { + if (strncmp(str, "html", 4) == 0) return Html; + if (strncmp(str, "body", 4) == 0) return Body; + if (strncmp(str, "p", 1) == 0) return P; + if (strncmp(str, "input", 5) == 0) return Input; + if (strncmp(str, "checkbox", 8) == 0) return Checkbox; + if (strncmp(str, "button", 6) == 0) return Button; + if (strncmp(str, "label", 5) == 0) return Label; + if (strncmp(str, "layout", 6) == 0) return Layout; + if (strncmp(str, "spacing", 7) == 0) return Spacing; + return Unknown; +} + +/* Structure for HTML attributes */ +struct HTMLAttribute { + char name[MAX_ATTR_NAME_LENGTH]; + char value[MAX_ATTR_VALUE_LENGTH]; +}; + +/* Structure for HTML nodes */ +struct Node { + HTMLTag tag; + + HTMLAttribute attributes[MAX_ATTRIBUTES]; + int attr_count; + + char data[100]; + + bool isTag; + + Node* parent; + Node* firstChild; + Node* nextSibling; + + Node(HTMLTag tag, const char* data, bool isTagNode, Node* parentNode) + : tag(tag), attr_count(0), isTag(isTagNode), parent(parentNode), firstChild(nullptr), nextSibling(nullptr) { + strncpy(this->data, data, 99); + this->data[99] = '\0'; + } + + ~Node() { + delete firstChild; + delete nextSibling; + } + + void addAttribute(const char* name, const char* value) { + if (attr_count < MAX_ATTRIBUTES) { + + strncpy(attributes[attr_count].name, name, MAX_ATTR_NAME_LENGTH - 1); + attributes[attr_count].name[MAX_ATTR_NAME_LENGTH - 1] = '\0'; + + strncpy(attributes[attr_count].value, value, MAX_ATTR_VALUE_LENGTH - 1); + attributes[attr_count].value[MAX_ATTR_VALUE_LENGTH - 1] = '\0'; + + attr_count++; + } + } +}; + +class HTMLParser { +public: + HTMLParser(const char* htmlContent) : html(htmlContent), root(new Node(Unknown, "root", true, nullptr)), current(root) { + + } + + ~HTMLParser() { + delete root; + } + + int parse() { + const char* pos = html; + while (*pos != '\0') { + pos = skipWhitespace(pos); + if (*pos == '<') { + if (*(pos + 1) != '/') { + + /* Start of a new tag */ + const char* tagStart = pos + 1; + pos = findTagEnd(pos); + if (*pos == '\0') return -1; /* Error: Malformed HTML */ + + char tagStr[MAX_TAG_NAME_LENGTH] = {0}; + const char* tagEnd = extractTagName(tagStart, tagStr); + HTMLTag tag = stringToHTMLTag(tagStr); + + Node* child = new Node(tag, "", true, current); + if (parseAttributes(tagEnd, pos, child) != 0) { + delete child; + return -2; /* Error parsing attributes */ + } + + addChild(child); + current = child; + } else { + /* End of a current tag */ + pos = findTagEnd(pos); + if (*pos == '\0') return -1; + current = current->parent ? current->parent : current; + } + } else { + /* Text content */ + const char* contentStart = pos; + while (*pos != '<' && *pos != '\0') { + pos++; + } + + if (pos > contentStart) { + char content[100] = {0}; + strncpy(content, contentStart, pos - contentStart < 99 ? pos - contentStart : 99); + Node* child = new Node(Unknown, content, false, current); + addChild(child); + } + } + } + return 0; /* Success */ + } + + void printTree() const { + printTreeRecursive(root, 0); + } + + static const char* getHtmlError(int code) { + switch (code) { + case -1: + return "Malformed HTML"; + case -2: + return "Error parsing attributes"; + default: + return "Unknown error"; + } + } + +private: + const char* html; + Node* root; + Node* current; + + bool isspace(char c) const { + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; + } + + const char* findTagEnd(const char* start) const { + while (*start != '>' && *start != '\0') { + start++; + } + return *start == '>' ? start + 1 : start; + } + + const char* skipWhitespace(const char* start) const { + while (*start != '\0' && isspace(*start)) { + start++; + } + return start; + } + + void addChild(Node* child) { + if (!current->firstChild) { + current->firstChild = child; + } else { + Node* temp = current->firstChild; + while (temp->nextSibling) { + temp = temp->nextSibling; + } + temp->nextSibling = child; + } + } + + void printTreeRecursive(const Node* node, int depth) const { + for (int i = 0; i < depth; ++i) { + std::cout << " "; + } + if (node->isTag) { + std::cout << "Tag: " << static_cast(node->tag); + /* Print attributes if any */ + for (int i = 0; i < node->attr_count; ++i) { + std::cout << " [" << node->attributes[i].name << "=\"" << node->attributes[i].value << "\"]"; + } + std::cout << std::endl; + } else { + std::cout << "Content: " << node->data << std::endl; + } + if (node->firstChild) { + printTreeRecursive(node->firstChild, depth + 1); + } + if (node->nextSibling) { + printTreeRecursive(node->nextSibling, depth); + } + } + + + /* Utility function to extract the tag name from a given position */ + const char* extractTagName(const char* start, char* buffer) { + const char* ptr = start; + while (*ptr != ' ' && *ptr != '>' && *ptr != '\0') { + *buffer++ = *ptr++; + } + *buffer = '\0'; /* Null-terminate the string */ + return ptr; /* Return the position after the tag name */ + } + + /* Utility function to parse attributes within a tag */ + int parseAttributes(const char* start, const char* end, Node* node) { + const char* ptr = start; + while (ptr < end && *ptr != '>') { + /* Skip any leading whitespace */ + while (isspace(*ptr)) ptr++; + + /* Extract attribute name */ + const char* attrNameStart = ptr; + while (*ptr != '=' && !isspace(*ptr) && *ptr != '\0' && ptr < end) { + ptr++; + } + char attrName[MAX_ATTR_NAME_LENGTH] = {0}; + strncpy(attrName, attrNameStart, ptr - attrNameStart); + + /* Check for '=' after attribute name */ + if (*ptr != '=' || *ptr == '\0') return -1; + ptr++; /* Skip '=' */ + + /* Check for opening quote of attribute value */ + if (*ptr != '\"') return -1; + ptr++; /* Skip opening quote */ + + /* Extract attribute value */ + const char* attrValueStart = ptr; + while (*ptr != '\"' && *ptr != '\0' && ptr < end) { + ptr++; + } + if (*ptr != '\"') return -1; /* Missing closing quote */ + char attrValue[MAX_ATTR_VALUE_LENGTH] = {0}; + strncpy(attrValue, attrValueStart, ptr - attrValueStart); + ptr++; /* Skip closing quote */ + + /* Add attribute to node */ + node->addAttribute(attrName, attrValue); + } + return 0; + } +}; + +int main() { + int ret; + const char* htmlContent = + "" + "" + "
" + "

Welcome to the Test Page

" + "

This is a paragraph with a link.

" + " " + " " + "
" + "" + "\0"; + + HTMLParser parser(htmlContent); + ret = parser.parse(); + if (ret != 0) { + std::cout << "Error: " << HTMLParser::getHtmlError(ret) << std::endl; + } + parser.printTree(); + + return 0; +} From ef45d3267627c31943269fd562758b47ce353cf9 Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Thu, 1 Feb 2024 15:50:20 +0100 Subject: [PATCH 07/23] Progress on textmode editor --- Makefile | 2 +- kernel/edit.c | 236 ++++++++++++- kernel/kthreads/shell.c | 2 +- rootfs/symbols.map | 763 ++++++++++++++++++++-------------------- 4 files changed, 619 insertions(+), 384 deletions(-) diff --git a/Makefile b/Makefile index b5e06d5..5441216 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ KERNELOBJ = bin/kernel.o bin/terminal.o bin/helpers.o bin/pci.o bin/virtualdisk. bin/diskdev.o bin/scheduler.o bin/work.o bin/rbuffer.o bin/errors.o bin/kclock.o bin/tar.o bin/color.o bin/loopback.o \ bin/serial.o bin/io.o bin/syscalls.o bin/list.o bin/hashmap.o bin/vbe.o bin/ksyms.o bin/windowserver.o bin/encoding.o\ bin/mouse.o bin/ipc.o bin/sysinf.o ${PROGRAMOBJ} ${GFXOBJ} bin/font8.o bin/net.o bin/fs.o bin/ext.o bin/fat16.o bin/partition.o\ - bin/admin.o bin/usermanager.o bin/user.o bin/group.o bin/snake.o bin/msgbox.o bin/kevents.o + bin/admin.o bin/usermanager.o bin/user.o bin/group.o bin/snake.o bin/msgbox.o bin/kevents.o bin/edit.o BOOTOBJ = bin/bootloader.o diff --git a/kernel/edit.c b/kernel/edit.c index 3dd21f1..373beeb 100644 --- a/kernel/edit.c +++ b/kernel/edit.c @@ -1,6 +1,11 @@ #include #include #include +#include +#include +#include +#include +#include #define MAX_LINES 512 @@ -13,13 +18,22 @@ struct line { struct textbuffer { struct line **lines; size_t line_count; + struct cursor { + size_t x; + size_t y; + } cursor; }; static struct textbuffer *textbuffer_create(void) { struct textbuffer *buffer = create(struct textbuffer); - buffer->lines = malloc(sizeof(struct line*) * MAX_LINES); - buffer->line_count = 0; + buffer->lines = kalloc(sizeof(struct line*) * MAX_LINES); + buffer->lines[0]->text = kalloc(32); + buffer->line_count = 1; + buffer->lines[0]->length = 0; + buffer->lines[0]->capacity = 32; + buffer->cursor.x = 0; + buffer->cursor.y = 0; return buffer; } @@ -34,3 +48,221 @@ static void textbuffer_destroy(struct textbuffer *buffer) free(buffer->lines); free(buffer); } + +static int textbuffer_new_line(struct textbuffer *buffer) +{ + if (buffer->line_count == MAX_LINES) { + return -1; + } + + buffer->lines[buffer->line_count] = kalloc(sizeof(struct line)); + buffer->lines[buffer->line_count]->text = kalloc(32); + buffer->lines[buffer->line_count]->length = 0; + buffer->lines[buffer->line_count]->capacity = 32; + buffer->line_count++; + + return 0; +} + +/* Function to display the content of the text buffer on the screen */ +static void textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg) { + uint8_t color = (bg << 4) | fg; + uint32_t x_start = 0; + uint32_t y_start = 0; + + /* Clear the screen before displaying new content */ + scr_clear(); + + for (size_t i = 0; i < buffer->line_count; i++) { + /* Calculate the position for each line */ + int32_t x = x_start; + int32_t y = y_start + i; + + /* Write the line to the screen */ + if (buffer->lines[i]->text) { + scrprintf(x, y, "%s", buffer->lines[i]->text); + } + } + + /* Set the cursor to the end of the text */ + if (buffer->line_count > 0) { + screen_set_cursor(x_start, y_start + buffer->line_count - 1); + } + + screen_set_cursor(buffer->cursor.x == 0 ? buffer->cursor.x : buffer->cursor.x -1, buffer->cursor.y); + /* write stats at the bottom */ + scrprintf(0, 24, "line_count: %d, x: %d, y: %d", buffer->line_count, buffer->cursor.x, buffer->cursor.y); +} + +/* Function to handle keyboard input of a char */ +static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { + /* Handle the backspace key */ + if (c == '\b') { + /* If the cursor is at the beginning of the line, go to the previous line */ + if (buffer->cursor.x == 0) { + /* If the cursor is at the beginning of the first line, do nothing */ + if (buffer->cursor.y == 0 ) { + return; + } + + /* TODO: move rest of line up */ + if(buffer->lines[buffer->cursor.y]->length > 0 && buffer->lines[buffer->cursor.y - 1]->capacity - buffer->lines[buffer->cursor.y - 1]->length > buffer->lines[buffer->cursor.y]->length){ + memcpy(buffer->lines[buffer->cursor.y - 1]->text + buffer->lines[buffer->cursor.y - 1]->length, buffer->lines[buffer->cursor.y]->text, buffer->lines[buffer->cursor.y]->length); + } + + /* update new length */ + buffer->lines[buffer->cursor.y - 1]->length += buffer->lines[buffer->cursor.y]->length; + + /* Move the content of all lines below current up one line */ + if(buffer->cursor.y < buffer->line_count - 1){ + for (size_t i = buffer->cursor.y; i < buffer->line_count - 1; i++) { + buffer->lines[i]->text = buffer->lines[i + 1]->text; + buffer->lines[i]->length = buffer->lines[i + 1]->length; + buffer->lines[i]->capacity = buffer->lines[i + 1]->capacity; + } + } + + /* Remove the last line */ + kfree(buffer->lines[buffer->line_count - 1]->text); + buffer->lines[buffer->line_count - 1]->text = NULL; + buffer->lines[buffer->line_count - 1]->length = 0; + buffer->lines[buffer->line_count - 1]->capacity = 0; + buffer->line_count--; + + buffer->cursor.x = buffer->lines[buffer->cursor.y - 1]->length; + buffer->cursor.y--; + } else { + /* Remove the character before the cursor */ + if(buffer->lines[buffer->cursor.y] == NULL) { + buffer->cursor.x = 0; + return; + } + + if(buffer->cursor.x < buffer->lines[buffer->cursor.y]->length) { + for (size_t i = buffer->cursor.x; i < buffer->lines[buffer->cursor.y]->length; i++) { + buffer->lines[buffer->cursor.y]->text[i - 1] = buffer->lines[buffer->cursor.y]->text[i]; + } + buffer->lines[buffer->cursor.y]->text[buffer->lines[buffer->cursor.y]->length - 1] = '\0'; + buffer->lines[buffer->cursor.y]->length--; + buffer->cursor.x--; + return; + } + + buffer->lines[buffer->cursor.y]->text[buffer->cursor.x - 1] = '\0'; + buffer->lines[buffer->cursor.y]->length--; + buffer->cursor.x--; + } + } else if (c == '\n') { + /* If the cursor is at the end of the line, create a new line */ + if (buffer->cursor.x == buffer->lines[buffer->cursor.y]->length) { + /* If the buffer is full, do nothing */ + if (buffer->line_count == MAX_LINES) { + return; + } + + /* Create a new line */ + buffer->lines[buffer->line_count] = kalloc(sizeof(struct line)); + buffer->lines[buffer->line_count]->text = kalloc(32); + buffer->lines[buffer->line_count]->length = 0; + buffer->lines[buffer->line_count]->capacity = 32; + buffer->line_count++; + + /* Move the cursor to the beginning of the new line */ + buffer->cursor.x = 0; + buffer->cursor.y++; + } else { + /* Move down the content of all lines below current */ + for (size_t i = buffer->line_count - 1; i > buffer->cursor.y + 1; i--) { + buffer->lines[i]->text = buffer->lines[i - 1]->text; + buffer->lines[i]->length = buffer->lines[i - 1]->length; + buffer->lines[i]->capacity = buffer->lines[i - 1]->capacity; + } + + /* Create a new line */ + buffer->lines[buffer->cursor.y + 1] = kalloc(sizeof(struct line)); + buffer->lines[buffer->cursor.y + 1]->text = kalloc(32); + buffer->lines[buffer->cursor.y + 1]->length = 0; + buffer->lines[buffer->cursor.y + 1]->capacity = 32; + buffer->line_count++; + + + /* clear next line */ + memset(buffer->lines[buffer->cursor.y + 1]->text, 0, buffer->lines[buffer->cursor.y + 1]->capacity); + + /* Move the content from x to end down one line */ + for (size_t i = buffer->lines[buffer->cursor.y]->length; i > buffer->cursor.x; i--) { + buffer->lines[buffer->cursor.y + 1]->text[i - buffer->cursor.x - 1] = buffer->lines[buffer->cursor.y]->text[i - 1]; + } + + /* Set the length of the new line */ + buffer->lines[buffer->cursor.y + 1]->length = buffer->lines[buffer->cursor.y]->length - buffer->cursor.x; + + memset(buffer->lines[buffer->cursor.y]->text + buffer->cursor.x, 0, buffer->lines[buffer->cursor.y]->capacity - buffer->cursor.x); + /* Set the length of the old line */ + buffer->lines[buffer->cursor.y]->length = buffer->cursor.x; + + /* Move the cursor to the beginning of the new line */ + buffer->cursor.x = 0; + buffer->cursor.y++; + } + } else if(c >= ARROW_RIGHT && c <= ARROW_UP ){ + switch (c){ + case ARROW_RIGHT: + if(buffer->cursor.x < buffer->lines[buffer->cursor.y]->length){ + buffer->cursor.x++; + } + break; + case ARROW_LEFT: + if(buffer->cursor.x > 0){ + buffer->cursor.x--; + } + break; + case ARROW_UP: + if(buffer->cursor.y > 0){ + buffer->cursor.y--; + } + break; + case ARROW_DOWN: + if(buffer->cursor.y < buffer->line_count - 1){ + buffer->cursor.y++; + } + break; + } + textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + } else { + /* If the buffer is full, do nothing */ + if (buffer->lines[buffer->cursor.y]->length == buffer->lines[buffer->cursor.y]->capacity) { + return; + } + + /* If x is behind length, then we move content forward */ + if(buffer->cursor.x < buffer->lines[buffer->cursor.y]->length) { + /* Move the content from x to end forward one character */ + for (size_t i = buffer->lines[buffer->cursor.y]->length; i > buffer->cursor.x; i--) { + buffer->lines[buffer->cursor.y]->text[i] = buffer->lines[buffer->cursor.y]->text[i - 1]; + } + } + + /* Insert the character at the cursor position */ + buffer->lines[buffer->cursor.y]->text[buffer->cursor.x] = c; + buffer->lines[buffer->cursor.y]->length++; + buffer->cursor.x++; + } +} + + +static __kthread_entry void editor() +{ + char c; + struct textbuffer *buffer = textbuffer_create(); + + while (1){ + c = kb_get_char(); + if(c == 0) continue; + textbuffer_handle_char(buffer, c); + textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + } + +} +EXPORT_KSYMBOL(editor); + diff --git a/kernel/kthreads/shell.c b/kernel/kthreads/shell.c index 6bd165e..ebc1805 100644 --- a/kernel/kthreads/shell.c +++ b/kernel/kthreads/shell.c @@ -735,9 +735,9 @@ static void __kthread_entry textshell() twritef("\n"); twritef("%s\n", about_text); + __textshell_reset_box(); textshell_login(term); - __textshell_reset_box(); twritef("Memory: %d%s/%d%s\n", used.size, used.unit, total.size, total.unit); twritef("Type 'help' for a list of commands\n"); diff --git a/rootfs/symbols.map b/rootfs/symbols.map index 1ba3029..eb21bf4 100644 --- a/rootfs/symbols.map +++ b/rootfs/symbols.map @@ -508,383 +508,386 @@ 00023b99 draw_box 00023c7e __textshell_reset_box 00023d0e textshell -000240df __net_find_interface -0002413f net_drop_packet -00024160 net_handle_recieve -00024287 net_get_interfaces -0002428d net_configure_iface -000242df net_incoming_packet -00024390 net_get_iface -00024406 net_iface_up -0002442d net_iface_down -00024454 net_list_ifaces -0002456e net_register_interface -0002459f net_send_skb -00024627 net_get_info -0002464e networking_main -0002482e __dhcp_add_option -0002489e __dhcp_send_discovery -000249e0 __dhcp_send_request -00024b5d dhcp_get_state -00024b65 dhcp_get_dns -00024b6b dhcp_get_ip -00024b80 dhcp_get_gw -00024b95 dhcpd -00024e14 udp_server -00024e9f tcp_server -00025013 __net_terminal_writef -00025078 __register_kthread_tcp_server -00025092 __register_kthread_udp_server -000250ac __register_kthread_udptest -000250c6 udptest -00025151 tcpd -00025235 logd -000252a0 __register_kthread_logd -000252ba logd_attach_by_pid -000252fe taskbar_reboot -0002532a __reboot -0002533f taskbar_readme -00025358 taskbar_about -00025371 taskbar_clock -0002538a taskbar_sysinf -000253a3 taskbar_bg_retro -000253da taskbar_bg_lotr2 -000253ef taskbar_bg_lotr -00025404 taskbar_bg_default_color_gray -00025416 taskbar_bg_default_color -00025428 taskbar_wolfstein -00025463 taskbar_bg_graph -0002549e taskbar_bg_calc -000254d9 taskbar_colors -00025514 taskbar_cube -0002554f taskbar_editor -0002558a taskbar_finder -000255c5 taskbar_terminal -0002560e __register_kthread_taskbar -00025628 taskbar_hdr_opt_event -000256b2 taskbar -00025c69 about -00025e34 __register_kthread_about -00025e4e __register_kthread_readme -00025e68 readme -00025fca gfx_default_hover -000260e9 gfx_destory_window -00026176 gfx_window_resize -0002621f gfx_window_maximize -00026298 gfx_default_mouse_up -00026366 gfx_default_mouse_down -00026428 gfx_default_click -00026617 gfx_draw_window -00027403 gfx_window_set_resizable -00027418 kernel_gfx_window_border_color -00027443 gfx_new_window -000276a3 gfx_point_in_rectangle -000276d0 gfx_draw_component -00027712 gfx_input_event -00027844 gfx_input_draw -0002794c gfx_input_manager_add -000279ad gfx_composition_remove_window -000279d7 gfx_composition_add_window -00027a1e gfx_set_background_color -00027a6f gfx_raw_background -00027abc gfx_decode_background_image -00027b09 gfx_set_taskbar -00027ba9 gfx_compositor_main -00027c1d kernel_gfx_draw_circle_helper -00027ec9 gfx_get_window_width -00027ede gfx_get_window_height -00027ef3 gfx_push_event -00027faf gfx_put_icon16 -000280a7 gfx_put_icon32 -0002819f gfx_event_loop -000282be kernel_gfx_draw_rectangle -000283b8 kernel_gfx_draw_contoured_box -00028458 kernel_gfx_draw_pixel -000284f6 kernel_gfx_draw_bitmap -00028614 kernel_gfx_draw_char -00028714 kernel_gfx_set_position -00028730 gfx_commit -00028749 kernel_gfx_draw_text -000287fc gfx_button_ext -0002892f gfx_button -0002894d kernel_gfx_set_title -000289b9 kernel_gfx_set_header -00028a25 kernel_gfx_draw_line -00028bc0 kernel_gfx_draw_circle -00028c3f kernel_gfx_draw_section -00028c45 kernel_gfx_draw_format_text -00028f97 gfx_syscall_hook -0002914e gfx_total_themes -00029154 kernel_gfx_current_theme -0002915a kernel_gfx_update_theme -00029228 kernel_gfx_default_theme -0002922e kernel_gfx_set_theme -00029253 kernel_gfx_get_theme -0002926e gfx_new_ctx -000292ca gfx_init_framebuffer -00029436 netdev_attach_driver -000294df is_netdev_attached -000294ed netdev_transmit -00029508 netdev_recieve -00029531 net_ethernet_add_header -000295c5 net_ethernet_parse -00029639 __skb_queue_remove -00029677 __skb_queue_add -000296c7 skb_free_queue -000296ff skb_new_queue -00029766 skb_free -000297a1 skb_new -0002980c skb_consume -0002983d __net_arp_send -000298fd net_init_arp -00029949 net_arp_add_entry -000299d8 net_arp_find_entry -00029a23 net_arp_respond -00029a98 net_net_arp_request -00029b1e arp_parse -00029bc8 net_ipv4_print -00029bce net_ipv4_add_header -00029d05 net_is_ipv4 -00029d42 net_ipv4_parse -00029e6f ntohl -00029e9b htonl -00029eae ntohs -00029ebb htons -00029ec8 checksum -00029f1f transport_checksum -00029f74 ip_to_int -0002a012 net_icmp_handle -0002a0d7 net_icmp_response -0002a0dd net_icmp_request -0002a1a0 ping -0002a1f9 net_icmp_parse -0002a269 net_udp_send -0002a39e net_udp_parse -0002a4c6 socket_type_to_str -0002a4d5 socket_domain_to_str -0002a4e4 socket_protocol_to_str -0002a4f3 net_sock_bind -0002a53e net_get_sockets -0002a55a sock_get -0002a57b get_total_sockets -0002a581 net_sock_is_established -0002a5c5 net_sock_awaiting_ack -0002a609 net_sock_data_ready -0002a662 net_sock_read -0002a764 net_sock_add_data -0002a9c4 sock_find_listen_tcp -0002aa08 net_sock_find_tcp -0002abfa net_prepare_tcp_sock -0002ac86 net_sock_accept -0002ac99 net_socket_find_udp -0002ad04 kernel_sock_shutdown -0002ad31 kernel_sock_cleanup -0002adb7 kernel_sock_close -0002adeb kernel_socket_create -0002af6e net_init_sockets -0002afb4 gethostname -0002b4ce __add_systemcall_gethostname -0002b4e5 net_init_dns -0002b514 route -0002b561 tcb_init -0002b57f tcb_new -0002b6eb tcp_state_to_str -0002b704 tcp_new_connection -0002b78c tcp_free_connection -0002b7af tcp_is_listening -0002b7c5 tcp_set_listening -0002b825 tcp_calculate_checksum -0002b8e9 __tcp_send -0002ba05 tcp_send_segment -0002bb48 tcp_accept_connection -0002bc8a tcp_send_ack -0002bdc0 tcp_read -0002bdc6 tcp_recv_segment -0002bdcc tcp_connect -0002be6f tcp_send_syn -0002be75 tcp_recv_ack -0002bef8 tcp_recv_fin -0002befe tcp_recv_syn -0002c030 tcp_send_fin -0002c0fc tcp_close_connection -0002c13b tcp_parse -0002c5d4 kernel_bind -0002c609 kernel_recvfrom -0002c60f kernel_recv -0002c681 kernel_recv_timeout -0002c6a7 kernel_connect -0002c7ab kernel_sendto -0002c865 kernel_accept -0002c8c8 kernel_listen -0002c8f0 kernel_send -0002c976 sys_kernel_bind -0002c9a8 __add_systemcall_sys_kernel_bind -0002c9bf __add_systemcall_sys_kernel_accept -0002c9d6 __add_systemcall_sys_kernel_connect -0002c9ed __add_systemcall_sys_kernel_listen -0002ca04 __add_systemcall_sys_kernel_recv -0002ca1b __add_systemcall_sys_kernel_recvfrom -0002ca32 __add_systemcall_sys_kernel_recv_timeout -0002ca49 __add_systemcall_sys_kernel_send -0002ca60 __add_systemcall_sys_kernel_sendto -0002ca77 __add_systemcall_sys_socket_create -0002ca8e __add_systemcall_sys_kernel_sock_close -0002caa5 sys_kernel_accept -0002cae5 sys_kernel_connect -0002cb17 sys_kernel_listen -0002cb46 sys_kernel_recv -0002cb7e sys_kernel_recvfrom -0002cbbe sys_kernel_recv_timeout -0002cbfc sys_kernel_send -0002cc34 sys_kernel_sendto -0002cc74 sys_socket_create -0002cc9b sys_kernel_sock_close -0002ccdc __iface_send -0002cd0b __iface_recieve -0002cd3a __iface_assign -0002cd4d __iface_detach -0002cd61 __iface_set_gateway -0002cd74 __iface_set_netmask -0002cd87 __iface_configure -0002cdd7 __iface_attach -0002cdfc net_interface_create -0002ce34 net_register_netdev -0002cf4c net_interface_destroy -0002cf61 __default_restart -0002cf67 __default_stop -0002cfcc __default_start -0002d046 nm_new -0002d0cf nm_free -0002d114 net_firewall_create -0002d137 fs_file2fd -0002d19e fs_alloc_file -0002d1e9 fs_free_file -0002d243 fs_register -0002d312 fs_init -0002d318 fs_unregister -0002d37b fs_get -0002d381 fs_close -0002d3f3 fs_open -0002d46d fs_seek -0002d4ea fs_read -0002d5ff fs_load_from_file -0002d68b fs_write -0002d746 fs_save_to_file -0002d7d2 fat16_rmdir -0002d7d8 fat16_stat -0002d7de fat16_close -0002d848 fat16_rename -0002d8dd fat16_mkdir -0002d9c2 fat16_remove -0002da35 fat16_open -0002db7f fat16_read -0002dce3 fat16_write -0002de12 fat16_list -0002e0e0 fat16_init -0002e194 path_next_iter -0002e203 inode_from_path_recursise -0002e281 inode_from_path -0002e33f ext_get_root -0002e348 ext_get_current_dir -0002e357 ext_get_size -0002e35d ext_get_inodes -0002e363 ext_get_blocks -0002e369 ext_sync -0002e3dc ext_create -0002e4c7 ext_read -0002e542 ext_seek -0002e589 ext_write -0002e5f5 ext_close -0002e657 ext_open_from_directory -0002e75d ext_open -0002e814 ext_size -0002e83d change_directory -0002e8a3 ext_create_directory -0002ea3d ext_create_file_system -0002ed0a init_ext -0002eea6 listdir -0002efc7 __inode_sync -0002f02a __inode_cache_insert -0002f120 __inode_load -0002f194 inodes_sync -0002f1cf inode_get -0002f22c inode_read -0002f414 inode_write -0002f672 alloc_inode -0002f72b mkdir -0002f7d8 sync -0002f80c mkfs -0002f819 fat16_read_data_from_cluster -0002f867 fat16_read_data -0002f948 fat16_find_cluster_by_offset -0002f9c3 fat16_write_data_to_cluster_with_offset -0002f9fe fat16_print_cluster_chain -0002fa2c fat16_write_data_to_cluster -0002fa5f fat16_write_data -0002fb7b get_fat_start_block -0002fb83 get_root_directory_start_block -0002fb92 get_data_start_block -0002fba4 fat16_get_fat_entry -0002fbbf fat16_set_fat_entry -0002fbff fat16_sync_fat_table -0002fc77 fat16_allocate_cluster -0002fc8f fat16_free_cluster -0002fca4 fat16_get_free_cluster -0002fcf9 fat16_sync_directory_entry -0002fd7b fat16_read_entry -0002fe28 fat16_find_entry -0002ff63 fat16_rename_entry -0002ffd4 fat16_free_clusters -0003001b fat16_delete_entry -00030082 fat16_add_entry -000301e9 fat16_used_blocks -00030222 fat16_to_upper -0003024e fat16_name_compare -00030373 sstrtok -00030434 fat16_directory_entry_debug -00030504 fat16_get_directory_entry -000306fc fat16_create_directory -00030801 fat16_read_file -00030852 fat16_create_file -000308d0 fat16_create_empty_file -00030990 fat16_directory_entries -00030a76 fat16_mbr_clear -00030b1f fat16_mbr_add_entry -00030c10 fat16_print_root_directory_entries -00030c28 fat16_change_directory -00030cb0 fat16_bootblock_info -00030e2d fat16_set_time -00030e61 fat16_set_date -00030e99 fat16_load -00031018 fat16_format -000312cd mbr_partition_type_string -00031350 mbr_partitions_parse -00031419 mbr_get -0003141f mbr_partition_load -0003143d __list_users -000314ce __change_user -00031570 __remove_user -0003161c __add_user -00031706 __find_user -000317db __authenticate_user -000318e9 __save_users -0003196d __load_users -00031b6f __ksymbol_admin -00031b89 admin -00031e9d usermanager_create -00031ebc __ksymbol_snakegame -00031ed6 init_game -00031f24 draw -00031f80 get_input -00031f9f update -00032126 game_loop -0003214c snakegame -00032197 __msgbox -00032597 msgbox_create -000325ca msgbox_show -00032612 kevents_list -00032784 kevents_init -000327c6 kevents_destroy -0003281b kevents_add -000328d2 kevents_create -00032955 _code_end +000240da __net_find_interface +0002413a net_drop_packet +0002415b net_handle_recieve +00024282 net_get_interfaces +00024288 net_configure_iface +000242da net_incoming_packet +0002438b net_get_iface +00024401 net_iface_up +00024428 net_iface_down +0002444f net_list_ifaces +00024569 net_register_interface +0002459a net_send_skb +00024622 net_get_info +00024649 networking_main +00024829 __dhcp_add_option +00024899 __dhcp_send_discovery +000249db __dhcp_send_request +00024b58 dhcp_get_state +00024b60 dhcp_get_dns +00024b66 dhcp_get_ip +00024b7b dhcp_get_gw +00024b90 dhcpd +00024e0f udp_server +00024e9a tcp_server +0002500e __net_terminal_writef +00025073 __register_kthread_tcp_server +0002508d __register_kthread_udp_server +000250a7 __register_kthread_udptest +000250c1 udptest +0002514c tcpd +00025230 logd +0002529b __register_kthread_logd +000252b5 logd_attach_by_pid +000252f9 taskbar_reboot +00025325 __reboot +0002533a taskbar_readme +00025353 taskbar_about +0002536c taskbar_clock +00025385 taskbar_sysinf +0002539e taskbar_bg_retro +000253d5 taskbar_bg_lotr2 +000253ea taskbar_bg_lotr +000253ff taskbar_bg_default_color_gray +00025411 taskbar_bg_default_color +00025423 taskbar_wolfstein +0002545e taskbar_bg_graph +00025499 taskbar_bg_calc +000254d4 taskbar_colors +0002550f taskbar_cube +0002554a taskbar_editor +00025585 taskbar_finder +000255c0 taskbar_terminal +00025609 __register_kthread_taskbar +00025623 taskbar_hdr_opt_event +000256ad taskbar +00025c64 about +00025e2f __register_kthread_about +00025e49 __register_kthread_readme +00025e63 readme +00025fc5 gfx_default_hover +000260e4 gfx_destory_window +00026171 gfx_window_resize +0002621a gfx_window_maximize +00026293 gfx_default_mouse_up +00026361 gfx_default_mouse_down +00026423 gfx_default_click +00026612 gfx_draw_window +000273fe gfx_window_set_resizable +00027413 kernel_gfx_window_border_color +0002743e gfx_new_window +0002769e gfx_point_in_rectangle +000276cb gfx_draw_component +0002770d gfx_input_event +0002783f gfx_input_draw +00027947 gfx_input_manager_add +000279a8 gfx_composition_remove_window +000279d2 gfx_composition_add_window +00027a19 gfx_set_background_color +00027a6a gfx_raw_background +00027ab7 gfx_decode_background_image +00027b04 gfx_set_taskbar +00027ba4 gfx_compositor_main +00027c18 kernel_gfx_draw_circle_helper +00027ec4 gfx_get_window_width +00027ed9 gfx_get_window_height +00027eee gfx_push_event +00027faa gfx_put_icon16 +000280a2 gfx_put_icon32 +0002819a gfx_event_loop +000282b9 kernel_gfx_draw_rectangle +000283b3 kernel_gfx_draw_contoured_box +00028453 kernel_gfx_draw_pixel +000284f1 kernel_gfx_draw_bitmap +0002860f kernel_gfx_draw_char +0002870f kernel_gfx_set_position +0002872b gfx_commit +00028744 kernel_gfx_draw_text +000287f7 gfx_button_ext +0002892a gfx_button +00028948 kernel_gfx_set_title +000289b4 kernel_gfx_set_header +00028a20 kernel_gfx_draw_line +00028bbb kernel_gfx_draw_circle +00028c3a kernel_gfx_draw_section +00028c40 kernel_gfx_draw_format_text +00028f92 gfx_syscall_hook +00029149 gfx_total_themes +0002914f kernel_gfx_current_theme +00029155 kernel_gfx_update_theme +00029223 kernel_gfx_default_theme +00029229 kernel_gfx_set_theme +0002924e kernel_gfx_get_theme +00029269 gfx_new_ctx +000292c5 gfx_init_framebuffer +00029431 netdev_attach_driver +000294da is_netdev_attached +000294e8 netdev_transmit +00029503 netdev_recieve +0002952c net_ethernet_add_header +000295c0 net_ethernet_parse +00029634 __skb_queue_remove +00029672 __skb_queue_add +000296c2 skb_free_queue +000296fa skb_new_queue +00029761 skb_free +0002979c skb_new +00029807 skb_consume +00029838 __net_arp_send +000298f8 net_init_arp +00029944 net_arp_add_entry +000299d3 net_arp_find_entry +00029a1e net_arp_respond +00029a93 net_net_arp_request +00029b19 arp_parse +00029bc3 net_ipv4_print +00029bc9 net_ipv4_add_header +00029d00 net_is_ipv4 +00029d3d net_ipv4_parse +00029e6a ntohl +00029e96 htonl +00029ea9 ntohs +00029eb6 htons +00029ec3 checksum +00029f1a transport_checksum +00029f6f ip_to_int +0002a00d net_icmp_handle +0002a0d2 net_icmp_response +0002a0d8 net_icmp_request +0002a19b ping +0002a1f4 net_icmp_parse +0002a264 net_udp_send +0002a399 net_udp_parse +0002a4c1 socket_type_to_str +0002a4d0 socket_domain_to_str +0002a4df socket_protocol_to_str +0002a4ee net_sock_bind +0002a539 net_get_sockets +0002a555 sock_get +0002a576 get_total_sockets +0002a57c net_sock_is_established +0002a5c0 net_sock_awaiting_ack +0002a604 net_sock_data_ready +0002a65d net_sock_read +0002a75f net_sock_add_data +0002a9bf sock_find_listen_tcp +0002aa03 net_sock_find_tcp +0002abf5 net_prepare_tcp_sock +0002ac81 net_sock_accept +0002ac94 net_socket_find_udp +0002acff kernel_sock_shutdown +0002ad2c kernel_sock_cleanup +0002adb2 kernel_sock_close +0002ade6 kernel_socket_create +0002af69 net_init_sockets +0002afaf gethostname +0002b4c9 __add_systemcall_gethostname +0002b4e0 net_init_dns +0002b50f route +0002b55c tcb_init +0002b57a tcb_new +0002b6e6 tcp_state_to_str +0002b6ff tcp_new_connection +0002b787 tcp_free_connection +0002b7aa tcp_is_listening +0002b7c0 tcp_set_listening +0002b820 tcp_calculate_checksum +0002b8e4 __tcp_send +0002ba00 tcp_send_segment +0002bb43 tcp_accept_connection +0002bc85 tcp_send_ack +0002bdbb tcp_read +0002bdc1 tcp_recv_segment +0002bdc7 tcp_connect +0002be6a tcp_send_syn +0002be70 tcp_recv_ack +0002bef3 tcp_recv_fin +0002bef9 tcp_recv_syn +0002c02b tcp_send_fin +0002c0f7 tcp_close_connection +0002c136 tcp_parse +0002c5cf kernel_bind +0002c604 kernel_recvfrom +0002c60a kernel_recv +0002c67c kernel_recv_timeout +0002c6a2 kernel_connect +0002c7a6 kernel_sendto +0002c860 kernel_accept +0002c8c3 kernel_listen +0002c8eb kernel_send +0002c971 sys_kernel_bind +0002c9a3 __add_systemcall_sys_kernel_bind +0002c9ba __add_systemcall_sys_kernel_accept +0002c9d1 __add_systemcall_sys_kernel_connect +0002c9e8 __add_systemcall_sys_kernel_listen +0002c9ff __add_systemcall_sys_kernel_recv +0002ca16 __add_systemcall_sys_kernel_recvfrom +0002ca2d __add_systemcall_sys_kernel_recv_timeout +0002ca44 __add_systemcall_sys_kernel_send +0002ca5b __add_systemcall_sys_kernel_sendto +0002ca72 __add_systemcall_sys_socket_create +0002ca89 __add_systemcall_sys_kernel_sock_close +0002caa0 sys_kernel_accept +0002cae0 sys_kernel_connect +0002cb12 sys_kernel_listen +0002cb41 sys_kernel_recv +0002cb79 sys_kernel_recvfrom +0002cbb9 sys_kernel_recv_timeout +0002cbf7 sys_kernel_send +0002cc2f sys_kernel_sendto +0002cc6f sys_socket_create +0002cc96 sys_kernel_sock_close +0002ccd7 __iface_send +0002cd06 __iface_recieve +0002cd35 __iface_assign +0002cd48 __iface_detach +0002cd5c __iface_set_gateway +0002cd6f __iface_set_netmask +0002cd82 __iface_configure +0002cdd2 __iface_attach +0002cdf7 net_interface_create +0002ce2f net_register_netdev +0002cf47 net_interface_destroy +0002cf5c __default_restart +0002cf62 __default_stop +0002cfc7 __default_start +0002d041 nm_new +0002d0ca nm_free +0002d10f net_firewall_create +0002d132 fs_file2fd +0002d199 fs_alloc_file +0002d1e4 fs_free_file +0002d23e fs_register +0002d30d fs_init +0002d313 fs_unregister +0002d376 fs_get +0002d37c fs_close +0002d3ee fs_open +0002d468 fs_seek +0002d4e5 fs_read +0002d5fa fs_load_from_file +0002d686 fs_write +0002d741 fs_save_to_file +0002d7cd fat16_rmdir +0002d7d3 fat16_stat +0002d7d9 fat16_close +0002d843 fat16_rename +0002d8d8 fat16_mkdir +0002d9bd fat16_remove +0002da30 fat16_open +0002db7a fat16_read +0002dcde fat16_write +0002de0d fat16_list +0002e0db fat16_init +0002e18f path_next_iter +0002e1fe inode_from_path_recursise +0002e27c inode_from_path +0002e33a ext_get_root +0002e343 ext_get_current_dir +0002e352 ext_get_size +0002e358 ext_get_inodes +0002e35e ext_get_blocks +0002e364 ext_sync +0002e3d7 ext_create +0002e4c2 ext_read +0002e53d ext_seek +0002e584 ext_write +0002e5f0 ext_close +0002e652 ext_open_from_directory +0002e758 ext_open +0002e80f ext_size +0002e838 change_directory +0002e89e ext_create_directory +0002ea38 ext_create_file_system +0002ed05 init_ext +0002eea1 listdir +0002efc2 __inode_sync +0002f025 __inode_cache_insert +0002f11b __inode_load +0002f18f inodes_sync +0002f1ca inode_get +0002f227 inode_read +0002f40f inode_write +0002f66d alloc_inode +0002f726 mkdir +0002f7d3 sync +0002f807 mkfs +0002f814 fat16_read_data_from_cluster +0002f862 fat16_read_data +0002f943 fat16_find_cluster_by_offset +0002f9be fat16_write_data_to_cluster_with_offset +0002f9f9 fat16_print_cluster_chain +0002fa27 fat16_write_data_to_cluster +0002fa5a fat16_write_data +0002fb76 get_fat_start_block +0002fb7e get_root_directory_start_block +0002fb8d get_data_start_block +0002fb9f fat16_get_fat_entry +0002fbba fat16_set_fat_entry +0002fbfa fat16_sync_fat_table +0002fc72 fat16_allocate_cluster +0002fc8a fat16_free_cluster +0002fc9f fat16_get_free_cluster +0002fcf4 fat16_sync_directory_entry +0002fd76 fat16_read_entry +0002fe23 fat16_find_entry +0002ff5e fat16_rename_entry +0002ffcf fat16_free_clusters +00030016 fat16_delete_entry +0003007d fat16_add_entry +000301e4 fat16_used_blocks +0003021d fat16_to_upper +00030249 fat16_name_compare +0003036e sstrtok +0003042f fat16_directory_entry_debug +000304ff fat16_get_directory_entry +000306f7 fat16_create_directory +000307fc fat16_read_file +0003084d fat16_create_file +000308cb fat16_create_empty_file +0003098b fat16_directory_entries +00030a71 fat16_mbr_clear +00030b1a fat16_mbr_add_entry +00030c0b fat16_print_root_directory_entries +00030c23 fat16_change_directory +00030cab fat16_bootblock_info +00030e28 fat16_set_time +00030e5c fat16_set_date +00030e94 fat16_load +00031013 fat16_format +000312c8 mbr_partition_type_string +0003134b mbr_partitions_parse +00031414 mbr_get +0003141a mbr_partition_load +00031438 __list_users +000314c9 __change_user +0003156b __remove_user +00031617 __add_user +00031701 __find_user +000317d6 __authenticate_user +000318e4 __save_users +00031968 __load_users +00031b6a __ksymbol_admin +00031b84 admin +00031e98 usermanager_create +00031eb7 __ksymbol_snakegame +00031ed1 init_game +00031f1f draw +00031f7b get_input +00031f9a update +00032121 game_loop +00032147 snakegame +00032192 __msgbox +00032592 msgbox_create +000325c5 msgbox_show +0003260d kevents_list +0003277f kevents_init +000327c1 kevents_destroy +00032816 kevents_add +000328cd kevents_create +00032950 __ksymbol_editor +0003296a textbuffer_display +00032a02 editor +00032e90 _code_end From ef8eca1e55183d9a2463ccb8418867757984027d Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Fri, 2 Feb 2024 08:33:01 +0100 Subject: [PATCH 08/23] Small textbuffer fixes --- kernel/edit.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/kernel/edit.c b/kernel/edit.c index 373beeb..f1116b0 100644 --- a/kernel/edit.c +++ b/kernel/edit.c @@ -64,6 +64,21 @@ static int textbuffer_new_line(struct textbuffer *buffer) return 0; } +static int textbuffer_remove_last_line(struct textbuffer *buffer) +{ + if (buffer->line_count == 0) { + return -1; + } + + kfree(buffer->lines[buffer->line_count - 1]->text); + buffer->lines[buffer->line_count - 1]->text = NULL; + buffer->lines[buffer->line_count - 1]->length = 0; + buffer->lines[buffer->line_count - 1]->capacity = 0; + buffer->line_count--; + + return 0; +} + /* Function to display the content of the text buffer on the screen */ static void textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg) { uint8_t color = (bg << 4) | fg; @@ -98,18 +113,17 @@ static void textbuffer_display(const struct textbuffer *buffer, enum vga_color f static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { /* Handle the backspace key */ if (c == '\b') { - /* If the cursor is at the beginning of the line, go to the previous line */ + /* If we are at the end of the line */ if (buffer->cursor.x == 0) { /* If the cursor is at the beginning of the first line, do nothing */ if (buffer->cursor.y == 0 ) { return; } - /* TODO: move rest of line up */ + /* Move the rest of the current line up if there is space. */ if(buffer->lines[buffer->cursor.y]->length > 0 && buffer->lines[buffer->cursor.y - 1]->capacity - buffer->lines[buffer->cursor.y - 1]->length > buffer->lines[buffer->cursor.y]->length){ memcpy(buffer->lines[buffer->cursor.y - 1]->text + buffer->lines[buffer->cursor.y - 1]->length, buffer->lines[buffer->cursor.y]->text, buffer->lines[buffer->cursor.y]->length); } - /* update new length */ buffer->lines[buffer->cursor.y - 1]->length += buffer->lines[buffer->cursor.y]->length; @@ -123,11 +137,7 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { } /* Remove the last line */ - kfree(buffer->lines[buffer->line_count - 1]->text); - buffer->lines[buffer->line_count - 1]->text = NULL; - buffer->lines[buffer->line_count - 1]->length = 0; - buffer->lines[buffer->line_count - 1]->capacity = 0; - buffer->line_count--; + textbuffer_remove_last_line(buffer); buffer->cursor.x = buffer->lines[buffer->cursor.y - 1]->length; buffer->cursor.y--; @@ -138,6 +148,7 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { return; } + /* If x is behind length, then we move content back */ if(buffer->cursor.x < buffer->lines[buffer->cursor.y]->length) { for (size_t i = buffer->cursor.x; i < buffer->lines[buffer->cursor.y]->length; i++) { buffer->lines[buffer->cursor.y]->text[i - 1] = buffer->lines[buffer->cursor.y]->text[i]; @@ -148,6 +159,7 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { return; } + /* If x is at length, then we just remove the last character */ buffer->lines[buffer->cursor.y]->text[buffer->cursor.x - 1] = '\0'; buffer->lines[buffer->cursor.y]->length--; buffer->cursor.x--; @@ -160,12 +172,7 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { return; } - /* Create a new line */ - buffer->lines[buffer->line_count] = kalloc(sizeof(struct line)); - buffer->lines[buffer->line_count]->text = kalloc(32); - buffer->lines[buffer->line_count]->length = 0; - buffer->lines[buffer->line_count]->capacity = 32; - buffer->line_count++; + textbuffer_new_line(buffer); /* Move the cursor to the beginning of the new line */ buffer->cursor.x = 0; @@ -178,18 +185,12 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { buffer->lines[i]->capacity = buffer->lines[i - 1]->capacity; } - /* Create a new line */ - buffer->lines[buffer->cursor.y + 1] = kalloc(sizeof(struct line)); - buffer->lines[buffer->cursor.y + 1]->text = kalloc(32); - buffer->lines[buffer->cursor.y + 1]->length = 0; - buffer->lines[buffer->cursor.y + 1]->capacity = 32; - buffer->line_count++; - + textbuffer_new_line(buffer); /* clear next line */ memset(buffer->lines[buffer->cursor.y + 1]->text, 0, buffer->lines[buffer->cursor.y + 1]->capacity); - /* Move the content from x to end down one line */ + /* Move the content from x to length down one line */ for (size_t i = buffer->lines[buffer->cursor.y]->length; i > buffer->cursor.x; i--) { buffer->lines[buffer->cursor.y + 1]->text[i - buffer->cursor.x - 1] = buffer->lines[buffer->cursor.y]->text[i - 1]; } @@ -198,6 +199,7 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { buffer->lines[buffer->cursor.y + 1]->length = buffer->lines[buffer->cursor.y]->length - buffer->cursor.x; memset(buffer->lines[buffer->cursor.y]->text + buffer->cursor.x, 0, buffer->lines[buffer->cursor.y]->capacity - buffer->cursor.x); + /* Set the length of the old line */ buffer->lines[buffer->cursor.y]->length = buffer->cursor.x; From b1000a931bab7801f912185c0ecbe40196df24e7 Mon Sep 17 00:00:00 2001 From: Joe Bayer <58609672+joexbayer@users.noreply.github.com> Date: Fri, 2 Feb 2024 22:45:36 +0100 Subject: [PATCH 09/23] Update readme.md --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 441f3f0..19f09fd 100644 --- a/readme.md +++ b/readme.md @@ -316,6 +316,7 @@ To run RetrOS-32: - [x] Mouse events - [x] Dynamic resize - [x] Fullscreen + - [x] Widgets Library - [x] Terminal, Window Server, Process Informtaion, Finder. - [x] Library (printf, memcpy, etc) - [x] IPC From f3c88437b5e2c05bcab1ee6d6f1f7abecd10310d Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Sat, 3 Feb 2024 20:06:55 +0100 Subject: [PATCH 10/23] progress on editor --- kernel/edit.c | 158 ++-- rootfs/symbols.map | 1761 ++++++++++++++++++++++---------------------- 2 files changed, 995 insertions(+), 924 deletions(-) diff --git a/kernel/edit.c b/kernel/edit.c index f1116b0..149267e 100644 --- a/kernel/edit.c +++ b/kernel/edit.c @@ -8,32 +8,46 @@ #include #define MAX_LINES 512 - -struct line { - char *text; - size_t length; - size_t capacity; -}; +#define LINE_CAPACITY 78 struct textbuffer { - struct line **lines; - size_t line_count; + struct line { + char *text; + size_t length; + size_t capacity; + } **lines; struct cursor { size_t x; size_t y; } cursor; + size_t line_count; }; +static int textbuffer_new_line(struct textbuffer *buffer); static struct textbuffer *textbuffer_create(void) { + int ret; struct textbuffer *buffer = create(struct textbuffer); + if(buffer == NULL){ + return NULL; + } + buffer->lines = kalloc(sizeof(struct line*) * MAX_LINES); - buffer->lines[0]->text = kalloc(32); - buffer->line_count = 1; - buffer->lines[0]->length = 0; - buffer->lines[0]->capacity = 32; + if(buffer->lines == NULL){ + kfree(buffer); + return NULL; + } + + ret = textbuffer_new_line(buffer); + if(ret < 0){ + kfree(buffer->lines); + kfree(buffer); + return NULL; + } + buffer->cursor.x = 0; buffer->cursor.y = 0; + return buffer; } @@ -41,12 +55,12 @@ static void textbuffer_destroy(struct textbuffer *buffer) { for (size_t i = 0; i < buffer->line_count; i++) { if (buffer->lines[i]->text) { - free(buffer->lines[i]->text); + kfree(buffer->lines[i]->text); } - free(buffer->lines[i]); + kfree(buffer->lines[i]); } - free(buffer->lines); - free(buffer); + kfree(buffer->lines); + kfree(buffer); } static int textbuffer_new_line(struct textbuffer *buffer) @@ -56,9 +70,20 @@ static int textbuffer_new_line(struct textbuffer *buffer) } buffer->lines[buffer->line_count] = kalloc(sizeof(struct line)); - buffer->lines[buffer->line_count]->text = kalloc(32); + if(buffer->lines[buffer->line_count] == NULL){ + return -1; + } + + buffer->lines[buffer->line_count]->text = kalloc(LINE_CAPACITY); + if(buffer->lines[buffer->line_count]->text == NULL){ + kfree(buffer->lines[buffer->line_count]); + return -1; + } + + memset(buffer->lines[buffer->line_count]->text, 0, LINE_CAPACITY); + buffer->lines[buffer->line_count]->length = 0; - buffer->lines[buffer->line_count]->capacity = 32; + buffer->lines[buffer->line_count]->capacity = LINE_CAPACITY; buffer->line_count++; return 0; @@ -71,9 +96,28 @@ static int textbuffer_remove_last_line(struct textbuffer *buffer) } kfree(buffer->lines[buffer->line_count - 1]->text); - buffer->lines[buffer->line_count - 1]->text = NULL; - buffer->lines[buffer->line_count - 1]->length = 0; - buffer->lines[buffer->line_count - 1]->capacity = 0; + kfree(buffer->lines[buffer->line_count - 1]); + buffer->line_count--; + + return 0; +} + +static int textbuffer_free_line(struct textbuffer *buffer, size_t line) +{ + if (line >= buffer->line_count) { + return -1; + } + + /* Move the content of all lines below current up one line */ + for (size_t i = line; i < buffer->line_count - 1; i++) { + memset(buffer->lines[i]->text, 0, buffer->lines[i]->capacity); + memcpy(buffer->lines[i]->text, buffer->lines[i + 1]->text, buffer->lines[i + 1]->length); + buffer->lines[i]->length = buffer->lines[i + 1]->length; + } + + /* Remove the last line */ + kfree(buffer->lines[buffer->line_count - 1]->text); + kfree(buffer->lines[buffer->line_count - 1]); buffer->line_count--; return 0; @@ -95,7 +139,7 @@ static void textbuffer_display(const struct textbuffer *buffer, enum vga_color f /* Write the line to the screen */ if (buffer->lines[i]->text) { - scrprintf(x, y, "%s", buffer->lines[i]->text); + scrprintf(x, 1+y, "%d: %s (l: %d)", i, buffer->lines[i]->text, buffer->lines[i]->length); } } @@ -104,13 +148,15 @@ static void textbuffer_display(const struct textbuffer *buffer, enum vga_color f screen_set_cursor(x_start, y_start + buffer->line_count - 1); } - screen_set_cursor(buffer->cursor.x == 0 ? buffer->cursor.x : buffer->cursor.x -1, buffer->cursor.y); + screen_set_cursor(buffer->cursor.x-1+3, 1+buffer->cursor.y); /* write stats at the bottom */ scrprintf(0, 24, "line_count: %d, x: %d, y: %d", buffer->line_count, buffer->cursor.x, buffer->cursor.y); } /* Function to handle keyboard input of a char */ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { + int ret; + /* Handle the backspace key */ if (c == '\b') { /* If we are at the end of the line */ @@ -124,27 +170,19 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { if(buffer->lines[buffer->cursor.y]->length > 0 && buffer->lines[buffer->cursor.y - 1]->capacity - buffer->lines[buffer->cursor.y - 1]->length > buffer->lines[buffer->cursor.y]->length){ memcpy(buffer->lines[buffer->cursor.y - 1]->text + buffer->lines[buffer->cursor.y - 1]->length, buffer->lines[buffer->cursor.y]->text, buffer->lines[buffer->cursor.y]->length); } + buffer->cursor.x = buffer->lines[buffer->cursor.y - 1]->length; + /* update new length */ buffer->lines[buffer->cursor.y - 1]->length += buffer->lines[buffer->cursor.y]->length; - /* Move the content of all lines below current up one line */ - if(buffer->cursor.y < buffer->line_count - 1){ - for (size_t i = buffer->cursor.y; i < buffer->line_count - 1; i++) { - buffer->lines[i]->text = buffer->lines[i + 1]->text; - buffer->lines[i]->length = buffer->lines[i + 1]->length; - buffer->lines[i]->capacity = buffer->lines[i + 1]->capacity; - } - } - - /* Remove the last line */ - textbuffer_remove_last_line(buffer); + textbuffer_free_line(buffer, buffer->cursor.y); - buffer->cursor.x = buffer->lines[buffer->cursor.y - 1]->length; buffer->cursor.y--; } else { /* Remove the character before the cursor */ if(buffer->lines[buffer->cursor.y] == NULL) { buffer->cursor.x = 0; + dbgprintf("buffer->lines[buffer->cursor.y] == NULL %d, 0x%x\n", buffer->cursor.y, buffer->lines[buffer->cursor.y]); return; } @@ -160,7 +198,7 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { } /* If x is at length, then we just remove the last character */ - buffer->lines[buffer->cursor.y]->text[buffer->cursor.x - 1] = '\0'; + buffer->lines[buffer->cursor.y]->text[buffer->cursor.x - 1] = 0; buffer->lines[buffer->cursor.y]->length--; buffer->cursor.x--; } @@ -172,21 +210,41 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { return; } - textbuffer_new_line(buffer); + ret = textbuffer_new_line(buffer); + if(ret < 0){ + warningf("textbuffer_new_line failed\n"); + return; + } + + if(buffer->cursor.y != buffer->line_count - 1){ + /* Move down the content of all lines below current */ + for (size_t i = buffer->line_count - 1; i > buffer->cursor.y + 1; i--) { + memset(buffer->lines[i]->text, 0, buffer->lines[i]->capacity); + memcpy(buffer->lines[i]->text, buffer->lines[i - 1]->text, buffer->lines[i - 1]->length); + buffer->lines[i]->length = buffer->lines[i - 1]->length; + } + /* clear next line */ + memset(buffer->lines[buffer->cursor.y + 1]->text, 0, buffer->lines[buffer->cursor.y + 1]->capacity); + buffer->lines[buffer->cursor.y + 1]->length = 0; + } /* Move the cursor to the beginning of the new line */ buffer->cursor.x = 0; buffer->cursor.y++; } else { + /* Create a new line */ + ret = textbuffer_new_line(buffer); + if(ret < 0){ + warningf("textbuffer_new_line failed\n"); + return; + } + /* Move down the content of all lines below current */ for (size_t i = buffer->line_count - 1; i > buffer->cursor.y + 1; i--) { - buffer->lines[i]->text = buffer->lines[i - 1]->text; + memcpy(buffer->lines[i]->text, buffer->lines[i - 1]->text, buffer->lines[i - 1]->length); buffer->lines[i]->length = buffer->lines[i - 1]->length; - buffer->lines[i]->capacity = buffer->lines[i - 1]->capacity; } - textbuffer_new_line(buffer); - /* clear next line */ memset(buffer->lines[buffer->cursor.y + 1]->text, 0, buffer->lines[buffer->cursor.y + 1]->capacity); @@ -222,15 +280,20 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { case ARROW_UP: if(buffer->cursor.y > 0){ buffer->cursor.y--; + if(buffer->cursor.x > buffer->lines[buffer->cursor.y]->length){ + buffer->cursor.x = buffer->lines[buffer->cursor.y]->length; + } } break; case ARROW_DOWN: if(buffer->cursor.y < buffer->line_count - 1){ buffer->cursor.y++; + if(buffer->cursor.x > buffer->lines[buffer->cursor.y]->length){ + buffer->cursor.x = buffer->lines[buffer->cursor.y]->length; + } } break; } - textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); } else { /* If the buffer is full, do nothing */ if (buffer->lines[buffer->cursor.y]->length == buffer->lines[buffer->cursor.y]->capacity) { @@ -255,16 +318,23 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { static __kthread_entry void editor() { - char c; + unsigned char c; struct textbuffer *buffer = textbuffer_create(); - + if(buffer == NULL){ + dbgprintf("buffer == NULL\n"); + } + + textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); while (1){ c = kb_get_char(); if(c == 0) continue; + if(c == CTRLC) break; + textbuffer_handle_char(buffer, c); textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); } + textbuffer_destroy(buffer); } EXPORT_KSYMBOL(editor); diff --git a/rootfs/symbols.map b/rootfs/symbols.map index eb21bf4..cf28cba 100644 --- a/rootfs/symbols.map +++ b/rootfs/symbols.map @@ -11,883 +11,884 @@ 00010103 kernel 0001059d kernel_get_context 000105a3 hexdump -000107f1 __terminal_set_ops -000108ba __terminal_scanf -000108c0 __terminal_write -0001090a __terminal_getchar_graphics -00010953 __terminal_scan_graphics -00010a31 __terminal_reset -00010a75 __terminal_detach -00010ab8 __terminal_attach -00010b03 __terminal_remove_line -00010b43 __terminal_putchar_graphics -00010c0c __terminal_writef -00010f16 __terminal_getchar_textmode -00010f3e __terminal_scan_textmode -00011002 __terminal_commit_textmode -000110ba __terminal_putchar_textmode -00011106 scan -0001113f terminal_set_color -00011157 __terminal_commit_graphics -000112b3 terminal_attach -000112d4 terminal_commit -000112f3 terminal_putchar -0001132f terminal_create -00011454 terminal_destroy -0001148c tlb_flush_addr -00011494 load_page_directory -000114a4 enable_paging -000114b6 pcb_save_context -000114e2 pcb_restore_context -0001150b _start_pcb -0001153d _start_pcb_skip -00011558 __ksymbol_lspci -00011572 pci_get_class_name -00011585 pci_get_device_name -000115f6 pci_get_vendor_name -00011644 lspci -00011791 pci_get_devices -00011797 pci_read_word -000117f1 pci_write_dword -00011840 pci_enable_device_busmaster -00011895 pci_register_device -00011916 init_pci -00011ac7 pci_find_device -00011b5d virtual_read -00011b88 virtual_write -00011bb3 virtual_disk_attach -00011bd2 wm_default_changes -00011c7a wm_default_workspace -00011cdc wm_default_draw -00011d7a wm_default_add -00011e21 init_windowmanager -00011f6b wm_default_mouse_event -00012191 wm_default_push_back -00012283 wm_default_push_front -00012372 wm_default_remove -00012483 wm_destroy -00012561 wm_new -000125c8 screen_set_cursor -00012628 scrcolor_set -0001263c scrput -00012662 scrwrite -000126ab scr_clear -000126fd scr_scroll -00012745 scrprintf -00012989 strlen -000129ab strcpy -000129df strncmp -00012a1a strcmp -00012a5a memcmp -00012a95 parse_arguments -00012b78 strchr -00012ba7 getopt -00012cb7 memcpy -00012d24 strtok -00012ddc xmemcpy -00012e63 memset -00012ee3 isdigit -00012ef7 isspace -00012f06 tolower -00012f1a isxdigit -00012f3e htoi -00012fe2 atoi -00013072 itoa -00013118 itohex -00013194 rdtsc -00013197 rand -000131b3 general_protection_fault -00013243 interrupt_get_count -00013252 print_page_fault_info -0001332f page_fault_interrupt -000133c1 interrupt_install_handler -000133d3 load_data_segments -000133df isr_handler -000134d2 init_interrupts -0001364b idt_flush -00013653 isr0 -00013660 isr1 -0001366d isr2 -0001367a isr3 -00013687 isr4 -00013694 isr5 -000136a1 isr6 -000136ae isr7 -000136bb isr8 -000136c8 isr9 -000136d5 isr10 -000136e2 isr11 -000136ef isr12 -000136fc isr13 -00013709 isr14 -00013716 isr15 -00013723 isr16 -00013730 isr17 -0001373d isr18 -0001374a isr19 -00013757 isr20 -00013764 isr21 -00013771 isr22 -0001377e isr23 -0001378b isr24 -00013798 isr25 -000137a5 isr26 -000137b2 isr27 -000137bf isr28 -000137cc isr29 -000137d9 isr30 -000137e6 isr31 -000137f3 isr32 -00013800 isr33 -0001380d isr34 -0001381a isr35 -00013824 isr36 -0001382e isr37 -00013838 isr38 -00013842 isr39 -0001384c isr40 -00013856 isr41 -00013860 isr42 -0001386a isr43 -00013874 isr44 -0001387e isr45 -00013888 isr46 -00013892 isr47 -0001389c isr_entry -000138b7 syscall_return_value -000138bb _syscall_entry -000138f8 page_fault_save -000138fc page_fault_error -00013900 _page_fault_entry -00013932 timer_callback -0001396a timer_get_tick -00013970 time_get_difference -000139b3 init_pit -00013a17 gdt_set_segment -00013a60 init_gdt -00013b6e rc -00013d5d __ksymbol_rc -00013d77 __ksymbol_as -00013d91 __ksymbol_cc -00013dab as -0001416d cc -000141c9 __cc -000144bd vm_print -000146ba eval -00014b54 vm_setup -00014b95 vm_init -00014bf0 vm_free -00014c1f vm_setup_stack -00014c7b lex_get_error -00014c88 next -00015193 match -000151e1 expression -000164e2 statement -000166eb function_parameter -000168ad function_body -00016abc function_declaration -00016b45 enum_declaration -00016c58 global_declaration -00016e85 lex_init -00016f20 program -00016fc1 find_mp_floating_ptr -00016ffd smp_parse -00017142 kb_get_char -0001718e kb_add_char -000171c9 kb_callback -000173f6 init_keyboard -0001746d pcb_await -00017497 __pcb_get_free -00017555 __add_systemcall_pcb_await -0001756c __pcb_free -000175bb __pcb_init_kernel_stack -0001761c __pcb_init_process -000176e1 init_pcbs -00017732 pcb_total_usage -0001775b pcb_get_info -0001784f pcb_kill -0001786c Genesis -0001786e idletask -00017889 pcb_get_by_pid -0001789a pcb_get_by_name -000178f3 pcb_dbg_print -0001796d pcb_cleanup_routine -00017b7d pcb_create_thread -00017c75 pcb_create_process -00017f07 pcb_create_kthread -000181e3 start_pcb -0001821b __pcb_queue_peek -0001825a __pcb_queue_pop -000182b6 __pcb_queue_remove -00018328 __pcb_queue_add -000183a1 __pcb_queue_push -0001843a pcb_new_queue -0001846b get_mem_info -000184c3 memory_map_init -0001858a memory_map_get -00018590 free -000185e7 malloc -00018683 calloc -000186b6 krealloc -00018722 init_memory -000187b4 vmem_free -00018824 vmem_alloc -00018891 vmem_free_page_region -000189f7 vmem_page_region_alloc -00018a32 vmem_create_page_region -00018b76 vmem_free_allocations -00018ca5 vmem_continious_allocation_map -00018cab vmem_free_allocation -00018cac vmem_stack_free -00018d5d vmem_stack_alloc -000190e2 vmem_dump_heap -00019177 vmem_init_process_thread -00019268 vmem_init_process -00019596 vmem_cleanup_process_thead -0001960d vmem_cleanup_process -000197fb vmem_init_kernel -000199bc vmem_allocator_create -00019a20 vmem_map_driver_region -00019a9e vmem_total_usage -00019ab1 vmem_init -00019be3 kalloc -00019d7a kcalloc -00019dac kfree -00019e42 palloc -00019e84 pmemory_used -00019ea0 kmemory_used -00019ea6 kmemory_total -00019eb2 kmem_init -00019f4f e1000_receive -0001a02a e1000_transmit -0001a0ec e1000_callback -0001a113 _e1000_tx_init -0001a1b7 _e1000_rx_init -0001a251 e1000_attach -0001a481 display_get_info -0001a4ea kenv_init -0001a501 kenv_set -0001a536 config_list -0001a607 kernel_config_load -0001a9f2 config_get_value -0001aaad spin_lock -0001aacd spin_unlock -0001aadb mutex_init -0001aaf8 acquire -0001ab95 release -0001ac37 kthread_entry -0001ac91 kthread_list -0001acf8 register_kthread -0001add1 start -0001ae73 ata_primary -0001ae74 ata_secondary -0001ae75 ata_wait -0001aeef ata_write -0001b066 ata_read -0001b1f6 ata_ide_init -0001b3c6 set_bitmap -0001b3e8 unset_bitmap -0001b40c get_bitmap -0001b42e get_bitmap_size -0001b442 create_bitmap -0001b476 destroy_bitmap -0001b489 bitmap_unset_continous -0001b4c3 bitmap_get_continous -0001b55f get_free_bitmap -0001b5b4 __rtc_check_in_progress -0001b5d6 __rtc_get_register -0001b5f6 get_current_time -0001b741 get_time -0001b76b init_tss -0001b799 __add_systemcall_sys_system -0001b7b0 exec_cmd -0001b8b4 sys_system -0001b8c4 __ksymbol_exec_cmd -0001b8de system_reboot -0001b912 align_to_pointer_size -0001b920 calculate_size_unit -0001b982 advanced_hash -0001b9b6 kernel_panic -0001b9d4 kref_init -0001b9ee kref_get -0001ba16 kref_put -0001ba3e csprintf -0001bc3f script_parse -0001bd14 login -0001c0b2 __login_create_virt_disk -0001c0dc __register_kthread_login -0001c0f6 help -0001c397 clear -0001c3b8 __ksymbol_new -0001c3d2 __ksymbol_list -0001c3ec __ksymbol_color -0001c406 __ksymbol_about -0001c420 __ksymbol_help -0001c43a __ksymbol_kevents -0001c454 __ksymbol_view -0001c46e __ksymbol_file -0001c488 __ksymbol_tcp -0001c4a2 __ksymbol_conf -0001c4bc __ksymbol_clear -0001c4d6 __ksymbol_services -0001c4f0 __ksymbol_reboot -0001c50a kevents -0001c5e4 services -0001c812 new -0001c953 list -0001ca53 file -0001cc21 color -0001ccc2 about -0001ccff view -0001cf14 tcp -0001d1f1 __tcp_reader -0001d312 conf -0001d5da reboot -0001d613 attach_disk_dev -0001d637 disk_attached -0001d63f disk_name -0001d648 disk_device_get -0001d64e disk_size -0001d66a write_block -0001d6a7 write_block_offset -0001d6ea read_block -0001d727 read_block_offset -0001d791 sched_consume -0001d7d2 sched_add -0001d82c sched_prioritize -0001d8e1 sched_round_robin -0001dac7 sched_exit -0001db80 sched_block -0001dc9e sched_default -0001dd78 sched_sleep -0001de1e sched_init_default -0001de9f get_scheduler -0001dea5 kernel_sleep -0001dec0 kernel_yield -0001df03 kernel_exit -0001df35 block -0001df5e unblock -0001df5f work_queue_add -0001e047 init_worker -0001e05f worker_thread -0001e0fe __ring_buffer_add -0001e1a6 __ring_buffer_read -0001e2b0 rbuffer_new -0001e319 rbuffer_free -0001e33b error_get_string -0001e377 kclock -0001e857 __register_kthread_kclock -0001e871 tar_extract -0001eac1 __ksymbol_tar -0001eadb tar_list -0001ebe5 tar -0001ee6e rgb_to_vga -0001ee7e rgb_to_components -0001eea5 color_distance_squared -0001ef10 rgb_init_color_table -0001efa1 iface_loopback_write -0001f062 iface_loopback_interrupt -0001f079 iface_loopback_read -0001f11c net_init_loopback -0001f133 serial_put -0001f173 serial_write -0001f1b5 serial_printf -0001f355 init_serial -0001f41b inportb -0001f424 inportw -0001f42e inportl -0001f437 outportb -0001f445 outportw -0001f454 outportl -0001f461 sys_create_thread -0001f480 __add_systemcall_sys_create_thread -0001f48b add_system_call -0001f4cb system_call -0001f536 hashmap_put -0001f59d hashmap_get -0001f621 hashmap_add -0001f6ab hashmap_free -0001f6ac reset_vga_palette -0001f6f2 vga_set_palette -0001f7dd b8to16 -0001f7ed vesa_put_pixel -0001f817 vesa_put_box -0001f892 vesa_put_block -0001f90d vesa_put_char -0001f988 vesa_put_char16 -0001fa1b vesa_put_icon16 -0001fa94 vesa_write -0001fad3 vesa_write_str -0001fb01 vesa_fill -0001fb83 vesa_fillrect -0001fbf5 vesa_inner_box -0001fcfd vesa_printf -0001ff6a ksyms_init -00020191 ksyms_add_symbol -0002024a __ksymbol_backtrace -00020264 ksyms_list -000202c6 ksyms_resolve_symbol -00020379 __backtrace_from -00020496 backtrace -000204a7 ws_fullscreen -00020621 ws_remove -000206d1 ws_add -000207bc ws_destroy -00020862 ws_draw -00020b0f ws_raw_wallpaper -00020bf5 ws_set_background_file -00020ed2 ws_init -00020fb5 ws_set_background -00021060 ws_new -000210ed encode_run_length -0002116a decode_run_length -000211d5 __mouse_handler -000212ec mouse_wait -00021334 mouse_write -00021376 mouse_get_event -000213b7 mouse_init -0002149c sys_ipc_open -000214ea __add_systemcall_sys_ipc_open -00021501 __add_systemcall_sys_ipc_close -00021518 __add_systemcall_sys_ipc_send -0002152f __add_systemcall_sys_ipc_receive -00021546 sys_ipc_close -0002158f sys_ipc_send -000215f6 sys_ipc_receive -0002165c sysinf -000223ae __register_kthread_sysinf -000223c8 echo -00022403 res -00022444 ifconfig -00022451 __ksymbol_ifconfig -0002246b __ksymbol_ps -00022485 __ksymbol_tree -0002249f __ksymbol_fat16 -000224b9 __ksymbol_xxd -000224d3 __ksymbol_sh -000224ed __ksymbol_ed -00022507 __ksymbol_exec -00022521 __ksymbol_ths -0002253b __ksymbol_dns -00022555 __ksymbol_th -0002256f __ksymbol_kill -00022589 __ksymbol_echo -000225a3 __ksymbol_fdisk -000225bd __ksymbol_meminfo -000225d7 __ksymbol_res -000225f1 __ksymbol_bg -0002260b __ksymbol_exit -00022625 __ksymbol_socks -0002263f __ksymbol_reset -00022659 exit -0002268d ps -00022901 print_pcb_tree -00022a00 tree -00022a40 fat16 -00022a68 xxd -00022b5d sh -00022c5d ed -00022caa exec -00022e0e ths -00022e7a dns -00022eee th -00022f0c kill -00022f2a fdisk -000230bc meminfo -0002329b bg -0002331a socks -000235c0 __register_kthread_shell -000235da __register_kthread_textshell -000235f4 shell_clear -00023637 reset_shell -000236a8 reset -000236fc shell_put -000238dd shell -00023b3e cleanup_function -00023b65 testfn -00023b99 draw_box -00023c7e __textshell_reset_box -00023d0e textshell -000240da __net_find_interface -0002413a net_drop_packet -0002415b net_handle_recieve -00024282 net_get_interfaces -00024288 net_configure_iface -000242da net_incoming_packet -0002438b net_get_iface -00024401 net_iface_up -00024428 net_iface_down -0002444f net_list_ifaces -00024569 net_register_interface -0002459a net_send_skb -00024622 net_get_info -00024649 networking_main -00024829 __dhcp_add_option -00024899 __dhcp_send_discovery -000249db __dhcp_send_request -00024b58 dhcp_get_state -00024b60 dhcp_get_dns -00024b66 dhcp_get_ip -00024b7b dhcp_get_gw -00024b90 dhcpd -00024e0f udp_server -00024e9a tcp_server -0002500e __net_terminal_writef -00025073 __register_kthread_tcp_server -0002508d __register_kthread_udp_server -000250a7 __register_kthread_udptest -000250c1 udptest -0002514c tcpd -00025230 logd -0002529b __register_kthread_logd -000252b5 logd_attach_by_pid -000252f9 taskbar_reboot -00025325 __reboot -0002533a taskbar_readme -00025353 taskbar_about -0002536c taskbar_clock -00025385 taskbar_sysinf -0002539e taskbar_bg_retro -000253d5 taskbar_bg_lotr2 -000253ea taskbar_bg_lotr -000253ff taskbar_bg_default_color_gray -00025411 taskbar_bg_default_color -00025423 taskbar_wolfstein -0002545e taskbar_bg_graph -00025499 taskbar_bg_calc -000254d4 taskbar_colors -0002550f taskbar_cube -0002554a taskbar_editor -00025585 taskbar_finder -000255c0 taskbar_terminal -00025609 __register_kthread_taskbar -00025623 taskbar_hdr_opt_event -000256ad taskbar -00025c64 about -00025e2f __register_kthread_about -00025e49 __register_kthread_readme -00025e63 readme -00025fc5 gfx_default_hover -000260e4 gfx_destory_window -00026171 gfx_window_resize -0002621a gfx_window_maximize -00026293 gfx_default_mouse_up -00026361 gfx_default_mouse_down -00026423 gfx_default_click -00026612 gfx_draw_window -000273fe gfx_window_set_resizable -00027413 kernel_gfx_window_border_color -0002743e gfx_new_window -0002769e gfx_point_in_rectangle -000276cb gfx_draw_component -0002770d gfx_input_event -0002783f gfx_input_draw -00027947 gfx_input_manager_add -000279a8 gfx_composition_remove_window -000279d2 gfx_composition_add_window -00027a19 gfx_set_background_color -00027a6a gfx_raw_background -00027ab7 gfx_decode_background_image -00027b04 gfx_set_taskbar -00027ba4 gfx_compositor_main -00027c18 kernel_gfx_draw_circle_helper -00027ec4 gfx_get_window_width -00027ed9 gfx_get_window_height -00027eee gfx_push_event -00027faa gfx_put_icon16 -000280a2 gfx_put_icon32 -0002819a gfx_event_loop -000282b9 kernel_gfx_draw_rectangle -000283b3 kernel_gfx_draw_contoured_box -00028453 kernel_gfx_draw_pixel -000284f1 kernel_gfx_draw_bitmap -0002860f kernel_gfx_draw_char -0002870f kernel_gfx_set_position -0002872b gfx_commit -00028744 kernel_gfx_draw_text -000287f7 gfx_button_ext -0002892a gfx_button -00028948 kernel_gfx_set_title -000289b4 kernel_gfx_set_header -00028a20 kernel_gfx_draw_line -00028bbb kernel_gfx_draw_circle -00028c3a kernel_gfx_draw_section -00028c40 kernel_gfx_draw_format_text -00028f92 gfx_syscall_hook -00029149 gfx_total_themes -0002914f kernel_gfx_current_theme -00029155 kernel_gfx_update_theme -00029223 kernel_gfx_default_theme -00029229 kernel_gfx_set_theme -0002924e kernel_gfx_get_theme -00029269 gfx_new_ctx -000292c5 gfx_init_framebuffer -00029431 netdev_attach_driver -000294da is_netdev_attached -000294e8 netdev_transmit -00029503 netdev_recieve -0002952c net_ethernet_add_header -000295c0 net_ethernet_parse -00029634 __skb_queue_remove -00029672 __skb_queue_add -000296c2 skb_free_queue -000296fa skb_new_queue -00029761 skb_free -0002979c skb_new -00029807 skb_consume -00029838 __net_arp_send -000298f8 net_init_arp -00029944 net_arp_add_entry -000299d3 net_arp_find_entry -00029a1e net_arp_respond -00029a93 net_net_arp_request -00029b19 arp_parse -00029bc3 net_ipv4_print -00029bc9 net_ipv4_add_header -00029d00 net_is_ipv4 -00029d3d net_ipv4_parse -00029e6a ntohl -00029e96 htonl -00029ea9 ntohs -00029eb6 htons -00029ec3 checksum -00029f1a transport_checksum -00029f6f ip_to_int -0002a00d net_icmp_handle -0002a0d2 net_icmp_response -0002a0d8 net_icmp_request -0002a19b ping -0002a1f4 net_icmp_parse -0002a264 net_udp_send -0002a399 net_udp_parse -0002a4c1 socket_type_to_str -0002a4d0 socket_domain_to_str -0002a4df socket_protocol_to_str -0002a4ee net_sock_bind -0002a539 net_get_sockets -0002a555 sock_get -0002a576 get_total_sockets -0002a57c net_sock_is_established -0002a5c0 net_sock_awaiting_ack -0002a604 net_sock_data_ready -0002a65d net_sock_read -0002a75f net_sock_add_data -0002a9bf sock_find_listen_tcp -0002aa03 net_sock_find_tcp -0002abf5 net_prepare_tcp_sock -0002ac81 net_sock_accept -0002ac94 net_socket_find_udp -0002acff kernel_sock_shutdown -0002ad2c kernel_sock_cleanup -0002adb2 kernel_sock_close -0002ade6 kernel_socket_create -0002af69 net_init_sockets -0002afaf gethostname -0002b4c9 __add_systemcall_gethostname -0002b4e0 net_init_dns -0002b50f route -0002b55c tcb_init -0002b57a tcb_new -0002b6e6 tcp_state_to_str -0002b6ff tcp_new_connection -0002b787 tcp_free_connection -0002b7aa tcp_is_listening -0002b7c0 tcp_set_listening -0002b820 tcp_calculate_checksum -0002b8e4 __tcp_send -0002ba00 tcp_send_segment -0002bb43 tcp_accept_connection -0002bc85 tcp_send_ack -0002bdbb tcp_read -0002bdc1 tcp_recv_segment -0002bdc7 tcp_connect -0002be6a tcp_send_syn -0002be70 tcp_recv_ack -0002bef3 tcp_recv_fin -0002bef9 tcp_recv_syn -0002c02b tcp_send_fin -0002c0f7 tcp_close_connection -0002c136 tcp_parse -0002c5cf kernel_bind -0002c604 kernel_recvfrom -0002c60a kernel_recv -0002c67c kernel_recv_timeout -0002c6a2 kernel_connect -0002c7a6 kernel_sendto -0002c860 kernel_accept -0002c8c3 kernel_listen -0002c8eb kernel_send -0002c971 sys_kernel_bind -0002c9a3 __add_systemcall_sys_kernel_bind -0002c9ba __add_systemcall_sys_kernel_accept -0002c9d1 __add_systemcall_sys_kernel_connect -0002c9e8 __add_systemcall_sys_kernel_listen -0002c9ff __add_systemcall_sys_kernel_recv -0002ca16 __add_systemcall_sys_kernel_recvfrom -0002ca2d __add_systemcall_sys_kernel_recv_timeout -0002ca44 __add_systemcall_sys_kernel_send -0002ca5b __add_systemcall_sys_kernel_sendto -0002ca72 __add_systemcall_sys_socket_create -0002ca89 __add_systemcall_sys_kernel_sock_close -0002caa0 sys_kernel_accept -0002cae0 sys_kernel_connect -0002cb12 sys_kernel_listen -0002cb41 sys_kernel_recv -0002cb79 sys_kernel_recvfrom -0002cbb9 sys_kernel_recv_timeout -0002cbf7 sys_kernel_send -0002cc2f sys_kernel_sendto -0002cc6f sys_socket_create -0002cc96 sys_kernel_sock_close -0002ccd7 __iface_send -0002cd06 __iface_recieve -0002cd35 __iface_assign -0002cd48 __iface_detach -0002cd5c __iface_set_gateway -0002cd6f __iface_set_netmask -0002cd82 __iface_configure -0002cdd2 __iface_attach -0002cdf7 net_interface_create -0002ce2f net_register_netdev -0002cf47 net_interface_destroy -0002cf5c __default_restart -0002cf62 __default_stop -0002cfc7 __default_start -0002d041 nm_new -0002d0ca nm_free -0002d10f net_firewall_create -0002d132 fs_file2fd -0002d199 fs_alloc_file -0002d1e4 fs_free_file -0002d23e fs_register -0002d30d fs_init -0002d313 fs_unregister -0002d376 fs_get -0002d37c fs_close -0002d3ee fs_open -0002d468 fs_seek -0002d4e5 fs_read -0002d5fa fs_load_from_file -0002d686 fs_write -0002d741 fs_save_to_file -0002d7cd fat16_rmdir -0002d7d3 fat16_stat -0002d7d9 fat16_close -0002d843 fat16_rename -0002d8d8 fat16_mkdir -0002d9bd fat16_remove -0002da30 fat16_open -0002db7a fat16_read -0002dcde fat16_write -0002de0d fat16_list -0002e0db fat16_init -0002e18f path_next_iter -0002e1fe inode_from_path_recursise -0002e27c inode_from_path -0002e33a ext_get_root -0002e343 ext_get_current_dir -0002e352 ext_get_size -0002e358 ext_get_inodes -0002e35e ext_get_blocks -0002e364 ext_sync -0002e3d7 ext_create -0002e4c2 ext_read -0002e53d ext_seek -0002e584 ext_write -0002e5f0 ext_close -0002e652 ext_open_from_directory -0002e758 ext_open -0002e80f ext_size -0002e838 change_directory -0002e89e ext_create_directory -0002ea38 ext_create_file_system -0002ed05 init_ext -0002eea1 listdir -0002efc2 __inode_sync -0002f025 __inode_cache_insert -0002f11b __inode_load -0002f18f inodes_sync -0002f1ca inode_get -0002f227 inode_read -0002f40f inode_write -0002f66d alloc_inode -0002f726 mkdir -0002f7d3 sync -0002f807 mkfs -0002f814 fat16_read_data_from_cluster -0002f862 fat16_read_data -0002f943 fat16_find_cluster_by_offset -0002f9be fat16_write_data_to_cluster_with_offset -0002f9f9 fat16_print_cluster_chain -0002fa27 fat16_write_data_to_cluster -0002fa5a fat16_write_data -0002fb76 get_fat_start_block -0002fb7e get_root_directory_start_block -0002fb8d get_data_start_block -0002fb9f fat16_get_fat_entry -0002fbba fat16_set_fat_entry -0002fbfa fat16_sync_fat_table -0002fc72 fat16_allocate_cluster -0002fc8a fat16_free_cluster -0002fc9f fat16_get_free_cluster -0002fcf4 fat16_sync_directory_entry -0002fd76 fat16_read_entry -0002fe23 fat16_find_entry -0002ff5e fat16_rename_entry -0002ffcf fat16_free_clusters -00030016 fat16_delete_entry -0003007d fat16_add_entry -000301e4 fat16_used_blocks -0003021d fat16_to_upper -00030249 fat16_name_compare -0003036e sstrtok -0003042f fat16_directory_entry_debug -000304ff fat16_get_directory_entry -000306f7 fat16_create_directory -000307fc fat16_read_file -0003084d fat16_create_file -000308cb fat16_create_empty_file -0003098b fat16_directory_entries -00030a71 fat16_mbr_clear -00030b1a fat16_mbr_add_entry -00030c0b fat16_print_root_directory_entries -00030c23 fat16_change_directory -00030cab fat16_bootblock_info -00030e28 fat16_set_time -00030e5c fat16_set_date -00030e94 fat16_load -00031013 fat16_format -000312c8 mbr_partition_type_string -0003134b mbr_partitions_parse -00031414 mbr_get -0003141a mbr_partition_load -00031438 __list_users -000314c9 __change_user -0003156b __remove_user -00031617 __add_user -00031701 __find_user -000317d6 __authenticate_user -000318e4 __save_users -00031968 __load_users -00031b6a __ksymbol_admin -00031b84 admin -00031e98 usermanager_create -00031eb7 __ksymbol_snakegame -00031ed1 init_game -00031f1f draw -00031f7b get_input -00031f9a update -00032121 game_loop -00032147 snakegame -00032192 __msgbox -00032592 msgbox_create -000325c5 msgbox_show -0003260d kevents_list -0003277f kevents_init -000327c1 kevents_destroy -00032816 kevents_add -000328cd kevents_create -00032950 __ksymbol_editor -0003296a textbuffer_display -00032a02 editor -00032e90 _code_end +000107f4 __terminal_set_ops +000108bd __terminal_scanf +000108c3 __terminal_write +0001090d __terminal_getchar_graphics +00010956 __terminal_scan_graphics +00010a34 __terminal_reset +00010a78 __terminal_detach +00010abb __terminal_attach +00010b06 __terminal_remove_line +00010b46 __terminal_putchar_graphics +00010c0f __terminal_writef +00010f19 __terminal_getchar_textmode +00010f41 __terminal_scan_textmode +00011005 __terminal_commit_textmode +000110bd __terminal_putchar_textmode +00011109 scan +00011142 terminal_set_color +0001115a __terminal_commit_graphics +000112b6 terminal_attach +000112d7 terminal_commit +000112f6 terminal_putchar +00011332 terminal_create +00011457 terminal_destroy +00011490 tlb_flush_addr +00011498 load_page_directory +000114a8 enable_paging +000114ba pcb_save_context +000114e6 pcb_restore_context +0001150f _start_pcb +00011541 _start_pcb_skip +0001155c __ksymbol_lspci +00011576 pci_get_class_name +00011589 pci_get_device_name +000115fa pci_get_vendor_name +00011648 lspci +00011795 pci_get_devices +0001179b pci_read_word +000117f5 pci_write_dword +00011844 pci_enable_device_busmaster +00011899 pci_register_device +0001191a init_pci +00011acb pci_find_device +00011b61 virtual_read +00011b8c virtual_write +00011bb7 virtual_disk_attach +00011bd6 wm_default_changes +00011c7e wm_default_workspace +00011ce0 wm_default_draw +00011d7e wm_default_add +00011e25 init_windowmanager +00011f6f wm_default_mouse_event +00012195 wm_default_push_back +00012287 wm_default_push_front +00012376 wm_default_remove +00012487 wm_destroy +00012565 wm_new +000125cc screen_set_cursor +0001262c scrcolor_set +00012640 scrput +00012666 scrwrite +000126af scr_clear +00012701 scr_scroll +00012749 scrprintf +0001298d strlen +000129af strcpy +000129e3 strncmp +00012a1e strcmp +00012a5e memcmp +00012a99 parse_arguments +00012b7c strchr +00012bab getopt +00012cbb memcpy +00012d28 strtok +00012de0 xmemcpy +00012e67 memset +00012ee7 isdigit +00012efb isspace +00012f0a tolower +00012f1e isxdigit +00012f42 htoi +00012fe6 atoi +00013076 itoa +0001311c itohex +00013198 rdtsc +0001319b rand +000131b7 general_protection_fault +00013247 interrupt_get_count +00013256 print_page_fault_info +00013333 page_fault_interrupt +000133c5 interrupt_install_handler +000133d7 load_data_segments +000133e3 isr_handler +000134d6 init_interrupts +0001364f idt_flush +00013657 isr0 +00013664 isr1 +00013671 isr2 +0001367e isr3 +0001368b isr4 +00013698 isr5 +000136a5 isr6 +000136b2 isr7 +000136bf isr8 +000136cc isr9 +000136d9 isr10 +000136e6 isr11 +000136f3 isr12 +00013700 isr13 +0001370d isr14 +0001371a isr15 +00013727 isr16 +00013734 isr17 +00013741 isr18 +0001374e isr19 +0001375b isr20 +00013768 isr21 +00013775 isr22 +00013782 isr23 +0001378f isr24 +0001379c isr25 +000137a9 isr26 +000137b6 isr27 +000137c3 isr28 +000137d0 isr29 +000137dd isr30 +000137ea isr31 +000137f7 isr32 +00013804 isr33 +00013811 isr34 +0001381e isr35 +00013828 isr36 +00013832 isr37 +0001383c isr38 +00013846 isr39 +00013850 isr40 +0001385a isr41 +00013864 isr42 +0001386e isr43 +00013878 isr44 +00013882 isr45 +0001388c isr46 +00013896 isr47 +000138a0 isr_entry +000138bb syscall_return_value +000138bf _syscall_entry +000138fc page_fault_save +00013900 page_fault_error +00013904 _page_fault_entry +00013936 timer_callback +0001396e timer_get_tick +00013974 time_get_difference +000139b7 init_pit +00013a1b gdt_set_segment +00013a64 init_gdt +00013b72 rc +00013d61 __ksymbol_rc +00013d7b __ksymbol_as +00013d95 __ksymbol_cc +00013daf as +00014171 cc +000141cd __cc +000144c1 vm_print +000146be eval +00014b58 vm_setup +00014b99 vm_init +00014bf4 vm_free +00014c23 vm_setup_stack +00014c7f lex_get_error +00014c8c next +00015197 match +000151e5 expression +000164e6 statement +000166ef function_parameter +000168b1 function_body +00016ac0 function_declaration +00016b49 enum_declaration +00016c5c global_declaration +00016e89 lex_init +00016f24 program +00016fc5 find_mp_floating_ptr +00017001 smp_parse +00017146 kb_get_char +00017192 kb_add_char +000171cd kb_callback +000173fa init_keyboard +00017471 pcb_await +0001749b __pcb_get_free +00017559 __add_systemcall_pcb_await +00017570 __pcb_free +000175bf __pcb_init_kernel_stack +00017620 __pcb_init_process +000176e5 init_pcbs +00017736 pcb_total_usage +0001775f pcb_get_info +00017853 pcb_kill +00017870 Genesis +00017872 idletask +0001788d pcb_get_by_pid +0001789e pcb_get_by_name +000178f7 pcb_dbg_print +00017971 pcb_cleanup_routine +00017b81 pcb_create_thread +00017c79 pcb_create_process +00017f0b pcb_create_kthread +000181e7 start_pcb +0001821f __pcb_queue_peek +0001825e __pcb_queue_pop +000182ba __pcb_queue_remove +0001832c __pcb_queue_add +000183a5 __pcb_queue_push +0001843e pcb_new_queue +0001846f get_mem_info +000184c7 memory_map_init +0001858e memory_map_get +00018594 free +000185eb malloc +00018687 calloc +000186ba krealloc +00018726 init_memory +000187b8 vmem_free +00018828 vmem_alloc +00018895 vmem_free_page_region +000189fb vmem_page_region_alloc +00018a36 vmem_create_page_region +00018b7a vmem_free_allocations +00018ca9 vmem_continious_allocation_map +00018caf vmem_free_allocation +00018cb0 vmem_stack_free +00018d61 vmem_stack_alloc +000190e6 vmem_dump_heap +0001917b vmem_init_process_thread +0001926c vmem_init_process +0001959a vmem_cleanup_process_thead +00019611 vmem_cleanup_process +000197ff vmem_init_kernel +000199c0 vmem_allocator_create +00019a24 vmem_map_driver_region +00019aa2 vmem_total_usage +00019ab5 vmem_init +00019be7 kalloc +00019d7e kcalloc +00019db0 kfree +00019e46 palloc +00019e88 pmemory_used +00019ea4 kmemory_used +00019eaa kmemory_total +00019eb6 kmem_init +00019f53 e1000_receive +0001a02e e1000_transmit +0001a0f0 e1000_callback +0001a117 _e1000_tx_init +0001a1bb _e1000_rx_init +0001a255 e1000_attach +0001a485 display_get_info +0001a4ee kenv_init +0001a505 kenv_set +0001a53a config_list +0001a60b kernel_config_load +0001a9f6 config_get_value +0001aab1 spin_lock +0001aad1 spin_unlock +0001aadf mutex_init +0001aafc acquire +0001ab99 release +0001ac3b kthread_entry +0001ac95 kthread_list +0001acfc register_kthread +0001add5 start +0001ae77 ata_primary +0001ae78 ata_secondary +0001ae79 ata_wait +0001aef3 ata_write +0001b06a ata_read +0001b1fa ata_ide_init +0001b3ca set_bitmap +0001b3ec unset_bitmap +0001b410 get_bitmap +0001b432 get_bitmap_size +0001b446 create_bitmap +0001b47a destroy_bitmap +0001b48d bitmap_unset_continous +0001b4c7 bitmap_get_continous +0001b563 get_free_bitmap +0001b5b8 __rtc_check_in_progress +0001b5da __rtc_get_register +0001b5fa get_current_time +0001b745 get_time +0001b76f init_tss +0001b79d __add_systemcall_sys_system +0001b7b4 exec_cmd +0001b8b8 sys_system +0001b8c8 __ksymbol_exec_cmd +0001b8e2 system_reboot +0001b916 align_to_pointer_size +0001b924 calculate_size_unit +0001b986 advanced_hash +0001b9ba kernel_panic +0001b9d8 kref_init +0001b9f2 kref_get +0001ba1a kref_put +0001ba42 csprintf +0001bc43 script_parse +0001bd18 login +0001c0b6 __login_create_virt_disk +0001c0e0 __register_kthread_login +0001c0fa help +0001c39b clear +0001c3bc __ksymbol_new +0001c3d6 __ksymbol_list +0001c3f0 __ksymbol_color +0001c40a __ksymbol_about +0001c424 __ksymbol_help +0001c43e __ksymbol_kevents +0001c458 __ksymbol_view +0001c472 __ksymbol_file +0001c48c __ksymbol_tcp +0001c4a6 __ksymbol_conf +0001c4c0 __ksymbol_clear +0001c4da __ksymbol_services +0001c4f4 __ksymbol_reboot +0001c50e kevents +0001c5e8 services +0001c816 new +0001c957 list +0001ca57 file +0001cc25 color +0001ccc6 about +0001cd03 view +0001cf18 tcp +0001d1f5 __tcp_reader +0001d316 conf +0001d5de reboot +0001d617 attach_disk_dev +0001d63b disk_attached +0001d643 disk_name +0001d64c disk_device_get +0001d652 disk_size +0001d66e write_block +0001d6ab write_block_offset +0001d6ee read_block +0001d72b read_block_offset +0001d795 sched_consume +0001d7d6 sched_add +0001d830 sched_prioritize +0001d8e5 sched_round_robin +0001dacb sched_exit +0001db84 sched_block +0001dca2 sched_default +0001dd7c sched_sleep +0001de22 sched_init_default +0001dea3 get_scheduler +0001dea9 kernel_sleep +0001dec4 kernel_yield +0001df07 kernel_exit +0001df39 block +0001df62 unblock +0001df63 work_queue_add +0001e04b init_worker +0001e063 worker_thread +0001e102 __ring_buffer_add +0001e1aa __ring_buffer_read +0001e2b4 rbuffer_new +0001e31d rbuffer_free +0001e33f error_get_string +0001e37b kclock +0001e85b __register_kthread_kclock +0001e875 tar_extract +0001eac5 __ksymbol_tar +0001eadf tar_list +0001ebe9 tar +0001ee72 rgb_to_vga +0001ee82 rgb_to_components +0001eea9 color_distance_squared +0001ef14 rgb_init_color_table +0001efa5 iface_loopback_write +0001f066 iface_loopback_interrupt +0001f07d iface_loopback_read +0001f120 net_init_loopback +0001f137 serial_put +0001f177 serial_write +0001f1b9 serial_printf +0001f359 init_serial +0001f41f inportb +0001f428 inportw +0001f432 inportl +0001f43b outportb +0001f449 outportw +0001f458 outportl +0001f465 sys_create_thread +0001f484 __add_systemcall_sys_create_thread +0001f48f add_system_call +0001f4cf system_call +0001f53a hashmap_put +0001f5a1 hashmap_get +0001f625 hashmap_add +0001f6af hashmap_free +0001f6b0 reset_vga_palette +0001f6f6 vga_set_palette +0001f7e1 b8to16 +0001f7f1 vesa_put_pixel +0001f81b vesa_put_box +0001f896 vesa_put_block +0001f911 vesa_put_char +0001f98c vesa_put_char16 +0001fa1f vesa_put_icon16 +0001fa98 vesa_write +0001fad7 vesa_write_str +0001fb05 vesa_fill +0001fb87 vesa_fillrect +0001fbf9 vesa_inner_box +0001fd01 vesa_printf +0001ff6e ksyms_init +00020195 ksyms_add_symbol +0002024e __ksymbol_backtrace +00020268 ksyms_list +000202ca ksyms_resolve_symbol +0002037d __backtrace_from +0002049a backtrace +000204ab ws_fullscreen +00020625 ws_remove +000206d5 ws_add +000207c0 ws_destroy +00020866 ws_draw +00020b13 ws_raw_wallpaper +00020bf9 ws_set_background_file +00020ed6 ws_init +00020fb9 ws_set_background +00021064 ws_new +000210f1 encode_run_length +0002116e decode_run_length +000211d9 __mouse_handler +000212f0 mouse_wait +00021338 mouse_write +0002137a mouse_get_event +000213bb mouse_init +000214a0 sys_ipc_open +000214ee __add_systemcall_sys_ipc_open +00021505 __add_systemcall_sys_ipc_close +0002151c __add_systemcall_sys_ipc_send +00021533 __add_systemcall_sys_ipc_receive +0002154a sys_ipc_close +00021593 sys_ipc_send +000215fa sys_ipc_receive +00021660 sysinf +000223b2 __register_kthread_sysinf +000223cc echo +00022407 res +00022448 ifconfig +00022455 __ksymbol_ifconfig +0002246f __ksymbol_ps +00022489 __ksymbol_tree +000224a3 __ksymbol_fat16 +000224bd __ksymbol_xxd +000224d7 __ksymbol_sh +000224f1 __ksymbol_ed +0002250b __ksymbol_exec +00022525 __ksymbol_ths +0002253f __ksymbol_dns +00022559 __ksymbol_th +00022573 __ksymbol_kill +0002258d __ksymbol_echo +000225a7 __ksymbol_fdisk +000225c1 __ksymbol_meminfo +000225db __ksymbol_res +000225f5 __ksymbol_bg +0002260f __ksymbol_exit +00022629 __ksymbol_socks +00022643 __ksymbol_reset +0002265d exit +00022691 ps +00022905 print_pcb_tree +00022a04 tree +00022a44 fat16 +00022a6c xxd +00022b61 sh +00022c61 ed +00022cae exec +00022e12 ths +00022e7e dns +00022ef2 th +00022f10 kill +00022f2e fdisk +000230c0 meminfo +0002329f bg +0002331e socks +000235c4 __register_kthread_shell +000235de __register_kthread_textshell +000235f8 shell_clear +0002363b reset_shell +000236ac reset +00023700 shell_put +000238e1 shell +00023b42 cleanup_function +00023b69 testfn +00023b9d draw_box +00023c84 __textshell_reset_box +00023d14 textshell +000240e0 __net_find_interface +00024140 net_drop_packet +00024161 net_handle_recieve +00024288 net_get_interfaces +0002428e net_configure_iface +000242e0 net_incoming_packet +00024391 net_get_iface +00024407 net_iface_up +0002442e net_iface_down +00024455 net_list_ifaces +0002456f net_register_interface +000245a0 net_send_skb +00024628 net_get_info +0002464f networking_main +0002482f __dhcp_add_option +0002489f __dhcp_send_discovery +000249e1 __dhcp_send_request +00024b5e dhcp_get_state +00024b66 dhcp_get_dns +00024b6c dhcp_get_ip +00024b81 dhcp_get_gw +00024b96 dhcpd +00024e15 udp_server +00024ea0 tcp_server +00025014 __net_terminal_writef +00025079 __register_kthread_tcp_server +00025093 __register_kthread_udp_server +000250ad __register_kthread_udptest +000250c7 udptest +00025152 tcpd +00025236 logd +000252a1 __register_kthread_logd +000252bb logd_attach_by_pid +000252ff taskbar_reboot +0002532b __reboot +00025340 taskbar_readme +00025359 taskbar_about +00025372 taskbar_clock +0002538b taskbar_sysinf +000253a4 taskbar_bg_retro +000253db taskbar_bg_lotr2 +000253f0 taskbar_bg_lotr +00025405 taskbar_bg_default_color_gray +00025417 taskbar_bg_default_color +00025429 taskbar_wolfstein +00025464 taskbar_bg_graph +0002549f taskbar_bg_calc +000254da taskbar_colors +00025515 taskbar_cube +00025550 taskbar_editor +0002558b taskbar_finder +000255c6 taskbar_terminal +0002560f __register_kthread_taskbar +00025629 taskbar_hdr_opt_event +000256b3 taskbar +00025c6a about +00025e35 __register_kthread_about +00025e4f __register_kthread_readme +00025e69 readme +00025fcb gfx_default_hover +000260ea gfx_destory_window +00026177 gfx_window_resize +00026220 gfx_window_maximize +00026299 gfx_default_mouse_up +00026367 gfx_default_mouse_down +00026429 gfx_default_click +00026618 gfx_draw_window +00027404 gfx_window_set_resizable +00027419 kernel_gfx_window_border_color +00027444 gfx_new_window +000276a4 gfx_point_in_rectangle +000276d1 gfx_draw_component +00027713 gfx_input_event +00027845 gfx_input_draw +0002794d gfx_input_manager_add +000279ae gfx_composition_remove_window +000279d8 gfx_composition_add_window +00027a1f gfx_set_background_color +00027a70 gfx_raw_background +00027abd gfx_decode_background_image +00027b0a gfx_set_taskbar +00027baa gfx_compositor_main +00027c1e kernel_gfx_draw_circle_helper +00027eca gfx_get_window_width +00027edf gfx_get_window_height +00027ef4 gfx_push_event +00027fb0 gfx_put_icon16 +000280a8 gfx_put_icon32 +000281a0 gfx_event_loop +000282bf kernel_gfx_draw_rectangle +000283b9 kernel_gfx_draw_contoured_box +00028459 kernel_gfx_draw_pixel +000284f7 kernel_gfx_draw_bitmap +00028615 kernel_gfx_draw_char +00028715 kernel_gfx_set_position +00028731 gfx_commit +0002874a kernel_gfx_draw_text +000287fd gfx_button_ext +00028930 gfx_button +0002894e kernel_gfx_set_title +000289ba kernel_gfx_set_header +00028a26 kernel_gfx_draw_line +00028bc1 kernel_gfx_draw_circle +00028c40 kernel_gfx_draw_section +00028c46 kernel_gfx_draw_format_text +00028f98 gfx_syscall_hook +0002914f gfx_total_themes +00029155 kernel_gfx_current_theme +0002915b kernel_gfx_update_theme +00029229 kernel_gfx_default_theme +0002922f kernel_gfx_set_theme +00029254 kernel_gfx_get_theme +0002926f gfx_new_ctx +000292cb gfx_init_framebuffer +00029437 netdev_attach_driver +000294e0 is_netdev_attached +000294ee netdev_transmit +00029509 netdev_recieve +00029532 net_ethernet_add_header +000295c6 net_ethernet_parse +0002963a __skb_queue_remove +00029678 __skb_queue_add +000296c8 skb_free_queue +00029700 skb_new_queue +00029767 skb_free +000297a2 skb_new +0002980d skb_consume +0002983e __net_arp_send +000298fe net_init_arp +0002994a net_arp_add_entry +000299d9 net_arp_find_entry +00029a24 net_arp_respond +00029a99 net_net_arp_request +00029b1f arp_parse +00029bc9 net_ipv4_print +00029bcf net_ipv4_add_header +00029d06 net_is_ipv4 +00029d43 net_ipv4_parse +00029e70 ntohl +00029e9c htonl +00029eaf ntohs +00029ebc htons +00029ec9 checksum +00029f20 transport_checksum +00029f75 ip_to_int +0002a013 net_icmp_handle +0002a0d8 net_icmp_response +0002a0de net_icmp_request +0002a1a1 ping +0002a1fa net_icmp_parse +0002a26a net_udp_send +0002a39f net_udp_parse +0002a4c7 socket_type_to_str +0002a4d6 socket_domain_to_str +0002a4e5 socket_protocol_to_str +0002a4f4 net_sock_bind +0002a53f net_get_sockets +0002a55b sock_get +0002a57c get_total_sockets +0002a582 net_sock_is_established +0002a5c6 net_sock_awaiting_ack +0002a60a net_sock_data_ready +0002a663 net_sock_read +0002a765 net_sock_add_data +0002a9c5 sock_find_listen_tcp +0002aa09 net_sock_find_tcp +0002abfb net_prepare_tcp_sock +0002ac87 net_sock_accept +0002ac9a net_socket_find_udp +0002ad05 kernel_sock_shutdown +0002ad32 kernel_sock_cleanup +0002adb8 kernel_sock_close +0002adec kernel_socket_create +0002af6f net_init_sockets +0002afb5 gethostname +0002b4cf __add_systemcall_gethostname +0002b4e6 net_init_dns +0002b515 route +0002b562 tcb_init +0002b580 tcb_new +0002b6ec tcp_state_to_str +0002b705 tcp_new_connection +0002b78d tcp_free_connection +0002b7b0 tcp_is_listening +0002b7c6 tcp_set_listening +0002b826 tcp_calculate_checksum +0002b8ea __tcp_send +0002ba06 tcp_send_segment +0002bb49 tcp_accept_connection +0002bc8b tcp_send_ack +0002bdc1 tcp_read +0002bdc7 tcp_recv_segment +0002bdcd tcp_connect +0002be70 tcp_send_syn +0002be76 tcp_recv_ack +0002bef9 tcp_recv_fin +0002beff tcp_recv_syn +0002c031 tcp_send_fin +0002c0fd tcp_close_connection +0002c13c tcp_parse +0002c5d5 kernel_bind +0002c60a kernel_recvfrom +0002c610 kernel_recv +0002c682 kernel_recv_timeout +0002c6a8 kernel_connect +0002c7ac kernel_sendto +0002c866 kernel_accept +0002c8c9 kernel_listen +0002c8f1 kernel_send +0002c977 sys_kernel_bind +0002c9a9 __add_systemcall_sys_kernel_bind +0002c9c0 __add_systemcall_sys_kernel_accept +0002c9d7 __add_systemcall_sys_kernel_connect +0002c9ee __add_systemcall_sys_kernel_listen +0002ca05 __add_systemcall_sys_kernel_recv +0002ca1c __add_systemcall_sys_kernel_recvfrom +0002ca33 __add_systemcall_sys_kernel_recv_timeout +0002ca4a __add_systemcall_sys_kernel_send +0002ca61 __add_systemcall_sys_kernel_sendto +0002ca78 __add_systemcall_sys_socket_create +0002ca8f __add_systemcall_sys_kernel_sock_close +0002caa6 sys_kernel_accept +0002cae6 sys_kernel_connect +0002cb18 sys_kernel_listen +0002cb47 sys_kernel_recv +0002cb7f sys_kernel_recvfrom +0002cbbf sys_kernel_recv_timeout +0002cbfd sys_kernel_send +0002cc35 sys_kernel_sendto +0002cc75 sys_socket_create +0002cc9c sys_kernel_sock_close +0002ccdd __iface_send +0002cd0c __iface_recieve +0002cd3b __iface_assign +0002cd4e __iface_detach +0002cd62 __iface_set_gateway +0002cd75 __iface_set_netmask +0002cd88 __iface_configure +0002cdd8 __iface_attach +0002cdfd net_interface_create +0002ce35 net_register_netdev +0002cf4d net_interface_destroy +0002cf62 __default_restart +0002cf68 __default_stop +0002cfcd __default_start +0002d047 nm_new +0002d0d0 nm_free +0002d115 net_firewall_create +0002d138 fs_file2fd +0002d19f fs_alloc_file +0002d1ea fs_free_file +0002d244 fs_register +0002d313 fs_init +0002d319 fs_unregister +0002d37c fs_get +0002d382 fs_close +0002d3f4 fs_open +0002d46e fs_seek +0002d4eb fs_read +0002d600 fs_load_from_file +0002d68c fs_write +0002d747 fs_save_to_file +0002d7d3 fat16_rmdir +0002d7d9 fat16_stat +0002d7df fat16_close +0002d849 fat16_rename +0002d8de fat16_mkdir +0002d9c3 fat16_remove +0002da36 fat16_open +0002db80 fat16_read +0002dce4 fat16_write +0002de13 fat16_list +0002e0e1 fat16_init +0002e195 path_next_iter +0002e204 inode_from_path_recursise +0002e282 inode_from_path +0002e340 ext_get_root +0002e349 ext_get_current_dir +0002e358 ext_get_size +0002e35e ext_get_inodes +0002e364 ext_get_blocks +0002e36a ext_sync +0002e3dd ext_create +0002e4c8 ext_read +0002e543 ext_seek +0002e58a ext_write +0002e5f6 ext_close +0002e658 ext_open_from_directory +0002e75e ext_open +0002e815 ext_size +0002e83e change_directory +0002e8a4 ext_create_directory +0002ea3e ext_create_file_system +0002ed0b init_ext +0002eea7 listdir +0002efc8 __inode_sync +0002f02b __inode_cache_insert +0002f121 __inode_load +0002f195 inodes_sync +0002f1d0 inode_get +0002f22d inode_read +0002f415 inode_write +0002f673 alloc_inode +0002f72c mkdir +0002f7d9 sync +0002f80d mkfs +0002f81a fat16_read_data_from_cluster +0002f868 fat16_read_data +0002f949 fat16_find_cluster_by_offset +0002f9c4 fat16_write_data_to_cluster_with_offset +0002f9ff fat16_print_cluster_chain +0002fa2d fat16_write_data_to_cluster +0002fa60 fat16_write_data +0002fb7c get_fat_start_block +0002fb84 get_root_directory_start_block +0002fb93 get_data_start_block +0002fba5 fat16_get_fat_entry +0002fbc0 fat16_set_fat_entry +0002fc00 fat16_sync_fat_table +0002fc78 fat16_allocate_cluster +0002fc90 fat16_free_cluster +0002fca5 fat16_get_free_cluster +0002fcfa fat16_sync_directory_entry +0002fd7c fat16_read_entry +0002fe29 fat16_find_entry +0002ff64 fat16_rename_entry +0002ffd5 fat16_free_clusters +0003001c fat16_delete_entry +00030083 fat16_add_entry +000301ea fat16_used_blocks +00030223 fat16_to_upper +0003024f fat16_name_compare +00030374 sstrtok +00030435 fat16_directory_entry_debug +00030505 fat16_get_directory_entry +000306fd fat16_create_directory +00030802 fat16_read_file +00030853 fat16_create_file +000308d1 fat16_create_empty_file +00030991 fat16_directory_entries +00030a77 fat16_mbr_clear +00030b20 fat16_mbr_add_entry +00030c11 fat16_print_root_directory_entries +00030c29 fat16_change_directory +00030cb1 fat16_bootblock_info +00030e2e fat16_set_time +00030e62 fat16_set_date +00030e9a fat16_load +00031019 fat16_format +000312ce mbr_partition_type_string +00031351 mbr_partitions_parse +0003141a mbr_get +00031420 mbr_partition_load +0003143e __list_users +000314cf __change_user +00031571 __remove_user +0003161d __add_user +00031707 __find_user +000317dc __authenticate_user +000318ea __save_users +0003196e __load_users +00031b70 __ksymbol_admin +00031b8a admin +00031e9e usermanager_create +00031ebd __ksymbol_snakegame +00031ed7 init_game +00031f25 draw +00031f81 get_input +00031fa0 update +00032127 game_loop +0003214d snakegame +00032198 __msgbox +00032598 msgbox_create +000325cb msgbox_show +00032613 kevents_list +00032785 kevents_init +000327c7 kevents_destroy +0003281c kevents_add +000328d3 kevents_create +00032956 __ksymbol_editor +00032970 textbuffer_new_line +00032a21 textbuffer_display +00032abd editor +0003307e _code_end From 4317ca01eb4eaf8f9650d0a3fdaf42e6e098118d Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Sun, 4 Feb 2024 17:01:34 +0100 Subject: [PATCH 11/23] edit loading and saving files --- kernel/edit.c | 100 +++++++++++++++++++++++++++++++++++++++------ rootfs/symbols.map | 10 +++-- 2 files changed, 94 insertions(+), 16 deletions(-) diff --git a/kernel/edit.c b/kernel/edit.c index 149267e..9f010ea 100644 --- a/kernel/edit.c +++ b/kernel/edit.c @@ -6,11 +6,17 @@ #include #include #include +#include #define MAX_LINES 512 #define LINE_CAPACITY 78 struct textbuffer { + struct textbuffer_ops { + int (*destroy)(struct textbuffer *buffer); + int (*display)(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg); + int (*put)(struct textbuffer *buffer, unsigned char c); + } *ops; struct line { char *text; size_t length; @@ -22,7 +28,20 @@ struct textbuffer { } cursor; size_t line_count; }; + +/* Function prototypes */ static int textbuffer_new_line(struct textbuffer *buffer); +static int textbuffer_remove_last_line(struct textbuffer *buffer); +static int textbuffer_free_line(struct textbuffer *buffer, size_t line); +static int textbuffer_destroy(struct textbuffer *buffer); +static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg); +static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c); + +static struct textbuffer_ops textbuffer_default_ops = { + .destroy = textbuffer_destroy, + .display = textbuffer_display, + .put = textbuffer_handle_char, +}; static struct textbuffer *textbuffer_create(void) { @@ -44,14 +63,15 @@ static struct textbuffer *textbuffer_create(void) kfree(buffer); return NULL; } - + + buffer->ops = &textbuffer_default_ops; buffer->cursor.x = 0; buffer->cursor.y = 0; return buffer; } -static void textbuffer_destroy(struct textbuffer *buffer) +static int textbuffer_destroy(struct textbuffer *buffer) { for (size_t i = 0; i < buffer->line_count; i++) { if (buffer->lines[i]->text) { @@ -61,6 +81,8 @@ static void textbuffer_destroy(struct textbuffer *buffer) } kfree(buffer->lines); kfree(buffer); + + return 0; } static int textbuffer_new_line(struct textbuffer *buffer) @@ -123,8 +145,51 @@ static int textbuffer_free_line(struct textbuffer *buffer, size_t line) return 0; } +static int textbuffer_save_file(struct textbuffer *buffer, const char *filename) +{ + byte_t *file = kalloc(1024); + if(file == NULL){ + return -1; + } + size_t len = 0; + for(size_t i = 0; i < buffer->line_count; i++){ + if(buffer->lines[i]->text){ + memcpy(file + len, buffer->lines[i]->text, buffer->lines[i]->length); + len += buffer->lines[i]->length; + } + } + int ret = fs_save_to_file(filename, file, len); + if(ret < 0){ + kfree(file); + return -1; + } + kfree(file); + return 0; +} + +static int textbuffer_load_file(struct textbuffer *buffer, const char *filename) +{ + byte_t *file = kalloc(1024); + if(file == NULL){ + return -1; + } + int ret = fs_load_from_file(filename, file, 1024); + if(ret < 0){ + kfree(file); + return -1; + } + size_t len = strlen(file); + for(size_t i = 0; i < len; i++){ + textbuffer_handle_char(buffer, file[i]); + } + + textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + + return 0; +} + /* Function to display the content of the text buffer on the screen */ -static void textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg) { +static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg) { uint8_t color = (bg << 4) | fg; uint32_t x_start = 0; uint32_t y_start = 0; @@ -138,9 +203,15 @@ static void textbuffer_display(const struct textbuffer *buffer, enum vga_color f int32_t y = y_start + i; /* Write the line to the screen */ - if (buffer->lines[i]->text) { + if(!buffer->lines[i]->text) { + continue; + } + if(buffer->cursor.y == i){ scrprintf(x, 1+y, "%d: %s (l: %d)", i, buffer->lines[i]->text, buffer->lines[i]->length); + } else { + scrprintf(x, 1+y, "%d: %s", i, buffer->lines[i]->text); } + } /* Set the cursor to the end of the text */ @@ -151,10 +222,12 @@ static void textbuffer_display(const struct textbuffer *buffer, enum vga_color f screen_set_cursor(buffer->cursor.x-1+3, 1+buffer->cursor.y); /* write stats at the bottom */ scrprintf(0, 24, "line_count: %d, x: %d, y: %d", buffer->line_count, buffer->cursor.x, buffer->cursor.y); + + return 0; } /* Function to handle keyboard input of a char */ -static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { +static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { int ret; /* Handle the backspace key */ @@ -163,7 +236,7 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { if (buffer->cursor.x == 0) { /* If the cursor is at the beginning of the first line, do nothing */ if (buffer->cursor.y == 0 ) { - return; + return -1; } /* Move the rest of the current line up if there is space. */ @@ -183,7 +256,7 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { if(buffer->lines[buffer->cursor.y] == NULL) { buffer->cursor.x = 0; dbgprintf("buffer->lines[buffer->cursor.y] == NULL %d, 0x%x\n", buffer->cursor.y, buffer->lines[buffer->cursor.y]); - return; + return -1; } /* If x is behind length, then we move content back */ @@ -194,7 +267,7 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { buffer->lines[buffer->cursor.y]->text[buffer->lines[buffer->cursor.y]->length - 1] = '\0'; buffer->lines[buffer->cursor.y]->length--; buffer->cursor.x--; - return; + return -1; } /* If x is at length, then we just remove the last character */ @@ -207,13 +280,13 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { if (buffer->cursor.x == buffer->lines[buffer->cursor.y]->length) { /* If the buffer is full, do nothing */ if (buffer->line_count == MAX_LINES) { - return; + return -1; } ret = textbuffer_new_line(buffer); if(ret < 0){ warningf("textbuffer_new_line failed\n"); - return; + return -1; } if(buffer->cursor.y != buffer->line_count - 1){ @@ -236,7 +309,7 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { ret = textbuffer_new_line(buffer); if(ret < 0){ warningf("textbuffer_new_line failed\n"); - return; + return -1; } /* Move down the content of all lines below current */ @@ -297,7 +370,7 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { } else { /* If the buffer is full, do nothing */ if (buffer->lines[buffer->cursor.y]->length == buffer->lines[buffer->cursor.y]->capacity) { - return; + return -1; } /* If x is behind length, then we move content forward */ @@ -313,6 +386,8 @@ static void textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { buffer->lines[buffer->cursor.y]->length++; buffer->cursor.x++; } + + return 0; } @@ -325,6 +400,7 @@ static __kthread_entry void editor() } textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + textbuffer_load_file(buffer, "/sysutil/default.cfg"); while (1){ c = kb_get_char(); if(c == 0) continue; diff --git a/rootfs/symbols.map b/rootfs/symbols.map index cf28cba..cc0886c 100644 --- a/rootfs/symbols.map +++ b/rootfs/symbols.map @@ -888,7 +888,9 @@ 0003281c kevents_add 000328d3 kevents_create 00032956 __ksymbol_editor -00032970 textbuffer_new_line -00032a21 textbuffer_display -00032abd editor -0003307e _code_end +00032970 textbuffer_destroy +000329e3 textbuffer_new_line +00032a99 textbuffer_handle_char +00032fda textbuffer_display +00033097 editor +000331eb _code_end From cb2aa01cabd0710722575e57b49a61b038e9e010 Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Sun, 4 Feb 2024 21:46:39 +0100 Subject: [PATCH 12/23] edit scrolling --- kernel/edit.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/kernel/edit.c b/kernel/edit.c index 9f010ea..9c9d38f 100644 --- a/kernel/edit.c +++ b/kernel/edit.c @@ -26,6 +26,10 @@ struct textbuffer { size_t x; size_t y; } cursor; + struct scroll { + size_t start; + size_t end; + } scroll; size_t line_count; }; @@ -67,6 +71,8 @@ static struct textbuffer *textbuffer_create(void) buffer->ops = &textbuffer_default_ops; buffer->cursor.x = 0; buffer->cursor.y = 0; + buffer->scroll.start = 0; + buffer->scroll.end = 0; return buffer; } @@ -155,7 +161,9 @@ static int textbuffer_save_file(struct textbuffer *buffer, const char *filename) for(size_t i = 0; i < buffer->line_count; i++){ if(buffer->lines[i]->text){ memcpy(file + len, buffer->lines[i]->text, buffer->lines[i]->length); - len += buffer->lines[i]->length; + /* Add a newline character after each line */ + file[len + buffer->lines[i]->length] = '\n'; + len += buffer->lines[i]->length + 1; } } int ret = fs_save_to_file(filename, file, len); @@ -192,24 +200,25 @@ static int textbuffer_load_file(struct textbuffer *buffer, const char *filename) static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg) { uint8_t color = (bg << 4) | fg; uint32_t x_start = 0; - uint32_t y_start = 0; + uint32_t y_start = buffer->scroll.start; /* Clear the screen before displaying new content */ scr_clear(); - - for (size_t i = 0; i < buffer->line_count; i++) { + + /* write from start to end, or line_count */ + for (size_t i = 0; i+y_start < buffer->line_count && i < 22; i++) { /* Calculate the position for each line */ int32_t x = x_start; int32_t y = y_start + i; /* Write the line to the screen */ - if(!buffer->lines[i]->text) { + if(!buffer->lines[y]->text) { continue; } - if(buffer->cursor.y == i){ - scrprintf(x, 1+y, "%d: %s (l: %d)", i, buffer->lines[i]->text, buffer->lines[i]->length); + if(buffer->cursor.y == y){ + scrprintf(x, 1+i, "%d: %s (l: %d)", y, buffer->lines[y]->text, buffer->lines[y]->length); } else { - scrprintf(x, 1+y, "%d: %s", i, buffer->lines[i]->text); + scrprintf(x, 1+i, "%d: %s", y, buffer->lines[y]->text); } } @@ -221,7 +230,7 @@ static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg screen_set_cursor(buffer->cursor.x-1+3, 1+buffer->cursor.y); /* write stats at the bottom */ - scrprintf(0, 24, "line_count: %d, x: %d, y: %d", buffer->line_count, buffer->cursor.x, buffer->cursor.y); + scrprintf(0, 24, "lc: %d, x: %d, y: %d, Save CTRL-S, Exit CTRL-C", buffer->line_count, buffer->cursor.x, buffer->cursor.y); return 0; } @@ -356,6 +365,9 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { if(buffer->cursor.x > buffer->lines[buffer->cursor.y]->length){ buffer->cursor.x = buffer->lines[buffer->cursor.y]->length; } + if (buffer->scroll.start > 0 && buffer->cursor.y < buffer->scroll.start) { + buffer->scroll.start--; + } } break; case ARROW_DOWN: @@ -364,6 +376,10 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { if(buffer->cursor.x > buffer->lines[buffer->cursor.y]->length){ buffer->cursor.x = buffer->lines[buffer->cursor.y]->length; } + + if (buffer->cursor.y >= 22 + buffer->scroll.start) { + buffer->scroll.start++; + } } break; } From 78813d45875cb27162154c58acdbe4217db56174 Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Mon, 5 Feb 2024 15:43:38 +0100 Subject: [PATCH 13/23] Cleanup on edit and added more symbols --- .gitignore | 1 + apps/libcore.a | Bin 20194 -> 0 bytes apps/libgraphic.a | Bin 15910 -> 0 bytes apps/libnet.a | Bin 2288 -> 0 bytes kernel/edit.c | 17 +- kernel/ksyms.c | 4 +- rootfs/symbols.map | 1766 ++++++++++++++++++++++---------------------- 7 files changed, 898 insertions(+), 890 deletions(-) delete mode 100644 apps/libcore.a delete mode 100644 apps/libgraphic.a delete mode 100644 apps/libnet.a diff --git a/.gitignore b/.gitignore index 380be04..2832767 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ boot.iso boot2.iso boot.img *.dat +*.a log.txt filesystemv2.img diff --git a/apps/libcore.a b/apps/libcore.a deleted file mode 100644 index 39a09ad6114eaccc2bac1010ad2a9ea4a104e6c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20194 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 diff --git a/apps/libnet.a b/apps/libnet.a deleted file mode 100644 index bc2a340f99b4a364929ddd4ea950b171cb8b941d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2288 zcmcIl!D|#}6n`6IUDLEg8#Oiow^BjdX55WIsDw5)tWl^UX%|6-?Cj)Ac9Y#1+4)Aa ziWQ{b61;opK|Fc$AMhZwMLc-(rUx&Aha770;6Ye_znSmLPAF^i;Dh)5-tYb1elzcV zGqYb!xJ|G6L*M?~TFa+s5~tT(t}s4sD$0E#(hq<9A@0?KP)Vic&xz}K>YNrY@O|ZJ zsnRLkuk(N;5S6p-;Vc;z(EelFlgHZc!Ly7oG*J~9guswC_ z<)G_y|BN~!hy+Ddj&7Ns3!7q`54 z({8t~{XOvTuS94^1MR4v($-k|fBuUu`N1`LZXa*6Eu9`(F7~&IE6c@!R`K8E;$W-z zYEf$cPJXly#k6o`3~YR#NsA07M<+sWnd=h;7c ze)?=<=^s=i+Jw=D()zC*{VehYcsKnrv}5nk|AgkkcfeP#|4V28dq`h^f0NedJNi@P zZ^OS$>kA$I4f2oPp^sn=uc3F_e**e$c(?t}LOTxc+CMY}-=4m|ndJVMN*l^ntyf;Q zR|x{Xjr`!ycvf4%2V#~ijCaAQ@m{EZ4YX%N&K~SpkRJed;ha7BA)uW#`H$dsw&X{_ z?JUVl;C6Q8r@`&4$ho(j4S5yZ&Vt;2uslh=iZ%ayu%u?gi=pS%>mTPM$vO4l+2$;W zQwGl%Y#QWqN&SJr{|xeZVSd`+tii}&j&(gElLpHMuNu5%@V>!k200G?E@yDkVApv*9rKX85GZzrf7Oh?!#zsAS=L4Br5x-L)GeG_GaH z^J4vab$Qfq3nGpCeV2ssN{#-#!8nQK36m+a^f+>iaWt_#1-WTOWY`Cd?^U|rqZ>Q@ vZh~g}P4C6uX*Pr;-))Ah<1@;=Y_AAKL(mM2*<08Gp02xt>z=YjKwI|~Lp-*` diff --git a/kernel/edit.c b/kernel/edit.c index 9c9d38f..e417c46 100644 --- a/kernel/edit.c +++ b/kernel/edit.c @@ -10,6 +10,12 @@ #define MAX_LINES 512 #define LINE_CAPACITY 78 +#define MAX_VISABLE_LINES 22 + +typdef enum __line_flags { + LINE_FLAG_NONE = 0 << 0, + LINE_FLAG_DIRTY = 1 << 0, +} line_flags_t; struct textbuffer { struct textbuffer_ops { @@ -20,7 +26,8 @@ struct textbuffer { struct line { char *text; size_t length; - size_t capacity; + size_t capacityi; + line_flags_t flags; } **lines; struct cursor { size_t x; @@ -72,7 +79,7 @@ static struct textbuffer *textbuffer_create(void) buffer->cursor.x = 0; buffer->cursor.y = 0; buffer->scroll.start = 0; - buffer->scroll.end = 0; + buffer->scroll.end = MAX_VISABLE_LINES; return buffer; } @@ -206,7 +213,7 @@ static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg scr_clear(); /* write from start to end, or line_count */ - for (size_t i = 0; i+y_start < buffer->line_count && i < 22; i++) { + for (size_t i = 0; i+y_start < buffer->line_count && i < buffer->scroll.end; i++) { /* Calculate the position for each line */ int32_t x = x_start; int32_t y = y_start + i; @@ -228,7 +235,7 @@ static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg screen_set_cursor(x_start, y_start + buffer->line_count - 1); } - screen_set_cursor(buffer->cursor.x-1+3, 1+buffer->cursor.y); + screen_set_cursor(buffer->cursor.x+2, 1+buffer->cursor.y); /* write stats at the bottom */ scrprintf(0, 24, "lc: %d, x: %d, y: %d, Save CTRL-S, Exit CTRL-C", buffer->line_count, buffer->cursor.x, buffer->cursor.y); @@ -377,7 +384,7 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { buffer->cursor.x = buffer->lines[buffer->cursor.y]->length; } - if (buffer->cursor.y >= 22 + buffer->scroll.start) { + if (buffer->cursor.y >= buffer->scroll.end + buffer->scroll.start) { buffer->scroll.start++; } } diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 5749aa9..fdfb4a0 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -21,7 +21,7 @@ #define KSYMS_MAX_DEPTH 100 #define KSYMS_MAX_SYMBOL_LENGTH 25 -#define MAX_SYMBOLS 800 +#define MAX_SYMBOLS 1000 /* kernel symbol table structure. */ static struct kernel_symbols { @@ -219,4 +219,4 @@ void backtrace() { uintptr_t *ebp = __builtin_frame_address(0); __backtrace_from(ebp); } -EXPORT_KSYMBOL(backtrace); \ No newline at end of file +EXPORT_KSYMBOL(backtrace); diff --git a/rootfs/symbols.map b/rootfs/symbols.map index cc0886c..7eebf90 100644 --- a/rootfs/symbols.map +++ b/rootfs/symbols.map @@ -11,886 +11,886 @@ 00010103 kernel 0001059d kernel_get_context 000105a3 hexdump -000107f4 __terminal_set_ops -000108bd __terminal_scanf -000108c3 __terminal_write -0001090d __terminal_getchar_graphics -00010956 __terminal_scan_graphics -00010a34 __terminal_reset -00010a78 __terminal_detach -00010abb __terminal_attach -00010b06 __terminal_remove_line -00010b46 __terminal_putchar_graphics -00010c0f __terminal_writef -00010f19 __terminal_getchar_textmode -00010f41 __terminal_scan_textmode -00011005 __terminal_commit_textmode -000110bd __terminal_putchar_textmode -00011109 scan -00011142 terminal_set_color -0001115a __terminal_commit_graphics -000112b6 terminal_attach -000112d7 terminal_commit -000112f6 terminal_putchar -00011332 terminal_create -00011457 terminal_destroy -00011490 tlb_flush_addr -00011498 load_page_directory -000114a8 enable_paging -000114ba pcb_save_context -000114e6 pcb_restore_context -0001150f _start_pcb -00011541 _start_pcb_skip -0001155c __ksymbol_lspci -00011576 pci_get_class_name -00011589 pci_get_device_name -000115fa pci_get_vendor_name -00011648 lspci -00011795 pci_get_devices -0001179b pci_read_word -000117f5 pci_write_dword -00011844 pci_enable_device_busmaster -00011899 pci_register_device -0001191a init_pci -00011acb pci_find_device -00011b61 virtual_read -00011b8c virtual_write -00011bb7 virtual_disk_attach -00011bd6 wm_default_changes -00011c7e wm_default_workspace -00011ce0 wm_default_draw -00011d7e wm_default_add -00011e25 init_windowmanager -00011f6f wm_default_mouse_event -00012195 wm_default_push_back -00012287 wm_default_push_front -00012376 wm_default_remove -00012487 wm_destroy -00012565 wm_new -000125cc screen_set_cursor -0001262c scrcolor_set -00012640 scrput -00012666 scrwrite -000126af scr_clear -00012701 scr_scroll -00012749 scrprintf -0001298d strlen -000129af strcpy -000129e3 strncmp -00012a1e strcmp -00012a5e memcmp -00012a99 parse_arguments -00012b7c strchr -00012bab getopt -00012cbb memcpy -00012d28 strtok -00012de0 xmemcpy -00012e67 memset -00012ee7 isdigit -00012efb isspace -00012f0a tolower -00012f1e isxdigit -00012f42 htoi -00012fe6 atoi -00013076 itoa -0001311c itohex -00013198 rdtsc -0001319b rand -000131b7 general_protection_fault -00013247 interrupt_get_count -00013256 print_page_fault_info -00013333 page_fault_interrupt -000133c5 interrupt_install_handler -000133d7 load_data_segments -000133e3 isr_handler -000134d6 init_interrupts -0001364f idt_flush -00013657 isr0 -00013664 isr1 -00013671 isr2 -0001367e isr3 -0001368b isr4 -00013698 isr5 -000136a5 isr6 -000136b2 isr7 -000136bf isr8 -000136cc isr9 -000136d9 isr10 -000136e6 isr11 -000136f3 isr12 -00013700 isr13 -0001370d isr14 -0001371a isr15 -00013727 isr16 -00013734 isr17 -00013741 isr18 -0001374e isr19 -0001375b isr20 -00013768 isr21 -00013775 isr22 -00013782 isr23 -0001378f isr24 -0001379c isr25 -000137a9 isr26 -000137b6 isr27 -000137c3 isr28 -000137d0 isr29 -000137dd isr30 -000137ea isr31 -000137f7 isr32 -00013804 isr33 -00013811 isr34 -0001381e isr35 -00013828 isr36 -00013832 isr37 -0001383c isr38 -00013846 isr39 -00013850 isr40 -0001385a isr41 -00013864 isr42 -0001386e isr43 -00013878 isr44 -00013882 isr45 -0001388c isr46 -00013896 isr47 -000138a0 isr_entry -000138bb syscall_return_value -000138bf _syscall_entry -000138fc page_fault_save -00013900 page_fault_error -00013904 _page_fault_entry -00013936 timer_callback -0001396e timer_get_tick -00013974 time_get_difference -000139b7 init_pit -00013a1b gdt_set_segment -00013a64 init_gdt -00013b72 rc -00013d61 __ksymbol_rc -00013d7b __ksymbol_as -00013d95 __ksymbol_cc -00013daf as -00014171 cc -000141cd __cc -000144c1 vm_print -000146be eval -00014b58 vm_setup -00014b99 vm_init -00014bf4 vm_free -00014c23 vm_setup_stack -00014c7f lex_get_error -00014c8c next -00015197 match -000151e5 expression -000164e6 statement -000166ef function_parameter -000168b1 function_body -00016ac0 function_declaration -00016b49 enum_declaration -00016c5c global_declaration -00016e89 lex_init -00016f24 program -00016fc5 find_mp_floating_ptr -00017001 smp_parse -00017146 kb_get_char -00017192 kb_add_char -000171cd kb_callback -000173fa init_keyboard -00017471 pcb_await -0001749b __pcb_get_free -00017559 __add_systemcall_pcb_await -00017570 __pcb_free -000175bf __pcb_init_kernel_stack -00017620 __pcb_init_process -000176e5 init_pcbs -00017736 pcb_total_usage -0001775f pcb_get_info -00017853 pcb_kill -00017870 Genesis -00017872 idletask -0001788d pcb_get_by_pid -0001789e pcb_get_by_name -000178f7 pcb_dbg_print -00017971 pcb_cleanup_routine -00017b81 pcb_create_thread -00017c79 pcb_create_process -00017f0b pcb_create_kthread -000181e7 start_pcb -0001821f __pcb_queue_peek -0001825e __pcb_queue_pop -000182ba __pcb_queue_remove -0001832c __pcb_queue_add -000183a5 __pcb_queue_push -0001843e pcb_new_queue -0001846f get_mem_info -000184c7 memory_map_init -0001858e memory_map_get -00018594 free -000185eb malloc -00018687 calloc -000186ba krealloc -00018726 init_memory -000187b8 vmem_free -00018828 vmem_alloc -00018895 vmem_free_page_region -000189fb vmem_page_region_alloc -00018a36 vmem_create_page_region -00018b7a vmem_free_allocations -00018ca9 vmem_continious_allocation_map -00018caf vmem_free_allocation -00018cb0 vmem_stack_free -00018d61 vmem_stack_alloc -000190e6 vmem_dump_heap -0001917b vmem_init_process_thread -0001926c vmem_init_process -0001959a vmem_cleanup_process_thead -00019611 vmem_cleanup_process -000197ff vmem_init_kernel -000199c0 vmem_allocator_create -00019a24 vmem_map_driver_region -00019aa2 vmem_total_usage -00019ab5 vmem_init -00019be7 kalloc -00019d7e kcalloc -00019db0 kfree -00019e46 palloc -00019e88 pmemory_used -00019ea4 kmemory_used -00019eaa kmemory_total -00019eb6 kmem_init -00019f53 e1000_receive -0001a02e e1000_transmit -0001a0f0 e1000_callback -0001a117 _e1000_tx_init -0001a1bb _e1000_rx_init -0001a255 e1000_attach -0001a485 display_get_info -0001a4ee kenv_init -0001a505 kenv_set -0001a53a config_list -0001a60b kernel_config_load -0001a9f6 config_get_value -0001aab1 spin_lock -0001aad1 spin_unlock -0001aadf mutex_init -0001aafc acquire -0001ab99 release -0001ac3b kthread_entry -0001ac95 kthread_list -0001acfc register_kthread -0001add5 start -0001ae77 ata_primary -0001ae78 ata_secondary -0001ae79 ata_wait -0001aef3 ata_write -0001b06a ata_read -0001b1fa ata_ide_init -0001b3ca set_bitmap -0001b3ec unset_bitmap -0001b410 get_bitmap -0001b432 get_bitmap_size -0001b446 create_bitmap -0001b47a destroy_bitmap -0001b48d bitmap_unset_continous -0001b4c7 bitmap_get_continous -0001b563 get_free_bitmap -0001b5b8 __rtc_check_in_progress -0001b5da __rtc_get_register -0001b5fa get_current_time -0001b745 get_time -0001b76f init_tss -0001b79d __add_systemcall_sys_system -0001b7b4 exec_cmd -0001b8b8 sys_system -0001b8c8 __ksymbol_exec_cmd -0001b8e2 system_reboot -0001b916 align_to_pointer_size -0001b924 calculate_size_unit -0001b986 advanced_hash -0001b9ba kernel_panic -0001b9d8 kref_init -0001b9f2 kref_get -0001ba1a kref_put -0001ba42 csprintf -0001bc43 script_parse -0001bd18 login -0001c0b6 __login_create_virt_disk -0001c0e0 __register_kthread_login -0001c0fa help -0001c39b clear -0001c3bc __ksymbol_new -0001c3d6 __ksymbol_list -0001c3f0 __ksymbol_color -0001c40a __ksymbol_about -0001c424 __ksymbol_help -0001c43e __ksymbol_kevents -0001c458 __ksymbol_view -0001c472 __ksymbol_file -0001c48c __ksymbol_tcp -0001c4a6 __ksymbol_conf -0001c4c0 __ksymbol_clear -0001c4da __ksymbol_services -0001c4f4 __ksymbol_reboot -0001c50e kevents -0001c5e8 services -0001c816 new -0001c957 list -0001ca57 file -0001cc25 color -0001ccc6 about -0001cd03 view -0001cf18 tcp -0001d1f5 __tcp_reader -0001d316 conf -0001d5de reboot -0001d617 attach_disk_dev -0001d63b disk_attached -0001d643 disk_name -0001d64c disk_device_get -0001d652 disk_size -0001d66e write_block -0001d6ab write_block_offset -0001d6ee read_block -0001d72b read_block_offset -0001d795 sched_consume -0001d7d6 sched_add -0001d830 sched_prioritize -0001d8e5 sched_round_robin -0001dacb sched_exit -0001db84 sched_block -0001dca2 sched_default -0001dd7c sched_sleep -0001de22 sched_init_default -0001dea3 get_scheduler -0001dea9 kernel_sleep -0001dec4 kernel_yield -0001df07 kernel_exit -0001df39 block -0001df62 unblock -0001df63 work_queue_add -0001e04b init_worker -0001e063 worker_thread -0001e102 __ring_buffer_add -0001e1aa __ring_buffer_read -0001e2b4 rbuffer_new -0001e31d rbuffer_free -0001e33f error_get_string -0001e37b kclock -0001e85b __register_kthread_kclock -0001e875 tar_extract -0001eac5 __ksymbol_tar -0001eadf tar_list -0001ebe9 tar -0001ee72 rgb_to_vga -0001ee82 rgb_to_components -0001eea9 color_distance_squared -0001ef14 rgb_init_color_table -0001efa5 iface_loopback_write -0001f066 iface_loopback_interrupt -0001f07d iface_loopback_read -0001f120 net_init_loopback -0001f137 serial_put -0001f177 serial_write -0001f1b9 serial_printf -0001f359 init_serial -0001f41f inportb -0001f428 inportw -0001f432 inportl -0001f43b outportb -0001f449 outportw -0001f458 outportl -0001f465 sys_create_thread -0001f484 __add_systemcall_sys_create_thread -0001f48f add_system_call -0001f4cf system_call -0001f53a hashmap_put -0001f5a1 hashmap_get -0001f625 hashmap_add -0001f6af hashmap_free -0001f6b0 reset_vga_palette -0001f6f6 vga_set_palette -0001f7e1 b8to16 -0001f7f1 vesa_put_pixel -0001f81b vesa_put_box -0001f896 vesa_put_block -0001f911 vesa_put_char -0001f98c vesa_put_char16 -0001fa1f vesa_put_icon16 -0001fa98 vesa_write -0001fad7 vesa_write_str -0001fb05 vesa_fill -0001fb87 vesa_fillrect -0001fbf9 vesa_inner_box -0001fd01 vesa_printf -0001ff6e ksyms_init -00020195 ksyms_add_symbol -0002024e __ksymbol_backtrace -00020268 ksyms_list -000202ca ksyms_resolve_symbol -0002037d __backtrace_from -0002049a backtrace -000204ab ws_fullscreen -00020625 ws_remove -000206d5 ws_add -000207c0 ws_destroy -00020866 ws_draw -00020b13 ws_raw_wallpaper -00020bf9 ws_set_background_file -00020ed6 ws_init -00020fb9 ws_set_background -00021064 ws_new -000210f1 encode_run_length -0002116e decode_run_length -000211d9 __mouse_handler -000212f0 mouse_wait -00021338 mouse_write -0002137a mouse_get_event -000213bb mouse_init -000214a0 sys_ipc_open -000214ee __add_systemcall_sys_ipc_open -00021505 __add_systemcall_sys_ipc_close -0002151c __add_systemcall_sys_ipc_send -00021533 __add_systemcall_sys_ipc_receive -0002154a sys_ipc_close -00021593 sys_ipc_send -000215fa sys_ipc_receive -00021660 sysinf -000223b2 __register_kthread_sysinf -000223cc echo -00022407 res -00022448 ifconfig -00022455 __ksymbol_ifconfig -0002246f __ksymbol_ps -00022489 __ksymbol_tree -000224a3 __ksymbol_fat16 -000224bd __ksymbol_xxd -000224d7 __ksymbol_sh -000224f1 __ksymbol_ed -0002250b __ksymbol_exec -00022525 __ksymbol_ths -0002253f __ksymbol_dns -00022559 __ksymbol_th -00022573 __ksymbol_kill -0002258d __ksymbol_echo -000225a7 __ksymbol_fdisk -000225c1 __ksymbol_meminfo -000225db __ksymbol_res -000225f5 __ksymbol_bg -0002260f __ksymbol_exit -00022629 __ksymbol_socks -00022643 __ksymbol_reset -0002265d exit -00022691 ps -00022905 print_pcb_tree -00022a04 tree -00022a44 fat16 -00022a6c xxd -00022b61 sh -00022c61 ed -00022cae exec -00022e12 ths -00022e7e dns -00022ef2 th -00022f10 kill -00022f2e fdisk -000230c0 meminfo -0002329f bg -0002331e socks -000235c4 __register_kthread_shell -000235de __register_kthread_textshell -000235f8 shell_clear -0002363b reset_shell -000236ac reset -00023700 shell_put -000238e1 shell -00023b42 cleanup_function -00023b69 testfn -00023b9d draw_box -00023c84 __textshell_reset_box -00023d14 textshell -000240e0 __net_find_interface -00024140 net_drop_packet -00024161 net_handle_recieve -00024288 net_get_interfaces -0002428e net_configure_iface -000242e0 net_incoming_packet -00024391 net_get_iface -00024407 net_iface_up -0002442e net_iface_down -00024455 net_list_ifaces -0002456f net_register_interface -000245a0 net_send_skb -00024628 net_get_info -0002464f networking_main -0002482f __dhcp_add_option -0002489f __dhcp_send_discovery -000249e1 __dhcp_send_request -00024b5e dhcp_get_state -00024b66 dhcp_get_dns -00024b6c dhcp_get_ip -00024b81 dhcp_get_gw -00024b96 dhcpd -00024e15 udp_server -00024ea0 tcp_server -00025014 __net_terminal_writef -00025079 __register_kthread_tcp_server -00025093 __register_kthread_udp_server -000250ad __register_kthread_udptest -000250c7 udptest -00025152 tcpd -00025236 logd -000252a1 __register_kthread_logd -000252bb logd_attach_by_pid -000252ff taskbar_reboot -0002532b __reboot -00025340 taskbar_readme -00025359 taskbar_about -00025372 taskbar_clock -0002538b taskbar_sysinf -000253a4 taskbar_bg_retro -000253db taskbar_bg_lotr2 -000253f0 taskbar_bg_lotr -00025405 taskbar_bg_default_color_gray -00025417 taskbar_bg_default_color -00025429 taskbar_wolfstein -00025464 taskbar_bg_graph -0002549f taskbar_bg_calc -000254da taskbar_colors -00025515 taskbar_cube -00025550 taskbar_editor -0002558b taskbar_finder -000255c6 taskbar_terminal -0002560f __register_kthread_taskbar -00025629 taskbar_hdr_opt_event -000256b3 taskbar -00025c6a about -00025e35 __register_kthread_about -00025e4f __register_kthread_readme -00025e69 readme -00025fcb gfx_default_hover -000260ea gfx_destory_window -00026177 gfx_window_resize -00026220 gfx_window_maximize -00026299 gfx_default_mouse_up -00026367 gfx_default_mouse_down -00026429 gfx_default_click -00026618 gfx_draw_window -00027404 gfx_window_set_resizable -00027419 kernel_gfx_window_border_color -00027444 gfx_new_window -000276a4 gfx_point_in_rectangle -000276d1 gfx_draw_component -00027713 gfx_input_event -00027845 gfx_input_draw -0002794d gfx_input_manager_add -000279ae gfx_composition_remove_window -000279d8 gfx_composition_add_window -00027a1f gfx_set_background_color -00027a70 gfx_raw_background -00027abd gfx_decode_background_image -00027b0a gfx_set_taskbar -00027baa gfx_compositor_main -00027c1e kernel_gfx_draw_circle_helper -00027eca gfx_get_window_width -00027edf gfx_get_window_height -00027ef4 gfx_push_event -00027fb0 gfx_put_icon16 -000280a8 gfx_put_icon32 -000281a0 gfx_event_loop -000282bf kernel_gfx_draw_rectangle -000283b9 kernel_gfx_draw_contoured_box -00028459 kernel_gfx_draw_pixel -000284f7 kernel_gfx_draw_bitmap -00028615 kernel_gfx_draw_char -00028715 kernel_gfx_set_position -00028731 gfx_commit -0002874a kernel_gfx_draw_text -000287fd gfx_button_ext -00028930 gfx_button -0002894e kernel_gfx_set_title -000289ba kernel_gfx_set_header -00028a26 kernel_gfx_draw_line -00028bc1 kernel_gfx_draw_circle -00028c40 kernel_gfx_draw_section -00028c46 kernel_gfx_draw_format_text -00028f98 gfx_syscall_hook -0002914f gfx_total_themes -00029155 kernel_gfx_current_theme -0002915b kernel_gfx_update_theme -00029229 kernel_gfx_default_theme -0002922f kernel_gfx_set_theme -00029254 kernel_gfx_get_theme -0002926f gfx_new_ctx -000292cb gfx_init_framebuffer -00029437 netdev_attach_driver -000294e0 is_netdev_attached -000294ee netdev_transmit -00029509 netdev_recieve -00029532 net_ethernet_add_header -000295c6 net_ethernet_parse -0002963a __skb_queue_remove -00029678 __skb_queue_add -000296c8 skb_free_queue -00029700 skb_new_queue -00029767 skb_free -000297a2 skb_new -0002980d skb_consume -0002983e __net_arp_send -000298fe net_init_arp -0002994a net_arp_add_entry -000299d9 net_arp_find_entry -00029a24 net_arp_respond -00029a99 net_net_arp_request -00029b1f arp_parse -00029bc9 net_ipv4_print -00029bcf net_ipv4_add_header -00029d06 net_is_ipv4 -00029d43 net_ipv4_parse -00029e70 ntohl -00029e9c htonl -00029eaf ntohs -00029ebc htons -00029ec9 checksum -00029f20 transport_checksum -00029f75 ip_to_int -0002a013 net_icmp_handle -0002a0d8 net_icmp_response -0002a0de net_icmp_request -0002a1a1 ping -0002a1fa net_icmp_parse -0002a26a net_udp_send -0002a39f net_udp_parse -0002a4c7 socket_type_to_str -0002a4d6 socket_domain_to_str -0002a4e5 socket_protocol_to_str -0002a4f4 net_sock_bind -0002a53f net_get_sockets -0002a55b sock_get -0002a57c get_total_sockets -0002a582 net_sock_is_established -0002a5c6 net_sock_awaiting_ack -0002a60a net_sock_data_ready -0002a663 net_sock_read -0002a765 net_sock_add_data -0002a9c5 sock_find_listen_tcp -0002aa09 net_sock_find_tcp -0002abfb net_prepare_tcp_sock -0002ac87 net_sock_accept -0002ac9a net_socket_find_udp -0002ad05 kernel_sock_shutdown -0002ad32 kernel_sock_cleanup -0002adb8 kernel_sock_close -0002adec kernel_socket_create -0002af6f net_init_sockets -0002afb5 gethostname -0002b4cf __add_systemcall_gethostname -0002b4e6 net_init_dns -0002b515 route -0002b562 tcb_init -0002b580 tcb_new -0002b6ec tcp_state_to_str -0002b705 tcp_new_connection -0002b78d tcp_free_connection -0002b7b0 tcp_is_listening -0002b7c6 tcp_set_listening -0002b826 tcp_calculate_checksum -0002b8ea __tcp_send -0002ba06 tcp_send_segment -0002bb49 tcp_accept_connection -0002bc8b tcp_send_ack -0002bdc1 tcp_read -0002bdc7 tcp_recv_segment -0002bdcd tcp_connect -0002be70 tcp_send_syn -0002be76 tcp_recv_ack -0002bef9 tcp_recv_fin -0002beff tcp_recv_syn -0002c031 tcp_send_fin -0002c0fd tcp_close_connection -0002c13c tcp_parse -0002c5d5 kernel_bind -0002c60a kernel_recvfrom -0002c610 kernel_recv -0002c682 kernel_recv_timeout -0002c6a8 kernel_connect -0002c7ac kernel_sendto -0002c866 kernel_accept -0002c8c9 kernel_listen -0002c8f1 kernel_send -0002c977 sys_kernel_bind -0002c9a9 __add_systemcall_sys_kernel_bind -0002c9c0 __add_systemcall_sys_kernel_accept -0002c9d7 __add_systemcall_sys_kernel_connect -0002c9ee __add_systemcall_sys_kernel_listen -0002ca05 __add_systemcall_sys_kernel_recv -0002ca1c __add_systemcall_sys_kernel_recvfrom -0002ca33 __add_systemcall_sys_kernel_recv_timeout -0002ca4a __add_systemcall_sys_kernel_send -0002ca61 __add_systemcall_sys_kernel_sendto -0002ca78 __add_systemcall_sys_socket_create -0002ca8f __add_systemcall_sys_kernel_sock_close -0002caa6 sys_kernel_accept -0002cae6 sys_kernel_connect -0002cb18 sys_kernel_listen -0002cb47 sys_kernel_recv -0002cb7f sys_kernel_recvfrom -0002cbbf sys_kernel_recv_timeout -0002cbfd sys_kernel_send -0002cc35 sys_kernel_sendto -0002cc75 sys_socket_create -0002cc9c sys_kernel_sock_close -0002ccdd __iface_send -0002cd0c __iface_recieve -0002cd3b __iface_assign -0002cd4e __iface_detach -0002cd62 __iface_set_gateway -0002cd75 __iface_set_netmask -0002cd88 __iface_configure -0002cdd8 __iface_attach -0002cdfd net_interface_create -0002ce35 net_register_netdev -0002cf4d net_interface_destroy -0002cf62 __default_restart -0002cf68 __default_stop -0002cfcd __default_start -0002d047 nm_new -0002d0d0 nm_free -0002d115 net_firewall_create -0002d138 fs_file2fd -0002d19f fs_alloc_file -0002d1ea fs_free_file -0002d244 fs_register -0002d313 fs_init -0002d319 fs_unregister -0002d37c fs_get -0002d382 fs_close -0002d3f4 fs_open -0002d46e fs_seek -0002d4eb fs_read -0002d600 fs_load_from_file -0002d68c fs_write -0002d747 fs_save_to_file -0002d7d3 fat16_rmdir -0002d7d9 fat16_stat -0002d7df fat16_close -0002d849 fat16_rename -0002d8de fat16_mkdir -0002d9c3 fat16_remove -0002da36 fat16_open -0002db80 fat16_read -0002dce4 fat16_write -0002de13 fat16_list -0002e0e1 fat16_init -0002e195 path_next_iter -0002e204 inode_from_path_recursise -0002e282 inode_from_path -0002e340 ext_get_root -0002e349 ext_get_current_dir -0002e358 ext_get_size -0002e35e ext_get_inodes -0002e364 ext_get_blocks -0002e36a ext_sync -0002e3dd ext_create -0002e4c8 ext_read -0002e543 ext_seek -0002e58a ext_write -0002e5f6 ext_close -0002e658 ext_open_from_directory -0002e75e ext_open -0002e815 ext_size -0002e83e change_directory -0002e8a4 ext_create_directory -0002ea3e ext_create_file_system -0002ed0b init_ext -0002eea7 listdir -0002efc8 __inode_sync -0002f02b __inode_cache_insert -0002f121 __inode_load -0002f195 inodes_sync -0002f1d0 inode_get -0002f22d inode_read -0002f415 inode_write -0002f673 alloc_inode -0002f72c mkdir -0002f7d9 sync -0002f80d mkfs -0002f81a fat16_read_data_from_cluster -0002f868 fat16_read_data -0002f949 fat16_find_cluster_by_offset -0002f9c4 fat16_write_data_to_cluster_with_offset -0002f9ff fat16_print_cluster_chain -0002fa2d fat16_write_data_to_cluster -0002fa60 fat16_write_data -0002fb7c get_fat_start_block -0002fb84 get_root_directory_start_block -0002fb93 get_data_start_block -0002fba5 fat16_get_fat_entry -0002fbc0 fat16_set_fat_entry -0002fc00 fat16_sync_fat_table -0002fc78 fat16_allocate_cluster -0002fc90 fat16_free_cluster -0002fca5 fat16_get_free_cluster -0002fcfa fat16_sync_directory_entry -0002fd7c fat16_read_entry -0002fe29 fat16_find_entry -0002ff64 fat16_rename_entry -0002ffd5 fat16_free_clusters -0003001c fat16_delete_entry -00030083 fat16_add_entry -000301ea fat16_used_blocks -00030223 fat16_to_upper -0003024f fat16_name_compare -00030374 sstrtok -00030435 fat16_directory_entry_debug -00030505 fat16_get_directory_entry -000306fd fat16_create_directory -00030802 fat16_read_file -00030853 fat16_create_file -000308d1 fat16_create_empty_file -00030991 fat16_directory_entries -00030a77 fat16_mbr_clear -00030b20 fat16_mbr_add_entry -00030c11 fat16_print_root_directory_entries -00030c29 fat16_change_directory -00030cb1 fat16_bootblock_info -00030e2e fat16_set_time -00030e62 fat16_set_date -00030e9a fat16_load -00031019 fat16_format -000312ce mbr_partition_type_string -00031351 mbr_partitions_parse -0003141a mbr_get -00031420 mbr_partition_load -0003143e __list_users -000314cf __change_user -00031571 __remove_user -0003161d __add_user -00031707 __find_user -000317dc __authenticate_user -000318ea __save_users -0003196e __load_users -00031b70 __ksymbol_admin -00031b8a admin -00031e9e usermanager_create -00031ebd __ksymbol_snakegame -00031ed7 init_game -00031f25 draw -00031f81 get_input -00031fa0 update -00032127 game_loop -0003214d snakegame -00032198 __msgbox -00032598 msgbox_create -000325cb msgbox_show -00032613 kevents_list -00032785 kevents_init -000327c7 kevents_destroy -0003281c kevents_add -000328d3 kevents_create -00032956 __ksymbol_editor -00032970 textbuffer_destroy -000329e3 textbuffer_new_line -00032a99 textbuffer_handle_char -00032fda textbuffer_display -00033097 editor -000331eb _code_end +000107f1 __terminal_set_ops +000108ba __terminal_scanf +000108c0 __terminal_write +0001090a __terminal_getchar_graphics +00010953 __terminal_scan_graphics +00010a31 __terminal_reset +00010a75 __terminal_detach +00010ab8 __terminal_attach +00010b03 __terminal_remove_line +00010b43 __terminal_putchar_graphics +00010c0c __terminal_writef +00010f16 __terminal_getchar_textmode +00010f3e __terminal_scan_textmode +00011002 __terminal_commit_textmode +000110ba __terminal_putchar_textmode +00011106 scan +0001113f terminal_set_color +00011157 __terminal_commit_graphics +000112b3 terminal_attach +000112d4 terminal_commit +000112f3 terminal_putchar +0001132f terminal_create +00011454 terminal_destroy +0001148c tlb_flush_addr +00011494 load_page_directory +000114a4 enable_paging +000114b6 pcb_save_context +000114e2 pcb_restore_context +0001150b _start_pcb +0001153d _start_pcb_skip +00011558 __ksymbol_lspci +00011572 pci_get_class_name +00011585 pci_get_device_name +000115f6 pci_get_vendor_name +00011644 lspci +00011791 pci_get_devices +00011797 pci_read_word +000117f1 pci_write_dword +00011840 pci_enable_device_busmaster +00011895 pci_register_device +00011916 init_pci +00011ac7 pci_find_device +00011b5d virtual_read +00011b88 virtual_write +00011bb3 virtual_disk_attach +00011bd2 wm_default_changes +00011c7a wm_default_workspace +00011cdc wm_default_draw +00011d7a wm_default_add +00011e21 init_windowmanager +00011f6b wm_default_mouse_event +00012191 wm_default_push_back +00012283 wm_default_push_front +00012372 wm_default_remove +00012483 wm_destroy +00012561 wm_new +000125c8 screen_set_cursor +00012628 scrcolor_set +0001263c scrput +00012662 scrwrite +000126ab scr_clear +000126fd scr_scroll +00012745 scrprintf +00012989 strlen +000129ab strcpy +000129df strncmp +00012a1a strcmp +00012a5a memcmp +00012a95 parse_arguments +00012b78 strchr +00012ba7 getopt +00012cb7 memcpy +00012d24 strtok +00012ddc xmemcpy +00012e63 memset +00012ee3 isdigit +00012ef7 isspace +00012f06 tolower +00012f1a isxdigit +00012f3e htoi +00012fe2 atoi +00013072 itoa +00013118 itohex +00013194 rdtsc +00013197 rand +000131b3 general_protection_fault +00013243 interrupt_get_count +00013252 print_page_fault_info +0001332f page_fault_interrupt +000133c1 interrupt_install_handler +000133d3 load_data_segments +000133df isr_handler +000134d2 init_interrupts +0001364b idt_flush +00013653 isr0 +00013660 isr1 +0001366d isr2 +0001367a isr3 +00013687 isr4 +00013694 isr5 +000136a1 isr6 +000136ae isr7 +000136bb isr8 +000136c8 isr9 +000136d5 isr10 +000136e2 isr11 +000136ef isr12 +000136fc isr13 +00013709 isr14 +00013716 isr15 +00013723 isr16 +00013730 isr17 +0001373d isr18 +0001374a isr19 +00013757 isr20 +00013764 isr21 +00013771 isr22 +0001377e isr23 +0001378b isr24 +00013798 isr25 +000137a5 isr26 +000137b2 isr27 +000137bf isr28 +000137cc isr29 +000137d9 isr30 +000137e6 isr31 +000137f3 isr32 +00013800 isr33 +0001380d isr34 +0001381a isr35 +00013824 isr36 +0001382e isr37 +00013838 isr38 +00013842 isr39 +0001384c isr40 +00013856 isr41 +00013860 isr42 +0001386a isr43 +00013874 isr44 +0001387e isr45 +00013888 isr46 +00013892 isr47 +0001389c isr_entry +000138b7 syscall_return_value +000138bb _syscall_entry +000138f8 page_fault_save +000138fc page_fault_error +00013900 _page_fault_entry +00013932 timer_callback +0001396a timer_get_tick +00013970 time_get_difference +000139b3 init_pit +00013a17 gdt_set_segment +00013a60 init_gdt +00013b6e rc +00013d5d __ksymbol_rc +00013d77 __ksymbol_as +00013d91 __ksymbol_cc +00013dab as +0001416d cc +000141c9 __cc +000144bd vm_print +000146ba eval +00014b54 vm_setup +00014b95 vm_init +00014bf0 vm_free +00014c1f vm_setup_stack +00014c7b lex_get_error +00014c88 next +00015193 match +000151e1 expression +000164e2 statement +000166eb function_parameter +000168ad function_body +00016abc function_declaration +00016b45 enum_declaration +00016c58 global_declaration +00016e85 lex_init +00016f20 program +00016fc1 find_mp_floating_ptr +00016ffd smp_parse +00017142 kb_get_char +0001718e kb_add_char +000171c9 kb_callback +000173f6 init_keyboard +0001746d pcb_await +00017497 __pcb_get_free +00017555 __add_systemcall_pcb_await +0001756c __pcb_free +000175bb __pcb_init_kernel_stack +0001761c __pcb_init_process +000176e1 init_pcbs +00017732 pcb_total_usage +0001775b pcb_get_info +0001784f pcb_kill +0001786c Genesis +0001786e idletask +00017889 pcb_get_by_pid +0001789a pcb_get_by_name +000178f3 pcb_dbg_print +0001796d pcb_cleanup_routine +00017b7d pcb_create_thread +00017c75 pcb_create_process +00017f07 pcb_create_kthread +000181e3 start_pcb +0001821b __pcb_queue_peek +0001825a __pcb_queue_pop +000182b6 __pcb_queue_remove +00018328 __pcb_queue_add +000183a1 __pcb_queue_push +0001843a pcb_new_queue +0001846b get_mem_info +000184c3 memory_map_init +0001858a memory_map_get +00018590 free +000185e7 malloc +00018683 calloc +000186b6 krealloc +00018722 init_memory +000187b4 vmem_free +00018824 vmem_alloc +00018891 vmem_free_page_region +000189f7 vmem_page_region_alloc +00018a32 vmem_create_page_region +00018b76 vmem_free_allocations +00018ca5 vmem_continious_allocation_map +00018cab vmem_free_allocation +00018cac vmem_stack_free +00018d5d vmem_stack_alloc +000190e2 vmem_dump_heap +00019177 vmem_init_process_thread +00019268 vmem_init_process +00019596 vmem_cleanup_process_thead +0001960d vmem_cleanup_process +000197fb vmem_init_kernel +000199bc vmem_allocator_create +00019a20 vmem_map_driver_region +00019a9e vmem_total_usage +00019ab1 vmem_init +00019be3 kalloc +00019d7a kcalloc +00019dac kfree +00019e42 palloc +00019e84 pmemory_used +00019ea0 kmemory_used +00019ea6 kmemory_total +00019eb2 kmem_init +00019f4f e1000_receive +0001a02a e1000_transmit +0001a0ec e1000_callback +0001a113 _e1000_tx_init +0001a1b7 _e1000_rx_init +0001a251 e1000_attach +0001a481 display_get_info +0001a4ea kenv_init +0001a501 kenv_set +0001a536 config_list +0001a607 kernel_config_load +0001a9f2 config_get_value +0001aaad spin_lock +0001aacd spin_unlock +0001aadb mutex_init +0001aaf8 acquire +0001ab95 release +0001ac37 kthread_entry +0001ac91 kthread_list +0001acf8 register_kthread +0001add1 start +0001ae73 ata_primary +0001ae74 ata_secondary +0001ae75 ata_wait +0001aeef ata_write +0001b066 ata_read +0001b1f6 ata_ide_init +0001b3c6 set_bitmap +0001b3e8 unset_bitmap +0001b40c get_bitmap +0001b42e get_bitmap_size +0001b442 create_bitmap +0001b476 destroy_bitmap +0001b489 bitmap_unset_continous +0001b4c3 bitmap_get_continous +0001b55f get_free_bitmap +0001b5b4 __rtc_check_in_progress +0001b5d6 __rtc_get_register +0001b5f6 get_current_time +0001b741 get_time +0001b76b init_tss +0001b799 __add_systemcall_sys_system +0001b7b0 exec_cmd +0001b8b4 sys_system +0001b8c4 __ksymbol_exec_cmd +0001b8de system_reboot +0001b912 align_to_pointer_size +0001b920 calculate_size_unit +0001b982 advanced_hash +0001b9b6 kernel_panic +0001b9d4 kref_init +0001b9ee kref_get +0001ba16 kref_put +0001ba3e csprintf +0001bc3f script_parse +0001bd14 login +0001c0b2 __login_create_virt_disk +0001c0dc __register_kthread_login +0001c0f6 help +0001c397 clear +0001c3b8 __ksymbol_new +0001c3d2 __ksymbol_list +0001c3ec __ksymbol_color +0001c406 __ksymbol_about +0001c420 __ksymbol_help +0001c43a __ksymbol_kevents +0001c454 __ksymbol_view +0001c46e __ksymbol_file +0001c488 __ksymbol_tcp +0001c4a2 __ksymbol_conf +0001c4bc __ksymbol_clear +0001c4d6 __ksymbol_services +0001c4f0 __ksymbol_reboot +0001c50a kevents +0001c5e4 services +0001c812 new +0001c953 list +0001ca53 file +0001cc21 color +0001ccc2 about +0001ccff view +0001cf14 tcp +0001d1f1 __tcp_reader +0001d312 conf +0001d5da reboot +0001d613 attach_disk_dev +0001d637 disk_attached +0001d63f disk_name +0001d648 disk_device_get +0001d64e disk_size +0001d66a write_block +0001d6a7 write_block_offset +0001d6ea read_block +0001d727 read_block_offset +0001d791 sched_consume +0001d7d2 sched_add +0001d82c sched_prioritize +0001d8e1 sched_round_robin +0001dac7 sched_exit +0001db80 sched_block +0001dc9e sched_default +0001dd78 sched_sleep +0001de1e sched_init_default +0001de9f get_scheduler +0001dea5 kernel_sleep +0001dec0 kernel_yield +0001df03 kernel_exit +0001df35 block +0001df5e unblock +0001df5f work_queue_add +0001e047 init_worker +0001e05f worker_thread +0001e0fe __ring_buffer_add +0001e1a6 __ring_buffer_read +0001e2b0 rbuffer_new +0001e319 rbuffer_free +0001e33b error_get_string +0001e377 kclock +0001e857 __register_kthread_kclock +0001e871 tar_extract +0001eac1 __ksymbol_tar +0001eadb tar_list +0001ebe5 tar +0001ee6e rgb_to_vga +0001ee7e rgb_to_components +0001eea5 color_distance_squared +0001ef10 rgb_init_color_table +0001efa1 iface_loopback_write +0001f062 iface_loopback_interrupt +0001f079 iface_loopback_read +0001f11c net_init_loopback +0001f133 serial_put +0001f173 serial_write +0001f1b5 serial_printf +0001f355 init_serial +0001f41b inportb +0001f424 inportw +0001f42e inportl +0001f437 outportb +0001f445 outportw +0001f454 outportl +0001f461 sys_create_thread +0001f480 __add_systemcall_sys_create_thread +0001f48b add_system_call +0001f4cb system_call +0001f536 hashmap_put +0001f59d hashmap_get +0001f621 hashmap_add +0001f6ab hashmap_free +0001f6ac reset_vga_palette +0001f6f2 vga_set_palette +0001f7dd b8to16 +0001f7ed vesa_put_pixel +0001f817 vesa_put_box +0001f892 vesa_put_block +0001f90d vesa_put_char +0001f988 vesa_put_char16 +0001fa1b vesa_put_icon16 +0001fa94 vesa_write +0001fad3 vesa_write_str +0001fb01 vesa_fill +0001fb83 vesa_fillrect +0001fbf5 vesa_inner_box +0001fcfd vesa_printf +0001ff6a ksyms_init +00020191 ksyms_add_symbol +0002024a __ksymbol_backtrace +00020264 ksyms_list +000202c6 ksyms_resolve_symbol +00020379 __backtrace_from +00020496 backtrace +000204a7 ws_fullscreen +00020621 ws_remove +000206d1 ws_add +000207bc ws_destroy +00020862 ws_draw +00020b0f ws_raw_wallpaper +00020bf5 ws_set_background_file +00020ed2 ws_init +00020fb5 ws_set_background +00021060 ws_new +000210ed encode_run_length +0002116a decode_run_length +000211d5 __mouse_handler +000212ec mouse_wait +00021334 mouse_write +00021376 mouse_get_event +000213b7 mouse_init +0002149c sys_ipc_open +000214ea __add_systemcall_sys_ipc_open +00021501 __add_systemcall_sys_ipc_close +00021518 __add_systemcall_sys_ipc_send +0002152f __add_systemcall_sys_ipc_receive +00021546 sys_ipc_close +0002158f sys_ipc_send +000215f6 sys_ipc_receive +0002165c sysinf +000223ae __register_kthread_sysinf +000223c8 echo +00022403 res +00022444 ifconfig +00022451 __ksymbol_ifconfig +0002246b __ksymbol_ps +00022485 __ksymbol_tree +0002249f __ksymbol_fat16 +000224b9 __ksymbol_xxd +000224d3 __ksymbol_sh +000224ed __ksymbol_ed +00022507 __ksymbol_exec +00022521 __ksymbol_ths +0002253b __ksymbol_dns +00022555 __ksymbol_th +0002256f __ksymbol_kill +00022589 __ksymbol_echo +000225a3 __ksymbol_fdisk +000225bd __ksymbol_meminfo +000225d7 __ksymbol_res +000225f1 __ksymbol_bg +0002260b __ksymbol_exit +00022625 __ksymbol_socks +0002263f __ksymbol_reset +00022659 exit +0002268d ps +00022901 print_pcb_tree +00022a00 tree +00022a40 fat16 +00022a68 xxd +00022b5d sh +00022c5d ed +00022caa exec +00022e0e ths +00022e7a dns +00022eee th +00022f0c kill +00022f2a fdisk +000230bc meminfo +0002329b bg +0002331a socks +000235c0 __register_kthread_shell +000235da __register_kthread_textshell +000235f4 shell_clear +00023637 reset_shell +000236a8 reset +000236fc shell_put +000238dd shell +00023b3e cleanup_function +00023b65 testfn +00023b99 draw_box +00023c7e __textshell_reset_box +00023d0e textshell +000240da __net_find_interface +0002413a net_drop_packet +0002415b net_handle_recieve +00024282 net_get_interfaces +00024288 net_configure_iface +000242da net_incoming_packet +0002438b net_get_iface +00024401 net_iface_up +00024428 net_iface_down +0002444f net_list_ifaces +00024569 net_register_interface +0002459a net_send_skb +00024622 net_get_info +00024649 networking_main +00024829 __dhcp_add_option +00024899 __dhcp_send_discovery +000249db __dhcp_send_request +00024b58 dhcp_get_state +00024b60 dhcp_get_dns +00024b66 dhcp_get_ip +00024b7b dhcp_get_gw +00024b90 dhcpd +00024e0f udp_server +00024e9a tcp_server +0002500e __net_terminal_writef +00025073 __register_kthread_tcp_server +0002508d __register_kthread_udp_server +000250a7 __register_kthread_udptest +000250c1 udptest +0002514c tcpd +00025230 logd +0002529b __register_kthread_logd +000252b5 logd_attach_by_pid +000252f9 taskbar_reboot +00025325 __reboot +0002533a taskbar_readme +00025353 taskbar_about +0002536c taskbar_clock +00025385 taskbar_sysinf +0002539e taskbar_bg_retro +000253d5 taskbar_bg_lotr2 +000253ea taskbar_bg_lotr +000253ff taskbar_bg_default_color_gray +00025411 taskbar_bg_default_color +00025423 taskbar_wolfstein +0002545e taskbar_bg_graph +00025499 taskbar_bg_calc +000254d4 taskbar_colors +0002550f taskbar_cube +0002554a taskbar_editor +00025585 taskbar_finder +000255c0 taskbar_terminal +00025609 __register_kthread_taskbar +00025623 taskbar_hdr_opt_event +000256ad taskbar +00025c64 about +00025e2f __register_kthread_about +00025e49 __register_kthread_readme +00025e63 readme +00025fc5 gfx_default_hover +000260e4 gfx_destory_window +00026171 gfx_window_resize +0002621a gfx_window_maximize +00026293 gfx_default_mouse_up +00026361 gfx_default_mouse_down +00026423 gfx_default_click +00026612 gfx_draw_window +000273fe gfx_window_set_resizable +00027413 kernel_gfx_window_border_color +0002743e gfx_new_window +0002769e gfx_point_in_rectangle +000276cb gfx_draw_component +0002770d gfx_input_event +0002783f gfx_input_draw +00027947 gfx_input_manager_add +000279a8 gfx_composition_remove_window +000279d2 gfx_composition_add_window +00027a19 gfx_set_background_color +00027a6a gfx_raw_background +00027ab7 gfx_decode_background_image +00027b04 gfx_set_taskbar +00027ba4 gfx_compositor_main +00027c18 kernel_gfx_draw_circle_helper +00027ec4 gfx_get_window_width +00027ed9 gfx_get_window_height +00027eee gfx_push_event +00027faa gfx_put_icon16 +000280a2 gfx_put_icon32 +0002819a gfx_event_loop +000282b9 kernel_gfx_draw_rectangle +000283b3 kernel_gfx_draw_contoured_box +00028453 kernel_gfx_draw_pixel +000284f1 kernel_gfx_draw_bitmap +0002860f kernel_gfx_draw_char +0002870f kernel_gfx_set_position +0002872b gfx_commit +00028744 kernel_gfx_draw_text +000287f7 gfx_button_ext +0002892a gfx_button +00028948 kernel_gfx_set_title +000289b4 kernel_gfx_set_header +00028a20 kernel_gfx_draw_line +00028bbb kernel_gfx_draw_circle +00028c3a kernel_gfx_draw_section +00028c40 kernel_gfx_draw_format_text +00028f92 gfx_syscall_hook +00029149 gfx_total_themes +0002914f kernel_gfx_current_theme +00029155 kernel_gfx_update_theme +00029223 kernel_gfx_default_theme +00029229 kernel_gfx_set_theme +0002924e kernel_gfx_get_theme +00029269 gfx_new_ctx +000292c5 gfx_init_framebuffer +00029431 netdev_attach_driver +000294da is_netdev_attached +000294e8 netdev_transmit +00029503 netdev_recieve +0002952c net_ethernet_add_header +000295c0 net_ethernet_parse +00029634 __skb_queue_remove +00029672 __skb_queue_add +000296c2 skb_free_queue +000296fa skb_new_queue +00029761 skb_free +0002979c skb_new +00029807 skb_consume +00029838 __net_arp_send +000298f8 net_init_arp +00029944 net_arp_add_entry +000299d3 net_arp_find_entry +00029a1e net_arp_respond +00029a93 net_net_arp_request +00029b19 arp_parse +00029bc3 net_ipv4_print +00029bc9 net_ipv4_add_header +00029d00 net_is_ipv4 +00029d3d net_ipv4_parse +00029e6a ntohl +00029e96 htonl +00029ea9 ntohs +00029eb6 htons +00029ec3 checksum +00029f1a transport_checksum +00029f6f ip_to_int +0002a00d net_icmp_handle +0002a0d2 net_icmp_response +0002a0d8 net_icmp_request +0002a19b ping +0002a1f4 net_icmp_parse +0002a264 net_udp_send +0002a399 net_udp_parse +0002a4c1 socket_type_to_str +0002a4d0 socket_domain_to_str +0002a4df socket_protocol_to_str +0002a4ee net_sock_bind +0002a539 net_get_sockets +0002a555 sock_get +0002a576 get_total_sockets +0002a57c net_sock_is_established +0002a5c0 net_sock_awaiting_ack +0002a604 net_sock_data_ready +0002a65d net_sock_read +0002a75f net_sock_add_data +0002a9bf sock_find_listen_tcp +0002aa03 net_sock_find_tcp +0002abf5 net_prepare_tcp_sock +0002ac81 net_sock_accept +0002ac94 net_socket_find_udp +0002acff kernel_sock_shutdown +0002ad2c kernel_sock_cleanup +0002adb2 kernel_sock_close +0002ade6 kernel_socket_create +0002af69 net_init_sockets +0002afaf gethostname +0002b4c9 __add_systemcall_gethostname +0002b4e0 net_init_dns +0002b50f route +0002b55c tcb_init +0002b57a tcb_new +0002b6e6 tcp_state_to_str +0002b6ff tcp_new_connection +0002b787 tcp_free_connection +0002b7aa tcp_is_listening +0002b7c0 tcp_set_listening +0002b820 tcp_calculate_checksum +0002b8e4 __tcp_send +0002ba00 tcp_send_segment +0002bb43 tcp_accept_connection +0002bc85 tcp_send_ack +0002bdbb tcp_read +0002bdc1 tcp_recv_segment +0002bdc7 tcp_connect +0002be6a tcp_send_syn +0002be70 tcp_recv_ack +0002bef3 tcp_recv_fin +0002bef9 tcp_recv_syn +0002c02b tcp_send_fin +0002c0f7 tcp_close_connection +0002c136 tcp_parse +0002c5cf kernel_bind +0002c604 kernel_recvfrom +0002c60a kernel_recv +0002c67c kernel_recv_timeout +0002c6a2 kernel_connect +0002c7a6 kernel_sendto +0002c860 kernel_accept +0002c8c3 kernel_listen +0002c8eb kernel_send +0002c971 sys_kernel_bind +0002c9a3 __add_systemcall_sys_kernel_bind +0002c9ba __add_systemcall_sys_kernel_accept +0002c9d1 __add_systemcall_sys_kernel_connect +0002c9e8 __add_systemcall_sys_kernel_listen +0002c9ff __add_systemcall_sys_kernel_recv +0002ca16 __add_systemcall_sys_kernel_recvfrom +0002ca2d __add_systemcall_sys_kernel_recv_timeout +0002ca44 __add_systemcall_sys_kernel_send +0002ca5b __add_systemcall_sys_kernel_sendto +0002ca72 __add_systemcall_sys_socket_create +0002ca89 __add_systemcall_sys_kernel_sock_close +0002caa0 sys_kernel_accept +0002cae0 sys_kernel_connect +0002cb12 sys_kernel_listen +0002cb41 sys_kernel_recv +0002cb79 sys_kernel_recvfrom +0002cbb9 sys_kernel_recv_timeout +0002cbf7 sys_kernel_send +0002cc2f sys_kernel_sendto +0002cc6f sys_socket_create +0002cc96 sys_kernel_sock_close +0002ccd7 __iface_send +0002cd06 __iface_recieve +0002cd35 __iface_assign +0002cd48 __iface_detach +0002cd5c __iface_set_gateway +0002cd6f __iface_set_netmask +0002cd82 __iface_configure +0002cdd2 __iface_attach +0002cdf7 net_interface_create +0002ce2f net_register_netdev +0002cf47 net_interface_destroy +0002cf5c __default_restart +0002cf62 __default_stop +0002cfc7 __default_start +0002d041 nm_new +0002d0ca nm_free +0002d10f net_firewall_create +0002d132 fs_file2fd +0002d199 fs_alloc_file +0002d1e4 fs_free_file +0002d23e fs_register +0002d30d fs_init +0002d313 fs_unregister +0002d376 fs_get +0002d37c fs_close +0002d3ee fs_open +0002d468 fs_seek +0002d4e5 fs_read +0002d5fa fs_load_from_file +0002d686 fs_write +0002d741 fs_save_to_file +0002d7cd fat16_rmdir +0002d7d3 fat16_stat +0002d7d9 fat16_close +0002d843 fat16_rename +0002d8d8 fat16_mkdir +0002d9bd fat16_remove +0002da30 fat16_open +0002db7a fat16_read +0002dcde fat16_write +0002de0d fat16_list +0002e0db fat16_init +0002e18f path_next_iter +0002e1fe inode_from_path_recursise +0002e27c inode_from_path +0002e33a ext_get_root +0002e343 ext_get_current_dir +0002e352 ext_get_size +0002e358 ext_get_inodes +0002e35e ext_get_blocks +0002e364 ext_sync +0002e3d7 ext_create +0002e4c2 ext_read +0002e53d ext_seek +0002e584 ext_write +0002e5f0 ext_close +0002e652 ext_open_from_directory +0002e758 ext_open +0002e80f ext_size +0002e838 change_directory +0002e89e ext_create_directory +0002ea38 ext_create_file_system +0002ed05 init_ext +0002eea1 listdir +0002efc2 __inode_sync +0002f025 __inode_cache_insert +0002f11b __inode_load +0002f18f inodes_sync +0002f1ca inode_get +0002f227 inode_read +0002f40f inode_write +0002f66d alloc_inode +0002f726 mkdir +0002f7d3 sync +0002f807 mkfs +0002f814 fat16_read_data_from_cluster +0002f862 fat16_read_data +0002f943 fat16_find_cluster_by_offset +0002f9be fat16_write_data_to_cluster_with_offset +0002f9f9 fat16_print_cluster_chain +0002fa27 fat16_write_data_to_cluster +0002fa5a fat16_write_data +0002fb76 get_fat_start_block +0002fb7e get_root_directory_start_block +0002fb8d get_data_start_block +0002fb9f fat16_get_fat_entry +0002fbba fat16_set_fat_entry +0002fbfa fat16_sync_fat_table +0002fc72 fat16_allocate_cluster +0002fc8a fat16_free_cluster +0002fc9f fat16_get_free_cluster +0002fcf4 fat16_sync_directory_entry +0002fd76 fat16_read_entry +0002fe23 fat16_find_entry +0002ff5e fat16_rename_entry +0002ffcf fat16_free_clusters +00030016 fat16_delete_entry +0003007d fat16_add_entry +000301e4 fat16_used_blocks +0003021d fat16_to_upper +00030249 fat16_name_compare +0003036e sstrtok +0003042f fat16_directory_entry_debug +000304ff fat16_get_directory_entry +000306f7 fat16_create_directory +000307fc fat16_read_file +0003084d fat16_create_file +000308cb fat16_create_empty_file +0003098b fat16_directory_entries +00030a71 fat16_mbr_clear +00030b1a fat16_mbr_add_entry +00030c0b fat16_print_root_directory_entries +00030c23 fat16_change_directory +00030cab fat16_bootblock_info +00030e28 fat16_set_time +00030e5c fat16_set_date +00030e94 fat16_load +00031013 fat16_format +000312c8 mbr_partition_type_string +0003134b mbr_partitions_parse +00031414 mbr_get +0003141a mbr_partition_load +00031438 __list_users +000314c9 __change_user +0003156b __remove_user +00031617 __add_user +00031701 __find_user +000317d6 __authenticate_user +000318e4 __save_users +00031968 __load_users +00031b6a __ksymbol_admin +00031b84 admin +00031e98 usermanager_create +00031eb7 __ksymbol_snakegame +00031ed1 init_game +00031f1f draw +00031f7b get_input +00031f9a update +00032121 game_loop +00032147 snakegame +00032192 __msgbox +00032592 msgbox_create +000325c5 msgbox_show +0003260d kevents_list +0003277f kevents_init +000327c1 kevents_destroy +00032816 kevents_add +000328cd kevents_create +00032950 __ksymbol_editor +0003296a textbuffer_destroy +000329dd textbuffer_new_line +00032a93 textbuffer_handle_char +0003300a textbuffer_display +000330e7 editor +00033259 _code_end From b93ef008b7e7157616e91cd7a2501737f474907e Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Mon, 5 Feb 2024 21:06:51 +0100 Subject: [PATCH 14/23] edit: lines without newlines --- include/libc.h | 1 + kernel/edit.c | 42 +- lib/libc.c | 16 + rootfs/symbols.map | 1772 ++++++++++++++++++++++---------------------- 4 files changed, 936 insertions(+), 895 deletions(-) diff --git a/include/libc.h b/include/libc.h index 041c28b..ee557ac 100644 --- a/include/libc.h +++ b/include/libc.h @@ -30,6 +30,7 @@ extern "C" int getopt(int argc, char* argv[], const char* optstring, char** optarg); char* strtok(char* str, const char* delim); +int strstr(const char* str, const char* str2); char* strchr(const char* str, int ch); int strlen(const char* str); uint32_t strcpy(char* dest, const char* src); diff --git a/kernel/edit.c b/kernel/edit.c index e417c46..fcc8fda 100644 --- a/kernel/edit.c +++ b/kernel/edit.c @@ -9,12 +9,13 @@ #include #define MAX_LINES 512 -#define LINE_CAPACITY 78 +#define LINE_CAPACITY 76 #define MAX_VISABLE_LINES 22 -typdef enum __line_flags { - LINE_FLAG_NONE = 0 << 0, - LINE_FLAG_DIRTY = 1 << 0, +typedef enum __line_flags { + LINE_FLAG_NONE = 1 << 0, + LINE_FLAG_DIRTY = 1 << 1, + LINE_FLAG_EXTENSION = 1 << 2, } line_flags_t; struct textbuffer { @@ -26,7 +27,7 @@ struct textbuffer { struct line { char *text; size_t length; - size_t capacityi; + size_t capacity; line_flags_t flags; } **lines; struct cursor { @@ -84,6 +85,22 @@ static struct textbuffer *textbuffer_create(void) return buffer; } +static int textbuffer_find(struct textbuffer *buffer, char* str) +{ + int ret; + /* find str in lines and goto line */ + for(size_t i = 0; i < buffer->line_count; i++){ + ret = strstr(buffer->lines[i]->text, str); + if(ret >= 0){ + buffer->cursor.y = i; + buffer->cursor.x = ret; + return 0; + } + } + + return -1; +} + static int textbuffer_destroy(struct textbuffer *buffer) { for (size_t i = 0; i < buffer->line_count; i++) { @@ -168,9 +185,14 @@ static int textbuffer_save_file(struct textbuffer *buffer, const char *filename) for(size_t i = 0; i < buffer->line_count; i++){ if(buffer->lines[i]->text){ memcpy(file + len, buffer->lines[i]->text, buffer->lines[i]->length); - /* Add a newline character after each line */ - file[len + buffer->lines[i]->length] = '\n'; - len += buffer->lines[i]->length + 1; + + /* Add newline if not extension */ + if(!HAS_FLAG(buffer->lines[i]->flags, LINE_FLAG_EXTENSION)){ + file[len + buffer->lines[i]->length] = '\n'; + len++; + } + + len += buffer->lines[i]->length; } } int ret = fs_save_to_file(filename, file, len); @@ -393,7 +415,9 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { } else { /* If the buffer is full, do nothing */ if (buffer->lines[buffer->cursor.y]->length == buffer->lines[buffer->cursor.y]->capacity) { - return -1; + /* Create new line, but flag it as extension */ + textbuffer_handle_char(buffer, '\n'); + buffer->lines[buffer->cursor.y]->flags |= LINE_FLAG_EXTENSION; } /* If x is behind length, then we move content forward */ diff --git a/lib/libc.c b/lib/libc.c index 9d7480a..17cd052 100644 --- a/lib/libc.c +++ b/lib/libc.c @@ -41,6 +41,22 @@ int strlen(const char* str) return len; } +int strstr(const char* haystack, const char* needle) +{ + int i, j; + for (i = 0; haystack[i] != '\0'; i++){ + for (j = 0; needle[j] != '\0'; j++){ + if (haystack[i + j] != needle[j]){ + break; + } + } + if (needle[j] == '\0'){ + return i; + } + } + return -1; +} + inline uint32_t strcpy(char* dest, const char* src) { uint32_t i = 0; diff --git a/rootfs/symbols.map b/rootfs/symbols.map index 7eebf90..c0fff00 100644 --- a/rootfs/symbols.map +++ b/rootfs/symbols.map @@ -8,889 +8,889 @@ 00010058 gdt_end 00010058 kernel_boot_printf 000100b7 init_kctors -00010103 kernel -0001059d kernel_get_context -000105a3 hexdump -000107f1 __terminal_set_ops -000108ba __terminal_scanf -000108c0 __terminal_write -0001090a __terminal_getchar_graphics -00010953 __terminal_scan_graphics -00010a31 __terminal_reset -00010a75 __terminal_detach -00010ab8 __terminal_attach -00010b03 __terminal_remove_line -00010b43 __terminal_putchar_graphics -00010c0c __terminal_writef -00010f16 __terminal_getchar_textmode -00010f3e __terminal_scan_textmode -00011002 __terminal_commit_textmode -000110ba __terminal_putchar_textmode -00011106 scan -0001113f terminal_set_color -00011157 __terminal_commit_graphics -000112b3 terminal_attach -000112d4 terminal_commit -000112f3 terminal_putchar -0001132f terminal_create -00011454 terminal_destroy -0001148c tlb_flush_addr -00011494 load_page_directory -000114a4 enable_paging -000114b6 pcb_save_context -000114e2 pcb_restore_context -0001150b _start_pcb -0001153d _start_pcb_skip -00011558 __ksymbol_lspci -00011572 pci_get_class_name -00011585 pci_get_device_name -000115f6 pci_get_vendor_name -00011644 lspci -00011791 pci_get_devices -00011797 pci_read_word -000117f1 pci_write_dword -00011840 pci_enable_device_busmaster -00011895 pci_register_device -00011916 init_pci -00011ac7 pci_find_device -00011b5d virtual_read -00011b88 virtual_write -00011bb3 virtual_disk_attach -00011bd2 wm_default_changes -00011c7a wm_default_workspace -00011cdc wm_default_draw -00011d7a wm_default_add -00011e21 init_windowmanager -00011f6b wm_default_mouse_event -00012191 wm_default_push_back -00012283 wm_default_push_front -00012372 wm_default_remove -00012483 wm_destroy -00012561 wm_new -000125c8 screen_set_cursor -00012628 scrcolor_set -0001263c scrput -00012662 scrwrite -000126ab scr_clear -000126fd scr_scroll -00012745 scrprintf -00012989 strlen -000129ab strcpy -000129df strncmp -00012a1a strcmp -00012a5a memcmp -00012a95 parse_arguments -00012b78 strchr -00012ba7 getopt -00012cb7 memcpy -00012d24 strtok -00012ddc xmemcpy -00012e63 memset -00012ee3 isdigit -00012ef7 isspace -00012f06 tolower -00012f1a isxdigit -00012f3e htoi -00012fe2 atoi -00013072 itoa -00013118 itohex -00013194 rdtsc -00013197 rand -000131b3 general_protection_fault -00013243 interrupt_get_count -00013252 print_page_fault_info -0001332f page_fault_interrupt -000133c1 interrupt_install_handler -000133d3 load_data_segments -000133df isr_handler -000134d2 init_interrupts -0001364b idt_flush -00013653 isr0 -00013660 isr1 -0001366d isr2 -0001367a isr3 -00013687 isr4 -00013694 isr5 -000136a1 isr6 -000136ae isr7 -000136bb isr8 -000136c8 isr9 -000136d5 isr10 -000136e2 isr11 -000136ef isr12 -000136fc isr13 -00013709 isr14 -00013716 isr15 -00013723 isr16 -00013730 isr17 -0001373d isr18 -0001374a isr19 -00013757 isr20 -00013764 isr21 -00013771 isr22 -0001377e isr23 -0001378b isr24 -00013798 isr25 -000137a5 isr26 -000137b2 isr27 -000137bf isr28 -000137cc isr29 -000137d9 isr30 -000137e6 isr31 -000137f3 isr32 -00013800 isr33 -0001380d isr34 -0001381a isr35 -00013824 isr36 -0001382e isr37 -00013838 isr38 -00013842 isr39 -0001384c isr40 -00013856 isr41 -00013860 isr42 -0001386a isr43 -00013874 isr44 -0001387e isr45 -00013888 isr46 -00013892 isr47 -0001389c isr_entry -000138b7 syscall_return_value -000138bb _syscall_entry -000138f8 page_fault_save -000138fc page_fault_error -00013900 _page_fault_entry -00013932 timer_callback -0001396a timer_get_tick -00013970 time_get_difference -000139b3 init_pit -00013a17 gdt_set_segment -00013a60 init_gdt -00013b6e rc -00013d5d __ksymbol_rc -00013d77 __ksymbol_as -00013d91 __ksymbol_cc -00013dab as -0001416d cc -000141c9 __cc -000144bd vm_print -000146ba eval -00014b54 vm_setup -00014b95 vm_init -00014bf0 vm_free -00014c1f vm_setup_stack -00014c7b lex_get_error -00014c88 next -00015193 match -000151e1 expression -000164e2 statement -000166eb function_parameter -000168ad function_body -00016abc function_declaration -00016b45 enum_declaration -00016c58 global_declaration -00016e85 lex_init -00016f20 program -00016fc1 find_mp_floating_ptr -00016ffd smp_parse -00017142 kb_get_char -0001718e kb_add_char -000171c9 kb_callback -000173f6 init_keyboard -0001746d pcb_await -00017497 __pcb_get_free -00017555 __add_systemcall_pcb_await -0001756c __pcb_free -000175bb __pcb_init_kernel_stack -0001761c __pcb_init_process -000176e1 init_pcbs -00017732 pcb_total_usage -0001775b pcb_get_info -0001784f pcb_kill -0001786c Genesis -0001786e idletask -00017889 pcb_get_by_pid -0001789a pcb_get_by_name -000178f3 pcb_dbg_print -0001796d pcb_cleanup_routine -00017b7d pcb_create_thread -00017c75 pcb_create_process -00017f07 pcb_create_kthread -000181e3 start_pcb -0001821b __pcb_queue_peek -0001825a __pcb_queue_pop -000182b6 __pcb_queue_remove -00018328 __pcb_queue_add -000183a1 __pcb_queue_push -0001843a pcb_new_queue -0001846b get_mem_info -000184c3 memory_map_init -0001858a memory_map_get -00018590 free -000185e7 malloc -00018683 calloc -000186b6 krealloc -00018722 init_memory -000187b4 vmem_free -00018824 vmem_alloc -00018891 vmem_free_page_region -000189f7 vmem_page_region_alloc -00018a32 vmem_create_page_region -00018b76 vmem_free_allocations -00018ca5 vmem_continious_allocation_map -00018cab vmem_free_allocation -00018cac vmem_stack_free -00018d5d vmem_stack_alloc -000190e2 vmem_dump_heap -00019177 vmem_init_process_thread -00019268 vmem_init_process -00019596 vmem_cleanup_process_thead -0001960d vmem_cleanup_process -000197fb vmem_init_kernel -000199bc vmem_allocator_create -00019a20 vmem_map_driver_region -00019a9e vmem_total_usage -00019ab1 vmem_init -00019be3 kalloc -00019d7a kcalloc -00019dac kfree -00019e42 palloc -00019e84 pmemory_used -00019ea0 kmemory_used -00019ea6 kmemory_total -00019eb2 kmem_init -00019f4f e1000_receive -0001a02a e1000_transmit -0001a0ec e1000_callback -0001a113 _e1000_tx_init -0001a1b7 _e1000_rx_init -0001a251 e1000_attach -0001a481 display_get_info -0001a4ea kenv_init -0001a501 kenv_set -0001a536 config_list -0001a607 kernel_config_load -0001a9f2 config_get_value -0001aaad spin_lock -0001aacd spin_unlock -0001aadb mutex_init -0001aaf8 acquire -0001ab95 release -0001ac37 kthread_entry -0001ac91 kthread_list -0001acf8 register_kthread -0001add1 start -0001ae73 ata_primary -0001ae74 ata_secondary -0001ae75 ata_wait -0001aeef ata_write -0001b066 ata_read -0001b1f6 ata_ide_init -0001b3c6 set_bitmap -0001b3e8 unset_bitmap -0001b40c get_bitmap -0001b42e get_bitmap_size -0001b442 create_bitmap -0001b476 destroy_bitmap -0001b489 bitmap_unset_continous -0001b4c3 bitmap_get_continous -0001b55f get_free_bitmap -0001b5b4 __rtc_check_in_progress -0001b5d6 __rtc_get_register -0001b5f6 get_current_time -0001b741 get_time -0001b76b init_tss -0001b799 __add_systemcall_sys_system -0001b7b0 exec_cmd -0001b8b4 sys_system -0001b8c4 __ksymbol_exec_cmd -0001b8de system_reboot -0001b912 align_to_pointer_size -0001b920 calculate_size_unit -0001b982 advanced_hash -0001b9b6 kernel_panic -0001b9d4 kref_init -0001b9ee kref_get -0001ba16 kref_put -0001ba3e csprintf -0001bc3f script_parse -0001bd14 login -0001c0b2 __login_create_virt_disk -0001c0dc __register_kthread_login -0001c0f6 help -0001c397 clear -0001c3b8 __ksymbol_new -0001c3d2 __ksymbol_list -0001c3ec __ksymbol_color -0001c406 __ksymbol_about -0001c420 __ksymbol_help -0001c43a __ksymbol_kevents -0001c454 __ksymbol_view -0001c46e __ksymbol_file -0001c488 __ksymbol_tcp -0001c4a2 __ksymbol_conf -0001c4bc __ksymbol_clear -0001c4d6 __ksymbol_services -0001c4f0 __ksymbol_reboot -0001c50a kevents -0001c5e4 services -0001c812 new -0001c953 list -0001ca53 file -0001cc21 color -0001ccc2 about -0001ccff view -0001cf14 tcp -0001d1f1 __tcp_reader -0001d312 conf -0001d5da reboot -0001d613 attach_disk_dev -0001d637 disk_attached -0001d63f disk_name -0001d648 disk_device_get -0001d64e disk_size -0001d66a write_block -0001d6a7 write_block_offset -0001d6ea read_block -0001d727 read_block_offset -0001d791 sched_consume -0001d7d2 sched_add -0001d82c sched_prioritize -0001d8e1 sched_round_robin -0001dac7 sched_exit -0001db80 sched_block -0001dc9e sched_default -0001dd78 sched_sleep -0001de1e sched_init_default -0001de9f get_scheduler -0001dea5 kernel_sleep -0001dec0 kernel_yield -0001df03 kernel_exit -0001df35 block -0001df5e unblock -0001df5f work_queue_add -0001e047 init_worker -0001e05f worker_thread -0001e0fe __ring_buffer_add -0001e1a6 __ring_buffer_read -0001e2b0 rbuffer_new -0001e319 rbuffer_free -0001e33b error_get_string -0001e377 kclock -0001e857 __register_kthread_kclock -0001e871 tar_extract -0001eac1 __ksymbol_tar -0001eadb tar_list -0001ebe5 tar -0001ee6e rgb_to_vga -0001ee7e rgb_to_components -0001eea5 color_distance_squared -0001ef10 rgb_init_color_table -0001efa1 iface_loopback_write -0001f062 iface_loopback_interrupt -0001f079 iface_loopback_read -0001f11c net_init_loopback -0001f133 serial_put -0001f173 serial_write -0001f1b5 serial_printf -0001f355 init_serial -0001f41b inportb -0001f424 inportw -0001f42e inportl -0001f437 outportb -0001f445 outportw -0001f454 outportl -0001f461 sys_create_thread -0001f480 __add_systemcall_sys_create_thread -0001f48b add_system_call -0001f4cb system_call -0001f536 hashmap_put -0001f59d hashmap_get -0001f621 hashmap_add -0001f6ab hashmap_free -0001f6ac reset_vga_palette -0001f6f2 vga_set_palette -0001f7dd b8to16 -0001f7ed vesa_put_pixel -0001f817 vesa_put_box -0001f892 vesa_put_block -0001f90d vesa_put_char -0001f988 vesa_put_char16 -0001fa1b vesa_put_icon16 -0001fa94 vesa_write -0001fad3 vesa_write_str -0001fb01 vesa_fill -0001fb83 vesa_fillrect -0001fbf5 vesa_inner_box -0001fcfd vesa_printf -0001ff6a ksyms_init -00020191 ksyms_add_symbol -0002024a __ksymbol_backtrace -00020264 ksyms_list -000202c6 ksyms_resolve_symbol -00020379 __backtrace_from -00020496 backtrace -000204a7 ws_fullscreen -00020621 ws_remove -000206d1 ws_add -000207bc ws_destroy -00020862 ws_draw -00020b0f ws_raw_wallpaper -00020bf5 ws_set_background_file -00020ed2 ws_init -00020fb5 ws_set_background -00021060 ws_new -000210ed encode_run_length -0002116a decode_run_length -000211d5 __mouse_handler -000212ec mouse_wait -00021334 mouse_write -00021376 mouse_get_event -000213b7 mouse_init -0002149c sys_ipc_open -000214ea __add_systemcall_sys_ipc_open -00021501 __add_systemcall_sys_ipc_close -00021518 __add_systemcall_sys_ipc_send -0002152f __add_systemcall_sys_ipc_receive -00021546 sys_ipc_close -0002158f sys_ipc_send -000215f6 sys_ipc_receive -0002165c sysinf -000223ae __register_kthread_sysinf -000223c8 echo -00022403 res -00022444 ifconfig -00022451 __ksymbol_ifconfig -0002246b __ksymbol_ps -00022485 __ksymbol_tree -0002249f __ksymbol_fat16 -000224b9 __ksymbol_xxd -000224d3 __ksymbol_sh -000224ed __ksymbol_ed -00022507 __ksymbol_exec -00022521 __ksymbol_ths -0002253b __ksymbol_dns -00022555 __ksymbol_th -0002256f __ksymbol_kill -00022589 __ksymbol_echo -000225a3 __ksymbol_fdisk -000225bd __ksymbol_meminfo -000225d7 __ksymbol_res -000225f1 __ksymbol_bg -0002260b __ksymbol_exit -00022625 __ksymbol_socks -0002263f __ksymbol_reset -00022659 exit -0002268d ps -00022901 print_pcb_tree -00022a00 tree -00022a40 fat16 -00022a68 xxd -00022b5d sh -00022c5d ed -00022caa exec -00022e0e ths -00022e7a dns -00022eee th -00022f0c kill -00022f2a fdisk -000230bc meminfo -0002329b bg -0002331a socks -000235c0 __register_kthread_shell -000235da __register_kthread_textshell -000235f4 shell_clear -00023637 reset_shell -000236a8 reset -000236fc shell_put -000238dd shell -00023b3e cleanup_function -00023b65 testfn -00023b99 draw_box -00023c7e __textshell_reset_box -00023d0e textshell -000240da __net_find_interface -0002413a net_drop_packet -0002415b net_handle_recieve -00024282 net_get_interfaces -00024288 net_configure_iface -000242da net_incoming_packet -0002438b net_get_iface -00024401 net_iface_up -00024428 net_iface_down -0002444f net_list_ifaces -00024569 net_register_interface -0002459a net_send_skb -00024622 net_get_info -00024649 networking_main -00024829 __dhcp_add_option -00024899 __dhcp_send_discovery -000249db __dhcp_send_request -00024b58 dhcp_get_state -00024b60 dhcp_get_dns -00024b66 dhcp_get_ip -00024b7b dhcp_get_gw -00024b90 dhcpd -00024e0f udp_server -00024e9a tcp_server -0002500e __net_terminal_writef -00025073 __register_kthread_tcp_server -0002508d __register_kthread_udp_server -000250a7 __register_kthread_udptest -000250c1 udptest -0002514c tcpd -00025230 logd -0002529b __register_kthread_logd -000252b5 logd_attach_by_pid -000252f9 taskbar_reboot -00025325 __reboot -0002533a taskbar_readme -00025353 taskbar_about -0002536c taskbar_clock -00025385 taskbar_sysinf -0002539e taskbar_bg_retro -000253d5 taskbar_bg_lotr2 -000253ea taskbar_bg_lotr -000253ff taskbar_bg_default_color_gray -00025411 taskbar_bg_default_color -00025423 taskbar_wolfstein -0002545e taskbar_bg_graph -00025499 taskbar_bg_calc -000254d4 taskbar_colors -0002550f taskbar_cube -0002554a taskbar_editor -00025585 taskbar_finder -000255c0 taskbar_terminal -00025609 __register_kthread_taskbar -00025623 taskbar_hdr_opt_event -000256ad taskbar -00025c64 about -00025e2f __register_kthread_about -00025e49 __register_kthread_readme -00025e63 readme -00025fc5 gfx_default_hover -000260e4 gfx_destory_window -00026171 gfx_window_resize -0002621a gfx_window_maximize -00026293 gfx_default_mouse_up -00026361 gfx_default_mouse_down -00026423 gfx_default_click -00026612 gfx_draw_window -000273fe gfx_window_set_resizable -00027413 kernel_gfx_window_border_color -0002743e gfx_new_window -0002769e gfx_point_in_rectangle -000276cb gfx_draw_component -0002770d gfx_input_event -0002783f gfx_input_draw -00027947 gfx_input_manager_add -000279a8 gfx_composition_remove_window -000279d2 gfx_composition_add_window -00027a19 gfx_set_background_color -00027a6a gfx_raw_background -00027ab7 gfx_decode_background_image -00027b04 gfx_set_taskbar -00027ba4 gfx_compositor_main -00027c18 kernel_gfx_draw_circle_helper -00027ec4 gfx_get_window_width -00027ed9 gfx_get_window_height -00027eee gfx_push_event -00027faa gfx_put_icon16 -000280a2 gfx_put_icon32 -0002819a gfx_event_loop -000282b9 kernel_gfx_draw_rectangle -000283b3 kernel_gfx_draw_contoured_box -00028453 kernel_gfx_draw_pixel -000284f1 kernel_gfx_draw_bitmap -0002860f kernel_gfx_draw_char -0002870f kernel_gfx_set_position -0002872b gfx_commit -00028744 kernel_gfx_draw_text -000287f7 gfx_button_ext -0002892a gfx_button -00028948 kernel_gfx_set_title -000289b4 kernel_gfx_set_header -00028a20 kernel_gfx_draw_line -00028bbb kernel_gfx_draw_circle -00028c3a kernel_gfx_draw_section -00028c40 kernel_gfx_draw_format_text -00028f92 gfx_syscall_hook -00029149 gfx_total_themes -0002914f kernel_gfx_current_theme -00029155 kernel_gfx_update_theme -00029223 kernel_gfx_default_theme -00029229 kernel_gfx_set_theme -0002924e kernel_gfx_get_theme -00029269 gfx_new_ctx -000292c5 gfx_init_framebuffer -00029431 netdev_attach_driver -000294da is_netdev_attached -000294e8 netdev_transmit -00029503 netdev_recieve -0002952c net_ethernet_add_header -000295c0 net_ethernet_parse -00029634 __skb_queue_remove -00029672 __skb_queue_add -000296c2 skb_free_queue -000296fa skb_new_queue -00029761 skb_free -0002979c skb_new -00029807 skb_consume -00029838 __net_arp_send -000298f8 net_init_arp -00029944 net_arp_add_entry -000299d3 net_arp_find_entry -00029a1e net_arp_respond -00029a93 net_net_arp_request -00029b19 arp_parse -00029bc3 net_ipv4_print -00029bc9 net_ipv4_add_header -00029d00 net_is_ipv4 -00029d3d net_ipv4_parse -00029e6a ntohl -00029e96 htonl -00029ea9 ntohs -00029eb6 htons -00029ec3 checksum -00029f1a transport_checksum -00029f6f ip_to_int -0002a00d net_icmp_handle -0002a0d2 net_icmp_response -0002a0d8 net_icmp_request -0002a19b ping -0002a1f4 net_icmp_parse -0002a264 net_udp_send -0002a399 net_udp_parse -0002a4c1 socket_type_to_str -0002a4d0 socket_domain_to_str -0002a4df socket_protocol_to_str -0002a4ee net_sock_bind -0002a539 net_get_sockets -0002a555 sock_get -0002a576 get_total_sockets -0002a57c net_sock_is_established -0002a5c0 net_sock_awaiting_ack -0002a604 net_sock_data_ready -0002a65d net_sock_read -0002a75f net_sock_add_data -0002a9bf sock_find_listen_tcp -0002aa03 net_sock_find_tcp -0002abf5 net_prepare_tcp_sock -0002ac81 net_sock_accept -0002ac94 net_socket_find_udp -0002acff kernel_sock_shutdown -0002ad2c kernel_sock_cleanup -0002adb2 kernel_sock_close -0002ade6 kernel_socket_create -0002af69 net_init_sockets -0002afaf gethostname -0002b4c9 __add_systemcall_gethostname -0002b4e0 net_init_dns -0002b50f route -0002b55c tcb_init -0002b57a tcb_new -0002b6e6 tcp_state_to_str -0002b6ff tcp_new_connection -0002b787 tcp_free_connection -0002b7aa tcp_is_listening -0002b7c0 tcp_set_listening -0002b820 tcp_calculate_checksum -0002b8e4 __tcp_send -0002ba00 tcp_send_segment -0002bb43 tcp_accept_connection -0002bc85 tcp_send_ack -0002bdbb tcp_read -0002bdc1 tcp_recv_segment -0002bdc7 tcp_connect -0002be6a tcp_send_syn -0002be70 tcp_recv_ack -0002bef3 tcp_recv_fin -0002bef9 tcp_recv_syn -0002c02b tcp_send_fin -0002c0f7 tcp_close_connection -0002c136 tcp_parse -0002c5cf kernel_bind -0002c604 kernel_recvfrom -0002c60a kernel_recv -0002c67c kernel_recv_timeout -0002c6a2 kernel_connect -0002c7a6 kernel_sendto -0002c860 kernel_accept -0002c8c3 kernel_listen -0002c8eb kernel_send -0002c971 sys_kernel_bind -0002c9a3 __add_systemcall_sys_kernel_bind -0002c9ba __add_systemcall_sys_kernel_accept -0002c9d1 __add_systemcall_sys_kernel_connect -0002c9e8 __add_systemcall_sys_kernel_listen -0002c9ff __add_systemcall_sys_kernel_recv -0002ca16 __add_systemcall_sys_kernel_recvfrom -0002ca2d __add_systemcall_sys_kernel_recv_timeout -0002ca44 __add_systemcall_sys_kernel_send -0002ca5b __add_systemcall_sys_kernel_sendto -0002ca72 __add_systemcall_sys_socket_create -0002ca89 __add_systemcall_sys_kernel_sock_close -0002caa0 sys_kernel_accept -0002cae0 sys_kernel_connect -0002cb12 sys_kernel_listen -0002cb41 sys_kernel_recv -0002cb79 sys_kernel_recvfrom -0002cbb9 sys_kernel_recv_timeout -0002cbf7 sys_kernel_send -0002cc2f sys_kernel_sendto -0002cc6f sys_socket_create -0002cc96 sys_kernel_sock_close -0002ccd7 __iface_send -0002cd06 __iface_recieve -0002cd35 __iface_assign -0002cd48 __iface_detach -0002cd5c __iface_set_gateway -0002cd6f __iface_set_netmask -0002cd82 __iface_configure -0002cdd2 __iface_attach -0002cdf7 net_interface_create -0002ce2f net_register_netdev -0002cf47 net_interface_destroy -0002cf5c __default_restart -0002cf62 __default_stop -0002cfc7 __default_start -0002d041 nm_new -0002d0ca nm_free -0002d10f net_firewall_create -0002d132 fs_file2fd -0002d199 fs_alloc_file -0002d1e4 fs_free_file -0002d23e fs_register -0002d30d fs_init -0002d313 fs_unregister -0002d376 fs_get -0002d37c fs_close -0002d3ee fs_open -0002d468 fs_seek -0002d4e5 fs_read -0002d5fa fs_load_from_file -0002d686 fs_write -0002d741 fs_save_to_file -0002d7cd fat16_rmdir -0002d7d3 fat16_stat -0002d7d9 fat16_close -0002d843 fat16_rename -0002d8d8 fat16_mkdir -0002d9bd fat16_remove -0002da30 fat16_open -0002db7a fat16_read -0002dcde fat16_write -0002de0d fat16_list -0002e0db fat16_init -0002e18f path_next_iter -0002e1fe inode_from_path_recursise -0002e27c inode_from_path -0002e33a ext_get_root -0002e343 ext_get_current_dir -0002e352 ext_get_size -0002e358 ext_get_inodes -0002e35e ext_get_blocks -0002e364 ext_sync -0002e3d7 ext_create -0002e4c2 ext_read -0002e53d ext_seek -0002e584 ext_write -0002e5f0 ext_close -0002e652 ext_open_from_directory -0002e758 ext_open -0002e80f ext_size -0002e838 change_directory -0002e89e ext_create_directory -0002ea38 ext_create_file_system -0002ed05 init_ext -0002eea1 listdir -0002efc2 __inode_sync -0002f025 __inode_cache_insert -0002f11b __inode_load -0002f18f inodes_sync -0002f1ca inode_get -0002f227 inode_read -0002f40f inode_write -0002f66d alloc_inode -0002f726 mkdir -0002f7d3 sync -0002f807 mkfs -0002f814 fat16_read_data_from_cluster -0002f862 fat16_read_data -0002f943 fat16_find_cluster_by_offset -0002f9be fat16_write_data_to_cluster_with_offset -0002f9f9 fat16_print_cluster_chain -0002fa27 fat16_write_data_to_cluster -0002fa5a fat16_write_data -0002fb76 get_fat_start_block -0002fb7e get_root_directory_start_block -0002fb8d get_data_start_block -0002fb9f fat16_get_fat_entry -0002fbba fat16_set_fat_entry -0002fbfa fat16_sync_fat_table -0002fc72 fat16_allocate_cluster -0002fc8a fat16_free_cluster -0002fc9f fat16_get_free_cluster -0002fcf4 fat16_sync_directory_entry -0002fd76 fat16_read_entry -0002fe23 fat16_find_entry -0002ff5e fat16_rename_entry -0002ffcf fat16_free_clusters -00030016 fat16_delete_entry -0003007d fat16_add_entry -000301e4 fat16_used_blocks -0003021d fat16_to_upper -00030249 fat16_name_compare -0003036e sstrtok -0003042f fat16_directory_entry_debug -000304ff fat16_get_directory_entry -000306f7 fat16_create_directory -000307fc fat16_read_file -0003084d fat16_create_file -000308cb fat16_create_empty_file -0003098b fat16_directory_entries -00030a71 fat16_mbr_clear -00030b1a fat16_mbr_add_entry -00030c0b fat16_print_root_directory_entries -00030c23 fat16_change_directory -00030cab fat16_bootblock_info -00030e28 fat16_set_time -00030e5c fat16_set_date -00030e94 fat16_load -00031013 fat16_format -000312c8 mbr_partition_type_string -0003134b mbr_partitions_parse -00031414 mbr_get -0003141a mbr_partition_load -00031438 __list_users -000314c9 __change_user -0003156b __remove_user -00031617 __add_user -00031701 __find_user -000317d6 __authenticate_user -000318e4 __save_users -00031968 __load_users -00031b6a __ksymbol_admin -00031b84 admin -00031e98 usermanager_create -00031eb7 __ksymbol_snakegame -00031ed1 init_game -00031f1f draw -00031f7b get_input -00031f9a update -00032121 game_loop -00032147 snakegame -00032192 __msgbox -00032592 msgbox_create -000325c5 msgbox_show -0003260d kevents_list -0003277f kevents_init -000327c1 kevents_destroy -00032816 kevents_add -000328cd kevents_create -00032950 __ksymbol_editor -0003296a textbuffer_destroy -000329dd textbuffer_new_line -00032a93 textbuffer_handle_char -0003300a textbuffer_display -000330e7 editor -00033259 _code_end +00010109 kernel +000105a7 kernel_get_context +000105b1 hexdump +00010801 __terminal_set_ops +000108ce __terminal_scanf +000108d8 __terminal_write +00010926 __terminal_getchar_graphics +00010973 __terminal_scan_graphics +00010a55 __terminal_reset +00010a9d __terminal_detach +00010ae4 __terminal_attach +00010b33 __terminal_remove_line +00010b73 __terminal_putchar_graphics +00010c40 __terminal_writef +00010f4f __terminal_getchar_textmode +00010f7b __terminal_scan_textmode +00011043 __terminal_commit_textmode +000110ff __terminal_putchar_textmode +0001114f scan +0001118c terminal_set_color +000111a8 __terminal_commit_graphics +00011309 terminal_attach +0001132e terminal_commit +00011351 terminal_putchar +00011391 terminal_create +000114ba terminal_destroy +000114f4 tlb_flush_addr +000114fc load_page_directory +0001150c enable_paging +0001151e pcb_save_context +0001154a pcb_restore_context +00011573 _start_pcb +000115a5 _start_pcb_skip +000115c0 __ksymbol_lspci +000115de pci_get_class_name +000115f5 pci_get_device_name +0001166a pci_get_vendor_name +000116bc lspci +0001180d pci_get_devices +00011817 pci_read_word +00011874 pci_write_dword +000118c7 pci_enable_device_busmaster +00011920 pci_register_device +000119a5 init_pci +00011b69 pci_find_device +00011c03 virtual_read +00011c32 virtual_write +00011c61 virtual_disk_attach +00011c84 wm_default_changes +00011d30 wm_default_workspace +00011d96 wm_default_draw +00011e38 wm_default_add +00011ee3 init_windowmanager +0001202f wm_default_mouse_event +0001224d wm_default_push_back +00012343 wm_default_push_front +00012436 wm_default_remove +0001254b wm_destroy +0001262d wm_new +00012698 screen_set_cursor +000126f8 scrcolor_set +00012710 scrput +0001273c scrwrite +00012789 scr_clear +000127df scr_scroll +0001282b scrprintf +00012aab strlen +00012ad1 strcpy +00012b07 strncmp +00012b44 strcmp +00012b88 memcmp +00012bc5 parse_arguments +00012cae strchr +00012ce1 getopt +00012e2c memcpy +00012e9d strtok +00012f59 xmemcpy +00012fe2 memset +00013060 isdigit +00013078 isspace +0001308b tolower +000130a3 isxdigit +000130cb htoi +00013173 atoi +00013205 itoa +000132b5 itohex +00013335 rdtsc +0001333c rand +0001335c general_protection_fault +000133f0 interrupt_get_count +00013403 print_page_fault_info +000134e0 page_fault_interrupt +00013576 interrupt_install_handler +0001358c load_data_segments +0001359c isr_handler +00013693 init_interrupts +00013810 idt_flush +00013818 isr0 +00013825 isr1 +00013832 isr2 +0001383f isr3 +0001384c isr4 +00013859 isr5 +00013866 isr6 +00013873 isr7 +00013880 isr8 +0001388d isr9 +0001389a isr10 +000138a7 isr11 +000138b4 isr12 +000138c1 isr13 +000138ce isr14 +000138db isr15 +000138e8 isr16 +000138f5 isr17 +00013902 isr18 +0001390f isr19 +0001391c isr20 +00013929 isr21 +00013936 isr22 +00013943 isr23 +00013950 isr24 +0001395d isr25 +0001396a isr26 +00013977 isr27 +00013984 isr28 +00013991 isr29 +0001399e isr30 +000139ab isr31 +000139b8 isr32 +000139c5 isr33 +000139d2 isr34 +000139df isr35 +000139e9 isr36 +000139f3 isr37 +000139fd isr38 +00013a07 isr39 +00013a11 isr40 +00013a1b isr41 +00013a25 isr42 +00013a2f isr43 +00013a39 isr44 +00013a43 isr45 +00013a4d isr46 +00013a57 isr47 +00013a61 isr_entry +00013a7c syscall_return_value +00013a80 _syscall_entry +00013abd page_fault_save +00013ac1 page_fault_error +00013ac5 _page_fault_entry +00013af7 timer_callback +00013b33 timer_get_tick +00013b3d time_get_difference +00013b82 init_pit +00013bea gdt_set_segment +00013c35 init_gdt +00013d47 rc +00013f3a __ksymbol_rc +00013f58 __ksymbol_as +00013f76 __ksymbol_cc +00013f94 as +0001435a cc +000143ba __cc +000146b3 vm_print +000148b4 eval +00014d53 vm_setup +00014d98 vm_init +00014df7 vm_free +00014e2a vm_setup_stack +00014e88 lex_get_error +00014e99 next +000154b4 match +00015506 expression +00016921 statement +00016b2e function_parameter +00016cf4 function_body +00016f07 function_declaration +00016f94 enum_declaration +000170aa global_declaration +000172db lex_init +0001737a program +0001741f find_mp_floating_ptr +0001745f smp_parse +000175a9 kb_get_char +000175f7 kb_add_char +00017636 kb_callback +00017867 init_keyboard +000178e2 pcb_await +00017910 __pcb_get_free +000179d6 __add_systemcall_pcb_await +000179f1 __pcb_free +00017a40 __pcb_init_kernel_stack +00017aa1 __pcb_init_process +00017b66 init_pcbs +00017bbb pcb_total_usage +00017bdc pcb_get_info +00017cc2 pcb_kill +00017ce3 Genesis +00017ce9 idletask +00017d08 pcb_get_by_pid +00017d1d pcb_get_by_name +00017d7a pcb_dbg_print +00017df8 pcb_cleanup_routine +0001800d pcb_create_thread +00018109 pcb_create_process +000183a2 pcb_create_kthread +00018688 start_pcb +000186c4 __pcb_queue_peek +00018707 __pcb_queue_pop +00018767 __pcb_queue_remove +000187dd __pcb_queue_add +0001885a __pcb_queue_push +000188f7 pcb_new_queue +0001892c get_mem_info +00018988 memory_map_init +00018a54 memory_map_get +00018a5e free +00018ab9 malloc +00018b59 calloc +00018b90 krealloc +00018c00 init_memory +00018c96 vmem_free +00018d0a vmem_alloc +00018d7b vmem_free_page_region +00018ee4 vmem_page_region_alloc +00018f1f vmem_create_page_region +00019062 vmem_free_allocations +0001918a vmem_continious_allocation_map +00019194 vmem_free_allocation +00019199 vmem_stack_free +0001924e vmem_stack_alloc +000195f8 vmem_dump_heap +00019691 vmem_init_process_thread +00019786 vmem_init_process +00019ab3 vmem_cleanup_process_thead +00019b2e vmem_cleanup_process +00019d1e vmem_init_kernel +00019edf vmem_allocator_create +00019f49 vmem_map_driver_region +00019fcb vmem_total_usage +00019fe2 vmem_init +0001a11a kalloc +0001a2b5 kcalloc +0001a2eb kfree +0001a385 palloc +0001a3d5 pmemory_used +0001a3f6 kmemory_used +0001a400 kmemory_total +0001a410 kmem_init +0001a4b1 e1000_receive +0001a58d e1000_transmit +0001a653 e1000_callback +0001a67e _e1000_tx_init +0001a726 _e1000_rx_init +0001a7c4 e1000_attach +0001aa17 display_get_info +0001aa85 kenv_init +0001aaa0 kenv_set +0001aadc config_list +0001abc2 kernel_config_load +0001af90 config_get_value +0001b053 spin_lock +0001b077 spin_unlock +0001b089 mutex_init +0001b0ab acquire +0001b14c release +0001b1f2 kthread_entry +0001b250 kthread_list +0001b2bb register_kthread +0001b398 start +0001b43e ata_primary +0001b443 ata_secondary +0001b448 ata_wait +0001b4c2 ata_write +0001b634 ata_read +0001b7b2 ata_ide_init +0001b986 set_bitmap +0001b9ac unset_bitmap +0001b9d4 get_bitmap +0001b9fa get_bitmap_size +0001ba12 create_bitmap +0001ba4a destroy_bitmap +0001ba61 bitmap_unset_continous +0001ba9e bitmap_get_continous +0001bb38 get_free_bitmap +0001bb91 __rtc_check_in_progress +0001bbb8 __rtc_get_register +0001bbdc get_current_time +0001bd25 get_time +0001bd53 init_tss +0001bd85 __add_systemcall_sys_system +0001bda0 exec_cmd +0001bef9 sys_system +0001bf0d __ksymbol_exec_cmd +0001bf2b system_reboot +0001bf63 align_to_pointer_size +0001bf75 calculate_size_unit +0001bfd5 advanced_hash +0001c010 kernel_panic +0001c032 kref_init +0001c050 kref_get +0001c07c kref_put +0001c0a8 csprintf +0001c2a6 script_parse +0001c378 login +0001c71a __login_create_virt_disk +0001c748 __register_kthread_login +0001c766 help +0001ca0b clear +0001ca30 __ksymbol_new +0001ca4e __ksymbol_list +0001ca6c __ksymbol_color +0001ca8a __ksymbol_about +0001caa8 __ksymbol_help +0001cac6 __ksymbol_kevents +0001cae4 __ksymbol_view +0001cb02 __ksymbol_file +0001cb20 __ksymbol_tcp +0001cb3e __ksymbol_conf +0001cb5c __ksymbol_clear +0001cb7a __ksymbol_services +0001cb98 __ksymbol_reboot +0001cbb6 kevents +0001cc94 services +0001cec6 new +0001d00b list +0001d10f file +0001d2e1 color +0001d386 about +0001d3c7 view +0001d5e0 tcp +0001d8c1 __tcp_reader +0001d9e6 conf +0001dcb2 reboot +0001dcef attach_disk_dev +0001dd17 disk_attached +0001dd23 disk_name +0001dd30 disk_device_get +0001dd3a disk_size +0001dd5a write_block +0001dd9b write_block_offset +0001dde2 read_block +0001de23 read_block_offset +0001de91 sched_consume +0001ded6 sched_add +0001df34 sched_prioritize +0001dfed sched_round_robin +0001e1d3 sched_exit +0001e290 sched_block +0001e3b2 sched_default +0001e48d sched_sleep +0001e537 sched_init_default +0001e5bc get_scheduler +0001e5c6 kernel_sleep +0001e5e5 kernel_yield +0001e62c kernel_exit +0001e662 block +0001e68f unblock +0001e694 work_queue_add +0001e798 init_worker +0001e7b4 worker_thread +0001e857 __ring_buffer_add +0001e903 __ring_buffer_read +0001ea11 rbuffer_new +0001ea7e rbuffer_free +0001eaa4 error_get_string +0001eae4 kclock +0001efbf __register_kthread_kclock +0001efdd tar_extract +0001f22d __ksymbol_tar +0001f24b tar_list +0001f356 tar +0001f5e3 rgb_to_vga +0001f5f7 rgb_to_components +0001f622 color_distance_squared +0001f692 rgb_init_color_table +0001f71d iface_loopback_write +0001f7e2 iface_loopback_interrupt +0001f7fd iface_loopback_read +0001f8a7 net_init_loopback +0001f8c2 serial_put +0001f906 serial_write +0001f94c serial_printf +0001fb00 init_serial +0001fbca inportb +0001fbd7 inportw +0001fbe5 inportl +0001fbf2 outportb +0001fc02 outportw +0001fc13 outportl +0001fc23 sys_create_thread +0001fc46 __add_systemcall_sys_create_thread +0001fc55 add_system_call +0001fc99 system_call +0001fd08 hashmap_put +0001fd74 hashmap_get +0001fdfc hashmap_add +0001fe8a hashmap_free +0001fe8f reset_vga_palette +0001fed9 vga_set_palette +0001ffc8 b8to16 +0001ffde vesa_put_pixel +0002000c vesa_put_box +00020086 vesa_put_block +00020100 vesa_put_char +0002017a vesa_put_char16 +00020212 vesa_put_icon16 +0002028d vesa_write +000202d0 vesa_write_str +00020302 vesa_fill +00020386 vesa_fillrect +000203f5 vesa_inner_box +00020501 vesa_printf +0002078d ksyms_init +000209ac ksyms_add_symbol +00020a69 __ksymbol_backtrace +00020a87 ksyms_list +00020aed ksyms_resolve_symbol +00020ba4 __backtrace_from +00020cc2 backtrace +00020cd7 ws_fullscreen +00020e55 ws_remove +00020f09 ws_add +00020ff8 ws_destroy +000210a2 ws_draw +00021353 ws_raw_wallpaper +0002143d ws_set_background_file +0002171d ws_init +00021804 ws_set_background +000218b3 ws_new +00021944 encode_run_length +000219cd decode_run_length +00021a44 __mouse_handler +00021b5c mouse_wait +00021ba4 mouse_write +00021be6 mouse_get_event +00021c2b mouse_init +00021d14 sys_ipc_open +00021d66 __add_systemcall_sys_ipc_open +00021d81 __add_systemcall_sys_ipc_close +00021d9c __add_systemcall_sys_ipc_send +00021db7 __add_systemcall_sys_ipc_receive +00021dd2 sys_ipc_close +00021e1f sys_ipc_send +00021e8a sys_ipc_receive +00021ef4 sysinf +00022c60 __register_kthread_sysinf +00022c7e echo +00022cbd res +00022d02 ifconfig +00022d13 __ksymbol_ifconfig +00022d31 __ksymbol_ps +00022d4f __ksymbol_tree +00022d6d __ksymbol_fat16 +00022d8b __ksymbol_xxd +00022da9 __ksymbol_sh +00022dc7 __ksymbol_ed +00022de5 __ksymbol_exec +00022e03 __ksymbol_ths +00022e21 __ksymbol_dns +00022e3f __ksymbol_th +00022e5d __ksymbol_kill +00022e7b __ksymbol_echo +00022e99 __ksymbol_fdisk +00022eb7 __ksymbol_meminfo +00022ed5 __ksymbol_res +00022ef3 __ksymbol_bg +00022f11 __ksymbol_exit +00022f2f __ksymbol_socks +00022f4d __ksymbol_reset +00022f6b exit +00022fa3 ps +0002321b print_pcb_tree +0002331a tree +0002335e fat16 +0002338a xxd +00023483 sh +00023587 ed +000235d8 exec +00023742 ths +000237b2 dns +0002382a th +0002384c kill +0002386e fdisk +00023a04 meminfo +00023be7 bg +00023c6a socks +00023f13 __register_kthread_shell +00023f31 __register_kthread_textshell +00023f4f shell_clear +00023f96 reset_shell +0002400b reset +00024063 shell_put +00024249 shell +000244ae cleanup_function +000244d9 testfn +00024511 draw_box +000245fa __textshell_reset_box +0002468a textshell +00024a5b __net_find_interface +00024abb net_drop_packet +00024adc net_handle_recieve +00024c07 net_get_interfaces +00024c11 net_configure_iface +00024c67 net_incoming_packet +00024d19 net_get_iface +00024d95 net_iface_up +00024dc0 net_iface_down +00024deb net_list_ifaces +00024f09 net_register_interface +00024f3e net_send_skb +00024fca net_get_info +00024ff5 networking_main +000251d5 __dhcp_add_option +0002523f __dhcp_send_discovery +00025381 __dhcp_send_request +000254fe dhcp_get_state +0002550a dhcp_get_dns +00025514 dhcp_get_ip +0002552d dhcp_get_gw +00025546 dhcpd +000257da udp_server +00025869 tcp_server +000259e1 __net_terminal_writef +00025a4a __register_kthread_tcp_server +00025a68 __register_kthread_udp_server +00025a86 __register_kthread_udptest +00025aa4 udptest +00025b33 tcpd +00025c1b logd +00025c8a __register_kthread_logd +00025ca8 logd_attach_by_pid +00025cf0 taskbar_reboot +00025d20 __reboot +00025d39 taskbar_readme +00025d56 taskbar_about +00025d73 taskbar_clock +00025d90 taskbar_sysinf +00025dad taskbar_bg_retro +00025de8 taskbar_bg_lotr2 +00025e01 taskbar_bg_lotr +00025e1a taskbar_bg_default_color_gray +00025e30 taskbar_bg_default_color +00025e46 taskbar_wolfstein +00025e85 taskbar_bg_graph +00025ec4 taskbar_bg_calc +00025f03 taskbar_colors +00025f42 taskbar_cube +00025f81 taskbar_editor +00025fc0 taskbar_finder +00025fff taskbar_terminal +0002604c __register_kthread_taskbar +0002606a taskbar_hdr_opt_event +000260f4 taskbar +00026701 about +000268d0 __register_kthread_about +000268ee __register_kthread_readme +0002690c readme +00026a72 gfx_default_hover +00026ba0 gfx_draw_window +000279bb gfx_destory_window +00027a4c gfx_window_resize +00027af9 gfx_window_maximize +00027b76 gfx_default_mouse_up +00027c48 gfx_default_mouse_down +00027d0e gfx_default_click +00027f01 gfx_window_set_resizable +00027f1a kernel_gfx_window_border_color +00027f49 gfx_new_window +000281b0 gfx_point_in_rectangle +000281e1 gfx_draw_component +00028227 gfx_input_event +00028348 gfx_input_draw +00028454 gfx_input_manager_add +000284b9 gfx_composition_remove_window +000284e7 gfx_composition_add_window +00028532 gfx_set_background_color +00028587 gfx_raw_background +000285d8 gfx_decode_background_image +00028629 gfx_set_taskbar +000286cd gfx_compositor_main +00028745 kernel_gfx_draw_circle_helper +000289bc gfx_get_window_width +000289d5 gfx_get_window_height +000289ee gfx_push_event +00028ab5 gfx_put_icon16 +00028bad gfx_put_icon32 +00028ca3 gfx_event_loop +00028dc9 kernel_gfx_draw_rectangle +00028ecb kernel_gfx_draw_contoured_box +00028f6f kernel_gfx_draw_pixel +00029018 kernel_gfx_draw_bitmap +0002913d kernel_gfx_draw_char +00029227 kernel_gfx_set_position +00029247 gfx_commit +00029264 kernel_gfx_draw_text +0002931b gfx_button_ext +00029452 gfx_button +00029474 kernel_gfx_set_title +000294e4 kernel_gfx_set_header +00029554 kernel_gfx_draw_line +000296ee kernel_gfx_draw_circle +00029771 kernel_gfx_draw_section +0002977b kernel_gfx_draw_format_text +00029acd gfx_syscall_hook +00029c89 gfx_total_themes +00029c93 kernel_gfx_current_theme +00029c9d kernel_gfx_update_theme +00029d6f kernel_gfx_default_theme +00029d79 kernel_gfx_set_theme +00029da2 kernel_gfx_get_theme +00029dc1 gfx_new_ctx +00029e21 gfx_init_framebuffer +00029f91 netdev_attach_driver +0002a03e is_netdev_attached +0002a050 netdev_transmit +0002a06f netdev_recieve +0002a09c net_ethernet_add_header +0002a134 net_ethernet_parse +0002a1af __skb_queue_remove +0002a1f1 __skb_queue_add +0002a245 skb_free_queue +0002a281 skb_new_queue +0002a2ec skb_free +0002a32b skb_new +0002a39a skb_consume +0002a3cf __net_arp_send +0002a48f net_init_arp +0002a4df net_arp_add_entry +0002a577 net_arp_find_entry +0002a5c6 net_arp_respond +0002a63f net_net_arp_request +0002a6c9 arp_parse +0002a777 net_ipv4_print +0002a781 net_ipv4_add_header +0002a8bc net_is_ipv4 +0002a8fd net_ipv4_parse +0002aa2e ntohl +0002aa5e htonl +0002aa75 ntohs +0002aa86 htons +0002aa97 checksum +0002aaf2 transport_checksum +0002ab4b ip_to_int +0002abed net_icmp_handle +0002acb6 net_icmp_response +0002acc0 net_icmp_request +0002ad87 ping +0002ade4 net_icmp_parse +0002ae58 net_udp_send +0002af91 net_udp_parse +0002b0bd socket_type_to_str +0002b0d0 socket_domain_to_str +0002b0e3 socket_protocol_to_str +0002b0f6 net_sock_bind +0002b145 net_get_sockets +0002b165 sock_get +0002b18a get_total_sockets +0002b194 net_sock_is_established +0002b1dc net_sock_awaiting_ack +0002b224 net_sock_data_ready +0002b27f net_sock_read +0002b384 net_sock_add_data +0002b5e8 sock_find_listen_tcp +0002b630 net_sock_find_tcp +0002b823 net_prepare_tcp_sock +0002b8b3 net_sock_accept +0002b8ca net_socket_find_udp +0002b939 kernel_sock_shutdown +0002b96a kernel_sock_cleanup +0002b9f4 kernel_sock_close +0002ba2c kernel_socket_create +0002bbb3 net_init_sockets +0002bbfd gethostname +0002c12b __add_systemcall_gethostname +0002c146 net_init_dns +0002c179 route +0002c1ca tcb_init +0002c1ec tcb_new +0002c35c tcp_state_to_str +0002c379 tcp_new_connection +0002c405 tcp_free_connection +0002c42c tcp_is_listening +0002c446 tcp_set_listening +0002c4aa tcp_calculate_checksum +0002c573 __tcp_send +0002c68f tcp_send_segment +0002c7d6 tcp_accept_connection +0002c91c tcp_send_ack +0002ca54 tcp_read +0002ca5e tcp_recv_segment +0002ca68 tcp_connect +0002cb0f tcp_send_syn +0002cb19 tcp_recv_ack +0002cba0 tcp_recv_fin +0002cbaa tcp_recv_syn +0002cce0 tcp_send_fin +0002cdb0 tcp_close_connection +0002cdf3 tcp_parse +0002d28f kernel_bind +0002d2c8 kernel_recvfrom +0002d2d2 kernel_recv +0002d348 kernel_recv_timeout +0002d372 kernel_connect +0002d478 kernel_sendto +0002d536 kernel_accept +0002d59d kernel_listen +0002d5c9 kernel_send +0002d653 sys_kernel_bind +0002d689 __add_systemcall_sys_kernel_bind +0002d6a4 __add_systemcall_sys_kernel_accept +0002d6bf __add_systemcall_sys_kernel_connect +0002d6da __add_systemcall_sys_kernel_listen +0002d6f5 __add_systemcall_sys_kernel_recv +0002d710 __add_systemcall_sys_kernel_recvfrom +0002d72b __add_systemcall_sys_kernel_recv_timeout +0002d746 __add_systemcall_sys_kernel_send +0002d761 __add_systemcall_sys_kernel_sendto +0002d77c __add_systemcall_sys_socket_create +0002d797 __add_systemcall_sys_kernel_sock_close +0002d7b2 sys_kernel_accept +0002d7f6 sys_kernel_connect +0002d82c sys_kernel_listen +0002d85f sys_kernel_recv +0002d89b sys_kernel_recvfrom +0002d8df sys_kernel_recv_timeout +0002d921 sys_kernel_send +0002d95d sys_kernel_sendto +0002d9a1 sys_socket_create +0002d9cc sys_kernel_sock_close +0002da11 __iface_send +0002da44 __iface_recieve +0002da77 __iface_assign +0002da8e __iface_detach +0002daa6 __iface_set_gateway +0002dabd __iface_set_netmask +0002dad4 __iface_configure +0002db28 __iface_attach +0002db51 net_interface_create +0002db8d net_register_netdev +0002dca9 net_interface_destroy +0002dcc2 __default_restart +0002dccc __default_stop +0002dd35 __default_start +0002ddb8 nm_new +0002de45 nm_free +0002de8e net_firewall_create +0002deb5 fs_file2fd +0002df1e fs_alloc_file +0002df6d fs_free_file +0002dfcb fs_register +0002e09e fs_init +0002e0a8 fs_unregister +0002e10f fs_get +0002e119 fs_close +0002e18f fs_open +0002e20d fs_seek +0002e28e fs_read +0002e3a7 fs_load_from_file +0002e437 fs_write +0002e4f6 fs_save_to_file +0002e586 fat16_rmdir +0002e590 fat16_stat +0002e59a fat16_close +0002e608 fat16_rename +0002e6a1 fat16_mkdir +0002e78a fat16_remove +0002e801 fat16_open +0002e94f fat16_read +0002eab2 fat16_write +0002ebe5 fat16_list +0002eeb7 fat16_init +0002ef6f path_next_iter +0002efdd inode_from_path_recursise +0002f05b inode_from_path +0002f11d ext_get_root +0002f12a ext_get_current_dir +0002f13d ext_get_size +0002f147 ext_get_inodes +0002f151 ext_get_blocks +0002f15b ext_sync +0002f1d2 ext_create +0002f2c1 ext_read +0002f340 ext_seek +0002f38b ext_write +0002f3fb ext_close +0002f461 ext_open_from_directory +0002f569 ext_open +0002f624 ext_size +0002f651 change_directory +0002f6bb ext_create_directory +0002f859 ext_create_file_system +0002fb2a init_ext +0002fcca listdir +0002fdf1 __inode_sync +0002fe54 __inode_cache_insert +0002ff4a __inode_load +0002ffbe inodes_sync +0002fffd inode_get +0003005e inode_read +0003024e inode_write +000304b5 alloc_inode +00030572 mkdir +00030623 sync +0003065b mkfs +0003066c fat16_read_data_from_cluster +000306be fat16_read_data +0003079b fat16_find_cluster_by_offset +0003081a fat16_write_data_to_cluster_with_offset +00030859 fat16_print_cluster_chain +0003088b fat16_write_data_to_cluster +000308c2 fat16_write_data +000309dd get_fat_start_block +000309e9 get_root_directory_start_block +000309fc get_data_start_block +00030a12 fat16_get_fat_entry +00030a31 fat16_set_fat_entry +00030a75 fat16_sync_fat_table +00030af1 fat16_allocate_cluster +00030b0d fat16_free_cluster +00030b26 fat16_get_free_cluster +00030b7f fat16_sync_directory_entry +00030c06 fat16_read_entry +00030cb7 fat16_find_entry +00030df2 fat16_rename_entry +00030e67 fat16_free_clusters +00030eb2 fat16_delete_entry +00030f1d fat16_add_entry +00031088 fat16_used_blocks +000310c5 fat16_to_upper +000310f5 fat16_name_compare +00031210 sstrtok +000312d3 fat16_directory_entry_debug +000313aa fat16_get_directory_entry +000315b3 fat16_create_directory +000316bc fat16_read_file +00031711 fat16_create_file +00031793 fat16_create_empty_file +0003185b fat16_directory_entries +00031946 fat16_mbr_clear +00031a11 fat16_mbr_add_entry +00031b06 fat16_print_root_directory_entries +00031b22 fat16_change_directory +00031bae fat16_bootblock_info +00031d2f fat16_set_time +00031d67 fat16_set_date +00031da3 fat16_load +00031f26 fat16_format +000321df mbr_partition_type_string +00032267 mbr_partitions_parse +00032335 mbr_get +0003233f mbr_partition_load +00032361 __list_users +000323f6 __change_user +0003249c __remove_user +0003254c __add_user +0003263a __find_user +0003270d __authenticate_user +00032820 __save_users +000328a8 __load_users +00032aae __ksymbol_admin +00032acc admin +00032de4 usermanager_create +00032e07 __ksymbol_snakegame +00032e25 init_game +00032e75 draw +00032ed5 get_input +00032ef8 update +00033084 game_loop +000330ae snakegame +000330fd __msgbox +00033510 msgbox_create +00033547 msgbox_show +00033593 kevents_list +00033709 kevents_init +0003374f kevents_destroy +000337a8 kevents_add +00033863 kevents_create +000338ea __ksymbol_editor +00033908 textbuffer_destroy +0003397f textbuffer_new_line +00033a35 textbuffer_handle_char +00033fea textbuffer_display +000340ce editor +00034244 _code_end From 8542a4112e5a7a858f7274d5370405c1f17b178e Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Tue, 6 Feb 2024 14:00:23 +0100 Subject: [PATCH 15/23] New textmode editor and small bug fixes --- Makefile | 2 +- admin/usermanager.c | 4 +- apps/Makefile | 4 +- apps/texed/Makefile | 53 ++ apps/texed/include/screen.h | 58 ++ apps/texed/screen.c | 163 ++++ apps/texed/texed.c | 482 ++++++++++ drivers/vga.c | 2 +- include/screen.h | 2 +- include/syscall_helper.h | 5 +- include/usermanager.h | 1 + kernel/edit.c | 463 --------- kernel/kthreads/login.c | 59 +- kernel/kthreads/shell.c | 23 +- kernel/memory.c | 15 +- kernel/pcb.c | 4 +- kernel/syscalls.c | 36 + rootfs/symbols.map | 1774 ++++++++++++++++++----------------- rootfs/sysutil/default.cfg | 5 +- rootfs/sysutil/startup.sh | 2 +- rootfs/sysutil/symbols.map | 2 +- 21 files changed, 1768 insertions(+), 1391 deletions(-) create mode 100644 apps/texed/Makefile create mode 100644 apps/texed/include/screen.h create mode 100644 apps/texed/screen.c create mode 100644 apps/texed/texed.c delete mode 100644 kernel/edit.c diff --git a/Makefile b/Makefile index 5441216..37f5513 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ KERNELOBJ = bin/kernel.o bin/terminal.o bin/helpers.o bin/pci.o bin/virtualdisk. bin/diskdev.o bin/scheduler.o bin/work.o bin/rbuffer.o bin/errors.o bin/kclock.o bin/tar.o bin/color.o bin/loopback.o \ bin/serial.o bin/io.o bin/syscalls.o bin/list.o bin/hashmap.o bin/vbe.o bin/ksyms.o bin/windowserver.o bin/encoding.o\ bin/mouse.o bin/ipc.o bin/sysinf.o ${PROGRAMOBJ} ${GFXOBJ} bin/font8.o bin/net.o bin/fs.o bin/ext.o bin/fat16.o bin/partition.o\ - bin/admin.o bin/usermanager.o bin/user.o bin/group.o bin/snake.o bin/msgbox.o bin/kevents.o bin/edit.o + bin/admin.o bin/usermanager.o bin/user.o bin/group.o bin/snake.o bin/msgbox.o bin/kevents.o BOOTOBJ = bin/bootloader.o diff --git a/admin/usermanager.c b/admin/usermanager.c index bbb2e0e..985dcef 100644 --- a/admin/usermanager.c +++ b/admin/usermanager.c @@ -27,6 +27,7 @@ static int __list_users(struct usermanager* usrman); static int __load_users(struct usermanager* usrman); static int __save_users(struct usermanager* usrman); static struct user* __authenticate_user(struct usermanager* usrman, const char* username, const char* password); +static struct user* __find_user(struct usermanager* usrman, const char* username); /* consts */ static const char* userdb = "/sysutil/users.db"; @@ -37,7 +38,8 @@ static struct user_manager_ops default_ops = { .list = __list_users, .load = __load_users, .save = __save_users, - .authenticate = __authenticate_user + .authenticate = __authenticate_user, + .get = __find_user }; static const struct userdb default_db = { .magic = USRMAN_MAGIC, diff --git a/apps/Makefile b/apps/Makefile index 272bdc0..d807b39 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -33,7 +33,7 @@ UTILS = bin/cppUtils.o bin/crt0.o USROBJS = COMMON = ../bin/syscall.o ../bin/libc.o ../bin/printf.o ../bin/graphics.o ../bin/netlib.o bin/cppUtils.o -LIB_COMMON_OBJS = ../bin/syscall.o ../bin/libc.o ../bin/printf.o bin/cppUtils.o +LIB_COMMON_OBJS = ../bin/syscall.o ../bin/libc.o ../bin/printf.o LIB_GRAPHICS_OBJS = ../bin/graphics.o ../bin/libc.o LIB_NET_OBJS = ../bin/netlib.o @@ -57,6 +57,7 @@ programs: staticlibs bin/crt0.o ${USROBJS} @make -C graphs/ @make -C cube/ @make -C users/ + @make -C texed/ @echo [USR] All user programs created and linked! bin/%.o: utils/%.cpp @@ -85,4 +86,5 @@ clean: @make -C graphs/ clean @make -C cube/ clean @make -C users/ clean + @make -C texed/ clean rm -f .depend diff --git a/apps/texed/Makefile b/apps/texed/Makefile new file mode 100644 index 0000000..a493770 --- /dev/null +++ b/apps/texed/Makefile @@ -0,0 +1,53 @@ +### RetrOS-32 v0.0.1 Makefile ### +# This makefile only works in the +# RetrOS-32 Environment. It depends +# on static libraries. +################################## +ROOT = ../../ + +CCFLAGS=-m32 -O2 -Wall -Wextra -Wpedantic -Wstrict-aliasing \ + -Wno-pointer-arith -Wno-unused-parameter -nostdlib \ + -nostdinc -ffreestanding -fno-pie -fno-stack-protector \ + -fno-builtin-function -fno-builtin -I $(ROOT)include/ -I $(ROOT)apps/ +MAKEFLAGS += --no-print-directory +UNAME := $(shell uname) +ifeq ($(UNAME),Linux) + CC=gcc + CPP=g++ + AS=as + LD=ld + + CCFLAGS += -elf_i386 + ASFLAGS += --32 + LDFLAGS += -m elf_i386 +else + CC=i386-elf-gcc + CPP=i386-elf-g++ + AS=i386-elf-as + LD=i386-elf-ld +endif + +#### ONLY EDIT THIS #### +OUTPUT = texed.o +LIBS = -lcore +EXTENDED = +######################## + +SRC_FILES = $(wildcard *.c) +OBJ_FILES = $(SRC_FILES:%.c=$(OUTPUTDIR)%.o) +OUTPUTDIR = ./bin/ + +all: $(OUTPUT) install + +install: $(OUTPUT) + @cp $(OUTPUT) $(ROOT)rootfs/bin + +$(OUTPUT): $(OBJ_FILES) + $(LD) -o $@ $(LDFLAGS) $^ -L$(ROOT)apps $(LIBS) $(EXTENDED) -T $(ROOT)apps/utils/linker.ld + +$(OUTPUTDIR)%.o: %.c + @mkdir -p $(OUTPUTDIR) + $(CC) $(CCFLAGS) -c $< -o $@ + +clean: + rm -rf $(OUTPUTDIR)* *.o *.d $(OUTPUT) .depend diff --git a/apps/texed/include/screen.h b/apps/texed/include/screen.h new file mode 100644 index 0000000..1c5f6fe --- /dev/null +++ b/apps/texed/include/screen.h @@ -0,0 +1,58 @@ +#ifndef __TEXED_SCREEN_H__ +#define __TEXED_SCREEN_H__ + +#include + +#define SCREEN_WIDTH 80 +#define SCREEN_HEIGHT 25 + +#define ARROW_UP 254 +#define ARROW_DOWN 253 +#define ARROW_LEFT 252 +#define ARROW_RIGHT 251 +#define F1 250 +#define F2 249 /* CTRL y */ +#define F3 248 +#define F4 247 /* CTRL w */ +#define F5 246 +#define F6 245 +#define F7 244 /* CTRL t */ +#define F8 243 +#define F9 242 /* CTRL r */ +#define F10 241 /* CTRL q */ + +#define TAB 9 + +#define CTRLC 227 +#define CTRLE 229 + +#define COLOR(fg, bg) (fg | bg << 4) + +enum vga_color { + VGA_COLOR_BLACK = 0, + VGA_COLOR_BLUE = 1, + VGA_COLOR_GREEN = 2, + VGA_COLOR_CYAN = 3, + VGA_COLOR_RED = 4, + VGA_COLOR_MAGENTA = 5, + VGA_COLOR_BROWN = 6, + VGA_COLOR_LIGHT_GREY = 7, + VGA_COLOR_DARK_GREY = 8, + VGA_COLOR_LIGHT_BLUE = 9, + VGA_COLOR_LIGHT_GREEN = 10, + VGA_COLOR_LIGHT_CYAN = 11, + VGA_COLOR_LIGHT_RED = 12, + VGA_COLOR_LIGHT_MAGENTA = 13, + VGA_COLOR_LIGHT_BROWN = 14, + VGA_COLOR_WHITE = 15, +}; + +int screen_put_char(int x, int y, unsigned char c, unsigned char color); +int screen_write(int x, int y, const char* str, unsigned char color); +int screen_printf(int x, int y, unsigned char color, char* fmt, ...); +char screen_get_char(); +int screen_clear(int from , int to, unsigned char color); +void screen_draw_box(int x, int y, int width, int height, char border_color); +int screen_clear_line(int y, unsigned char color); + +#endif // __TEXED_SCREEN_H__ \ No newline at end of file diff --git a/apps/texed/screen.c b/apps/texed/screen.c new file mode 100644 index 0000000..2f046b0 --- /dev/null +++ b/apps/texed/screen.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include + +#include "../include/screen.h" + +#define MAX_FMT_STR_SIZE 256 + +/* Macro to serialize a character and a color into a short */ +/* Only platform depedent syscall needed */ +int screen_put_char(int x, int y, unsigned char c, unsigned char color) +{ + return invoke_syscall(SYSCALL_SCREEN_PUT, x, y, (((unsigned short)(c) << 8) | (unsigned char)(color))); +} + +char screen_get_char() +{ + return invoke_syscall(SYSCALL_SCREEN_GET, 0, 0, 0); +} + +int screen_write(int x, int y, const char* str, unsigned char color) +{ + int i = 0; + while(str[i] != '\0'){ + screen_put_char(x+i, y, str[i], color); + i++; + } + return i; +} + +int screen_clear_line(int y, unsigned char color) +{ + for (int x = 1; x < SCREEN_WIDTH-1; x++){ + screen_put_char(x, y, ' ', color); + } +} + +int screen_clear(int from , int to, unsigned char color) +{ + for (int y = 2; y < SCREEN_HEIGHT-2; y++){ + for (int x = 1; x < SCREEN_WIDTH-1; x++){ + screen_put_char(x, y, ' ', color); + } + } +} + +int screen_set_cursor(int x, int y) +{ + return invoke_syscall(SYSCALL_SET_CURSOR, x, y, 0); +} + + +void screen_draw_box(int x, int y, int width, int height, char border_color) { + // Extended ASCII characters for double line box drawing + unsigned char top_left = 201; // '╔' + unsigned char top_right = 187; // '╗' + unsigned char bottom_left = 200; // '╚' + unsigned char bottom_right = 188; // '╝' + unsigned char horizontal = 205; // '═' + unsigned char vertical = 186; // '║' + + // Draw corners + screen_put_char(x, y, top_left, border_color); + screen_put_char(x + width - 1, y, top_right, border_color); + screen_put_char(x, y + height - 1, bottom_left, border_color); + screen_put_char(x + width - 1, y + height - 1, bottom_right, border_color); + + // Draw top and bottom borders with connectors + for (int i = x + 1; i < x + width - 1; ++i) { + screen_put_char(i, y, horizontal, border_color); // Top border + screen_put_char(i, y + height - 1, horizontal, border_color); // Bottom border + } + + // Draw left, right borders, and connectors + for (int i = y + 1; i < y + height - 1; ++i) { + screen_put_char(x, i, vertical, border_color); // Left border + screen_put_char(x + width - 1, i, vertical, border_color); // Right border + } +} + +/** + * Writes the given string with formats to screen on give location. + * @param int x coordinate + * @param int y coordinate + * @param char* format string + * @param ... variable parameters + * @return number of bytes written + */ +int screen_printf(int x, int y, unsigned char color, char* fmt, ...) +{ + va_list args; + + int x_offset = 0; + int written = 0; + char str[MAX_FMT_STR_SIZE]; + int num = 0; + + va_start(args, fmt); + + while (*fmt != '\0') { + switch (*fmt){ + case '%': + memset(str, 0, MAX_FMT_STR_SIZE); + switch (*(fmt+1)){ + case 'd': + case 'i': ; + num = va_arg(args, int); + itoa(num, str); + screen_write(x+x_offset, y, str, color); + x_offset += strlen(str); + break; + case 'p': ; /* p for padded int */ + num = va_arg(args, int); + itoa(num, str); + screen_write(x+x_offset, y, str, color); + x_offset += strlen(str); + + if(strlen(str) < 3){ + int pad = 3-strlen(str); + for (int i = 0; i < pad; i++){ + screen_put_char(x+x_offset, y, ' ', color); + x_offset++; + } + } + break; + case 'x': + case 'X': ; + num = va_arg(args, int); + itohex(num, str); + screen_write(x+x_offset, y, str, color); + x_offset += strlen(str); + break; + case 's': ; + char* str_arg = va_arg(args, char *); + screen_write(x+x_offset, y, str_arg, color); + x_offset += strlen(str_arg); + break; + case 'c': ; + char char_arg = (char)va_arg(args, int); + screen_put_char(x+x_offset, y, char_arg, color); + x_offset++; + break; + default: + break; + } + fmt++; + break; + case '\n': + y++; + written += x_offset; + x_offset = 0; + break; + default: + screen_put_char(x+x_offset, y, *fmt, color); + x_offset++; + written++; + } + fmt++; + } + written += x_offset; + return written; +} \ No newline at end of file diff --git a/apps/texed/texed.c b/apps/texed/texed.c new file mode 100644 index 0000000..5ff9664 --- /dev/null +++ b/apps/texed/texed.c @@ -0,0 +1,482 @@ +#include +#include +#include +#include +#include + +#include "include/screen.h" + +#define MAX_LINES 512 +#define LINE_CAPACITY 78 +#define MAX_VISABLE_LINES 21 + +typedef enum __line_flags { + LINE_FLAG_NONE = 1 << 0, + LINE_FLAG_DIRTY = 1 << 1, + LINE_FLAG_EXTENSION = 1 << 2, +} line_flags_t; + +struct textbuffer { + struct textbuffer_ops { + int (*destroy)(struct textbuffer *buffer); + int (*display)(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg); + int (*put)(struct textbuffer *buffer, unsigned char c); + } *ops; + struct line { + char *text; + size_t length; + size_t capacity; + line_flags_t flags; + } **lines; + struct cursor { + size_t x; + size_t y; + } cursor; + struct scroll { + size_t start; + size_t end; + } scroll; + size_t line_count; + char filename[256]; +}; + +/* Function prototypes */ +static int textbuffer_new_line(struct textbuffer *buffer); +static int textbuffer_remove_last_line(struct textbuffer *buffer); +static int textbuffer_free_line(struct textbuffer *buffer, size_t line); +static int textbuffer_destroy(struct textbuffer *buffer); +static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg); +static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c); + +static struct textbuffer_ops textbuffer_default_ops = { + .destroy = textbuffer_destroy, + .display = textbuffer_display, + .put = textbuffer_handle_char, +}; + +static struct textbuffer *textbuffer_create(void) { + int ret; + struct textbuffer *buffer = malloc(sizeof(struct textbuffer)); + if (buffer == NULL) { + return NULL; + } + + buffer->lines = malloc(sizeof(struct line *) * MAX_LINES); + if (buffer->lines == NULL) { + free(buffer); + return NULL; + } + + ret = textbuffer_new_line(buffer); + if (ret < 0) { + free(buffer->lines); + free(buffer); + return NULL; + } + + buffer->ops = &textbuffer_default_ops; + buffer->cursor.x = 0; + buffer->cursor.y = 0; + buffer->scroll.start = 0; + buffer->scroll.end = MAX_VISABLE_LINES; + + return buffer; +} + +static int textbuffer_find(struct textbuffer *buffer, char *str) { + int ret; + /* find str in lines and goto line */ + for (size_t i = 0; i < buffer->line_count; i++) { + ret = strstr(buffer->lines[i]->text, str); + if (ret >= 0) { + buffer->cursor.y = i; + buffer->cursor.x = ret; + return 0; + } + } + + return -1; +} + +static int textbuffer_destroy(struct textbuffer *buffer) { + for (size_t i = 0; i < buffer->line_count; i++) { + if (buffer->lines[i]->text) { + free(buffer->lines[i]->text); + } + free(buffer->lines[i]); + } + free(buffer->lines); + free(buffer); + + return 0; +} + +static int textbuffer_new_line(struct textbuffer *buffer) { + if (buffer->line_count == MAX_LINES) { + return -1; + } + + buffer->lines[buffer->line_count] = malloc(sizeof(struct line)); + if (buffer->lines[buffer->line_count] == NULL) { + return -1; + } + + buffer->lines[buffer->line_count]->text = malloc(LINE_CAPACITY); + if (buffer->lines[buffer->line_count]->text == NULL) { + free(buffer->lines[buffer->line_count]); + return -1; + } + + memset(buffer->lines[buffer->line_count]->text, 0, LINE_CAPACITY); + + buffer->lines[buffer->line_count]->length = 0; + buffer->lines[buffer->line_count]->capacity = LINE_CAPACITY; + buffer->line_count++; + + return 0; +} + +static int textbuffer_remove_last_line(struct textbuffer *buffer) { + if (buffer->line_count == 0) { + return -1; + } + + free(buffer->lines[buffer->line_count - 1]->text); + free(buffer->lines[buffer->line_count - 1]); + buffer->line_count--; + + return 0; +} + +static int textbuffer_free_line(struct textbuffer *buffer, size_t line) { + if (line >= buffer->line_count) { + return -1; + } + + /* Move the content of all lines below current up one line */ + for (size_t i = line; i < buffer->line_count - 1; i++) { + memset(buffer->lines[i]->text, 0, buffer->lines[i]->capacity); + memcpy(buffer->lines[i]->text, buffer->lines[i + 1]->text, buffer->lines[i + 1]->length); + buffer->lines[i]->length = buffer->lines[i + 1]->length; + } + + /* Remove the last line */ + free(buffer->lines[buffer->line_count - 1]->text); + free(buffer->lines[buffer->line_count - 1]); + buffer->line_count--; + + return 0; +} + +static int textbuffer_save_file(struct textbuffer *buffer, const char *filename) { + return -1; + char* file = malloc(2048); + if (file == NULL) { + return -1; + } + + size_t len = 0; + for (size_t i = 0; i < buffer->line_count; i++) { + if (buffer->lines[i]->text) { + memcpy(file + len, buffer->lines[i]->text, buffer->lines[i]->length); + /* Add newline if not extension */ + if (!HAS_FLAG(buffer->lines[i]->flags, LINE_FLAG_EXTENSION)) { + file[len + buffer->lines[i]->length] = '\n'; + len++; + } + + len += buffer->lines[i]->length; + } + } + return 0; +} + +static int textbuffer_load_file(struct textbuffer *buffer, const char *filename){ + char* file = malloc(2048); + if (file == NULL) { + return -1; + } + + int fd = open(filename, FS_FILE_FLAG_CREATE | FS_FILE_FLAG_READ | FS_FILE_FLAG_WRITE); + if (fd < 0) { + return -1; + } + + int ret = read(fd, file, 2048); + if (ret < 0) { + fclose(fd); + return -1; + } + + fclose(fd); + + /* set filename */ + strcpy(buffer->filename, filename); + screen_printf(SCREEN_WIDTH/2 - strlen(filename)/2, 1, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE), filename); + + size_t len = ret; + for (size_t i = 0; i < len; i++) { + textbuffer_handle_char(buffer, file[i]); + } + + textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + + return 0; +} + +/* Function to display the content of the text buffer on the screen */ +static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg) { + uint32_t x_start = 0; + uint32_t y_start = buffer->scroll.start; + + /* Clear the screen before displaying new content */ + //screen_clear(0, 0, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + + /* fill top row with light grey */ + for (size_t i = 0; i < 80; i++) { + screen_put_char(i, 0, ' ', COLOR(VGA_COLOR_BLACK, VGA_COLOR_LIGHT_GREY)); + } + screen_printf(0, 0, COLOR(VGA_COLOR_BLACK, VGA_COLOR_LIGHT_GREY), " File Edit Search Help"); + + /* draw mode */ + screen_put_char(3, 1, '[', COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + screen_put_char(4, 1, 'R', COLOR(VGA_COLOR_GREEN, VGA_COLOR_BLUE)); + screen_put_char(5, 1, ']', COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + + /* write from start to end, or line_count */ + for (size_t i = 0; i + y_start < buffer->line_count && i < buffer->scroll.end; i++) { + /* Calculate the position for each line */ + int32_t x = x_start; + int32_t y = y_start + i; + + /* Write the line to the screen */ + if (!buffer->lines[y]->text) { + continue; + } + + screen_clear_line(2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + if (buffer->cursor.y == y) { + screen_printf(1+x, 2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE) , "%s %c", buffer->lines[y]->text, 27); + } else { + screen_printf(1+x, 2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE), "%s", buffer->lines[y]->text); + } + } + + screen_set_cursor(buffer->cursor.x, 2+buffer->cursor.y - buffer->scroll.start); + + /* fill bottom row with light grey */ + for (size_t i = 0; i < 80; i++) { + screen_put_char(i, 24, ' ', COLOR(VGA_COLOR_BLACK, VGA_COLOR_LIGHT_GREY)); + } + + /* write stats at the bottom */ + screen_printf(0, 24, COLOR(VGA_COLOR_BLACK, VGA_COLOR_LIGHT_GREY), "lc: %d, x: %d, y: %d, Save CTRL-S, Exit CTRL-C", buffer->line_count, buffer->cursor.x, buffer->cursor.y); + + return 0; +} + +/* Function to handle keyboard input of a char */ +static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { + int ret; + + /* Handle the backspace key */ + if (c == '\b') { + /* If we are at the end of the line */ + if (buffer->cursor.x == 0) { + /* If the cursor is at the beginning of the first line, do nothing */ + if (buffer->cursor.y == 0) { + return -1; + } + + /* Move the rest of the current line up if there is space. */ + if (buffer->lines[buffer->cursor.y]->length > 0 && buffer->lines[buffer->cursor.y - 1]->capacity - buffer->lines[buffer->cursor.y - 1]->length > buffer->lines[buffer->cursor.y]->length) { + memcpy(buffer->lines[buffer->cursor.y - 1]->text + buffer->lines[buffer->cursor.y - 1]->length, buffer->lines[buffer->cursor.y]->text, buffer->lines[buffer->cursor.y]->length); + } + buffer->cursor.x = buffer->lines[buffer->cursor.y - 1]->length; + + /* update new length */ + buffer->lines[buffer->cursor.y - 1]->length += buffer->lines[buffer->cursor.y]->length; + + textbuffer_free_line(buffer, buffer->cursor.y); + + buffer->cursor.y--; + } else { + /* Remove the character before the cursor */ + if (buffer->lines[buffer->cursor.y] == NULL) { + buffer->cursor.x = 0; + return -1; + } + + /* If x is behind length, then we move content back */ + if (buffer->cursor.x < buffer->lines[buffer->cursor.y]->length) { + for (size_t i = buffer->cursor.x; i < buffer->lines[buffer->cursor.y]->length; i++) { + buffer->lines[buffer->cursor.y]->text[i - 1] = buffer->lines[buffer->cursor.y]->text[i]; + } + buffer->lines[buffer->cursor.y]->text[buffer->lines[buffer->cursor.y]->length - 1] = '\0'; + buffer->lines[buffer->cursor.y]->length--; + buffer->cursor.x--; + return -1; + } + + /* If x is at length, then we just remove the last character */ + buffer->lines[buffer->cursor.y]->text[buffer->cursor.x - 1] = 0; + buffer->lines[buffer->cursor.y]->length--; + buffer->cursor.x--; + } + } else if (c == '\n') { + /* If the cursor is at the end of the line, create a new line */ + if (buffer->cursor.x == buffer->lines[buffer->cursor.y]->length) { + /* If the buffer is full, do nothing */ + if (buffer->line_count == MAX_LINES) { + return -1; + } + + ret = textbuffer_new_line(buffer); + if (ret < 0) { + printf("textbuffer_new_line failed\n"); + return -1; + } + + if (buffer->cursor.y != buffer->line_count - 1) { + /* Move down the content of all lines below current */ + for (size_t i = buffer->line_count - 1; i > buffer->cursor.y + 1; i--) { + memset(buffer->lines[i]->text, 0, buffer->lines[i]->capacity); + memcpy(buffer->lines[i]->text, buffer->lines[i - 1]->text, buffer->lines[i - 1]->length); + buffer->lines[i]->length = buffer->lines[i - 1]->length; + } + /* clear next line */ + memset(buffer->lines[buffer->cursor.y + 1]->text, 0, buffer->lines[buffer->cursor.y + 1]->capacity); + buffer->lines[buffer->cursor.y + 1]->length = 0; + } + + /* Move the cursor to the beginning of the new line */ + buffer->cursor.x = 0; + buffer->cursor.y++; + } else { + /* Create a new line */ + ret = textbuffer_new_line(buffer); + if (ret < 0) { + printf("textbuffer_new_line failed\n"); + return -1; + } + + /* Move down the content of all lines below current */ + for (size_t i = buffer->line_count - 1; i > buffer->cursor.y + 1; i--) { + memcpy(buffer->lines[i]->text, buffer->lines[i - 1]->text, buffer->lines[i - 1]->length); + buffer->lines[i]->length = buffer->lines[i - 1]->length; + } + + /* clear next line */ + memset(buffer->lines[buffer->cursor.y + 1]->text, 0, buffer->lines[buffer->cursor.y + 1]->capacity); + + /* Move the content from x to length down one line */ + for (size_t i = buffer->lines[buffer->cursor.y]->length; i > buffer->cursor.x; i--) { + buffer->lines[buffer->cursor.y + 1]->text[i - buffer->cursor.x - 1] = buffer->lines[buffer->cursor.y]->text[i - 1]; + } + + /* Set the length of the new line */ + buffer->lines[buffer->cursor.y + 1]->length = buffer->lines[buffer->cursor.y]->length - buffer->cursor.x; + + memset(buffer->lines[buffer->cursor.y]->text + buffer->cursor.x, 0, buffer->lines[buffer->cursor.y]->capacity - buffer->cursor.x); + + /* Set the length of the old line */ + buffer->lines[buffer->cursor.y]->length = buffer->cursor.x; + + /* Move the cursor to the beginning of the new line */ + buffer->cursor.x = 0; + buffer->cursor.y++; + } + if (buffer->cursor.y >= buffer->scroll.end + buffer->scroll.start) { + buffer->scroll.start++; + } + } else if (c >= ARROW_RIGHT && c <= ARROW_UP) { + switch (c) { + case ARROW_RIGHT: + if (buffer->cursor.x < buffer->lines[buffer->cursor.y]->length) { + buffer->cursor.x++; + } + break; + case ARROW_LEFT: + if (buffer->cursor.x > 0) { + buffer->cursor.x--; + } + break; + case ARROW_UP: + if (buffer->cursor.y > 0) { + buffer->cursor.y--; + if (buffer->cursor.x > buffer->lines[buffer->cursor.y]->length) { + buffer->cursor.x = buffer->lines[buffer->cursor.y]->length; + } + if (buffer->scroll.start > 0 && + buffer->cursor.y < buffer->scroll.start) { + buffer->scroll.start--; + } + } + break; + case ARROW_DOWN: + if (buffer->cursor.y < buffer->line_count - 1) { + buffer->cursor.y++; + if (buffer->cursor.x > buffer->lines[buffer->cursor.y]->length) { + buffer->cursor.x = buffer->lines[buffer->cursor.y]->length; + } + + if (buffer->cursor.y >= buffer->scroll.end + buffer->scroll.start) { + buffer->scroll.start++; + } + } + break; + } + screen_set_cursor(buffer->cursor.x, 1+buffer->cursor.y); + } else { + /* If the buffer is full, do nothing */ + if (buffer->lines[buffer->cursor.y]->length == buffer->lines[buffer->cursor.y]->capacity) { + /* Create new line, but flag it as extension */ + textbuffer_handle_char(buffer, '\n'); + buffer->lines[buffer->cursor.y]->flags |= LINE_FLAG_EXTENSION; + } + + /* If x is behind length, then we move content forward */ + if (buffer->cursor.x < buffer->lines[buffer->cursor.y]->length) { + /* Move the content from x to end forward one character */ + for (size_t i = buffer->lines[buffer->cursor.y]->length; i > buffer->cursor.x; i--) { + buffer->lines[buffer->cursor.y]->text[i] = buffer->lines[buffer->cursor.y]->text[i - 1]; + } + } + + /* Insert the character at the cursor position */ + buffer->lines[buffer->cursor.y]->text[buffer->cursor.x] = c; + buffer->lines[buffer->cursor.y]->length++; + buffer->cursor.x++; + } + + return 0; +} + +int main(int argc, char *argv[]) { + unsigned char c; + struct textbuffer *buffer = textbuffer_create(); + if (buffer == NULL) { + return -1; + } + + screen_draw_box(0, 1, 80, 23, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + if(argc > 1) { + textbuffer_load_file(buffer, argv[1]); + } + + textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + while (1) { + c = screen_get_char(); + if (c == 0) + continue; + if (c == CTRLC) + break; + + textbuffer_handle_char(buffer, c); + textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + } + + textbuffer_destroy(buffer); + + return 0; +} \ No newline at end of file diff --git a/drivers/vga.c b/drivers/vga.c index 10ad32d..31dd7cb 100644 --- a/drivers/vga.c +++ b/drivers/vga.c @@ -35,7 +35,7 @@ static inline uint16_t vga_entry(unsigned char uc, uint8_t color) return (uint16_t) uc | (uint16_t) color << 8; } -void screen_set_cursor(int x, int y) +void scr_set_cursor(int x, int y) { uint16_t pos = y * SCREEN_WIDTH + x + 1; outportb(0x3D4, 0x0F); diff --git a/include/screen.h b/include/screen.h index 7802598..a6c725d 100644 --- a/include/screen.h +++ b/include/screen.h @@ -31,7 +31,7 @@ enum vga_color { void scrcolor_set(enum vga_color fg, enum vga_color bg); void scrput(int x, int y, unsigned char c, uint8_t color); void scrwrite(int x, int y, char* str, uint8_t color); -void screen_set_cursor(int x, int y); +int screen_set_cursor(int x, int y); void scr_clear(); void scr_scroll(); int scrprintf(int32_t x, int32_t y, char* fmt, ...); diff --git a/include/syscall_helper.h b/include/syscall_helper.h index d006562..9f8cb2c 100644 --- a/include/syscall_helper.h +++ b/include/syscall_helper.h @@ -44,7 +44,10 @@ enum { SYSCALL_JOIN_THREAD, SYSCALL_AWAIT_PROCESS, - SYSCALL_SYSTEM + SYSCALL_SYSTEM, + SYSCALL_SCREEN_PUT, + SYSCALL_SCREEN_GET, + SYSCALL_SET_CURSOR }; #endif /* __SYSCALL_HELPER_H */ diff --git a/include/usermanager.h b/include/usermanager.h index 5d75ece..9cc709d 100644 --- a/include/usermanager.h +++ b/include/usermanager.h @@ -22,6 +22,7 @@ struct user_manager_ops { int (*load)(struct usermanager *manager); int (*save)(struct usermanager *manager); struct user* (*authenticate)(struct usermanager *manager, const char* username, const char* password); + struct user* (*get)(struct usermanager *manager, const char* username); }; struct usermanager { diff --git a/kernel/edit.c b/kernel/edit.c deleted file mode 100644 index fcc8fda..0000000 --- a/kernel/edit.c +++ /dev/null @@ -1,463 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_LINES 512 -#define LINE_CAPACITY 76 -#define MAX_VISABLE_LINES 22 - -typedef enum __line_flags { - LINE_FLAG_NONE = 1 << 0, - LINE_FLAG_DIRTY = 1 << 1, - LINE_FLAG_EXTENSION = 1 << 2, -} line_flags_t; - -struct textbuffer { - struct textbuffer_ops { - int (*destroy)(struct textbuffer *buffer); - int (*display)(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg); - int (*put)(struct textbuffer *buffer, unsigned char c); - } *ops; - struct line { - char *text; - size_t length; - size_t capacity; - line_flags_t flags; - } **lines; - struct cursor { - size_t x; - size_t y; - } cursor; - struct scroll { - size_t start; - size_t end; - } scroll; - size_t line_count; -}; - -/* Function prototypes */ -static int textbuffer_new_line(struct textbuffer *buffer); -static int textbuffer_remove_last_line(struct textbuffer *buffer); -static int textbuffer_free_line(struct textbuffer *buffer, size_t line); -static int textbuffer_destroy(struct textbuffer *buffer); -static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg); -static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c); - -static struct textbuffer_ops textbuffer_default_ops = { - .destroy = textbuffer_destroy, - .display = textbuffer_display, - .put = textbuffer_handle_char, -}; - -static struct textbuffer *textbuffer_create(void) -{ - int ret; - struct textbuffer *buffer = create(struct textbuffer); - if(buffer == NULL){ - return NULL; - } - - buffer->lines = kalloc(sizeof(struct line*) * MAX_LINES); - if(buffer->lines == NULL){ - kfree(buffer); - return NULL; - } - - ret = textbuffer_new_line(buffer); - if(ret < 0){ - kfree(buffer->lines); - kfree(buffer); - return NULL; - } - - buffer->ops = &textbuffer_default_ops; - buffer->cursor.x = 0; - buffer->cursor.y = 0; - buffer->scroll.start = 0; - buffer->scroll.end = MAX_VISABLE_LINES; - - return buffer; -} - -static int textbuffer_find(struct textbuffer *buffer, char* str) -{ - int ret; - /* find str in lines and goto line */ - for(size_t i = 0; i < buffer->line_count; i++){ - ret = strstr(buffer->lines[i]->text, str); - if(ret >= 0){ - buffer->cursor.y = i; - buffer->cursor.x = ret; - return 0; - } - } - - return -1; -} - -static int textbuffer_destroy(struct textbuffer *buffer) -{ - for (size_t i = 0; i < buffer->line_count; i++) { - if (buffer->lines[i]->text) { - kfree(buffer->lines[i]->text); - } - kfree(buffer->lines[i]); - } - kfree(buffer->lines); - kfree(buffer); - - return 0; -} - -static int textbuffer_new_line(struct textbuffer *buffer) -{ - if (buffer->line_count == MAX_LINES) { - return -1; - } - - buffer->lines[buffer->line_count] = kalloc(sizeof(struct line)); - if(buffer->lines[buffer->line_count] == NULL){ - return -1; - } - - buffer->lines[buffer->line_count]->text = kalloc(LINE_CAPACITY); - if(buffer->lines[buffer->line_count]->text == NULL){ - kfree(buffer->lines[buffer->line_count]); - return -1; - } - - memset(buffer->lines[buffer->line_count]->text, 0, LINE_CAPACITY); - - buffer->lines[buffer->line_count]->length = 0; - buffer->lines[buffer->line_count]->capacity = LINE_CAPACITY; - buffer->line_count++; - - return 0; -} - -static int textbuffer_remove_last_line(struct textbuffer *buffer) -{ - if (buffer->line_count == 0) { - return -1; - } - - kfree(buffer->lines[buffer->line_count - 1]->text); - kfree(buffer->lines[buffer->line_count - 1]); - buffer->line_count--; - - return 0; -} - -static int textbuffer_free_line(struct textbuffer *buffer, size_t line) -{ - if (line >= buffer->line_count) { - return -1; - } - - /* Move the content of all lines below current up one line */ - for (size_t i = line; i < buffer->line_count - 1; i++) { - memset(buffer->lines[i]->text, 0, buffer->lines[i]->capacity); - memcpy(buffer->lines[i]->text, buffer->lines[i + 1]->text, buffer->lines[i + 1]->length); - buffer->lines[i]->length = buffer->lines[i + 1]->length; - } - - /* Remove the last line */ - kfree(buffer->lines[buffer->line_count - 1]->text); - kfree(buffer->lines[buffer->line_count - 1]); - buffer->line_count--; - - return 0; -} - -static int textbuffer_save_file(struct textbuffer *buffer, const char *filename) -{ - byte_t *file = kalloc(1024); - if(file == NULL){ - return -1; - } - size_t len = 0; - for(size_t i = 0; i < buffer->line_count; i++){ - if(buffer->lines[i]->text){ - memcpy(file + len, buffer->lines[i]->text, buffer->lines[i]->length); - - /* Add newline if not extension */ - if(!HAS_FLAG(buffer->lines[i]->flags, LINE_FLAG_EXTENSION)){ - file[len + buffer->lines[i]->length] = '\n'; - len++; - } - - len += buffer->lines[i]->length; - } - } - int ret = fs_save_to_file(filename, file, len); - if(ret < 0){ - kfree(file); - return -1; - } - kfree(file); - return 0; -} - -static int textbuffer_load_file(struct textbuffer *buffer, const char *filename) -{ - byte_t *file = kalloc(1024); - if(file == NULL){ - return -1; - } - int ret = fs_load_from_file(filename, file, 1024); - if(ret < 0){ - kfree(file); - return -1; - } - size_t len = strlen(file); - for(size_t i = 0; i < len; i++){ - textbuffer_handle_char(buffer, file[i]); - } - - textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); - - return 0; -} - -/* Function to display the content of the text buffer on the screen */ -static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg) { - uint8_t color = (bg << 4) | fg; - uint32_t x_start = 0; - uint32_t y_start = buffer->scroll.start; - - /* Clear the screen before displaying new content */ - scr_clear(); - - /* write from start to end, or line_count */ - for (size_t i = 0; i+y_start < buffer->line_count && i < buffer->scroll.end; i++) { - /* Calculate the position for each line */ - int32_t x = x_start; - int32_t y = y_start + i; - - /* Write the line to the screen */ - if(!buffer->lines[y]->text) { - continue; - } - if(buffer->cursor.y == y){ - scrprintf(x, 1+i, "%d: %s (l: %d)", y, buffer->lines[y]->text, buffer->lines[y]->length); - } else { - scrprintf(x, 1+i, "%d: %s", y, buffer->lines[y]->text); - } - - } - - /* Set the cursor to the end of the text */ - if (buffer->line_count > 0) { - screen_set_cursor(x_start, y_start + buffer->line_count - 1); - } - - screen_set_cursor(buffer->cursor.x+2, 1+buffer->cursor.y); - /* write stats at the bottom */ - scrprintf(0, 24, "lc: %d, x: %d, y: %d, Save CTRL-S, Exit CTRL-C", buffer->line_count, buffer->cursor.x, buffer->cursor.y); - - return 0; -} - -/* Function to handle keyboard input of a char */ -static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { - int ret; - - /* Handle the backspace key */ - if (c == '\b') { - /* If we are at the end of the line */ - if (buffer->cursor.x == 0) { - /* If the cursor is at the beginning of the first line, do nothing */ - if (buffer->cursor.y == 0 ) { - return -1; - } - - /* Move the rest of the current line up if there is space. */ - if(buffer->lines[buffer->cursor.y]->length > 0 && buffer->lines[buffer->cursor.y - 1]->capacity - buffer->lines[buffer->cursor.y - 1]->length > buffer->lines[buffer->cursor.y]->length){ - memcpy(buffer->lines[buffer->cursor.y - 1]->text + buffer->lines[buffer->cursor.y - 1]->length, buffer->lines[buffer->cursor.y]->text, buffer->lines[buffer->cursor.y]->length); - } - buffer->cursor.x = buffer->lines[buffer->cursor.y - 1]->length; - - /* update new length */ - buffer->lines[buffer->cursor.y - 1]->length += buffer->lines[buffer->cursor.y]->length; - - textbuffer_free_line(buffer, buffer->cursor.y); - - buffer->cursor.y--; - } else { - /* Remove the character before the cursor */ - if(buffer->lines[buffer->cursor.y] == NULL) { - buffer->cursor.x = 0; - dbgprintf("buffer->lines[buffer->cursor.y] == NULL %d, 0x%x\n", buffer->cursor.y, buffer->lines[buffer->cursor.y]); - return -1; - } - - /* If x is behind length, then we move content back */ - if(buffer->cursor.x < buffer->lines[buffer->cursor.y]->length) { - for (size_t i = buffer->cursor.x; i < buffer->lines[buffer->cursor.y]->length; i++) { - buffer->lines[buffer->cursor.y]->text[i - 1] = buffer->lines[buffer->cursor.y]->text[i]; - } - buffer->lines[buffer->cursor.y]->text[buffer->lines[buffer->cursor.y]->length - 1] = '\0'; - buffer->lines[buffer->cursor.y]->length--; - buffer->cursor.x--; - return -1; - } - - /* If x is at length, then we just remove the last character */ - buffer->lines[buffer->cursor.y]->text[buffer->cursor.x - 1] = 0; - buffer->lines[buffer->cursor.y]->length--; - buffer->cursor.x--; - } - } else if (c == '\n') { - /* If the cursor is at the end of the line, create a new line */ - if (buffer->cursor.x == buffer->lines[buffer->cursor.y]->length) { - /* If the buffer is full, do nothing */ - if (buffer->line_count == MAX_LINES) { - return -1; - } - - ret = textbuffer_new_line(buffer); - if(ret < 0){ - warningf("textbuffer_new_line failed\n"); - return -1; - } - - if(buffer->cursor.y != buffer->line_count - 1){ - /* Move down the content of all lines below current */ - for (size_t i = buffer->line_count - 1; i > buffer->cursor.y + 1; i--) { - memset(buffer->lines[i]->text, 0, buffer->lines[i]->capacity); - memcpy(buffer->lines[i]->text, buffer->lines[i - 1]->text, buffer->lines[i - 1]->length); - buffer->lines[i]->length = buffer->lines[i - 1]->length; - } - /* clear next line */ - memset(buffer->lines[buffer->cursor.y + 1]->text, 0, buffer->lines[buffer->cursor.y + 1]->capacity); - buffer->lines[buffer->cursor.y + 1]->length = 0; - } - - /* Move the cursor to the beginning of the new line */ - buffer->cursor.x = 0; - buffer->cursor.y++; - } else { - /* Create a new line */ - ret = textbuffer_new_line(buffer); - if(ret < 0){ - warningf("textbuffer_new_line failed\n"); - return -1; - } - - /* Move down the content of all lines below current */ - for (size_t i = buffer->line_count - 1; i > buffer->cursor.y + 1; i--) { - memcpy(buffer->lines[i]->text, buffer->lines[i - 1]->text, buffer->lines[i - 1]->length); - buffer->lines[i]->length = buffer->lines[i - 1]->length; - } - - /* clear next line */ - memset(buffer->lines[buffer->cursor.y + 1]->text, 0, buffer->lines[buffer->cursor.y + 1]->capacity); - - /* Move the content from x to length down one line */ - for (size_t i = buffer->lines[buffer->cursor.y]->length; i > buffer->cursor.x; i--) { - buffer->lines[buffer->cursor.y + 1]->text[i - buffer->cursor.x - 1] = buffer->lines[buffer->cursor.y]->text[i - 1]; - } - - /* Set the length of the new line */ - buffer->lines[buffer->cursor.y + 1]->length = buffer->lines[buffer->cursor.y]->length - buffer->cursor.x; - - memset(buffer->lines[buffer->cursor.y]->text + buffer->cursor.x, 0, buffer->lines[buffer->cursor.y]->capacity - buffer->cursor.x); - - /* Set the length of the old line */ - buffer->lines[buffer->cursor.y]->length = buffer->cursor.x; - - /* Move the cursor to the beginning of the new line */ - buffer->cursor.x = 0; - buffer->cursor.y++; - } - } else if(c >= ARROW_RIGHT && c <= ARROW_UP ){ - switch (c){ - case ARROW_RIGHT: - if(buffer->cursor.x < buffer->lines[buffer->cursor.y]->length){ - buffer->cursor.x++; - } - break; - case ARROW_LEFT: - if(buffer->cursor.x > 0){ - buffer->cursor.x--; - } - break; - case ARROW_UP: - if(buffer->cursor.y > 0){ - buffer->cursor.y--; - if(buffer->cursor.x > buffer->lines[buffer->cursor.y]->length){ - buffer->cursor.x = buffer->lines[buffer->cursor.y]->length; - } - if (buffer->scroll.start > 0 && buffer->cursor.y < buffer->scroll.start) { - buffer->scroll.start--; - } - } - break; - case ARROW_DOWN: - if(buffer->cursor.y < buffer->line_count - 1){ - buffer->cursor.y++; - if(buffer->cursor.x > buffer->lines[buffer->cursor.y]->length){ - buffer->cursor.x = buffer->lines[buffer->cursor.y]->length; - } - - if (buffer->cursor.y >= buffer->scroll.end + buffer->scroll.start) { - buffer->scroll.start++; - } - } - break; - } - } else { - /* If the buffer is full, do nothing */ - if (buffer->lines[buffer->cursor.y]->length == buffer->lines[buffer->cursor.y]->capacity) { - /* Create new line, but flag it as extension */ - textbuffer_handle_char(buffer, '\n'); - buffer->lines[buffer->cursor.y]->flags |= LINE_FLAG_EXTENSION; - } - - /* If x is behind length, then we move content forward */ - if(buffer->cursor.x < buffer->lines[buffer->cursor.y]->length) { - /* Move the content from x to end forward one character */ - for (size_t i = buffer->lines[buffer->cursor.y]->length; i > buffer->cursor.x; i--) { - buffer->lines[buffer->cursor.y]->text[i] = buffer->lines[buffer->cursor.y]->text[i - 1]; - } - } - - /* Insert the character at the cursor position */ - buffer->lines[buffer->cursor.y]->text[buffer->cursor.x] = c; - buffer->lines[buffer->cursor.y]->length++; - buffer->cursor.x++; - } - - return 0; -} - - -static __kthread_entry void editor() -{ - unsigned char c; - struct textbuffer *buffer = textbuffer_create(); - if(buffer == NULL){ - dbgprintf("buffer == NULL\n"); - } - - textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); - textbuffer_load_file(buffer, "/sysutil/default.cfg"); - while (1){ - c = kb_get_char(); - if(c == 0) continue; - if(c == CTRLC) break; - - textbuffer_handle_char(buffer, c); - textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); - } - - textbuffer_destroy(buffer); -} -EXPORT_KSYMBOL(editor); - diff --git a/kernel/kthreads/login.c b/kernel/kthreads/login.c index 83b38d0..2e14770 100644 --- a/kernel/kthreads/login.c +++ b/kernel/kthreads/login.c @@ -30,6 +30,7 @@ #include #include #include +#include struct gfx_input_manager input_manager = {0}; @@ -40,8 +41,47 @@ static void __callback __login_create_virt_disk(int opt){ } } +static int login_startup(struct user* usr){ + + $process->current->user = usr; + + exec_cmd("sh /sysutil/startup.sh"); + + if(!disk_attached()){ + struct msgbox* box = msgbox_create( + MSGBOX_TYPE_WARNING, + MSGBOX_BUTTON_OK | MSGBOX_BUTTON_CANCEL, + "No disk attached", " Create virtual disk?", + __login_create_virt_disk + ); + msgbox_show(box); + } + + gfx_set_taskbar(0); + kernel_exit(); + return; +} + void __kthread_entry login() { + /* check if logon is disabled and a default usr is set. */ + char* logon = config_get_value("system", "logon"); + if(logon != NULL){ + if(strcmp(logon, "disabled") == 0){ + char* username = config_get_value("system", "user"); + if(username != NULL){ + struct user* usr = $services->usermanager->ops->get($services->usermanager, username); + if(usr == NULL){ + warningf("Failed to get user"); + return; + } + + login_startup(usr); + return; + } + } + } + struct window* w = gfx_new_window(275, 100, GFX_NO_OPTIONS); if(w == NULL){ warningf("Failed to create window for login"); @@ -110,8 +150,6 @@ void __kthread_entry login() case GFX_EVENT_MOUSE:{ /* check if OK is clicked x = event.data, y = event.data2 */ if(event.data > 10+10+120 && event.data < 10+10+120+50 && event.data2 > 10+10+10+10 && event.data2 < 10+10+10+10+20){ - - /* check if username and password is correct */ struct user* usr = usermanager->ops->authenticate(usermanager, input_manager.inputs[0].buffer, @@ -122,22 +160,7 @@ void __kthread_entry login() break; } - $process->current->user = usr; - - exec_cmd("sh /sysutil/startup.sh"); - - if(!disk_attached()){ - struct msgbox* box = msgbox_create( - MSGBOX_TYPE_WARNING, - MSGBOX_BUTTON_OK | MSGBOX_BUTTON_CANCEL, - "No disk attached", " Create virtual disk?", - __login_create_virt_disk - ); - msgbox_show(box); - } - - gfx_set_taskbar(0); - kernel_exit(); + login_startup(usr); return; } } diff --git a/kernel/kthreads/shell.c b/kernel/kthreads/shell.c index ebc1805..0bc97aa 100644 --- a/kernel/kthreads/shell.c +++ b/kernel/kthreads/shell.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -299,7 +300,7 @@ void exec(int argc, char* argv[]) pid = pcb_create_process(argv[idx], argc-idx, &argv[idx], 0 /* PCB_FLAG_KERNEL */); if(pid > 0){ - //pcb_await(pid); + if(!kthread_as_deamon) pcb_await(pid); return; } @@ -671,7 +672,7 @@ static int __textshell_reset_box() /* header */ scrwrite(40-(strlen(" Terminal ")/2) , 1, " Terminal ", color); - screen_set_cursor(3, SCREEN_HEIGHT-1); + scr_set_cursor(3, SCREEN_HEIGHT-1); return 0; } @@ -680,6 +681,20 @@ static int textshell_login(struct terminal* term) { struct usermanager* usrman = $services->usermanager; + char* logon = config_get_value("system", "logon"); + if(logon != NULL){ + if(strcmp(logon, "disabled") == 0){ + char* user = config_get_value("system", "user"); + if(user != NULL){ + struct user* u = usrman->ops->get(usrman, user); + if(u != NULL){ + $process->current->user = u; + return 0; + } + } + } + } + char username[32]; char password[32]; @@ -751,7 +766,7 @@ static void __kthread_entry textshell() x--; scrput(4+x, SCREEN_HEIGHT-1, ' ', VGA_COLOR_WHITE | VGA_COLOR_BLUE << 4); text_shell_buffer[x] = 0; - screen_set_cursor(4+x, SCREEN_HEIGHT-1); + scr_set_cursor(4+x, SCREEN_HEIGHT-1); continue; } @@ -770,7 +785,7 @@ static void __kthread_entry textshell() scrput(4+x, SCREEN_HEIGHT-1, c, VGA_COLOR_WHITE); text_shell_buffer[x] = c; x++; - screen_set_cursor(4+x, SCREEN_HEIGHT-1); + scr_set_cursor(4+x, SCREEN_HEIGHT-1); } } EXPORT_KTHREAD(textshell); diff --git a/kernel/memory.c b/kernel/memory.c index 1613772..4b17765 100644 --- a/kernel/memory.c +++ b/kernel/memory.c @@ -107,9 +107,9 @@ void free(void* ptr) if(ptr == NULL)return; /* lock on free as multiple threads can free at the same time */ - spin_lock(&$process->current->allocations->spinlock); + spin_lock(&($process->current->allocations->spinlock)); vmem_stack_free($process->current, ptr); - spin_unlock(&$process->current->allocations->spinlock); + spin_unlock(&($process->current->allocations->spinlock)); } void* malloc(unsigned int size) @@ -121,17 +121,12 @@ void* malloc(unsigned int size) size = ALIGN(size, PTR_SIZE); /* lock on malloc as multiple threads can malloc at the same time */ - spin_lock(&$process->current->allocations->spinlock); + spin_lock(&($process->current->allocations->spinlock)); + /* No need to check if ptr is null as we simply return it */ void* ptr = vmem_stack_alloc($process->current, size); - if(ptr == NULL){ - spin_unlock(&$process->current->allocations->spinlock); - return NULL; - } - - dbgprintf("Allocated %d bytes at %x\n", size, ptr); - spin_unlock(&$process->current->allocations->spinlock); + spin_unlock(&($process->current->allocations->spinlock)); return ptr; } diff --git a/kernel/pcb.c b/kernel/pcb.c index 3c682f2..b546b10 100644 --- a/kernel/pcb.c +++ b/kernel/pcb.c @@ -293,7 +293,9 @@ struct pcb* pcb_get_by_name(char* name) int pcb_await(int pid) { if(pid < 0 || pid > MAX_NUM_OF_PCBS) return -1; - while(pcb_table[pid].state != STOPPED); + while(pcb_table[pid].state != STOPPED){ + kernel_yield(); + } return 0; } EXPORT_SYSCALL(SYSCALL_AWAIT_PROCESS, pcb_await); diff --git a/kernel/syscalls.c b/kernel/syscalls.c index 12361dc..a7523c5 100644 --- a/kernel/syscalls.c +++ b/kernel/syscalls.c @@ -10,11 +10,13 @@ */ #include +#include #include #include #include #include #include +#include syscall_t syscall[255]; @@ -30,6 +32,40 @@ int sys_create_thread(void (*entry)(), void* arg, byte_t flags) } EXPORT_SYSCALL(SYSCALL_CREATE_THREAD, sys_create_thread); +/* Macro to deserialize a short back into a character */ +#define DESERIALIZE_CHAR(serialized) ((char)((serialized) >> 8)) +/* Macro to deserialize a short back into a color */ +#define DESERIALIZE_COLOR(serialized) ((char)(serialized)) +int sys_screen_put(int x, int y, short packet) +{ + /* validate coordinates */ + if(x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT){ + return -1; + } + + /* get character and color from packet */ + char c = DESERIALIZE_CHAR(packet); + char color = DESERIALIZE_COLOR(packet); + + scrput(x, y, c, color); + return 0; +} +EXPORT_SYSCALL(SYSCALL_SCREEN_PUT, sys_screen_put); + +char sys_screen_get() +{ + return kb_get_char(); +} +EXPORT_SYSCALL(SYSCALL_SCREEN_GET, sys_screen_get); + +int sys_scr_set_cursor(int x, int y) +{ + scr_set_cursor(x, y); + return 0; +} +EXPORT_SYSCALL(SYSCALL_SET_CURSOR, sys_scr_set_cursor); + + int system_call(int index, int arg1, int arg2, int arg3) { /* Call system call function based on index. */ diff --git a/rootfs/symbols.map b/rootfs/symbols.map index c0fff00..1f5f505 100644 --- a/rootfs/symbols.map +++ b/rootfs/symbols.map @@ -8,889 +8,891 @@ 00010058 gdt_end 00010058 kernel_boot_printf 000100b7 init_kctors -00010109 kernel -000105a7 kernel_get_context -000105b1 hexdump -00010801 __terminal_set_ops -000108ce __terminal_scanf -000108d8 __terminal_write -00010926 __terminal_getchar_graphics -00010973 __terminal_scan_graphics -00010a55 __terminal_reset -00010a9d __terminal_detach -00010ae4 __terminal_attach -00010b33 __terminal_remove_line -00010b73 __terminal_putchar_graphics -00010c40 __terminal_writef -00010f4f __terminal_getchar_textmode -00010f7b __terminal_scan_textmode -00011043 __terminal_commit_textmode -000110ff __terminal_putchar_textmode -0001114f scan -0001118c terminal_set_color -000111a8 __terminal_commit_graphics -00011309 terminal_attach -0001132e terminal_commit -00011351 terminal_putchar -00011391 terminal_create -000114ba terminal_destroy -000114f4 tlb_flush_addr -000114fc load_page_directory -0001150c enable_paging -0001151e pcb_save_context -0001154a pcb_restore_context -00011573 _start_pcb -000115a5 _start_pcb_skip -000115c0 __ksymbol_lspci -000115de pci_get_class_name -000115f5 pci_get_device_name -0001166a pci_get_vendor_name -000116bc lspci -0001180d pci_get_devices -00011817 pci_read_word -00011874 pci_write_dword -000118c7 pci_enable_device_busmaster -00011920 pci_register_device -000119a5 init_pci -00011b69 pci_find_device -00011c03 virtual_read -00011c32 virtual_write -00011c61 virtual_disk_attach -00011c84 wm_default_changes -00011d30 wm_default_workspace -00011d96 wm_default_draw -00011e38 wm_default_add -00011ee3 init_windowmanager -0001202f wm_default_mouse_event -0001224d wm_default_push_back -00012343 wm_default_push_front -00012436 wm_default_remove -0001254b wm_destroy -0001262d wm_new -00012698 screen_set_cursor -000126f8 scrcolor_set -00012710 scrput -0001273c scrwrite -00012789 scr_clear -000127df scr_scroll -0001282b scrprintf -00012aab strlen -00012ad1 strcpy -00012b07 strncmp -00012b44 strcmp -00012b88 memcmp -00012bc5 parse_arguments -00012cae strchr -00012ce1 getopt -00012e2c memcpy -00012e9d strtok -00012f59 xmemcpy -00012fe2 memset -00013060 isdigit -00013078 isspace -0001308b tolower -000130a3 isxdigit -000130cb htoi -00013173 atoi -00013205 itoa -000132b5 itohex -00013335 rdtsc -0001333c rand -0001335c general_protection_fault -000133f0 interrupt_get_count -00013403 print_page_fault_info -000134e0 page_fault_interrupt -00013576 interrupt_install_handler -0001358c load_data_segments -0001359c isr_handler -00013693 init_interrupts -00013810 idt_flush -00013818 isr0 -00013825 isr1 -00013832 isr2 -0001383f isr3 -0001384c isr4 -00013859 isr5 -00013866 isr6 -00013873 isr7 -00013880 isr8 -0001388d isr9 -0001389a isr10 -000138a7 isr11 -000138b4 isr12 -000138c1 isr13 -000138ce isr14 -000138db isr15 -000138e8 isr16 -000138f5 isr17 -00013902 isr18 -0001390f isr19 -0001391c isr20 -00013929 isr21 -00013936 isr22 -00013943 isr23 -00013950 isr24 -0001395d isr25 -0001396a isr26 -00013977 isr27 -00013984 isr28 -00013991 isr29 -0001399e isr30 -000139ab isr31 -000139b8 isr32 -000139c5 isr33 -000139d2 isr34 -000139df isr35 -000139e9 isr36 -000139f3 isr37 -000139fd isr38 -00013a07 isr39 -00013a11 isr40 -00013a1b isr41 -00013a25 isr42 -00013a2f isr43 -00013a39 isr44 -00013a43 isr45 -00013a4d isr46 -00013a57 isr47 -00013a61 isr_entry -00013a7c syscall_return_value -00013a80 _syscall_entry -00013abd page_fault_save -00013ac1 page_fault_error -00013ac5 _page_fault_entry -00013af7 timer_callback -00013b33 timer_get_tick -00013b3d time_get_difference -00013b82 init_pit -00013bea gdt_set_segment -00013c35 init_gdt -00013d47 rc -00013f3a __ksymbol_rc -00013f58 __ksymbol_as -00013f76 __ksymbol_cc -00013f94 as -0001435a cc -000143ba __cc -000146b3 vm_print -000148b4 eval -00014d53 vm_setup -00014d98 vm_init -00014df7 vm_free -00014e2a vm_setup_stack -00014e88 lex_get_error -00014e99 next -000154b4 match -00015506 expression -00016921 statement -00016b2e function_parameter -00016cf4 function_body -00016f07 function_declaration -00016f94 enum_declaration -000170aa global_declaration -000172db lex_init -0001737a program -0001741f find_mp_floating_ptr -0001745f smp_parse -000175a9 kb_get_char -000175f7 kb_add_char -00017636 kb_callback -00017867 init_keyboard -000178e2 pcb_await -00017910 __pcb_get_free -000179d6 __add_systemcall_pcb_await -000179f1 __pcb_free -00017a40 __pcb_init_kernel_stack -00017aa1 __pcb_init_process -00017b66 init_pcbs -00017bbb pcb_total_usage -00017bdc pcb_get_info -00017cc2 pcb_kill -00017ce3 Genesis -00017ce9 idletask -00017d08 pcb_get_by_pid -00017d1d pcb_get_by_name -00017d7a pcb_dbg_print -00017df8 pcb_cleanup_routine -0001800d pcb_create_thread -00018109 pcb_create_process -000183a2 pcb_create_kthread -00018688 start_pcb -000186c4 __pcb_queue_peek -00018707 __pcb_queue_pop -00018767 __pcb_queue_remove -000187dd __pcb_queue_add -0001885a __pcb_queue_push -000188f7 pcb_new_queue -0001892c get_mem_info -00018988 memory_map_init -00018a54 memory_map_get -00018a5e free -00018ab9 malloc -00018b59 calloc -00018b90 krealloc -00018c00 init_memory -00018c96 vmem_free -00018d0a vmem_alloc -00018d7b vmem_free_page_region -00018ee4 vmem_page_region_alloc -00018f1f vmem_create_page_region -00019062 vmem_free_allocations -0001918a vmem_continious_allocation_map -00019194 vmem_free_allocation -00019199 vmem_stack_free -0001924e vmem_stack_alloc -000195f8 vmem_dump_heap -00019691 vmem_init_process_thread -00019786 vmem_init_process -00019ab3 vmem_cleanup_process_thead -00019b2e vmem_cleanup_process -00019d1e vmem_init_kernel -00019edf vmem_allocator_create -00019f49 vmem_map_driver_region -00019fcb vmem_total_usage -00019fe2 vmem_init -0001a11a kalloc -0001a2b5 kcalloc -0001a2eb kfree -0001a385 palloc -0001a3d5 pmemory_used -0001a3f6 kmemory_used -0001a400 kmemory_total -0001a410 kmem_init -0001a4b1 e1000_receive -0001a58d e1000_transmit -0001a653 e1000_callback -0001a67e _e1000_tx_init -0001a726 _e1000_rx_init -0001a7c4 e1000_attach -0001aa17 display_get_info -0001aa85 kenv_init -0001aaa0 kenv_set -0001aadc config_list -0001abc2 kernel_config_load -0001af90 config_get_value -0001b053 spin_lock -0001b077 spin_unlock -0001b089 mutex_init -0001b0ab acquire -0001b14c release -0001b1f2 kthread_entry -0001b250 kthread_list -0001b2bb register_kthread -0001b398 start -0001b43e ata_primary -0001b443 ata_secondary -0001b448 ata_wait -0001b4c2 ata_write -0001b634 ata_read -0001b7b2 ata_ide_init -0001b986 set_bitmap -0001b9ac unset_bitmap -0001b9d4 get_bitmap -0001b9fa get_bitmap_size -0001ba12 create_bitmap -0001ba4a destroy_bitmap -0001ba61 bitmap_unset_continous -0001ba9e bitmap_get_continous -0001bb38 get_free_bitmap -0001bb91 __rtc_check_in_progress -0001bbb8 __rtc_get_register -0001bbdc get_current_time -0001bd25 get_time -0001bd53 init_tss -0001bd85 __add_systemcall_sys_system -0001bda0 exec_cmd -0001bef9 sys_system -0001bf0d __ksymbol_exec_cmd -0001bf2b system_reboot -0001bf63 align_to_pointer_size -0001bf75 calculate_size_unit -0001bfd5 advanced_hash -0001c010 kernel_panic -0001c032 kref_init -0001c050 kref_get -0001c07c kref_put -0001c0a8 csprintf -0001c2a6 script_parse -0001c378 login -0001c71a __login_create_virt_disk -0001c748 __register_kthread_login -0001c766 help -0001ca0b clear -0001ca30 __ksymbol_new -0001ca4e __ksymbol_list -0001ca6c __ksymbol_color -0001ca8a __ksymbol_about -0001caa8 __ksymbol_help -0001cac6 __ksymbol_kevents -0001cae4 __ksymbol_view -0001cb02 __ksymbol_file -0001cb20 __ksymbol_tcp -0001cb3e __ksymbol_conf -0001cb5c __ksymbol_clear -0001cb7a __ksymbol_services -0001cb98 __ksymbol_reboot -0001cbb6 kevents -0001cc94 services -0001cec6 new -0001d00b list -0001d10f file -0001d2e1 color -0001d386 about -0001d3c7 view -0001d5e0 tcp -0001d8c1 __tcp_reader -0001d9e6 conf -0001dcb2 reboot -0001dcef attach_disk_dev -0001dd17 disk_attached -0001dd23 disk_name -0001dd30 disk_device_get -0001dd3a disk_size -0001dd5a write_block -0001dd9b write_block_offset -0001dde2 read_block -0001de23 read_block_offset -0001de91 sched_consume -0001ded6 sched_add -0001df34 sched_prioritize -0001dfed sched_round_robin -0001e1d3 sched_exit -0001e290 sched_block -0001e3b2 sched_default -0001e48d sched_sleep -0001e537 sched_init_default -0001e5bc get_scheduler -0001e5c6 kernel_sleep -0001e5e5 kernel_yield -0001e62c kernel_exit -0001e662 block -0001e68f unblock -0001e694 work_queue_add -0001e798 init_worker -0001e7b4 worker_thread -0001e857 __ring_buffer_add -0001e903 __ring_buffer_read -0001ea11 rbuffer_new -0001ea7e rbuffer_free -0001eaa4 error_get_string -0001eae4 kclock -0001efbf __register_kthread_kclock -0001efdd tar_extract -0001f22d __ksymbol_tar -0001f24b tar_list -0001f356 tar -0001f5e3 rgb_to_vga -0001f5f7 rgb_to_components -0001f622 color_distance_squared -0001f692 rgb_init_color_table -0001f71d iface_loopback_write -0001f7e2 iface_loopback_interrupt -0001f7fd iface_loopback_read -0001f8a7 net_init_loopback -0001f8c2 serial_put -0001f906 serial_write -0001f94c serial_printf -0001fb00 init_serial -0001fbca inportb -0001fbd7 inportw -0001fbe5 inportl -0001fbf2 outportb -0001fc02 outportw -0001fc13 outportl -0001fc23 sys_create_thread -0001fc46 __add_systemcall_sys_create_thread -0001fc55 add_system_call -0001fc99 system_call -0001fd08 hashmap_put -0001fd74 hashmap_get -0001fdfc hashmap_add -0001fe8a hashmap_free -0001fe8f reset_vga_palette -0001fed9 vga_set_palette -0001ffc8 b8to16 -0001ffde vesa_put_pixel -0002000c vesa_put_box -00020086 vesa_put_block -00020100 vesa_put_char -0002017a vesa_put_char16 -00020212 vesa_put_icon16 -0002028d vesa_write -000202d0 vesa_write_str -00020302 vesa_fill -00020386 vesa_fillrect -000203f5 vesa_inner_box -00020501 vesa_printf -0002078d ksyms_init -000209ac ksyms_add_symbol -00020a69 __ksymbol_backtrace -00020a87 ksyms_list -00020aed ksyms_resolve_symbol -00020ba4 __backtrace_from -00020cc2 backtrace -00020cd7 ws_fullscreen -00020e55 ws_remove -00020f09 ws_add -00020ff8 ws_destroy -000210a2 ws_draw -00021353 ws_raw_wallpaper -0002143d ws_set_background_file -0002171d ws_init -00021804 ws_set_background -000218b3 ws_new -00021944 encode_run_length -000219cd decode_run_length -00021a44 __mouse_handler -00021b5c mouse_wait -00021ba4 mouse_write -00021be6 mouse_get_event -00021c2b mouse_init -00021d14 sys_ipc_open -00021d66 __add_systemcall_sys_ipc_open -00021d81 __add_systemcall_sys_ipc_close -00021d9c __add_systemcall_sys_ipc_send -00021db7 __add_systemcall_sys_ipc_receive -00021dd2 sys_ipc_close -00021e1f sys_ipc_send -00021e8a sys_ipc_receive -00021ef4 sysinf -00022c60 __register_kthread_sysinf -00022c7e echo -00022cbd res -00022d02 ifconfig -00022d13 __ksymbol_ifconfig -00022d31 __ksymbol_ps -00022d4f __ksymbol_tree -00022d6d __ksymbol_fat16 -00022d8b __ksymbol_xxd -00022da9 __ksymbol_sh -00022dc7 __ksymbol_ed -00022de5 __ksymbol_exec -00022e03 __ksymbol_ths -00022e21 __ksymbol_dns -00022e3f __ksymbol_th -00022e5d __ksymbol_kill -00022e7b __ksymbol_echo -00022e99 __ksymbol_fdisk -00022eb7 __ksymbol_meminfo -00022ed5 __ksymbol_res -00022ef3 __ksymbol_bg -00022f11 __ksymbol_exit -00022f2f __ksymbol_socks -00022f4d __ksymbol_reset -00022f6b exit -00022fa3 ps -0002321b print_pcb_tree -0002331a tree -0002335e fat16 -0002338a xxd -00023483 sh -00023587 ed -000235d8 exec -00023742 ths -000237b2 dns -0002382a th -0002384c kill -0002386e fdisk -00023a04 meminfo -00023be7 bg -00023c6a socks -00023f13 __register_kthread_shell -00023f31 __register_kthread_textshell -00023f4f shell_clear -00023f96 reset_shell -0002400b reset -00024063 shell_put -00024249 shell -000244ae cleanup_function -000244d9 testfn -00024511 draw_box -000245fa __textshell_reset_box -0002468a textshell -00024a5b __net_find_interface -00024abb net_drop_packet -00024adc net_handle_recieve -00024c07 net_get_interfaces -00024c11 net_configure_iface -00024c67 net_incoming_packet -00024d19 net_get_iface -00024d95 net_iface_up -00024dc0 net_iface_down -00024deb net_list_ifaces -00024f09 net_register_interface -00024f3e net_send_skb -00024fca net_get_info -00024ff5 networking_main -000251d5 __dhcp_add_option -0002523f __dhcp_send_discovery -00025381 __dhcp_send_request -000254fe dhcp_get_state -0002550a dhcp_get_dns -00025514 dhcp_get_ip -0002552d dhcp_get_gw -00025546 dhcpd -000257da udp_server -00025869 tcp_server -000259e1 __net_terminal_writef -00025a4a __register_kthread_tcp_server -00025a68 __register_kthread_udp_server -00025a86 __register_kthread_udptest -00025aa4 udptest -00025b33 tcpd -00025c1b logd -00025c8a __register_kthread_logd -00025ca8 logd_attach_by_pid -00025cf0 taskbar_reboot -00025d20 __reboot -00025d39 taskbar_readme -00025d56 taskbar_about -00025d73 taskbar_clock -00025d90 taskbar_sysinf -00025dad taskbar_bg_retro -00025de8 taskbar_bg_lotr2 -00025e01 taskbar_bg_lotr -00025e1a taskbar_bg_default_color_gray -00025e30 taskbar_bg_default_color -00025e46 taskbar_wolfstein -00025e85 taskbar_bg_graph -00025ec4 taskbar_bg_calc -00025f03 taskbar_colors -00025f42 taskbar_cube -00025f81 taskbar_editor -00025fc0 taskbar_finder -00025fff taskbar_terminal -0002604c __register_kthread_taskbar -0002606a taskbar_hdr_opt_event -000260f4 taskbar -00026701 about -000268d0 __register_kthread_about -000268ee __register_kthread_readme -0002690c readme -00026a72 gfx_default_hover -00026ba0 gfx_draw_window -000279bb gfx_destory_window -00027a4c gfx_window_resize -00027af9 gfx_window_maximize -00027b76 gfx_default_mouse_up -00027c48 gfx_default_mouse_down -00027d0e gfx_default_click -00027f01 gfx_window_set_resizable -00027f1a kernel_gfx_window_border_color -00027f49 gfx_new_window -000281b0 gfx_point_in_rectangle -000281e1 gfx_draw_component -00028227 gfx_input_event -00028348 gfx_input_draw -00028454 gfx_input_manager_add -000284b9 gfx_composition_remove_window -000284e7 gfx_composition_add_window -00028532 gfx_set_background_color -00028587 gfx_raw_background -000285d8 gfx_decode_background_image -00028629 gfx_set_taskbar -000286cd gfx_compositor_main -00028745 kernel_gfx_draw_circle_helper -000289bc gfx_get_window_width -000289d5 gfx_get_window_height -000289ee gfx_push_event -00028ab5 gfx_put_icon16 -00028bad gfx_put_icon32 -00028ca3 gfx_event_loop -00028dc9 kernel_gfx_draw_rectangle -00028ecb kernel_gfx_draw_contoured_box -00028f6f kernel_gfx_draw_pixel -00029018 kernel_gfx_draw_bitmap -0002913d kernel_gfx_draw_char -00029227 kernel_gfx_set_position -00029247 gfx_commit -00029264 kernel_gfx_draw_text -0002931b gfx_button_ext -00029452 gfx_button -00029474 kernel_gfx_set_title -000294e4 kernel_gfx_set_header -00029554 kernel_gfx_draw_line -000296ee kernel_gfx_draw_circle -00029771 kernel_gfx_draw_section -0002977b kernel_gfx_draw_format_text -00029acd gfx_syscall_hook -00029c89 gfx_total_themes -00029c93 kernel_gfx_current_theme -00029c9d kernel_gfx_update_theme -00029d6f kernel_gfx_default_theme -00029d79 kernel_gfx_set_theme -00029da2 kernel_gfx_get_theme -00029dc1 gfx_new_ctx -00029e21 gfx_init_framebuffer -00029f91 netdev_attach_driver -0002a03e is_netdev_attached -0002a050 netdev_transmit -0002a06f netdev_recieve -0002a09c net_ethernet_add_header -0002a134 net_ethernet_parse -0002a1af __skb_queue_remove -0002a1f1 __skb_queue_add -0002a245 skb_free_queue -0002a281 skb_new_queue -0002a2ec skb_free -0002a32b skb_new -0002a39a skb_consume -0002a3cf __net_arp_send -0002a48f net_init_arp -0002a4df net_arp_add_entry -0002a577 net_arp_find_entry -0002a5c6 net_arp_respond -0002a63f net_net_arp_request -0002a6c9 arp_parse -0002a777 net_ipv4_print -0002a781 net_ipv4_add_header -0002a8bc net_is_ipv4 -0002a8fd net_ipv4_parse -0002aa2e ntohl -0002aa5e htonl -0002aa75 ntohs -0002aa86 htons -0002aa97 checksum -0002aaf2 transport_checksum -0002ab4b ip_to_int -0002abed net_icmp_handle -0002acb6 net_icmp_response -0002acc0 net_icmp_request -0002ad87 ping -0002ade4 net_icmp_parse -0002ae58 net_udp_send -0002af91 net_udp_parse -0002b0bd socket_type_to_str -0002b0d0 socket_domain_to_str -0002b0e3 socket_protocol_to_str -0002b0f6 net_sock_bind -0002b145 net_get_sockets -0002b165 sock_get -0002b18a get_total_sockets -0002b194 net_sock_is_established -0002b1dc net_sock_awaiting_ack -0002b224 net_sock_data_ready -0002b27f net_sock_read -0002b384 net_sock_add_data -0002b5e8 sock_find_listen_tcp -0002b630 net_sock_find_tcp -0002b823 net_prepare_tcp_sock -0002b8b3 net_sock_accept -0002b8ca net_socket_find_udp -0002b939 kernel_sock_shutdown -0002b96a kernel_sock_cleanup -0002b9f4 kernel_sock_close -0002ba2c kernel_socket_create -0002bbb3 net_init_sockets -0002bbfd gethostname -0002c12b __add_systemcall_gethostname -0002c146 net_init_dns -0002c179 route -0002c1ca tcb_init -0002c1ec tcb_new -0002c35c tcp_state_to_str -0002c379 tcp_new_connection -0002c405 tcp_free_connection -0002c42c tcp_is_listening -0002c446 tcp_set_listening -0002c4aa tcp_calculate_checksum -0002c573 __tcp_send -0002c68f tcp_send_segment -0002c7d6 tcp_accept_connection -0002c91c tcp_send_ack -0002ca54 tcp_read -0002ca5e tcp_recv_segment -0002ca68 tcp_connect -0002cb0f tcp_send_syn -0002cb19 tcp_recv_ack -0002cba0 tcp_recv_fin -0002cbaa tcp_recv_syn -0002cce0 tcp_send_fin -0002cdb0 tcp_close_connection -0002cdf3 tcp_parse -0002d28f kernel_bind -0002d2c8 kernel_recvfrom -0002d2d2 kernel_recv -0002d348 kernel_recv_timeout -0002d372 kernel_connect -0002d478 kernel_sendto -0002d536 kernel_accept -0002d59d kernel_listen -0002d5c9 kernel_send -0002d653 sys_kernel_bind -0002d689 __add_systemcall_sys_kernel_bind -0002d6a4 __add_systemcall_sys_kernel_accept -0002d6bf __add_systemcall_sys_kernel_connect -0002d6da __add_systemcall_sys_kernel_listen -0002d6f5 __add_systemcall_sys_kernel_recv -0002d710 __add_systemcall_sys_kernel_recvfrom -0002d72b __add_systemcall_sys_kernel_recv_timeout -0002d746 __add_systemcall_sys_kernel_send -0002d761 __add_systemcall_sys_kernel_sendto -0002d77c __add_systemcall_sys_socket_create -0002d797 __add_systemcall_sys_kernel_sock_close -0002d7b2 sys_kernel_accept -0002d7f6 sys_kernel_connect -0002d82c sys_kernel_listen -0002d85f sys_kernel_recv -0002d89b sys_kernel_recvfrom -0002d8df sys_kernel_recv_timeout -0002d921 sys_kernel_send -0002d95d sys_kernel_sendto -0002d9a1 sys_socket_create -0002d9cc sys_kernel_sock_close -0002da11 __iface_send -0002da44 __iface_recieve -0002da77 __iface_assign -0002da8e __iface_detach -0002daa6 __iface_set_gateway -0002dabd __iface_set_netmask -0002dad4 __iface_configure -0002db28 __iface_attach -0002db51 net_interface_create -0002db8d net_register_netdev -0002dca9 net_interface_destroy -0002dcc2 __default_restart -0002dccc __default_stop -0002dd35 __default_start -0002ddb8 nm_new -0002de45 nm_free -0002de8e net_firewall_create -0002deb5 fs_file2fd -0002df1e fs_alloc_file -0002df6d fs_free_file -0002dfcb fs_register -0002e09e fs_init -0002e0a8 fs_unregister -0002e10f fs_get -0002e119 fs_close -0002e18f fs_open -0002e20d fs_seek -0002e28e fs_read -0002e3a7 fs_load_from_file -0002e437 fs_write -0002e4f6 fs_save_to_file -0002e586 fat16_rmdir -0002e590 fat16_stat -0002e59a fat16_close -0002e608 fat16_rename -0002e6a1 fat16_mkdir -0002e78a fat16_remove -0002e801 fat16_open -0002e94f fat16_read -0002eab2 fat16_write -0002ebe5 fat16_list -0002eeb7 fat16_init -0002ef6f path_next_iter -0002efdd inode_from_path_recursise -0002f05b inode_from_path -0002f11d ext_get_root -0002f12a ext_get_current_dir -0002f13d ext_get_size -0002f147 ext_get_inodes -0002f151 ext_get_blocks -0002f15b ext_sync -0002f1d2 ext_create -0002f2c1 ext_read -0002f340 ext_seek -0002f38b ext_write -0002f3fb ext_close -0002f461 ext_open_from_directory -0002f569 ext_open -0002f624 ext_size -0002f651 change_directory -0002f6bb ext_create_directory -0002f859 ext_create_file_system -0002fb2a init_ext -0002fcca listdir -0002fdf1 __inode_sync -0002fe54 __inode_cache_insert -0002ff4a __inode_load -0002ffbe inodes_sync -0002fffd inode_get -0003005e inode_read -0003024e inode_write -000304b5 alloc_inode -00030572 mkdir -00030623 sync -0003065b mkfs -0003066c fat16_read_data_from_cluster -000306be fat16_read_data -0003079b fat16_find_cluster_by_offset -0003081a fat16_write_data_to_cluster_with_offset -00030859 fat16_print_cluster_chain -0003088b fat16_write_data_to_cluster -000308c2 fat16_write_data -000309dd get_fat_start_block -000309e9 get_root_directory_start_block -000309fc get_data_start_block -00030a12 fat16_get_fat_entry -00030a31 fat16_set_fat_entry -00030a75 fat16_sync_fat_table -00030af1 fat16_allocate_cluster -00030b0d fat16_free_cluster -00030b26 fat16_get_free_cluster -00030b7f fat16_sync_directory_entry -00030c06 fat16_read_entry -00030cb7 fat16_find_entry -00030df2 fat16_rename_entry -00030e67 fat16_free_clusters -00030eb2 fat16_delete_entry -00030f1d fat16_add_entry -00031088 fat16_used_blocks -000310c5 fat16_to_upper -000310f5 fat16_name_compare -00031210 sstrtok -000312d3 fat16_directory_entry_debug -000313aa fat16_get_directory_entry -000315b3 fat16_create_directory -000316bc fat16_read_file -00031711 fat16_create_file -00031793 fat16_create_empty_file -0003185b fat16_directory_entries -00031946 fat16_mbr_clear -00031a11 fat16_mbr_add_entry -00031b06 fat16_print_root_directory_entries -00031b22 fat16_change_directory -00031bae fat16_bootblock_info -00031d2f fat16_set_time -00031d67 fat16_set_date -00031da3 fat16_load -00031f26 fat16_format -000321df mbr_partition_type_string -00032267 mbr_partitions_parse -00032335 mbr_get -0003233f mbr_partition_load -00032361 __list_users -000323f6 __change_user -0003249c __remove_user -0003254c __add_user -0003263a __find_user -0003270d __authenticate_user -00032820 __save_users -000328a8 __load_users -00032aae __ksymbol_admin -00032acc admin -00032de4 usermanager_create -00032e07 __ksymbol_snakegame -00032e25 init_game -00032e75 draw -00032ed5 get_input -00032ef8 update -00033084 game_loop -000330ae snakegame -000330fd __msgbox -00033510 msgbox_create -00033547 msgbox_show -00033593 kevents_list -00033709 kevents_init -0003374f kevents_destroy -000337a8 kevents_add -00033863 kevents_create -000338ea __ksymbol_editor -00033908 textbuffer_destroy -0003397f textbuffer_new_line -00033a35 textbuffer_handle_char -00033fea textbuffer_display -000340ce editor -00034244 _code_end +00010103 kernel +0001059d kernel_get_context +000105a3 hexdump +000107f1 __terminal_set_ops +000108ba __terminal_scanf +000108c0 __terminal_write +0001090a __terminal_getchar_graphics +00010953 __terminal_scan_graphics +00010a31 __terminal_reset +00010a75 __terminal_detach +00010ab8 __terminal_attach +00010b03 __terminal_remove_line +00010b43 __terminal_putchar_graphics +00010c0c __terminal_writef +00010f16 __terminal_getchar_textmode +00010f3e __terminal_scan_textmode +00011002 __terminal_commit_textmode +000110ba __terminal_putchar_textmode +00011106 scan +0001113f terminal_set_color +00011157 __terminal_commit_graphics +000112b3 terminal_attach +000112d4 terminal_commit +000112f3 terminal_putchar +0001132f terminal_create +00011454 terminal_destroy +0001148c tlb_flush_addr +00011494 load_page_directory +000114a4 enable_paging +000114b6 pcb_save_context +000114e2 pcb_restore_context +0001150b _start_pcb +0001153d _start_pcb_skip +00011558 __ksymbol_lspci +00011572 pci_get_class_name +00011585 pci_get_device_name +000115f6 pci_get_vendor_name +00011644 lspci +00011791 pci_get_devices +00011797 pci_read_word +000117f1 pci_write_dword +00011840 pci_enable_device_busmaster +00011895 pci_register_device +00011916 init_pci +00011ac7 pci_find_device +00011b5d virtual_read +00011b88 virtual_write +00011bb3 virtual_disk_attach +00011bd2 wm_default_changes +00011c7a wm_default_workspace +00011cdc wm_default_draw +00011d7a wm_default_add +00011e21 init_windowmanager +00011f6b wm_default_mouse_event +00012191 wm_default_push_back +00012283 wm_default_push_front +00012372 wm_default_remove +00012483 wm_destroy +00012561 wm_new +000125c8 scr_set_cursor +00012628 scrcolor_set +0001263c scrput +00012662 scrwrite +000126ab scr_clear +000126fd scr_scroll +00012745 scrprintf +00012989 strlen +000129ab strstr +00012a12 strcpy +00012a46 strncmp +00012a81 strcmp +00012ac1 memcmp +00012afc parse_arguments +00012bdf strchr +00012c0e getopt +00012d1e memcpy +00012d8b strtok +00012e43 xmemcpy +00012eca memset +00012f4a isdigit +00012f5e isspace +00012f6d tolower +00012f81 isxdigit +00012fa5 htoi +00013049 atoi +000130d9 itoa +0001317f itohex +000131fb rdtsc +000131fe rand +0001321a general_protection_fault +000132aa interrupt_get_count +000132b9 print_page_fault_info +00013396 page_fault_interrupt +00013428 interrupt_install_handler +0001343a load_data_segments +00013446 isr_handler +00013539 init_interrupts +000136b2 idt_flush +000136ba isr0 +000136c7 isr1 +000136d4 isr2 +000136e1 isr3 +000136ee isr4 +000136fb isr5 +00013708 isr6 +00013715 isr7 +00013722 isr8 +0001372f isr9 +0001373c isr10 +00013749 isr11 +00013756 isr12 +00013763 isr13 +00013770 isr14 +0001377d isr15 +0001378a isr16 +00013797 isr17 +000137a4 isr18 +000137b1 isr19 +000137be isr20 +000137cb isr21 +000137d8 isr22 +000137e5 isr23 +000137f2 isr24 +000137ff isr25 +0001380c isr26 +00013819 isr27 +00013826 isr28 +00013833 isr29 +00013840 isr30 +0001384d isr31 +0001385a isr32 +00013867 isr33 +00013874 isr34 +00013881 isr35 +0001388b isr36 +00013895 isr37 +0001389f isr38 +000138a9 isr39 +000138b3 isr40 +000138bd isr41 +000138c7 isr42 +000138d1 isr43 +000138db isr44 +000138e5 isr45 +000138ef isr46 +000138f9 isr47 +00013903 isr_entry +0001391e syscall_return_value +00013922 _syscall_entry +0001395f page_fault_save +00013963 page_fault_error +00013967 _page_fault_entry +00013999 timer_callback +000139d1 timer_get_tick +000139d7 time_get_difference +00013a1a init_pit +00013a7e gdt_set_segment +00013ac7 init_gdt +00013bd5 rc +00013dc4 __ksymbol_rc +00013dde __ksymbol_as +00013df8 __ksymbol_cc +00013e12 as +000141d4 cc +00014230 __cc +00014524 vm_print +00014721 eval +00014bbb vm_setup +00014bfc vm_init +00014c57 vm_free +00014c86 vm_setup_stack +00014ce2 lex_get_error +00014cef next +000151fa match +00015248 expression +00016549 statement +00016752 function_parameter +00016914 function_body +00016b23 function_declaration +00016bac enum_declaration +00016cbf global_declaration +00016eec lex_init +00016f87 program +00017028 find_mp_floating_ptr +00017064 smp_parse +000171a9 kb_get_char +000171f5 kb_add_char +00017230 kb_callback +0001745d init_keyboard +000174d4 __pcb_get_free +00017592 pcb_await +000175e1 __add_systemcall_pcb_await +000175f8 __pcb_free +00017647 __pcb_init_kernel_stack +000176a8 __pcb_init_process +0001776d init_pcbs +000177be pcb_total_usage +000177e7 pcb_get_info +000178db pcb_kill +000178f8 Genesis +000178fa idletask +00017915 pcb_get_by_pid +00017926 pcb_get_by_name +0001797f pcb_dbg_print +000179f9 pcb_cleanup_routine +00017c09 pcb_create_thread +00017d01 pcb_create_process +00017f93 pcb_create_kthread +0001826f start_pcb +000182a7 __pcb_queue_peek +000182e6 __pcb_queue_pop +00018342 __pcb_queue_remove +000183b4 __pcb_queue_add +0001842d __pcb_queue_push +000184c6 pcb_new_queue +000184f7 get_mem_info +0001854f memory_map_init +00018616 memory_map_get +0001861c free +00018673 malloc +0001870f calloc +00018742 krealloc +000187ae init_memory +00018840 vmem_free +000188b0 vmem_alloc +0001891d vmem_free_page_region +00018a83 vmem_page_region_alloc +00018abe vmem_create_page_region +00018c02 vmem_free_allocations +00018d31 vmem_continious_allocation_map +00018d37 vmem_free_allocation +00018d38 vmem_stack_free +00018de9 vmem_stack_alloc +0001916e vmem_dump_heap +00019203 vmem_init_process_thread +000192f4 vmem_init_process +00019622 vmem_cleanup_process_thead +00019699 vmem_cleanup_process +00019887 vmem_init_kernel +00019a48 vmem_allocator_create +00019aac vmem_map_driver_region +00019b2a vmem_total_usage +00019b3d vmem_init +00019c6f kalloc +00019e06 kcalloc +00019e38 kfree +00019ece palloc +00019f10 pmemory_used +00019f2c kmemory_used +00019f32 kmemory_total +00019f3e kmem_init +00019fdb e1000_receive +0001a0b6 e1000_transmit +0001a178 e1000_callback +0001a19f _e1000_tx_init +0001a243 _e1000_rx_init +0001a2dd e1000_attach +0001a50d display_get_info +0001a576 kenv_init +0001a58d kenv_set +0001a5c2 config_list +0001a693 kernel_config_load +0001aa7e config_get_value +0001ab39 spin_lock +0001ab59 spin_unlock +0001ab67 mutex_init +0001ab84 acquire +0001ac21 release +0001acc3 kthread_entry +0001ad1d kthread_list +0001ad84 register_kthread +0001ae5d start +0001aeff ata_primary +0001af00 ata_secondary +0001af01 ata_wait +0001af7b ata_write +0001b0f2 ata_read +0001b282 ata_ide_init +0001b452 set_bitmap +0001b474 unset_bitmap +0001b498 get_bitmap +0001b4ba get_bitmap_size +0001b4ce create_bitmap +0001b502 destroy_bitmap +0001b515 bitmap_unset_continous +0001b54f bitmap_get_continous +0001b5eb get_free_bitmap +0001b640 __rtc_check_in_progress +0001b662 __rtc_get_register +0001b682 get_current_time +0001b7cd get_time +0001b7f7 init_tss +0001b825 __add_systemcall_sys_system +0001b83c exec_cmd +0001b940 sys_system +0001b950 __ksymbol_exec_cmd +0001b96a system_reboot +0001b99e align_to_pointer_size +0001b9ac calculate_size_unit +0001ba0e advanced_hash +0001ba42 kernel_panic +0001ba60 kref_init +0001ba7a kref_get +0001baa2 kref_put +0001baca csprintf +0001bccb script_parse +0001bda0 login_startup +0001be08 login +0001c1d3 __login_create_virt_disk +0001c1fd __register_kthread_login +0001c217 help +0001c4b8 clear +0001c4d9 __ksymbol_new +0001c4f3 __ksymbol_list +0001c50d __ksymbol_color +0001c527 __ksymbol_about +0001c541 __ksymbol_help +0001c55b __ksymbol_kevents +0001c575 __ksymbol_view +0001c58f __ksymbol_file +0001c5a9 __ksymbol_tcp +0001c5c3 __ksymbol_conf +0001c5dd __ksymbol_clear +0001c5f7 __ksymbol_services +0001c611 __ksymbol_reboot +0001c62b kevents +0001c705 services +0001c933 new +0001ca74 list +0001cb74 file +0001cd42 color +0001cde3 about +0001ce20 view +0001d035 tcp +0001d312 __tcp_reader +0001d433 conf +0001d6fb reboot +0001d734 attach_disk_dev +0001d758 disk_attached +0001d760 disk_name +0001d769 disk_device_get +0001d76f disk_size +0001d78b write_block +0001d7c8 write_block_offset +0001d80b read_block +0001d848 read_block_offset +0001d8b2 sched_consume +0001d8f3 sched_add +0001d94d sched_prioritize +0001da02 sched_round_robin +0001dbe8 sched_exit +0001dca1 sched_block +0001ddbf sched_default +0001de99 sched_sleep +0001df3f sched_init_default +0001dfc0 get_scheduler +0001dfc6 kernel_sleep +0001dfe1 kernel_yield +0001e024 kernel_exit +0001e056 block +0001e07f unblock +0001e080 work_queue_add +0001e168 init_worker +0001e180 worker_thread +0001e21f __ring_buffer_add +0001e2c7 __ring_buffer_read +0001e3d1 rbuffer_new +0001e43a rbuffer_free +0001e45c error_get_string +0001e498 kclock +0001e978 __register_kthread_kclock +0001e992 tar_extract +0001ebe2 __ksymbol_tar +0001ebfc tar_list +0001ed06 tar +0001ef8f rgb_to_vga +0001ef9f rgb_to_components +0001efc6 color_distance_squared +0001f031 rgb_init_color_table +0001f0c2 iface_loopback_write +0001f183 iface_loopback_interrupt +0001f19a iface_loopback_read +0001f23d net_init_loopback +0001f254 serial_put +0001f294 serial_write +0001f2d6 serial_printf +0001f476 init_serial +0001f53c inportb +0001f545 inportw +0001f54f inportl +0001f558 outportb +0001f566 outportw +0001f575 outportl +0001f582 sys_create_thread +0001f5a1 sys_screen_put +0001f5de sys_screen_get +0001f5eb sys_scr_set_cursor +0001f603 __add_systemcall_sys_scr_set_cursor +0001f60e __add_systemcall_sys_screen_get +0001f619 __add_systemcall_sys_screen_put +0001f624 __add_systemcall_sys_create_thread +0001f62f add_system_call +0001f66f system_call +0001f6da hashmap_put +0001f741 hashmap_get +0001f7c5 hashmap_add +0001f84f hashmap_free +0001f850 reset_vga_palette +0001f896 vga_set_palette +0001f981 b8to16 +0001f991 vesa_put_pixel +0001f9bb vesa_put_box +0001fa36 vesa_put_block +0001fab1 vesa_put_char +0001fb2c vesa_put_char16 +0001fbbf vesa_put_icon16 +0001fc38 vesa_write +0001fc77 vesa_write_str +0001fca5 vesa_fill +0001fd27 vesa_fillrect +0001fd99 vesa_inner_box +0001fea1 vesa_printf +0002010e ksyms_init +00020335 ksyms_add_symbol +000203ee __ksymbol_backtrace +00020408 ksyms_list +0002046a ksyms_resolve_symbol +0002051d __backtrace_from +0002063a backtrace +0002064b ws_fullscreen +000207c5 ws_remove +00020875 ws_add +00020960 ws_destroy +00020a06 ws_draw +00020cb3 ws_raw_wallpaper +00020d99 ws_set_background_file +00021076 ws_init +00021159 ws_set_background +00021204 ws_new +00021291 encode_run_length +0002130e decode_run_length +00021379 __mouse_handler +00021490 mouse_wait +000214d8 mouse_write +0002151a mouse_get_event +0002155b mouse_init +00021640 sys_ipc_open +0002168e __add_systemcall_sys_ipc_open +000216a5 __add_systemcall_sys_ipc_close +000216bc __add_systemcall_sys_ipc_send +000216d3 __add_systemcall_sys_ipc_receive +000216ea sys_ipc_close +00021733 sys_ipc_send +0002179a sys_ipc_receive +00021800 sysinf +00022552 __register_kthread_sysinf +0002256c echo +000225a7 res +000225e8 ifconfig +000225f5 __ksymbol_ifconfig +0002260f __ksymbol_ps +00022629 __ksymbol_tree +00022643 __ksymbol_fat16 +0002265d __ksymbol_xxd +00022677 __ksymbol_sh +00022691 __ksymbol_ed +000226ab __ksymbol_exec +000226c5 __ksymbol_ths +000226df __ksymbol_dns +000226f9 __ksymbol_th +00022713 __ksymbol_kill +0002272d __ksymbol_echo +00022747 __ksymbol_fdisk +00022761 __ksymbol_meminfo +0002277b __ksymbol_res +00022795 __ksymbol_bg +000227af __ksymbol_exit +000227c9 __ksymbol_socks +000227e3 __ksymbol_reset +000227fd exit +00022831 ps +00022aa5 print_pcb_tree +00022ba4 tree +00022be4 fat16 +00022c0c xxd +00022d01 sh +00022e01 ed +00022e4e exec +00022fc4 ths +00023030 dns +000230a4 th +000230c2 kill +000230e0 fdisk +00023272 meminfo +00023451 bg +000234d0 socks +00023776 __register_kthread_shell +00023790 __register_kthread_textshell +000237aa shell_clear +000237ed reset_shell +0002385e reset +000238b2 shell_put +00023a93 shell +00023cf4 cleanup_function +00023d1b testfn +00023d4f draw_box +00023e34 __textshell_reset_box +00023ec4 textshell +0002430f __net_find_interface +0002436f net_drop_packet +00024390 net_handle_recieve +000244b7 net_get_interfaces +000244bd net_configure_iface +0002450f net_incoming_packet +000245c0 net_get_iface +00024636 net_iface_up +0002465d net_iface_down +00024684 net_list_ifaces +0002479e net_register_interface +000247cf net_send_skb +00024857 net_get_info +0002487e networking_main +00024a5e __dhcp_add_option +00024ace __dhcp_send_discovery +00024c10 __dhcp_send_request +00024d8d dhcp_get_state +00024d95 dhcp_get_dns +00024d9b dhcp_get_ip +00024db0 dhcp_get_gw +00024dc5 dhcpd +00025044 udp_server +000250cf tcp_server +00025243 __net_terminal_writef +000252a8 __register_kthread_tcp_server +000252c2 __register_kthread_udp_server +000252dc __register_kthread_udptest +000252f6 udptest +00025381 tcpd +00025465 logd +000254d0 __register_kthread_logd +000254ea logd_attach_by_pid +0002552e taskbar_reboot +0002555a __reboot +0002556f taskbar_readme +00025588 taskbar_about +000255a1 taskbar_clock +000255ba taskbar_sysinf +000255d3 taskbar_bg_retro +0002560a taskbar_bg_lotr2 +0002561f taskbar_bg_lotr +00025634 taskbar_bg_default_color_gray +00025646 taskbar_bg_default_color +00025658 taskbar_wolfstein +00025693 taskbar_bg_graph +000256ce taskbar_bg_calc +00025709 taskbar_colors +00025744 taskbar_cube +0002577f taskbar_editor +000257ba taskbar_finder +000257f5 taskbar_terminal +0002583e __register_kthread_taskbar +00025858 taskbar_hdr_opt_event +000258e2 taskbar +00025e99 about +00026064 __register_kthread_about +0002607e __register_kthread_readme +00026098 readme +000261fa gfx_default_hover +00026319 gfx_destory_window +000263a6 gfx_window_resize +0002644f gfx_window_maximize +000264c8 gfx_default_mouse_up +00026596 gfx_default_mouse_down +00026658 gfx_default_click +00026847 gfx_draw_window +00027633 gfx_window_set_resizable +00027648 kernel_gfx_window_border_color +00027673 gfx_new_window +000278d3 gfx_point_in_rectangle +00027900 gfx_draw_component +00027942 gfx_input_event +00027a74 gfx_input_draw +00027b7c gfx_input_manager_add +00027bdd gfx_composition_remove_window +00027c07 gfx_composition_add_window +00027c4e gfx_set_background_color +00027c9f gfx_raw_background +00027cec gfx_decode_background_image +00027d39 gfx_set_taskbar +00027dd9 gfx_compositor_main +00027e4d kernel_gfx_draw_circle_helper +000280f9 gfx_get_window_width +0002810e gfx_get_window_height +00028123 gfx_push_event +000281df gfx_put_icon16 +000282d7 gfx_put_icon32 +000283cf gfx_event_loop +000284ee kernel_gfx_draw_rectangle +000285e8 kernel_gfx_draw_contoured_box +00028688 kernel_gfx_draw_pixel +00028726 kernel_gfx_draw_bitmap +00028844 kernel_gfx_draw_char +00028944 kernel_gfx_set_position +00028960 gfx_commit +00028979 kernel_gfx_draw_text +00028a2c gfx_button_ext +00028b5f gfx_button +00028b7d kernel_gfx_set_title +00028be9 kernel_gfx_set_header +00028c55 kernel_gfx_draw_line +00028df0 kernel_gfx_draw_circle +00028e6f kernel_gfx_draw_section +00028e75 kernel_gfx_draw_format_text +000291c7 gfx_syscall_hook +0002937e gfx_total_themes +00029384 kernel_gfx_current_theme +0002938a kernel_gfx_update_theme +00029458 kernel_gfx_default_theme +0002945e kernel_gfx_set_theme +00029483 kernel_gfx_get_theme +0002949e gfx_new_ctx +000294fa gfx_init_framebuffer +00029666 netdev_attach_driver +0002970f is_netdev_attached +0002971d netdev_transmit +00029738 netdev_recieve +00029761 net_ethernet_add_header +000297f5 net_ethernet_parse +00029869 __skb_queue_remove +000298a7 __skb_queue_add +000298f7 skb_free_queue +0002992f skb_new_queue +00029996 skb_free +000299d1 skb_new +00029a3c skb_consume +00029a6d __net_arp_send +00029b2d net_init_arp +00029b79 net_arp_add_entry +00029c08 net_arp_find_entry +00029c53 net_arp_respond +00029cc8 net_net_arp_request +00029d4e arp_parse +00029df8 net_ipv4_print +00029dfe net_ipv4_add_header +00029f35 net_is_ipv4 +00029f72 net_ipv4_parse +0002a09f ntohl +0002a0cb htonl +0002a0de ntohs +0002a0eb htons +0002a0f8 checksum +0002a14f transport_checksum +0002a1a4 ip_to_int +0002a242 net_icmp_handle +0002a307 net_icmp_response +0002a30d net_icmp_request +0002a3d0 ping +0002a429 net_icmp_parse +0002a499 net_udp_send +0002a5ce net_udp_parse +0002a6f6 socket_type_to_str +0002a705 socket_domain_to_str +0002a714 socket_protocol_to_str +0002a723 net_sock_bind +0002a76e net_get_sockets +0002a78a sock_get +0002a7ab get_total_sockets +0002a7b1 net_sock_is_established +0002a7f5 net_sock_awaiting_ack +0002a839 net_sock_data_ready +0002a892 net_sock_read +0002a994 net_sock_add_data +0002abf4 sock_find_listen_tcp +0002ac38 net_sock_find_tcp +0002ae2a net_prepare_tcp_sock +0002aeb6 net_sock_accept +0002aec9 net_socket_find_udp +0002af34 kernel_sock_shutdown +0002af61 kernel_sock_cleanup +0002afe7 kernel_sock_close +0002b01b kernel_socket_create +0002b19e net_init_sockets +0002b1e4 gethostname +0002b6fe __add_systemcall_gethostname +0002b715 net_init_dns +0002b744 route +0002b791 tcb_init +0002b7af tcb_new +0002b91b tcp_state_to_str +0002b934 tcp_new_connection +0002b9bc tcp_free_connection +0002b9df tcp_is_listening +0002b9f5 tcp_set_listening +0002ba55 tcp_calculate_checksum +0002bb19 __tcp_send +0002bc35 tcp_send_segment +0002bd78 tcp_accept_connection +0002beba tcp_send_ack +0002bff0 tcp_read +0002bff6 tcp_recv_segment +0002bffc tcp_connect +0002c09f tcp_send_syn +0002c0a5 tcp_recv_ack +0002c128 tcp_recv_fin +0002c12e tcp_recv_syn +0002c260 tcp_send_fin +0002c32c tcp_close_connection +0002c36b tcp_parse +0002c804 kernel_bind +0002c839 kernel_recvfrom +0002c83f kernel_recv +0002c8b1 kernel_recv_timeout +0002c8d7 kernel_connect +0002c9db kernel_sendto +0002ca95 kernel_accept +0002caf8 kernel_listen +0002cb20 kernel_send +0002cba6 sys_kernel_bind +0002cbd8 __add_systemcall_sys_kernel_bind +0002cbef __add_systemcall_sys_kernel_accept +0002cc06 __add_systemcall_sys_kernel_connect +0002cc1d __add_systemcall_sys_kernel_listen +0002cc34 __add_systemcall_sys_kernel_recv +0002cc4b __add_systemcall_sys_kernel_recvfrom +0002cc62 __add_systemcall_sys_kernel_recv_timeout +0002cc79 __add_systemcall_sys_kernel_send +0002cc90 __add_systemcall_sys_kernel_sendto +0002cca7 __add_systemcall_sys_socket_create +0002ccbe __add_systemcall_sys_kernel_sock_close +0002ccd5 sys_kernel_accept +0002cd15 sys_kernel_connect +0002cd47 sys_kernel_listen +0002cd76 sys_kernel_recv +0002cdae sys_kernel_recvfrom +0002cdee sys_kernel_recv_timeout +0002ce2c sys_kernel_send +0002ce64 sys_kernel_sendto +0002cea4 sys_socket_create +0002cecb sys_kernel_sock_close +0002cf0c __iface_send +0002cf3b __iface_recieve +0002cf6a __iface_assign +0002cf7d __iface_detach +0002cf91 __iface_set_gateway +0002cfa4 __iface_set_netmask +0002cfb7 __iface_configure +0002d007 __iface_attach +0002d02c net_interface_create +0002d064 net_register_netdev +0002d17c net_interface_destroy +0002d191 __default_restart +0002d197 __default_stop +0002d1fc __default_start +0002d276 nm_new +0002d2ff nm_free +0002d344 net_firewall_create +0002d367 fs_file2fd +0002d3ce fs_alloc_file +0002d419 fs_free_file +0002d473 fs_register +0002d542 fs_init +0002d548 fs_unregister +0002d5ab fs_get +0002d5b1 fs_close +0002d623 fs_open +0002d69d fs_seek +0002d71a fs_read +0002d82f fs_load_from_file +0002d8bb fs_write +0002d976 fs_save_to_file +0002da02 fat16_rmdir +0002da08 fat16_stat +0002da0e fat16_close +0002da78 fat16_rename +0002db0d fat16_mkdir +0002dbf2 fat16_remove +0002dc65 fat16_open +0002ddaf fat16_read +0002df13 fat16_write +0002e042 fat16_list +0002e310 fat16_init +0002e3c4 path_next_iter +0002e433 inode_from_path_recursise +0002e4b1 inode_from_path +0002e56f ext_get_root +0002e578 ext_get_current_dir +0002e587 ext_get_size +0002e58d ext_get_inodes +0002e593 ext_get_blocks +0002e599 ext_sync +0002e60c ext_create +0002e6f7 ext_read +0002e772 ext_seek +0002e7b9 ext_write +0002e825 ext_close +0002e887 ext_open_from_directory +0002e98d ext_open +0002ea44 ext_size +0002ea6d change_directory +0002ead3 ext_create_directory +0002ec6d ext_create_file_system +0002ef3a init_ext +0002f0d6 listdir +0002f1f7 __inode_sync +0002f25a __inode_cache_insert +0002f350 __inode_load +0002f3c4 inodes_sync +0002f3ff inode_get +0002f45c inode_read +0002f644 inode_write +0002f8a2 alloc_inode +0002f95b mkdir +0002fa08 sync +0002fa3c mkfs +0002fa49 fat16_read_data_from_cluster +0002fa97 fat16_read_data +0002fb78 fat16_find_cluster_by_offset +0002fbf3 fat16_write_data_to_cluster_with_offset +0002fc2e fat16_print_cluster_chain +0002fc5c fat16_write_data_to_cluster +0002fc8f fat16_write_data +0002fdab get_fat_start_block +0002fdb3 get_root_directory_start_block +0002fdc2 get_data_start_block +0002fdd4 fat16_get_fat_entry +0002fdef fat16_set_fat_entry +0002fe2f fat16_sync_fat_table +0002fea7 fat16_allocate_cluster +0002febf fat16_free_cluster +0002fed4 fat16_get_free_cluster +0002ff29 fat16_sync_directory_entry +0002ffab fat16_read_entry +00030058 fat16_find_entry +00030193 fat16_rename_entry +00030204 fat16_free_clusters +0003024b fat16_delete_entry +000302b2 fat16_add_entry +00030419 fat16_used_blocks +00030452 fat16_to_upper +0003047e fat16_name_compare +000305a3 sstrtok +00030664 fat16_directory_entry_debug +00030734 fat16_get_directory_entry +0003092c fat16_create_directory +00030a31 fat16_read_file +00030a82 fat16_create_file +00030b00 fat16_create_empty_file +00030bc0 fat16_directory_entries +00030ca6 fat16_mbr_clear +00030d4f fat16_mbr_add_entry +00030e40 fat16_print_root_directory_entries +00030e58 fat16_change_directory +00030ee0 fat16_bootblock_info +0003105d fat16_set_time +00031091 fat16_set_date +000310c9 fat16_load +00031248 fat16_format +000314fd mbr_partition_type_string +00031580 mbr_partitions_parse +00031649 mbr_get +0003164f mbr_partition_load +0003166d __list_users +000316fe __change_user +000317a0 __remove_user +0003184c __add_user +00031936 __find_user +00031a0e __authenticate_user +00031b21 __save_users +00031ba5 __load_users +00031da7 __ksymbol_admin +00031dc1 admin +000320df usermanager_create +000320fe __ksymbol_snakegame +00032118 init_game +00032166 draw +000321c2 get_input +000321e1 update +00032368 game_loop +0003238e snakegame +000323d9 __msgbox +000327d9 msgbox_create +0003280c msgbox_show +00032854 kevents_list +000329c6 kevents_init +00032a08 kevents_destroy +00032a5d kevents_add +00032b14 kevents_create +00032b97 _code_end diff --git a/rootfs/sysutil/default.cfg b/rootfs/sysutil/default.cfg index 85c8856..4e26ea1 100644 --- a/rootfs/sysutil/default.cfg +++ b/rootfs/sysutil/default.cfg @@ -1,7 +1,10 @@ -# conf file is loaded on boot [terminal] background=0x0 text=0x1c [network] loopback=enable + +[system] +logon=disabled +user=admin diff --git a/rootfs/sysutil/startup.sh b/rootfs/sysutil/startup.sh index 7dc9d37..20a4276 100644 --- a/rootfs/sysutil/startup.sh +++ b/rootfs/sysutil/startup.sh @@ -1,3 +1,3 @@ exec kclock exec taskbar -exec /bin/users.o +exec -d /bin/users.o diff --git a/rootfs/sysutil/symbols.map b/rootfs/sysutil/symbols.map index b3bf55b..0a2f136 100644 --- a/rootfs/sysutil/symbols.map +++ b/rootfs/sysutil/symbols.map @@ -67,7 +67,7 @@ 000121d2 wm_default_remove 000122e3 wm_destroy 000123c1 wm_new -00012428 screen_set_cursor +00012428 scr_set_cursor 00012488 scrcolor_set 0001249c scrput 000124c2 scrwrite From 02f4bc995f569fc14edd705003fd2731f293d8b2 Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Wed, 7 Feb 2024 21:01:47 +0100 Subject: [PATCH 16/23] VGA textmode screen emulator --- Makefile | 2 +- apps/texed/texed.c | 13 + drivers/keyboard.c | 30 +- drivers/screen.c | 98 +++ drivers/vbe.c | 11 - drivers/vga.c | 56 ++ graphics/windowserver.c | 2 +- include/font8.h | 2 +- include/keyboard.h | 2 +- include/screen.h | 5 + kernel/kernel.c | 1 + kernel/kthreads/shell.c | 3 +- kernel/syscalls.c | 2 +- kernel/terminal.c | 5 +- lib/font8.c | 46 +- rootfs/symbols.map | 1781 ++++++++++++++++++++------------------- 16 files changed, 1142 insertions(+), 917 deletions(-) create mode 100644 drivers/screen.c diff --git a/Makefile b/Makefile index 37f5513..bc8c090 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ KERNELOBJ = bin/kernel.o bin/terminal.o bin/helpers.o bin/pci.o bin/virtualdisk. bin/diskdev.o bin/scheduler.o bin/work.o bin/rbuffer.o bin/errors.o bin/kclock.o bin/tar.o bin/color.o bin/loopback.o \ bin/serial.o bin/io.o bin/syscalls.o bin/list.o bin/hashmap.o bin/vbe.o bin/ksyms.o bin/windowserver.o bin/encoding.o\ bin/mouse.o bin/ipc.o bin/sysinf.o ${PROGRAMOBJ} ${GFXOBJ} bin/font8.o bin/net.o bin/fs.o bin/ext.o bin/fat16.o bin/partition.o\ - bin/admin.o bin/usermanager.o bin/user.o bin/group.o bin/snake.o bin/msgbox.o bin/kevents.o + bin/admin.o bin/usermanager.o bin/user.o bin/group.o bin/snake.o bin/msgbox.o bin/kevents.o bin/screen.o BOOTOBJ = bin/bootloader.o diff --git a/apps/texed/texed.c b/apps/texed/texed.c index 5ff9664..8782109 100644 --- a/apps/texed/texed.c +++ b/apps/texed/texed.c @@ -1,3 +1,14 @@ +/** + * @file texed.c + * @author Joe Bayer (joexbayer) + * @brief Textmode editor + * @version 0.1 + * @date 2024-02-07 + * + * @copyright Copyright (c) 2024 + * + */ + #include #include #include @@ -459,6 +470,8 @@ int main(int argc, char *argv[]) { return -1; } + screen_clear(0, 0, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + screen_draw_box(0, 1, 80, 23, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); if(argc > 1) { textbuffer_load_file(buffer, argv[1]); diff --git a/drivers/keyboard.c b/drivers/keyboard.c index 92e2d7d..b755d0e 100644 --- a/drivers/keyboard.c +++ b/drivers/keyboard.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -75,18 +76,31 @@ static uint8_t __alt_pressed = 0; static uint8_t __ctrl_pressed = 0; static uint8_t __super_pressed = 0; - -unsigned char kb_get_char() +unsigned char kb_get_char(int spin) { - //acquire(&kb_lock); - if(kb_buffer_tail == kb_buffer_head){ - //release(&kb_lock); - return 0; - } + acquire(&kb_lock); + + if(spin){ + + while(kb_buffer_tail == kb_buffer_head){ + release(&kb_lock); + + kernel_yield(); + + acquire(&kb_lock); + } + + } else { + if(kb_buffer_tail == kb_buffer_head){ + release(&kb_lock); + return 0; + } + } unsigned char c = kb_buffer[kb_buffer_tail]; kb_buffer_tail = (kb_buffer_tail + 1) % KB_BUFFER_SIZE; - //release(&kb_lock); + + release(&kb_lock); return c; } diff --git a/drivers/screen.c b/drivers/screen.c new file mode 100644 index 0000000..3200c8f --- /dev/null +++ b/drivers/screen.c @@ -0,0 +1,98 @@ +/** + * @file screen.c + * @author Joe Bayer (joexbayer) + * @brief VGA Textmode visual driver + * @version 0.1 + * @date 2024-02-07 + * + * @copyright Copyright (c) 2024 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VIDEO_ADDRESS 0xB8000 +#define MAX_ROWS 25 +#define MAX_COLS 80 + +/* Macro to extract the character from a VGA entry */ +#define VGA_ENTRY_CHAR(vga_entry) ((vga_entry) & 0xFF) +/* Macro to extract the foreground color from a VGA entry */ +#define VGA_ENTRY_FG_COLOR(vga_entry) (((vga_entry) >> 8) & 0x0F) +/* Macro to extract the background color from a VGA entry */ +#define VGA_ENTRY_BG_COLOR(vga_entry) (((vga_entry) >> 12) & 0x0F) + + +static int screen_draw_char(struct window* w, int x, int y, unsigned char c, color_t fg, color_t bg) +{ + for (int l = 0; l < 8; l++) { + for (int i = 8; i >= 0; i--) { + if(c > 0 && c < 128){ + if(font8x8_basic[c][l] & (1 << i)){ + putpixel(w->inner, (x)+i, (y)+l, fg, w->pitch); + } else { + putpixel(w->inner, (x)+i, (y)+l, bg, w->pitch); + } + } else if(c > 179 && c < 218 ) { + if (font8x8_box[c][l] & (1 << i)) { + putpixel(w->inner, (x)+i, (y)+l, fg, w->pitch); + } else { + putpixel(w->inner, (x)+i, (y)+l, bg, w->pitch); + } + } else { + putpixel(w->inner, (x)+i, (y)+l, COLOR_BLUE, w->pitch); + } + } + } + return 0; +} + +static int screeny(int argc, char* argv[]) +{ + struct window* w = gfx_new_window(MAX_COLS*8, MAX_ROWS*8, 0); + if(w == NULL){ + return -1; + } + kernel_gfx_set_title("VGA Textmode"); + + start("textshell", 0, NULL); + + while (1){ + for(int k = 0; k < MAX_ROWS; k++){ + for(int j = 0; j < MAX_COLS; j++){ + uint16_t entry = scrget(j, k); + unsigned char c = VGA_ENTRY_CHAR(entry); + color_t fg = VGA_ENTRY_FG_COLOR(entry); + color_t bg = VGA_ENTRY_BG_COLOR(entry); + + screen_draw_char(w, j*8, k*8, c, fg, bg); + } + } + + struct gfx_event event; + int ret = gfx_event_loop(&event, GFX_EVENT_NONBLOCKING); + if(ret == -1) continue; + + switch (event.event){ + case GFX_EVENT_EXIT: + return; + case GFX_EVENT_KEYBOARD: + scr_keyboard_add(event.data); + break; + default: + break; + } + + } + + return 0; +} +EXPORT_KTHREAD(screeny); \ No newline at end of file diff --git a/drivers/vbe.c b/drivers/vbe.c index a849c78..07581e6 100644 --- a/drivers/vbe.c +++ b/drivers/vbe.c @@ -100,17 +100,6 @@ void vesa_put_pixel(uint8_t* buffer, int x,int y, unsigned char color) putpixel(buffer, x , y, color, vbe_info->pitch); } -void vesa_put_box(uint8_t* buffer, unsigned char c, int x, int y, int color) -{ - for (int l = 0; l < 8; l++) { - for (int i = 8; i >= 0; i--) { - if (font8x8_box[c][l] & (1 << i)) { - putpixel(buffer, (x)+i, (y)+l, color, vbe_info->pitch); - } - } - } -} - void vesa_put_block(uint8_t* buffer, unsigned char c, int x, int y, int color) { for (int l = 0; l < 8; l++) { diff --git a/drivers/vga.c b/drivers/vga.c index 31dd7cb..a1d6fd6 100644 --- a/drivers/vga.c +++ b/drivers/vga.c @@ -18,10 +18,14 @@ #include #include #include +#include +#include #define MAX_FMT_STR_SIZE 50 uint16_t* const VGA_MEMORY = (uint16_t*) 0xB8000; + +uint16_t* VGA_BUFFER = NULL; //uint16_t* const VGA_MEMORY = (uint16_t*) 0xa0000; static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) @@ -62,6 +66,19 @@ void scrput(int x, int y, unsigned char c, uint8_t color) { const int index = y * SCREEN_WIDTH + x; VGA_MEMORY[index] = vga_entry(c, color); + if(VGA_BUFFER != NULL){ + VGA_BUFFER[index] = vga_entry(c, color); + } +} + +uint16_t scrget(int x, int y) +{ + if(VGA_BUFFER == NULL){ + return 0; + } + + const int index = y * SCREEN_WIDTH + x; + return VGA_BUFFER[index]; } /** @@ -191,4 +208,43 @@ int32_t scrprintf(int32_t x, int32_t y, char* fmt, ...) } written += x_offset; return written; +} + +int init_vga() +{ + VGA_BUFFER = (uint16_t*)kalloc(SCREEN_WIDTH*SCREEN_HEIGHT*sizeof(uint16_t)); + if(VGA_BUFFER == NULL){ + return -1; + } + for(int i = 0; i < SCREEN_WIDTH*SCREEN_HEIGHT; i++){ + VGA_BUFFER[i] = vga_entry(' ', scrcolor); + } + return 0; +} + + +/* MOVE TO A BETTER PLACE */ +static unsigned char kb_buffer[256] = {0}; +static int kb_buffer_tail = 0; +static int kb_buffer_head = 0; + +void scr_keyboard_add(unsigned char c) +{ + kb_buffer[kb_buffer_head] = c; + kb_buffer_head = (kb_buffer_head + 1) % 256; +} + +unsigned char scr_keyboard_get() +{ + if($kernel->graphic_mode == KERNEL_FLAG_TEXTMODE){ + return kb_get_char(1); + } else { + + while(kb_buffer_tail == kb_buffer_head){ + kernel_yield(); + } + unsigned char c = kb_buffer[kb_buffer_tail]; + kb_buffer_tail = (kb_buffer_tail + 1) % 256; + return c; + } } \ No newline at end of file diff --git a/graphics/windowserver.c b/graphics/windowserver.c index 1e8f00d..0a44999 100644 --- a/graphics/windowserver.c +++ b/graphics/windowserver.c @@ -319,7 +319,7 @@ static int ws_draw(struct windowserver* ws) int mouse_changed = mouse_get_event(&ws->m); get_current_time(&ws->time); ws->window_changes = ws->_wm->ops->changes(ws->_wm); - unsigned char key = kb_get_char(); + unsigned char key = kb_get_char(0); __ws_key_event(ws, key); diff --git a/include/font8.h b/include/font8.h index 0b93552..ebdb185 100644 --- a/include/font8.h +++ b/include/font8.h @@ -5,6 +5,6 @@ extern uint8_t font8x8_basic[128][8]; extern uint8_t font8x8_block[32][8]; -extern uint8_t font8x8_box[128][8]; +extern uint8_t font8x8_box[256][8]; #endif /* B826F0B7_0AD1_409C_87C1_1BD5D4EEA75C */ diff --git a/include/keyboard.h b/include/keyboard.h index 7e963fc..df5cf4b 100644 --- a/include/keyboard.h +++ b/include/keyboard.h @@ -24,6 +24,6 @@ #define CTRLE 229 void init_keyboard(); -unsigned char kb_get_char(); +unsigned char kb_get_char(int block); #endif \ No newline at end of file diff --git a/include/screen.h b/include/screen.h index a6c725d..2c23987 100644 --- a/include/screen.h +++ b/include/screen.h @@ -35,5 +35,10 @@ int screen_set_cursor(int x, int y); void scr_clear(); void scr_scroll(); int scrprintf(int32_t x, int32_t y, char* fmt, ...); +int init_vga(); +uint16_t scrget(int x, int y); + +void scr_keyboard_add(unsigned char c); +unsigned char scr_keyboard_get(); #endif \ No newline at end of file diff --git a/kernel/kernel.c b/kernel/kernel.c index 6237640..c34ace6 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -144,6 +144,7 @@ void kernel(uint32_t magic) init_pcbs(); init_pci(); init_worker(); + init_vga(); kernel_boot_printf("Kernel constructors initialized."); /* Graphics */ diff --git a/kernel/kthreads/shell.c b/kernel/kthreads/shell.c index 0bc97aa..42c1a21 100644 --- a/kernel/kthreads/shell.c +++ b/kernel/kthreads/shell.c @@ -726,7 +726,6 @@ static int textshell_login(struct terminal* term) static byte_t* text_shell_buffer = NULL; static void __kthread_entry textshell() { - ubyte_t c; short x = 0; @@ -758,7 +757,7 @@ static void __kthread_entry textshell() twritef("Type 'help' for a list of commands\n"); term->ops->commit(term); while (1){ - c = kb_get_char(); + c = scr_keyboard_get(); if(c == 0) continue; if(c == '\b'){ diff --git a/kernel/syscalls.c b/kernel/syscalls.c index a7523c5..b34c50c 100644 --- a/kernel/syscalls.c +++ b/kernel/syscalls.c @@ -54,7 +54,7 @@ EXPORT_SYSCALL(SYSCALL_SCREEN_PUT, sys_screen_put); char sys_screen_get() { - return kb_get_char(); + return scr_keyboard_get(); } EXPORT_SYSCALL(SYSCALL_SCREEN_GET, sys_screen_get); diff --git a/kernel/terminal.c b/kernel/terminal.c index 9982c24..b5cfcfe 100644 --- a/kernel/terminal.c +++ b/kernel/terminal.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -259,7 +260,7 @@ static int __terminal_getchar_textmode(struct terminal* term) { if(term == NULL) return -1; - ubyte_t c = kb_get_char(); + ubyte_t c = scr_keyboard_get(); if(c == 0) return -1; return c; @@ -273,7 +274,7 @@ static int __terminal_scan_textmode(struct terminal* term, ubyte_t* data, int si int i = 0; ubyte_t c = 0; while (i < size && c != '\n'){ - c = kb_get_char(); + c = scr_keyboard_get(); if(c == 0) continue; if(c == CTRLC){ diff --git a/lib/font8.c b/lib/font8.c index 04959a2..62e12e9 100644 --- a/lib/font8.c +++ b/lib/font8.c @@ -177,8 +177,52 @@ uint8_t font8x8_block[32][8] = { { 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F}, // U+259E (boxes top right and bottom left) { 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF}, // U+259F (boxes right and bottom) }; +uint8_t font8x8_box[256][8] = { + // ... (other characters before index 179) ... -uint8_t font8x8_box[128][8] = { + // Box Drawing Characters (Code Page 437) + [179] = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, // │ + [180] = {0x08, 0x08, 0x08, 0x0f, 0x0f, 0x00, 0x00, 0x00}, // ┤ + [181] = {0x08, 0x08, 0x08, 0xff, 0xff, 0x00, 0x00, 0x00}, // ╡ + [182] = {0x08, 0x08, 0x08, 0xf8, 0xf8, 0x00, 0x00, 0x00}, // ╢ + [183] = {0x08, 0x08, 0x08, 0x0f, 0x0f, 0x08, 0x08, 0x08}, // ╖ + [184] = {0x08, 0x08, 0x08, 0xff, 0xff, 0x08, 0x08, 0x08}, // ╕ + [185] = {0x08, 0x08, 0x08, 0xf8, 0xf8, 0x08, 0x08, 0x08}, // ╣ + [186] = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, // ║ + [187] = {0x00, 0x00, 0x00, 0x0f, 0x0f, 0x08, 0x08, 0x08}, // ╗ + [188] = {0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0x08, 0x08}, // ╝ + [189] = {0x00, 0x00, 0x00, 0xf8, 0xf8, 0x08, 0x08, 0x08}, // ╜ + [190] = {0x08, 0x08, 0x08, 0x0f, 0x0f, 0x00, 0x00, 0x00}, // ╛ + [191] = {0x08, 0x08, 0x08, 0xff, 0xff, 0x00, 0x00, 0x00}, // ┐ + [192] = {0x08, 0x08, 0x08, 0xf8, 0xf8, 0x00, 0x00, 0x00}, // └ + [193] = {0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0xff, 0x00}, // ┴ + [194] = {0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x0f, 0x00}, // ┬ + [195] = {0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0xf8, 0x00}, // ├ + [196] = {0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00}, // ─ + [197] = {0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0xff, 0x08}, // ┼ + [198] = {0x08, 0x08, 0x08, 0xff, 0xff, 0x08, 0x08, 0x08}, // ╞ + [199] = {0x08, 0x08, 0x08, 0x0f, 0x0f, 0x08, 0x08, 0x08}, // ╟ + [200] = {0x08, 0x08, 0x08, 0xf8, 0xf8, 0x08, 0x08, 0x08}, // ╚ + [201] = {0x08, 0x08, 0x08, 0xff, 0xff, 0x08, 0x08, 0x08}, // ╔ + [202] = {0x08, 0x08, 0x08, 0xff, 0xff, 0x00, 0x00, 0x00}, // ╩ + [203] = {0x08, 0x08, 0x08, 0x0f, 0x0f, 0x00, 0x00, 0x00}, // ╦ + [204] = {0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0x08, 0x08}, // ╠ + [205] = {0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00}, // ═ + [206] = {0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0x08, 0x08}, // ╬ + [207] = {0x00, 0x00, 0x00, 0x0f, 0x0f, 0x08, 0x08, 0x08}, // ╧ + [208] = {0x00, 0x00, 0x00, 0xf8, 0xf8, 0x08, 0x08, 0x08}, // ╨ + [209] = {0x08, 0x08, 0x08, 0xff, 0xff, 0x00, 0x00, 0x00}, // ╤ + [210] = {0x08, 0x08, 0x08, 0x0f, 0x0f, 0x00, 0x00, 0x00}, // ╥ + [211] = {0x08, 0x08, 0x08, 0xf8, 0xf8, 0x00, 0x00, 0x00}, // ╙ + [212] = {0x08, 0x08, 0x08, 0xff, 0xff, 0x00, 0x00, 0x00}, // ╘ + [213] = {0x00, 0x00, 0x00, 0x0f, 0x0f, 0x08, 0x08, 0x08}, // ╒ + [214] = {0x00, 0x00, 0x00, 0xf8, 0xf8, 0x08, 0x08, 0x08}, // ╓ + [215] = {0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0x08, 0x08}, // ╫ + [216] = {0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0x08, 0x08}, // ╪ + [217] = {0x08, 0x08, 0x08, 0x0f, 0x0f, 0x00, 0x00, 0x00}, // ┘ +}; + +uint8_t font8x8_box_old[128][8] = { { 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}, // U+2500 (thin horizontal) { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00}, // U+2501 (thick horizontal) { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, // U+2502 (thin vertical) diff --git a/rootfs/symbols.map b/rootfs/symbols.map index 1f5f505..607b5e4 100644 --- a/rootfs/symbols.map +++ b/rootfs/symbols.map @@ -8,891 +8,896 @@ 00010058 gdt_end 00010058 kernel_boot_printf 000100b7 init_kctors -00010103 kernel -0001059d kernel_get_context -000105a3 hexdump -000107f1 __terminal_set_ops -000108ba __terminal_scanf -000108c0 __terminal_write -0001090a __terminal_getchar_graphics -00010953 __terminal_scan_graphics -00010a31 __terminal_reset -00010a75 __terminal_detach -00010ab8 __terminal_attach -00010b03 __terminal_remove_line -00010b43 __terminal_putchar_graphics -00010c0c __terminal_writef -00010f16 __terminal_getchar_textmode -00010f3e __terminal_scan_textmode -00011002 __terminal_commit_textmode -000110ba __terminal_putchar_textmode -00011106 scan -0001113f terminal_set_color -00011157 __terminal_commit_graphics -000112b3 terminal_attach -000112d4 terminal_commit -000112f3 terminal_putchar -0001132f terminal_create -00011454 terminal_destroy -0001148c tlb_flush_addr -00011494 load_page_directory -000114a4 enable_paging -000114b6 pcb_save_context -000114e2 pcb_restore_context -0001150b _start_pcb -0001153d _start_pcb_skip -00011558 __ksymbol_lspci -00011572 pci_get_class_name -00011585 pci_get_device_name -000115f6 pci_get_vendor_name -00011644 lspci -00011791 pci_get_devices -00011797 pci_read_word -000117f1 pci_write_dword -00011840 pci_enable_device_busmaster -00011895 pci_register_device -00011916 init_pci -00011ac7 pci_find_device -00011b5d virtual_read -00011b88 virtual_write -00011bb3 virtual_disk_attach -00011bd2 wm_default_changes -00011c7a wm_default_workspace -00011cdc wm_default_draw -00011d7a wm_default_add -00011e21 init_windowmanager -00011f6b wm_default_mouse_event -00012191 wm_default_push_back -00012283 wm_default_push_front -00012372 wm_default_remove -00012483 wm_destroy -00012561 wm_new -000125c8 scr_set_cursor -00012628 scrcolor_set -0001263c scrput -00012662 scrwrite -000126ab scr_clear -000126fd scr_scroll -00012745 scrprintf -00012989 strlen -000129ab strstr -00012a12 strcpy -00012a46 strncmp -00012a81 strcmp -00012ac1 memcmp -00012afc parse_arguments -00012bdf strchr -00012c0e getopt -00012d1e memcpy -00012d8b strtok -00012e43 xmemcpy -00012eca memset -00012f4a isdigit -00012f5e isspace -00012f6d tolower -00012f81 isxdigit -00012fa5 htoi -00013049 atoi -000130d9 itoa -0001317f itohex -000131fb rdtsc -000131fe rand -0001321a general_protection_fault -000132aa interrupt_get_count -000132b9 print_page_fault_info -00013396 page_fault_interrupt -00013428 interrupt_install_handler -0001343a load_data_segments -00013446 isr_handler -00013539 init_interrupts -000136b2 idt_flush -000136ba isr0 -000136c7 isr1 -000136d4 isr2 -000136e1 isr3 -000136ee isr4 -000136fb isr5 -00013708 isr6 -00013715 isr7 -00013722 isr8 -0001372f isr9 -0001373c isr10 -00013749 isr11 -00013756 isr12 -00013763 isr13 -00013770 isr14 -0001377d isr15 -0001378a isr16 -00013797 isr17 -000137a4 isr18 -000137b1 isr19 -000137be isr20 -000137cb isr21 -000137d8 isr22 -000137e5 isr23 -000137f2 isr24 -000137ff isr25 -0001380c isr26 -00013819 isr27 -00013826 isr28 -00013833 isr29 -00013840 isr30 -0001384d isr31 -0001385a isr32 -00013867 isr33 -00013874 isr34 -00013881 isr35 -0001388b isr36 -00013895 isr37 -0001389f isr38 -000138a9 isr39 -000138b3 isr40 -000138bd isr41 -000138c7 isr42 -000138d1 isr43 -000138db isr44 -000138e5 isr45 -000138ef isr46 -000138f9 isr47 -00013903 isr_entry -0001391e syscall_return_value -00013922 _syscall_entry -0001395f page_fault_save -00013963 page_fault_error -00013967 _page_fault_entry -00013999 timer_callback -000139d1 timer_get_tick -000139d7 time_get_difference -00013a1a init_pit -00013a7e gdt_set_segment -00013ac7 init_gdt -00013bd5 rc -00013dc4 __ksymbol_rc -00013dde __ksymbol_as -00013df8 __ksymbol_cc -00013e12 as -000141d4 cc -00014230 __cc -00014524 vm_print -00014721 eval -00014bbb vm_setup -00014bfc vm_init -00014c57 vm_free -00014c86 vm_setup_stack -00014ce2 lex_get_error -00014cef next -000151fa match -00015248 expression -00016549 statement -00016752 function_parameter -00016914 function_body -00016b23 function_declaration -00016bac enum_declaration -00016cbf global_declaration -00016eec lex_init -00016f87 program -00017028 find_mp_floating_ptr -00017064 smp_parse -000171a9 kb_get_char -000171f5 kb_add_char -00017230 kb_callback -0001745d init_keyboard -000174d4 __pcb_get_free -00017592 pcb_await -000175e1 __add_systemcall_pcb_await -000175f8 __pcb_free -00017647 __pcb_init_kernel_stack -000176a8 __pcb_init_process -0001776d init_pcbs -000177be pcb_total_usage -000177e7 pcb_get_info -000178db pcb_kill -000178f8 Genesis -000178fa idletask -00017915 pcb_get_by_pid -00017926 pcb_get_by_name -0001797f pcb_dbg_print -000179f9 pcb_cleanup_routine -00017c09 pcb_create_thread -00017d01 pcb_create_process -00017f93 pcb_create_kthread -0001826f start_pcb -000182a7 __pcb_queue_peek -000182e6 __pcb_queue_pop -00018342 __pcb_queue_remove -000183b4 __pcb_queue_add -0001842d __pcb_queue_push -000184c6 pcb_new_queue -000184f7 get_mem_info -0001854f memory_map_init -00018616 memory_map_get -0001861c free -00018673 malloc -0001870f calloc -00018742 krealloc -000187ae init_memory -00018840 vmem_free -000188b0 vmem_alloc -0001891d vmem_free_page_region -00018a83 vmem_page_region_alloc -00018abe vmem_create_page_region -00018c02 vmem_free_allocations -00018d31 vmem_continious_allocation_map -00018d37 vmem_free_allocation -00018d38 vmem_stack_free -00018de9 vmem_stack_alloc -0001916e vmem_dump_heap -00019203 vmem_init_process_thread -000192f4 vmem_init_process -00019622 vmem_cleanup_process_thead -00019699 vmem_cleanup_process -00019887 vmem_init_kernel -00019a48 vmem_allocator_create -00019aac vmem_map_driver_region -00019b2a vmem_total_usage -00019b3d vmem_init -00019c6f kalloc -00019e06 kcalloc -00019e38 kfree -00019ece palloc -00019f10 pmemory_used -00019f2c kmemory_used -00019f32 kmemory_total -00019f3e kmem_init -00019fdb e1000_receive -0001a0b6 e1000_transmit -0001a178 e1000_callback -0001a19f _e1000_tx_init -0001a243 _e1000_rx_init -0001a2dd e1000_attach -0001a50d display_get_info -0001a576 kenv_init -0001a58d kenv_set -0001a5c2 config_list -0001a693 kernel_config_load -0001aa7e config_get_value -0001ab39 spin_lock -0001ab59 spin_unlock -0001ab67 mutex_init -0001ab84 acquire -0001ac21 release -0001acc3 kthread_entry -0001ad1d kthread_list -0001ad84 register_kthread -0001ae5d start -0001aeff ata_primary -0001af00 ata_secondary -0001af01 ata_wait -0001af7b ata_write -0001b0f2 ata_read -0001b282 ata_ide_init -0001b452 set_bitmap -0001b474 unset_bitmap -0001b498 get_bitmap -0001b4ba get_bitmap_size -0001b4ce create_bitmap -0001b502 destroy_bitmap -0001b515 bitmap_unset_continous -0001b54f bitmap_get_continous -0001b5eb get_free_bitmap -0001b640 __rtc_check_in_progress -0001b662 __rtc_get_register -0001b682 get_current_time -0001b7cd get_time -0001b7f7 init_tss -0001b825 __add_systemcall_sys_system -0001b83c exec_cmd -0001b940 sys_system -0001b950 __ksymbol_exec_cmd -0001b96a system_reboot -0001b99e align_to_pointer_size -0001b9ac calculate_size_unit -0001ba0e advanced_hash -0001ba42 kernel_panic -0001ba60 kref_init -0001ba7a kref_get -0001baa2 kref_put -0001baca csprintf -0001bccb script_parse -0001bda0 login_startup -0001be08 login -0001c1d3 __login_create_virt_disk -0001c1fd __register_kthread_login -0001c217 help -0001c4b8 clear -0001c4d9 __ksymbol_new -0001c4f3 __ksymbol_list -0001c50d __ksymbol_color -0001c527 __ksymbol_about -0001c541 __ksymbol_help -0001c55b __ksymbol_kevents -0001c575 __ksymbol_view -0001c58f __ksymbol_file -0001c5a9 __ksymbol_tcp -0001c5c3 __ksymbol_conf -0001c5dd __ksymbol_clear -0001c5f7 __ksymbol_services -0001c611 __ksymbol_reboot -0001c62b kevents -0001c705 services -0001c933 new -0001ca74 list -0001cb74 file -0001cd42 color -0001cde3 about -0001ce20 view -0001d035 tcp -0001d312 __tcp_reader -0001d433 conf -0001d6fb reboot -0001d734 attach_disk_dev -0001d758 disk_attached -0001d760 disk_name -0001d769 disk_device_get -0001d76f disk_size -0001d78b write_block -0001d7c8 write_block_offset -0001d80b read_block -0001d848 read_block_offset -0001d8b2 sched_consume -0001d8f3 sched_add -0001d94d sched_prioritize -0001da02 sched_round_robin -0001dbe8 sched_exit -0001dca1 sched_block -0001ddbf sched_default -0001de99 sched_sleep -0001df3f sched_init_default -0001dfc0 get_scheduler -0001dfc6 kernel_sleep -0001dfe1 kernel_yield -0001e024 kernel_exit -0001e056 block -0001e07f unblock -0001e080 work_queue_add -0001e168 init_worker -0001e180 worker_thread -0001e21f __ring_buffer_add -0001e2c7 __ring_buffer_read -0001e3d1 rbuffer_new -0001e43a rbuffer_free -0001e45c error_get_string -0001e498 kclock -0001e978 __register_kthread_kclock -0001e992 tar_extract -0001ebe2 __ksymbol_tar -0001ebfc tar_list -0001ed06 tar -0001ef8f rgb_to_vga -0001ef9f rgb_to_components -0001efc6 color_distance_squared -0001f031 rgb_init_color_table -0001f0c2 iface_loopback_write -0001f183 iface_loopback_interrupt -0001f19a iface_loopback_read -0001f23d net_init_loopback -0001f254 serial_put -0001f294 serial_write -0001f2d6 serial_printf -0001f476 init_serial -0001f53c inportb -0001f545 inportw -0001f54f inportl -0001f558 outportb -0001f566 outportw -0001f575 outportl -0001f582 sys_create_thread -0001f5a1 sys_screen_put -0001f5de sys_screen_get -0001f5eb sys_scr_set_cursor -0001f603 __add_systemcall_sys_scr_set_cursor -0001f60e __add_systemcall_sys_screen_get -0001f619 __add_systemcall_sys_screen_put -0001f624 __add_systemcall_sys_create_thread -0001f62f add_system_call -0001f66f system_call -0001f6da hashmap_put -0001f741 hashmap_get -0001f7c5 hashmap_add -0001f84f hashmap_free -0001f850 reset_vga_palette -0001f896 vga_set_palette -0001f981 b8to16 -0001f991 vesa_put_pixel -0001f9bb vesa_put_box -0001fa36 vesa_put_block -0001fab1 vesa_put_char -0001fb2c vesa_put_char16 -0001fbbf vesa_put_icon16 -0001fc38 vesa_write -0001fc77 vesa_write_str -0001fca5 vesa_fill -0001fd27 vesa_fillrect -0001fd99 vesa_inner_box -0001fea1 vesa_printf -0002010e ksyms_init -00020335 ksyms_add_symbol -000203ee __ksymbol_backtrace -00020408 ksyms_list -0002046a ksyms_resolve_symbol -0002051d __backtrace_from -0002063a backtrace -0002064b ws_fullscreen -000207c5 ws_remove -00020875 ws_add -00020960 ws_destroy -00020a06 ws_draw -00020cb3 ws_raw_wallpaper -00020d99 ws_set_background_file -00021076 ws_init -00021159 ws_set_background -00021204 ws_new -00021291 encode_run_length -0002130e decode_run_length -00021379 __mouse_handler -00021490 mouse_wait -000214d8 mouse_write -0002151a mouse_get_event -0002155b mouse_init -00021640 sys_ipc_open -0002168e __add_systemcall_sys_ipc_open -000216a5 __add_systemcall_sys_ipc_close -000216bc __add_systemcall_sys_ipc_send -000216d3 __add_systemcall_sys_ipc_receive -000216ea sys_ipc_close -00021733 sys_ipc_send -0002179a sys_ipc_receive -00021800 sysinf -00022552 __register_kthread_sysinf -0002256c echo -000225a7 res -000225e8 ifconfig -000225f5 __ksymbol_ifconfig -0002260f __ksymbol_ps -00022629 __ksymbol_tree -00022643 __ksymbol_fat16 -0002265d __ksymbol_xxd -00022677 __ksymbol_sh -00022691 __ksymbol_ed -000226ab __ksymbol_exec -000226c5 __ksymbol_ths -000226df __ksymbol_dns -000226f9 __ksymbol_th -00022713 __ksymbol_kill -0002272d __ksymbol_echo -00022747 __ksymbol_fdisk -00022761 __ksymbol_meminfo -0002277b __ksymbol_res -00022795 __ksymbol_bg -000227af __ksymbol_exit -000227c9 __ksymbol_socks -000227e3 __ksymbol_reset -000227fd exit -00022831 ps -00022aa5 print_pcb_tree -00022ba4 tree -00022be4 fat16 -00022c0c xxd -00022d01 sh -00022e01 ed -00022e4e exec -00022fc4 ths -00023030 dns -000230a4 th -000230c2 kill -000230e0 fdisk -00023272 meminfo -00023451 bg -000234d0 socks -00023776 __register_kthread_shell -00023790 __register_kthread_textshell -000237aa shell_clear -000237ed reset_shell -0002385e reset -000238b2 shell_put -00023a93 shell -00023cf4 cleanup_function -00023d1b testfn -00023d4f draw_box -00023e34 __textshell_reset_box -00023ec4 textshell -0002430f __net_find_interface -0002436f net_drop_packet -00024390 net_handle_recieve -000244b7 net_get_interfaces -000244bd net_configure_iface -0002450f net_incoming_packet -000245c0 net_get_iface -00024636 net_iface_up -0002465d net_iface_down -00024684 net_list_ifaces -0002479e net_register_interface -000247cf net_send_skb -00024857 net_get_info -0002487e networking_main -00024a5e __dhcp_add_option -00024ace __dhcp_send_discovery -00024c10 __dhcp_send_request -00024d8d dhcp_get_state -00024d95 dhcp_get_dns -00024d9b dhcp_get_ip -00024db0 dhcp_get_gw -00024dc5 dhcpd -00025044 udp_server -000250cf tcp_server -00025243 __net_terminal_writef -000252a8 __register_kthread_tcp_server -000252c2 __register_kthread_udp_server -000252dc __register_kthread_udptest -000252f6 udptest -00025381 tcpd -00025465 logd -000254d0 __register_kthread_logd -000254ea logd_attach_by_pid -0002552e taskbar_reboot -0002555a __reboot -0002556f taskbar_readme -00025588 taskbar_about -000255a1 taskbar_clock -000255ba taskbar_sysinf -000255d3 taskbar_bg_retro -0002560a taskbar_bg_lotr2 -0002561f taskbar_bg_lotr -00025634 taskbar_bg_default_color_gray -00025646 taskbar_bg_default_color -00025658 taskbar_wolfstein -00025693 taskbar_bg_graph -000256ce taskbar_bg_calc -00025709 taskbar_colors -00025744 taskbar_cube -0002577f taskbar_editor -000257ba taskbar_finder -000257f5 taskbar_terminal -0002583e __register_kthread_taskbar -00025858 taskbar_hdr_opt_event -000258e2 taskbar -00025e99 about -00026064 __register_kthread_about -0002607e __register_kthread_readme -00026098 readme -000261fa gfx_default_hover -00026319 gfx_destory_window -000263a6 gfx_window_resize -0002644f gfx_window_maximize -000264c8 gfx_default_mouse_up -00026596 gfx_default_mouse_down -00026658 gfx_default_click -00026847 gfx_draw_window -00027633 gfx_window_set_resizable -00027648 kernel_gfx_window_border_color -00027673 gfx_new_window -000278d3 gfx_point_in_rectangle -00027900 gfx_draw_component -00027942 gfx_input_event -00027a74 gfx_input_draw -00027b7c gfx_input_manager_add -00027bdd gfx_composition_remove_window -00027c07 gfx_composition_add_window -00027c4e gfx_set_background_color -00027c9f gfx_raw_background -00027cec gfx_decode_background_image -00027d39 gfx_set_taskbar -00027dd9 gfx_compositor_main -00027e4d kernel_gfx_draw_circle_helper -000280f9 gfx_get_window_width -0002810e gfx_get_window_height -00028123 gfx_push_event -000281df gfx_put_icon16 -000282d7 gfx_put_icon32 -000283cf gfx_event_loop -000284ee kernel_gfx_draw_rectangle -000285e8 kernel_gfx_draw_contoured_box -00028688 kernel_gfx_draw_pixel -00028726 kernel_gfx_draw_bitmap -00028844 kernel_gfx_draw_char -00028944 kernel_gfx_set_position -00028960 gfx_commit -00028979 kernel_gfx_draw_text -00028a2c gfx_button_ext -00028b5f gfx_button -00028b7d kernel_gfx_set_title -00028be9 kernel_gfx_set_header -00028c55 kernel_gfx_draw_line -00028df0 kernel_gfx_draw_circle -00028e6f kernel_gfx_draw_section -00028e75 kernel_gfx_draw_format_text -000291c7 gfx_syscall_hook -0002937e gfx_total_themes -00029384 kernel_gfx_current_theme -0002938a kernel_gfx_update_theme -00029458 kernel_gfx_default_theme -0002945e kernel_gfx_set_theme -00029483 kernel_gfx_get_theme -0002949e gfx_new_ctx -000294fa gfx_init_framebuffer -00029666 netdev_attach_driver -0002970f is_netdev_attached -0002971d netdev_transmit -00029738 netdev_recieve -00029761 net_ethernet_add_header -000297f5 net_ethernet_parse -00029869 __skb_queue_remove -000298a7 __skb_queue_add -000298f7 skb_free_queue -0002992f skb_new_queue -00029996 skb_free -000299d1 skb_new -00029a3c skb_consume -00029a6d __net_arp_send -00029b2d net_init_arp -00029b79 net_arp_add_entry -00029c08 net_arp_find_entry -00029c53 net_arp_respond -00029cc8 net_net_arp_request -00029d4e arp_parse -00029df8 net_ipv4_print -00029dfe net_ipv4_add_header -00029f35 net_is_ipv4 -00029f72 net_ipv4_parse -0002a09f ntohl -0002a0cb htonl -0002a0de ntohs -0002a0eb htons -0002a0f8 checksum -0002a14f transport_checksum -0002a1a4 ip_to_int -0002a242 net_icmp_handle -0002a307 net_icmp_response -0002a30d net_icmp_request -0002a3d0 ping -0002a429 net_icmp_parse -0002a499 net_udp_send -0002a5ce net_udp_parse -0002a6f6 socket_type_to_str -0002a705 socket_domain_to_str -0002a714 socket_protocol_to_str -0002a723 net_sock_bind -0002a76e net_get_sockets -0002a78a sock_get -0002a7ab get_total_sockets -0002a7b1 net_sock_is_established -0002a7f5 net_sock_awaiting_ack -0002a839 net_sock_data_ready -0002a892 net_sock_read -0002a994 net_sock_add_data -0002abf4 sock_find_listen_tcp -0002ac38 net_sock_find_tcp -0002ae2a net_prepare_tcp_sock -0002aeb6 net_sock_accept -0002aec9 net_socket_find_udp -0002af34 kernel_sock_shutdown -0002af61 kernel_sock_cleanup -0002afe7 kernel_sock_close -0002b01b kernel_socket_create -0002b19e net_init_sockets -0002b1e4 gethostname -0002b6fe __add_systemcall_gethostname -0002b715 net_init_dns -0002b744 route -0002b791 tcb_init -0002b7af tcb_new -0002b91b tcp_state_to_str -0002b934 tcp_new_connection -0002b9bc tcp_free_connection -0002b9df tcp_is_listening -0002b9f5 tcp_set_listening -0002ba55 tcp_calculate_checksum -0002bb19 __tcp_send -0002bc35 tcp_send_segment -0002bd78 tcp_accept_connection -0002beba tcp_send_ack -0002bff0 tcp_read -0002bff6 tcp_recv_segment -0002bffc tcp_connect -0002c09f tcp_send_syn -0002c0a5 tcp_recv_ack -0002c128 tcp_recv_fin -0002c12e tcp_recv_syn -0002c260 tcp_send_fin -0002c32c tcp_close_connection -0002c36b tcp_parse -0002c804 kernel_bind -0002c839 kernel_recvfrom -0002c83f kernel_recv -0002c8b1 kernel_recv_timeout -0002c8d7 kernel_connect -0002c9db kernel_sendto -0002ca95 kernel_accept -0002caf8 kernel_listen -0002cb20 kernel_send -0002cba6 sys_kernel_bind -0002cbd8 __add_systemcall_sys_kernel_bind -0002cbef __add_systemcall_sys_kernel_accept -0002cc06 __add_systemcall_sys_kernel_connect -0002cc1d __add_systemcall_sys_kernel_listen -0002cc34 __add_systemcall_sys_kernel_recv -0002cc4b __add_systemcall_sys_kernel_recvfrom -0002cc62 __add_systemcall_sys_kernel_recv_timeout -0002cc79 __add_systemcall_sys_kernel_send -0002cc90 __add_systemcall_sys_kernel_sendto -0002cca7 __add_systemcall_sys_socket_create -0002ccbe __add_systemcall_sys_kernel_sock_close -0002ccd5 sys_kernel_accept -0002cd15 sys_kernel_connect -0002cd47 sys_kernel_listen -0002cd76 sys_kernel_recv -0002cdae sys_kernel_recvfrom -0002cdee sys_kernel_recv_timeout -0002ce2c sys_kernel_send -0002ce64 sys_kernel_sendto -0002cea4 sys_socket_create -0002cecb sys_kernel_sock_close -0002cf0c __iface_send -0002cf3b __iface_recieve -0002cf6a __iface_assign -0002cf7d __iface_detach -0002cf91 __iface_set_gateway -0002cfa4 __iface_set_netmask -0002cfb7 __iface_configure -0002d007 __iface_attach -0002d02c net_interface_create -0002d064 net_register_netdev -0002d17c net_interface_destroy -0002d191 __default_restart -0002d197 __default_stop -0002d1fc __default_start -0002d276 nm_new -0002d2ff nm_free -0002d344 net_firewall_create -0002d367 fs_file2fd -0002d3ce fs_alloc_file -0002d419 fs_free_file -0002d473 fs_register -0002d542 fs_init -0002d548 fs_unregister -0002d5ab fs_get -0002d5b1 fs_close -0002d623 fs_open -0002d69d fs_seek -0002d71a fs_read -0002d82f fs_load_from_file -0002d8bb fs_write -0002d976 fs_save_to_file -0002da02 fat16_rmdir -0002da08 fat16_stat -0002da0e fat16_close -0002da78 fat16_rename -0002db0d fat16_mkdir -0002dbf2 fat16_remove -0002dc65 fat16_open -0002ddaf fat16_read -0002df13 fat16_write -0002e042 fat16_list -0002e310 fat16_init -0002e3c4 path_next_iter -0002e433 inode_from_path_recursise -0002e4b1 inode_from_path -0002e56f ext_get_root -0002e578 ext_get_current_dir -0002e587 ext_get_size -0002e58d ext_get_inodes -0002e593 ext_get_blocks -0002e599 ext_sync -0002e60c ext_create -0002e6f7 ext_read -0002e772 ext_seek -0002e7b9 ext_write -0002e825 ext_close -0002e887 ext_open_from_directory -0002e98d ext_open -0002ea44 ext_size -0002ea6d change_directory -0002ead3 ext_create_directory -0002ec6d ext_create_file_system -0002ef3a init_ext -0002f0d6 listdir -0002f1f7 __inode_sync -0002f25a __inode_cache_insert -0002f350 __inode_load -0002f3c4 inodes_sync -0002f3ff inode_get -0002f45c inode_read -0002f644 inode_write -0002f8a2 alloc_inode -0002f95b mkdir -0002fa08 sync -0002fa3c mkfs -0002fa49 fat16_read_data_from_cluster -0002fa97 fat16_read_data -0002fb78 fat16_find_cluster_by_offset -0002fbf3 fat16_write_data_to_cluster_with_offset -0002fc2e fat16_print_cluster_chain -0002fc5c fat16_write_data_to_cluster -0002fc8f fat16_write_data -0002fdab get_fat_start_block -0002fdb3 get_root_directory_start_block -0002fdc2 get_data_start_block -0002fdd4 fat16_get_fat_entry -0002fdef fat16_set_fat_entry -0002fe2f fat16_sync_fat_table -0002fea7 fat16_allocate_cluster -0002febf fat16_free_cluster -0002fed4 fat16_get_free_cluster -0002ff29 fat16_sync_directory_entry -0002ffab fat16_read_entry -00030058 fat16_find_entry -00030193 fat16_rename_entry -00030204 fat16_free_clusters -0003024b fat16_delete_entry -000302b2 fat16_add_entry -00030419 fat16_used_blocks -00030452 fat16_to_upper -0003047e fat16_name_compare -000305a3 sstrtok -00030664 fat16_directory_entry_debug -00030734 fat16_get_directory_entry -0003092c fat16_create_directory -00030a31 fat16_read_file -00030a82 fat16_create_file -00030b00 fat16_create_empty_file -00030bc0 fat16_directory_entries -00030ca6 fat16_mbr_clear -00030d4f fat16_mbr_add_entry -00030e40 fat16_print_root_directory_entries -00030e58 fat16_change_directory -00030ee0 fat16_bootblock_info -0003105d fat16_set_time -00031091 fat16_set_date -000310c9 fat16_load -00031248 fat16_format -000314fd mbr_partition_type_string -00031580 mbr_partitions_parse -00031649 mbr_get -0003164f mbr_partition_load -0003166d __list_users -000316fe __change_user -000317a0 __remove_user -0003184c __add_user -00031936 __find_user -00031a0e __authenticate_user -00031b21 __save_users -00031ba5 __load_users -00031da7 __ksymbol_admin -00031dc1 admin -000320df usermanager_create -000320fe __ksymbol_snakegame -00032118 init_game -00032166 draw -000321c2 get_input -000321e1 update -00032368 game_loop -0003238e snakegame -000323d9 __msgbox -000327d9 msgbox_create -0003280c msgbox_show -00032854 kevents_list -000329c6 kevents_init -00032a08 kevents_destroy -00032a5d kevents_add -00032b14 kevents_create -00032b97 _code_end +00010109 kernel +000105ac kernel_get_context +000105b6 hexdump +00010806 __terminal_set_ops +000108d3 __terminal_scanf +000108dd __terminal_write +0001092b __terminal_getchar_graphics +00010978 __terminal_scan_graphics +00010a5a __terminal_reset +00010aa2 __terminal_detach +00010ae9 __terminal_attach +00010b38 __terminal_remove_line +00010b78 __terminal_putchar_graphics +00010c45 __terminal_writef +00010f54 __terminal_getchar_textmode +00010f80 __terminal_scan_textmode +00011048 __terminal_commit_textmode +00011104 __terminal_putchar_textmode +00011154 scan +00011191 terminal_set_color +000111ad __terminal_commit_graphics +0001130e terminal_attach +00011333 terminal_commit +00011356 terminal_putchar +00011396 terminal_create +000114bf terminal_destroy +000114fc tlb_flush_addr +00011504 load_page_directory +00011514 enable_paging +00011526 pcb_save_context +00011552 pcb_restore_context +0001157b _start_pcb +000115ad _start_pcb_skip +000115c8 __ksymbol_lspci +000115e6 pci_get_class_name +000115fd pci_get_device_name +00011672 pci_get_vendor_name +000116c4 lspci +00011815 pci_get_devices +0001181f pci_read_word +0001187c pci_write_dword +000118cf pci_enable_device_busmaster +00011928 pci_register_device +000119ad init_pci +00011b71 pci_find_device +00011c0b virtual_read +00011c3a virtual_write +00011c69 virtual_disk_attach +00011c8c wm_default_changes +00011d38 wm_default_workspace +00011d9e wm_default_draw +00011e40 wm_default_add +00011eeb init_windowmanager +00012037 wm_default_mouse_event +00012255 wm_default_push_back +0001234b wm_default_push_front +0001243e wm_default_remove +00012553 wm_destroy +00012635 wm_new +000126a0 scr_set_cursor +00012700 scrcolor_set +00012718 scrput +00012752 scrget +0001277c scrwrite +000127c9 scr_clear +0001281f scr_scroll +0001286b scrprintf +00012aeb init_vga +00012b13 scr_keyboard_add +00012b3d scr_keyboard_get +00012ba3 strlen +00012bc9 strstr +00012c37 strcpy +00012c6d strncmp +00012caa strcmp +00012cee memcmp +00012d2b parse_arguments +00012e14 strchr +00012e47 getopt +00012f92 memcpy +00013003 strtok +000130bf xmemcpy +00013148 memset +000131c6 isdigit +000131de isspace +000131f1 tolower +00013209 isxdigit +00013231 htoi +000132d9 atoi +0001336b itoa +0001341b itohex +0001349b rdtsc +000134a2 rand +000134c2 general_protection_fault +00013556 interrupt_get_count +00013569 print_page_fault_info +00013646 page_fault_interrupt +000136dc interrupt_install_handler +000136f2 load_data_segments +00013702 isr_handler +000137f9 init_interrupts +00013976 idt_flush +0001397e isr0 +0001398b isr1 +00013998 isr2 +000139a5 isr3 +000139b2 isr4 +000139bf isr5 +000139cc isr6 +000139d9 isr7 +000139e6 isr8 +000139f3 isr9 +00013a00 isr10 +00013a0d isr11 +00013a1a isr12 +00013a27 isr13 +00013a34 isr14 +00013a41 isr15 +00013a4e isr16 +00013a5b isr17 +00013a68 isr18 +00013a75 isr19 +00013a82 isr20 +00013a8f isr21 +00013a9c isr22 +00013aa9 isr23 +00013ab6 isr24 +00013ac3 isr25 +00013ad0 isr26 +00013add isr27 +00013aea isr28 +00013af7 isr29 +00013b04 isr30 +00013b11 isr31 +00013b1e isr32 +00013b2b isr33 +00013b38 isr34 +00013b45 isr35 +00013b4f isr36 +00013b59 isr37 +00013b63 isr38 +00013b6d isr39 +00013b77 isr40 +00013b81 isr41 +00013b8b isr42 +00013b95 isr43 +00013b9f isr44 +00013ba9 isr45 +00013bb3 isr46 +00013bbd isr47 +00013bc7 isr_entry +00013be2 syscall_return_value +00013be6 _syscall_entry +00013c23 page_fault_save +00013c27 page_fault_error +00013c2b _page_fault_entry +00013c5d timer_callback +00013c99 timer_get_tick +00013ca3 time_get_difference +00013ce8 init_pit +00013d50 gdt_set_segment +00013d9b init_gdt +00013ead rc +000140a0 __ksymbol_rc +000140be __ksymbol_as +000140dc __ksymbol_cc +000140fa as +000144c0 cc +00014520 __cc +00014819 vm_print +00014a1a eval +00014eb9 vm_setup +00014efe vm_init +00014f5d vm_free +00014f90 vm_setup_stack +00014fee lex_get_error +00014fff next +0001561a match +0001566c expression +00016a87 statement +00016c94 function_parameter +00016e5a function_body +0001706d function_declaration +000170fa enum_declaration +00017210 global_declaration +00017441 lex_init +000174e0 program +00017585 find_mp_floating_ptr +000175c5 smp_parse +0001770f kb_get_char +000177db kb_add_char +0001781a kb_callback +00017a4b init_keyboard +00017ac6 __pcb_get_free +00017b8c pcb_await +00017be0 __add_systemcall_pcb_await +00017bfb __pcb_free +00017c4a __pcb_init_kernel_stack +00017cab __pcb_init_process +00017d70 init_pcbs +00017dc5 pcb_total_usage +00017de6 pcb_get_info +00017ecc pcb_kill +00017eed Genesis +00017ef3 idletask +00017f12 pcb_get_by_pid +00017f27 pcb_get_by_name +00017f84 pcb_dbg_print +00018002 pcb_cleanup_routine +00018217 pcb_create_thread +00018313 pcb_create_process +000185ac pcb_create_kthread +00018892 start_pcb +000188ce __pcb_queue_peek +00018911 __pcb_queue_pop +00018971 __pcb_queue_remove +000189e7 __pcb_queue_add +00018a64 __pcb_queue_push +00018b01 pcb_new_queue +00018b36 get_mem_info +00018b92 memory_map_init +00018c5e memory_map_get +00018c68 free +00018cc3 malloc +00018d2f calloc +00018d66 krealloc +00018dd6 init_memory +00018e6c vmem_free +00018ee0 vmem_alloc +00018f51 vmem_free_page_region +000190ba vmem_page_region_alloc +000190f5 vmem_create_page_region +00019238 vmem_free_allocations +00019360 vmem_continious_allocation_map +0001936a vmem_free_allocation +0001936f vmem_stack_free +00019424 vmem_stack_alloc +000197ce vmem_dump_heap +00019867 vmem_init_process_thread +0001995c vmem_init_process +00019c89 vmem_cleanup_process_thead +00019d04 vmem_cleanup_process +00019ef4 vmem_init_kernel +0001a0b5 vmem_allocator_create +0001a11f vmem_map_driver_region +0001a1a1 vmem_total_usage +0001a1b8 vmem_init +0001a2f0 kalloc +0001a48b kcalloc +0001a4c1 kfree +0001a55b palloc +0001a5ab pmemory_used +0001a5cc kmemory_used +0001a5d6 kmemory_total +0001a5e6 kmem_init +0001a687 e1000_receive +0001a763 e1000_transmit +0001a829 e1000_callback +0001a854 _e1000_tx_init +0001a8fc _e1000_rx_init +0001a99a e1000_attach +0001abed display_get_info +0001ac5b kenv_init +0001ac76 kenv_set +0001acb2 config_list +0001ad98 kernel_config_load +0001b166 config_get_value +0001b229 spin_lock +0001b24d spin_unlock +0001b25f mutex_init +0001b281 acquire +0001b322 release +0001b3c8 kthread_entry +0001b426 kthread_list +0001b491 register_kthread +0001b56e start +0001b614 ata_primary +0001b619 ata_secondary +0001b61e ata_wait +0001b698 ata_write +0001b80a ata_read +0001b988 ata_ide_init +0001bb5c set_bitmap +0001bb82 unset_bitmap +0001bbaa get_bitmap +0001bbd0 get_bitmap_size +0001bbe8 create_bitmap +0001bc20 destroy_bitmap +0001bc37 bitmap_unset_continous +0001bc74 bitmap_get_continous +0001bd0e get_free_bitmap +0001bd67 __rtc_check_in_progress +0001bd8e __rtc_get_register +0001bdb2 get_current_time +0001befb get_time +0001bf29 init_tss +0001bf5b __add_systemcall_sys_system +0001bf76 exec_cmd +0001c0cf sys_system +0001c0e3 __ksymbol_exec_cmd +0001c101 system_reboot +0001c139 align_to_pointer_size +0001c14b calculate_size_unit +0001c1ab advanced_hash +0001c1e6 kernel_panic +0001c208 kref_init +0001c226 kref_get +0001c252 kref_put +0001c27e csprintf +0001c47c script_parse +0001c54e login_startup +0001c5b6 login +0001c985 __login_create_virt_disk +0001c9b3 __register_kthread_login +0001c9d1 help +0001cc76 clear +0001cc9b __ksymbol_new +0001ccb9 __ksymbol_list +0001ccd7 __ksymbol_color +0001ccf5 __ksymbol_about +0001cd13 __ksymbol_help +0001cd31 __ksymbol_kevents +0001cd4f __ksymbol_view +0001cd6d __ksymbol_file +0001cd8b __ksymbol_tcp +0001cda9 __ksymbol_conf +0001cdc7 __ksymbol_clear +0001cde5 __ksymbol_services +0001ce03 __ksymbol_reboot +0001ce21 kevents +0001ceff services +0001d131 new +0001d276 list +0001d37a file +0001d54c color +0001d5f1 about +0001d632 view +0001d84b tcp +0001db2c __tcp_reader +0001dc51 conf +0001df1d reboot +0001df5a attach_disk_dev +0001df82 disk_attached +0001df8e disk_name +0001df9b disk_device_get +0001dfa5 disk_size +0001dfc5 write_block +0001e006 write_block_offset +0001e04d read_block +0001e08e read_block_offset +0001e0fc sched_consume +0001e141 sched_add +0001e19f sched_prioritize +0001e258 sched_round_robin +0001e43e sched_exit +0001e4fb sched_block +0001e61d sched_default +0001e6f8 sched_sleep +0001e7a2 sched_init_default +0001e827 get_scheduler +0001e831 kernel_sleep +0001e850 kernel_yield +0001e897 kernel_exit +0001e8cd block +0001e8fa unblock +0001e8ff work_queue_add +0001ea03 init_worker +0001ea1f worker_thread +0001eac2 __ring_buffer_add +0001eb6e __ring_buffer_read +0001ec7c rbuffer_new +0001ece9 rbuffer_free +0001ed0f error_get_string +0001ed4f kclock +0001f22a __register_kthread_kclock +0001f248 tar_extract +0001f498 __ksymbol_tar +0001f4b6 tar_list +0001f5c1 tar +0001f84e rgb_to_vga +0001f862 rgb_to_components +0001f88d color_distance_squared +0001f8fd rgb_init_color_table +0001f988 iface_loopback_write +0001fa4d iface_loopback_interrupt +0001fa68 iface_loopback_read +0001fb12 net_init_loopback +0001fb2d serial_put +0001fb71 serial_write +0001fbb7 serial_printf +0001fd6b init_serial +0001fe35 inportb +0001fe42 inportw +0001fe50 inportl +0001fe5d outportb +0001fe6d outportw +0001fe7e outportl +0001fe8e sys_create_thread +0001feb1 sys_screen_put +0001fef2 sys_screen_get +0001ff03 sys_scr_set_cursor +0001ff1f __add_systemcall_sys_scr_set_cursor +0001ff2e __add_systemcall_sys_screen_get +0001ff3d __add_systemcall_sys_screen_put +0001ff4c __add_systemcall_sys_create_thread +0001ff5b add_system_call +0001ff9f system_call +0002000e hashmap_put +0002007a hashmap_get +00020102 hashmap_add +00020190 hashmap_free +00020195 reset_vga_palette +000201df vga_set_palette +000202ce b8to16 +000202e4 vesa_put_pixel +00020312 vesa_put_block +0002038c vesa_put_char +00020406 vesa_put_char16 +0002049e vesa_put_icon16 +00020519 vesa_write +0002055c vesa_write_str +0002058e vesa_fill +00020612 vesa_fillrect +00020681 vesa_inner_box +0002078d vesa_printf +00020a19 ksyms_init +00020c38 ksyms_add_symbol +00020cf5 __ksymbol_backtrace +00020d13 ksyms_list +00020d79 ksyms_resolve_symbol +00020e30 __backtrace_from +00020f4e backtrace +00020f63 ws_fullscreen +000210e1 ws_remove +00021195 ws_add +00021284 ws_destroy +0002132e ws_draw +000215e6 ws_raw_wallpaper +000216d0 ws_set_background_file +000219b0 ws_init +00021a97 ws_set_background +00021b46 ws_new +00021bd7 encode_run_length +00021c60 decode_run_length +00021cd7 __mouse_handler +00021def mouse_wait +00021e37 mouse_write +00021e79 mouse_get_event +00021ebe mouse_init +00021fa7 sys_ipc_open +00021ff9 __add_systemcall_sys_ipc_open +00022014 __add_systemcall_sys_ipc_close +0002202f __add_systemcall_sys_ipc_send +0002204a __add_systemcall_sys_ipc_receive +00022065 sys_ipc_close +000220b2 sys_ipc_send +0002211d sys_ipc_receive +00022187 sysinf +00022ef3 __register_kthread_sysinf +00022f11 echo +00022f50 res +00022f95 ifconfig +00022fa6 __ksymbol_ifconfig +00022fc4 __ksymbol_ps +00022fe2 __ksymbol_tree +00023000 __ksymbol_fat16 +0002301e __ksymbol_xxd +0002303c __ksymbol_sh +0002305a __ksymbol_ed +00023078 __ksymbol_exec +00023096 __ksymbol_ths +000230b4 __ksymbol_dns +000230d2 __ksymbol_th +000230f0 __ksymbol_kill +0002310e __ksymbol_echo +0002312c __ksymbol_fdisk +0002314a __ksymbol_meminfo +00023168 __ksymbol_res +00023186 __ksymbol_bg +000231a4 __ksymbol_exit +000231c2 __ksymbol_socks +000231e0 __ksymbol_reset +000231fe exit +00023236 ps +000234ae print_pcb_tree +000235ad tree +000235f1 fat16 +0002361d xxd +00023716 sh +0002381a ed +0002386b exec +000239e7 ths +00023a57 dns +00023acf th +00023af1 kill +00023b13 fdisk +00023ca9 meminfo +00023e8c bg +00023f0f socks +000241b8 __register_kthread_shell +000241d6 __register_kthread_textshell +000241f4 shell_clear +0002423b reset_shell +000242b0 reset +00024308 shell_put +000244ee shell +00024753 cleanup_function +0002477e testfn +000247b6 draw_box +0002489f __textshell_reset_box +0002492f textshell +00024d7c __net_find_interface +00024ddc net_drop_packet +00024dfd net_handle_recieve +00024f28 net_get_interfaces +00024f32 net_configure_iface +00024f88 net_incoming_packet +0002503a net_get_iface +000250b6 net_iface_up +000250e1 net_iface_down +0002510c net_list_ifaces +0002522a net_register_interface +0002525f net_send_skb +000252eb net_get_info +00025316 networking_main +000254f6 __dhcp_add_option +00025560 __dhcp_send_discovery +000256a2 __dhcp_send_request +0002581f dhcp_get_state +0002582b dhcp_get_dns +00025835 dhcp_get_ip +0002584e dhcp_get_gw +00025867 dhcpd +00025afb udp_server +00025b8a tcp_server +00025d02 __net_terminal_writef +00025d6b __register_kthread_tcp_server +00025d89 __register_kthread_udp_server +00025da7 __register_kthread_udptest +00025dc5 udptest +00025e54 tcpd +00025f3c logd +00025fab __register_kthread_logd +00025fc9 logd_attach_by_pid +00026011 taskbar_reboot +00026041 __reboot +0002605a taskbar_readme +00026077 taskbar_about +00026094 taskbar_clock +000260b1 taskbar_sysinf +000260ce taskbar_bg_retro +00026109 taskbar_bg_lotr2 +00026122 taskbar_bg_lotr +0002613b taskbar_bg_default_color_gray +00026151 taskbar_bg_default_color +00026167 taskbar_wolfstein +000261a6 taskbar_bg_graph +000261e5 taskbar_bg_calc +00026224 taskbar_colors +00026263 taskbar_cube +000262a2 taskbar_editor +000262e1 taskbar_finder +00026320 taskbar_terminal +0002636d __register_kthread_taskbar +0002638b taskbar_hdr_opt_event +00026415 taskbar +00026a22 about +00026bf1 __register_kthread_about +00026c0f __register_kthread_readme +00026c2d readme +00026d93 gfx_default_hover +00026ec1 gfx_draw_window +00027cdc gfx_destory_window +00027d6d gfx_window_resize +00027e1a gfx_window_maximize +00027e97 gfx_default_mouse_up +00027f69 gfx_default_mouse_down +0002802f gfx_default_click +00028222 gfx_window_set_resizable +0002823b kernel_gfx_window_border_color +0002826a gfx_new_window +000284d1 gfx_point_in_rectangle +00028502 gfx_draw_component +00028548 gfx_input_event +00028669 gfx_input_draw +00028775 gfx_input_manager_add +000287da gfx_composition_remove_window +00028808 gfx_composition_add_window +00028853 gfx_set_background_color +000288a8 gfx_raw_background +000288f9 gfx_decode_background_image +0002894a gfx_set_taskbar +000289ee gfx_compositor_main +00028a66 kernel_gfx_draw_circle_helper +00028cdd gfx_get_window_width +00028cf6 gfx_get_window_height +00028d0f gfx_push_event +00028dd6 gfx_put_icon16 +00028ece gfx_put_icon32 +00028fc4 gfx_event_loop +000290ea kernel_gfx_draw_rectangle +000291ec kernel_gfx_draw_contoured_box +00029290 kernel_gfx_draw_pixel +00029339 kernel_gfx_draw_bitmap +0002945e kernel_gfx_draw_char +00029548 kernel_gfx_set_position +00029568 gfx_commit +00029585 kernel_gfx_draw_text +0002963c gfx_button_ext +00029773 gfx_button +00029795 kernel_gfx_set_title +00029805 kernel_gfx_set_header +00029875 kernel_gfx_draw_line +00029a0f kernel_gfx_draw_circle +00029a92 kernel_gfx_draw_section +00029a9c kernel_gfx_draw_format_text +00029dee gfx_syscall_hook +00029faa gfx_total_themes +00029fb4 kernel_gfx_current_theme +00029fbe kernel_gfx_update_theme +0002a090 kernel_gfx_default_theme +0002a09a kernel_gfx_set_theme +0002a0c3 kernel_gfx_get_theme +0002a0e2 gfx_new_ctx +0002a142 gfx_init_framebuffer +0002a2b2 netdev_attach_driver +0002a35f is_netdev_attached +0002a371 netdev_transmit +0002a390 netdev_recieve +0002a3bd net_ethernet_add_header +0002a455 net_ethernet_parse +0002a4d0 __skb_queue_remove +0002a512 __skb_queue_add +0002a566 skb_free_queue +0002a5a2 skb_new_queue +0002a60d skb_free +0002a64c skb_new +0002a6bb skb_consume +0002a6f0 __net_arp_send +0002a7b0 net_init_arp +0002a800 net_arp_add_entry +0002a898 net_arp_find_entry +0002a8e7 net_arp_respond +0002a960 net_net_arp_request +0002a9ea arp_parse +0002aa98 net_ipv4_print +0002aaa2 net_ipv4_add_header +0002abdd net_is_ipv4 +0002ac1e net_ipv4_parse +0002ad4f ntohl +0002ad7f htonl +0002ad96 ntohs +0002ada7 htons +0002adb8 checksum +0002ae13 transport_checksum +0002ae6c ip_to_int +0002af0e net_icmp_handle +0002afd7 net_icmp_response +0002afe1 net_icmp_request +0002b0a8 ping +0002b105 net_icmp_parse +0002b179 net_udp_send +0002b2b2 net_udp_parse +0002b3de socket_type_to_str +0002b3f1 socket_domain_to_str +0002b404 socket_protocol_to_str +0002b417 net_sock_bind +0002b466 net_get_sockets +0002b486 sock_get +0002b4ab get_total_sockets +0002b4b5 net_sock_is_established +0002b4fd net_sock_awaiting_ack +0002b545 net_sock_data_ready +0002b5a0 net_sock_read +0002b6a5 net_sock_add_data +0002b909 sock_find_listen_tcp +0002b951 net_sock_find_tcp +0002bb44 net_prepare_tcp_sock +0002bbd4 net_sock_accept +0002bbeb net_socket_find_udp +0002bc5a kernel_sock_shutdown +0002bc8b kernel_sock_cleanup +0002bd15 kernel_sock_close +0002bd4d kernel_socket_create +0002bed4 net_init_sockets +0002bf1e gethostname +0002c44c __add_systemcall_gethostname +0002c467 net_init_dns +0002c49a route +0002c4eb tcb_init +0002c50d tcb_new +0002c67d tcp_state_to_str +0002c69a tcp_new_connection +0002c726 tcp_free_connection +0002c74d tcp_is_listening +0002c767 tcp_set_listening +0002c7cb tcp_calculate_checksum +0002c894 __tcp_send +0002c9b0 tcp_send_segment +0002caf7 tcp_accept_connection +0002cc3d tcp_send_ack +0002cd75 tcp_read +0002cd7f tcp_recv_segment +0002cd89 tcp_connect +0002ce30 tcp_send_syn +0002ce3a tcp_recv_ack +0002cec1 tcp_recv_fin +0002cecb tcp_recv_syn +0002d001 tcp_send_fin +0002d0d1 tcp_close_connection +0002d114 tcp_parse +0002d5b0 kernel_bind +0002d5e9 kernel_recvfrom +0002d5f3 kernel_recv +0002d669 kernel_recv_timeout +0002d693 kernel_connect +0002d799 kernel_sendto +0002d857 kernel_accept +0002d8be kernel_listen +0002d8ea kernel_send +0002d974 sys_kernel_bind +0002d9aa __add_systemcall_sys_kernel_bind +0002d9c5 __add_systemcall_sys_kernel_accept +0002d9e0 __add_systemcall_sys_kernel_connect +0002d9fb __add_systemcall_sys_kernel_listen +0002da16 __add_systemcall_sys_kernel_recv +0002da31 __add_systemcall_sys_kernel_recvfrom +0002da4c __add_systemcall_sys_kernel_recv_timeout +0002da67 __add_systemcall_sys_kernel_send +0002da82 __add_systemcall_sys_kernel_sendto +0002da9d __add_systemcall_sys_socket_create +0002dab8 __add_systemcall_sys_kernel_sock_close +0002dad3 sys_kernel_accept +0002db17 sys_kernel_connect +0002db4d sys_kernel_listen +0002db80 sys_kernel_recv +0002dbbc sys_kernel_recvfrom +0002dc00 sys_kernel_recv_timeout +0002dc42 sys_kernel_send +0002dc7e sys_kernel_sendto +0002dcc2 sys_socket_create +0002dced sys_kernel_sock_close +0002dd32 __iface_send +0002dd65 __iface_recieve +0002dd98 __iface_assign +0002ddaf __iface_detach +0002ddc7 __iface_set_gateway +0002ddde __iface_set_netmask +0002ddf5 __iface_configure +0002de49 __iface_attach +0002de72 net_interface_create +0002deae net_register_netdev +0002dfca net_interface_destroy +0002dfe3 __default_restart +0002dfed __default_stop +0002e056 __default_start +0002e0d9 nm_new +0002e166 nm_free +0002e1af net_firewall_create +0002e1d6 fs_file2fd +0002e23f fs_alloc_file +0002e28e fs_free_file +0002e2ec fs_register +0002e3bf fs_init +0002e3c9 fs_unregister +0002e430 fs_get +0002e43a fs_close +0002e4b0 fs_open +0002e52e fs_seek +0002e5af fs_read +0002e6c8 fs_load_from_file +0002e758 fs_write +0002e817 fs_save_to_file +0002e8a7 fat16_rmdir +0002e8b1 fat16_stat +0002e8bb fat16_close +0002e929 fat16_rename +0002e9c2 fat16_mkdir +0002eaab fat16_remove +0002eb22 fat16_open +0002ec70 fat16_read +0002edd3 fat16_write +0002ef06 fat16_list +0002f1d8 fat16_init +0002f290 path_next_iter +0002f2fe inode_from_path_recursise +0002f37c inode_from_path +0002f43e ext_get_root +0002f44b ext_get_current_dir +0002f45e ext_get_size +0002f468 ext_get_inodes +0002f472 ext_get_blocks +0002f47c ext_sync +0002f4f3 ext_create +0002f5e2 ext_read +0002f661 ext_seek +0002f6ac ext_write +0002f71c ext_close +0002f782 ext_open_from_directory +0002f88a ext_open +0002f945 ext_size +0002f972 change_directory +0002f9dc ext_create_directory +0002fb7a ext_create_file_system +0002fe4b init_ext +0002ffeb listdir +00030112 __inode_sync +00030175 __inode_cache_insert +0003026b __inode_load +000302df inodes_sync +0003031e inode_get +0003037f inode_read +0003056f inode_write +000307d6 alloc_inode +00030893 mkdir +00030944 sync +0003097c mkfs +0003098d fat16_read_data_from_cluster +000309df fat16_read_data +00030abc fat16_find_cluster_by_offset +00030b3b fat16_write_data_to_cluster_with_offset +00030b7a fat16_print_cluster_chain +00030bac fat16_write_data_to_cluster +00030be3 fat16_write_data +00030cfe get_fat_start_block +00030d0a get_root_directory_start_block +00030d1d get_data_start_block +00030d33 fat16_get_fat_entry +00030d52 fat16_set_fat_entry +00030d96 fat16_sync_fat_table +00030e12 fat16_allocate_cluster +00030e2e fat16_free_cluster +00030e47 fat16_get_free_cluster +00030ea0 fat16_sync_directory_entry +00030f27 fat16_read_entry +00030fd8 fat16_find_entry +00031113 fat16_rename_entry +00031188 fat16_free_clusters +000311d3 fat16_delete_entry +0003123e fat16_add_entry +000313a9 fat16_used_blocks +000313e6 fat16_to_upper +00031416 fat16_name_compare +00031531 sstrtok +000315f4 fat16_directory_entry_debug +000316cb fat16_get_directory_entry +000318d4 fat16_create_directory +000319dd fat16_read_file +00031a32 fat16_create_file +00031ab4 fat16_create_empty_file +00031b7c fat16_directory_entries +00031c67 fat16_mbr_clear +00031d32 fat16_mbr_add_entry +00031e27 fat16_print_root_directory_entries +00031e43 fat16_change_directory +00031ecf fat16_bootblock_info +00032050 fat16_set_time +00032088 fat16_set_date +000320c4 fat16_load +00032247 fat16_format +00032500 mbr_partition_type_string +00032588 mbr_partitions_parse +00032656 mbr_get +00032660 mbr_partition_load +00032682 __list_users +00032717 __change_user +000327bd __remove_user +0003286d __add_user +0003295b __find_user +00032a35 __authenticate_user +00032b4d __save_users +00032bd5 __load_users +00032ddb __ksymbol_admin +00032df9 admin +0003311b usermanager_create +0003313e __ksymbol_snakegame +0003315c init_game +000331ac draw +0003320c get_input +0003322f update +000333bb game_loop +000333e5 snakegame +00033434 __msgbox +00033847 msgbox_create +0003387e msgbox_show +000338ca kevents_list +00033a40 kevents_init +00033a86 kevents_destroy +00033adf kevents_add +00033b9a kevents_create +00033c21 __register_kthread_screeny +00033c3f screeny +00033ea0 _code_end From 8d6bf3ceff7b87025e70b537357274b2c5999c8a Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Thu, 8 Feb 2024 11:15:33 +0100 Subject: [PATCH 17/23] Working textmode screen and textmode editor search --- .gitignore | 3 + Makefile | 5 +- apps/texed/include/screen.h | 4 + apps/texed/include/textbuffer.h | 40 ++ apps/texed/screen.c | 30 +- apps/texed/search.c | 69 +++ apps/texed/texed.c | 71 ++- drivers/keyboard.c | 256 +++++---- drivers/screen.c | 98 ---- drivers/vga.c | 28 +- include/screen.h | 2 +- kernel/kernel.c | 2 +- kernel/kthreads/textmode.c | 117 +++++ kernel/terminal.c | 2 - rootfs/symbols.map | 903 -------------------------------- rootfs/sysutil/symbols.map | 860 ------------------------------ 16 files changed, 428 insertions(+), 2062 deletions(-) create mode 100644 apps/texed/include/textbuffer.h create mode 100644 apps/texed/search.c delete mode 100644 drivers/screen.c create mode 100644 kernel/kthreads/textmode.c delete mode 100644 rootfs/symbols.map delete mode 100644 rootfs/sysutil/symbols.map diff --git a/.gitignore b/.gitignore index 2832767..064be63 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,9 @@ rootfs/bin/* RetrOS-32-debug.img +rootfs/symbols.map +rootfs/sysutil/symbols.map + # Executables *.exe *.out diff --git a/Makefile b/Makefile index bc8c090..3674efc 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ KERNELOBJ = bin/kernel.o bin/terminal.o bin/helpers.o bin/pci.o bin/virtualdisk. bin/diskdev.o bin/scheduler.o bin/work.o bin/rbuffer.o bin/errors.o bin/kclock.o bin/tar.o bin/color.o bin/loopback.o \ bin/serial.o bin/io.o bin/syscalls.o bin/list.o bin/hashmap.o bin/vbe.o bin/ksyms.o bin/windowserver.o bin/encoding.o\ bin/mouse.o bin/ipc.o bin/sysinf.o ${PROGRAMOBJ} ${GFXOBJ} bin/font8.o bin/net.o bin/fs.o bin/ext.o bin/fat16.o bin/partition.o\ - bin/admin.o bin/usermanager.o bin/user.o bin/group.o bin/snake.o bin/msgbox.o bin/kevents.o bin/screen.o + bin/admin.o bin/usermanager.o bin/user.o bin/group.o bin/snake.o bin/msgbox.o bin/kevents.o bin/textmode.o BOOTOBJ = bin/bootloader.o @@ -80,16 +80,19 @@ bootblock: $(BOOTOBJ) @$(LD) $(LDFLAGS) -o bin/bootblock $^ -Ttext 0x7C00 --oformat=binary multiboot_kernel: bin/multiboot.o $(KERNELOBJ) + @echo "[KERNEL] Linking kernel..." @$(LD) -o bin/kernelout $^ $(LDFLAGS) -T ./boot/multiboot.ld @echo "[KERNEL] Finished compiling kernel." # Idea taken from SerenityOS symbols: bin/multiboot.o $(KERNELOBJ) + @echo "[KERNEL] Creating symbols..." @$(LD) -o bin/symbols $^ $(LDFLAGS) -T ./kernel/linkersym.ld @nm -C -n bin/symbols | grep ' [Tt] ' | sed 's/ [Tt] / /' > rootfs/symbols.map kernel: bin/kcrt0.o $(KERNELOBJ) + @echo "[KERNEL] Linking kernel..." @$(LD) -o bin/kernelout $^ $(LDFLAGS) -T ./kernel/linker.ld .depend: **/*.[cSh] diff --git a/apps/texed/include/screen.h b/apps/texed/include/screen.h index 1c5f6fe..d6e3cc4 100644 --- a/apps/texed/include/screen.h +++ b/apps/texed/include/screen.h @@ -25,6 +25,9 @@ #define CTRLC 227 #define CTRLE 229 +#define CTRLS 243 +#define CTRLF 230 + #define COLOR(fg, bg) (fg | bg << 4) @@ -54,5 +57,6 @@ char screen_get_char(); int screen_clear(int from , int to, unsigned char color); void screen_draw_box(int x, int y, int width, int height, char border_color); int screen_clear_line(int y, unsigned char color); +int screen_set_cursor(int x, int y); #endif // __TEXED_SCREEN_H__ \ No newline at end of file diff --git a/apps/texed/include/textbuffer.h b/apps/texed/include/textbuffer.h new file mode 100644 index 0000000..cb0a22d --- /dev/null +++ b/apps/texed/include/textbuffer.h @@ -0,0 +1,40 @@ +#ifndef __TEXTBUFFER_H +#define __TEXTBUFFER_H + +#include +#include + +typedef enum __line_flags { + LINE_FLAG_NONE = 1 << 0, + LINE_FLAG_DIRTY = 1 << 1, + LINE_FLAG_EXTENSION = 1 << 2, +} line_flags_t; + +struct textbuffer { + struct textbuffer_ops { + int (*destroy)(struct textbuffer *buffer); + int (*display)(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg); + int (*put)(struct textbuffer *buffer, unsigned char c); + int (*jump)(struct textbuffer *buffer, size_t x, size_t y); + } *ops; + struct line { + char *text; + size_t length; + size_t capacity; + line_flags_t flags; + } **lines; + struct cursor { + unsigned int x; + unsigned int y; + } cursor; + struct scroll { + size_t start; + size_t end; + } scroll; + size_t line_count; + char filename[256]; +}; + +int textbuffer_search_main(struct textbuffer* buffer); + +#endif // !__TEXTBUFFER_H \ No newline at end of file diff --git a/apps/texed/screen.c b/apps/texed/screen.c index 2f046b0..5c67809 100644 --- a/apps/texed/screen.c +++ b/apps/texed/screen.c @@ -52,30 +52,30 @@ int screen_set_cursor(int x, int y) void screen_draw_box(int x, int y, int width, int height, char border_color) { - // Extended ASCII characters for double line box drawing - unsigned char top_left = 201; // '╔' - unsigned char top_right = 187; // '╗' - unsigned char bottom_left = 200; // '╚' - unsigned char bottom_right = 188; // '╝' - unsigned char horizontal = 205; // '═' - unsigned char vertical = 186; // '║' - - // Draw corners + /* Extended ASCII characters for double line box drawing */ + unsigned char top_left = 201; /* '╔' */ + unsigned char top_right = 187; /* '╗' */ + unsigned char bottom_left = 200; /* '╚' */ + unsigned char bottom_right = 188; /* '╝' */ + unsigned char horizontal = 205; /* '═' */ + unsigned char vertical = 186; /* '║' */ + + /* Draw corners */ screen_put_char(x, y, top_left, border_color); screen_put_char(x + width - 1, y, top_right, border_color); screen_put_char(x, y + height - 1, bottom_left, border_color); screen_put_char(x + width - 1, y + height - 1, bottom_right, border_color); - // Draw top and bottom borders with connectors + /* Draw top and bottom borders with connectors */ for (int i = x + 1; i < x + width - 1; ++i) { - screen_put_char(i, y, horizontal, border_color); // Top border - screen_put_char(i, y + height - 1, horizontal, border_color); // Bottom border + screen_put_char(i, y, horizontal, border_color); /* Top border */ + screen_put_char(i, y + height - 1, horizontal, border_color); /* Bottom border */ } - // Draw left, right borders, and connectors + /* Draw left, right borders, and connectors */ for (int i = y + 1; i < y + height - 1; ++i) { - screen_put_char(x, i, vertical, border_color); // Left border - screen_put_char(x + width - 1, i, vertical, border_color); // Right border + screen_put_char(x, i, vertical, border_color); /* Left border */ + screen_put_char(x + width - 1, i, vertical, border_color); /* Right border */ } } diff --git a/apps/texed/search.c b/apps/texed/search.c new file mode 100644 index 0000000..c0123db --- /dev/null +++ b/apps/texed/search.c @@ -0,0 +1,69 @@ +#include +#include + +#include "include/screen.h" +#include "include/textbuffer.h" + +#define MAX_SEARCH 100 + +static int textbuffer_search(struct textbuffer* buffer, char* search) { + int ret; + /* find str in lines and goto line */ + for (size_t i = 0; i < buffer->line_count; i++) { + ret = strstr(buffer->lines[i]->text, search); + if (ret >= 0) { + buffer->cursor.x = ret; + buffer->ops->jump(buffer, ret, i); + return 0; + } + } + return -1; +} + +static int textbuffer_search_box(struct textbuffer* buffer) { + + char search[MAX_SEARCH] = {0}; + int search_len = 0; + + for(int x = 10; x < 60; x++) + for(int y = 5; y < 20; y++) + screen_put_char(x, y, ' ', COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + + screen_draw_box(10, 5, 50, 15, COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + + screen_put_char(13, 5, '[', COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + screen_put_char(14, 5, 'S', COLOR(VGA_COLOR_GREEN, VGA_COLOR_LIGHT_GREY)); + screen_put_char(15, 5, ']', COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + + screen_write(13, 6, "Search: ", COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + screen_write(13, 7, " ", COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + + while(1) { + screen_set_cursor(13 + search_len, 7); + screen_write(13, 7, search, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + unsigned char c = screen_get_char(); + if (c == 0) + continue; + if (c == CTRLC) + break; + if (c == '\b'){ + if (search_len > 0){ + search_len--; + search[search_len] = 0; + } + continue; + } + if (c == '\n'){ + return textbuffer_search(buffer, search); + } + + search[search_len] = c; + search_len++; + } + return -1; +} + +int textbuffer_search_main(struct textbuffer* buffer) { + textbuffer_search_box(buffer); + return 0; +} \ No newline at end of file diff --git a/apps/texed/texed.c b/apps/texed/texed.c index 8782109..0f3f00a 100644 --- a/apps/texed/texed.c +++ b/apps/texed/texed.c @@ -13,56 +13,29 @@ #include #include #include +#include #include #include "include/screen.h" +#include "include/textbuffer.h" #define MAX_LINES 512 #define LINE_CAPACITY 78 #define MAX_VISABLE_LINES 21 -typedef enum __line_flags { - LINE_FLAG_NONE = 1 << 0, - LINE_FLAG_DIRTY = 1 << 1, - LINE_FLAG_EXTENSION = 1 << 2, -} line_flags_t; - -struct textbuffer { - struct textbuffer_ops { - int (*destroy)(struct textbuffer *buffer); - int (*display)(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg); - int (*put)(struct textbuffer *buffer, unsigned char c); - } *ops; - struct line { - char *text; - size_t length; - size_t capacity; - line_flags_t flags; - } **lines; - struct cursor { - size_t x; - size_t y; - } cursor; - struct scroll { - size_t start; - size_t end; - } scroll; - size_t line_count; - char filename[256]; -}; - /* Function prototypes */ static int textbuffer_new_line(struct textbuffer *buffer); -static int textbuffer_remove_last_line(struct textbuffer *buffer); static int textbuffer_free_line(struct textbuffer *buffer, size_t line); static int textbuffer_destroy(struct textbuffer *buffer); static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg); static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c); +static int textbuffer_jump(struct textbuffer *buffer, unsigned int x, unsigned int y); static struct textbuffer_ops textbuffer_default_ops = { .destroy = textbuffer_destroy, .display = textbuffer_display, .put = textbuffer_handle_char, + .jump = textbuffer_jump, }; static struct textbuffer *textbuffer_create(void) { @@ -235,13 +208,24 @@ static int textbuffer_load_file(struct textbuffer *buffer, const char *filename) return 0; } +static int textbuffer_jump(struct textbuffer *buffer, unsigned int x, unsigned int y) { + buffer->cursor.y = y; + buffer->cursor.x = x; + + if(buffer->cursor.y > MAX_VISABLE_LINES) { + buffer->scroll.start = buffer->cursor.y - MAX_VISABLE_LINES; + } + + return 0; +} + /* Function to display the content of the text buffer on the screen */ static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg) { uint32_t x_start = 0; uint32_t y_start = buffer->scroll.start; /* Clear the screen before displaying new content */ - //screen_clear(0, 0, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + screen_clear(0, 0, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); /* fill top row with light grey */ for (size_t i = 0; i < 80; i++) { @@ -257,15 +241,15 @@ static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg /* write from start to end, or line_count */ for (size_t i = 0; i + y_start < buffer->line_count && i < buffer->scroll.end; i++) { /* Calculate the position for each line */ - int32_t x = x_start; - int32_t y = y_start + i; + uint32_t x = x_start; + uint32_t y = y_start + i; /* Write the line to the screen */ if (!buffer->lines[y]->text) { continue; } - screen_clear_line(2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + //screen_clear_line(2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); if (buffer->cursor.y == y) { screen_printf(1+x, 2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE) , "%s %c", buffer->lines[y]->text, 27); } else { @@ -344,7 +328,6 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { ret = textbuffer_new_line(buffer); if (ret < 0) { - printf("textbuffer_new_line failed\n"); return -1; } @@ -367,7 +350,6 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { /* Create a new line */ ret = textbuffer_new_line(buffer); if (ret < 0) { - printf("textbuffer_new_line failed\n"); return -1; } @@ -464,6 +446,7 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { } int main(int argc, char *argv[]) { + int ret; unsigned char c; struct textbuffer *buffer = textbuffer_create(); if (buffer == NULL) { @@ -478,13 +461,25 @@ int main(int argc, char *argv[]) { } textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + while (1) { c = screen_get_char(); if (c == 0) continue; if (c == CTRLC) break; - + if (c == CTRLS){ + textbuffer_save_file(buffer, buffer->filename); + continue; + } + if (c == CTRLF){ + ret = textbuffer_search_main(buffer); + textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + if(ret < 0) + screen_write(0, 24, "Search failed", COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + continue; + } + textbuffer_handle_char(buffer, c); textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); } diff --git a/drivers/keyboard.c b/drivers/keyboard.c index b755d0e..43a00e7 100644 --- a/drivers/keyboard.c +++ b/drivers/keyboard.c @@ -5,70 +5,63 @@ * @see http://www.osdever.net/bkerndev/Docs/keyboard.htm * @version 0.1 * @date 2022-06-01 - * + * * @copyright Copyright (c) 2022 - * + * */ -#include -#include #include -#include -#include #include -#include +#include #include +#include +#include #include +#include +#include -#include #include -#define KB_IRQ 33 /* Default is 1, 33 after mapped. */ +#define KB_IRQ 33 /* Default is 1, 33 after mapped. */ #define KB_BUFFER_SIZE 255 static mutex_t kb_lock; static unsigned char kb_buffer[KB_BUFFER_SIZE]; -static int kb_buffer_head = 0; -static int kb_buffer_tail = 0; - -static unsigned char kbdus[128] = -{ - 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */ - '9', '0', '-', '=', '\b', /* Backspace */ - '\t', /* Tab */ - 'q', 'w', 'e', 'r', /* 19 */ - 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */ - 0, /* 29 - Control */ - 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */ - '\'', '`', 0, /* Left shift */ - '\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */ - 'm', ',', '.', '/', 0, /* Right shift */ - '*', - 0, /* Alt */ - ' ', /* Space bar */ - 0, /* Caps lock */ - F1, /* 59 - F1 key ... > */ - F2, F3, F4, F5, F6, F7, F8, F9, - F10, /* < ... F10 */ - 0, /* 69 - Num lock*/ - 0, /* Scroll Lock */ - 0, /* Home key */ - ARROW_UP, /* Up Arrow */ - 0, /* Page Up */ - '-', - ARROW_LEFT, /* Left Arrow */ - 0, - ARROW_RIGHT, /* Right Arrow */ - '+', - 0, /* 79 - End key*/ - ARROW_DOWN, /* Down Arrow */ - 0, /* Page Down */ - 0, /* Insert Key */ - 0, /* Delete Key */ - 0, 0, 0, - 0, /* F11 Key */ - 0, /* F12 Key */ - 0, /* All other keys are undefined */ +static volatile int kb_buffer_head = 0; +static volatile int kb_buffer_tail = 0; + +static unsigned char kbdus[128] = { + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */ + '9', '0', '-', '=', '\b', /* Backspace */ + '\t', /* Tab */ + 'q', 'w', 'e', 'r', /* 19 */ + 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key + */ + 0, /* 29 - Control */ + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */ + '\'', '`', 0, /* Left shift */ + '\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */ + 'm', ',', '.', '/', 0, /* Right shift */ + '*', 0, /* Alt */ + ' ', /* Space bar */ + 0, /* Caps lock */ + F1, /* 59 - F1 key ... > */ + F2, F3, F4, F5, F6, F7, F8, F9, F10, /* < ... F10 */ + 0, /* 69 - Num lock*/ + 0, /* Scroll Lock */ + 0, /* Home key */ + ARROW_UP, /* Up Arrow */ + 0, /* Page Up */ + '-', ARROW_LEFT, /* Left Arrow */ + 0, ARROW_RIGHT, /* Right Arrow */ + '+', 0, /* 79 - End key*/ + ARROW_DOWN, /* Down Arrow */ + 0, /* Page Down */ + 0, /* Insert Key */ + 0, /* Delete Key */ + 0, 0, 0, 0, /* F11 Key */ + 0, /* F12 Key */ + 0, /* All other keys are undefined */ }; static int __keyboard_presses = 0; static uint8_t __shift_pressed = 0; @@ -76,129 +69,124 @@ static uint8_t __alt_pressed = 0; static uint8_t __ctrl_pressed = 0; static uint8_t __super_pressed = 0; -unsigned char kb_get_char(int spin) -{ - acquire(&kb_lock); - - if(spin){ +unsigned char kb_get_char(int spin) { + acquire(&kb_lock); - while(kb_buffer_tail == kb_buffer_head){ + if (spin) { + + while (kb_buffer_tail == kb_buffer_head) { release(&kb_lock); - + kernel_yield(); - + acquire(&kb_lock); } - + } else { - if(kb_buffer_tail == kb_buffer_head){ + if (kb_buffer_tail == kb_buffer_head) { release(&kb_lock); return 0; } } - - unsigned char c = kb_buffer[kb_buffer_tail]; - kb_buffer_tail = (kb_buffer_tail + 1) % KB_BUFFER_SIZE; - release(&kb_lock); - return c; + unsigned char c = kb_buffer[kb_buffer_tail]; + kb_buffer_tail = (kb_buffer_tail + 1) % KB_BUFFER_SIZE; + + release(&kb_lock); + return c; } -void kb_add_char(unsigned char c) -{ - kb_buffer[kb_buffer_head] = c; - kb_buffer_head = (kb_buffer_head + 1) % KB_BUFFER_SIZE; +void kb_add_char(unsigned char c) { + kb_buffer[kb_buffer_head] = c; + kb_buffer_head = (kb_buffer_head + 1) % KB_BUFFER_SIZE; } +static void __int_handler kb_callback() { + uint8_t scancode = + inportb(0x60); /* Recieve scancode, also ACK's interrupt? */ + switch (scancode) { + case 0x2a: /* shift down */ + __shift_pressed = 1; + return; + case 0xaa: /* shift up */ + __shift_pressed = 0; + return; + case 224: /* shift down */ + __alt_pressed = 1; + return; + case 184: /* shift up */ + __alt_pressed = 0; + return; + case 29: /* ctrl down */ + __ctrl_pressed = 1; + return; + case 157: /* ctrl up */ + __ctrl_pressed = 0; + return; + case 91: /* windows key */ + __super_pressed = 1; + return; + case 219: /* windows key up */ + __super_pressed = 0; + return; + default: + break; + } + + if (scancode & 0x80) + return; + /* CTRL: down 29 up 157 */ -static void __int_handler kb_callback() -{ - uint8_t scancode = inportb(0x60); /* Recieve scancode, also ACK's interrupt? */ - switch (scancode) { - case 0x2a: /* shift down */ - __shift_pressed = 1; - return; - case 0xaa: /* shift up */ - __shift_pressed = 0; - return; - case 224: /* shift down */ - __alt_pressed = 1; - return; - case 184: /* shift up */ - __alt_pressed = 0; - return; - case 29: /* ctrl down */ - __ctrl_pressed = 1; - return; - case 157: /* ctrl up */ - __ctrl_pressed = 0; - return; - case 91: /* windows key */ - __super_pressed = 1; - return; - case 219: /* windows key up */ - __super_pressed = 0; - return; - default: - break; - } - - if(scancode & 0x80) - return; - - /* CTRL: down 29 up 157 */ - - unsigned char c = kbdus[scancode]; - if(c == '7' && __shift_pressed){ + unsigned char c = kbdus[scancode]; + if (c == '7' && __shift_pressed) { kb_add_char('/'); - } else if(c == '8' && __shift_pressed){ + } else if (c == '8' && __shift_pressed) { kb_add_char('('); - } else if(c == '9' && __shift_pressed){ + } else if (c == '9' && __shift_pressed) { kb_add_char(')'); - } else if(c == ',' && __shift_pressed){ + } else if (c == ',' && __shift_pressed) { kb_add_char(';'); - } else if(c == '0' && __shift_pressed){ + } else if (c == '0' && __shift_pressed) { kb_add_char('='); - } else if(c == '7' && __shift_pressed){ + } else if (c == '7' && __shift_pressed) { kb_add_char('/'); - } else if(c == '8' && __alt_pressed){ + } else if (c == '8' && __alt_pressed) { kb_add_char('['); - } else if(c == '9' && __alt_pressed){ + } else if (c == '9' && __alt_pressed) { kb_add_char(']'); - } else if(c == '7' && __alt_pressed){ + } else if (c == '7' && __alt_pressed) { kb_add_char('{'); - } else if(c == '0' && __alt_pressed){ + } else if (c == '0' && __alt_pressed) { kb_add_char('}'); - } else if(c == '2' && __shift_pressed){ + } else if (c == '2' && __shift_pressed) { kb_add_char('"'); - } else if(c == 92 && __shift_pressed){ + } else if (c == 92 && __shift_pressed) { kb_add_char('*'); - } else if(__ctrl_pressed) { - kb_add_char(128+c); + } else if (__ctrl_pressed) { + kb_add_char(128 + c); } else { - kb_add_char( __shift_pressed ? c+('A'-'a') : c); + kb_add_char(__shift_pressed ? c + ('A' - 'a') : c); } - __keyboard_presses++; + __keyboard_presses++; } static void keyboard_buffer_clear() { - while (inportb(0x64) & 1) { - inportb(0x60); // Read and discard - } + while (inportb(0x64) & 1) { + inportb(0x60); /* Read and discard */ + } } -void init_keyboard() -{ +void init_keyboard() { mutex_init(&kb_lock); - outportb(0x64, 0xAE); // Send the keyboard enable command - outportb(0x60, 0xFF); // Send the keyboard reset command + outportb(0x64, 0xAE); /* Send the keyboard enable command */ + outportb(0x60, 0xFF); /* Send the keyboard reset command */ keyboard_buffer_clear(); - // Firstly, register our timer callback. - interrupt_install_handler(KB_IRQ, &kb_callback); - dbgprintf("[PS/2] Keyboard initialized.\n"); -} \ No newline at end of file + /* Firstly, register our timer callback. */ + interrupt_install_handler(KB_IRQ, &kb_callback); + dbgprintf("[PS/2] Keyboard initialized.\n"); +} diff --git a/drivers/screen.c b/drivers/screen.c deleted file mode 100644 index 3200c8f..0000000 --- a/drivers/screen.c +++ /dev/null @@ -1,98 +0,0 @@ -/** - * @file screen.c - * @author Joe Bayer (joexbayer) - * @brief VGA Textmode visual driver - * @version 0.1 - * @date 2024-02-07 - * - * @copyright Copyright (c) 2024 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VIDEO_ADDRESS 0xB8000 -#define MAX_ROWS 25 -#define MAX_COLS 80 - -/* Macro to extract the character from a VGA entry */ -#define VGA_ENTRY_CHAR(vga_entry) ((vga_entry) & 0xFF) -/* Macro to extract the foreground color from a VGA entry */ -#define VGA_ENTRY_FG_COLOR(vga_entry) (((vga_entry) >> 8) & 0x0F) -/* Macro to extract the background color from a VGA entry */ -#define VGA_ENTRY_BG_COLOR(vga_entry) (((vga_entry) >> 12) & 0x0F) - - -static int screen_draw_char(struct window* w, int x, int y, unsigned char c, color_t fg, color_t bg) -{ - for (int l = 0; l < 8; l++) { - for (int i = 8; i >= 0; i--) { - if(c > 0 && c < 128){ - if(font8x8_basic[c][l] & (1 << i)){ - putpixel(w->inner, (x)+i, (y)+l, fg, w->pitch); - } else { - putpixel(w->inner, (x)+i, (y)+l, bg, w->pitch); - } - } else if(c > 179 && c < 218 ) { - if (font8x8_box[c][l] & (1 << i)) { - putpixel(w->inner, (x)+i, (y)+l, fg, w->pitch); - } else { - putpixel(w->inner, (x)+i, (y)+l, bg, w->pitch); - } - } else { - putpixel(w->inner, (x)+i, (y)+l, COLOR_BLUE, w->pitch); - } - } - } - return 0; -} - -static int screeny(int argc, char* argv[]) -{ - struct window* w = gfx_new_window(MAX_COLS*8, MAX_ROWS*8, 0); - if(w == NULL){ - return -1; - } - kernel_gfx_set_title("VGA Textmode"); - - start("textshell", 0, NULL); - - while (1){ - for(int k = 0; k < MAX_ROWS; k++){ - for(int j = 0; j < MAX_COLS; j++){ - uint16_t entry = scrget(j, k); - unsigned char c = VGA_ENTRY_CHAR(entry); - color_t fg = VGA_ENTRY_FG_COLOR(entry); - color_t bg = VGA_ENTRY_BG_COLOR(entry); - - screen_draw_char(w, j*8, k*8, c, fg, bg); - } - } - - struct gfx_event event; - int ret = gfx_event_loop(&event, GFX_EVENT_NONBLOCKING); - if(ret == -1) continue; - - switch (event.event){ - case GFX_EVENT_EXIT: - return; - case GFX_EVENT_KEYBOARD: - scr_keyboard_add(event.data); - break; - default: - break; - } - - } - - return 0; -} -EXPORT_KTHREAD(screeny); \ No newline at end of file diff --git a/drivers/vga.c b/drivers/vga.c index a1d6fd6..2781955 100644 --- a/drivers/vga.c +++ b/drivers/vga.c @@ -25,7 +25,7 @@ uint16_t* const VGA_MEMORY = (uint16_t*) 0xB8000; -uint16_t* VGA_BUFFER = NULL; +volatile uint16_t* VGA_BUFFER = NULL; //uint16_t* const VGA_MEMORY = (uint16_t*) 0xa0000; static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) @@ -41,11 +41,14 @@ static inline uint16_t vga_entry(unsigned char uc, uint8_t color) void scr_set_cursor(int x, int y) { - uint16_t pos = y * SCREEN_WIDTH + x + 1; - outportb(0x3D4, 0x0F); - outportb(0x3D5, (uint8_t) (pos & 0xFF)); - outportb(0x3D4, 0x0E); - outportb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF)); + if($kernel->graphic_mode == KERNEL_FLAG_TEXTMODE){ + uint16_t pos = y * SCREEN_WIDTH + x; + outportb(0x3D4, 0x0F); + outportb(0x3D5, (uint8_t) (pos & 0xFF)); + outportb(0x3D4, 0x0E); + outportb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF)); + return; + } } void scrcolor_set(enum vga_color fg, enum vga_color bg) @@ -81,6 +84,11 @@ uint16_t scrget(int x, int y) return VGA_BUFFER[index]; } +uint16_t* scr_buffer() +{ + return VGA_BUFFER; +} + /** * Writes given string to terminal at specified position. * @param int x coordinate of screen. @@ -225,8 +233,8 @@ int init_vga() /* MOVE TO A BETTER PLACE */ static unsigned char kb_buffer[256] = {0}; -static int kb_buffer_tail = 0; -static int kb_buffer_head = 0; +static volatile int kb_buffer_tail = 0; +static volatile int kb_buffer_head = 0; void scr_keyboard_add(unsigned char c) { @@ -243,8 +251,10 @@ unsigned char scr_keyboard_get() while(kb_buffer_tail == kb_buffer_head){ kernel_yield(); } + unsigned char c = kb_buffer[kb_buffer_tail]; kb_buffer_tail = (kb_buffer_tail + 1) % 256; + dbgprintf("Got %c from buffer\n", c); return c; } -} \ No newline at end of file +} diff --git a/include/screen.h b/include/screen.h index 2c23987..e2150be 100644 --- a/include/screen.h +++ b/include/screen.h @@ -31,12 +31,12 @@ enum vga_color { void scrcolor_set(enum vga_color fg, enum vga_color bg); void scrput(int x, int y, unsigned char c, uint8_t color); void scrwrite(int x, int y, char* str, uint8_t color); -int screen_set_cursor(int x, int y); void scr_clear(); void scr_scroll(); int scrprintf(int32_t x, int32_t y, char* fmt, ...); int init_vga(); uint16_t scrget(int x, int y); +uint16_t* scr_buffer(); void scr_keyboard_add(unsigned char c); unsigned char scr_keyboard_get(); diff --git a/kernel/kernel.c b/kernel/kernel.c index c34ace6..ab9af4b 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -246,7 +246,7 @@ void kernel(uint32_t magic) start("netd", 0, NULL); kernel_boot_printf("Deamons initialized."); - init_pit(1000); + init_pit(100); kernel_boot_printf("Timer initialized."); dbgprintf("Critical counter: %d\n", __cli_cnt); diff --git a/kernel/kthreads/textmode.c b/kernel/kthreads/textmode.c new file mode 100644 index 0000000..376f2ff --- /dev/null +++ b/kernel/kthreads/textmode.c @@ -0,0 +1,117 @@ +/** + * @file screen.c + * @author Joe Bayer (joexbayer) + * @brief VGA Textmode visual driver + * @version 0.1 + * @date 2024-02-07 + * + * @copyright Copyright (c) 2024 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VIDEO_ADDRESS 0xB8000 +#define MAX_ROWS 25 +#define MAX_COLS 80 + +/* Macro to extract the character from a VGA entry */ +#define VGA_ENTRY_CHAR(vga_entry) ((vga_entry) & 0xFF) +/* Macro to extract the foreground color from a VGA entry */ +#define VGA_ENTRY_FG_COLOR(vga_entry) (((vga_entry) >> 8) & 0x0F) +/* Macro to extract the background color from a VGA entry */ +#define VGA_ENTRY_BG_COLOR(vga_entry) (((vga_entry) >> 12) & 0x0F) + +static int screen_draw_char(struct window *w, int x, int y, unsigned char c, color_t fg, color_t bg) { + int char_height = 8; /* Height of the character */ + int total_height = 12; /* Total height of the drawing area */ + int offset = (total_height - char_height) / 2; /* Offset to center the character */ + + for (int l = 0; l < total_height; l++) { + for (int i = 0; i < 8; i++) { + /* Check if the current pixel is within the vertical range of the character */ + if (l >= offset && l < offset + char_height) { + /* Character drawing logic */ + if ((c > 0 && c < 128 && font8x8_basic[c][l - offset] & (1 << i)) || + (c > 179 && c < 218 && font8x8_box[c][l - offset] & (1 << i))) { + putpixel(w->inner, x + i, y + l, fg, w->pitch); + } else { + putpixel(w->inner, x + i, y + l, bg, w->pitch); + } + } else { + /* Draw the background for areas above and below the character */ + putpixel(w->inner, x + i, y + l, bg, w->pitch); + } + } + } + return 0; +} + +static int screeny(int argc, char *argv[]) { + volatile uint16_t* buffer = scr_buffer(); + + /* Create a cache for the screen */ + uint16_t* cache = (uint16_t*)kalloc(MAX_ROWS * MAX_COLS * sizeof(uint16_t)); + if (cache == NULL) { + return -1; + } + memset(cache, 0, MAX_ROWS * MAX_COLS * sizeof(uint16_t)); + + struct window *w = gfx_new_window(MAX_COLS * 8, MAX_ROWS * 12, 0); + if (w == NULL) { + return -1; + } + kernel_gfx_set_title("VGA Textmode"); + + start("textshell", 0, NULL); + + while (1) { + for (int k = 0; k < MAX_ROWS; k++) { + for (int j = 0; j < MAX_COLS; j++) { + uint16_t entry = buffer[k * MAX_COLS + j]; + if (entry == cache[k * MAX_COLS + j]) { + continue; + } + + unsigned char c = VGA_ENTRY_CHAR(entry); + color_t fg = VGA_ENTRY_FG_COLOR(entry); + color_t bg = VGA_ENTRY_BG_COLOR(entry); + + screen_draw_char(w, j * 8, k * 12, c, fg, bg); + + cache[k * MAX_COLS + j] = entry; + } + } + gfx_commit(); + + kernel_yield(); + + struct gfx_event event; + int ret = gfx_event_loop(&event, GFX_EVENT_NONBLOCKING); + if (ret == -1) + continue; + + switch (event.event) { + case GFX_EVENT_EXIT: + return -1; + case GFX_EVENT_KEYBOARD: + scr_keyboard_add(event.data); + break; + default: + break; + } + + kernel_yield(); + } + + return 0; +} +EXPORT_KTHREAD(screeny); diff --git a/kernel/terminal.c b/kernel/terminal.c index b5cfcfe..e3f022d 100644 --- a/kernel/terminal.c +++ b/kernel/terminal.c @@ -20,8 +20,6 @@ #include #include -#include - #define MAX_FMT_STR_SIZE 50 /* OLD */ diff --git a/rootfs/symbols.map b/rootfs/symbols.map deleted file mode 100644 index 607b5e4..0000000 --- a/rootfs/symbols.map +++ /dev/null @@ -1,903 +0,0 @@ -00010000 _code -00010000 _start -00010030 gdtp -00010040 gdt_null -00010040 gdt_start -00010048 code_descriptor -00010050 data_descriptor -00010058 gdt_end -00010058 kernel_boot_printf -000100b7 init_kctors -00010109 kernel -000105ac kernel_get_context -000105b6 hexdump -00010806 __terminal_set_ops -000108d3 __terminal_scanf -000108dd __terminal_write -0001092b __terminal_getchar_graphics -00010978 __terminal_scan_graphics -00010a5a __terminal_reset -00010aa2 __terminal_detach -00010ae9 __terminal_attach -00010b38 __terminal_remove_line -00010b78 __terminal_putchar_graphics -00010c45 __terminal_writef -00010f54 __terminal_getchar_textmode -00010f80 __terminal_scan_textmode -00011048 __terminal_commit_textmode -00011104 __terminal_putchar_textmode -00011154 scan -00011191 terminal_set_color -000111ad __terminal_commit_graphics -0001130e terminal_attach -00011333 terminal_commit -00011356 terminal_putchar -00011396 terminal_create -000114bf terminal_destroy -000114fc tlb_flush_addr -00011504 load_page_directory -00011514 enable_paging -00011526 pcb_save_context -00011552 pcb_restore_context -0001157b _start_pcb -000115ad _start_pcb_skip -000115c8 __ksymbol_lspci -000115e6 pci_get_class_name -000115fd pci_get_device_name -00011672 pci_get_vendor_name -000116c4 lspci -00011815 pci_get_devices -0001181f pci_read_word -0001187c pci_write_dword -000118cf pci_enable_device_busmaster -00011928 pci_register_device -000119ad init_pci -00011b71 pci_find_device -00011c0b virtual_read -00011c3a virtual_write -00011c69 virtual_disk_attach -00011c8c wm_default_changes -00011d38 wm_default_workspace -00011d9e wm_default_draw -00011e40 wm_default_add -00011eeb init_windowmanager -00012037 wm_default_mouse_event -00012255 wm_default_push_back -0001234b wm_default_push_front -0001243e wm_default_remove -00012553 wm_destroy -00012635 wm_new -000126a0 scr_set_cursor -00012700 scrcolor_set -00012718 scrput -00012752 scrget -0001277c scrwrite -000127c9 scr_clear -0001281f scr_scroll -0001286b scrprintf -00012aeb init_vga -00012b13 scr_keyboard_add -00012b3d scr_keyboard_get -00012ba3 strlen -00012bc9 strstr -00012c37 strcpy -00012c6d strncmp -00012caa strcmp -00012cee memcmp -00012d2b parse_arguments -00012e14 strchr -00012e47 getopt -00012f92 memcpy -00013003 strtok -000130bf xmemcpy -00013148 memset -000131c6 isdigit -000131de isspace -000131f1 tolower -00013209 isxdigit -00013231 htoi -000132d9 atoi -0001336b itoa -0001341b itohex -0001349b rdtsc -000134a2 rand -000134c2 general_protection_fault -00013556 interrupt_get_count -00013569 print_page_fault_info -00013646 page_fault_interrupt -000136dc interrupt_install_handler -000136f2 load_data_segments -00013702 isr_handler -000137f9 init_interrupts -00013976 idt_flush -0001397e isr0 -0001398b isr1 -00013998 isr2 -000139a5 isr3 -000139b2 isr4 -000139bf isr5 -000139cc isr6 -000139d9 isr7 -000139e6 isr8 -000139f3 isr9 -00013a00 isr10 -00013a0d isr11 -00013a1a isr12 -00013a27 isr13 -00013a34 isr14 -00013a41 isr15 -00013a4e isr16 -00013a5b isr17 -00013a68 isr18 -00013a75 isr19 -00013a82 isr20 -00013a8f isr21 -00013a9c isr22 -00013aa9 isr23 -00013ab6 isr24 -00013ac3 isr25 -00013ad0 isr26 -00013add isr27 -00013aea isr28 -00013af7 isr29 -00013b04 isr30 -00013b11 isr31 -00013b1e isr32 -00013b2b isr33 -00013b38 isr34 -00013b45 isr35 -00013b4f isr36 -00013b59 isr37 -00013b63 isr38 -00013b6d isr39 -00013b77 isr40 -00013b81 isr41 -00013b8b isr42 -00013b95 isr43 -00013b9f isr44 -00013ba9 isr45 -00013bb3 isr46 -00013bbd isr47 -00013bc7 isr_entry -00013be2 syscall_return_value -00013be6 _syscall_entry -00013c23 page_fault_save -00013c27 page_fault_error -00013c2b _page_fault_entry -00013c5d timer_callback -00013c99 timer_get_tick -00013ca3 time_get_difference -00013ce8 init_pit -00013d50 gdt_set_segment -00013d9b init_gdt -00013ead rc -000140a0 __ksymbol_rc -000140be __ksymbol_as -000140dc __ksymbol_cc -000140fa as -000144c0 cc -00014520 __cc -00014819 vm_print -00014a1a eval -00014eb9 vm_setup -00014efe vm_init -00014f5d vm_free -00014f90 vm_setup_stack -00014fee lex_get_error -00014fff next -0001561a match -0001566c expression -00016a87 statement -00016c94 function_parameter -00016e5a function_body -0001706d function_declaration -000170fa enum_declaration -00017210 global_declaration -00017441 lex_init -000174e0 program -00017585 find_mp_floating_ptr -000175c5 smp_parse -0001770f kb_get_char -000177db kb_add_char -0001781a kb_callback -00017a4b init_keyboard -00017ac6 __pcb_get_free -00017b8c pcb_await -00017be0 __add_systemcall_pcb_await -00017bfb __pcb_free -00017c4a __pcb_init_kernel_stack -00017cab __pcb_init_process -00017d70 init_pcbs -00017dc5 pcb_total_usage -00017de6 pcb_get_info -00017ecc pcb_kill -00017eed Genesis -00017ef3 idletask -00017f12 pcb_get_by_pid -00017f27 pcb_get_by_name -00017f84 pcb_dbg_print -00018002 pcb_cleanup_routine -00018217 pcb_create_thread -00018313 pcb_create_process -000185ac pcb_create_kthread -00018892 start_pcb -000188ce __pcb_queue_peek -00018911 __pcb_queue_pop -00018971 __pcb_queue_remove -000189e7 __pcb_queue_add -00018a64 __pcb_queue_push -00018b01 pcb_new_queue -00018b36 get_mem_info -00018b92 memory_map_init -00018c5e memory_map_get -00018c68 free -00018cc3 malloc -00018d2f calloc -00018d66 krealloc -00018dd6 init_memory -00018e6c vmem_free -00018ee0 vmem_alloc -00018f51 vmem_free_page_region -000190ba vmem_page_region_alloc -000190f5 vmem_create_page_region -00019238 vmem_free_allocations -00019360 vmem_continious_allocation_map -0001936a vmem_free_allocation -0001936f vmem_stack_free -00019424 vmem_stack_alloc -000197ce vmem_dump_heap -00019867 vmem_init_process_thread -0001995c vmem_init_process -00019c89 vmem_cleanup_process_thead -00019d04 vmem_cleanup_process -00019ef4 vmem_init_kernel -0001a0b5 vmem_allocator_create -0001a11f vmem_map_driver_region -0001a1a1 vmem_total_usage -0001a1b8 vmem_init -0001a2f0 kalloc -0001a48b kcalloc -0001a4c1 kfree -0001a55b palloc -0001a5ab pmemory_used -0001a5cc kmemory_used -0001a5d6 kmemory_total -0001a5e6 kmem_init -0001a687 e1000_receive -0001a763 e1000_transmit -0001a829 e1000_callback -0001a854 _e1000_tx_init -0001a8fc _e1000_rx_init -0001a99a e1000_attach -0001abed display_get_info -0001ac5b kenv_init -0001ac76 kenv_set -0001acb2 config_list -0001ad98 kernel_config_load -0001b166 config_get_value -0001b229 spin_lock -0001b24d spin_unlock -0001b25f mutex_init -0001b281 acquire -0001b322 release -0001b3c8 kthread_entry -0001b426 kthread_list -0001b491 register_kthread -0001b56e start -0001b614 ata_primary -0001b619 ata_secondary -0001b61e ata_wait -0001b698 ata_write -0001b80a ata_read -0001b988 ata_ide_init -0001bb5c set_bitmap -0001bb82 unset_bitmap -0001bbaa get_bitmap -0001bbd0 get_bitmap_size -0001bbe8 create_bitmap -0001bc20 destroy_bitmap -0001bc37 bitmap_unset_continous -0001bc74 bitmap_get_continous -0001bd0e get_free_bitmap -0001bd67 __rtc_check_in_progress -0001bd8e __rtc_get_register -0001bdb2 get_current_time -0001befb get_time -0001bf29 init_tss -0001bf5b __add_systemcall_sys_system -0001bf76 exec_cmd -0001c0cf sys_system -0001c0e3 __ksymbol_exec_cmd -0001c101 system_reboot -0001c139 align_to_pointer_size -0001c14b calculate_size_unit -0001c1ab advanced_hash -0001c1e6 kernel_panic -0001c208 kref_init -0001c226 kref_get -0001c252 kref_put -0001c27e csprintf -0001c47c script_parse -0001c54e login_startup -0001c5b6 login -0001c985 __login_create_virt_disk -0001c9b3 __register_kthread_login -0001c9d1 help -0001cc76 clear -0001cc9b __ksymbol_new -0001ccb9 __ksymbol_list -0001ccd7 __ksymbol_color -0001ccf5 __ksymbol_about -0001cd13 __ksymbol_help -0001cd31 __ksymbol_kevents -0001cd4f __ksymbol_view -0001cd6d __ksymbol_file -0001cd8b __ksymbol_tcp -0001cda9 __ksymbol_conf -0001cdc7 __ksymbol_clear -0001cde5 __ksymbol_services -0001ce03 __ksymbol_reboot -0001ce21 kevents -0001ceff services -0001d131 new -0001d276 list -0001d37a file -0001d54c color -0001d5f1 about -0001d632 view -0001d84b tcp -0001db2c __tcp_reader -0001dc51 conf -0001df1d reboot -0001df5a attach_disk_dev -0001df82 disk_attached -0001df8e disk_name -0001df9b disk_device_get -0001dfa5 disk_size -0001dfc5 write_block -0001e006 write_block_offset -0001e04d read_block -0001e08e read_block_offset -0001e0fc sched_consume -0001e141 sched_add -0001e19f sched_prioritize -0001e258 sched_round_robin -0001e43e sched_exit -0001e4fb sched_block -0001e61d sched_default -0001e6f8 sched_sleep -0001e7a2 sched_init_default -0001e827 get_scheduler -0001e831 kernel_sleep -0001e850 kernel_yield -0001e897 kernel_exit -0001e8cd block -0001e8fa unblock -0001e8ff work_queue_add -0001ea03 init_worker -0001ea1f worker_thread -0001eac2 __ring_buffer_add -0001eb6e __ring_buffer_read -0001ec7c rbuffer_new -0001ece9 rbuffer_free -0001ed0f error_get_string -0001ed4f kclock -0001f22a __register_kthread_kclock -0001f248 tar_extract -0001f498 __ksymbol_tar -0001f4b6 tar_list -0001f5c1 tar -0001f84e rgb_to_vga -0001f862 rgb_to_components -0001f88d color_distance_squared -0001f8fd rgb_init_color_table -0001f988 iface_loopback_write -0001fa4d iface_loopback_interrupt -0001fa68 iface_loopback_read -0001fb12 net_init_loopback -0001fb2d serial_put -0001fb71 serial_write -0001fbb7 serial_printf -0001fd6b init_serial -0001fe35 inportb -0001fe42 inportw -0001fe50 inportl -0001fe5d outportb -0001fe6d outportw -0001fe7e outportl -0001fe8e sys_create_thread -0001feb1 sys_screen_put -0001fef2 sys_screen_get -0001ff03 sys_scr_set_cursor -0001ff1f __add_systemcall_sys_scr_set_cursor -0001ff2e __add_systemcall_sys_screen_get -0001ff3d __add_systemcall_sys_screen_put -0001ff4c __add_systemcall_sys_create_thread -0001ff5b add_system_call -0001ff9f system_call -0002000e hashmap_put -0002007a hashmap_get -00020102 hashmap_add -00020190 hashmap_free -00020195 reset_vga_palette -000201df vga_set_palette -000202ce b8to16 -000202e4 vesa_put_pixel -00020312 vesa_put_block -0002038c vesa_put_char -00020406 vesa_put_char16 -0002049e vesa_put_icon16 -00020519 vesa_write -0002055c vesa_write_str -0002058e vesa_fill -00020612 vesa_fillrect -00020681 vesa_inner_box -0002078d vesa_printf -00020a19 ksyms_init -00020c38 ksyms_add_symbol -00020cf5 __ksymbol_backtrace -00020d13 ksyms_list -00020d79 ksyms_resolve_symbol -00020e30 __backtrace_from -00020f4e backtrace -00020f63 ws_fullscreen -000210e1 ws_remove -00021195 ws_add -00021284 ws_destroy -0002132e ws_draw -000215e6 ws_raw_wallpaper -000216d0 ws_set_background_file -000219b0 ws_init -00021a97 ws_set_background -00021b46 ws_new -00021bd7 encode_run_length -00021c60 decode_run_length -00021cd7 __mouse_handler -00021def mouse_wait -00021e37 mouse_write -00021e79 mouse_get_event -00021ebe mouse_init -00021fa7 sys_ipc_open -00021ff9 __add_systemcall_sys_ipc_open -00022014 __add_systemcall_sys_ipc_close -0002202f __add_systemcall_sys_ipc_send -0002204a __add_systemcall_sys_ipc_receive -00022065 sys_ipc_close -000220b2 sys_ipc_send -0002211d sys_ipc_receive -00022187 sysinf -00022ef3 __register_kthread_sysinf -00022f11 echo -00022f50 res -00022f95 ifconfig -00022fa6 __ksymbol_ifconfig -00022fc4 __ksymbol_ps -00022fe2 __ksymbol_tree -00023000 __ksymbol_fat16 -0002301e __ksymbol_xxd -0002303c __ksymbol_sh -0002305a __ksymbol_ed -00023078 __ksymbol_exec -00023096 __ksymbol_ths -000230b4 __ksymbol_dns -000230d2 __ksymbol_th -000230f0 __ksymbol_kill -0002310e __ksymbol_echo -0002312c __ksymbol_fdisk -0002314a __ksymbol_meminfo -00023168 __ksymbol_res -00023186 __ksymbol_bg -000231a4 __ksymbol_exit -000231c2 __ksymbol_socks -000231e0 __ksymbol_reset -000231fe exit -00023236 ps -000234ae print_pcb_tree -000235ad tree -000235f1 fat16 -0002361d xxd -00023716 sh -0002381a ed -0002386b exec -000239e7 ths -00023a57 dns -00023acf th -00023af1 kill -00023b13 fdisk -00023ca9 meminfo -00023e8c bg -00023f0f socks -000241b8 __register_kthread_shell -000241d6 __register_kthread_textshell -000241f4 shell_clear -0002423b reset_shell -000242b0 reset -00024308 shell_put -000244ee shell -00024753 cleanup_function -0002477e testfn -000247b6 draw_box -0002489f __textshell_reset_box -0002492f textshell -00024d7c __net_find_interface -00024ddc net_drop_packet -00024dfd net_handle_recieve -00024f28 net_get_interfaces -00024f32 net_configure_iface -00024f88 net_incoming_packet -0002503a net_get_iface -000250b6 net_iface_up -000250e1 net_iface_down -0002510c net_list_ifaces -0002522a net_register_interface -0002525f net_send_skb -000252eb net_get_info -00025316 networking_main -000254f6 __dhcp_add_option -00025560 __dhcp_send_discovery -000256a2 __dhcp_send_request -0002581f dhcp_get_state -0002582b dhcp_get_dns -00025835 dhcp_get_ip -0002584e dhcp_get_gw -00025867 dhcpd -00025afb udp_server -00025b8a tcp_server -00025d02 __net_terminal_writef -00025d6b __register_kthread_tcp_server -00025d89 __register_kthread_udp_server -00025da7 __register_kthread_udptest -00025dc5 udptest -00025e54 tcpd -00025f3c logd -00025fab __register_kthread_logd -00025fc9 logd_attach_by_pid -00026011 taskbar_reboot -00026041 __reboot -0002605a taskbar_readme -00026077 taskbar_about -00026094 taskbar_clock -000260b1 taskbar_sysinf -000260ce taskbar_bg_retro -00026109 taskbar_bg_lotr2 -00026122 taskbar_bg_lotr -0002613b taskbar_bg_default_color_gray -00026151 taskbar_bg_default_color -00026167 taskbar_wolfstein -000261a6 taskbar_bg_graph -000261e5 taskbar_bg_calc -00026224 taskbar_colors -00026263 taskbar_cube -000262a2 taskbar_editor -000262e1 taskbar_finder -00026320 taskbar_terminal -0002636d __register_kthread_taskbar -0002638b taskbar_hdr_opt_event -00026415 taskbar -00026a22 about -00026bf1 __register_kthread_about -00026c0f __register_kthread_readme -00026c2d readme -00026d93 gfx_default_hover -00026ec1 gfx_draw_window -00027cdc gfx_destory_window -00027d6d gfx_window_resize -00027e1a gfx_window_maximize -00027e97 gfx_default_mouse_up -00027f69 gfx_default_mouse_down -0002802f gfx_default_click -00028222 gfx_window_set_resizable -0002823b kernel_gfx_window_border_color -0002826a gfx_new_window -000284d1 gfx_point_in_rectangle -00028502 gfx_draw_component -00028548 gfx_input_event -00028669 gfx_input_draw -00028775 gfx_input_manager_add -000287da gfx_composition_remove_window -00028808 gfx_composition_add_window -00028853 gfx_set_background_color -000288a8 gfx_raw_background -000288f9 gfx_decode_background_image -0002894a gfx_set_taskbar -000289ee gfx_compositor_main -00028a66 kernel_gfx_draw_circle_helper -00028cdd gfx_get_window_width -00028cf6 gfx_get_window_height -00028d0f gfx_push_event -00028dd6 gfx_put_icon16 -00028ece gfx_put_icon32 -00028fc4 gfx_event_loop -000290ea kernel_gfx_draw_rectangle -000291ec kernel_gfx_draw_contoured_box -00029290 kernel_gfx_draw_pixel -00029339 kernel_gfx_draw_bitmap -0002945e kernel_gfx_draw_char -00029548 kernel_gfx_set_position -00029568 gfx_commit -00029585 kernel_gfx_draw_text -0002963c gfx_button_ext -00029773 gfx_button -00029795 kernel_gfx_set_title -00029805 kernel_gfx_set_header -00029875 kernel_gfx_draw_line -00029a0f kernel_gfx_draw_circle -00029a92 kernel_gfx_draw_section -00029a9c kernel_gfx_draw_format_text -00029dee gfx_syscall_hook -00029faa gfx_total_themes -00029fb4 kernel_gfx_current_theme -00029fbe kernel_gfx_update_theme -0002a090 kernel_gfx_default_theme -0002a09a kernel_gfx_set_theme -0002a0c3 kernel_gfx_get_theme -0002a0e2 gfx_new_ctx -0002a142 gfx_init_framebuffer -0002a2b2 netdev_attach_driver -0002a35f is_netdev_attached -0002a371 netdev_transmit -0002a390 netdev_recieve -0002a3bd net_ethernet_add_header -0002a455 net_ethernet_parse -0002a4d0 __skb_queue_remove -0002a512 __skb_queue_add -0002a566 skb_free_queue -0002a5a2 skb_new_queue -0002a60d skb_free -0002a64c skb_new -0002a6bb skb_consume -0002a6f0 __net_arp_send -0002a7b0 net_init_arp -0002a800 net_arp_add_entry -0002a898 net_arp_find_entry -0002a8e7 net_arp_respond -0002a960 net_net_arp_request -0002a9ea arp_parse -0002aa98 net_ipv4_print -0002aaa2 net_ipv4_add_header -0002abdd net_is_ipv4 -0002ac1e net_ipv4_parse -0002ad4f ntohl -0002ad7f htonl -0002ad96 ntohs -0002ada7 htons -0002adb8 checksum -0002ae13 transport_checksum -0002ae6c ip_to_int -0002af0e net_icmp_handle -0002afd7 net_icmp_response -0002afe1 net_icmp_request -0002b0a8 ping -0002b105 net_icmp_parse -0002b179 net_udp_send -0002b2b2 net_udp_parse -0002b3de socket_type_to_str -0002b3f1 socket_domain_to_str -0002b404 socket_protocol_to_str -0002b417 net_sock_bind -0002b466 net_get_sockets -0002b486 sock_get -0002b4ab get_total_sockets -0002b4b5 net_sock_is_established -0002b4fd net_sock_awaiting_ack -0002b545 net_sock_data_ready -0002b5a0 net_sock_read -0002b6a5 net_sock_add_data -0002b909 sock_find_listen_tcp -0002b951 net_sock_find_tcp -0002bb44 net_prepare_tcp_sock -0002bbd4 net_sock_accept -0002bbeb net_socket_find_udp -0002bc5a kernel_sock_shutdown -0002bc8b kernel_sock_cleanup -0002bd15 kernel_sock_close -0002bd4d kernel_socket_create -0002bed4 net_init_sockets -0002bf1e gethostname -0002c44c __add_systemcall_gethostname -0002c467 net_init_dns -0002c49a route -0002c4eb tcb_init -0002c50d tcb_new -0002c67d tcp_state_to_str -0002c69a tcp_new_connection -0002c726 tcp_free_connection -0002c74d tcp_is_listening -0002c767 tcp_set_listening -0002c7cb tcp_calculate_checksum -0002c894 __tcp_send -0002c9b0 tcp_send_segment -0002caf7 tcp_accept_connection -0002cc3d tcp_send_ack -0002cd75 tcp_read -0002cd7f tcp_recv_segment -0002cd89 tcp_connect -0002ce30 tcp_send_syn -0002ce3a tcp_recv_ack -0002cec1 tcp_recv_fin -0002cecb tcp_recv_syn -0002d001 tcp_send_fin -0002d0d1 tcp_close_connection -0002d114 tcp_parse -0002d5b0 kernel_bind -0002d5e9 kernel_recvfrom -0002d5f3 kernel_recv -0002d669 kernel_recv_timeout -0002d693 kernel_connect -0002d799 kernel_sendto -0002d857 kernel_accept -0002d8be kernel_listen -0002d8ea kernel_send -0002d974 sys_kernel_bind -0002d9aa __add_systemcall_sys_kernel_bind -0002d9c5 __add_systemcall_sys_kernel_accept -0002d9e0 __add_systemcall_sys_kernel_connect -0002d9fb __add_systemcall_sys_kernel_listen -0002da16 __add_systemcall_sys_kernel_recv -0002da31 __add_systemcall_sys_kernel_recvfrom -0002da4c __add_systemcall_sys_kernel_recv_timeout -0002da67 __add_systemcall_sys_kernel_send -0002da82 __add_systemcall_sys_kernel_sendto -0002da9d __add_systemcall_sys_socket_create -0002dab8 __add_systemcall_sys_kernel_sock_close -0002dad3 sys_kernel_accept -0002db17 sys_kernel_connect -0002db4d sys_kernel_listen -0002db80 sys_kernel_recv -0002dbbc sys_kernel_recvfrom -0002dc00 sys_kernel_recv_timeout -0002dc42 sys_kernel_send -0002dc7e sys_kernel_sendto -0002dcc2 sys_socket_create -0002dced sys_kernel_sock_close -0002dd32 __iface_send -0002dd65 __iface_recieve -0002dd98 __iface_assign -0002ddaf __iface_detach -0002ddc7 __iface_set_gateway -0002ddde __iface_set_netmask -0002ddf5 __iface_configure -0002de49 __iface_attach -0002de72 net_interface_create -0002deae net_register_netdev -0002dfca net_interface_destroy -0002dfe3 __default_restart -0002dfed __default_stop -0002e056 __default_start -0002e0d9 nm_new -0002e166 nm_free -0002e1af net_firewall_create -0002e1d6 fs_file2fd -0002e23f fs_alloc_file -0002e28e fs_free_file -0002e2ec fs_register -0002e3bf fs_init -0002e3c9 fs_unregister -0002e430 fs_get -0002e43a fs_close -0002e4b0 fs_open -0002e52e fs_seek -0002e5af fs_read -0002e6c8 fs_load_from_file -0002e758 fs_write -0002e817 fs_save_to_file -0002e8a7 fat16_rmdir -0002e8b1 fat16_stat -0002e8bb fat16_close -0002e929 fat16_rename -0002e9c2 fat16_mkdir -0002eaab fat16_remove -0002eb22 fat16_open -0002ec70 fat16_read -0002edd3 fat16_write -0002ef06 fat16_list -0002f1d8 fat16_init -0002f290 path_next_iter -0002f2fe inode_from_path_recursise -0002f37c inode_from_path -0002f43e ext_get_root -0002f44b ext_get_current_dir -0002f45e ext_get_size -0002f468 ext_get_inodes -0002f472 ext_get_blocks -0002f47c ext_sync -0002f4f3 ext_create -0002f5e2 ext_read -0002f661 ext_seek -0002f6ac ext_write -0002f71c ext_close -0002f782 ext_open_from_directory -0002f88a ext_open -0002f945 ext_size -0002f972 change_directory -0002f9dc ext_create_directory -0002fb7a ext_create_file_system -0002fe4b init_ext -0002ffeb listdir -00030112 __inode_sync -00030175 __inode_cache_insert -0003026b __inode_load -000302df inodes_sync -0003031e inode_get -0003037f inode_read -0003056f inode_write -000307d6 alloc_inode -00030893 mkdir -00030944 sync -0003097c mkfs -0003098d fat16_read_data_from_cluster -000309df fat16_read_data -00030abc fat16_find_cluster_by_offset -00030b3b fat16_write_data_to_cluster_with_offset -00030b7a fat16_print_cluster_chain -00030bac fat16_write_data_to_cluster -00030be3 fat16_write_data -00030cfe get_fat_start_block -00030d0a get_root_directory_start_block -00030d1d get_data_start_block -00030d33 fat16_get_fat_entry -00030d52 fat16_set_fat_entry -00030d96 fat16_sync_fat_table -00030e12 fat16_allocate_cluster -00030e2e fat16_free_cluster -00030e47 fat16_get_free_cluster -00030ea0 fat16_sync_directory_entry -00030f27 fat16_read_entry -00030fd8 fat16_find_entry -00031113 fat16_rename_entry -00031188 fat16_free_clusters -000311d3 fat16_delete_entry -0003123e fat16_add_entry -000313a9 fat16_used_blocks -000313e6 fat16_to_upper -00031416 fat16_name_compare -00031531 sstrtok -000315f4 fat16_directory_entry_debug -000316cb fat16_get_directory_entry -000318d4 fat16_create_directory -000319dd fat16_read_file -00031a32 fat16_create_file -00031ab4 fat16_create_empty_file -00031b7c fat16_directory_entries -00031c67 fat16_mbr_clear -00031d32 fat16_mbr_add_entry -00031e27 fat16_print_root_directory_entries -00031e43 fat16_change_directory -00031ecf fat16_bootblock_info -00032050 fat16_set_time -00032088 fat16_set_date -000320c4 fat16_load -00032247 fat16_format -00032500 mbr_partition_type_string -00032588 mbr_partitions_parse -00032656 mbr_get -00032660 mbr_partition_load -00032682 __list_users -00032717 __change_user -000327bd __remove_user -0003286d __add_user -0003295b __find_user -00032a35 __authenticate_user -00032b4d __save_users -00032bd5 __load_users -00032ddb __ksymbol_admin -00032df9 admin -0003311b usermanager_create -0003313e __ksymbol_snakegame -0003315c init_game -000331ac draw -0003320c get_input -0003322f update -000333bb game_loop -000333e5 snakegame -00033434 __msgbox -00033847 msgbox_create -0003387e msgbox_show -000338ca kevents_list -00033a40 kevents_init -00033a86 kevents_destroy -00033adf kevents_add -00033b9a kevents_create -00033c21 __register_kthread_screeny -00033c3f screeny -00033ea0 _code_end diff --git a/rootfs/sysutil/symbols.map b/rootfs/sysutil/symbols.map deleted file mode 100644 index 0a2f136..0000000 --- a/rootfs/sysutil/symbols.map +++ /dev/null @@ -1,860 +0,0 @@ -00010000 _code -00010000 _start -00010030 gdtp -00010040 gdt_null -00010040 gdt_start -00010048 code_descriptor -00010050 data_descriptor -00010058 gdt_end -00010058 kernel_boot_printf -000100b7 init_kctors -00010103 kernel -00010544 kernel_get_context -0001054a hexdump -00010798 __terminal_set_ops -00010861 __terminal_scanf -00010867 __terminal_write -000108b1 __terminal_getchar_graphics -000108fa __terminal_scan_graphics -000109d8 __terminal_reset -00010a1c __terminal_detach -00010a5f __terminal_attach -00010aaa __terminal_commit_graphics -00010b80 __terminal_remove_line -00010bc0 __terminal_putchar_graphics -00010c89 __terminal_writef -00010f30 __terminal_getchar_textmode -00010f58 __terminal_scan_textmode -00011018 __terminal_commit_textmode -000110d0 __terminal_putchar_textmode -0001111c scan -00011155 terminal_set_color -00011156 terminal_attach -00011177 terminal_commit -00011196 terminal_putchar -00011197 terminal_create -000112b5 terminal_destroy -000112ec tlb_flush_addr -000112f4 load_page_directory -00011304 enable_paging -00011316 pcb_save_context -00011342 pcb_restore_context -0001136b _start_pcb -0001139d _start_pcb_skip -000113b8 __ksymbol_lspci -000113d2 pci_get_class_name -000113e5 pci_get_device_name -00011456 pci_get_vendor_name -000114a4 lspci -000115f1 pci_get_devices -000115f7 pci_read_word -00011651 pci_write_dword -000116a0 pci_enable_device_busmaster -000116f5 pci_register_device -00011776 init_pci -00011927 pci_find_device -000119bd virtual_read -000119e8 virtual_write -00011a13 virtual_disk_attach -00011a32 wm_default_changes -00011ada wm_default_workspace -00011b3c wm_default_draw -00011bda wm_default_add -00011c81 init_windowmanager -00011dcb wm_default_mouse_event -00011ff1 wm_default_push_back -000120e3 wm_default_push_front -000121d2 wm_default_remove -000122e3 wm_destroy -000123c1 wm_new -00012428 scr_set_cursor -00012488 scrcolor_set -0001249c scrput -000124c2 scrwrite -0001250b scr_clear -0001255d scr_scroll -000125a5 scrprintf -000127e9 strlen -0001280b strcpy -0001283f strncmp -0001287a strcmp -000128ba memcmp -000128f5 parse_arguments -000129d8 strchr -00012a07 getopt -00012b17 memcpy -00012b84 strtok -00012c3c xmemcpy -00012cc3 memset -00012d43 isdigit -00012d57 isspace -00012d66 tolower -00012d7a isxdigit -00012d9e htoi -00012e42 atoi -00012ed2 itoa -00012f78 itohex -00012ff4 rdtsc -00012ff7 rand -00013013 general_protection_fault -00013083 interrupt_get_count -00013092 print_page_fault_info -0001316f page_fault_interrupt -00013233 interrupt_install_handler -00013245 load_data_segments -00013251 isr_handler -00013344 init_interrupts -000134bd idt_flush -000134c5 isr0 -000134d2 isr1 -000134df isr2 -000134ec isr3 -000134f9 isr4 -00013506 isr5 -00013513 isr6 -00013520 isr7 -0001352d isr8 -0001353a isr9 -00013547 isr10 -00013554 isr11 -00013561 isr12 -0001356e isr13 -0001357b isr14 -00013588 isr15 -00013595 isr16 -000135a2 isr17 -000135af isr18 -000135bc isr19 -000135c9 isr20 -000135d6 isr21 -000135e3 isr22 -000135f0 isr23 -000135fd isr24 -0001360a isr25 -00013617 isr26 -00013624 isr27 -00013631 isr28 -0001363e isr29 -0001364b isr30 -00013658 isr31 -00013665 isr32 -00013672 isr33 -0001367f isr34 -0001368c isr35 -00013696 isr36 -000136a0 isr37 -000136aa isr38 -000136b4 isr39 -000136be isr40 -000136c8 isr41 -000136d2 isr42 -000136dc isr43 -000136e6 isr44 -000136f0 isr45 -000136fa isr46 -00013704 isr47 -0001370e isr_entry -00013729 syscall_return_value -0001372d _syscall_entry -0001376a page_fault_save -0001376e page_fault_error -00013772 _page_fault_entry -000137a4 timer_callback -000137dc timer_get_tick -000137e2 time_get_difference -00013825 init_pit -00013889 gdt_set_segment -000138d2 init_gdt -000139e0 rc -00013bcf __ksymbol_rc -00013be9 __ksymbol_as -00013c03 __ksymbol_cc -00013c1d as -00013fdf cc -0001403b __cc -0001432f vm_print -0001452c eval -000149c6 vm_setup -00014a07 vm_init -00014a62 vm_free -00014a91 vm_setup_stack -00014aed lex_get_error -00014afa next -00015005 match -00015053 expression -00016354 statement -0001655d function_parameter -0001671f function_body -0001692e function_declaration -000169b7 enum_declaration -00016aca global_declaration -00016cf7 lex_init -00016d92 program -00016e33 find_mp_floating_ptr -00016e6f smp_parse -00016fb4 kb_get_char -00017000 kb_add_char -0001703b kb_callback -00017268 init_keyboard -000172df pcb_await -00017309 __pcb_get_free -000173c7 __add_systemcall_pcb_await -000173de __pcb_free -0001742d __pcb_init_kernel_stack -0001748e __pcb_init_process -00017553 init_pcbs -000175af pcb_total_usage -000175d8 pcb_get_info -00017702 pcb_kill -0001771f Genesis -00017721 idletask -0001773c pcb_get_by_pid -0001774d pcb_get_by_name -000177a6 pcb_dbg_print -00017820 pcb_cleanup_routine -000179f3 pcb_create_thread -00017aa6 pcb_create_process -00017cf1 pcb_create_kthread -00017f80 start_pcb -00017fb8 __pcb_queue_peek -00017ff7 __pcb_queue_pop -00018053 __pcb_queue_remove -000180c5 __pcb_queue_add -0001813e __pcb_queue_push -000181d7 pcb_new_queue -00018208 memory_map_init -000182cf memory_map_get -000182d5 free -0001833f malloc -000183db calloc -0001840e get_mem_info -00018466 init_memory -000184f8 vmem_free -00018568 vmem_alloc -000185d5 vmem_free_page_region -0001873b vmem_page_region_alloc -00018776 vmem_create_page_region -000188ba vmem_free_allocations -000189e9 vmem_continious_allocation_map -000189ef vmem_free_allocation -000189f0 vmem_stack_free -00018aa1 vmem_stack_alloc -00018e26 vmem_dump_heap -00018ebb vmem_init_process_thread -00018fac vmem_init_process -000192da vmem_cleanup_process_thead -00019351 vmem_cleanup_process -0001953f vmem_init_kernel -00019700 vmem_allocator_create -00019764 vmem_map_driver_region -000197e2 vmem_total_usage -000197f5 vmem_init -00019927 kalloc -00019abe kcalloc -00019af0 kfree -00019b86 palloc -00019bc8 pmemory_used -00019be4 kmemory_used -00019bea kmemory_total -00019bf6 kmem_init -00019c93 e1000_receive -00019d6e e1000_transmit -00019e30 e1000_callback -00019e57 _e1000_tx_init -00019efb _e1000_rx_init -00019f95 e1000_attach -0001a1c5 display_get_info -0001a22e kenv_init -0001a245 kenv_set -0001a27a config_list -0001a34b kernel_config_load -0001a736 config_get_value -0001a7f1 spin_lock -0001a811 spin_unlock -0001a81f mutex_init -0001a83c acquire -0001a8d9 release -0001a97b kthread_entry -0001a9d5 kthread_list -0001aa3c register_kthread -0001ab15 start -0001abb7 ata_primary -0001abb8 ata_secondary -0001abb9 ata_wait -0001ac33 ata_write -0001adaa ata_read -0001af3a ata_ide_init -0001b10a set_bitmap -0001b12c unset_bitmap -0001b150 get_bitmap -0001b172 get_bitmap_size -0001b186 create_bitmap -0001b1ba destroy_bitmap -0001b1cd bitmap_unset_continous -0001b207 bitmap_get_continous -0001b2a3 get_free_bitmap -0001b2f8 __rtc_check_in_progress -0001b31a __rtc_get_register -0001b33a get_current_time -0001b485 get_time -0001b4af init_tss -0001b4dd exec_cmd -0001b5e1 __ksymbol_exec_cmd -0001b5fb reboot -0001b62f align_to_pointer_size -0001b63d calculate_size_unit -0001b69f kernel_panic -0001b6bd kref_init -0001b6d7 kref_get -0001b6ff kref_put -0001b727 csprintf -0001b928 script_parse -0001b9fd login -0001bc71 __login_create_virt_disk -0001bc9b __register_kthread_login -0001bcb5 help -0001bf1b clear -0001bf3c __ksymbol_new -0001bf56 __ksymbol_list -0001bf70 __ksymbol_color -0001bf8a __ksymbol_about -0001bfa4 __ksymbol_help -0001bfbe __ksymbol_view -0001bfd8 __ksymbol_file -0001bff2 __ksymbol_tcp -0001c00c __ksymbol_conf -0001c026 __ksymbol_clear -0001c040 new -0001c181 list -0001c281 file -0001c44f color -0001c4f0 about -0001c52d view -0001c742 tcp -0001ca1f __tcp_reader -0001cb40 conf -0001cdc5 attach_disk_dev -0001cde9 disk_attached -0001cdf1 disk_name -0001cdfa disk_device_get -0001ce00 disk_size -0001ce1c write_block -0001ce59 write_block_offset -0001ce9c read_block -0001ced9 read_block_offset -0001cf43 sched_consume -0001cf84 sched_add -0001cfde sched_prioritize -0001d093 sched_round_robin -0001d279 sched_exit -0001d332 sched_block -0001d450 sched_default -0001d52a sched_sleep -0001d5d0 sched_init_default -0001d651 get_scheduler -0001d657 kernel_sleep -0001d672 kernel_yield -0001d6b5 kernel_exit -0001d6e7 block -0001d710 unblock -0001d711 work_queue_add -0001d7f9 init_worker -0001d811 worker_thread -0001d8b0 __ring_buffer_add -0001d958 __ring_buffer_read -0001da62 rbuffer_new -0001dacb rbuffer_free -0001daed error_get_string -0001db29 kclock -0001e009 __register_kthread_kclock -0001e023 tar_extract -0001e273 __ksymbol_tar -0001e28d tar_list -0001e397 tar -0001e620 rgb_to_vga -0001e630 rgb_to_components -0001e657 color_distance_squared -0001e6c2 rgb_init_color_table -0001e753 iface_loopback_write -0001e814 iface_loopback_interrupt -0001e82b iface_loopback_read -0001e8ce net_init_loopback -0001e8e5 serial_put -0001e925 serial_write -0001e967 serial_printf -0001eb07 init_serial -0001ebcd inportb -0001ebd6 inportw -0001ebe0 inportl -0001ebe9 outportb -0001ebf7 outportw -0001ec06 outportl -0001ec13 sys_create_thread -0001ec32 __add_systemcall_sys_create_thread -0001ec3d add_system_call -0001ec7d system_call -0001ece8 hashmap_put -0001ed4f hashmap_get -0001edd3 hashmap_add -0001ee5d hashmap_free -0001ee5e reset_vga_palette -0001eea4 vga_set_palette -0001ef8f b8to16 -0001ef9f vesa_put_pixel -0001efc9 vesa_put_box -0001f044 vesa_put_block -0001f0bf vesa_put_char -0001f13a vesa_put_char16 -0001f1cd vesa_put_icon16 -0001f246 vesa_write -0001f285 vesa_write_str -0001f2b3 vesa_fill -0001f335 vesa_fillrect -0001f3a7 vesa_inner_box -0001f4af vesa_printf -0001f71c ksyms_init -0001f943 ksyms_add_symbol -0001f9fc __ksymbol_backtrace -0001fa16 ksyms_list -0001fa78 ksyms_resolve_symbol -0001fb2b __backtrace_from -0001fc48 backtrace -0001fc59 ws_fullscreen -0001fdd3 ws_remove -0001fe83 ws_add -0001ff6e ws_destroy -00020014 ws_draw -000202c1 ws_raw_wallpaper -000203a7 ws_set_background_file -00020684 ws_init -00020767 ws_set_background -00020812 ws_new -0002089f encode_run_length -0002091c decode_run_length -00020987 __mouse_handler -00020a9e mouse_wait -00020ae6 mouse_write -00020b28 mouse_get_event -00020b69 mouse_init -00020c4e sys_ipc_open -00020c9c __add_systemcall_sys_ipc_open -00020cb3 __add_systemcall_sys_ipc_close -00020cca __add_systemcall_sys_ipc_send -00020ce1 __add_systemcall_sys_ipc_receive -00020cf8 sys_ipc_close -00020d41 sys_ipc_send -00020da8 sys_ipc_receive -00020e0e sysinf -00021b60 __register_kthread_sysinf -00021b7a echo -00021bb5 res -00021bf6 ifconfig -00021c03 __ksymbol_ifconfig -00021c1d __ksymbol_ps -00021c37 __ksymbol_tree -00021c51 __ksymbol_fat16 -00021c6b __ksymbol_xxd -00021c85 __ksymbol_sh -00021c9f __ksymbol_ed -00021cb9 __ksymbol_exec -00021cd3 __ksymbol_ths -00021ced __ksymbol_dns -00021d07 __ksymbol_th -00021d21 __ksymbol_kill -00021d3b __ksymbol_echo -00021d55 __ksymbol_fdisk -00021d6f __ksymbol_meminfo -00021d89 __ksymbol_res -00021da3 __ksymbol_bg -00021dbd __ksymbol_exit -00021dd7 __ksymbol_socks -00021df1 __ksymbol_reset -00021e0b exit -00021e3f ps -000220a5 print_pcb_tree -000221a4 tree -000221e4 fat16 -0002220c xxd -00022301 sh -00022401 ed -0002244e exec -000225b2 ths -0002261e dns -00022692 th -000226b0 kill -000226ce fdisk -00022860 meminfo -00022a3f bg -00022abe socks -00022d64 __register_kthread_shell -00022d7e __register_kthread_textshell -00022d98 shell_clear -00022ddb reset_shell -00022e4c reset -00022ea0 shell_put -00023081 shell -000232d7 cleanup_function -000232fe testfn -00023332 draw_box -00023417 __textshell_reset_box -000234a7 textshell -00023721 __net_find_interface -00023781 net_drop_packet -000237a2 net_handle_recieve -000238c9 net_get_interfaces -000238cf net_configure_iface -00023921 net_incoming_packet -000239d2 net_get_iface -00023a48 net_iface_up -00023a6f net_iface_down -00023a96 net_list_ifaces -00023bb0 net_register_interface -00023be1 net_send_skb -00023c69 net_get_info -00023c90 networking_main -00023e70 __dhcp_add_option -00023ee0 __dhcp_send_discovery -00024022 __dhcp_send_request -0002419f dhcp_get_state -000241a7 dhcp_get_dns -000241ad dhcp_get_ip -000241c2 dhcp_get_gw -000241d7 dhcpd -00024456 udp_server -000244e1 tcp_server -00024655 __net_terminal_writef -000246ba __register_kthread_tcp_server -000246d4 __register_kthread_udp_server -000246ee __register_kthread_udptest -00024708 udptest -00024793 tcpd -00024877 logd -000248e2 __register_kthread_logd -000248fc logd_attach_by_pid -00024940 taskbar_reboot -0002496c __reboot -00024981 taskbar_readme -0002499a taskbar_about -000249b3 taskbar_clock -000249cc taskbar_sysinf -000249e5 taskbar_bg_retro -00024a1c taskbar_bg_lotr2 -00024a31 taskbar_bg_lotr -00024a46 taskbar_bg_default_color_gray -00024a58 taskbar_bg_default_color -00024a6a taskbar_wolfstein -00024aa5 taskbar_bg_graph -00024ae0 taskbar_bg_calc -00024b1b taskbar_colors -00024b56 taskbar_cube -00024b91 taskbar_editor -00024bcc taskbar_finder -00024c07 taskbar_terminal -00024c50 __register_kthread_taskbar -00024c6a taskbar_hdr_opt_event -00024cf4 taskbar -000252ab about -00025476 __register_kthread_about -00025490 __register_kthread_readme -000254aa readme -0002560c gfx_default_hover -0002572b gfx_destory_window -000257b8 gfx_window_resize -00025861 gfx_window_maximize -000258da gfx_default_mouse_up -000259a8 gfx_default_mouse_down -00025a6a gfx_default_click -00025c59 gfx_draw_window -00026a45 gfx_window_set_resizable -00026a5a kernel_gfx_window_border_color -00026a85 gfx_new_window -00026ce5 gfx_point_in_rectangle -00026d12 gfx_draw_component -00026d54 gfx_composition_remove_window -00026d7e gfx_composition_add_window -00026dc5 gfx_set_background_color -00026e16 gfx_raw_background -00026e63 gfx_decode_background_image -00026eb0 gfx_set_taskbar -00026f03 gfx_compositor_main -00026f77 kernel_gfx_draw_circle_helper -00027223 gfx_get_window_width -00027238 gfx_get_window_height -0002724d gfx_push_event -00027309 gfx_put_icon16 -00027401 gfx_put_icon32 -000274f9 gfx_event_loop -00027618 kernel_gfx_draw_rectangle -00027712 kernel_gfx_draw_contoured_box -000277b2 kernel_gfx_draw_pixel -00027850 kernel_gfx_draw_bitmap -0002796e kernel_gfx_draw_char -00027a6e kernel_gfx_set_position -00027a8a gfx_commit -00027aa3 kernel_gfx_draw_text -00027b56 gfx_button_ext -00027c89 gfx_button -00027ca7 kernel_gfx_set_title -00027d13 kernel_gfx_set_header -00027d7f kernel_gfx_draw_line -00027f1a kernel_gfx_draw_circle -00027f99 kernel_gfx_draw_section -00027f9f kernel_gfx_draw_format_text -000282f1 gfx_syscall_hook -000284a8 gfx_total_themes -000284ae kernel_gfx_current_theme -000284b4 kernel_gfx_update_theme -00028582 kernel_gfx_default_theme -00028588 kernel_gfx_set_theme -000285ad kernel_gfx_get_theme -000285c8 gfx_new_ctx -00028624 gfx_init_framebuffer -00028790 netdev_attach_driver -00028839 is_netdev_attached -00028847 netdev_transmit -00028862 netdev_recieve -0002888b net_ethernet_add_header -0002891f net_ethernet_parse -00028993 __skb_queue_remove -000289d1 __skb_queue_add -00028a21 skb_free_queue -00028a59 skb_new_queue -00028ac0 skb_free -00028afb skb_new -00028b66 skb_consume -00028b97 __net_arp_send -00028c57 net_init_arp -00028ca3 net_arp_add_entry -00028d32 net_arp_find_entry -00028d7d net_arp_respond -00028df2 net_net_arp_request -00028e78 arp_parse -00028f22 net_ipv4_print -00028f28 net_ipv4_add_header -0002905f net_is_ipv4 -0002909c net_ipv4_parse -000291c9 ntohl -000291f5 htonl -00029208 ntohs -00029215 htons -00029222 checksum -00029279 transport_checksum -000292ce ip_to_int -0002936c net_icmp_handle -00029431 net_icmp_response -00029437 net_icmp_request -000294fa ping -00029553 net_icmp_parse -000295c3 net_udp_send -000296f8 net_udp_parse -00029820 socket_type_to_str -0002982f socket_domain_to_str -0002983e socket_protocol_to_str -0002984d net_sock_bind -00029898 net_get_sockets -000298b4 sock_get -000298d5 get_total_sockets -000298db net_sock_is_established -0002991f net_sock_awaiting_ack -00029963 net_sock_data_ready -000299bc net_sock_read -00029abe net_sock_add_data -00029d1e sock_find_listen_tcp -00029d62 net_sock_find_tcp -00029f54 net_prepare_tcp_sock -00029fe0 net_sock_accept -00029ff3 net_socket_find_udp -0002a05e kernel_sock_shutdown -0002a08b kernel_sock_cleanup -0002a111 kernel_sock_close -0002a145 kernel_socket_create -0002a2c8 net_init_sockets -0002a30e gethostname -0002a828 __add_systemcall_gethostname -0002a83f net_init_dns -0002a86e route -0002a8bb tcb_init -0002a8d9 tcb_new -0002aa45 tcp_state_to_str -0002aa5e tcp_new_connection -0002aae6 tcp_free_connection -0002ab09 tcp_is_listening -0002ab1f tcp_set_listening -0002ab7f tcp_calculate_checksum -0002ac43 __tcp_send -0002ad5f tcp_send_segment -0002aea2 tcp_accept_connection -0002afe4 tcp_send_ack -0002b11a tcp_read -0002b120 tcp_recv_segment -0002b126 tcp_connect -0002b1c9 tcp_send_syn -0002b1cf tcp_recv_ack -0002b252 tcp_recv_fin -0002b258 tcp_recv_syn -0002b38a tcp_send_fin -0002b456 tcp_close_connection -0002b495 tcp_parse -0002b92e kernel_bind -0002b963 kernel_recvfrom -0002b969 kernel_recv -0002b9db kernel_recv_timeout -0002ba01 kernel_connect -0002bb05 kernel_sendto -0002bbbf kernel_accept -0002bc22 kernel_listen -0002bc4a kernel_send -0002bcd0 sys_kernel_bind -0002bd02 __add_systemcall_sys_kernel_bind -0002bd19 __add_systemcall_sys_kernel_accept -0002bd30 __add_systemcall_sys_kernel_connect -0002bd47 __add_systemcall_sys_kernel_listen -0002bd5e __add_systemcall_sys_kernel_recv -0002bd75 __add_systemcall_sys_kernel_recvfrom -0002bd8c __add_systemcall_sys_kernel_recv_timeout -0002bda3 __add_systemcall_sys_kernel_send -0002bdba __add_systemcall_sys_kernel_sendto -0002bdd1 __add_systemcall_sys_socket_create -0002bde8 __add_systemcall_sys_kernel_sock_close -0002bdff sys_kernel_accept -0002be3f sys_kernel_connect -0002be71 sys_kernel_listen -0002bea0 sys_kernel_recv -0002bed8 sys_kernel_recvfrom -0002bf18 sys_kernel_recv_timeout -0002bf56 sys_kernel_send -0002bf8e sys_kernel_sendto -0002bfce sys_socket_create -0002bff5 sys_kernel_sock_close -0002c036 __iface_send -0002c065 __iface_recieve -0002c094 __iface_assign -0002c0a7 __iface_detach -0002c0bb __iface_set_gateway -0002c0ce __iface_set_netmask -0002c0e1 __iface_configure -0002c131 __iface_attach -0002c156 net_interface_create -0002c18e net_register_netdev -0002c2a6 net_interface_destroy -0002c2bb __default_restart -0002c2c1 __default_stop -0002c326 __default_start -0002c3a0 nm_new -0002c429 nm_free -0002c46e net_firewall_create -0002c491 fs_file2fd -0002c4f8 fs_alloc_file -0002c543 fs_free_file -0002c59d fs_register -0002c66c fs_init -0002c672 fs_unregister -0002c6d5 fs_get -0002c6db fs_close -0002c74d fs_open -0002c7c7 fs_seek -0002c844 fs_read -0002c959 fs_load_from_file -0002c9e5 fs_write -0002caa0 fat16_rmdir -0002caa6 fat16_stat -0002caac fat16_close -0002cb16 fat16_rename -0002cbab fat16_mkdir -0002cc90 fat16_remove -0002cd03 fat16_open -0002ce4d fat16_read -0002cfb1 fat16_write -0002d0df fat16_list -0002d3ad fat16_init -0002d461 path_next_iter -0002d4d0 inode_from_path_recursise -0002d54e inode_from_path -0002d60c ext_get_root -0002d615 ext_get_current_dir -0002d624 ext_get_size -0002d62a ext_get_inodes -0002d630 ext_get_blocks -0002d636 ext_sync -0002d6a9 ext_create -0002d794 ext_read -0002d80f ext_seek -0002d856 ext_write -0002d8c2 ext_close -0002d924 ext_open_from_directory -0002da2a ext_open -0002dae1 ext_size -0002db0a change_directory -0002db70 ext_create_directory -0002dd0a ext_create_file_system -0002dfd7 init_ext -0002e173 listdir -0002e294 __inode_sync -0002e2f7 __inode_cache_insert -0002e3ed __inode_load -0002e461 inodes_sync -0002e49c inode_get -0002e4f9 inode_read -0002e6e1 inode_write -0002e93f alloc_inode -0002e9f8 mkdir -0002eaa5 sync -0002ead9 mkfs -0002eae6 fat16_read_data_from_cluster -0002eb34 fat16_read_data -0002ec15 fat16_find_cluster_by_offset -0002ec90 fat16_write_data_to_cluster_with_offset -0002eccb fat16_print_cluster_chain -0002ecf9 fat16_write_data_to_cluster -0002ed2c fat16_write_data -0002ee48 get_fat_start_block -0002ee50 get_root_directory_start_block -0002ee5f get_data_start_block -0002ee71 fat16_get_fat_entry -0002ee8c fat16_set_fat_entry -0002eecc fat16_sync_fat_table -0002ef44 fat16_allocate_cluster -0002ef5c fat16_free_cluster -0002ef71 fat16_get_free_cluster -0002efc6 fat16_sync_directory_entry -0002f048 fat16_read_entry -0002f0f5 fat16_find_entry -0002f230 fat16_rename_entry -0002f2a1 fat16_free_clusters -0002f2e8 fat16_delete_entry -0002f34f fat16_add_entry -0002f4b6 fat16_used_blocks -0002f4ef fat16_to_upper -0002f51b fat16_name_compare -0002f640 sstrtok -0002f701 fat16_directory_entry_debug -0002f7d1 fat16_get_directory_entry -0002f9c9 fat16_create_directory -0002face fat16_read_file -0002fb1f fat16_create_file -0002fb9d fat16_create_empty_file -0002fc5d fat16_directory_entries -0002fd43 fat16_mbr_clear -0002fdec fat16_mbr_add_entry -0002fedd fat16_print_root_directory_entries -0002fef5 fat16_change_directory -0002ff7d fat16_bootblock_info -000300fa fat16_set_time -0003012e fat16_set_date -00030166 fat16_load -000302e5 fat16_format -0003059a mbr_partition_type_string -0003061d mbr_partitions_parse -000306e6 mbr_get -000306ec mbr_partition_load -0003070a __ksymbol_snakegame -00030724 init_game -00030772 draw -000307ce get_input -000307ed update -00030974 game_loop -0003099a snakegame -000309e5 __msgbox -00030de5 msgbox_create -00030e18 msgbox_show -00030e60 _code_end From 80df26882b99e196b076376854e8afc932f4225b Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Fri, 9 Feb 2024 15:31:24 +0100 Subject: [PATCH 18/23] Bugfixes in VGA screen driver and mouse cursor. --- drivers/vga.c | 22 ++++++++++++++++----- include/screen.h | 9 ++++++++- kernel/kernel.c | 2 +- kernel/kthreads/shell.c | 2 +- kernel/kthreads/snake.c | 30 +++++++++++++++-------------- kernel/kthreads/taskbar.c | 2 +- kernel/kthreads/textmode.c | 39 +++++++++++++++++++++++++++++++++++--- kernel/syscalls.c | 2 +- kernel/terminal.c | 4 ++-- 9 files changed, 83 insertions(+), 29 deletions(-) diff --git a/drivers/vga.c b/drivers/vga.c index 2781955..044b7f3 100644 --- a/drivers/vga.c +++ b/drivers/vga.c @@ -23,10 +23,11 @@ #define MAX_FMT_STR_SIZE 50 +//uint16_t* const VGA_MEMORY = (uint16_t*) 0xa0000; uint16_t* const VGA_MEMORY = (uint16_t*) 0xB8000; +static volatile uint16_t* VGA_BUFFER = NULL; -volatile uint16_t* VGA_BUFFER = NULL; -//uint16_t* const VGA_MEMORY = (uint16_t*) 0xa0000; +static struct screen_cursor cursor = {0, 0}; static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) { @@ -41,6 +42,9 @@ static inline uint16_t vga_entry(unsigned char uc, uint8_t color) void scr_set_cursor(int x, int y) { + cursor.x = x; + cursor.y = y; + if($kernel->graphic_mode == KERNEL_FLAG_TEXTMODE){ uint16_t pos = y * SCREEN_WIDTH + x; outportb(0x3D4, 0x0F); @@ -51,6 +55,11 @@ void scr_set_cursor(int x, int y) } } +struct screen_cursor scr_get_cursor() +{ + return cursor; +} + void scrcolor_set(enum vga_color fg, enum vga_color bg) { scrcolor = vga_entry_color(fg, bg); @@ -242,19 +251,22 @@ void scr_keyboard_add(unsigned char c) kb_buffer_head = (kb_buffer_head + 1) % 256; } -unsigned char scr_keyboard_get() +unsigned char scr_keyboard_get(int wait) { if($kernel->graphic_mode == KERNEL_FLAG_TEXTMODE){ - return kb_get_char(1); + return kb_get_char(wait); } else { while(kb_buffer_tail == kb_buffer_head){ kernel_yield(); + + if(!wait){ + return 0; + } } unsigned char c = kb_buffer[kb_buffer_tail]; kb_buffer_tail = (kb_buffer_tail + 1) % 256; - dbgprintf("Got %c from buffer\n", c); return c; } } diff --git a/include/screen.h b/include/screen.h index e2150be..a25d591 100644 --- a/include/screen.h +++ b/include/screen.h @@ -28,6 +28,11 @@ enum vga_color { VGA_COLOR_WHITE = 15, }; +struct screen_cursor { + int x; + int y; +}; + void scrcolor_set(enum vga_color fg, enum vga_color bg); void scrput(int x, int y, unsigned char c, uint8_t color); void scrwrite(int x, int y, char* str, uint8_t color); @@ -39,6 +44,8 @@ uint16_t scrget(int x, int y); uint16_t* scr_buffer(); void scr_keyboard_add(unsigned char c); -unsigned char scr_keyboard_get(); +unsigned char scr_keyboard_get(int wait); + +struct screen_cursor scr_get_cursor(); #endif \ No newline at end of file diff --git a/kernel/kernel.c b/kernel/kernel.c index ab9af4b..c34ace6 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -246,7 +246,7 @@ void kernel(uint32_t magic) start("netd", 0, NULL); kernel_boot_printf("Deamons initialized."); - init_pit(100); + init_pit(1000); kernel_boot_printf("Timer initialized."); dbgprintf("Critical counter: %d\n", __cli_cnt); diff --git a/kernel/kthreads/shell.c b/kernel/kthreads/shell.c index 42c1a21..18c70a1 100644 --- a/kernel/kthreads/shell.c +++ b/kernel/kthreads/shell.c @@ -757,7 +757,7 @@ static void __kthread_entry textshell() twritef("Type 'help' for a list of commands\n"); term->ops->commit(term); while (1){ - c = scr_keyboard_get(); + c = scr_keyboard_get(1); if(c == 0) continue; if(c == '\b'){ diff --git a/kernel/kthreads/snake.c b/kernel/kthreads/snake.c index e0aa6fc..36f4b8e 100644 --- a/kernel/kthreads/snake.c +++ b/kernel/kthreads/snake.c @@ -31,6 +31,7 @@ struct point { struct point snake[SNAKE_LENGTH]; int length = 5; +int speed = 100; struct point fruit; int direction = ARROW_RIGHT; @@ -42,27 +43,32 @@ void init_game() { fruit.x = 20; fruit.y = 15; + + speed = 100; } void draw() { scr_clear(); - - for (int i = 0; i < length; i++) { - scrput(snake[i].x, snake[i].y, 'O', 0x0A); + + for (int i = 1; i < length; i++) { + scrput(snake[i].x, snake[i].y, 'a', 0x0A); } + scrput(snake[0].x, snake[0].y, '@', 0x0A); scrput(fruit.x, fruit.y, 'F', 0x0C); } int get_input() { - return $process->current->term->ops->getchar($process->current->term); + return scr_keyboard_get(0); } int update() { int input = get_input(); - if(input == CTRLC) return -1; - - if (input != 255) { + if(input == CTRLC){ + dbgprintf("Exiting game\n"); + return -1; + } + if (input != 255 && input != 0) { direction = input; } @@ -79,11 +85,13 @@ int update() { length++; fruit.x = rand() % SCREEN_WIDTH; fruit.y = rand() % SCREEN_HEIGHT; + speed -= 2; } /* Collision with walls */ if (snake[0].x < 0 || snake[0].x >= SCREEN_WIDTH || snake[0].y < 0 || snake[0].y >= SCREEN_HEIGHT) { + dbgprintf("Collision with wall at %d, %d\n", snake[0].x, snake[0].y); return -1; } @@ -102,17 +110,11 @@ void game_loop() { draw(); if(update() == -1) return; - kernel_sleep(100); + kernel_sleep(speed); } } static int snakegame() { - struct kernel_context* ctx = kernel_get_context(); - if(ctx->graphic_mode == KERNEL_FLAG_GRAPHICS) { - twritef("This game is not compatible with graphics mode\n"); - return 0; - } - init_game(); game_loop(); return 0; diff --git a/kernel/kthreads/taskbar.c b/kernel/kthreads/taskbar.c index 8a0f04a..0d8accc 100644 --- a/kernel/kthreads/taskbar.c +++ b/kernel/kthreads/taskbar.c @@ -298,7 +298,7 @@ static void __kthread_entry taskbar(void) return; } - w->ops->move(w, 0, 0); + w->ops->move(w, 0, 20); w->draw->rect(w, 0, TASKBAR_HEIGHT+1, vbe_info->width, 1, COLOR_VGA_DARK_GRAY); w->draw->rect(w, 0, 0, vbe_info->width, 2, 0xf); diff --git a/kernel/kthreads/textmode.c b/kernel/kthreads/textmode.c index 376f2ff..629f95e 100644 --- a/kernel/kthreads/textmode.c +++ b/kernel/kthreads/textmode.c @@ -30,6 +30,25 @@ /* Macro to extract the background color from a VGA entry */ #define VGA_ENTRY_BG_COLOR(vga_entry) (((vga_entry) >> 12) & 0x0F) +static int screen_draw_cursor(struct window *w, int x, int y, color_t fg) { + int char_height = 8; /* Height of the character */ + int total_height = 12; /* Total height of the drawing area */ + int offset = (total_height - char_height) / 2; /* Offset to center the character */ + + for (int l = 0; l < total_height; l++) { + for (int i = 0; i < 8; i++) { + /* Check if the current pixel is within the vertical range of the character */ + if (l >= offset && l < offset + char_height) { + /* Character drawing logic */ + if(font8x8_basic['_'][l - offset] & (1 << i)){ + putpixel(w->inner, x + i, y + l, fg, w->pitch); + } + } + } + } + return 0; +} + static int screen_draw_char(struct window *w, int x, int y, unsigned char c, color_t fg, color_t bg) { int char_height = 8; /* Height of the character */ int total_height = 12; /* Total height of the drawing area */ @@ -49,7 +68,13 @@ static int screen_draw_char(struct window *w, int x, int y, unsigned char c, col } else { /* Draw the background for areas above and below the character */ putpixel(w->inner, x + i, y + l, bg, w->pitch); - } + /* if the character is a box character draw its upper row and lower row */ + if (c > 179 && c < 218) { + if (font8x8_box[c][0] & (1 << i)) { + putpixel(w->inner, x + i, y + l, fg, w->pitch); + } + } + } } } return 0; @@ -57,6 +82,7 @@ static int screen_draw_char(struct window *w, int x, int y, unsigned char c, col static int screeny(int argc, char *argv[]) { volatile uint16_t* buffer = scr_buffer(); + struct screen_cursor cursor = scr_get_cursor(); /* Create a cache for the screen */ uint16_t* cache = (uint16_t*)kalloc(MAX_ROWS * MAX_COLS * sizeof(uint16_t)); @@ -74,10 +100,12 @@ static int screeny(int argc, char *argv[]) { start("textshell", 0, NULL); while (1) { + cursor = scr_get_cursor(); + for (int k = 0; k < MAX_ROWS; k++) { for (int j = 0; j < MAX_COLS; j++) { uint16_t entry = buffer[k * MAX_COLS + j]; - if (entry == cache[k * MAX_COLS + j]) { + if (entry == cache[k * MAX_COLS + j] && k != cursor.y && j != cursor.x) { continue; } @@ -87,9 +115,12 @@ static int screeny(int argc, char *argv[]) { screen_draw_char(w, j * 8, k * 12, c, fg, bg); + screen_draw_cursor(w, cursor.x * 8, cursor.y * 12, 0x0f); + cache[k * MAX_COLS + j] = entry; } } + gfx_commit(); kernel_yield(); @@ -100,8 +131,10 @@ static int screeny(int argc, char *argv[]) { continue; switch (event.event) { - case GFX_EVENT_EXIT: + case GFX_EVENT_EXIT:{ + kfree(cache); return -1; + } case GFX_EVENT_KEYBOARD: scr_keyboard_add(event.data); break; diff --git a/kernel/syscalls.c b/kernel/syscalls.c index b34c50c..49dc00a 100644 --- a/kernel/syscalls.c +++ b/kernel/syscalls.c @@ -54,7 +54,7 @@ EXPORT_SYSCALL(SYSCALL_SCREEN_PUT, sys_screen_put); char sys_screen_get() { - return scr_keyboard_get(); + return scr_keyboard_get(1); } EXPORT_SYSCALL(SYSCALL_SCREEN_GET, sys_screen_get); diff --git a/kernel/terminal.c b/kernel/terminal.c index e3f022d..d8bf1dc 100644 --- a/kernel/terminal.c +++ b/kernel/terminal.c @@ -258,7 +258,7 @@ static int __terminal_getchar_textmode(struct terminal* term) { if(term == NULL) return -1; - ubyte_t c = scr_keyboard_get(); + ubyte_t c = scr_keyboard_get(1); if(c == 0) return -1; return c; @@ -272,7 +272,7 @@ static int __terminal_scan_textmode(struct terminal* term, ubyte_t* data, int si int i = 0; ubyte_t c = 0; while (i < size && c != '\n'){ - c = scr_keyboard_get(); + c = scr_keyboard_get(1); if(c == 0) continue; if(c == CTRLC){ From 52312410bfd22017becf77f41cb26c362b577bde Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Fri, 9 Feb 2024 15:39:18 +0100 Subject: [PATCH 19/23] snakegame hotfix --- kernel/kthreads/snake.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/kthreads/snake.c b/kernel/kthreads/snake.c index 36f4b8e..2b805a2 100644 --- a/kernel/kthreads/snake.c +++ b/kernel/kthreads/snake.c @@ -68,7 +68,7 @@ int update() { dbgprintf("Exiting game\n"); return -1; } - if (input != 255 && input != 0) { + if (input == ARROW_UP || input == ARROW_DOWN || input == ARROW_LEFT || input == ARROW_RIGHT) { direction = input; } @@ -83,8 +83,8 @@ int update() { if (snake[0].x == fruit.x && snake[0].y == fruit.y) { length++; - fruit.x = rand() % SCREEN_WIDTH; - fruit.y = rand() % SCREEN_HEIGHT; + fruit.x = 2+ (rand() % (SCREEN_WIDTH-4)); + fruit.y = 2+ (rand() % (SCREEN_HEIGHT-4)); speed -= 2; } From 03c4e25aaef02bd010b1fea3ae5b78e7482ed097 Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Sat, 10 Feb 2024 22:07:03 +0100 Subject: [PATCH 20/23] small bugfixes --- kernel/kthreads/shell.c | 3 +-- kernel/kthreads/snake.c | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/kernel/kthreads/shell.c b/kernel/kthreads/shell.c index 18c70a1..45dce63 100644 --- a/kernel/kthreads/shell.c +++ b/kernel/kthreads/shell.c @@ -738,8 +738,6 @@ static void __kthread_entry textshell() return; } - scrwrite(0, 0, " RetrOS 32 - Textmode ", VGA_COLOR_BLUE | VGA_COLOR_LIGHT_GREY << 4); - struct mem_info minfo; get_mem_info(&minfo); @@ -757,6 +755,7 @@ static void __kthread_entry textshell() twritef("Type 'help' for a list of commands\n"); term->ops->commit(term); while (1){ + scrwrite(0, 0, " RetrOS 32 - Textmode ", VGA_COLOR_BLUE | VGA_COLOR_LIGHT_GREY << 4); c = scr_keyboard_get(1); if(c == 0) continue; diff --git a/kernel/kthreads/snake.c b/kernel/kthreads/snake.c index 2b805a2..5764793 100644 --- a/kernel/kthreads/snake.c +++ b/kernel/kthreads/snake.c @@ -49,13 +49,22 @@ void init_game() { void draw() { scr_clear(); + + for(int i = 0; i < SCREEN_WIDTH; i++) { + scrput(i, 0, ' ', VGA_COLOR_BLUE | VGA_COLOR_LIGHT_GREY << 4 ); + scrput(i, SCREEN_HEIGHT-1, ' ', VGA_COLOR_BLUE | VGA_COLOR_LIGHT_GREY << 4); + } + + scrwrite(10, 0, "Snake Game - Use arrow keys to move", VGA_COLOR_BLUE | VGA_COLOR_LIGHT_GREY << 4);; for (int i = 1; i < length; i++) { - scrput(snake[i].x, snake[i].y, 'a', 0x0A); + scrput(snake[i].x, snake[i].y, 'a', VGA_COLOR_WHITE | VGA_COLOR_BLUE << 4); } - scrput(snake[0].x, snake[0].y, '@', 0x0A); + scrput(snake[0].x, snake[0].y, '@', VGA_COLOR_WHITE | VGA_COLOR_BLUE << 4); + + scrput(fruit.x, fruit.y, 'F', VGA_COLOR_WHITE | VGA_COLOR_BLUE << 4); - scrput(fruit.x, fruit.y, 'F', 0x0C); + scrprintf(0, SCREEN_HEIGHT-2, "Score: %d", length-5); } int get_input() { @@ -90,7 +99,7 @@ int update() { /* Collision with walls */ if (snake[0].x < 0 || snake[0].x >= SCREEN_WIDTH || - snake[0].y < 0 || snake[0].y >= SCREEN_HEIGHT) { + snake[0].y < 1 || snake[0].y >= SCREEN_HEIGHT-1) { dbgprintf("Collision with wall at %d, %d\n", snake[0].x, snake[0].y); return -1; } From 709be578b3a6853cc75f0c1a4121c752a2d4769d Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Sun, 11 Feb 2024 19:07:51 +0100 Subject: [PATCH 21/23] bug fixes and texed saving --- apps/texed/texed.c | 31 ++++++++++++++++++++++++++----- kernel/kthreads/taskbar.c | 2 +- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/apps/texed/texed.c b/apps/texed/texed.c index 0f3f00a..2842078 100644 --- a/apps/texed/texed.c +++ b/apps/texed/texed.c @@ -151,9 +151,9 @@ static int textbuffer_free_line(struct textbuffer *buffer, size_t line) { return 0; } +#define HAS_FLAG(flags, flag) (flags & flag) static int textbuffer_save_file(struct textbuffer *buffer, const char *filename) { - return -1; char* file = malloc(2048); if (file == NULL) { return -1; @@ -169,9 +169,26 @@ static int textbuffer_save_file(struct textbuffer *buffer, const char *filename) len++; } - len += buffer->lines[i]->length; + len += buffer->lines[i]->length; } } + + int fd = open(buffer->filename, FS_FILE_FLAG_CREATE | FS_FILE_FLAG_READ | FS_FILE_FLAG_WRITE); + if (fd < 0) { + free(file); + return -1; + } + + int ret = write(fd, file, len); + if (ret < 0) { + fclose(fd); + free(file); + return -1; + } + + fclose(fd); + free(file); + return 0; } @@ -181,7 +198,7 @@ static int textbuffer_load_file(struct textbuffer *buffer, const char *filename) return -1; } - int fd = open(filename, FS_FILE_FLAG_CREATE | FS_FILE_FLAG_READ | FS_FILE_FLAG_WRITE); + int fd = open(filename, FS_FILE_FLAG_READ | FS_FILE_FLAG_WRITE); if (fd < 0) { return -1; } @@ -238,6 +255,9 @@ static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg screen_put_char(4, 1, 'R', COLOR(VGA_COLOR_GREEN, VGA_COLOR_BLUE)); screen_put_char(5, 1, ']', COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + /* draw filename */ + screen_printf(6, 1, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE), " %s", buffer->filename); + /* write from start to end, or line_count */ for (size_t i = 0; i + y_start < buffer->line_count && i < buffer->scroll.end; i++) { /* Calculate the position for each line */ @@ -257,7 +277,7 @@ static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg } } - screen_set_cursor(buffer->cursor.x, 2+buffer->cursor.y - buffer->scroll.start); + screen_set_cursor(buffer->cursor.x+1, 2+buffer->cursor.y - buffer->scroll.start); /* fill bottom row with light grey */ for (size_t i = 0; i < 80; i++) { @@ -419,7 +439,7 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { } break; } - screen_set_cursor(buffer->cursor.x, 1+buffer->cursor.y); + //screen_set_cursor(buffer->cursor.x, 1+buffer->cursor.y); } else { /* If the buffer is full, do nothing */ if (buffer->lines[buffer->cursor.y]->length == buffer->lines[buffer->cursor.y]->capacity) { @@ -458,6 +478,7 @@ int main(int argc, char *argv[]) { screen_draw_box(0, 1, 80, 23, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); if(argc > 1) { textbuffer_load_file(buffer, argv[1]); + strcpy(buffer->filename, argv[1]); } textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); diff --git a/kernel/kthreads/taskbar.c b/kernel/kthreads/taskbar.c index 0d8accc..8a0f04a 100644 --- a/kernel/kthreads/taskbar.c +++ b/kernel/kthreads/taskbar.c @@ -298,7 +298,7 @@ static void __kthread_entry taskbar(void) return; } - w->ops->move(w, 0, 20); + w->ops->move(w, 0, 0); w->draw->rect(w, 0, TASKBAR_HEIGHT+1, vbe_info->width, 1, COLOR_VGA_DARK_GRAY); w->draw->rect(w, 0, 0, vbe_info->width, 2, 0xf); From 9dfef422e6bf6e2ef17f3f50146580a214db6fa1 Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Tue, 13 Feb 2024 15:42:37 +0100 Subject: [PATCH 22/23] textmode editor Ncurses version. --- Makefile | 8 +- apps/texed/Makefile.bak | 34 +++++ apps/texed/cmd.c | 90 +++++++++++ apps/texed/helpers.c | 75 +++++++++ apps/texed/include/screen.h | 42 ++++-- apps/texed/include/textbuffer.h | 17 ++- apps/texed/screen.c | 110 ++++++++++++-- apps/texed/search.c | 54 ++----- apps/texed/{texed.c => textbuffer.c} | 217 ++++++++++++++++++++++++--- developer/interpreter.c | 2 + include/libc.h | 1 + kernel/vmem.c | 4 +- lib/libc.c | 21 +++ 13 files changed, 575 insertions(+), 100 deletions(-) create mode 100644 apps/texed/Makefile.bak create mode 100644 apps/texed/cmd.c create mode 100644 apps/texed/helpers.c rename apps/texed/{texed.c => textbuffer.c} (70%) diff --git a/Makefile b/Makefile index 3674efc..64ebc0f 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ ASFLAGS= LDFLAGS= MAKEFLAGS += --no-print-directory -QEMU_OPS = -device e1000,netdev=net0 -serial stdio -netdev user,id=net0,hostfwd=tcp::8080-:8080 -object filter-dump,id=net0,netdev=net0,file=dump.dat -m 32m +QEMU_OPS = -display sdl -device e1000,netdev=net0 -serial stdio -netdev user,id=net0,hostfwd=tcp::8080-:8080 -object filter-dump,id=net0,netdev=net0,file=dump.dat -m 32m # ---------------- For counting how many files to compile ---------------- ifneq ($(words $(MAKECMDGOALS)),1) @@ -88,7 +88,7 @@ multiboot_kernel: bin/multiboot.o $(KERNELOBJ) symbols: bin/multiboot.o $(KERNELOBJ) @echo "[KERNEL] Creating symbols..." @$(LD) -o bin/symbols $^ $(LDFLAGS) -T ./kernel/linkersym.ld - @nm -C -n bin/symbols | grep ' [Tt] ' | sed 's/ [Tt] / /' > rootfs/symbols.map + @nm -C -n bin/symbols | grep ' [Tt] ' | sed 's/ [Tt] / /' > rootfs/sysutil/symbols.map kernel: bin/kcrt0.o $(KERNELOBJ) @@ -106,7 +106,7 @@ bin/%.o: */%.c @$(ECHO) [KERNEL] Compiling $< @$(CC) -o $@ -c $< $(CCFLAGS) -bin/%.o: */*/%.c +bin/%.o: kernel/*/%.c @$(ECHO) [PROGRAM] Compiling $< @$(CC) -o $@ -c $< $(CCFLAGS) @@ -159,7 +159,7 @@ create_fs: bare: compile create_fs -img: grub_fix tools compile symbols tests create_fs sync +img: grub_fix tools compile symbols create_fs sync @echo "Finished creating the image." $(TIME-END) diff --git a/apps/texed/Makefile.bak b/apps/texed/Makefile.bak new file mode 100644 index 0000000..40c7504 --- /dev/null +++ b/apps/texed/Makefile.bak @@ -0,0 +1,34 @@ +### Standard Unix Environment Makefile ### +# This makefile is adapted to compile with ncurses +# in a standard Unix-like environment. +############################################## +CC=gcc +CPP=g++ +AS=as +LD=ld +UNAME := $(shell uname) +ifeq ($(UNAME),Linux) + CCFLAGS=-O2 -Wall -Wextra -Wpedantic -Iinclude/ -Iapps/ + LDFLAGS=-lncurses +else + # For macOS, adjust as needed (e.g., clang, ncurses path) + CCFLAGS=-O2 -Iinclude/ -I/usr/local/opt/ncurses/include -DNCURSES + LDFLAGS=-L/usr/local/opt/ncurses/lib -lncurses +endif + +#### ONLY EDIT THIS #### +OUTPUT = texed +SRC_FILES = $(wildcard *.c) +OBJ_FILES = $(SRC_FILES:%.c=%.o) +######################## + +all: $(OUTPUT) + +$(OUTPUT): $(OBJ_FILES) + $(CC) -o $@ $^ $(LDFLAGS) + +%.o: %.c + $(CC) $(CCFLAGS) -c $< -o $@ + +clean: + rm -f *.o $(OUTPUT) diff --git a/apps/texed/cmd.c b/apps/texed/cmd.c new file mode 100644 index 0000000..c0e5879 --- /dev/null +++ b/apps/texed/cmd.c @@ -0,0 +1,90 @@ + +#ifndef NCURSES +#include +#include +#else +#include +#include +#include +#include +#include +#endif // !NCURSES + +#include "include/screen.h" +#include "include/textbuffer.h" + +#define MAX_CMD 100 + +static int textbuffer_replace(struct textbuffer *buffer, char *search, char *replace) { + for (size_t i = 0; i < buffer->line_count; i++) { + int index; + while ((index = strstr(buffer->lines[i]->text, search)) >= 0) { + size_t replace_len = strlen(replace); + size_t search_len = strlen(search); + size_t new_length = buffer->lines[i]->length - search_len + replace_len; + + if (new_length > buffer->lines[i]->capacity) { + return -1; + } + + memmove(buffer->lines[i]->text + index + replace_len, + buffer->lines[i]->text + index + search_len, + buffer->lines[i]->length - index - search_len); + memcpy(buffer->lines[i]->text + index, replace, replace_len); + + buffer->lines[i]->length = new_length; + } + } + return 0; +} + +static int textbuffer_parse_replace(struct textbuffer *buffer, char *command) { + char search[MAX_CMD]; + char replace[MAX_CMD]; + int i = 0; + int j = 0; + int k = 0; + while(command[i] != ' ') { + i++; + } + i++; + while (command[i] != ' ') { + search[j] = command[i]; + i++; + j++; + } + search[j] = '\0'; + i++; + while (command[i] != '\0') { + replace[k] = command[i]; + i++; + k++; + } + replace[k] = '\0'; + + textbuffer_replace(buffer, search, replace); +} + +static int textbuffer_command(struct textbuffer* buffer, char* command) { + if (strcmp(command, "search") == 0) { + textbuffer_search_main(buffer); + } + + if (strcmp(command, "exit") == 0) { + return -117; + + } + + // replace word with word without strtok + if (strncmp(command, "replace", 7) == 0) { + textbuffer_parse_replace(buffer, command); + } + + return 0; +} + + +int textbuffer_command_main(struct textbuffer* buffer) { + textbuffer_get_input(buffer, 'C', "Command: ", textbuffer_command); + return 0; +} \ No newline at end of file diff --git a/apps/texed/helpers.c b/apps/texed/helpers.c new file mode 100644 index 0000000..75bd85f --- /dev/null +++ b/apps/texed/helpers.c @@ -0,0 +1,75 @@ +#ifndef NCURSES +#include +#include +#else +#include +#include +#include +#include +#include +#endif // !NCURSES + +#include "include/screen.h" +#include "include/textbuffer.h" + +#define MAX_INPUT 100 + +int textbuffer_get_input(struct textbuffer* buffer, char tag, char* message, int (*callback)(struct textbuffer*, char*)) +{ + char input[MAX_INPUT]; + int input_len = 0; + + int box_width = 50; + int box_height = 15; + int screen_width = 80; + int screen_height = 23; + + int start_x = (screen_width - box_width) / 2; + int start_y = (screen_height - box_height) / 2; + + for (int x = start_x; x < start_x + box_width; x++) { + for (int y = start_y; y < start_y + box_height; y++) { + screen_put_char(x, y, ' ', COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + } + } + + screen_draw_box(start_x, start_y, box_width, box_height, COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + + + screen_put_char(start_x+3, start_y, '[', COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + screen_put_char(start_x+4, start_y, tag, COLOR(VGA_COLOR_GREEN, VGA_COLOR_LIGHT_GREY)); + screen_put_char(start_x+5, start_y, ']', COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + + screen_write(start_x+3, start_y+1, message, COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + screen_write(start_x+3, start_y+2, " ", COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + + screen_write(start_x+3, start_y+4, "Press [Enter] to input", COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); + + while(1) { + screen_set_cursor(start_x+3 + input_len, start_y+2); + screen_write(start_x+3, start_y+2, input, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + int c = screen_get_char(); + if (c == 0) + continue; + if (c == CTRLC) + break; + if (c == BACKSPACE){ + if (input_len > 0){ + input_len--; + input[input_len] = 0; + } + continue; + } + if (c == ENTER){ + return callback(buffer, input); + } + + if(input_len >= MAX_INPUT) { + continue; + } + + input[input_len] = c; + input_len++; + } + return -1; +} diff --git a/apps/texed/include/screen.h b/apps/texed/include/screen.h index d6e3cc4..821cd51 100644 --- a/apps/texed/include/screen.h +++ b/apps/texed/include/screen.h @@ -1,25 +1,44 @@ #ifndef __TEXED_SCREEN_H__ #define __TEXED_SCREEN_H__ +#ifndef NCURSES #include +#else +#include +#include +#include +#include +#include +#endif // !NCURSES + #define SCREEN_WIDTH 80 #define SCREEN_HEIGHT 25 + +#ifdef NCURSES +#define ARROW_UP KEY_UP +#define ARROW_DOWN KEY_DOWN +#define ARROW_LEFT KEY_LEFT +#define ARROW_RIGHT KEY_RIGHT + +#define BACKSPACE 127 +#define ENTER '\n' + +#define CTRLC 3 // ASCII for Ctrl+C +#define CTRLE 5 // ASCII for Ctrl+E +#define CTRLS 19 // ASCII for Ctrl+S +#define CTRLF 6 // ASCII for Ctrl+F + +#else + #define ARROW_UP 254 #define ARROW_DOWN 253 #define ARROW_LEFT 252 #define ARROW_RIGHT 251 -#define F1 250 -#define F2 249 /* CTRL y */ -#define F3 248 -#define F4 247 /* CTRL w */ -#define F5 246 -#define F6 245 -#define F7 244 /* CTRL t */ -#define F8 243 -#define F9 242 /* CTRL r */ -#define F10 241 /* CTRL q */ + +#define BACKSPACE '\b' +#define ENTER '\n' #define TAB 9 @@ -28,6 +47,7 @@ #define CTRLS 243 #define CTRLF 230 +#endif #define COLOR(fg, bg) (fg | bg << 4) @@ -53,7 +73,7 @@ enum vga_color { int screen_put_char(int x, int y, unsigned char c, unsigned char color); int screen_write(int x, int y, const char* str, unsigned char color); int screen_printf(int x, int y, unsigned char color, char* fmt, ...); -char screen_get_char(); +int screen_get_char(); int screen_clear(int from , int to, unsigned char color); void screen_draw_box(int x, int y, int width, int height, char border_color); int screen_clear_line(int y, unsigned char color); diff --git a/apps/texed/include/textbuffer.h b/apps/texed/include/textbuffer.h index cb0a22d..6505701 100644 --- a/apps/texed/include/textbuffer.h +++ b/apps/texed/include/textbuffer.h @@ -1,9 +1,10 @@ #ifndef __TEXTBUFFER_H #define __TEXTBUFFER_H -#include #include +#include "screen.h" + typedef enum __line_flags { LINE_FLAG_NONE = 1 << 0, LINE_FLAG_DIRTY = 1 << 1, @@ -32,9 +33,23 @@ struct textbuffer { size_t end; } scroll; size_t line_count; + /* Define a structure for keyword-color pairs */ + struct syntax_highlight { + struct keyword { + char keyword[32]; + char color; + } keywords[32]; + int count; + } *syntax; + char filename[256]; }; +/* helpers */ +int textbuffer_get_input(struct textbuffer* buffer, char tag, char* message, int (*callback)(struct textbuffer*, char*)); + +/* mains */ int textbuffer_search_main(struct textbuffer* buffer); +int textbuffer_command_main(struct textbuffer* buffer); #endif // !__TEXTBUFFER_H \ No newline at end of file diff --git a/apps/texed/screen.c b/apps/texed/screen.c index 5c67809..f50fc7a 100644 --- a/apps/texed/screen.c +++ b/apps/texed/screen.c @@ -1,24 +1,112 @@ -#include -#include -#include -#include - #include "../include/screen.h" #define MAX_FMT_STR_SIZE 256 -/* Macro to serialize a character and a color into a short */ /* Only platform depedent syscall needed */ +#ifndef NCURSES + +#include +#include +#include +#include + int screen_put_char(int x, int y, unsigned char c, unsigned char color) { return invoke_syscall(SYSCALL_SCREEN_PUT, x, y, (((unsigned short)(c) << 8) | (unsigned char)(color))); } +int screen_get_char(){return invoke_syscall(SYSCALL_SCREEN_GET, 0, 0, 0);} +int screen_set_cursor(int x, int y){return invoke_syscall(SYSCALL_SET_CURSOR, x, y, 0);} +#else + +#include +#include +#include +#include +#include + +int screen_put_char(int x, int y, unsigned char c, unsigned char color) { + int fg = color & 0x0F; // Extract the foreground color + int bg = (color & 0xF0) >> 4; // Extract the background color + + // Initialize color pair (if not already done) + // Assuming COLOR_PAIRS is large enough + int color_pair = bg * 8 + fg + 1; // Calculate a unique pair number + init_pair(color_pair, fg, bg); + + // Move to the specified location and add the character + attron(COLOR_PAIR(color_pair)); + mvaddch(y, x, c); + attroff(COLOR_PAIR(color_pair)); + + refresh(); // Refresh the screen to show changes + return 0; // Success +} + +int screen_get_char() { + // Get the character at the current cursor position + int c = getch(); + printf("%c\n", c); + return c; +} + +int screen_set_cursor(int x, int y) { + // Move the cursor to the specified location + move(x, y); + return 0; // Success +} -char screen_get_char() +inline void reverse(char s[]) { - return invoke_syscall(SYSCALL_SCREEN_GET, 0, 0, 0); + int c, i, j; + + for (i = 0, j = strlen(s)-1; i < j; i++, j--) + { + c = s[i]; + s[i] = s[j]; + s[j] = c; + } +} + +inline int itoa(int n, char s[]) +{ + int i, sign; + + if ((sign = n) < 0) + n = -n; + i = 0; + do { + s[i++] = n % 10 + '0'; + } while ((n /= 10) > 0); + + if(sign < 0) + s[i++] = '-'; + + s[i] = '\0'; + reverse(s); + + return i; } +inline int itohex(uint32_t n, char s[]) +{ + uint32_t i, d; + + i = 0; + do { + d = n % 16; + if (d < 10) + s[i++] = d + '0'; + else + s[i++] = d - 10 + 'a'; + } while ((n /= 16) > 0); + s[i] = 0; + reverse(s); + + return i; +} + +#endif + int screen_write(int x, int y, const char* str, unsigned char color) { int i = 0; @@ -45,12 +133,6 @@ int screen_clear(int from , int to, unsigned char color) } } -int screen_set_cursor(int x, int y) -{ - return invoke_syscall(SYSCALL_SET_CURSOR, x, y, 0); -} - - void screen_draw_box(int x, int y, int width, int height, char border_color) { /* Extended ASCII characters for double line box drawing */ unsigned char top_left = 201; /* '╔' */ diff --git a/apps/texed/search.c b/apps/texed/search.c index c0123db..2eebad4 100644 --- a/apps/texed/search.c +++ b/apps/texed/search.c @@ -1,5 +1,13 @@ +#ifndef NCURSES #include #include +#else +#include +#include +#include +#include +#include +#endif // !NCURSES #include "include/screen.h" #include "include/textbuffer.h" @@ -20,50 +28,8 @@ static int textbuffer_search(struct textbuffer* buffer, char* search) { return -1; } -static int textbuffer_search_box(struct textbuffer* buffer) { - - char search[MAX_SEARCH] = {0}; - int search_len = 0; - - for(int x = 10; x < 60; x++) - for(int y = 5; y < 20; y++) - screen_put_char(x, y, ' ', COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); - - screen_draw_box(10, 5, 50, 15, COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); - - screen_put_char(13, 5, '[', COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); - screen_put_char(14, 5, 'S', COLOR(VGA_COLOR_GREEN, VGA_COLOR_LIGHT_GREY)); - screen_put_char(15, 5, ']', COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); - - screen_write(13, 6, "Search: ", COLOR(VGA_COLOR_WHITE, VGA_COLOR_LIGHT_GREY)); - screen_write(13, 7, " ", COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); - - while(1) { - screen_set_cursor(13 + search_len, 7); - screen_write(13, 7, search, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); - unsigned char c = screen_get_char(); - if (c == 0) - continue; - if (c == CTRLC) - break; - if (c == '\b'){ - if (search_len > 0){ - search_len--; - search[search_len] = 0; - } - continue; - } - if (c == '\n'){ - return textbuffer_search(buffer, search); - } - - search[search_len] = c; - search_len++; - } - return -1; -} - int textbuffer_search_main(struct textbuffer* buffer) { - textbuffer_search_box(buffer); + textbuffer_get_input(buffer, 'S', "Search: ", textbuffer_search); + return 0; } \ No newline at end of file diff --git a/apps/texed/texed.c b/apps/texed/textbuffer.c similarity index 70% rename from apps/texed/texed.c rename to apps/texed/textbuffer.c index 2842078..7f6f2d8 100644 --- a/apps/texed/texed.c +++ b/apps/texed/textbuffer.c @@ -8,13 +8,33 @@ * @copyright Copyright (c) 2024 * */ - +#ifndef NCURSES #include #include #include #include #include #include +#else + +#include +#include +#include +#include +#include +#include + +#include // For open +#include // For close +#include +#include + +inline int isspace(char c) +{ + return c == ' '; +} +#endif // !NCURSES + #include "include/screen.h" #include "include/textbuffer.h" @@ -28,7 +48,7 @@ static int textbuffer_new_line(struct textbuffer *buffer); static int textbuffer_free_line(struct textbuffer *buffer, size_t line); static int textbuffer_destroy(struct textbuffer *buffer); static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg); -static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c); +static int textbuffer_handle_char(struct textbuffer *buffer, int c); static int textbuffer_jump(struct textbuffer *buffer, unsigned int x, unsigned int y); static struct textbuffer_ops textbuffer_default_ops = { @@ -58,6 +78,32 @@ static struct textbuffer *textbuffer_create(void) { return NULL; } + buffer->syntax = malloc(sizeof(struct syntax_highlight)); + if (buffer->syntax == NULL) { + free(buffer->lines); + free(buffer); + return NULL; + } + + /* Set default syntax highlighting */ + buffer->syntax->count = 10; + strcpy(buffer->syntax->keywords[0].keyword, (const char*)"int"); + buffer->syntax->keywords[0].color = VGA_COLOR_LIGHT_GREEN; + strcpy(buffer->syntax->keywords[1].keyword, (const char*)"char"); + buffer->syntax->keywords[1].color = VGA_COLOR_LIGHT_GREEN; + strcpy(buffer->syntax->keywords[2].keyword, (const char*)"void"); + buffer->syntax->keywords[2].color = VGA_COLOR_LIGHT_GREEN; + strcpy(buffer->syntax->keywords[3].keyword, (const char*)"if"); + buffer->syntax->keywords[3].color = VGA_COLOR_LIGHT_BROWN; + strcpy(buffer->syntax->keywords[4].keyword, (const char*)"else"); + buffer->syntax->keywords[4].color = VGA_COLOR_LIGHT_BROWN; + strcpy(buffer->syntax->keywords[5].keyword, (const char*)"while"); + buffer->syntax->keywords[5].color = VGA_COLOR_LIGHT_BROWN; + strcpy(buffer->syntax->keywords[6].keyword, (const char*)"for"); + buffer->syntax->keywords[6].color = VGA_COLOR_LIGHT_BROWN; + strcpy(buffer->syntax->keywords[7].keyword, (const char*)"return"); + buffer->syntax->keywords[7].color = VGA_COLOR_LIGHT_RED; + buffer->ops = &textbuffer_default_ops; buffer->cursor.x = 0; buffer->cursor.y = 0; @@ -113,6 +159,7 @@ static int textbuffer_new_line(struct textbuffer *buffer) { memset(buffer->lines[buffer->line_count]->text, 0, LINE_CAPACITY); + buffer->lines[buffer->line_count]->flags = 0; buffer->lines[buffer->line_count]->length = 0; buffer->lines[buffer->line_count]->capacity = LINE_CAPACITY; buffer->line_count++; @@ -165,15 +212,19 @@ static int textbuffer_save_file(struct textbuffer *buffer, const char *filename) memcpy(file + len, buffer->lines[i]->text, buffer->lines[i]->length); /* Add newline if not extension */ if (!HAS_FLAG(buffer->lines[i]->flags, LINE_FLAG_EXTENSION)) { - file[len + buffer->lines[i]->length] = '\n'; + file[len + buffer->lines[i]->length] = ENTER; len++; } len += buffer->lines[i]->length; } } - + +#ifndef NCURSES int fd = open(buffer->filename, FS_FILE_FLAG_CREATE | FS_FILE_FLAG_READ | FS_FILE_FLAG_WRITE); +#else + int fd = open(buffer->filename, O_WRONLY | O_CREAT, 0644); +#endif // !NCURSES if (fd < 0) { free(file); return -1; @@ -198,18 +249,26 @@ static int textbuffer_load_file(struct textbuffer *buffer, const char *filename) return -1; } +#ifndef NCURSES int fd = open(filename, FS_FILE_FLAG_READ | FS_FILE_FLAG_WRITE); +#else + int fd = open(filename, O_RDONLY); +#endif // !NCURSES + if (fd < 0) { return -1; } - int ret = read(fd, file, 2048); if (ret < 0) { fclose(fd); return -1; } +#ifndef NCURSES fclose(fd); +#else + close(fd); +#endif // !NCURSES /* set filename */ strcpy(buffer->filename, filename); @@ -229,20 +288,67 @@ static int textbuffer_jump(struct textbuffer *buffer, unsigned int x, unsigned i buffer->cursor.y = y; buffer->cursor.x = x; - if(buffer->cursor.y > MAX_VISABLE_LINES) { - buffer->scroll.start = buffer->cursor.y - MAX_VISABLE_LINES; + if(buffer->cursor.y > 20) { + buffer->scroll.start = buffer->cursor.y - 20; } + textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + return 0; } +/* Function to find a keyword in the text and return its color, or default color if not found */ +static enum vga_color get_keyword_color(const struct textbuffer *buffer, const char *text, size_t text_len, size_t *keyword_length) { + for (int i = 0; i < buffer->syntax->count; i++) { + const char *keyword = buffer->syntax->keywords[i].keyword; + size_t keyword_len = strlen(keyword); + + if (text_len >= keyword_len && strncmp(text, keyword, keyword_len) == 0 && + (text_len == keyword_len || isspace(text[keyword_len]))) { + *keyword_length = keyword_len; + return buffer->syntax->keywords[i].color; + } + } + + *keyword_length = 0; + return VGA_COLOR_WHITE; +} + +static int textbuffer_print_line(struct textbuffer *buffer, int x, int y, size_t line) { + if (line >= buffer->line_count) { + return -1; + } + + struct line *l = buffer->lines[line]; + for (size_t i = 0; i < l->length;) { + size_t remaining_length = l->length - i; + size_t keyword_len = 0; + enum vga_color color = get_keyword_color(buffer, &l->text[i], remaining_length, &keyword_len); + + if (keyword_len > 0) { + for (size_t j = 0; j < keyword_len; j++) { + screen_put_char(x + i + j, y, l->text[i + j], COLOR(color, VGA_COLOR_BLUE)); + } + i += keyword_len; + } else { + screen_put_char(x + i, y, l->text[i], COLOR(color, VGA_COLOR_BLUE)); + i++; + } + } + + return 0; +} + + + /* Function to display the content of the text buffer on the screen */ static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg, enum vga_color bg) { uint32_t x_start = 0; + uint32_t last_line_y = 0; uint32_t y_start = buffer->scroll.start; /* Clear the screen before displaying new content */ - screen_clear(0, 0, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + //screen_clear(0, 0, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); /* fill top row with light grey */ for (size_t i = 0; i < 80; i++) { @@ -255,28 +361,35 @@ static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg screen_put_char(4, 1, 'R', COLOR(VGA_COLOR_GREEN, VGA_COLOR_BLUE)); screen_put_char(5, 1, ']', COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); - /* draw filename */ - screen_printf(6, 1, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE), " %s", buffer->filename); - /* write from start to end, or line_count */ for (size_t i = 0; i + y_start < buffer->line_count && i < buffer->scroll.end; i++) { /* Calculate the position for each line */ uint32_t x = x_start; uint32_t y = y_start + i; + last_line_y = 2 + i; /* Write the line to the screen */ - if (!buffer->lines[y]->text) { - continue; - } + // if (!(buffer->lines[y]->flags & LINE_FLAG_DIRTY)) { + // continue; + //} - //screen_clear_line(2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + screen_clear_line(2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); if (buffer->cursor.y == y) { - screen_printf(1+x, 2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE) , "%s %c", buffer->lines[y]->text, 27); + //screen_printf(1+x, 2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE) , "%s %c", buffer->lines[y]->text, 27); } else { - screen_printf(1+x, 2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE), "%s", buffer->lines[y]->text); + //screen_printf(1+x, 2 + i, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE), "%s", buffer->lines[y]->text); } + textbuffer_print_line(buffer, 1+x, 2 + i, y); + + /* Clear DIRTY flag */ + buffer->lines[y]->flags &= ~LINE_FLAG_DIRTY; } + /* Clear the line after the last actual line */ + if (last_line_y < MAX_VISABLE_LINES) { + screen_clear_line(last_line_y + 1, COLOR(VGA_COLOR_WHITE, VGA_COLOR_BLUE)); + } + screen_set_cursor(buffer->cursor.x+1, 2+buffer->cursor.y - buffer->scroll.start); /* fill bottom row with light grey */ @@ -285,17 +398,17 @@ static int textbuffer_display(const struct textbuffer *buffer, enum vga_color fg } /* write stats at the bottom */ - screen_printf(0, 24, COLOR(VGA_COLOR_BLACK, VGA_COLOR_LIGHT_GREY), "lc: %d, x: %d, y: %d, Save CTRL-S, Exit CTRL-C", buffer->line_count, buffer->cursor.x, buffer->cursor.y); + screen_printf(0, 24, COLOR(VGA_COLOR_BLACK, VGA_COLOR_LIGHT_GREY), "lc: %d, x: %d, y: %d, Save CTRL-S, Command CTRL-C, Search CTRL-F", buffer->line_count, buffer->cursor.x, buffer->cursor.y); return 0; } /* Function to handle keyboard input of a char */ -static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { +static int textbuffer_handle_char(struct textbuffer *buffer, int c) { int ret; /* Handle the backspace key */ - if (c == '\b') { + if (c == BACKSPACE) { /* If we are at the end of the line */ if (buffer->cursor.x == 0) { /* If the cursor is at the beginning of the first line, do nothing */ @@ -315,6 +428,9 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { textbuffer_free_line(buffer, buffer->cursor.y); buffer->cursor.y--; + + /* mark as dirty */ + buffer->lines[buffer->cursor.y]->flags |= LINE_FLAG_DIRTY; } else { /* Remove the character before the cursor */ if (buffer->lines[buffer->cursor.y] == NULL) { @@ -330,6 +446,9 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { buffer->lines[buffer->cursor.y]->text[buffer->lines[buffer->cursor.y]->length - 1] = '\0'; buffer->lines[buffer->cursor.y]->length--; buffer->cursor.x--; + + /* mark as dirty */ + buffer->lines[buffer->cursor.y]->flags |= LINE_FLAG_DIRTY; return -1; } @@ -337,6 +456,9 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { buffer->lines[buffer->cursor.y]->text[buffer->cursor.x - 1] = 0; buffer->lines[buffer->cursor.y]->length--; buffer->cursor.x--; + + /* mark as dirty */ + buffer->lines[buffer->cursor.y]->flags |= LINE_FLAG_DIRTY; } } else if (c == '\n') { /* If the cursor is at the end of the line, create a new line */ @@ -357,6 +479,9 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { memset(buffer->lines[i]->text, 0, buffer->lines[i]->capacity); memcpy(buffer->lines[i]->text, buffer->lines[i - 1]->text, buffer->lines[i - 1]->length); buffer->lines[i]->length = buffer->lines[i - 1]->length; + + /* mark as dirty */ + buffer->lines[i]->flags |= LINE_FLAG_DIRTY; } /* clear next line */ memset(buffer->lines[buffer->cursor.y + 1]->text, 0, buffer->lines[buffer->cursor.y + 1]->capacity); @@ -366,6 +491,9 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { /* Move the cursor to the beginning of the new line */ buffer->cursor.x = 0; buffer->cursor.y++; + + /* mark as dirty */ + buffer->lines[buffer->cursor.y]->flags |= LINE_FLAG_DIRTY; } else { /* Create a new line */ ret = textbuffer_new_line(buffer); @@ -377,6 +505,9 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { for (size_t i = buffer->line_count - 1; i > buffer->cursor.y + 1; i--) { memcpy(buffer->lines[i]->text, buffer->lines[i - 1]->text, buffer->lines[i - 1]->length); buffer->lines[i]->length = buffer->lines[i - 1]->length; + + /* mark as dirty */ + buffer->lines[i]->flags |= LINE_FLAG_DIRTY; } /* clear next line */ @@ -398,11 +529,14 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { /* Move the cursor to the beginning of the new line */ buffer->cursor.x = 0; buffer->cursor.y++; + + /* mark as dirty */ + buffer->lines[buffer->cursor.y]->flags |= LINE_FLAG_DIRTY; } if (buffer->cursor.y >= buffer->scroll.end + buffer->scroll.start) { buffer->scroll.start++; } - } else if (c >= ARROW_RIGHT && c <= ARROW_UP) { + } else if (c == ARROW_RIGHT || c == ARROW_LEFT || c == ARROW_UP || c == ARROW_DOWN) { switch (c) { case ARROW_RIGHT: if (buffer->cursor.x < buffer->lines[buffer->cursor.y]->length) { @@ -453,6 +587,9 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { /* Move the content from x to end forward one character */ for (size_t i = buffer->lines[buffer->cursor.y]->length; i > buffer->cursor.x; i--) { buffer->lines[buffer->cursor.y]->text[i] = buffer->lines[buffer->cursor.y]->text[i - 1]; + + /* mark as dirty */ + buffer->lines[buffer->cursor.y]->flags |= LINE_FLAG_DIRTY; } } @@ -460,14 +597,34 @@ static int textbuffer_handle_char(struct textbuffer *buffer, unsigned char c) { buffer->lines[buffer->cursor.y]->text[buffer->cursor.x] = c; buffer->lines[buffer->cursor.y]->length++; buffer->cursor.x++; + + /* mark as dirty */ + buffer->lines[buffer->cursor.y]->flags |= LINE_FLAG_DIRTY; } return 0; } int main(int argc, char *argv[]) { + + +#ifdef NCURSES + initscr(); + + if (has_colors() == FALSE) { + endwin(); + printf("Your terminal does not support color\n"); + return -1; + } + + start_color(); + + noecho(); + keypad(stdscr, TRUE); +#endif // !NCURSES + int ret; - unsigned char c; + int c; struct textbuffer *buffer = textbuffer_create(); if (buffer == NULL) { return -1; @@ -487,12 +644,17 @@ int main(int argc, char *argv[]) { c = screen_get_char(); if (c == 0) continue; - if (c == CTRLC) - break; + if (c == CTRLC){ + ret = textbuffer_command_main(buffer); + textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + if(ret == -117) break; + continue; + } if (c == CTRLS){ textbuffer_save_file(buffer, buffer->filename); continue; } + if (c == CTRLF){ ret = textbuffer_search_main(buffer); textbuffer_display(buffer, VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); @@ -507,5 +669,10 @@ int main(int argc, char *argv[]) { textbuffer_destroy(buffer); + + #ifdef NCURSES + endwin(); + #endif // !NCURSES + return 0; -} \ No newline at end of file +} diff --git a/developer/interpreter.c b/developer/interpreter.c index 95a73bd..73f74c0 100644 --- a/developer/interpreter.c +++ b/developer/interpreter.c @@ -251,6 +251,8 @@ static int __cc(int argc, char **argv) kfree(src); + terminal_commit(); + return 0; } diff --git a/include/libc.h b/include/libc.h index ee557ac..70c19d6 100644 --- a/include/libc.h +++ b/include/libc.h @@ -42,6 +42,7 @@ uint32_t memcmp(const void* ptr, const void* ptr2, uint32_t len); void* memset (void *dest, int val, int len); void* memcpy(void *dest, const void *src, int n); void* xmemcpy(void *dest, const void *src, int n); +void* memmove(void *dest, const void *src, size_t n); int parse_arguments(const char *input_string, char tokens[10][100]); diff --git a/kernel/vmem.c b/kernel/vmem.c index 81746b3..f521ce6 100644 --- a/kernel/vmem.c +++ b/kernel/vmem.c @@ -15,6 +15,9 @@ #include #include +#undef dbgprintf +#define dbgprintf(...) + struct virtual_memory_allocator; /* allocator prototypes */ @@ -368,7 +371,6 @@ void* vmem_stack_alloc(struct pcb* pcb, int _size) warningf("Out memory\n"); return NULL; } - dbgprintf("New allocation: 0x%x\n", allocation); allocation->size = _size; allocation->used = _size; diff --git a/lib/libc.c b/lib/libc.c index 17cd052..b815bea 100644 --- a/lib/libc.c +++ b/lib/libc.c @@ -69,6 +69,27 @@ inline uint32_t strcpy(char* dest, const char* src) return i; } +inline void* memmove(void *dest, const void *src, size_t n) +{ + unsigned char *d = dest; + const unsigned char *s = src; + if (d == s) { + return dest; + } + + if (d < s) { + for (size_t i = 0; i < n; i++) { + d[i] = s[i]; + } + } else { + for (size_t i = n; i != 0; i--) { + d[i - 1] = s[i - 1]; + } + } + return dest; +} + + inline uint32_t strncmp(const char* str, const char* str2, uint32_t len) { return memcmp((uint8_t*)str, (uint8_t*)str2, len); From 7952ea7161684bac502378a8904821e4c46b096e Mon Sep 17 00:00:00 2001 From: Joe Bayer Date: Tue, 13 Feb 2024 22:26:26 +0100 Subject: [PATCH 23/23] added missing archive file --- apps/Makefile | 2 +- docs/pictures/textedit.gif | Bin 0 -> 495860 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 docs/pictures/textedit.gif diff --git a/apps/Makefile b/apps/Makefile index d807b39..b24eefb 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -33,7 +33,7 @@ UTILS = bin/cppUtils.o bin/crt0.o USROBJS = COMMON = ../bin/syscall.o ../bin/libc.o ../bin/printf.o ../bin/graphics.o ../bin/netlib.o bin/cppUtils.o -LIB_COMMON_OBJS = ../bin/syscall.o ../bin/libc.o ../bin/printf.o +LIB_COMMON_OBJS = ../bin/syscall.o ../bin/libc.o ../bin/printf.o bin/cppUtils.o LIB_GRAPHICS_OBJS = ../bin/graphics.o ../bin/libc.o LIB_NET_OBJS = ../bin/netlib.o diff --git a/docs/pictures/textedit.gif b/docs/pictures/textedit.gif new file mode 100644 index 0000000000000000000000000000000000000000..e953d6e676bfa506da2519b18ef846ce618004b5 GIT binary patch literal 495860 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

u=F3A=TJq>Su+bb0KJV42mC3jEB zO1{|lz-7mo?-M?U|8Ab!`29We5@$KG+ie@>#rJ2CH$EMhOP{j8)&p$20&BP3+r0ld zW$#}r0l33w%R>I9F2NkxrA&#HczXKa2q;vczWwh~4)tBlo?D7frQd#{-f}HG`fKq- zhVhr#)8}v5e9+zRC+QHre8y_=$kLwv2N5MNZT`FYC$-{*g0Z*x`|qERSWZU?>ukrE zYJY9NJvjfbf97(=$N^88N2g6!Bx5!@AHQJU|0{TSI``lF8TY8;-&GW~2fgkoz0J7d zxI;_0E_}J|isA3Se;j|#8C`-|O8RKQ)1|w8_VJ7>;u%Wkq!B{hL7Yxm(8_O_Kj6Xh zaO7Lu)^>2eOqPstHA9aBpTMR=2JA5JEoNDHVDbr2>|uAo?|!l?a<(rwtz$FFU&@Sh z2}0C$Yap!S+<-R)X~`~1dSo6Kk{x|T;^JsZ8ZM%q&jP%@G`z1YZa$c{sj{cE_7brbvW(l_zHq!7-`h-zG8Z%VG z2Aw%Yy73;72?JU>!z`C#cIOerSPyI(Lqb#!W6C%*LP==w!n=;>Zx@*Z@1+xjm`*_C zcxC8$F-k}uX^0wy0)yIy{2O?IXZ0`S0PcN~+5-EAd(W?T`3mX&*98s@YmWZAvXl3#T)H|XOT-d}!%6tVkwV~DgaXgoS08drbe2BN zMv86FD$aXZG}TQq9HbtcNJADYd#H1*^`L0^l}NFnZ(g}Z0ZWKy)n%nekoZR`7aicYZnJBU@=?EYPT83 zzb?wd6&e_DLLb-iU|YvW#IpKS4si$d>mGXT6)HUYv`=13?#ehSGc2NXMi=dChtyAc zbV}l_S4gfk&wk0QT-gbLiD%KMmgx!(|>5rDxk{A{pEmY+5@LIeM3E$$YpJ@#7vwA_eJ~CP< zY*3oHkEyiDEd&laMQd6kKD9 zG2L15_310AGTXk#HfcW%!yhjn?6)g1c|7({cz}_&rNZ++%ACR1m#w>^KJ7k_kK22r z_mkJsmi<3VlU~ej?)&;e@w@(q$=X|6ZXmk4_fMUkZ84+@?DA}nSj=0@G+nugGNHck zoPXBRmDTip`g1|XMuJkT{NGHqN!?2WWgQs-Agu^@h?z{X1Vf7v^VuFV6q0JeAsqy1Alb4Sb&t<*~&F z-oLr5yngoVzN9D0Z=XHC{`iqY<-MZI8XD0ych9B%$Tl5#qVJe}A4WLP`_*16ylwpX zmw(?Q#h*W=%O4odI$~O}{qySQ+3VN7o?4GMKmY#AQHvMC;bZ^Z%5cy$Go_C!5qm6`+tZh0>Xw8D{th*on4zh^ciy`-+pBfyU}TBue`kb$-QayDP4{nVBDt^r zYAiXV1kC#O2_Ih|+3Uys*B|xmHCg6W^WmU3t+CtD4(prEzZF5%>#xLbxR0=pK9cL1 zl6${)63feTyWc~E+&p(h5m8W& zObv7`eR3_)`vM&aYZs*yJoH`3m{CYEvkJ6?nZ)NIx+hO!0fHb;9E((nbj1jmmPU|b zJUr0;iP$pc?0Yw~rL&0ft9BD>VwvZgf|J@;vTLWXr1l6~Nid`q&yJx9+9^D>D98u} zYON1TU_t$K+L3CQ$?~A#PEe;A#tood^`NiI0@M@1x(l@B7euxK^y4q$!g!I&tr_w0 zVKpSkA#>^#fHotZl}No7%^}@%dk!4Jji})U)r-N@BMb+~2{X^svjZ&zOq^Yn;~dZR zDXvQfP+dK#rVdrsAsphX>%O_UmAd~>0XEW#aWgK|ND!GE>OP2T>YGrr=UK6a5k_!_ zK1lwmqMr({XlB@2;c3RAM`UjRYMQiZ?M&ez!pIRCeuM`T0E9Fzw1Af-5Fuv7VIDjQ zJDAui8Y$p8asfgxaGom!r3J%Qiy*4mH9V4`l`dm+hG_|*(l!`!nLuXCNxMiMumN+? zm!{Ufp`}fVFS{I20T49Mc#e5;WCu--rELxBvs_R#2rYmUu(2ropmp*v$_S#24~wso z_LgeG$2G;i<>&1jg10*<@h5&d1=_p@Ljz7kF2fw^T%Fj9)`_0}(Ql@TLT;l}uYe;5 zST1VG@H|%#YdM_H!0ghOHe41B(md3(7@EEkgEaBNk-P)MvRa=Oi3IHH3yRadaB`t zE@jis)Qxe^;$iz_7mN|8B3e?703os&53G`?SZ zzGJYw3zeqA}WboWQt!SGal!IhQ{6?5X9;W~r@Q~-FAB=R4+7PU@Hrt}J|ZYS6kz>AC>ZhV z`50K;u53|R)@wbfcW)qbD>Q9%Z*P%C zt)9}N-Y$b3UVkWP~VG7M+S|$!zv49b; z`>H`PYA4PE z$|mDrSOsw-NPV0s)(+WC=Sf%&TMvLcNdbTY+yOsW77aL94kLJm-5Z?k{Th4c_o%%d z68B)*(Z|&ogVqW|s0~RY-{V0_M(e&i&qkd<(h&~b&c@AJ7%3NHWDOV(>5zsgSVkPu z$%2ZGP~s6AKx2|iiE@|WqEPme$}zZ#;_$Aiy<7Rx-8 zz*%Kg`Z8>+2r}C0*%2oLekUOG@lN`S;}t1ztt&--#h-n$4PK#N{H}U_jUE$fth;yJ zQ*|FZ2v56^`09)3D)hbqQkH^wm{TKU+@f^Ms*a8m-$u zrt6dMge)OG4_7yPfdn;Wrq%u`zB%?`JhV{d=aTl^8f-Yd%UZqkEMlf*rPP|nm>#j^wo-!vtA1VrX)9~p9Y+@ zsa`+=Qk@Osj z-VtAQ(ZPer5zt;a4>8?9&CTo?S&&nK7J&kEB4l0dVy@+4mIafSL0IDR^fM9UI+5QO zu&*BWJjf$vGWFA723)v2FVO2^rdc<`@gPEHk+HcHMx2p9J@^E_%p}J1#GMPZU2uH&E zzDvlP)BtoqM5HZ*w(HZU!wu*|&?AJ*3=m((%YI{J0OU!7-&5B|;q1!2Nyc#cGKE{{ z{@<3;lCg3tf*ykMGr7of7L=${pyNk~tZQiS!O2Vz%MwBid0^`v9xf5Y)?GPf8*aJz zm*>|$P*8B1q*%3AhI)s3O4`F}jFxcw8QJBb`4s6~a6?z3M?;TTM{{x4N3jmxeS^K@ zhAVD{`Dv$?u9vn|xGsOubM!CiP}g?+a=y7nY*_3ZL9FCgJ!0j0)6}{v<(O{MU0KKe z7N!I$u;y>HP1|MB1`=8Fvg*h~)pOGwwKgyT++3@Z2G7DjV?`(;F{R)o7vy1b_~10 zG^m^CJ$P7@SD8udzgBL0{nU-?^|t+OH~KHy-ne$-#_emi19xr=+_$~?y zGhKEz2_6`iXPY+XNzy@evWp38WBi(3VpWa|*Uo%>$fSE<>Xlu>$Gm%g@?^qzS{uXq zX+s9fL!)m79t_jQ+W^#nlez*7wXyNQ-QHW~rYRdHp)g1ToCdw^pX?|YJZL{xk2Id! za9lk+cQEq*n`K7=ia-F|;{TUrM~agp$5+V+w8Z}{f%$*4>@LOsn`M{Ak+M808D3SC z|0#jF+`?wDuh0pfP>n0<5a z^AQBJ0|P=R+6BPGunun_Xsdw3a8~zPZ9u5WK}`0;5Uy)UoEa3CCo2F3Gd{@fUaauY z!36?X5Nx!39xodEF<5$m-C-)Z!3#_7jJ#tiCJ#P z6_A{^-?9dM>=oyWo`Al_^f7A=P0CM4iN(j8`4@bpA$QC+PSl)Dxm2dZVKo(S7pA4| zS=F$>ZCa;U83oRr%NYcvhwEPp0fxR%|9@&5BH{sAGT+JKdG+ch7=1kG4uDZ!l|4m5 zLM8TEB-c`h)880nj$0BbKGeV!SV6+38Rirs>bDN(?2m6xPde=zmAhw6RCv9Wl=nMG z9QPCZl}Gs*-_6tbx7eNM$gv~&QHe5SC+aW!;D01bC8-JfB`S$gH?Yq1wf6rkqFF?k2crd%h`=l>N)p^oejJkEj;k3qbG3#aNRi1pOeP*T{Cek~PHm)+q8<{A(m<4=GUSZ1O4ckD zBauPT?FmV8K|Nr+gLKxF<(+gksh;@!2zf*NKk0ut>Y>S=AEx#a4Aw8Rc?(Fv!?tuo zOO|7{7A0-|^7vPjLt$Uwee5P-%HQvEKaG8Wq}urwku&D9c|~zkvNQE}j?;|B&*t=D z%5xTJ$m((*x6nSrvUkub-b#ANAL)4vo3_9WuY2RHyi)XNNS&yHf1_*~2I_1y;BX41 zz{djY-PaE9Bh_o>-voCsy%zi z>wWF8GD~m7+I`O($9u4ASp29>@}QsLak$$oicTkT1CyhrTdPI}fdTRurp_v;bx2eC*#>?TmIm1NUrqHLUbH75c3W{G{)b;T2p+(QR}& z;c*~og4Ey^--h*E0kdr$bwoVQM(}-H7aD^a(BIokeOI<^v6!tp`n@yZ1%BHm`0OyC z-MM3bM>r#i(^t8kkXIt0F{qH#Hq02#uMGeFV4s7 zo>tXS+{4bzPY!SM+IG?W$K|ZMM#1VgYEI@^U9KxTAEiI_Y&Nhp?5KUp_9cVo&xEtH zJ^4|cDTu?{pZxxDE#$pn!eQ^{FO=lF^IW@vgAUI(NXhr{%Tj$w^3Rv7e)f-_=}3sR z**HQ25?Z z@H%3BL{G;f+4FqRkk0I7`ls##*KMC)nw0I5NI0MK)O)t^HMPaouZLs&asEo)Xj@Z@ zaX#L)) z0vQT=NDbyafXZ+_LmPf-ET8U)A|sX9dain;aj358IO9Rl*bI^bHGTTH6mcimLbKc5 z$)gRRk<@Ek@>-DSgOE7Hz{+D!)!psnh}1wu@kA+wme_J#@)AJDyK6MNv_uP);DezP z-6e0;;+vAyOH$chycZBi&O-=}z3VR0fJn$8^d%#YeKPsw=J+n%EM+$fbDmtp^WTCe z)4fgxe8A}=Fh^^6=w$%F2zr{N2^onyRbRc~fG>Ti57^sn?_z=HW|#`+&?Z)-bYvQY zCAMXal#K$#8GvN12e1A6h717rKcV{bA%P9-<(6&e3yuPkqz35BpVlyhhs!5rfU!&+ zMLu7BbzAb@_iBS2GQ!_OflWccMD}Bv$UDyFqA$MzacK|}^LahAk;WyI&y6%KentAu zF*$k}Jhj%Ad=yX?W5)i$CV(soZ|URin8VNC!++{u0WIZx#v`Y@akH{H8qVRil9uF? z4aXrYEei%S5HPH$&Ny54{cXj)fN|JI;#We|rw9C+u0Jp9W7M#H_8?ZnQlLiifGfv~ z9%URTRfU*RI{pk>&vs+Uth`ONx~x`9b!BeWCSebmtK+|pC~}cvIZobFhm&5d`z8&p zofhWE&~8gelc@o2%)h$h4To%avIPf7AJ8x{KAOD>Ynt8T=?@p73e`CF5t0fbc;n}o$t ztf@2qhpsmdgzAqUe$SbG7-Q_a#=h^n1~axOB$Op(>|==$m8hJVv1S{T5H*%0DJn^& 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

3WL$M~MCN2{HoA`#mh6@Y(Y`V) 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%0Al~!Y!gBVFva4 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%0DG)zmQ`lLj1O$`n|ecbv>uH;T#XQwi?X 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 literal 0 HcmV?d00001