; fox32os kernel const LOAD_ADDRESS: 0x03000000 const FOX32OS_VERSION_MAJOR: 0 const FOX32OS_VERSION_MINOR: 2 const FOX32OS_VERSION_PATCH: 0 const FOX32OS_API_VERSION: 1 const REQUIRED_FOX32ROM_API_VERSION: 1 const SYSTEM_STACK: 0x01FFF800 const BACKGROUND_COLOR: 0xFF674764 const TEXT_COLOR: 0xFFFFFFFF jmp entry ; system jump table org.pad 0x00000010 jump_table: data.32 get_os_version data.32 get_os_api_version data.32 get_current_disk_id data.32 set_current_disk_id ; FXF jump table org.pad 0x00000110 data.32 parse_fxf_binary data.32 launch_fxf_from_disk ; task jump table org.pad 0x00000210 data.32 new_task data.32 yield_task data.32 end_current_task data.32 get_current_task_id data.32 get_unused_task_id data.32 is_task_id_used data.32 save_state_and_yield_task ; memory jump table org.pad 0x00000310 data.32 allocate_memory data.32 free_memory ; window jump table org.pad 0x00000410 data.32 new_window data.32 destroy_window data.32 new_window_event data.32 get_next_window_event data.32 draw_title_bar_to_window data.32 move_window data.32 fill_window data.32 get_window_overlay_number data.32 start_dragging_window data.32 new_messagebox data.32 get_active_window_struct ; VFS jump table org.pad 0x00000510 data.32 open data.32 seek data.32 tell data.32 read data.32 write data.32 get_size ; widget jump table org.pad 0x00000610 data.32 draw_widgets_to_window data.32 handle_widget_click jump_table_end: ; initialization code entry: ; before doing anything, check if we are running on top of an existing instance of the kernel ; we can do this by comparing our load address to the known load address that the bootloader loads us to ; only the high 16 bits are checked rcall 6 pop r1 mov.16 r1, 0 cmp r1, LOAD_ADDRESS ifz jmp entry_ok ; if it appears that we're running on top of an existing kernel, then show a messagebox and exit ; call the messagebox routines of the existing kernel mov r0, 0 mov r1, kernelception_error_str mov r2, 0 mov r3, 64 mov r4, 64 mov r5, 184 call [0x00000C34] ; new_messagebox call [0x00000A18] ; end_current_task rjmp 0 entry_ok: mov rsp, SYSTEM_STACK ; save the boot disk id that the bootloader passed in r0 mov.8 [current_disk_id], r0 ; clear the background mov r0, BACKGROUND_COLOR call fill_background ; check for the required fox32rom API version mov r0, get_rom_api_version add r0, 2 mov r0, [r0] cmp [r0], 0 ifz jmp api_version_too_low_error call get_rom_api_version cmp r0, REQUIRED_FOX32ROM_API_VERSION iflt jmp api_version_too_low_error ; initialize the memory allocator call initialize_allocator ; draw the bottom bar mov r0, bottom_bar_str_0 mov r1, 8 mov r2, 448 mov r3, TEXT_COLOR mov r4, 0x00000000 call draw_str_to_background mov r0, bottom_bar_patterns mov r1, 1 mov r2, 16 call set_tilemap mov r1, 0 mov r2, 464 mov r31, 640 draw_bottom_bar_loop: mov r4, r31 rem r4, 2 cmp r4, 0 ifz mov r0, 0 ifnz mov r0, 1 call draw_tile_to_background inc r1 loop draw_bottom_bar_loop mov r0, 10 mov r1, 464 mov r2, 20 mov r3, 16 mov r4, 0xFFFFFFFF call draw_filled_rectangle_to_background mov r0, bottom_bar_str_1 mov r1, 12 mov r2, 464 mov r3, 0xFF000000 mov r4, 0xFFFFFFFF call draw_str_to_background mov r0, bottom_bar_str_2 mov r1, 488 mov r2, 464 mov r3, 0xFF000000 mov r4, 0xFFFFFFFF mov r10, FOX32OS_VERSION_MAJOR mov r11, FOX32OS_VERSION_MINOR mov r12, FOX32OS_VERSION_PATCH call draw_format_str_to_background ; copy the jump table to 0x00000810 mov r0, jump_table mov r1, 0x00000810 mov r2, jump_table_end sub r2, jump_table call copy_memory_bytes ; check if a disk is inserted as disk 1 ; if so, skip checking startup.cfg and just run disk 1 in r31, 0x80001001 cmp r31, 0 ifnz jmp boot_disk_1 try_startup: ; open startup.cfg call get_current_disk_id mov r1, r0 mov r0, startup_cfg mov r2, startup_cfg_struct call ryfs_open cmp r0, 0 ifz jmp startup_error ; load a startup task load_startup_task: ; load 11 bytes of startup.cfg into startup_file mov r0, 11 mov r1, startup_cfg_struct mov r2, startup_file call ryfs_read ; open the actual startup file call get_current_disk_id mov r1, r0 mov r0, startup_file mov r2, startup_file_struct call ryfs_open cmp r0, 0 ifz jmp boot_disk_1 ; allocate memory for the startup file mov r0, startup_file_struct call get_size call allocate_memory cmp r0, 0 ifz jmp memory_error mov [startup_file_binary_ptr], r0 ; allocate 64KiB for the startup file's stack mov r0, 65536 call allocate_memory cmp r0, 0 ifz jmp memory_error mov [startup_file_stack_ptr], r0 ; read the startup file into memory mov r0, startup_file_struct mov r1, [startup_file_binary_ptr] call ryfs_read_whole_file ; relocate and execute it as a new task mov r0, r1 call parse_fxf_binary mov r3, r1 mov r1, r0 movz.8 r0, [next_task_id] mov r2, [startup_file_stack_ptr] add r2, 65536 sub r2, 4 mov r4, [startup_file_stack_ptr] call new_task ; when the startup file yields for the first time, we'll end up back here ; now, check to see if startup.cfg has any other entries ; we do this by checking to see if the size of startup.cfg is less than or equal to 12 * next_task_id bytes inc.8 [next_task_id] mov r0, startup_cfg_struct call get_size movz.8 r1, [next_task_id] mul r1, 12 cmp r0, r1 iflteq jmp no_other_tasks ; seek forward one byte to skip the linefeed mov r0, startup_cfg_struct call ryfs_tell inc r0 mov r1, startup_cfg_struct call ryfs_seek ; load the next task jmp load_startup_task no_other_tasks: ; start the event manager task call start_event_manager_task ; jump back to it without adding this "task" (not really a task) into the queue. ; end_current_task_no_mark_no_free is used specifically because it doesn't mark ; the current task (still set to 0) as unused, and it doesn't free the memory ; block. ; this does not return. call end_current_task_no_mark_no_free ; try loading the raw contents of disk 1 as an FXF binary ; if disk 1 is not inserted, then fail boot_disk_1: ; check if a disk is inserted as disk 1 in r31, 0x80001001 cmp r31, 0 ifz jmp startup_error ; a disk is inserted, load it!! ; allocate memory for the startup file ; r31 contains disk size mov r0, r31 call allocate_memory cmp r0, 0 ifz jmp memory_error div r31, 512 inc r31 mov r2, r0 ; destination pointer mov r5, r0 mov r0, 0 ; sector counter mov r3, 0x80003001 ; command to read a sector from disk 1 into memory mov r4, 0x80002000 ; command to set the location of the buffer boot_disk_1_loop: out r4, r2 ; set the memory buffer location out r3, r0 ; read the current sector into memory inc r0 ; increment sector counter add r2, 512 ; increment the destination pointer loop boot_disk_1_loop mov r1, r5 mov r0, r5 call parse_fxf_binary cmp r0, 0 ifz jmp disk_1_is_not_fxf mov r3, r1 mov r1, r0 movz.8 r0, [next_task_id] mov r2, rsp sub r2, 4 mov r4, 0 ; don't attempt to free any stack block if the task ends call new_task jmp no_other_tasks ; disk 1 was found to not be a valid FXF binary ; free the memory allocated for it and instead just keep it mounted as a disk disk_1_is_not_fxf: mov r0, r5 call free_memory jmp try_startup startup_error: mov r0, BACKGROUND_COLOR call fill_background mov r0, startup_error_str mov r1, 16 mov r2, 464 mov r3, TEXT_COLOR mov r4, 0x00000000 mov r10, FOX32OS_VERSION_MAJOR mov r11, FOX32OS_VERSION_MINOR mov r12, FOX32OS_VERSION_PATCH call draw_format_str_to_background rjmp 0 memory_error: mov r0, BACKGROUND_COLOR call fill_background mov r0, memory_error_str mov r1, 16 mov r2, 464 mov r3, TEXT_COLOR mov r4, 0x00000000 mov r10, FOX32OS_VERSION_MAJOR mov r11, FOX32OS_VERSION_MINOR mov r12, FOX32OS_VERSION_PATCH call draw_format_str_to_background rjmp 0 api_version_too_low_error: mov r0, BACKGROUND_COLOR call fill_background mov r0, api_error_str mov r1, 16 mov r2, 464 mov r3, TEXT_COLOR mov r4, 0x00000000 mov r10, FOX32OS_VERSION_MAJOR mov r11, FOX32OS_VERSION_MINOR mov r12, FOX32OS_VERSION_PATCH call draw_format_str_to_background rjmp 0 get_current_disk_id: movz.8 r0, [current_disk_id] ret set_current_disk_id: mov.8 [current_disk_id], r0 ret get_os_version: mov r0, FOX32OS_VERSION_MAJOR mov r1, FOX32OS_VERSION_MINOR mov r2, FOX32OS_VERSION_PATCH ret get_os_api_version: mov r0, FOX32OS_API_VERSION ret #include "allocator.asm" #include "fxf/fxf.asm" #include "task.asm" #include "vfs/vfs.asm" #include "widget/widget.asm" #include "window/window.asm" bottom_bar_str_0: data.strz "FOX" bottom_bar_str_1: data.strz "32" bottom_bar_str_2: data.strz " OS version %u.%u.%u " startup_error_str: data.strz "fox32 - OS version %u.%u.%u - startup.cfg is invalid!" memory_error_str: data.strz "fox32 - OS version %u.%u.%u - not enough memory to perform operation!" api_error_str: data.strz "fox32 - OS version %u.%u.%u - fox32rom API version too low!" kernelception_error_str: data.strz "Error: kernelception?" bottom_bar_patterns: ; 1x16 tile data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF ; 1x16 tile data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 data.32 0xFFFFFFFF data.32 0xFF674764 next_task_id: data.8 0 current_disk_id: data.8 0 startup_cfg: data.str "startup cfg" startup_cfg_struct: data.32 0 data.32 0 startup_file: data.str " " startup_file_struct: data.32 0 data.32 0 startup_file_binary_ptr: data.32 0 startup_file_stack_ptr: data.32 0 #include "../../fox32rom/fox32rom.def" kernel_bottom: