diff --git a/const.inc b/const.inc new file mode 100644 index 0000000..cd0871e --- /dev/null +++ b/const.inc @@ -0,0 +1,939 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 6929 $ + + +dpl0 equ 10010000b ; data read dpl0 +drw0 equ 10010010b ; data read/write dpl0 +drw3 equ 11110010b ; data read/write dpl3 +cpl0 equ 10011010b ; code read dpl0 +cpl3 equ 11111010b ; code read dpl3 + +D32 equ 01000000b ; 32bit segment +G32 equ 10000000b ; page gran + + +;;;;;;;;;;;;cpu_caps flags;;;;;;;;;;;;;;;; + +CPU_386 equ 3 +CPU_486 equ 4 +CPU_PENTIUM equ 5 +CPU_P6 equ 6 +CPU_PENTIUM4 equ 0x0F + +CAPS_FPU equ 00 ;on-chip x87 floating point unit +CAPS_VME equ 01 ;virtual-mode enhancements +CAPS_DE equ 02 ;debugging extensions +CAPS_PSE equ 03 ;page-size extensions +CAPS_TSC equ 04 ;time stamp counter +CAPS_MSR equ 05 ;model-specific registers +CAPS_PAE equ 06 ;physical-address extensions +CAPS_MCE equ 07 ;machine check exception +CAPS_CX8 equ 08 ;CMPXCHG8B instruction +CAPS_APIC equ 09 ;on-chip advanced programmable + ; interrupt controller +; 10 ;unused +CAPS_SEP equ 11 ;SYSENTER and SYSEXIT instructions +CAPS_MTRR equ 12 ;memory-type range registers +CAPS_PGE equ 13 ;page global extension +CAPS_MCA equ 14 ;machine check architecture +CAPS_CMOV equ 15 ;conditional move instructions +CAPS_PAT equ 16 ;page attribute table + +CAPS_PSE36 equ 17 ;page-size extensions +CAPS_PSN equ 18 ;processor serial number +CAPS_CLFLUSH equ 19 ;CLFUSH instruction + +CAPS_DS equ 21 ;debug store +CAPS_ACPI equ 22 ;thermal monitor and software + ;controlled clock supported +CAPS_MMX equ 23 ;MMX instructions +CAPS_FXSR equ 24 ;FXSAVE and FXRSTOR instructions +CAPS_SSE equ 25 ;SSE instructions +CAPS_SSE2 equ 26 ;SSE2 instructions +CAPS_SS equ 27 ;self-snoop +CAPS_HTT equ 28 ;hyper-threading technology +CAPS_TM equ 29 ;thermal monitor supported +CAPS_IA64 equ 30 ;IA64 capabilities +CAPS_PBE equ 31 ;pending break enable + +;ecx +CAPS_SSE3 equ 32 ;SSE3 instructions +; 33 +; 34 +CAPS_MONITOR equ 35 ;MONITOR/MWAIT instructions +CAPS_DS_CPL equ 36 ; +CAPS_VMX equ 37 ;virtual mode extensions +; 38 ; +CAPS_EST equ 39 ;enhansed speed step +CAPS_TM2 equ 40 ;thermal monitor2 supported +; 41 +CAPS_CID equ 42 ; +; 43 +; 44 +CAPS_CX16 equ 45 ;CMPXCHG16B instruction +CAPS_xTPR equ 46 ; +; +;reserved +; +;ext edx /ecx +CAPS_SYSCAL equ 64 ; +CAPS_XD equ 65 ;execution disable +CAPS_FFXSR equ 66 ; +CAPS_RDTSCP equ 67 ; +CAPS_X64 equ 68 ; +CAPS_3DNOW equ 69 ; +CAPS_3DNOWEXT equ 70 ; +CAPS_LAHF equ 71 ; +CAPS_CMP_LEG equ 72 ; +CAPS_SVM equ 73 ;secure virual machine +CAPS_ALTMOVCR8 equ 74 ; + +; CPU MSR names +MSR_SYSENTER_CS equ 0x174 +MSR_SYSENTER_ESP equ 0x175 +MSR_SYSENTER_EIP equ 0x176 +MSR_CR_PAT equ 0x277 +MSR_MTRR_DEF_TYPE equ 0x2FF + +MSR_AMD_EFER equ 0xC0000080 ; Extended Feature Enable Register +MSR_AMD_STAR equ 0xC0000081 ; SYSCALL/SYSRET Target Address Register + +CR0_PE equ 0x00000001 ;protected mode +CR0_MP equ 0x00000002 ;monitor fpu +CR0_EM equ 0x00000004 ;fpu emulation +CR0_TS equ 0x00000008 ;task switch +CR0_ET equ 0x00000010 ;extension type hardcoded to 1 +CR0_NE equ 0x00000020 ;numeric error +CR0_WP equ 0x00010000 ;write protect +CR0_AM equ 0x00040000 ;alignment check +CR0_NW equ 0x20000000 ;not write-through +CR0_CD equ 0x40000000 ;cache disable +CR0_PG equ 0x80000000 ;paging + + +CR4_VME equ 0x0001 +CR4_PVI equ 0x0002 +CR4_TSD equ 0x0004 +CR4_DE equ 0x0008 +CR4_PSE equ 0x0010 +CR4_PAE equ 0x0020 +CR4_MCE equ 0x0040 +CR4_PGE equ 0x0080 +CR4_PCE equ 0x0100 +CR4_OSFXSR equ 0x0200 +CR4_OSXMMEXPT equ 0x0400 + +SSE_IE equ 0x0001 +SSE_DE equ 0x0002 +SSE_ZE equ 0x0004 +SSE_OE equ 0x0008 +SSE_UE equ 0x0010 +SSE_PE equ 0x0020 +SSE_DAZ equ 0x0040 +SSE_IM equ 0x0080 +SSE_DM equ 0x0100 +SSE_ZM equ 0x0200 +SSE_OM equ 0x0400 +SSE_UM equ 0x0800 +SSE_PM equ 0x1000 +SSE_FZ equ 0x8000 + +SSE_INIT equ (SSE_IM+SSE_DM+SSE_ZM+SSE_OM+SSE_UM+SSE_PM) + +IRQ_PIC equ 0 +IRQ_APIC equ 1 + +struct TSS + _back rw 2 + _esp0 rd 1 + _ss0 rw 2 + _esp1 rd 1 + _ss1 rw 2 + _esp2 rd 1 + _ss2 rw 2 + _cr3 rd 1 + _eip rd 1 + _eflags rd 1 + _eax rd 1 + _ecx rd 1 + _edx rd 1 + _ebx rd 1 + _esp rd 1 + _ebp rd 1 + _esi rd 1 + _edi rd 1 + _es rw 2 + _cs rw 2 + _ss rw 2 + _ds rw 2 + _fs rw 2 + _gs rw 2 + _ldt rw 2 + _trap rw 1 + _io rw 1 + rb 24 + _io_map_0 rb 4096 + _io_map_1 rb 4096 +ends + +DRIVE_DATA_SIZE equ 16 + +OS_BASE equ 0x80000000 + +window_data equ (OS_BASE+0x0001000) + +CURRENT_TASK equ (OS_BASE+0x0003000) +TASK_COUNT equ (OS_BASE+0x0003004) +TASK_BASE equ (OS_BASE+0x0003010) +TASK_DATA equ (OS_BASE+0x0003020) +TASK_EVENT equ (OS_BASE+0x0003020) + +CDDataBuf equ (OS_BASE+0x0005000) + +;unused 0x6000 - 0x8fff + +BOOT_VARS equ (OS_BASE) ;0x9000 + +idts equ (OS_BASE+0x000B100) +WIN_STACK equ (OS_BASE+0x000C000) +WIN_POS equ (OS_BASE+0x000C400) +FDD_BUFF equ (OS_BASE+0x000D000) ;512 + +WIN_TEMP_XY equ (OS_BASE+0x000F300) +KEY_COUNT equ (OS_BASE+0x000F400) +KEY_BUFF equ (OS_BASE+0x000F401) ; 120*2 + 2*2 = 244 bytes, actually 255 bytes + +BTN_COUNT equ (OS_BASE+0x000F500) +BTN_BUFF equ (OS_BASE+0x000F501) + + +BTN_ADDR equ (OS_BASE+0x000FE88) +MEM_AMOUNT equ (OS_BASE+0x000FE8C) + +SYS_SHUTDOWN equ (OS_BASE+0x000FF00) +TASK_ACTIVATE equ (OS_BASE+0x000FF01) + + +TMP_STACK_TOP equ 0x006CC00 + +sys_proc equ (OS_BASE+0x006F000) + +SLOT_BASE equ (OS_BASE+0x0080000) + +VGABasePtr equ (OS_BASE+0x00A0000) + +CLEAN_ZONE equ (_CLEAN_ZONE-OS_BASE) + +UPPER_KERNEL_PAGES equ (OS_BASE+0x0400000) + +virtual at (OS_BASE+0x05FFF80) + tss TSS +end virtual + +HEAP_BASE equ (OS_BASE+0x0800000) +HEAP_MIN_SIZE equ 0x01000000 + +page_tabs equ 0xFDC00000 +app_page_tabs equ 0xFDC00000 +kernel_tabs equ (page_tabs+ (OS_BASE shr 10)) ;0xFDE00000 +master_tab equ (page_tabs+ (page_tabs shr 10)) ;0xFDFF70000 + +LFB_BASE equ 0xFE000000 + + +new_app_base equ 0; + +twdw equ 0x2000 ;(CURRENT_TASK-window_data) + +std_application_base_address equ new_app_base +RING0_STACK_SIZE equ (0x2000 - 512) ;512 байт для контекста FPU + +REG_SS equ (RING0_STACK_SIZE-4) +REG_APP_ESP equ (RING0_STACK_SIZE-8) +REG_EFLAGS equ (RING0_STACK_SIZE-12) +REG_CS equ (RING0_STACK_SIZE-16) +REG_EIP equ (RING0_STACK_SIZE-20) +REG_EAX equ (RING0_STACK_SIZE-24) +REG_ECX equ (RING0_STACK_SIZE-28) +REG_EDX equ (RING0_STACK_SIZE-32) +REG_EBX equ (RING0_STACK_SIZE-36) +REG_ESP equ (RING0_STACK_SIZE-40) ;RING0_STACK_SIZE-20 +REG_EBP equ (RING0_STACK_SIZE-44) +REG_ESI equ (RING0_STACK_SIZE-48) +REG_EDI equ (RING0_STACK_SIZE-52) +REG_RET equ (RING0_STACK_SIZE-56) ;irq0.return + + +PAGE_SIZE equ 4096 + +PG_UNMAP equ 0x000 +PG_READ equ 0x001 +PG_WRITE equ 0x002 +PG_USER equ 0x004 +PG_PCD equ 0x008 +PG_PWT equ 0x010 +PG_ACCESSED equ 0x020 +PG_DIRTY equ 0x040 +PG_PAT equ 0x080 +PG_GLOBAL equ 0x100 +PG_SHARED equ 0x200 + +PG_SWR equ 0x003 ; (PG_WRITE+PG_READ) +PG_UR equ 0x005 ; (PG_USER+PG_READ) +PG_UWR equ 0x007 ; (PG_USER+PG_WRITE+PG_READ) +PG_NOCACHE equ 0x018 ; (PG_PCD+PG_PWT) + +PDE_LARGE equ 0x080 + +PAT_WB equ 0x000 +PAT_WC equ 0x008 +PAT_UCM equ 0x010 +PAT_UC equ 0x018 + +PAT_TYPE_UC equ 0 +PAT_TYPE_WC equ 1 +PAT_TYPE_WB equ 6 +PAT_TYPE_UCM equ 7 + +PAT_VALUE equ 0x00070106; (UC<<24)|(UCM<<16)|(WC<<8)|WB + +;;;;;;;;;;;boot time variables + +BOOT_BPP equ 0x9000 ;byte bits per pixel +BOOT_PITCH equ 0x9001 ;word scanline length +BOOT_VESA_MODE equ 0x9008 ;word vesa video mode +BOOT_X_RES equ 0x900A ;word X res +BOOT_Y_RES equ 0x900C ;word Y res +BOOT_BANK_SW equ 0x9014 ;dword Vesa 1.2 pm bank switch +BOOT_LFB equ 0x9018 ;dword Vesa 2.0 LFB address +BOOT_MTRR equ 0x901C ;byte 0 or 1 : enable MTRR graphics acceleration +;BOOT_LOG equ 0x901D ;byte not used anymore (0 or 1 : enable system log display) +BOOT_LAUNCHER_START equ 0x901D ;byte (0 or 1) start the first app (right now it's LAUNCHER) after kernel is loaded? +;BOOT_DIRECT_LFB equ 0x901E ;byte 0 or 1 : enable direct lfb write, paging disabled +BOOT_DEBUG_PRINT equ 0x901E ;byte If nonzero, duplicates debug output to the screen. +BOOT_DMA equ 0x901F ; +BOOT_PCI_DATA equ 0x9020 ;8bytes pci data +BOOT_VRR equ 0x9030 ;byte VRR start enabled 1, 2-no +;BOOT_IDE_BASE_ADDR equ 0x9031 ;word IDEContrRegsBaseAddr ; now free and is not used +BOOT_MEM_AMOUNT equ 0x9034 ;dword memory amount + +BOOT_APM_ENTRY equ 0x9040 +BOOT_APM_VERSION equ 0x9044 +BOOT_APM_FLAGS equ 0x9046 ;unused +BOOT_APM_CODE_32 equ 0x9050 +BOOT_APM_CODE_16 equ 0x9052 +BOOT_APM_DATA_16 equ 0x9054 +;BOOT_IDE_BAR0_16 equ 0x9056 ; now free and is not used +;BOOT_IDE_BAR1_16 equ 0x9058 ; now free and is not used +;BOOT_IDE_BAR2_16 equ 0x905A ; now free and is not used +;BOOT_IDE_BAR3_16 equ 0x905C ; now free and is not used +;BOOT_IDE_PI_16 equ 0x905E ; now free and is not used +;BOOT_IDE_INTERR_16 equ 0x9060 ; now free and is not used + +TMP_FILE_NAME equ 0 +TMP_CMD_LINE equ 1024 +TMP_ICON_OFFS equ 1280 + + +EVENT_REDRAW equ 0x00000001 +EVENT_KEY equ 0x00000002 +EVENT_BUTTON equ 0x00000004 +EVENT_BACKGROUND equ 0x00000010 +EVENT_MOUSE equ 0x00000020 +EVENT_IPC equ 0x00000040 +EVENT_NETWORK equ 0x00000080 +EVENT_DEBUG equ 0x00000100 +EVENT_NETWORK2 equ 0x00000200 +EVENT_EXTENDED equ 0x00000400 + +EV_INTR equ 1 + +STDIN_FILENO equ 0 +STDOUT_FILENO equ 1 +STDERR_FILENO equ 2 + +SYSTEM_SHUTDOWN equ 2 +SYSTEM_REBOOT equ 3 +SYSTEM_RESTART equ 4 + +BLIT_CLIENT_RELATIVE equ 0x20000000 + +struct SYSCALL_STACK + _eip dd ? + _edi dd ? ; +4 + _esi dd ? ; +8 + _ebp dd ? ; +12 + _esp dd ? ; +16 + _ebx dd ? ; +20 + _edx dd ? ; +24 + _ecx dd ? ; +28 + _eax dd ? ; +32 +ends + +struct LHEAD + next dd ? ;next object in list + prev dd ? ;prev object in list +ends + +struct MUTEX_WAITER + list LHEAD + task dd ? + type dd ? +ends + +struct MUTEX + wait_list LHEAD + count dd ? +ends + +struct RWSEM + wait_list LHEAD + count dd ? +ends + +struct FUTEX + list LHEAD + magic dd ? + handle dd ? + destroy dd ? + + wait_list LHEAD + pointer dd ? + flags dd ? +ends + +FUTEX_INIT equ 0 +FUTEX_DESTROY equ 1 +FUTEX_WAIT equ 2 +FUTEX_WAKE equ 3 + +struct FILED + list LHEAD + magic rd 1 + handle rd 1 + destroy rd 1 + mode rd 1 + file rd 1 +ends + +struct PIPE + pipe_ops rd 1 + buffer rd 1 + readers rd 1 + writers rd 1 + + pipe_lock MUTEX + count rd 1 + + read_end rd 1 + write_end rd 1 + rlist LHEAD + wlist LHEAD +ends + +struct PROC + list LHEAD + thr_list LHEAD + heap_lock MUTEX + heap_base rd 1 + heap_top rd 1 + mem_used rd 1 + dlls_list_ptr rd 1 + pdt_0_phys rd 1 + pdt_1_phys rd 1 + io_map_0 rd 1 + io_map_1 rd 1 + + ht_lock rd 1 + ht_free rd 1 ;htab[0] stdin + ht_next rd 1 ;htab[1] stdout + htab rd 1024-PROC.htab/4 ;htab[2] stderr + pdt_0 rd 1024 +ends + +struct DBG_REGS + dr0 dd ? + dr1 dd ? + dr2 dd ? + dr3 dd ? + dr7 dd ? +ends + +struct POINT + x dd ? + y dd ? +ends + +struct RECT + left dd ? + top dd ? + right dd ? + bottom dd ? +ends + +struct BOX + left dd ? + top dd ? + width dd ? + height dd ? +ends + +struct APPDATA + app_name rb 11 + rb 5 + + list LHEAD ;+16 + process dd ? ;+24 + fpu_state dd ? ;+28 + exc_handler dd ? ;+32 + except_mask dd ? ;+36 + pl0_stack dd ? ;+40 + cursor dd ? ;+44 + fd_ev dd ? ;+48 + bk_ev dd ? ;+52 + fd_obj dd ? ;+56 + bk_obj dd ? ;+60 + saved_esp dd ? ;+64 + io_map rd 2 ;+68 + dbg_state dd ? ;+76 + cur_dir dd ? ;+80 + wait_timeout dd ? ;+84 + saved_esp0 dd ? ;+88 + wait_begin dd ? ;+92 +++ + wait_test dd ? ;+96 +++ + wait_param dd ? ;+100 +++ + tls_base dd ? ;+104 + dd ? ;+108 + event_filter dd ? ;+112 + draw_bgr_x dd ? ;+116 + draw_bgr_y dd ? ;+120 + dd ? ;+124 + wnd_shape dd ? ;+128 + wnd_shape_scale dd ? ;+132 + dd ? ;+136 + dd ? ;+140 + saved_box BOX ;+144 + ipc_start dd ? ;+160 + ipc_size dd ? ;+164 + event_mask dd ? ;+168 + debugger_slot dd ? ;+172 + terminate_protection dd ? ;+176 + keyboard_mode db ? ;+180 + captionEncoding db ? + rb 2 + exec_params dd ? ;+184 + dbg_event_mem dd ? ;+188 + dbg_regs DBG_REGS ;+192 + wnd_caption dd ? ;+212 + wnd_clientbox BOX ;+216 + priority dd ? ;+232 + in_schedule LHEAD ;+236 +ends + +APP_OBJ_OFFSET equ 48 +APP_EV_OFFSET equ 40 + +struct TASKDATA + event_mask dd ? + pid dd ? + dw ? + state db ? + db ? + dw ? + wnd_number db ? + db ? + mem_start dd ? + counter_sum dd ? + counter_add dd ? + cpu_usage dd ? +ends + +TSTATE_RUNNING = 0 +TSTATE_RUN_SUSPENDED = 1 +TSTATE_WAIT_SUSPENDED = 2 +TSTATE_ZOMBIE = 3 +TSTATE_TERMINATING = 4 +TSTATE_WAITING = 5 +TSTATE_FREE = 9 + +; constants definition +WSTATE_NORMAL = 00000000b +WSTATE_MAXIMIZED = 00000001b +WSTATE_MINIMIZED = 00000010b +WSTATE_ROLLEDUP = 00000100b + +WSTATE_REDRAW = 00000001b +WSTATE_WNDDRAWN = 00000010b + +WSTYLE_HASCAPTION = 00010000b +WSTYLE_CLIENTRELATIVE = 00100000b + +ZPOS_DESKTOP = -2 +ZPOS_ALWAYS_BACK = -1 +ZPOS_NORMAL = 0 +ZPOS_ALWAYS_TOP = 1 ;ZPOS_ALWAYS_TOP is always last and has max number! +; structures definition +struct WDATA + box BOX + cl_workarea dd ? + cl_titlebar dd ? + cl_frames dd ? + z_modif db ? + fl_wstate db ? + fl_wdrawn db ? + fl_redraw db ? +ends + +label WDATA.fl_wstyle byte at WDATA.cl_workarea + 3 + + +struct SYS_VARS + bpp dd ? + scanline dd ? + vesa_mode dd ? + x_res dd ? + y_res dd ? +ends + +struct APPOBJ ; common object header + magic dd ? ; + destroy dd ? ; internal destructor + fd dd ? ; next object in list + bk dd ? ; prev object in list + pid dd ? ; owner id +ends + +struct CURSOR APPOBJ + base dd ? ;allocated memory + hot_x dd ? ;hotspot coords + hot_y dd ? + + list_next dd ? ;next cursor in cursor list + list_prev dd ? ;prev cursor in cursor list + dev_obj dd ? ;device depended data +ends + + +struct EVENT APPOBJ + id dd ? ;event uid + state dd ? ;internal flags + code dd ? + rd 5 +ends + + +struct SMEM + bk dd ? + fd dd ? ;+4 + base dd ? ;+8 + size dd ? ;+12 + access dd ? ;+16 + refcount dd ? ;+20 + name rb 32 ;+24 +ends + +struct SMAP APPOBJ + base dd ? ;mapped base + parent dd ? ;SMEM +ends + +struct DLLDESCR + bk dd ? + fd dd ? ;+4 + data dd ? ;+8 + size dd ? ;+12 + timestamp dq ? + refcount dd ? + defaultbase dd ? + coff_hdr dd ? + symbols_ptr dd ? + symbols_num dd ? + symbols_lim dd ? + exports dd ? ;export table + name rb 260 +ends + +struct HDLL + fd dd ? ;next object in list + bk dd ? ;prev object in list + pid dd ? ;owner id + + base dd ? ;mapped base + size dd ? ;mapped size + refcount dd ? ;reference counter for this process and this lib + parent dd ? ;DLLDESCR +ends + + +struct BOOT_DATA + bpp dd ? + scanline dd ? + vesa_mode dd ? + x_res dd ? + y_res dd ? + mouse_port dd ? + bank_switch dd ? + lfb dd ? + vesa_mem dd ? + log dd ? + direct_lfb dd ? + pci_data dd ? + dd ? + vrr dd ? + ide_base dd ? + mem_amount dd ? + pages_count dd ? + pagemap_size dd ? + kernel_max dd ? + kernel_pages dd ? + kernel_tables dd ? + + cpu_vendor dd ? + dd ? + dd ? + cpu_sign dd ? + cpu_info dd ? + cpu_caps dd ? + dd ? + dd ? +ends + +struct display_t + x dd ? + y dd ? + width dd ? + height dd ? + bits_per_pixel dd ? + vrefresh dd ? + current_lfb dd ? + lfb_pitch dd ? + + win_map_lock RWSEM + win_map dd ? + win_map_pitch dd ? + win_map_size dd ? + + modes dd ? + ddev dd ? + connector dd ? + crtc dd ? + + cr_list.next dd ? + cr_list.prev dd ? + + cursor dd ? + + init_cursor dd ? + select_cursor dd ? + show_cursor dd ? + move_cursor dd ? + restore_cursor dd ? + disable_mouse dd ? + mask_seqno dd ? + check_mouse dd ? + check_m_pixel dd ? + + bytes_per_pixel dd ? +ends + +struct DISPMODE + width dw ? + height dw ? + bpp dw ? + freq dw ? +ends + + +struct PCIDEV + bk dd ? + fd dd ? + vendor_device_id dd ? + class dd ? + devfn db ? + bus db ? + rb 2 + owner dd ? ; pointer to SRV or 0 +ends + +struct IDE_DATA + ProgrammingInterface dd ? + Interrupt dw ? + RegsBaseAddres dw ? + BAR0_val dw ? + BAR1_val dw ? + BAR2_val dw ? + BAR3_val dw ? + dma_hdd_channel_1 db ? + dma_hdd_channel_2 db ? + pcidev dd ? ; pointer to corresponding PCIDEV structure +ends + +struct IDE_CACHE + pointer dd ? + size dd ? ; not use + data_pointer dd ? + system_data_size dd ? ; not use + appl_data_size dd ? ; not use + system_data dd ? + appl_data dd ? + system_sad_size dd ? + appl_sad_size dd ? + search_start dd ? + appl_search_start dd ? +ends + +struct IDE_DEVICE + UDMA_possible_modes db ? + UDMA_set_mode db ? +ends + +; The following macro assume that we are on uniprocessor machine. +; Serious work is needed for multiprocessor machines. +macro spin_lock_irqsave spinlock +{ + pushf + cli +} +macro spin_unlock_irqrestore spinlock +{ + popf +} +macro spin_lock_irq spinlock +{ + cli +} +macro spin_unlock_irq spinlock +{ + sti +} + +struct MEM_STATE + mutex MUTEX + smallmap dd ? + treemap dd ? + topsize dd ? + top dd ? + smallbins rd 4*32 + treebins rd 32 +ends + +struct PG_DATA + mem_amount dd ? + vesa_mem dd ? + pages_count dd ? + pages_free dd ? + pages_faults dd ? + pagemap_size dd ? + kernel_pages dd ? + kernel_tables dd ? + sys_page_dir dd ? + mutex MUTEX +ends + +struct SRV + srv_name rb 16 ;ASCIIZ string + magic dd ? ;+0x10 ;'SRV ' + size dd ? ;+0x14 ;size of structure SRV + fd dd ? ;+0x18 ;next SRV descriptor + bk dd ? ;+0x1C ;prev SRV descriptor + base dd ? ;+0x20 ;service base address + entry dd ? ;+0x24 ;service START function + srv_proc dd ? ;+0x28 ;user mode service handler + srv_proc_ex dd ? ;+0x2C ;kernel mode service handler +ends + +struct USBSRV + srv SRV + usb_func dd ? +ends + +struct USBFUNC + strucsize dd ? + add_device dd ? + device_disconnect dd ? +ends + +DRV_ENTRY equ 1 +DRV_EXIT equ -1 + +struct COFF_HEADER + machine dw ? + nSections dw ? + DataTime dd ? + pSymTable dd ? + nSymbols dd ? + optHeader dw ? + flags dw ? +ends + +struct COFF_SECTION + Name rb 8 + VirtualSize dd ? + VirtualAddress dd ? + SizeOfRawData dd ? + PtrRawData dd ? + PtrReloc dd ? + PtrLinenumbers dd ? + NumReloc dw ? + NumLinenum dw ? + Characteristics dd ? +ends + +struct COFF_RELOC + VirtualAddress dd ? + SymIndex dd ? + Type dw ? +ends + +struct COFF_SYM + Name rb 8 + Value dd ? + SectionNumber dw ? + Type dw ? + StorageClass db ? + NumAuxSymbols db ? +ends + +struct STRIPPED_PE_HEADER + Signature dw ? + Characteristics dw ? + AddressOfEntryPoint dd ? + ImageBase dd ? + SectionAlignmentLog db ? + FileAlignmentLog db ? + MajorOSVersion db ? + MinorOSVersion db ? + SizeOfImage dd ? + SizeOfStackReserve dd ? + SizeOfHeapReserve dd ? + SizeOfHeaders dd ? + Subsystem db ? + NumberOfRvaAndSizes db ? + NumberOfSections dw ? +ends +STRIPPED_PE_SIGNATURE = 0x4503 ; 'PE' xor 'S' +SPE_DIRECTORY_IMPORT = 0 +SPE_DIRECTORY_EXPORT = 1 +SPE_DIRECTORY_BASERELOC = 2 + +struct IOCTL + handle dd ? + io_code dd ? + input dd ? + inp_size dd ? + output dd ? + out_size dd ? +ends + +struct IRQH + list LHEAD + handler dd ? ;handler roututine + data dd ? ;user-specific data + num_ints dd ? ;how many times handled +ends diff --git a/debug-fdo.inc b/debug-fdo.inc new file mode 100644 index 0000000..96a7a07 --- /dev/null +++ b/debug-fdo.inc @@ -0,0 +1,435 @@ +; +; Formatted Debug Output (FDO) +; Copyright (c) 2005-2006, mike.dld +; Created: 2005-01-29, Changed: 2006-11-10 +; +; For questions and bug reports, mail to mike.dld@gmail.com +; +; Available format specifiers are: %s, %d, %u, %x (with partial width support) +; + +; to be defined: +; __DEBUG__ equ 1 +; __DEBUG_LEVEL__ equ 5 + +macro debug_func name { + if used name + name@of@func equ name +} + +macro debug_beginf { + align 4 + name@of@func: +} + +debug_endf fix end if + +macro DEBUGS _sign,[_str] { + common + local tp + tp equ 0 + match _arg:_num,_str \{ + DEBUGS_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _str \{ + DEBUGS_N _sign,,_arg + \} +} + +macro DEBUGS_N _sign,_num,[_str] { + common + pushf + pushad + local ..str,..label,is_str + is_str = 0 + forward + if _str eqtype '' + is_str = 1 + end if + common + if is_str = 1 + jmp ..label + ..str db _str,0 + ..label: + add esp,4*8+4 + mov edx,..str + sub esp,4*8+4 + else + mov edx,_str + end if + if ~_num eq + if _num eqtype eax + if _num in + mov esi,_num + else if ~_num eq esi + movzx esi,_num + end if + else if _num eqtype 0 + mov esi,_num + else + local tp + tp equ 0 + match [_arg],_num \{ + mov esi,dword[_arg] + tp equ 1 + \} + match =0 =dword[_arg],tp _num \{ + mov esi,dword[_arg] + tp equ 1 + \} + match =0 =word[_arg],tp _num \{ + movzx esi,word[_arg] + tp equ 1 + \} + match =0 =byte[_arg],tp _num \{ + movzx esi,byte[_arg] + tp equ 1 + \} + match =0,tp \{ + 'Error: specified string width is incorrect' + \} + end if + else + mov esi,0x7FFFFFFF + end if + call fdo_debug_outstr + popad + popf +} + +macro DEBUGD _sign,_dec { + local tp + tp equ 0 + match _arg:_num,_dec \{ + DEBUGD_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _dec \{ + DEBUGD_N _sign,,_arg + \} +} + +macro DEBUGD_N _sign,_num,_dec { + pushf + pushad + if (~_num eq) + if (_dec eqtype eax | _dec eqtype 0) + 'Error: precision allowed only for in-memory variables' + end if + if (~_num in <1,2,4>) + if _sign + 'Error: 1, 2 and 4 are only allowed for precision in %d' + else + 'Error: 1, 2 and 4 are only allowed for precision in %u' + end if + end if + end if + if _dec eqtype eax + if _dec in + mov eax,_dec + else if ~_dec eq eax + if _sign = 1 + movsx eax,_dec + else + movzx eax,_dec + end if + end if + else if _dec eqtype 0 + mov eax,_dec + else + add esp,4*8+4 + if _num eq + mov eax,dword _dec + else if _num = 1 + if _sign = 1 + movsx eax,byte _dec + else + movzx eax,byte _dec + end if + else if _num = 2 + if _sign = 1 + movsx eax,word _dec + else + movzx eax,word _dec + end if + else + mov eax,dword _dec + end if + sub esp,4*8+4 + end if + mov cl,_sign + call fdo_debug_outdec + popad + popf +} + +macro DEBUGH _sign,_hex { + local tp + tp equ 0 + match _arg:_num,_hex \{ + DEBUGH_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _hex \{ + DEBUGH_N _sign,,_arg + \} +} + +macro DEBUGH_N _sign,_num,_hex { + pushf + pushad + if (~_num eq) & (~_num in <1,2,3,4,5,6,7,8>) + 'Error: 1..8 are only allowed for precision in %x' + end if + if _hex eqtype eax + if _hex in + if ~_hex eq eax + mov eax,_hex + end if + else if _hex in + if ~_hex eq ax + movzx eax,_hex + end if + shl eax,16 + if (_num eq) + mov edx,4 + end if + else if _hex in + if ~_hex eq al + movzx eax,_hex + end if + shl eax,24 + if (_num eq) + mov edx,2 + end if + end if + else if _hex eqtype 0 + mov eax,_hex + else + add esp,4*8+4 + mov eax,dword _hex + sub esp,4*8+4 + end if + if ~_num eq + mov edx,_num + else + mov edx,8 + end if + call fdo_debug_outhex + popad + popf +} + +;----------------------------------------------------------------------------- + +debug_func fdo_debug_outchar +debug_beginf + pushad + mov cl,al + mov ebx,1 + mov eax,63 +; mcall + call put_board + popad + ret +debug_endf + +debug_func fdo_debug_outstr +debug_beginf + mov eax,63 + mov ebx,1 + .l1: dec esi + js .l2 + mov cl,[edx] + or cl,cl + jz .l2 +; mcall + call put_board + inc edx + jmp .l1 + .l2: ret +debug_endf + +debug_func fdo_debug_outdec +debug_beginf + or cl,cl + jz @f + or eax,eax + jns @f + neg eax + push eax + mov al,'-' + call fdo_debug_outchar + pop eax + @@: push 10 + pop ecx + push -'0' + .l1: xor edx,edx + div ecx + push edx + test eax,eax + jnz .l1 + .l2: pop eax + add al,'0' + jz .l3 + call fdo_debug_outchar + jmp .l2 + .l3: ret +debug_endf + +debug_func fdo_debug_outhex + __fdo_hexdigits db '0123456789ABCDEF' +debug_beginf + mov cl,dl + neg cl + add cl,8 + shl cl,2 + rol eax,cl + .l1: rol eax,4 + push eax + and eax,0x0000000F + mov al,[__fdo_hexdigits+eax] + call fdo_debug_outchar + pop eax + dec edx + jnz .l1 + ret +debug_endf + +;----------------------------------------------------------------------------- + +macro DEBUGF _level,_format,[_arg] { + common + if __DEBUG__ = 1 & _level >= __DEBUG_LEVEL__ + local ..f1,f2,a1,a2,c1,c2,c3,..lbl + _debug_str_ equ __debug_str_ # a1 + a1 = 0 + c2 = 0 + c3 = 0 + f2 = 0 + repeat ..lbl-..f1 + virtual at 0 + db _format,0,0 + load c1 word from %-1 + end virtual + if c1 = '%s' + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER S,a1,0,_arg + else if c1 = '%x' + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER H,a1,0,_arg + else if c1 = '%d' | c1 = '%u' + local c4 + if c1 = '%d' + c4 = 1 + else + c4 = 0 + end if + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER D,a1,c4,_arg + else if c1 = '\n' + c3 = c3 + 1 + end if + end repeat + virtual at 0 + db _format,0,0 + load c1 from f2-c2 + end virtual + if (c1<>0)&(f2<>..lbl-..f1-1) + DEBUGS 0,_debug_str_+f2-c2 + end if + virtual at 0 + ..f1 db _format,0 + ..lbl: + __debug_strings equ __debug_strings,_debug_str_,<_format>,..lbl-..f1-1-c2-c3 + end virtual + end if +} + +macro DEBUGFG _level, _group, _format, [_arg] { + common + if _group eqtype + DEBUGF _level, _format,_arg + else + if _level >= _group + DEBUGF 999, _format,_arg + end if + end if +} + +macro __include_debug_strings dummy,[_id,_fmt,_len] { + common + local c1,a1,a2 + forward + if defined _len & ~_len eq + _id: + a1 = 0 + a2 = 0 + repeat _len + virtual at 0 + db _fmt,0,0 + load c1 word from %+a2-1 + end virtual + if (c1='%s')|(c1='%x')|(c1='%d')|(c1='%u') + db 0 + a2 = a2 + 1 + else if (c1='\n') + dw $0A0D + a1 = a1 + 1 + a2 = a2 + 1 + else + db c1 and 0x0FF + end if + end repeat + db 0 + end if +} + +macro DEBUGF_HELPER _letter,_num,_sign,[_arg] { + common + local num + num = 0 + forward + if num = _num + DEBUG#_letter _sign,_arg + end if + num = num+1 + common + _num = _num+1 +} + +macro include_debug_strings { + if __DEBUG__ = 1 + match dbg_str,__debug_strings \{ + __include_debug_strings dbg_str + \} + end if +} diff --git a/disk.inc b/disk.inc new file mode 100644 index 0000000..81e21a0 --- /dev/null +++ b/disk.inc @@ -0,0 +1,203 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2011-2015. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 6917 $ + +; ============================================================================= +; ================================= Constants ================================= +; ============================================================================= +; Error codes for callback functions. +DISK_STATUS_OK = 0 ; success +DISK_STATUS_GENERAL_ERROR = -1; if no other code is suitable +DISK_STATUS_INVALID_CALL = 1 ; invalid input parameters +DISK_STATUS_NO_MEDIA = 2 ; no media present +DISK_STATUS_END_OF_MEDIA = 3 ; end of media while reading/writing data +DISK_STATUS_NO_MEMORY = 4 ; insufficient memory for driver operation +; Driver flags. Represent bits in DISK.DriverFlags. +DISK_NO_INSERT_NOTIFICATION = 1 +; Media flags. Represent bits in DISKMEDIAINFO.Flags. +DISK_MEDIA_READONLY = 1 + +; If too many partitions are detected,there is probably an error on the disk. +; 256 partitions should be enough for any reasonable use. +; Also, the same number is limiting the number of MBRs to process; if +; too many MBRs are visible,there probably is a loop in the MBR structure. +MAX_NUM_PARTITIONS = 256 + +; This structure holds information on a medium. +; Objects with this structure are allocated by the kernel as a part of the DISK +; structure and are filled by a driver in the 'querymedia' callback. +struct DISKMEDIAINFO + Flags dd ? +; Combination of DISK_MEDIA_* bits. + SectorSize dd ? +; Size of the sector. + Capacity dq ? +; Size of the media in sectors. +ends + +; This structure represents the disk cache. To follow the old implementation, +; there are two distinct caches for a disk, one for "system" data,and the other +; for "application" data. +struct DISKCACHE +; The following fields are inherited from data32.inc:cache_ideX. + pointer dd ? + data_size dd ? ; unused + data dd ? + sad_size dd ? + search_start dd ? + sector_size_log dd ? +ends + +; This structure represents a disk device and its media for the kernel. +; This structure is allocated by the kernel in the 'disk_add' function, +; freed in the 'disk_dereference' function. +struct DISK +; Fields of disk object + Next dd ? + Prev dd ? +; All disk devices are linked in one list with these two fields. +; Head of the list is the 'disk_list' variable. + Functions dd ? +; Pointer to the 'DISKFUNC' structure with driver functions. + Name dd ? +; Pointer to the string used for accesses through the global filesystem. + UserData dd ? +; This field is passed to all callback functions so a driver can decide which +; physical device is addressed. + DriverFlags dd ? +; Bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit is defined. +; If it is set, the driver will never issue 'disk_media_changed' notification +; with argument set to true, so the kernel must try to detect media during +; requests from the file system. + RefCount dd ? +; Count of active references to this structure. One reference is kept during +; the lifetime of the structure between 'disk_add' and 'disk_del'. +; Another reference is taken during any filesystem operation for this disk. +; One reference is added if media is inserted. +; The structure is destroyed when the reference count decrements to zero: +; this usually occurs in 'disk_del', but can be delayed to the end of last +; filesystem operation, if one is active. + MediaLock MUTEX +; Lock to protect the MEDIA structure. See the description after +; 'disk_list_mutex' for the locking strategy. +; Fields of media object + MediaInserted db ? +; 0 if media is not inserted, nonzero otherwise. + MediaUsed db ? +; 0 if media fields are not used, nonzero otherwise. If .MediaRefCount is +; nonzero, this field is nonzero too; however, when .MediaRefCount goes +; to zero, there is some time interval during which media object is still used. + dw ? ; padding +; The following fields are not valid unless either .MediaInserted is nonzero +; or they are accessed from a code which has obtained the reference when +; .MediaInserted was nonzero. + MediaRefCount dd ? +; Count of active references to the media object. One reference is kept during +; the lifetime of the media between two calls to 'disk_media_changed'. +; Another reference is taken during any filesystem operation for this media. +; The callback 'closemedia' is called when the reference count decrements to +; zero: this usually occurs in 'disk_media_changed', but can be delayed to the +; end of the last filesystem operation, if one is active. + MediaInfo DISKMEDIAINFO +; This field keeps information on the current media. + NumPartitions dd ? +; Number of partitions on this media. + Partitions dd ? +; Pointer to array of .NumPartitions pointers to PARTITION structures. + cache_size dd ? +; inherited from cache_ideX_size + CacheLock MUTEX +; Lock to protect both caches. + SysCache DISKCACHE + AppCache DISKCACHE +; Two caches for the disk. +ends + +; This structure represents one partition for the kernel. This is a base +; template, the actual contents after common fields is determined by the +; file system code for this partition. +struct PARTITION + FirstSector dq ? +; First sector of the partition. + Length dq ? +; Length of the partition in sectors. + Disk dd ? +; Pointer to parent DISK structure. + FSUserFunctions dd ? +; Handlers for the sysfunction 70h. This field is a pointer to the following +; array. The first dword is pointer to disconnect handler. +; The first dword is a number of supported subfunctions, other dwords +; point to handlers of corresponding subfunctions. +; ...fs-specific data may follow... +ends + +; This is an external structure, it represents an entry in the partition table. +struct PARTITION_TABLE_ENTRY + Bootable db ? +; 80h = bootable partition, 0 = non-bootable partition, other values = invalid + FirstHead db ? + FirstSector db ? + FirstTrack db ? +; Coordinates of first sector in CHS. + Type db ? +; Partition type, one of predefined constants. 0 = empty, several types denote +; extended partition (see process_partition_table_entry), we are not interested +; in other values. + LastHead db ? + LastSector db ? + LastTrack db ? +; Coordinates of last sector in CHS. + FirstAbsSector dd ? +; Coordinate of first sector in LBA. + Length dd ? +; Length of the partition in sectors. +ends + +; GUID Partition Table Header, UEFI 2.6, Table 18 +struct GPTH + Signature rb 8 +; 'EFI PART' + Revision dd ? +; 0x00010000 + HeaderSize dd ? +; Size of this header in bytes, must fit to one sector. + HeaderCRC32 dd ? +; Set this field to zero, compute CRC32 via 0xEDB88320, compare. + Reserved dd ? +; Must be zero. + MyLBA dq ? +; LBA of the sector containing this GPT header. + AlternateLBA dq ? +; LBA of the sector containing the other GPT header. +; AlternateLBA of Primary GPTH points to Backup one and vice versa. + FirstUsableLBA dq ? +; Only sectors between first and last UsableLBA may form partitions + LastUsableLBA dq ? + DiskGUID rb 16 +; Globally Unique IDentifier + PartitionEntryLBA dq ? +; First LBA of Partition Entry Array. +; Length in bytes is computed as a product of two following fields. + NumberOfPartitionEntries dd ? +; Actual number of partitions depends on the contents of Partition Entry Array. +; A partition entry is unused if zeroed. + SizeOfPartitionEntry dd ? ; in bytes + PartitionEntryArrayCRC32 dd ? +; Same CRC as for GPT header. +ends + +; GPT Partition Entry, UEFI 2.6, Table 19 +struct GPE + PartitionTypeGUID rb 16 + UniquePartitionGUID rb 16 + StartingLBA dq ? + EndingLBA dq ? +; Length in sectors is EndingLBA - StartingLBA + 1. + Attributes dq ? + PartitionName rb 72 +ends diff --git a/fdo.inc b/fdo.inc new file mode 100644 index 0000000..8adb226 --- /dev/null +++ b/fdo.inc @@ -0,0 +1,441 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 5363 $ + +_esp equ esp + +; +; Formatted Debug Output (FDO) +; Copyright (c) 2005-2006, mike.dld +; Created: 2005-01-29, Changed: 2006-11-10 +; +; For questions and bug reports, mail to mike.dld@gmail.com +; +; Available format specifiers are: %s, %d, %u, %x (with partial width support) +; + +; to be defined: +; __DEBUG__ equ 1 +; __DEBUG_LEVEL__ equ 5 + +macro debug_func name { + if used name + name@of@func equ name +} + +macro debug_beginf { + align 4 + name@of@func: +} + +debug_endf fix end if + +macro DEBUGS _sign,[_str] { + common + local tp + tp equ 0 + match _arg:_num,_str \{ + DEBUGS_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _str \{ + DEBUGS_N _sign,,_arg + \} +} + +macro DEBUGS_N _sign,_num,[_str] { + common + pushf + pushad + local ..str,..label,is_str + is_str = 0 + forward + if _str eqtype '' + is_str = 1 + end if + common + if is_str = 1 + jmp ..label + ..str db _str,0 + ..label: + mov edx, ..str + else +esp equ esp+4*8+4 + mov edx, _str +esp equ _esp + end if + if ~_num eq + if _num eqtype eax + if _num in + mov esi, _num + else if ~_num eq esi + movzx esi, _num + end if + else if _num eqtype 0 + mov esi, _num + else + local tp + tp equ 0 + match [_arg],_num \{ + mov esi, dword[_arg] + tp equ 1 + \} + match =0 =dword[_arg],tp _num \{ + mov esi, dword[_arg] + tp equ 1 + \} + match =0 =word[_arg],tp _num \{ + movzx esi, word[_arg] + tp equ 1 + \} + match =0 =byte[_arg],tp _num \{ + movzx esi, byte[_arg] + tp equ 1 + \} + match =0,tp \{ + 'Error: specified string width is incorrect' + \} + end if + else + mov esi, 0x7FFFFFFF + end if + call fdo_debug_outstr + popad + popf +} + +macro DEBUGD _sign,_dec { + local tp + tp equ 0 + match _arg:_num,_dec \{ + DEBUGD_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _dec \{ + DEBUGD_N _sign,,_arg + \} +} + +macro DEBUGD_N _sign,_num,_dec { + pushf + pushad + if (~_num eq) + if (_dec eqtype eax | _dec eqtype 0) + 'Error: precision allowed only for in-memory variables' + end if + if (~_num in <1,2,4>) + if _sign + 'Error: 1, 2 and 4 are only allowed for precision in %d' + else + 'Error: 1, 2 and 4 are only allowed for precision in %u' + end if + end if + end if + if _dec eqtype eax + if _dec in + mov eax, _dec + else if ~_dec eq eax + if _sign = 1 + movsx eax, _dec + else + movzx eax, _dec + end if + end if + else if _dec eqtype 0 + mov eax, _dec + else +; add esp,4*8+4 +esp equ esp+4*8+4 + if _num eq + mov eax, dword _dec + else if _num = 1 + if _sign = 1 + movsx eax, byte _dec + else + movzx eax, byte _dec + end if + else if _num = 2 + if _sign = 1 + movsx eax, word _dec + else + movzx eax, word _dec + end if + else + mov eax, dword _dec + end if +esp equ _esp +; sub esp,4*8+4 + end if + mov cl, _sign + call fdo_debug_outdec + popad + popf +} + +macro DEBUGH _sign,_hex { + local tp + tp equ 0 + match _arg:_num,_hex \{ + DEBUGH_N _sign,_num,_arg + tp equ 1 + \} + match =0 _arg,tp _hex \{ + DEBUGH_N _sign,,_arg + \} +} + +macro DEBUGH_N _sign,_num,_hex { + pushf + pushad + if (~_num eq) & (~_num in <1,2,3,4,5,6,7,8>) + 'Error: 1..8 are only allowed for precision in %x' + end if + if _hex eqtype eax + if _hex in + if ~_hex eq eax + mov eax, _hex + end if + mov edx, 8 + else if _hex in + if ~_hex eq ax + movzx eax, _hex + end if + if (_num eq) + mov edx, 4 + end if + else if _hex in + if ~_hex eq al + movzx eax, _hex + end if + if (_num eq) + mov edx, 2 + end if + end if + else if _hex eqtype 0 + mov eax, _hex + else +; add esp,4*8+4 +esp equ esp+4*8+4 + mov eax, dword _hex +esp equ _esp +; sub esp,4*8+4 + end if + if ~_num eq + mov edx, _num + else + if ~_hex eqtype eax + mov edx, 8 + end if + end if + call fdo_debug_outhex + popad + popf +} + +;----------------------------------------------------------------------------- + +debug_func fdo_debug_outchar +debug_beginf + pushad + movzx ecx, al + mov ebx, 1 + call sys_msg_board + popad + ret +debug_endf + +debug_func fdo_debug_outstr +debug_beginf + mov ebx, 1 + .l1: + dec esi + js .l2 + movzx ecx, byte[edx] + or cl, cl + jz .l2 + call sys_msg_board + inc edx + jmp .l1 + .l2: + ret +debug_endf + +debug_func fdo_debug_outdec +debug_beginf + or cl, cl + jz @f + or eax, eax + jns @f + neg eax + push eax + mov al, '-' + call fdo_debug_outchar + pop eax + @@: + movi ecx, 10 + push -'0' + .l1: + xor edx, edx + div ecx + push edx + test eax, eax + jnz .l1 + .l2: + pop eax + add al, '0' + jz .l3 + call fdo_debug_outchar + jmp .l2 + .l3: + ret +debug_endf + +debug_func fdo_debug_outhex + __fdo_hexdigits db '0123456789ABCDEF' +debug_beginf + mov cl, dl + neg cl + add cl, 8 + shl cl, 2 + rol eax, cl + .l1: + rol eax, 4 + push eax + and eax, 0x0000000F + mov al, [__fdo_hexdigits+eax] + call fdo_debug_outchar + pop eax + dec edx + jnz .l1 + ret +debug_endf + +;----------------------------------------------------------------------------- + +macro DEBUGF _level,_format,[_arg] { + common + if __DEBUG__ = 1 & _level >= __DEBUG_LEVEL__ + local ..f1,f2,a1,a2,c1,c2,c3,..lbl + _debug_str_ equ __debug_str_ # a1 + a1 = 0 + c2 = 0 + c3 = 0 + f2 = 0 + repeat ..lbl-..f1 + virtual at 0 + db _format,0,0 + load c1 word from %-1 + end virtual + if c1 = '%s' + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER S,a1,0,_arg + else if c1 = '%x' + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER H,a1,0,_arg + else if c1 = '%d' | c1 = '%u' + local c4 + if c1 = '%d' + c4 = 1 + else + c4 = 0 + end if + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER D,a1,c4,_arg + else if c1 = '\n' + c3 = c3 + 1 + end if + end repeat + virtual at 0 + db _format,0,0 + load c1 from f2-c2 + end virtual + if (c1<>0)&(f2<>..lbl-..f1-1) + DEBUGS 0,_debug_str_+f2-c2 + end if + virtual at 0 + ..f1 db _format,0 + ..lbl: + __debug_strings equ __debug_strings,_debug_str_,<_format>,..lbl-..f1-1-c2-c3 + end virtual + end if +} + +macro __include_debug_strings dummy,[_id,_fmt,_len] { + common + local c1,a1,a2 + forward + if defined _len & ~_len eq + _id: + a1 = 0 + a2 = 0 + repeat _len + virtual at 0 + db _fmt,0,0 + load c1 word from %+a2-1 + end virtual + if (c1='%s')|(c1='%x')|(c1='%d')|(c1='%u') + db 0 + a2 = a2 + 1 + else if (c1='\n') + dw $0A0D + a1 = a1 + 1 + a2 = a2 + 1 + else + db c1 and 0x0FF + end if + end repeat + db 0 + end if +} + +macro DEBUGF_HELPER _letter,_num,_sign,[_arg] { + common + local num + num = 0 + forward + if num = _num + DEBUG#_letter _sign,_arg + end if + num = num+1 + common + _num = _num+1 +} + +macro include_debug_strings { + if __DEBUG__ = 1 + match dbg_str,__debug_strings \{ + __include_debug_strings dbg_str + \} + end if +} diff --git a/fs_common.inc b/fs_common.inc new file mode 100644 index 0000000..e10a22c --- /dev/null +++ b/fs_common.inc @@ -0,0 +1,142 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License. ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 6462 $ + +fsReadCMOS: + out 70h, al + in al, 71h + xor ah, ah + shl ax, 4 + shr al, 4 + aad + ret + +fsGetTime: + mov al, 7 + call fsReadCMOS + ror eax, 8 + mov al, 8 + call fsReadCMOS + ror eax, 8 + mov al, 9 + call fsReadCMOS + add eax, 2000 + ror eax, 16 + push eax + xor eax, eax + call fsReadCMOS + ror eax, 8 + mov al, 2 + call fsReadCMOS + ror eax, 8 + mov al, 4 + call fsReadCMOS + ror eax, 16 + push eax + mov esi, esp + add esp, 8 +fsCalculateTime: +; in: esi -> data block +; out: eax = seconds since 01.01.2001 + movzx eax, word [esi+6] + sub eax, 2001 + jnc @f + xor eax, eax +@@: + mov edx, months + mov ebx, eax + inc eax + test eax, 3 + jnz @f + add edx, 12 +@@: + movzx eax, byte [esi+5] + dec eax + xor ecx, ecx +@@: + dec eax + js @f + add cl, [edx+eax] + adc ch, 0 + jmp @b +@@: + mov eax, ebx ; years + mov edx, 365 + mul edx + shr ebx, 2 + add eax, ebx + add eax, ecx + mov bl, [esi+4] + dec eax + add eax, ebx ; days + mov dl, 24 + mul edx + mov bl, [esi+2] + add eax, ebx ; hours + mov ecx, 60 + mul ecx + mov bl, [esi+1] + add eax, ebx ; minutes + mul ecx + mov bl, [esi] + add eax, ebx + ret + +;iglobal +months db 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +months2 db 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +;endg + +fsTime2bdfe: +; in: eax = seconds since 01.01.2001 +; edi -> data block +; out: edi = edi+8 + xor edx, edx + mov ecx, 60 + div ecx + mov [edi], dl + xor edx, edx + div ecx + mov [edi+1], dl + xor edx, edx + mov cl, 24 + div ecx + mov [edi+2], dx + xor edx, edx + mov cx, 365 + div ecx + mov ebx, eax + add ebx, 2001 + shr eax, 2 + sub edx, eax + jns @f + dec ebx + add edx, 365 + test ebx, 3 + jnz @f + inc edx +@@: + xor eax, eax + mov ecx, months-1 + test ebx, 3 + jnz @f + add ecx, 12 +@@: + inc ecx + inc eax + sub dl, [ecx] + jnc @b + dec dh + jns @b + add dl, [ecx] + inc edx + mov [edi+4], dl + mov [edi+5], al + mov [edi+6], bx + add edi, 8 + ret diff --git a/kglobals.inc b/kglobals.inc new file mode 100644 index 0000000..1abadec --- /dev/null +++ b/kglobals.inc @@ -0,0 +1,69 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 5363 $ + + +;------------------------------------------------------------------ +; use "iglobal" for inserting initialized global data definitions. +;------------------------------------------------------------------ +macro iglobal { + IGlobals equ IGlobals, + macro __IGlobalBlock { } + +macro iglobal_nested { + IGlobals equ IGlobals, + macro __IGlobalBlock \{ } + +;------------------------------------------------------------- +; use 'uglobal' for inserting uninitialized global definitions. +; even when you define some data values, these variables +; will be stored as uninitialized data. +;------------------------------------------------------------- +macro uglobal { + UGlobals equ UGlobals, + macro __UGlobalBlock { } + +macro uglobal_nested { + UGlobals equ UGlobals, + macro __UGlobalBlock \{ } + +endg fix } ; Use endg for ending iglobal and uglobal blocks. +endg_nested fix \} + +macro IncludeIGlobals{ + macro IGlobals dummy,[n] \{ __IGlobalBlock + purge __IGlobalBlock \} + match I, IGlobals \{ I \} } + + +macro IncludeUGlobals{ + macro UGlobals dummy,[n] \{ + \common + \local begin, size + begin = $ + virtual at $ + \forward + __UGlobalBlock + purge __UGlobalBlock + \common + size = $ - begin + end virtual + rb size + \} + match U, UGlobals \{ U \} } + +macro IncludeAllGlobals { + IncludeIGlobals + IncludeUGlobals +} + +iglobal +endg + +uglobal +endg diff --git a/macros.inc b/macros.inc new file mode 100644 index 0000000..2db0846 --- /dev/null +++ b/macros.inc @@ -0,0 +1,99 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +__REV = 0 + +macro $Revision a { + match =: Num =$,a \{ + if __REV < Num + __REV = Num + end if + \} +} + +$Revision: 5788 $ + + +;// mike.dld, 2006-29-01 [ + +; macros definition +macro diff16 title,l1,l2 +{ + local s,d + s = l2-l1 + display title,': 0x' + repeat 16 + d = 48 + s shr ((16-%) shl 2) and $0F + if d > 57 + d = d + 65-57-1 + end if + display d + end repeat + display 13,10 +} +macro diff10 title,l1,l2 + { + local s,d,z,m + s = l2-l1 + z = 0 + m = 1000000000 + display title,': ' + repeat 10 + d = '0' + s / m + s = s - (s/m)*m + m = m / 10 + if d <> '0' + z = 1 + end if + if z <> 0 + display d + end if + end repeat + display 13,10 + } + +include 'kglobals.inc' + +; \begin{diamond}[29.09.2006] +; may be useful for kernel debugging +; example 1: +; dbgstr 'Hello, World!' +; example 2: +; dbgstr 'Hello, World!', save_flags +macro dbgstr string*, f +{ +local a +iglobal_nested +a db 'K : ',string,13,10,0 +endg_nested +if ~ f eq + pushfd +end if + push esi + mov esi, a + call sys_msg_board_str + pop esi +if ~ f eq + popfd +end if +} +; \end{diamond}[29.09.2006] + + +; MOV Immediate. +; Useful for things like movi eax,10: +; shorter than regular mov, but slightly slower, +; do not use it in performance-critical places. +macro movi dst, imm +{ +if imm >= -0x80 & imm <= 0x7F + push imm + pop dst +else + mov dst, imm +end if +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..f69eac5 --- /dev/null +++ b/makefile @@ -0,0 +1,25 @@ +FASM=fasm + +all: xfskosfuse + +#xfskos: xfskos.o +# ld *.o -o $@ -m elf_i386 -nostdlib +# strip $@ + +xfskos.o: xfskos.asm xfs.inc xfs.asm + $(FASM) $< $@ + +xfskosfuse: xfskosfuse.o xfskos.o + gcc -m32 -Wall $^ -o $@ -D_FILE_OFFSET_BITS=64 -lfuse -g3 -O0 + +xfskosfuse.o: xfskosfuse.c + gcc -m32 -Wall -c $< -D_FILE_OFFSET_BITS=64 -g3 -O0 + +.PHONY: all clean check + +clean: + rm -f *.o xfskos + +check: xfskos + echo ok + diff --git a/proc32.inc b/proc32.inc new file mode 100644 index 0000000..aa3ffc9 --- /dev/null +++ b/proc32.inc @@ -0,0 +1,270 @@ + +; Macroinstructions for defining and calling procedures + +macro stdcall proc,[arg] ; directly call STDCALL procedure + { common + if ~ arg eq + reverse + pushd arg + common + end if + call proc } + +macro invoke proc,[arg] ; indirectly call STDCALL procedure + { common + if ~ arg eq + reverse + pushd arg + common + end if + call [proc] } + +macro ccall proc,[arg] ; directly call CDECL procedure + { common + size@ccall = 0 + if ~ arg eq + reverse + pushd arg + size@ccall = size@ccall+4 + common + end if + call proc + if size@ccall + add esp,size@ccall + end if } + +macro cinvoke proc,[arg] ; indirectly call CDECL procedure + { common + size@ccall = 0 + if ~ arg eq + reverse + pushd arg + size@ccall = size@ccall+4 + common + end if + call [proc] + if size@ccall + add esp,size@ccall + end if } + +macro proc [args] ; define procedure + { common + match name params, args> + \{ define@proc name, \{ prologue name,flag,parmbytes,localbytes,reglist \} + macro locals + \{ virtual at ebp-localbytes+current + macro label def \\{ match . type,def> \\\{ deflocal@proc .,label, + \\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \} + macro finish@proc \{ localbytes = (((current-1) shr 2)+1) shl 2 + end if \} } + +macro defargs@proc [arg] + { common + if ~ arg eq + forward + local ..arg,current@arg + match argname:type, arg + \{ current@arg equ argname + label ..arg type + argname equ ..arg + if dqword eq type + dd ?,?,?,? + else if tbyte eq type + dd ?,?,? + else if qword eq type | pword eq type + dd ?,? + else + dd ? + end if \} + match =current@arg,current@arg + \{ current@arg equ arg + arg equ ..arg + ..arg dd ? \} + common + args@proc equ current@arg + forward + restore current@arg + common + end if } + +macro deflocal@proc name,def,[val] + { common + match vars, all@vars \{ all@vars equ all@vars, \} + all@vars equ all@vars name + forward + local ..var,..tmp + match =label,def \{ ..tmp equ \} + match tmp,..tmp \{ ..var def val \} + match ,..tmp \{ label ..var val \} + match =?, val \{ ..tmp equ \} + match any =dup (=?), val \{ ..tmp equ \} + match tmp : value, ..tmp : val + \{ tmp: end virtual + initlocal@proc ..var,def value + virtual at tmp\} + common + match first rest, ..var, \{ name equ first \} } + +macro initlocal@proc name,def + { virtual at name + def + size@initlocal = $ - name + end virtual + position@initlocal = 0 + while size@initlocal > position@initlocal + virtual at name + def + if size@initlocal - position@initlocal < 2 + current@initlocal = 1 + load byte@initlocal byte from name+position@initlocal + else if size@initlocal - position@initlocal < 4 + current@initlocal = 2 + load word@initlocal word from name+position@initlocal + else + current@initlocal = 4 + load dword@initlocal dword from name+position@initlocal + end if + end virtual + if current@initlocal = 1 + mov byte [name+position@initlocal],byte@initlocal + else if current@initlocal = 2 + mov word [name+position@initlocal],word@initlocal + else + mov dword [name+position@initlocal],dword@initlocal + end if + position@initlocal = position@initlocal + current@initlocal + end while } + +macro endp + { purge ret,locals,endl + finish@proc + purge finish@proc + restore regs@proc + match all,args@proc \{ restore all \} + restore args@proc + match all,all@vars \{ restore all \} } + +macro local [var] + { common + locals + forward done@local equ + match varname[count]:vartype, var + \{ match =BYTE, vartype \\{ varname rb count + restore done@local \\} + match =WORD, vartype \\{ varname rw count + restore done@local \\} + match =DWORD, vartype \\{ varname rd count + restore done@local \\} + match =PWORD, vartype \\{ varname rp count + restore done@local \\} + match =QWORD, vartype \\{ varname rq count + restore done@local \\} + match =TBYTE, vartype \\{ varname rt count + restore done@local \\} + match =DQWORD, vartype \\{ label varname dqword + rq count+count + restore done@local \\} + match , done@local \\{ virtual + varname vartype + end virtual + rb count*sizeof.\#vartype + restore done@local \\} \} + match :varname:vartype, done@local:var + \{ match =BYTE, vartype \\{ varname db ? + restore done@local \\} + match =WORD, vartype \\{ varname dw ? + restore done@local \\} + match =DWORD, vartype \\{ varname dd ? + restore done@local \\} + match =PWORD, vartype \\{ varname dp ? + restore done@local \\} + match =QWORD, vartype \\{ varname dq ? + restore done@local \\} + match =TBYTE, vartype \\{ varname dt ? + restore done@local \\} + match =DQWORD, vartype \\{ label varname dqword + dq ?,? + restore done@local \\} + match , done@local \\{ varname vartype + restore done@local \\} \} + match ,done@local + \{ var + restore done@local \} + common + endl } diff --git a/struct.inc b/struct.inc new file mode 100644 index 0000000..947a84e --- /dev/null +++ b/struct.inc @@ -0,0 +1,180 @@ + +; Macroinstructions for defining data structures + +macro struct name + { fields@struct equ name + match child parent, name \{ fields@struct equ child,fields@\#parent \} + sub@struct equ + struc db [val] \{ \common fields@struct equ fields@struct,.,db, \} + struc dw [val] \{ \common fields@struct equ fields@struct,.,dw, \} + struc du [val] \{ \common fields@struct equ fields@struct,.,du, \} + struc dd [val] \{ \common fields@struct equ fields@struct,.,dd, \} + struc dp [val] \{ \common fields@struct equ fields@struct,.,dp, \} + struc dq [val] \{ \common fields@struct equ fields@struct,.,dq, \} + struc dt [val] \{ \common fields@struct equ fields@struct,.,dt, \} + struc rb count \{ fields@struct equ fields@struct,.,db,count dup (?) \} + struc rw count \{ fields@struct equ fields@struct,.,dw,count dup (?) \} + struc rd count \{ fields@struct equ fields@struct,.,dd,count dup (?) \} + struc rp count \{ fields@struct equ fields@struct,.,dp,count dup (?) \} + struc rq count \{ fields@struct equ fields@struct,.,dq,count dup (?) \} + struc rt count \{ fields@struct equ fields@struct,.,dt,count dup (?) \} + macro db [val] \{ \common \local anonymous + fields@struct equ fields@struct,anonymous,db, \} + macro dw [val] \{ \common \local anonymous + fields@struct equ fields@struct,anonymous,dw, \} + macro du [val] \{ \common \local anonymous + fields@struct equ fields@struct,anonymous,du, \} + macro dd [val] \{ \common \local anonymous + fields@struct equ fields@struct,anonymous,dd, \} + macro dp [val] \{ \common \local anonymous + fields@struct equ fields@struct,anonymous,dp, \} + macro dq [val] \{ \common \local anonymous + fields@struct equ fields@struct,anonymous,dq, \} + macro dt [val] \{ \common \local anonymous + fields@struct equ fields@struct,anonymous,dt, \} + macro rb count \{ \local anonymous + fields@struct equ fields@struct,anonymous,db,count dup (?) \} + macro rw count \{ \local anonymous + fields@struct equ fields@struct,anonymous,dw,count dup (?) \} + macro rd count \{ \local anonymous + fields@struct equ fields@struct,anonymous,dd,count dup (?) \} + macro rp count \{ \local anonymous + fields@struct equ fields@struct,anonymous,dp,count dup (?) \} + macro rq count \{ \local anonymous + fields@struct equ fields@struct,anonymous,dq,count dup (?) \} + macro rt count \{ \local anonymous + fields@struct equ fields@struct,anonymous,dt,count dup (?) \} + macro union \{ fields@struct equ fields@struct,,union,< + sub@struct equ union \} + macro struct \{ fields@struct equ fields@struct,,substruct,< + sub@struct equ substruct \} + virtual at 0 } + +macro ends + { match , sub@struct \{ restruc db,dw,du,dd,dp,dq,dt + restruc rb,rw,rd,rp,rq,rt + purge db,dw,du,dd,dp,dq,dt + purge rb,rw,rd,rp,rq,rt + purge union,struct + match name=,fields,fields@struct \\{ fields@struct equ + make@struct name,fields + fields@\\#name equ fields \\} + end virtual \} + match any, sub@struct \{ fields@struct equ fields@struct> \} + restore sub@struct } + +macro make@struct name,[field,type,def] + { common + if $ + display 'Error: definition of ',`name,' contains illegal instructions.',0Dh,0Ah + err + end if + local define + define equ name + forward + local sub + match , field \{ make@substruct type,name,sub def + define equ define,.,sub, \} + match any, field \{ define equ define,.#field,type, \} + common + match fields, define \{ define@struct fields \} } + +macro define@struct name,[field,type,def] + { common + local list + list equ + forward + if ~ field eq . + name#field type def + sizeof.#name#field = $ - name#field + else + rb sizeof.#type + end if + local value + match any, list \{ list equ list, \} + list equ list + common + sizeof.#name = $ + restruc name + match values, list \{ + struc name value \\{ + match any, fields@struct \\\{ fields@struct equ fields@struct,.,name, \\\} + match , fields@struct \\\{ label . + forward + match , value \\\\{ field type def \\\\} + match any, value \\\\{ field type value + if ~ field eq . + rb sizeof.#name#field - ($-field) + end if \\\\} + common \\\} \\} \} } + +macro enable@substruct + { macro make@substruct substruct,parent,name,[field,type,def] + \{ \common + \local define + define equ parent,name + \forward + \local sub + match , field \\{ match any, type \\\{ enable@substruct + make@substruct type,name,sub def + purge make@substruct + define equ define,.,sub, \\\} \\} + match any, field \\{ define equ define,.\#field,type, \\} + \common + match fields, define \\{ define@\#substruct fields \\} \} } + +enable@substruct + +macro define@union parent,name,[field,type,def] + { common + virtual at 0 + forward + if ~ field eq . + virtual at 0 + parent#field type def + sizeof.#parent#field = $ - parent#field + end virtual + if sizeof.#parent#field > $ + rb sizeof.#parent#field - $ + end if + else if sizeof.#type > $ + rb sizeof.#type - $ + end if + common + sizeof.#name = $ + end virtual + struc name [value] \{ \common + label .\#name + last@union equ + forward + match any, last@union \\{ virtual at .\#name + field type def + end virtual \\} + match , last@union \\{ match , value \\\{ field type def \\\} + match any, value \\\{ field type value \\\} \\} + last@union equ field + common rb sizeof.#name - ($ - .\#name) \} } + +macro define@substruct parent,name,[field,type,def] + { common + virtual at 0 + forward + if ~ field eq . + parent#field type def + sizeof.#parent#field = $ - parent#field + else + rb sizeof.#type + end if + local value + common + sizeof.#name = $ + end virtual + struc name value \{ + label .\#name + forward + match , value \\{ field type def \\} + match any, value \\{ field type value + if ~ field eq . + rb sizeof.#parent#field - ($-field) + end if \\} + common \} } diff --git a/system.inc b/system.inc new file mode 100644 index 0000000..a7d6de6 --- /dev/null +++ b/system.inc @@ -0,0 +1,17 @@ +SYS_EXIT = 1 +SYS_READ = 3 +SYS_WRITE = 4 +SYS_OPEN = 5 +SYS_CLOSE = 6 +SYS_LSEEK = 19 + +SEEK_SET = 0 +SEEK_CUR = 1 +SEEK_END = 2 + +O_RDONLY = 0 +O_LARGEFILE = 0x8000 + +STDIN = 0 +STDOUT = 1 +STDERR = 2 diff --git a/xfs.asm b/xfs.asm new file mode 100644 index 0000000..b956dbe --- /dev/null +++ b/xfs.asm @@ -0,0 +1,2790 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2013-2016. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License. ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 6462 $ + +; XFS external functions +; in: +; ebx -> parameter structure of sysfunc 70 +; ebp -> XFS structure +; [esi]+[[esp+4]] = name +; out: +; eax, ebx = return values for sysfunc 70 +;iglobal +align 4 +xfs_user_functions: + dd xfs_free + dd (xfs_user_functions_end - xfs_user_functions - 4) / 4 + dd xfs_ReadFile + dd xfs_ReadFolder + dd 0;xfs_CreateFile + dd 0;xfs_WriteFile + dd 0;xfs_SetFileEnd + dd xfs_GetFileInfo + dd 0;xfs_SetFileInfo + dd 0 + dd 0;xfs_Delete + dd 0;xfs_CreateFolder +xfs_user_functions_end: +;endg + +include 'xfs.inc' + +; Mount if it's a valid XFS partition. +xfs_create_partition: +; in: +; ebp -> PARTITION structure +; ebx -> boot sector +; out: +; eax -> XFS structure, 0 = not XFS + push ebx ecx edx esi edi + cmp dword [esi+DISK.MediaInfo.SectorSize], 512 + jnz .error + cmp dword[ebx + xfs_sb.sb_magicnum], XFS_SB_MAGIC ; signature + jne .error + + ; TODO: check XFS.versionnum and XFS.features2 + ; print superblock params for debugging (waiting for bug reports) + + movi eax, sizeof.XFS + call malloc + test eax, eax + jz .error + + ; standard partition initialization, common for all file systems + + mov edi, eax + mov eax, dword[ebp + PARTITION.FirstSector] + mov dword[edi + XFS.FirstSector], eax + mov eax, dword[ebp + PARTITION.FirstSector + 4] + mov dword[edi + XFS.FirstSector + 4], eax + mov eax, dword[ebp + PARTITION.Length] + mov dword[edi + XFS.Length], eax + mov eax, dword[ebp + PARTITION.Length + 4] + mov dword[edi + XFS.Length + 4], eax + mov eax, [ebp + PARTITION.Disk] + mov [edi + XFS.Disk], eax + mov [edi + XFS.FSUserFunctions], xfs_user_functions + + ; here we initialize only one mutex so far (for the entire partition) + ; XFS potentially allows parallel r/w access to several AGs, keep it in mind for SMP times + + lea ecx, [edi + XFS.Lock] + call mutex_init + + ; read superblock and fill just allocated XFS partition structure + + mov eax, [ebx + xfs_sb.sb_blocksize] + bswap eax ; XFS is big endian + mov [edi + XFS.blocksize], eax + movzx eax, word[ebx + xfs_sb.sb_sectsize] + xchg al, ah + mov [edi + XFS.sectsize], eax + movzx eax, word[ebx + xfs_sb.sb_versionnum] + xchg al, ah + mov [edi + XFS.versionnum], eax + mov eax, [ebx + xfs_sb.sb_features2] + bswap eax + mov [edi + XFS.features2], eax + movzx eax, word[ebx + xfs_sb.sb_inodesize] + xchg al, ah + mov [edi + XFS.inodesize], eax + movzx eax, word[ebx + xfs_sb.sb_inopblock] ; inodes per block + xchg al, ah + mov [edi + XFS.inopblock], eax + movzx eax, byte[ebx + xfs_sb.sb_blocklog] ; log2 of block size, in bytes + mov [edi + XFS.blocklog], eax + movzx eax, byte[ebx + xfs_sb.sb_sectlog] + mov [edi + XFS.sectlog], eax + movzx eax, byte[ebx + xfs_sb.sb_inodelog] + mov [edi + XFS.inodelog], eax + movzx eax, byte[ebx + xfs_sb.sb_inopblog] + mov [edi + XFS.inopblog], eax + movzx eax, byte[ebx + xfs_sb.sb_dirblklog] + mov [edi + XFS.dirblklog], eax + mov eax, dword[ebx + xfs_sb.sb_rootino + 4] ; + bswap eax ; big + mov dword[edi + XFS.rootino + 0], eax ; endian + mov eax, dword[ebx + xfs_sb.sb_rootino + 0] ; 64bit + bswap eax ; number + mov dword[edi + XFS.rootino + 4], eax ; + + mov eax, [edi + XFS.blocksize] + mov ecx, [edi + XFS.dirblklog] + shl eax, cl + mov [edi + XFS.dirblocksize], eax ; blocks for files, dirblocks for directories + + ; sector is always smaller than block + ; so precalculate shift order to allow faster sector_num->block_num conversion + + mov ecx, [edi + XFS.blocklog] + sub ecx, [edi + XFS.sectlog] + mov [edi + XFS.blockmsectlog], ecx + + mov eax, 1 + shl eax, cl + mov [edi + XFS.sectpblock], eax + + ; shift order for inode_num->block_num conversion + + mov eax, [edi + XFS.blocklog] + sub eax, [edi + XFS.inodelog] + mov [edi + XFS.inodetoblocklog], eax + + mov eax, [ebx + xfs_sb.sb_agblocks] + bswap eax + mov [edi + XFS.agblocks], eax + movzx ecx, byte[ebx + xfs_sb.sb_agblklog] + mov [edi + XFS.agblklog], ecx + + ; get the mask for block numbers + ; block numbers are AG relative! + ; bitfield length may vary between partitions + + mov eax, 1 + shl eax, cl + dec eax + mov dword[edi + XFS.agblockmask + 0], eax + mov eax, 1 + sub ecx, 32 + jc @f + shl eax, cl + @@: + dec eax + mov dword[edi + XFS.agblockmask + 4], eax + + ; calculate magic offsets for directories + + mov ecx, [edi + XFS.blocklog] + mov eax, XFS_DIR2_LEAF_OFFSET AND 0xffffffff ; lo + mov edx, XFS_DIR2_LEAF_OFFSET SHR 32 ; hi + shrd eax, edx, cl + mov [edi + XFS.dir2_leaf_offset_blocks], eax + + mov ecx, [edi + XFS.blocklog] + mov eax, XFS_DIR2_FREE_OFFSET AND 0xffffffff ; lo + mov edx, XFS_DIR2_FREE_OFFSET SHR 32 ; hi + shrd eax, edx, cl + mov [edi + XFS.dir2_free_offset_blocks], eax + +; mov ecx, [edi + XFS.dirblklog] +; mov eax, [edi + XFS.blocksize] +; shl eax, cl +; mov [edi + XFS.dirblocksize], eax + + mov eax, [edi + XFS.blocksize] + call malloc + test eax, eax + jz .error + mov [edi + XFS.cur_block], eax + + ; we do need XFS.blocksize bytes for single inode + ; minimal file system structure is block, inodes are packed in blocks + + mov eax, [edi + XFS.blocksize] + call malloc + test eax, eax + jz .error + mov [edi + XFS.cur_inode], eax + + ; temporary inode + ; used for browsing directories + + mov eax, [edi + XFS.blocksize] + call malloc + test eax, eax + jz .error + mov [edi + XFS.tmp_inode], eax + + ; current sector + ; only for sector size structures like AGI + ; inodes has usually the same size, but never store them here + + mov eax, [edi + XFS.sectsize] + call malloc + test eax, eax + jz .error + mov [edi + XFS.cur_sect], eax + + ; current directory block + + mov eax, [edi + XFS.dirblocksize] + call malloc + test eax, eax + jz .error + mov [edi + XFS.cur_dirblock], eax + + .quit: + mov eax, edi ; return pointer to allocated XFS partition structure + pop edi esi edx ecx ebx + ret + .error: + xor eax, eax + pop edi esi edx ecx ebx + ret + + +; lock partition access mutex +proc xfs_lock +;DEBUGF 1,"xfs_lock\n" + lea ecx, [ebp + XFS.Lock] + jmp mutex_lock +endp + + +; unlock partition access mutex +proc xfs_unlock +;DEBUGF 1,"xfs_unlock\n" + lea ecx, [ebp + XFS.Lock] + jmp mutex_unlock +endp + + +; free all the allocated memory +; called on partition destroy +proc xfs_free + push ebp + xchg ebp, eax + stdcall kernel_free, [ebp + XFS.cur_block] + stdcall kernel_free, [ebp + XFS.cur_inode] + stdcall kernel_free, [ebp + XFS.cur_sect] + stdcall kernel_free, [ebp + XFS.cur_dirblock] + stdcall kernel_free, [ebp + XFS.tmp_inode] + xchg ebp, eax + call free + pop ebp + ret +endp + + +;--------------------------------------------------------------- +; block number (AG relative) +; eax -- block_lo +; edx -- block_hi +; ebx -- buffer +;--------------------------------------------------------------- +xfs_read_block: + push ebx esi + + push edx + push eax + + ; XFS block numbers are AG relative + ; they come in bitfield form of concatenated AG and block numbers + ; to get absolute block number for fs_read32_sys we should + ; 1. extract AG number (using precalculated mask) + ; 2. multiply it by the AG size in blocks + ; 3. add AG relative block number + + ; 1. + mov ecx, [ebp + XFS.agblklog] + shrd eax, edx, cl + shr edx, cl + ; 2. + mul dword[ebp + XFS.agblocks] + pop ecx + pop esi + and ecx, dword[ebp + XFS.agblockmask + 0] + and esi, dword[ebp + XFS.agblockmask + 4] + ; 3. + add eax, ecx + adc edx, esi + +DEBUGF 1,"read block: 0x%x%x\n",edx,eax + ; there is no way to read file system block at once, therefore we + ; 1. calculate the number of sectors first + ; 2. and then read them in series + + ; 1. + mov ecx, [ebp + XFS.blockmsectlog] + shld edx, eax, cl + shl eax, cl + mov esi, [ebp + XFS.sectpblock] + + ; 2. + .next_sector: + push eax edx + call fs_read32_sys + mov ecx, eax + pop edx eax + test ecx, ecx + jnz .error + add eax, 1 ; be ready to fs_read64_sys + adc edx, 0 + add ebx, [ebp + XFS.sectsize] ; update buffer offset + dec esi + jnz .next_sector + + .quit: + xor eax, eax + pop esi ebx + ret + .error: + mov eax, ecx + pop esi ebx + ret + + +;--------------------------------------------------------------- +; push buffer +; push startblock_hi +; push startblock_lo +; call xfs_read_dirblock +; test eax, eax +;--------------------------------------------------------------- +xfs_read_dirblock: +;mov eax, [esp + 4] +;mov edx, [esp + 8] +;DEBUGF 1,"read dirblock at: %d %d\n",edx,eax +;DEBUGF 1,"dirblklog: %d\n",[ebp + XFS.dirblklog] + push ebx esi + + mov eax, [esp + 12] ; startblock_lo + mov edx, [esp + 16] ; startblock_hi + mov ebx, [esp + 20] ; buffer + + ; dirblock >= block + ; read dirblocks by blocks + + mov ecx, [ebp + XFS.dirblklog] + mov esi, 1 + shl esi, cl + .next_block: + push eax edx + call xfs_read_block + mov ecx, eax + pop edx eax + test ecx, ecx + jnz .error + add eax, 1 ; be ready to fs_read64_sys + adc edx, 0 + add ebx, [ebp + XFS.blocksize] + dec esi + jnz .next_block + + .quit: + xor eax, eax + pop esi ebx + ret 12 + .error: + mov eax, ecx + pop esi ebx + ret 12 + + +;--------------------------------------------------------------- +; push buffer +; push inode_hi +; push inode_lo +; call xfs_read_inode +; test eax, eax +;--------------------------------------------------------------- +xfs_read_inode: +DEBUGF 1,"reading inode: 0x%x%x\n",[esp+8],[esp+4] + push ebx + mov eax, [esp + 8] ; inode_lo + mov edx, [esp + 12] ; inode_hi + mov ebx, [esp + 16] ; buffer + + ; inodes are packed into blocks + ; 1. calculate block number + ; 2. read the block + ; 3. add inode offset to block base address + + ; 1. + mov ecx, [ebp + XFS.inodetoblocklog] + shrd eax, edx, cl + shr edx, cl + ; 2. + call xfs_read_block + test eax, eax + jnz .error + + ; note that inode numbers should be first extracted from bitfields using mask + + mov eax, [esp + 8] + mov edx, 1 + mov ecx, [ebp + XFS.inopblog] + shl edx, cl + dec edx ; get inode number mask + and eax, edx ; apply mask + mov ecx, [ebp + XFS.inodelog] + shl eax, cl + add ebx, eax + +;DEBUGF 1,"dinode: %x\n", ebx +;DEBUGF 1," %x\n",[ebx+0x00] +;DEBUGF 1," %x\n",[ebx+0x04] +;DEBUGF 1," %x\n",[ebx+0x08] +;DEBUGF 1," %x\n",[ebx+0x0c] +;DEBUGF 1," %x\n",[ebx+0x10] +;DEBUGF 1," %x\n",[ebx+0x14] +;DEBUGF 1," %x\n",[ebx+0x18] +;DEBUGF 1," %x\n",[ebx+0x1c] +;DEBUGF 1," %x\n",[ebx+0x20] +;DEBUGF 1," %x\n",[ebx+0x24] +;DEBUGF 1," %x\n",[ebx+0x28] +;DEBUGF 1," %x\n",[ebx+0x2c] +;DEBUGF 1," %x\n",[ebx+0x30] +;DEBUGF 1," %x\n",[ebx+0x34] +;DEBUGF 1," %x\n",[ebx+0x38] +;DEBUGF 1," %x\n",[ebx+0x3c] + cmp word[ebx], XFS_DINODE_MAGIC ; test signature + jnz .error + .quit: + xor eax, eax + mov edx, ebx + pop ebx + ret 12 + .error: + movi eax, ERROR_FS_FAIL + mov edx, ebx + pop ebx + ret 12 + + +;---------------------------------------------------------------- +; push encoding ; ASCII / UNICODE +; push src ; inode +; push dst ; bdfe +; push entries_to_read +; push start_number ; from 0 +;---------------------------------------------------------------- +xfs_dir_get_bdfes: +DEBUGF 1,"xfs_dir_get_bdfes: %d entries from %d\n",[esp+8],[esp+4] + sub esp, 4 ; local vars + push ecx edx esi edi + + mov ebx, [esp + 36] ; src + mov edx, [esp + 32] ; dst + mov ecx, [esp + 24] ; start_number + + ; define directory ondisk format and jump to corresponding label + + cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_LOCAL + jne .not_shortdir + jmp .shortdir + .not_shortdir: + cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS + jne .not_blockdir + mov eax, [ebx + xfs_inode.di_core.di_nextents] + bswap eax + cmp eax, 1 + jne .not_blockdir + jmp .blockdir + .not_blockdir: + cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS + jne .not_leafdir + mov eax, [ebx + xfs_inode.di_core.di_nextents] + bswap eax + cmp eax, 4 + ja .not_leafdir + jmp .leafdir + .not_leafdir: + cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS + jne .not_nodedir + jmp .nodedir + .not_nodedir: + cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE + jne .not_btreedir + jmp .btreedir + .not_btreedir: + movi eax, ERROR_FS_FAIL + jmp .error + + ; short form directory (all the data fits into inode) + .shortdir: +;DEBUGF 1,"shortdir\n", + movzx eax, word[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count] + test al, al ; is count zero? + jnz @f ; if not, use it (i8count must be zero then) + shr eax, 8 ; use i8count + @@: + add eax, 1 ; '..' and '.' are implicit + mov dword[edx + 0], 1 ; version + mov [edx + 8], eax ; total entries + sub eax, [esp + 24] ; start number + cmp eax, [esp + 28] ; entries to read + jbe @f + mov eax, [esp + 28] + @@: + mov [esp + 28], eax + mov [edx + 4], eax ; number of actually read entries + mov [ebp + XFS.entries_read], eax + + ; inode numbers are often saved as 4 bytes (iff they fit) + ; compute the length of inode numbers + + mov eax, 4 ; 4 by default + cmp byte[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.i8count], 0 + je @f + add eax, eax ; 4+4=8, iff i8count != 0 + @@: + mov dword[edx + 12], 0 ; reserved + mov dword[edx + 16], 0 ; + mov dword[edx + 20], 0 ; + mov dword[edx + 24], 0 ; + mov dword[edx + 28], 0 ; + add edx, 32 + lea esi, [ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + eax] + dec ecx + js .shortdir.fill + + ; skip some entries if the first entry to read is not 0 + + .shortdir.skip: + test ecx, ecx + jz .shortdir.skipped + movzx edi, byte[esi + xfs_dir2_sf_entry.namelen] + lea esi, [esi + xfs_dir2_sf_entry.name + edi] + add esi, eax + dec ecx + jnz .shortdir.skip + mov ecx, [esp + 28] ; entries to read + jmp .shortdir.skipped + .shortdir.fill: + mov ecx, [esp + 28] ; total number + test ecx, ecx + jz .quit + push ecx +;DEBUGF 1,"ecx: %d\n",ecx + lea edi, [edx + 40] ; get file name offset +;DEBUGF 1,"filename: ..\n" + mov dword[edi], '..' + mov edi, edx + push eax ebx edx esi + stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + 4], dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent] + stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode] +; test eax, eax +; jnz .error + stdcall xfs_get_inode_info, edx, edi + test eax, eax + pop esi edx ebx eax + jnz .error + mov ecx, [esp + 44] ; file name encding + mov [edx + 4], ecx + add edx, 304 ; ASCII only for now + pop ecx + dec ecx + jz .quit + +; push ecx +; lea edi, [edx + 40] +;DEBUGF 1,"filename: .\n" +; mov dword[edi], '.' +; mov edi, edx +; push eax edx +; stdcall xfs_get_inode_info, [ebp + XFS.cur_inode], edi +; test eax, eax +; pop edx eax +; jnz .error +; mov ecx, [esp + 44] +; mov [edx + 4], ecx +; add edx, 304 ; ASCII only for now +; pop ecx +; dec ecx +; jz .quit + + ; we skipped some entries + ; now we fill min(required, present) number of bdfe's + + .shortdir.skipped: +;DEBUGF 1,"ecx: %d\n",ecx + push ecx + movzx ecx, byte[esi + xfs_dir2_sf_entry.namelen] + add esi, xfs_dir2_sf_entry.name + lea edi, [edx + 40] ; bdfe offset of file name +;DEBUGF 1,"filename: |%s|\n",esi + rep movsb + mov word[edi], 0 ; terminator (ASCIIZ) + + push eax ebx ecx edx esi +; push edx ; for xfs_get_inode_info + mov edi, edx + stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], [esi + 4], [esi] + stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode] +; test eax, eax +; jnz .error + stdcall xfs_get_inode_info, edx, edi + test eax, eax + pop esi edx ecx ebx eax + jnz .error + mov ecx, [esp + 44] ; file name encoding + mov [edx + 4], ecx + + add edx, 304 ; ASCII only for now + add esi, eax + pop ecx + dec ecx + jnz .shortdir.skipped + jmp .quit + + .blockdir: +;DEBUGF 1,"blockdir\n" + push edx + lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] + stdcall xfs_extent_unpack, eax +;DEBUGF 1,"extent.br_startoff : 0x%x%x\n",[ebp+XFS.extent.br_startoff+4],[ebp+XFS.extent.br_startoff+0] +;DEBUGF 1,"extent.br_startblock: 0x%x%x\n",[ebp+XFS.extent.br_startblock+4],[ebp+XFS.extent.br_startblock+0] +;DEBUGF 1,"extent.br_blockcount: %d\n",[ebp+XFS.extent.br_blockcount] +;DEBUGF 1,"extent.br_state : %d\n",[ebp+XFS.extent.br_state] + stdcall xfs_read_dirblock, dword[ebp + XFS.extent.br_startblock + 0], dword[ebp + XFS.extent.br_startblock + 4], [ebp + XFS.cur_dirblock] + test eax, eax + pop edx + jnz .error +;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock] + mov ebx, [ebp + XFS.cur_dirblock] + mov dword[edx + 0], 1 ; version + mov eax, [ebp + XFS.dirblocksize] + mov ecx, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.stale] + mov eax, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.count] + bswap ecx + bswap eax + sub eax, ecx ; actual number of entries = count - stale + mov [edx + 8], eax ; total entries +;DEBUGF 1,"total entries: %d\n",eax + sub eax, [esp + 24] ; start number + cmp eax, [esp + 28] ; entries to read + jbe @f + mov eax, [esp + 28] + @@: + mov [esp + 28], eax + mov [edx + 4], eax ; number of actually read entries + mov [ebp + XFS.entries_read], eax +;DEBUGF 1,"actually read entries: %d\n",eax + mov dword[edx + 12], 0 ; reserved + mov dword[edx + 16], 0 ; + mov dword[edx + 20], 0 ; + mov dword[edx + 24], 0 ; + mov dword[edx + 28], 0 ; + add ebx, xfs_dir2_block.u + + mov ecx, [esp + 24] ; start entry number + ; also means how many to skip + test ecx, ecx + jz .blockdir.skipped + .blockdir.skip: + cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG + jne @f + movzx eax, word[ebx + xfs_dir2_data_union.unused.length] + xchg al, ah + add ebx, eax + jmp .blockdir.skip + @@: + movzx eax, [ebx + xfs_dir2_data_union.xentry.namelen] + lea ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2] ; 2 bytes for 'tag' + add ebx, 7 ; align on 8 bytes + and ebx, not 7 + dec ecx + jnz .blockdir.skip + .blockdir.skipped: + mov ecx, [edx + 4] ; actually read entries + test ecx, ecx + jz .quit + add edx, 32 ; set edx to the first bdfe + .blockdir.next_entry: + cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_NULL + jne @f + movzx eax, word[ebx + xfs_dir2_data_union.unused.length] + xchg al, ah + add ebx, eax + jmp .blockdir.next_entry + @@: + push ecx + push eax ebx ecx edx esi + mov edi, edx + mov edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0] + mov eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4] + bswap edx + bswap eax + stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode] + stdcall xfs_get_inode_info, edx, edi + test eax, eax + pop esi edx ecx ebx eax + jnz .error + mov ecx, [esp + 44] + mov [edx + 4], ecx + lea edi, [edx + 40] + movzx ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen] + lea esi, [ebx + xfs_dir2_data_union.xentry.name] +;DEBUGF 1,"filename: |%s|\n",esi + rep movsb +; call utf8_to_cp866 + mov word[edi], 0 ; terminator + lea ebx, [esi + 2] ; skip 'tag' + add ebx, 7 ; xfs_dir2_data_entries are aligned to 8 bytes + and ebx, not 7 + add edx, 304 + pop ecx + dec ecx + jnz .blockdir.next_entry + jmp .quit + + .leafdir: +;DEBUGF 1,"readdir: leaf\n" + mov [ebp + XFS.cur_inode_save], ebx + push ebx ecx edx + lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] + mov edx, [ebx + xfs_inode.di_core.di_nextents] + bswap edx + stdcall xfs_extent_list_read_dirblock, eax, [ebp + XFS.dir2_leaf_offset_blocks], 0, edx, 0xffffffff, 0xffffffff + mov ecx, eax + and ecx, edx + inc ecx + pop edx ecx ebx + jz .error + + mov eax, [ebp + XFS.cur_dirblock] + movzx ecx, word[eax + xfs_dir2_leaf.hdr.stale] + movzx eax, word[eax + xfs_dir2_leaf.hdr.count] + xchg cl, ch + xchg al, ah + sub eax, ecx +;DEBUGF 1,"total count: %d\n",eax + + mov dword[edx + 0], 1 ; version + mov [edx + 8], eax ; total entries + sub eax, [esp + 24] ; start number + cmp eax, [esp + 28] ; entries to read + jbe @f + mov eax, [esp + 28] + @@: + mov [esp + 28], eax + mov [edx + 4], eax ; number of actually read entries + + mov dword[edx + 12], 0 ; reserved + mov dword[edx + 16], 0 ; + mov dword[edx + 20], 0 ; + mov dword[edx + 24], 0 ; + mov dword[edx + 28], 0 ; + + mov eax, [ebp + XFS.cur_dirblock] + add eax, [ebp + XFS.dirblocksize] + mov [ebp + XFS.max_dirblockaddr], eax + mov dword[ebp + XFS.next_block_num + 0], 0 + mov dword[ebp + XFS.next_block_num + 4], 0 + + mov ebx, [ebp + XFS.max_dirblockaddr] ; to read dirblock immediately + mov ecx, [esp + 24] ; start number + test ecx, ecx + jz .leafdir.skipped + .leafdir.skip: + cmp ebx, [ebp + XFS.max_dirblockaddr] + jne @f + push ecx edx + mov ebx, [ebp + XFS.cur_inode_save] + lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] + mov edx, [ebx + xfs_inode.di_core.di_nextents] + bswap edx + stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 + mov ecx, eax + and ecx, edx + inc ecx + jz .error + add eax, 1 + adc edx, 0 + mov dword[ebp + XFS.next_block_num + 0], eax + mov dword[ebp + XFS.next_block_num + 4], edx + mov ebx, [ebp + XFS.cur_dirblock] + add ebx, sizeof.xfs_dir2_data_hdr + pop edx ecx + @@: + cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG + jne @f + movzx eax, word[ebx + xfs_dir2_data_union.unused.length] + xchg al, ah + add ebx, eax + jmp .leafdir.skip + @@: + movzx eax, [ebx + xfs_dir2_data_union.xentry.namelen] + lea ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2] ; 2 for 'tag' + add ebx, 7 + and ebx, not 7 + dec ecx + jnz .leafdir.skip + .leafdir.skipped: + mov [ebp + XFS.entries_read], 0 + mov ecx, [edx + 4] ; actually read entries + test ecx, ecx + jz .quit + add edx, 32 ; first bdfe entry + .leafdir.next_entry: +;DEBUGF 1,"next_extry\n" + cmp ebx, [ebp + XFS.max_dirblockaddr] + jne .leafdir.process_current_block + push ecx edx + mov ebx, [ebp + XFS.cur_inode_save] + lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] + mov edx, [ebx + xfs_inode.di_core.di_nextents] + bswap edx + stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 +;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax + mov ecx, eax + and ecx, edx + inc ecx + jnz @f + pop edx ecx + jmp .quit + @@: + add eax, 1 + adc edx, 0 + mov dword[ebp + XFS.next_block_num + 0], eax + mov dword[ebp + XFS.next_block_num + 4], edx + mov ebx, [ebp + XFS.cur_dirblock] + add ebx, sizeof.xfs_dir2_data_hdr + pop edx ecx + .leafdir.process_current_block: + cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG + jne @f + movzx eax, word[ebx + xfs_dir2_data_union.unused.length] + xchg al, ah + add ebx, eax + jmp .leafdir.next_entry + @@: + push eax ebx ecx edx esi + mov edi, edx + mov edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0] + mov eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4] + bswap edx + bswap eax + stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode] + stdcall xfs_get_inode_info, edx, edi + test eax, eax + pop esi edx ecx ebx eax + jnz .error + push ecx + mov ecx, [esp + 44] + mov [edx + 4], ecx + lea edi, [edx + 40] + movzx ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen] + lea esi, [ebx + xfs_dir2_data_union.xentry.name] +;DEBUGF 1,"filename: |%s|\n",esi + rep movsb + pop ecx + mov word[edi], 0 + lea ebx, [esi + 2] ; skip 'tag' + add ebx, 7 ; xfs_dir2_data_entries are aligned to 8 bytes + and ebx, not 7 + add edx, 304 ; ASCII only for now + inc [ebp + XFS.entries_read] + dec ecx + jnz .leafdir.next_entry + jmp .quit + + .nodedir: +;DEBUGF 1,"readdir: node\n" + push edx + mov [ebp + XFS.cur_inode_save], ebx + mov [ebp + XFS.entries_read], 0 + lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] + mov edx, [ebx + xfs_inode.di_core.di_nextents] + bswap edx + stdcall xfs_dir2_node_get_numfiles, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks] + pop edx + test eax, eax + jnz .error + mov eax, [ebp + XFS.entries_read] + mov [ebp + XFS.entries_read], 0 +;DEBUGF 1,"numfiles: %d\n",eax + mov dword[edx + 0], 1 ; version + mov [edx + 8], eax ; total entries + sub eax, [esp + 24] ; start number + cmp eax, [esp + 28] ; entries to read + jbe @f + mov eax, [esp + 28] + @@: + mov [esp + 28], eax + mov [edx + 4], eax ; number of actually read entries + + mov dword[edx + 12], 0 ; reserved + mov dword[edx + 16], 0 ; + mov dword[edx + 20], 0 ; + mov dword[edx + 24], 0 ; + mov dword[edx + 28], 0 ; + + mov eax, [ebp + XFS.cur_dirblock] + add eax, [ebp + XFS.dirblocksize] + mov [ebp + XFS.max_dirblockaddr], eax + mov dword[ebp + XFS.next_block_num + 0], 0 + mov dword[ebp + XFS.next_block_num + 4], 0 + + mov ebx, [ebp + XFS.max_dirblockaddr] ; to read dirblock immediately + mov ecx, [esp + 24] ; start number + test ecx, ecx + jz .leafdir.skipped + jmp .leafdir.skip + + .btreedir: +;DEBUGF 1,"readdir: btree\n" + mov [ebp + XFS.cur_inode_save], ebx + push ebx edx + mov eax, [ebx + xfs_inode.di_core.di_nextents] + bswap eax + mov [ebp + XFS.ro_nextents], eax + mov eax, [ebp + XFS.inodesize] + sub eax, xfs_inode.di_u + sub eax, sizeof.xfs_bmdr_block + shr eax, 4 +;DEBUGF 1,"maxnumresc: %d\n",eax + mov edx, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 0] + mov eax, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 4] + bswap eax + bswap edx + mov ebx, [ebp + XFS.cur_block] +;DEBUGF 1,"read_block: %x %x ",edx,eax + stdcall xfs_read_block + pop edx ebx + test eax, eax + jnz .error +;DEBUGF 1,"ok\n" + + mov ebx, [ebp + XFS.cur_block] + push edx + mov [ebp + XFS.entries_read], 0 + lea eax, [ebx + sizeof.xfs_bmbt_block] + mov edx, [ebp + XFS.ro_nextents] + stdcall xfs_dir2_node_get_numfiles, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks] + pop edx + test eax, eax + jnz .error + mov eax, [ebp + XFS.entries_read] + mov [ebp + XFS.entries_read], 0 +;DEBUGF 1,"numfiles: %d\n",eax + + mov dword[edx + 0], 1 ; version + mov [edx + 8], eax ; total entries + sub eax, [esp + 24] ; start number + cmp eax, [esp + 28] ; entries to read + jbe @f + mov eax, [esp + 28] + @@: + mov [esp + 28], eax + mov [edx + 4], eax ; number of actually read entries + + mov dword[edx + 12], 0 + mov dword[edx + 16], 0 + mov dword[edx + 20], 0 + mov dword[edx + 24], 0 + mov dword[edx + 28], 0 + + mov eax, [ebp + XFS.cur_dirblock] ; fsblock? + add eax, [ebp + XFS.dirblocksize] + mov [ebp + XFS.max_dirblockaddr], eax + mov dword[ebp + XFS.next_block_num + 0], 0 + mov dword[ebp + XFS.next_block_num + 4], 0 + + mov ebx, [ebp + XFS.max_dirblockaddr] ; to read dirblock immediately + mov ecx, [esp + 24] ; start number + test ecx, ecx + jz .btreedir.skipped +; jmp .btreedir.skip + .btreedir.skip: + cmp ebx, [ebp + XFS.max_dirblockaddr] + jne @f + push ecx edx + mov ebx, [ebp + XFS.cur_block] + lea eax, [ebx + sizeof.xfs_bmbt_block] + mov edx, [ebp + XFS.ro_nextents] + stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 +;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax + mov ecx, eax + and ecx, edx + inc ecx + jz .error + add eax, 1 + adc edx, 0 + mov dword[ebp + XFS.next_block_num + 0], eax + mov dword[ebp + XFS.next_block_num + 4], edx + mov ebx, [ebp + XFS.cur_dirblock] + add ebx, sizeof.xfs_dir2_data_hdr + pop edx ecx + @@: + cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG + jne @f + movzx eax, word[ebx + xfs_dir2_data_union.unused.length] + xchg al, ah + add ebx, eax + jmp .btreedir.skip + @@: + movzx eax, [ebx + xfs_dir2_data_union.xentry.namelen] + lea ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2] ; 2 for 'tag' + add ebx, 7 + and ebx, not 7 + dec ecx + jnz .btreedir.skip + .btreedir.skipped: + mov [ebp + XFS.entries_read], 0 + mov ecx, [edx + 4] ; actually read entries + test ecx, ecx + jz .quit + add edx, 32 + .btreedir.next_entry: +;mov eax, [ebp + XFS.entries_read] +;DEBUGF 1,"next_extry: %d\n",eax + cmp ebx, [ebp + XFS.max_dirblockaddr] + jne .btreedir.process_current_block + push ecx edx + mov ebx, [ebp + XFS.cur_block] + lea eax, [ebx + sizeof.xfs_bmbt_block] + mov edx, [ebp + XFS.ro_nextents] + stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 +;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax + mov ecx, eax + and ecx, edx + inc ecx + jnz @f + pop edx ecx + jmp .quit + @@: + add eax, 1 + adc edx, 0 + mov dword[ebp + XFS.next_block_num + 0], eax + mov dword[ebp + XFS.next_block_num + 4], edx + mov ebx, [ebp + XFS.cur_dirblock] + add ebx, sizeof.xfs_dir2_data_hdr + pop edx ecx + .btreedir.process_current_block: + cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG + jne @f + movzx eax, word[ebx + xfs_dir2_data_union.unused.length] + xchg al, ah + add ebx, eax + jmp .btreedir.next_entry + @@: + push eax ebx ecx edx esi + mov edi, edx + mov edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0] + mov eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4] + bswap edx + bswap eax + stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode] + stdcall xfs_get_inode_info, edx, edi + test eax, eax + pop esi edx ecx ebx eax + jnz .error + push ecx + mov ecx, [esp + 44] + mov [edx + 4], ecx + lea edi, [edx + 40] + movzx ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen] + lea esi, [ebx + xfs_dir2_data_union.xentry.name] +;DEBUGF 1,"filename: |%s|\n",esi + rep movsb + pop ecx + mov word[edi], 0 + lea ebx, [esi + 2] ; skip 'tag' + add ebx, 7 ; xfs_dir2_data_entries are aligned to 8 bytes + and ebx, not 7 + add edx, 304 + inc [ebp + XFS.entries_read] + dec ecx + jnz .btreedir.next_entry + jmp .quit + + + .quit: + pop edi esi edx ecx + add esp, 4 ; pop vars + xor eax, eax +; mov ebx, [esp + 8] + mov ebx, [ebp + XFS.entries_read] +DEBUGF 1,"xfs_dir_get_bdfes done: %d\n",ebx + ret 20 + .error: + pop edi esi edx ecx + add esp, 4 ; pop vars + mov eax, ERROR_FS_FAIL + movi ebx, -1 + ret 20 + + +;---------------------------------------------------------------- +; push inode_hi +; push inode_lo +; push name +;---------------------------------------------------------------- +xfs_get_inode_short: + ; this function searches for the file in _current_ dir + ; it is called recursively for all the subdirs /path/to/my/file + +DEBUGF 1, "xfs_get_inode_short: %s\n", [esp+4] + mov esi, [esp + 4] ; name + movzx eax, word[esi] + cmp eax, '.' ; current dir; it is already read, just return + je .quit + cmp eax, './' ; same thing + je .quit + + ; read inode + + mov eax, [esp + 8] ; inode_lo + mov edx, [esp + 12] ; inode_hi + stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode] + test eax, eax + movi eax, ERROR_FS_FAIL + jnz .error + + ; find file name in directory + ; switch directory ondisk format + + mov ebx, edx + mov [ebp + XFS.cur_inode_save], ebx + cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_LOCAL + jne .not_shortdir +DEBUGF 1, "dir: shortdir\n" + jmp .shortdir + .not_shortdir: + cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS + jne .not_blockdir + mov eax, [ebx + xfs_inode.di_core.di_nextents] + bswap eax + cmp eax, 1 + jne .not_blockdir + jmp .blockdir + .not_blockdir: + cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS + jne .not_leafdir + mov eax, [ebx + xfs_inode.di_core.di_nextents] + bswap eax + cmp eax, 4 + ja .not_leafdir + jmp .leafdir + .not_leafdir: + cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS + jne .not_nodedir + jmp .nodedir + .not_nodedir: + cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE + jne .not_btreedir + jmp .btreedir + .not_btreedir: +DEBUGF 1,"NOT IMPLEMENTED: DIR FORMAT\n" + jmp .error + + .shortdir: + .shortdir.check_parent: + ; parent inode number in shortform directories is always implicit, check this case + mov eax, [esi] + and eax, 0x00ffffff + cmp eax, '..' + jz .shortdir.parent2 + cmp eax, '../' + jz .shortdir.parent3 + jmp .shortdir.common + .shortdir.parent3: + inc esi + .shortdir.parent2: + add esi, 2 + add ebx, xfs_inode.di_u + stdcall xfs_get_inode_number_sf, dword[ebx + xfs_dir2_sf_hdr.count], dword[ebx + xfs_dir2_sf_hdr.parent + 4], dword[ebx + xfs_dir2_sf_hdr.parent] +DEBUGF 1,"found inode: 0x%x%x\n",edx,eax + jmp .quit + + ; not a parent inode? + ; search in the list, all the other files are stored uniformly + + .shortdir.common: + mov eax, 4 + movzx edx, word[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count] ; read count (byte) and i8count (byte) at once + test dl, dl ; is count zero? + jnz @f + shr edx, 8 ; use i8count + add eax, eax ; inode_num size + @@: + lea edi, [ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + eax] + + .next_name: + movzx ecx, byte[edi + xfs_dir2_sf_entry.namelen] + add edi, xfs_dir2_sf_entry.name + mov esi, [esp + 4] +DEBUGF 1,"esi: %s\n",esi +DEBUGF 1,"edi: %s\n",edi + repe cmpsb + jne @f + cmp byte[esi], 0 ; HINT: use adc here? + je .found + cmp byte[esi], '/' + je .found_inc + @@: + add edi, ecx + add edi, eax + dec edx + jnz .next_name + movi eax, ERROR_FILE_NOT_FOUND + jmp .error + .found_inc: ; increment esi to skip '/' symbol + ; this means esi always points to valid file name or zero terminator byte + inc esi + .found: + stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], [edi + 4], [edi] +;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax + jmp .quit + + .blockdir: + lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] + stdcall xfs_extent_unpack, eax + stdcall xfs_read_dirblock, dword[ebp + XFS.extent.br_startblock + 0], dword[ebp + XFS.extent.br_startblock + 4], [ebp + XFS.cur_dirblock] + test eax, eax + jnz .error +;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock] + mov ebx, [ebp + XFS.cur_dirblock] + mov eax, [ebp + XFS.dirblocksize] + mov eax, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.count] + ; note that we don't subtract xfs_dir2_block_tail.stale here, + ; since we need the number of leaf entries rather than file number + bswap eax + add ebx, [ebp + XFS.dirblocksize] +; mov ecx, sizeof.xfs_dir2_leaf_entry + imul ecx, eax, sizeof.xfs_dir2_leaf_entry + sub ebx, sizeof.xfs_dir2_block_tail + sub ebx, ecx + shr ecx, 3 + push ecx ; for xfs_get_inode_by_hash + push ebx ; for xfs_get_inode_by_hash + + mov edi, esi + xor eax, eax + mov ecx, 4096 ; MAX_PATH_LEN + repne scasb + movi eax, ERROR_FS_FAIL + jne .error + neg ecx + add ecx, 4096 ; MAX_PATH_LEN + dec ecx + mov edx, ecx +;DEBUGF 1,"strlen total : %d\n",edx + mov edi, esi + mov eax, '/' + mov ecx, edx + repne scasb + jne @f + inc ecx + @@: + neg ecx + add ecx, edx +;DEBUGF 1,"strlen current: %d\n",ecx + stdcall xfs_hashname, esi, ecx + add esi, ecx + cmp byte[esi], '/' + jne @f + inc esi + @@: +;DEBUGF 1,"hashed: 0x%x\n",eax +; bswap eax + stdcall xfs_get_addr_by_hash + bswap eax +;DEBUGF 1,"got address: 0x%x\n",eax + cmp eax, -1 + jne @f + movi eax, ERROR_FILE_NOT_FOUND + mov ebx, -1 + jmp .error + @@: + shl eax, 3 + mov ebx, [ebp + XFS.cur_dirblock] + add ebx, eax + mov edx, [ebx + 0] + mov eax, [ebx + 4] + bswap edx + bswap eax +;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax + jmp .quit + + .leafdir: +;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock] + lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] + mov edx, [ebx + xfs_inode.di_core.di_nextents] + bswap edx + stdcall xfs_extent_list_read_dirblock, eax, [ebp + XFS.dir2_leaf_offset_blocks], 0, edx, -1, -1 +;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax + mov ecx, eax + and ecx, edx + inc ecx + jz .error + + mov ebx, [ebp + XFS.cur_dirblock] + movzx eax, [ebx + xfs_dir2_leaf.hdr.count] + ; note that we don't subtract xfs_dir2_leaf.hdr.stale here, + ; since we need the number of leaf entries rather than file number + xchg al, ah + add ebx, xfs_dir2_leaf.ents +; imul ecx, eax, sizeof.xfs_dir2_leaf_entry +; shr ecx, 3 + push eax ; for xfs_get_addr_by_hash: len + push ebx ; for xfs_get_addr_by_hash: base + + mov edi, esi + xor eax, eax + mov ecx, 4096 ; MAX_PATH_LEN + repne scasb + movi eax, ERROR_FS_FAIL + jne .error + neg ecx + add ecx, 4096 + dec ecx + mov edx, ecx +;DEBUGF 1,"strlen total : %d\n",edx + mov edi, esi + mov eax, '/' + mov ecx, edx + repne scasb + jne @f + inc ecx + @@: + neg ecx + add ecx, edx +;DEBUGF 1,"strlen current: %d\n",ecx + stdcall xfs_hashname, esi, ecx + add esi, ecx + cmp byte[esi], '/' + jne @f + inc esi + @@: +;DEBUGF 1,"hashed: 0x%x\n",eax + stdcall xfs_get_addr_by_hash + bswap eax +;DEBUGF 1,"got address: 0x%x\n",eax + cmp eax, -1 + jne @f + movi eax, ERROR_FILE_NOT_FOUND + mov ebx, -1 + jmp .error + @@: + + mov ebx, [ebp + XFS.cur_inode_save] + push esi edi + xor edi, edi + mov esi, eax + shld edi, esi, 3 ; get offset + shl esi, 3 ; 2^3 = 8 byte align + mov edx, esi + mov ecx, [ebp + XFS.dirblklog] + add ecx, [ebp + XFS.blocklog] + mov eax, 1 + shl eax, cl + dec eax + and edx, eax + push edx + shrd esi, edi, cl + shr edi, cl + lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] + mov edx, [ebx + xfs_inode.di_core.di_nextents] + bswap edx + stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 +;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax + pop edx + pop edi esi + mov ecx, eax + and ecx, edx + inc ecx + jz .error + + mov ebx, [ebp + XFS.cur_dirblock] + add ebx, edx + mov edx, [ebx + 0] + mov eax, [ebx + 4] + bswap edx + bswap eax +;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax + jmp .quit + + .nodedir: +;DEBUGF 1,"lookupdir: node\n" + mov [ebp + XFS.cur_inode_save], ebx + + mov edi, esi + xor eax, eax + mov ecx, 4096 ; MAX_PATH_LEN + repne scasb + movi eax, ERROR_FS_FAIL + jne .error + neg ecx + add ecx, 4096 ; MAX_PATH_LEN + dec ecx + mov edx, ecx +;DEBUGF 1,"strlen total : %d\n",edx + mov edi, esi + mov eax, '/' + mov ecx, edx + repne scasb + jne @f + inc ecx + @@: + neg ecx + add ecx, edx +;DEBUGF 1,"strlen current: %d\n",ecx + stdcall xfs_hashname, esi, ecx + add esi, ecx + cmp byte[esi], '/' + jne @f + inc esi + @@: +;DEBUGF 1,"hashed: 0x%x\n",eax + push edi edx + mov edi, eax + mov [ebp + XFS.entries_read], 0 + lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] + mov edx, [ebx + xfs_inode.di_core.di_nextents] + bswap edx + stdcall xfs_dir2_lookupdir_node, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks], edi + pop edx edi + test eax, eax + jnz .error + bswap ecx +;DEBUGF 1,"got address: 0x%x\n",ecx + + mov ebx, [ebp + XFS.cur_inode_save] + push esi edi + xor edi, edi + mov esi, ecx + shld edi, esi, 3 ; get offset + shl esi, 3 ; 8 byte align + mov edx, esi + mov ecx, [ebp + XFS.dirblklog] + add ecx, [ebp + XFS.blocklog] + mov eax, 1 + shl eax, cl + dec eax + and edx, eax + push edx + shrd esi, edi, cl + shr edi, cl + lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] + mov edx, [ebx + xfs_inode.di_core.di_nextents] + bswap edx + stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 +;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax + pop edx + pop edi esi + mov ecx, eax + and ecx, edx + inc ecx + jz .error + + mov ebx, [ebp + XFS.cur_dirblock] + add ebx, edx + mov edx, [ebx + 0] + mov eax, [ebx + 4] + bswap edx + bswap eax +;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax + jmp .quit + + .btreedir: +DEBUGF 1,"lookupdir: btree\n" + mov [ebp + XFS.cur_inode_save], ebx + + push ebx edx + mov eax, [ebx + xfs_inode.di_core.di_nextents] + bswap eax + mov [ebp + XFS.ro_nextents], eax + mov eax, [ebp + XFS.inodesize] + sub eax, xfs_inode.di_u + sub eax, sizeof.xfs_bmdr_block + shr eax, 4 ; FIXME forkoff +;DEBUGF 1,"maxnumresc: %d\n",eax + mov edx, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 0] + mov eax, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 4] + bswap eax + bswap edx + mov ebx, [ebp + XFS.cur_block] +;DEBUGF 1,"read_block: %x %x ",edx,eax + stdcall xfs_read_block + pop edx ebx + test eax, eax + jnz .error +;DEBUGF 1,"ok\n" + mov ebx, [ebp + XFS.cur_block] + + mov edi, esi + xor eax, eax + mov ecx, 4096 ; MAX_PATH_LEN + repne scasb + movi eax, ERROR_FS_FAIL + jne .error + neg ecx + add ecx, 4096 + dec ecx + mov edx, ecx +DEBUGF 1,"strlen total : %d\n",edx + mov edi, esi + mov eax, '/' + mov ecx, edx + repne scasb + jne @f + inc ecx + @@: + neg ecx + add ecx, edx +DEBUGF 1,"strlen current: %d\n",ecx + stdcall xfs_hashname, esi, ecx + add esi, ecx + cmp byte[esi], '/' + jne @f + inc esi + @@: +DEBUGF 1,"hashed: 0x%x\n",eax + push edi edx + mov edi, eax + mov [ebp + XFS.entries_read], 0 + lea eax, [ebx + sizeof.xfs_bmbt_block] + mov edx, [ebp + XFS.ro_nextents] +;push eax +;mov eax, [ebp + XFS.dir2_leaf_offset_blocks] +;DEBUGF 1,": 0x%x %d\n",eax,eax +;pop eax + stdcall xfs_dir2_lookupdir_node, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks], edi + pop edx edi + test eax, eax + jnz .error + bswap ecx +DEBUGF 1,"got address: 0x%x\n",ecx + + mov ebx, [ebp + XFS.cur_block] + push esi edi + xor edi, edi + mov esi, ecx + shld edi, esi, 3 ; get offset + shl esi, 3 + mov edx, esi + mov ecx, [ebp + XFS.dirblklog] + add ecx, [ebp + XFS.blocklog] + mov eax, 1 + shl eax, cl + dec eax + and edx, eax + push edx + shrd esi, edi, cl + shr edi, cl + lea eax, [ebx + sizeof.xfs_bmbt_block] + mov edx, [ebp + XFS.ro_nextents] + stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 +;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax + pop edx + pop edi esi + mov ecx, eax + and ecx, edx + inc ecx + jz .error + + mov ebx, [ebp + XFS.cur_dirblock] + add ebx, edx + mov edx, [ebx + 0] + mov eax, [ebx + 4] + bswap edx + bswap eax +DEBUGF 1,"found inode: 0x%x%x\n",edx,eax + jmp .quit + + .quit: + ret 12 + .error: + xor eax, eax + mov edx, eax + ret 12 + + +;---------------------------------------------------------------- +; push name +; call xfs_get_inode +; test eax, eax +;---------------------------------------------------------------- +xfs_get_inode: + ; call xfs_get_inode_short until file is found / error returned + +DEBUGF 1,"getting inode of: %s\n",[esp+4] + push ebx esi edi + + ; start from the root inode + + mov edx, dword[ebp + XFS.rootino + 4] ; hi + mov eax, dword[ebp + XFS.rootino + 0] ; lo + mov esi, [esp + 16] ; name + + .next_dir: + cmp byte[esi], 0 + jz .found + +;DEBUGF 1,"next_level: |%s|\n",esi + stdcall xfs_get_inode_short, esi, eax, edx + test edx, edx + jnz @f + test eax, eax + jz .error + @@: + jmp .next_dir ; file name found, go to next directory level + + .found: +DEBUGF 1, "inode found: 0x%x%x\n", edx, eax + + .quit: + pop edi esi ebx + ret 4 + .error: + pop edi esi ebx + xor eax, eax + mov edx, eax + ret 4 + + +;---------------------------------------------------------------- +; xfs_ReadFolder - XFS implementation of reading a folder +; in: ebp = pointer to XFS structure +; in: esi+[esp+4] = name +; in: ebx = pointer to parameters from sysfunc 70 +; out: eax, ebx = return values for sysfunc 70 +;---------------------------------------------------------------- +xfs_ReadFolder: + + ; to read folder + ; 1. lock partition + ; 2. find inode number + ; 3. read this inode + ; 4. get bdfe's + ; 5. unlock partition + + ; 1. + call xfs_lock + push ecx edx esi edi + + ; 2. + push ebx esi edi + add esi, [esp + 32] ; directory name +DEBUGF 1,"xfs_ReadFolder: |%s|\n",esi + stdcall xfs_get_inode, esi + pop edi esi ebx + mov ecx, edx + or ecx, eax + jnz @f + movi eax, ERROR_FILE_NOT_FOUND + jmp .error + @@: + + ; 3. + stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode] + test eax, eax + movi eax, ERROR_FS_FAIL + jnz .error + + ; 4. + mov eax, [ebx + 8] ; encoding + and eax, 1 + stdcall xfs_dir_get_bdfes, [ebx + 4], [ebx + 12], [ebx + 16], edx, eax + test eax, eax + jnz .error + + .quit: +;DEBUGF 1,"\n\n" + pop edi esi edx ecx + ; 5. + call xfs_unlock + xor eax, eax + ret + .error: +;DEBUGF 1,"\n\n" + pop edi esi edx ecx + push eax + call xfs_unlock + pop eax + ret + + +;---------------------------------------------------------------- +; push inode_num_hi +; push inode_num_lo +; push [count] +; call xfs_get_inode_number_sf +;---------------------------------------------------------------- +xfs_get_inode_number_sf: + + ; inode numbers in short form directories may be 4 or 8 bytes long + ; determine the length in run time and read inode number at given address + + cmp byte[esp + 4 + xfs_dir2_sf_hdr.i8count], 0 ; i8count == 0 means 4 byte per inode number + je .i4bytes + .i8bytes: + mov edx, [esp + 12] ; hi + mov eax, [esp + 8] ; lo + bswap edx ; big endian + bswap eax + ret 12 + .i4bytes: + xor edx, edx ; no hi + mov eax, [esp + 12] ; hi = lo + bswap eax ; big endian + ret 12 + + +;---------------------------------------------------------------- +; push dest +; push src +; call xfs_get_inode_info +;---------------------------------------------------------------- +xfs_get_inode_info: + + ; get access time and other file properties + ; useful for browsing directories + ; called for each dir entry + +;DEBUGF 1,"get_inode_info\n" + xor eax, eax + mov edx, [esp + 4] + movzx ecx, word[edx + xfs_inode.di_core.di_mode] + xchg cl, ch +;DEBUGF 1,"di_mode: %x\n",ecx + test ecx, S_IFDIR ; directory? + jz @f + mov eax, 0x10 ; set directory flag + @@: + + mov edi, [esp + 8] + mov [edi + 0], eax + mov eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi + bswap eax + mov dword[edi + 36], eax ; file size hi +;DEBUGF 1,"file_size hi: %d\n",eax + mov eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo + bswap eax + mov dword[edi + 32], eax ; file size lo +;DEBUGF 1,"file_size lo: %d\n",eax + + add edi, 8 + mov eax, [edx + xfs_inode.di_core.di_ctime.t_sec] + bswap eax + push edx + sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60 + call fsTime2bdfe + pop edx + + mov eax, [edx + xfs_inode.di_core.di_atime.t_sec] + bswap eax + push edx + sub eax, 978307200 + call fsTime2bdfe + pop edx + + mov eax, [edx + xfs_inode.di_core.di_mtime.t_sec] + bswap eax + push edx + sub eax, 978307200 + call fsTime2bdfe + pop edx + + .quit: + xor eax, eax + ret 8 + .error: + movi eax, ERROR_FS_FAIL + ret 8 + + +;---------------------------------------------------------------- +; push extent_data +; call xfs_extent_unpack +;---------------------------------------------------------------- +xfs_extent_unpack: + + ; extents come as packet 128bit bitfields + ; lets unpack them to access internal fields + ; write result to the XFS.extent structure + + push eax ebx ecx edx + mov ebx, [esp + 20] + + xor eax, eax + mov edx, [ebx + 0] + bswap edx + test edx, 0x80000000 ; mask, see documentation + setnz al + mov [ebp + XFS.extent.br_state], eax + + and edx, 0x7fffffff ; mask + mov eax, [ebx + 4] + bswap eax + shrd eax, edx, 9 + shr edx, 9 + mov dword[ebp + XFS.extent.br_startoff + 0], eax + mov dword[ebp + XFS.extent.br_startoff + 4], edx + + mov edx, [ebx + 4] + mov eax, [ebx + 8] + mov ecx, [ebx + 12] + bswap edx + bswap eax + bswap ecx + and edx, 0x000001ff ; mask + shrd ecx, eax, 21 + shrd eax, edx, 21 + mov dword[ebp + XFS.extent.br_startblock + 0], ecx + mov dword[ebp + XFS.extent.br_startblock + 4], eax + + mov eax, [ebx + 12] + bswap eax + and eax, 0x001fffff ; mask + mov [ebp + XFS.extent.br_blockcount], eax + + pop edx ecx ebx eax +;DEBUGF 1,"extent.br_startoff : %d %d\n",[ebp+XFS.extent.br_startoff+4],[ebp+XFS.extent.br_startoff+0] +;DEBUGF 1,"extent.br_startblock: %d %d\n",[ebp+XFS.extent.br_startblock+4],[ebp+XFS.extent.br_startblock+0] +;DEBUGF 1,"extent.br_blockcount: %d\n",[ebp+XFS.extent.br_blockcount] +;DEBUGF 1,"extent.br_state : %d\n",[ebp+XFS.extent.br_state] + ret 4 + + +;---------------------------------------------------------------- +; push namelen +; push name +; call xfs_hashname +;---------------------------------------------------------------- +xfs_hashname: ; xfs_da_hashname + + ; simple hash function + ; never fails) + + push ecx esi + xor eax, eax + mov esi, [esp + 12] ; name + mov ecx, [esp + 16] ; namelen +;mov esi, '.' +;mov ecx, 1 +;DEBUGF 1,"hashname: %d %s\n",ecx,esi + + @@: + rol eax, 7 + xor al, [esi] + add esi, 1 + loop @b + + pop esi ecx + ret 8 + + +;---------------------------------------------------------------- +; push len +; push base +; eax -- hash value +; call xfs_get_addr_by_hash +;---------------------------------------------------------------- +xfs_get_addr_by_hash: + + ; look for the directory entry offset by its file name hash + ; allows fast file search for block, leaf and node directories + ; binary (ternary) search + +;DEBUGF 1,"get_addr_by_hash\n" + push ebx esi + mov ebx, [esp + 12] ; left + mov edx, [esp + 16] ; len + .next: + mov ecx, edx +; jecxz .error + test ecx, ecx + jz .error + shr ecx, 1 + mov esi, [ebx + ecx*8 + xfs_dir2_leaf_entry.hashval] + bswap esi +;DEBUGF 1,"cmp 0x%x",esi + cmp eax, esi + jb .below + ja .above + mov eax, [ebx + ecx*8 + xfs_dir2_leaf_entry.address] + pop esi ebx + ret 8 + .below: +;DEBUGF 1,"b\n" + mov edx, ecx + jmp .next + .above: +;DEBUGF 1,"a\n" + lea ebx, [ebx + ecx*8 + 8] + sub edx, ecx + dec edx + jmp .next + .error: + mov eax, -1 + pop esi ebx + ret 8 + + +;---------------------------------------------------------------- +; xfs_GetFileInfo - XFS implementation of getting file info +; in: ebp = pointer to XFS structure +; in: esi+[esp+4] = name +; in: ebx = pointer to parameters from sysfunc 70 +; out: eax, ebx = return values for sysfunc 70 +;---------------------------------------------------------------- +xfs_GetFileInfo: + + ; lock partition + ; get inode number by file name + ; read inode + ; get info + ; unlock partition + + push ecx edx esi edi + call xfs_lock + + add esi, [esp + 20] ; name +;DEBUGF 1,"xfs_GetFileInfo: |%s|\n",esi + stdcall xfs_get_inode, esi + mov ecx, edx + or ecx, eax + jnz @f + movi eax, ERROR_FILE_NOT_FOUND + jmp .error + @@: + stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode] + test eax, eax + movi eax, ERROR_FS_FAIL + jnz .error + + stdcall xfs_get_inode_info, edx, [ebx + 16] + + .quit: + call xfs_unlock + pop edi esi edx ecx + xor eax, eax +;DEBUGF 1,"quit\n\n" + ret + .error: + call xfs_unlock + pop edi esi edx ecx +;DEBUGF 1,"error\n\n" + ret + + +;---------------------------------------------------------------- +; xfs_ReadFile - XFS implementation of reading a file +; in: ebp = pointer to XFS structure +; in: esi+[esp+4] = name +; in: ebx = pointer to parameters from sysfunc 70 +; out: eax, ebx = return values for sysfunc 70 +;---------------------------------------------------------------- +xfs_ReadFile: + push ebx ecx edx esi edi + call xfs_lock + add esi, [esp + 24] + stdcall xfs_get_inode, esi + mov ecx, edx + or ecx, eax + jnz @f + movi eax, ERROR_FILE_NOT_FOUND + jmp .error + @@: + stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode] + test eax, eax + movi eax, ERROR_FS_FAIL + jnz .error + mov [ebp + XFS.cur_inode_save], edx + + cmp byte[edx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS + jne .not_extent_list + jmp .extent_list + .not_extent_list: + cmp byte[edx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE + jne .not_btree + jmp .btree + .not_btree: +DEBUGF 1,"XFS: NOT IMPLEMENTED: FILE FORMAT\n" + movi eax, ERROR_FS_FAIL + jmp .error + .extent_list: + mov ecx, [ebx + 12] ; bytes to read + mov edi, [ebx + 16] ; buffer for data + mov esi, [ebx + 8] ; offset_hi + mov ebx, [ebx + 4] ; offset_lo + + mov eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo + bswap eax + mov dword[ebp + XFS.bytes_left_in_file + 0], eax ; lo + mov eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi + bswap eax + mov dword[ebp + XFS.bytes_left_in_file + 4], eax ; hi + + mov eax, [edx + xfs_inode.di_core.di_nextents] + bswap eax + mov [ebp + XFS.left_extents], eax + + mov dword[ebp + XFS.bytes_read], 0 ; actually read bytes + + xor eax, eax ; extent offset in list + .extent_list.next_extent: +;DEBUGF 1,"extent_list.next_extent, eax: 0x%x\n",eax +;DEBUGF 1,"bytes_to_read: %d\n",ecx +;DEBUGF 1,"cur file offset: %d %d\n",esi,ebx +;DEBUGF 1,"esp: 0x%x\n",esp + cmp [ebp + XFS.left_extents], 0 + jne @f + test ecx, ecx + jz .quit + movi eax, ERROR_END_OF_FILE + jmp .error + @@: + push eax + lea eax, [edx + xfs_inode.di_u + eax + xfs_bmbt_rec.l0] + stdcall xfs_extent_unpack, eax + pop eax + dec [ebp + XFS.left_extents] + add eax, sizeof.xfs_bmbt_rec + push eax ebx ecx edx esi + mov ecx, [ebp + XFS.blocklog] + shrd ebx, esi, cl + shr esi, cl + cmp esi, dword[ebp + XFS.extent.br_startoff + 4] + jb .extent_list.to_hole ; handle sparse files + ja @f + cmp ebx, dword[ebp + XFS.extent.br_startoff + 0] + jb .extent_list.to_hole ; handle sparse files + je .extent_list.to_extent ; read from the start of current extent + @@: + xor edx, edx + mov eax, [ebp + XFS.extent.br_blockcount] + add eax, dword[ebp + XFS.extent.br_startoff + 0] + adc edx, dword[ebp + XFS.extent.br_startoff + 4] +;DEBUGF 1,"br_startoff: %d %d\n",edx,eax + cmp esi, edx + ja .extent_list.skip_extent + jb .extent_list.to_extent + cmp ebx, eax + jae .extent_list.skip_extent + jmp .extent_list.to_extent + .extent_list.to_hole: +;DEBUGF 1,"extent_list.to_hole\n" + pop esi edx ecx ebx eax + jmp .extent_list.read_hole + .extent_list.to_extent: +;DEBUGF 1,"extent_list.to_extent\n" + pop esi edx ecx ebx eax + jmp .extent_list.read_extent + .extent_list.skip_extent: +;DEBUGF 1,"extent_list.skip_extent\n" + pop esi edx ecx ebx eax + jmp .extent_list.next_extent + + .extent_list.read_hole: +;DEBUGF 1,"hole: offt: 0x%x%x ",esi,ebx + push eax edx + mov eax, dword[ebp + XFS.extent.br_startoff + 0] + mov edx, dword[ebp + XFS.extent.br_startoff + 4] + push esi ebx + mov ebx, ecx + sub eax, ebx ; get hole_size, it is 64 bit + sbb edx, 0 ; now edx:eax contains the size of hole +;DEBUGF 1,"size: 0x%x%x\n",edx,eax + jnz @f ; if hole size >= 2^32, write bytes_to_read zero bytes + cmp eax, ecx ; if hole size >= bytes_to_read, write bytes_to_read zeros + jae @f + mov ecx, eax ; if hole is < than bytes_to_read, write hole size zeros + @@: + sub ebx, ecx ; bytes_to_read - hole_size = left_to_read + add dword[esp + 0], ecx ; update pushed file offset + adc dword[esp + 4], 0 + xor eax, eax ; hole is made of zeros + rep stosb + mov ecx, ebx + pop ebx esi + + test ecx, ecx ; all requested bytes are read? + pop edx eax + jz .quit + jmp .extent_list.read_extent ; continue from the start of unpacked extent + + .extent_list.read_extent: +;DEBUGF 1,"extent_list.read_extent\n" + push eax ebx ecx edx esi + mov eax, ebx + mov edx, esi + mov ecx, [ebp + XFS.blocklog] + shrd eax, edx, cl + shr edx, cl + sub eax, dword[ebp + XFS.extent.br_startoff + 0] ; skip esi:ebx ? + sbb edx, dword[ebp + XFS.extent.br_startoff + 4] + sub [ebp + XFS.extent.br_blockcount], eax + add dword[ebp + XFS.extent.br_startblock + 0], eax + adc dword[ebp + XFS.extent.br_startblock + 4], 0 + .extent_list.read_extent.next_block: +;DEBUGF 1,"extent_list.read_extent.next_block\n" + cmp [ebp + XFS.extent.br_blockcount], 0 ; out of blocks in current extent? + jne @f + pop esi edx ecx ebx eax + jmp .extent_list.next_extent ; go to next extent + @@: + mov eax, dword[ebp + XFS.extent.br_startblock + 0] + mov edx, dword[ebp + XFS.extent.br_startblock + 4] + push ebx + mov ebx, [ebp + XFS.cur_block] +;DEBUGF 1,"read block: 0x%x%x\n",edx,eax + stdcall xfs_read_block + test eax, eax + pop ebx + jz @f + pop esi edx ecx ebx eax + movi eax, ERROR_FS_FAIL + jmp .error + @@: + dec [ebp + XFS.extent.br_blockcount] + add dword[ebp + XFS.extent.br_startblock + 0], 1 + adc dword[ebp + XFS.extent.br_startblock + 4], 0 + mov esi, [ebp + XFS.cur_block] + mov ecx, [ebp + XFS.blocklog] + mov eax, 1 + shl eax, cl + dec eax ; get blocklog mask + and eax, ebx ; offset in current block + add esi, eax + neg eax + add eax, [ebp + XFS.blocksize] + mov ecx, [esp + 8] ; pushed ecx, bytes_to_read + cmp ecx, eax ; is current block enough? + jbe @f ; if so, read bytes_to_read bytes + mov ecx, eax ; otherwise read the block up to the end + @@: + sub [esp + 8], ecx ; left_to_read + add [esp + 12], ecx ; update current file offset, pushed ebx + sub dword[ebp + XFS.bytes_left_in_file + 0], ecx + sbb dword[ebp + XFS.bytes_left_in_file + 4], 0 + jnc @f + add dword[ebp + XFS.bytes_left_in_file + 0], ecx + mov ecx, dword[ebp + XFS.bytes_left_in_file + 0] + mov dword[ebp + XFS.bytes_left_in_file + 0], 0 + mov dword[ebp + XFS.bytes_left_in_file + 4], 0 + @@: + add [ebp + XFS.bytes_read], ecx + adc [esp + 0], dword 0 ; pushed esi +;DEBUGF 1,"read data: %d\n",ecx + rep movsb + mov ecx, [esp + 8] +;DEBUGF 1,"left_to_read: %d\n",ecx + xor ebx, ebx + test ecx, ecx + jz @f + cmp dword[ebp + XFS.bytes_left_in_file + 4], 0 + jne .extent_list.read_extent.next_block + cmp dword[ebp + XFS.bytes_left_in_file + 0], 0 + jne .extent_list.read_extent.next_block + @@: + pop esi edx ecx ebx eax + jmp .quit + + .btree: + mov ecx, [ebx + 12] ; bytes to read + mov [ebp + XFS.bytes_to_read], ecx + mov edi, [ebx + 16] ; buffer for data + mov esi, [ebx + 8] ; offset_hi + mov ebx, [ebx + 4] ; offset_lo + mov dword[ebp + XFS.file_offset + 0], ebx + mov dword[ebp + XFS.file_offset + 4], esi + mov [ebp + XFS.buffer_pos], edi + + mov eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo + bswap eax + mov dword[ebp + XFS.bytes_left_in_file + 0], eax ; lo + mov eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi + bswap eax + mov dword[ebp + XFS.bytes_left_in_file + 4], eax ; hi + + mov eax, [edx + xfs_inode.di_core.di_nextents] + bswap eax + mov [ebp + XFS.left_extents], eax + + mov dword[ebp + XFS.bytes_read], 0 ; actually read bytes + + push ebx ecx edx esi edi + mov [ebp + XFS.eof], 0 + mov eax, dword[ebp + XFS.file_offset + 0] + mov edx, dword[ebp + XFS.file_offset + 4] + add eax, [ebp + XFS.bytes_to_read] + adc edx, 0 + sub eax, dword[ebp + XFS.bytes_left_in_file + 0] + sbb edx, dword[ebp + XFS.bytes_left_in_file + 4] + jc @f ; file_offset + bytes_to_read < file_size + jz @f ; file_offset + bytes_to_read = file_size + mov [ebp + XFS.eof], 1 + cmp edx, 0 + jne .error.eof + sub dword[ebp + XFS.bytes_to_read], eax + jc .error.eof + jz .error.eof + @@: + stdcall xfs_btree_read, 0, 0, 1 + pop edi esi edx ecx ebx + test eax, eax + jnz .error + cmp [ebp + XFS.eof], 1 + jne .quit + jmp .error.eof + + + .quit: + call xfs_unlock + pop edi esi edx ecx ebx + xor eax, eax + mov ebx, [ebp + XFS.bytes_read] +;DEBUGF 1,"quit: %d\n\n",ebx + ret + .error.eof: + movi eax, ERROR_END_OF_FILE + .error: +;DEBUGF 1,"error\n\n" + call xfs_unlock + pop edi esi edx ecx ebx + mov ebx, [ebp + XFS.bytes_read] + ret + + +;---------------------------------------------------------------- +; push max_offset_hi +; push max_offset_lo +; push nextents +; push block_number_hi +; push block_number_lo +; push extent_list +; -1 / read block number +;---------------------------------------------------------------- +xfs_extent_list_read_dirblock: ; skips holes +;DEBUGF 1,"xfs_extent_list_read_dirblock\n" + push ebx esi edi +;mov eax, [esp+28] +;DEBUGF 1,"nextents: %d\n",eax +;mov eax, [esp+20] +;mov edx, [esp+24] +;DEBUGF 1,"block_number: 0x%x%x\n",edx,eax +;mov eax, [esp+32] +;mov edx, [esp+36] +;DEBUGF 1,"max_addr : 0x%x%x\n",edx,eax + mov ebx, [esp + 16] + mov esi, [esp + 20] + mov edi, [esp + 24] +; mov ecx, [esp + 28] ; nextents + .next_extent: +;DEBUGF 1,"next_extent\n" + dec dword[esp + 28] + js .error + stdcall xfs_extent_unpack, ebx + add ebx, sizeof.xfs_bmbt_rec ; next extent + mov edx, dword[ebp + XFS.extent.br_startoff + 4] + mov eax, dword[ebp + XFS.extent.br_startoff + 0] + cmp edx, [esp + 36] ; max_offset_hi + ja .error + jb @f + cmp eax, [esp + 32] ; max_offset_lo + jae .error + @@: + cmp edi, edx + jb .hole + ja .check_count + cmp esi, eax + jb .hole + ja .check_count + jmp .read_block + .hole: +;DEBUGF 1,"hole\n" + mov esi, eax + mov edi, edx + jmp .read_block + .check_count: +;DEBUGF 1,"check_count\n" + add eax, [ebp + XFS.extent.br_blockcount] + adc edx, 0 + cmp edi, edx + ja .next_extent + jb .read_block + cmp esi, eax + jae .next_extent +; jmp .read_block + .read_block: +;DEBUGF 1,"read_block\n" + push esi edi + sub esi, dword[ebp + XFS.extent.br_startoff + 0] + sbb edi, dword[ebp + XFS.extent.br_startoff + 4] + add esi, dword[ebp + XFS.extent.br_startblock + 0] + adc edi, dword[ebp + XFS.extent.br_startblock + 4] + stdcall xfs_read_dirblock, esi, edi, [ebp + XFS.cur_dirblock] + pop edx eax + .quit: +;DEBUGF 1,"xfs_extent_list_read_dirblock: quit\n" + pop edi esi ebx + ret 24 + .error: +;DEBUGF 1,"xfs_extent_list_read_dirblock: error\n" + xor eax, eax + dec eax + mov edx, eax + pop edi esi ebx + ret 24 + + +;---------------------------------------------------------------- +; push dirblock_num +; push nextents +; push extent_list +;---------------------------------------------------------------- +xfs_dir2_node_get_numfiles: + + ; unfortunately, we need to set 'total entries' field + ; this often requires additional effort, since there is no such a number in most directory ondisk formats + +;DEBUGF 1,"xfs_dir2_node_get_numfiles\n" + push ebx ecx edx esi edi + + mov eax, [esp + 24] + mov edx, [esp + 28] + mov esi, [esp + 32] + stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1 + mov ecx, eax + and ecx, edx + inc ecx + jnz @f + movi eax, ERROR_FS_FAIL + jmp .error + @@: + mov ebx, [ebp + XFS.cur_dirblock] + cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC + je .node + cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC + je .leaf + mov eax, ERROR_FS_FAIL + jmp .error + + .node: +;DEBUGF 1,".node\n" + mov edi, [ebx + xfs_da_intnode.hdr.info.forw] + bswap edi + mov eax, [esp + 24] + mov edx, [esp + 28] + mov esi, [ebx + xfs_da_intnode.btree.before] + bswap esi + stdcall xfs_dir2_node_get_numfiles, eax, edx, esi + test eax, eax + jnz .error + jmp .common + + .leaf: +;DEBUGF 1,".leaf\n" + movzx ecx, word[ebx + xfs_dir2_leaf.hdr.count] + xchg cl, ch + movzx eax, word[ebx + xfs_dir2_leaf.hdr.stale] + xchg al, ah + sub ecx, eax + add [ebp + XFS.entries_read], ecx + mov edi, [ebx + xfs_dir2_leaf.hdr.info.forw] + bswap edi + jmp .common + + .common: + test edi, edi + jz .quit + mov esi, edi + mov eax, [esp + 24] + mov edx, [esp + 28] + stdcall xfs_dir2_node_get_numfiles, eax, edx, esi + test eax, eax + jnz .error + jmp .quit + + .quit: +;DEBUGF 1,".quit\n" + pop edi esi edx ecx ebx + xor eax, eax + ret 12 + .error: +;DEBUGF 1,".error\n" + pop edi esi edx ecx ebx + movi eax, ERROR_FS_FAIL + ret 12 + + +;---------------------------------------------------------------- +; push hash +; push dirblock_num +; push nextents +; push extent_list +;---------------------------------------------------------------- +xfs_dir2_lookupdir_node: +DEBUGF 1,"xfs_dir2_lookupdir_node\n" + push ebx edx esi edi + + mov eax, [esp + 20] + mov edx, [esp + 24] + mov esi, [esp + 28] +DEBUGF 1,"read dirblock: 0x%x %d\n",esi,esi + stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1 +DEBUGF 1,"dirblock read: 0x%x%x\n",edx,eax + mov ecx, eax + and ecx, edx + inc ecx + jnz @f + movi eax, ERROR_FS_FAIL + jmp .error + @@: +DEBUGF 1,"checkpoint #1\n" + mov ebx, [ebp + XFS.cur_dirblock] + cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC + je .node + cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC + je .leaf + mov eax, ERROR_FS_FAIL +DEBUGF 1,"checkpoint #2\n" + jmp .error + + .node: +DEBUGF 1,".node\n" + mov edi, [esp + 32] ; hash + movzx ecx, word[ebx + xfs_da_intnode.hdr.count] + xchg cl, ch + mov [ebp + XFS.left_leaves], ecx + xor ecx, ecx + .node.next_leaf: + mov esi, [ebx + xfs_da_intnode.btree + ecx*sizeof.xfs_da_node_entry + xfs_da_node_entry.hashval] + bswap esi + cmp edi, esi + jbe .node.leaf_found + inc ecx + cmp ecx, [ebp + XFS.left_leaves] + jne .node.next_leaf + mov eax, ERROR_FILE_NOT_FOUND + jmp .error + @@: + .node.leaf_found: + mov eax, [esp + 20] + mov edx, [esp + 24] + mov esi, [ebx + xfs_da_intnode.btree + ecx*sizeof.xfs_da_node_entry + xfs_da_node_entry.before] + bswap esi + stdcall xfs_dir2_lookupdir_node, eax, edx, esi, edi + test eax, eax + jz .quit + movi eax, ERROR_FILE_NOT_FOUND + jmp .error + + .leaf: +DEBUGF 1,".leaf\n" + movzx ecx, [ebx + xfs_dir2_leaf.hdr.count] + xchg cl, ch + lea esi, [ebx + xfs_dir2_leaf.ents] + mov eax, [esp + 32] + stdcall xfs_get_addr_by_hash, esi, ecx + cmp eax, -1 + je .error + mov ecx, eax + jmp .quit + + .quit: +DEBUGF 1,".quit\n" + pop edi esi edx ebx + xor eax, eax + ret 16 + .error: +DEBUGF 1,".error\n" + pop edi esi edx ebx + ret 16 + + +;---------------------------------------------------------------- +; push dirblock_num +; push nextents +; push extent_list +;---------------------------------------------------------------- +xfs_dir2_btree_get_numfiles: +;DEBUGF 1,"xfs_dir2_node_get_numfiles\n" + push ebx ecx edx esi edi + + mov eax, [esp + 24] + mov edx, [esp + 28] + mov esi, [esp + 32] + stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1 + mov ecx, eax + and ecx, edx + inc ecx + jnz @f + movi eax, ERROR_FS_FAIL + jmp .error + @@: + mov ebx, [ebp + XFS.cur_dirblock] + cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC + je .node + cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC + je .leaf + mov eax, ERROR_FS_FAIL + jmp .error + + .node: +;DEBUGF 1,".node\n" + mov edi, [ebx + xfs_da_intnode.hdr.info.forw] + bswap edi + mov eax, [esp + 24] + mov edx, [esp + 28] + mov esi, [ebx + xfs_da_intnode.btree.before] + bswap esi + stdcall xfs_dir2_node_get_numfiles, eax, edx, esi + test eax, eax + jnz .error + jmp .common + + .leaf: +;DEBUGF 1,".leaf\n" + movzx ecx, word[ebx + xfs_dir2_leaf.hdr.count] + xchg cl, ch + movzx eax, word[ebx + xfs_dir2_leaf.hdr.stale] + xchg al, ah + sub ecx, eax + add [ebp + XFS.entries_read], ecx + mov edi, [ebx + xfs_dir2_leaf.hdr.info.forw] + bswap edi + jmp .common + + .common: + test edi, edi + jz .quit + mov esi, edi + mov eax, [esp + 24] + mov edx, [esp + 28] + stdcall xfs_dir2_node_get_numfiles, eax, edx, esi + test eax, eax + jnz .error + jmp .quit + + .quit: +;DEBUGF 1,".quit\n" + pop edi esi edx ecx ebx + xor eax, eax + ret 12 + .error: +;DEBUGF 1,".error\n" + pop edi esi edx ecx ebx + movi eax, ERROR_FS_FAIL + ret 12 + + +;---------------------------------------------------------------- +; push is_root +; push block_hi +; push block_lo +;---------------------------------------------------------------- +xfs_btree_read: + push ebx ecx edx esi edi + cmp dword[esp + 32], 1 ; is root? + je .root + jmp .not_root + .root: +DEBUGF 1,".root\n" + mov ebx, [ebp + XFS.cur_inode_save] + add ebx, xfs_inode.di_u + movzx edx, [ebx + xfs_bmdr_block.bb_numrecs] + xchg dl, dh + dec edx + add ebx, sizeof.xfs_bmdr_block + xor eax, eax + dec eax + .root.next_key: +DEBUGF 1,".root.next_key\n" + cmp [ebp + XFS.bytes_to_read], 0 + je .quit + inc eax + cmp eax, edx ; out of keys? + ja .root.key_found ; there is no length field, so try the last key + lea edi, [ebx + sizeof.xfs_bmbt_key*eax + 0] + lea esi, [ebx + sizeof.xfs_bmbt_key*eax + 4] + bswap edi + bswap esi + mov ecx, [ebp + XFS.blocklog] + shld edi, esi, cl + shl esi, cl + cmp edi, dword[ebp + XFS.file_offset + 4] + ja .root.prev_or_hole + jb .root.next_key + cmp esi, dword[ebp + XFS.file_offset + 0] + ja .root.prev_or_hole + jb .root.next_key + jmp .root.key_found + .root.prev_or_hole: +DEBUGF 1,".root.prev_or_hole\n" + test eax, eax + jz .root.hole + dec eax + jmp .root.key_found + .root.hole: +DEBUGF 1,".root.hole\n" + push eax edx esi edi + mov ecx, [ebp + XFS.blocklog] + shld edi, esi, cl + shl esi, cl + sub esi, dword[ebp + XFS.file_offset + 0] + sbb edi, dword[ebp + XFS.file_offset + 4] + mov ecx, [ebp + XFS.bytes_to_read] + cmp edi, 0 ; hole size >= 2^32 + jne @f + cmp ecx, esi + jbe @f + mov ecx, esi + @@: + add dword[ebp + XFS.file_offset + 0], ecx + adc dword[ebp + XFS.file_offset + 4], 0 + sub [ebp + XFS.bytes_to_read], ecx + xor eax, eax + mov edi, [ebp + XFS.buffer_pos] + rep stosb + mov [ebp + XFS.buffer_pos], edi + pop edi esi edx eax + jmp .root.next_key + .root.key_found: +DEBUGF 1,".root.key_found\n" + mov edx, [ebp + XFS.cur_inode_save] + mov eax, [ebp + XFS.inodesize] + sub eax, xfs_inode.di_u + cmp [edx + xfs_inode.di_core.di_forkoff], 0 + je @f + movzx eax, [edx + xfs_inode.di_core.di_forkoff] + shl eax, XFS_DIR2_DATA_ALIGN_LOG ; 3 + @@: + sub eax, sizeof.xfs_bmdr_block + shr eax, 4 ;log2(sizeof.xfs_bmbt_key + sizeof.xfs_bmdr_ptr) + mov edx, [ebx + sizeof.xfs_bmbt_key*eax + 0] ; hi + mov eax, [ebx + sizeof.xfs_bmbt_key*eax + 4] ; hi + bswap edx + bswap eax + stdcall xfs_btree_read, eax, edx, 0 + test eax, eax + jnz .error + jmp .root.next_key + + .not_root: +DEBUGF 1,".root.not_root\n" + mov eax, [esp + 24] ; block_lo + mov edx, [esp + 28] ; block_hi + mov ebx, [ebp + XFS.cur_block] + stdcall xfs_read_block + test eax, eax + jnz .error + mov ebx, [ebp + XFS.cur_block] + + cmp [ebx + xfs_bmbt_block.bb_magic], XFS_BMAP_MAGIC + jne .error + cmp [ebx + xfs_bmbt_block.bb_level], 0 ; leaf? + je .leaf + jmp .node + + .node: +; mov eax, [ebp + XFS.blocksize] +; sub eax, sizeof.xfs_bmbt_block +; shr eax, 4 ; maxnumrecs + mov eax, dword[ebp + XFS.file_offset + 0] ; lo + mov edx, dword[ebp + XFS.file_offset + 4] ; hi + movzx edx, [ebx + xfs_bmbt_block.bb_numrecs] + xchg dl, dh + dec edx + add ebx, sizeof.xfs_bmbt_block + xor eax, eax + dec eax + .node.next_key: + push eax ecx edx esi edi + mov eax, [esp + 44] ; block_lo + mov edx, [esp + 48] ; block_hi + mov ebx, [ebp + XFS.cur_block] + stdcall xfs_read_block + test eax, eax + jnz .error + mov ebx, [ebp + XFS.cur_block] + add ebx, sizeof.xfs_bmbt_block + pop edi esi edx ecx eax + cmp [ebp + XFS.bytes_to_read], 0 + je .quit + inc eax + cmp eax, edx ; out of keys? + ja .node.key_found ; there is no length field, so try the last key + lea edi, [ebx + sizeof.xfs_bmbt_key*eax + 0] + lea esi, [ebx + sizeof.xfs_bmbt_key*eax + 4] + bswap edi + bswap esi + mov ecx, [ebp + XFS.blocklog] + shld edi, esi, cl + shl esi, cl + cmp edi, dword[ebp + XFS.file_offset + 4] + ja .node.prev_or_hole + jb .node.next_key + cmp esi, dword[ebp + XFS.file_offset + 0] + ja .node.prev_or_hole + jb .node.next_key + jmp .node.key_found + .node.prev_or_hole: + test eax, eax + jz .node.hole + dec eax + jmp .node.key_found + .node.hole: + push eax edx esi edi + mov ecx, [ebp + XFS.blocklog] + shld edi, esi, cl + shl esi, cl + sub esi, dword[ebp + XFS.file_offset + 0] + sbb edi, dword[ebp + XFS.file_offset + 4] + mov ecx, [ebp + XFS.bytes_to_read] + cmp edi, 0 ; hole size >= 2^32 + jne @f + cmp ecx, esi + jbe @f + mov ecx, esi + @@: + add dword[ebp + XFS.file_offset + 0], ecx + adc dword[ebp + XFS.file_offset + 4], 0 + sub [ebp + XFS.bytes_to_read], ecx + xor eax, eax + mov edi, [ebp + XFS.buffer_pos] + rep stosb + mov [ebp + XFS.buffer_pos], edi + pop edi esi edx eax + jmp .node.next_key + .node.key_found: + mov edx, [ebp + XFS.cur_inode_save] + mov eax, [ebp + XFS.inodesize] + sub eax, xfs_inode.di_u + cmp [edx + xfs_inode.di_core.di_forkoff], 0 + je @f + movzx eax, [edx + xfs_inode.di_core.di_forkoff] + shl eax, XFS_DIR2_DATA_ALIGN_LOG ; 3 + @@: + sub eax, sizeof.xfs_bmdr_block + shr eax, 4 ;log2(sizeof.xfs_bmbt_key + sizeof.xfs_bmdr_ptr) + mov edx, [ebx + sizeof.xfs_bmbt_key*eax + 0] ; hi + mov eax, [ebx + sizeof.xfs_bmbt_key*eax + 4] ; hi + bswap edx + bswap eax + stdcall xfs_btree_read, eax, edx, 0 + test eax, eax + jnz .error + jmp .node.next_key + jmp .quit + + .leaf: + + jmp .quit + + .error: + pop edi esi edx ecx ebx + movi eax, ERROR_FS_FAIL + ret 4 + .quit: + pop edi esi edx ecx ebx + xor eax, eax + ret 4 + + +;---------------------------------------------------------------- +; push nextents +; push extent_list +; push file_offset_hi +; push file_offset_lo +;---------------------------------------------------------------- +;xfs_extent_list_read: +; push ebx 0 edx esi edi ; zero means actually_read_bytes +; +; .quit: +; pop edi esi edx ecx ebx +; xor eax, eax +; ret 24 +; .error: +; pop edi esi edx ecx ebx +; ret 24 diff --git a/xfs.inc b/xfs.inc new file mode 100644 index 0000000..860753f --- /dev/null +++ b/xfs.inc @@ -0,0 +1,529 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 5363 $ + + +; from stat.h +; distinguish file types +S_IFMT = 0170000o ; These bits determine file type. +S_IFDIR = 0040000o ; Directory. +S_IFCHR = 0020000o ; Character device. +S_IFBLK = 0060000o ; Block device. +S_IFREG = 0100000o ; Regular file. +S_IFIFO = 0010000o ; FIFO. +S_IFLNK = 0120000o ; Symbolic link. +S_IFSOCK = 0140000o ; Socket. +; end stat.h + + +; XFS null constant: empty fields must be all ones, not zeros! +XFS_NULL = -1 + + +; static sector numbers +XFS_SECT_SB = 0 +XFS_SECT_AGF = 1 +XFS_SECT_AGI = 2 +XFS_SECT_AGFL = 3 + + +; signatures of file system structures +; 'string' numbers are treated by fasm as big endian +XFS_SB_MAGIC = 'XFSB' +XFS_AGF_MAGIC = 'XAGF' +XFS_AGI_MAGIC = 'XAGI' +XFS_ABTB_MAGIC = 'ABTB' +XFS_ABTC_MAGIC = 'ABTC' +XFS_IBT_MAGIC = 'IABT' +XFS_DINODE_MAGIC = 'IN' +XFS_BMAP_MAGIC = 'BMAP' +XFS_DA_NODE_MAGIC = 0xbefe ; these are little endian here +XFS_ATTR_LEAF_MAGIC = 0xeefb ; but big endian in docs +XFS_DIR2_LEAF1_MAGIC = 0xf1d2 ; pay attention! +XFS_DIR2_LEAFN_MAGIC = 0xffd2 ; +XFS_DIR2_BLOCK_MAGIC = 'XD2B' +XFS_DIR2_DATA_MAGIC = 'XD2D' +XFS_DIR2_FREE_MAGIC = 'XD2F' +XFS_DQUOT_MAGIC = 'DQ' + + +; bitfield lengths for packed extent +; MSB to LSB / left to right +BMBT_EXNTFLAG_BITLEN = 1 +BMBT_STARTOFF_BITLEN = 54 +BMBT_STARTBLOCK_BITLEN = 52 +BMBT_BLOCKCOUNT_BITLEN = 21 + + +; those constants are taken from linux source (xfs_dir2_leaf.h) +; they are magic infile offsets for directories +XFS_DIR2_DATA_ALIGN_LOG = 3 ; i.e., 8 bytes +XFS_DIR2_LEAF_SPACE = 1 +XFS_DIR2_SPACE_SIZE = 1 SHL (32 + XFS_DIR2_DATA_ALIGN_LOG) +XFS_DIR2_LEAF_OFFSET = XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE +XFS_DIR2_FREE_SPACE = 2 +XFS_DIR2_SPACE_SIZE = 1 SHL (32 + XFS_DIR2_DATA_ALIGN_LOG) +XFS_DIR2_FREE_OFFSET = XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE + + +; data section magic constants for directories (xfs_dir2_data.h) +XFS_DIR2_DATA_FD_COUNT = 3 +XFS_DIR2_DATA_FREE_TAG = 0xffff + + +; valid inode formats +; enum xfs_dinode_fmt (xfs_dinode.h) +XFS_DINODE_FMT_DEV = 0 ; xfs_dev_t +XFS_DINODE_FMT_LOCAL = 1 ; one inode is enough (shortdir) +XFS_DINODE_FMT_EXTENTS = 2 ; one or more extents (leafdir, nodedir, regular files) +XFS_DINODE_FMT_BTREE = 3 ; highly fragmented files or really huge directories +XFS_DINODE_FMT_UUID = 4 ; uuid_t + + +; size of the unlinked inode hash table in the agi +XFS_AGI_UNLINKED_BUCKETS = 64 + + +; possible extent states +; enum xfs_exntst_t (xfs_bmap_btree.h) +XFS_EXT_NORM = 0 +XFS_EXT_UNWRITTEN = 1 +XFS_EXT_DMAPI_OFFLINE = 2 +XFS_EXT_INVALID = 3 + + +; values for inode core flags / di_flags (xfs_dinode.h) +XFS_DIFLAG_REALTIME_BIT = 0 ; file's blocks come from rt area +XFS_DIFLAG_PREALLOC_BIT = 1 ; file space has been preallocated +XFS_DIFLAG_NEWRTBM_BIT = 2 ; for rtbitmap inode, new format +XFS_DIFLAG_IMMUTABLE_BIT = 3 ; inode is immutable +XFS_DIFLAG_APPEND_BIT = 4 ; inode is append-only +XFS_DIFLAG_SYNC_BIT = 5 ; inode is written synchronously +XFS_DIFLAG_NOATIME_BIT = 6 ; do not update atime +XFS_DIFLAG_NODUMP_BIT = 7 ; do not dump +XFS_DIFLAG_RTINHERIT_BIT = 8 ; create with realtime bit set +XFS_DIFLAG_PROJINHERIT_BIT = 9 ; create with parents projid +XFS_DIFLAG_NOSYMLINKS_BIT = 10 ; disallow symlink creation +XFS_DIFLAG_EXTSIZE_BIT = 11 ; inode extent size allocator hint +XFS_DIFLAG_EXTSZINHERIT_BIT = 12 ; inherit inode extent size +XFS_DIFLAG_NODEFRAG_BIT = 13 ; do not reorganize/defragment +XFS_DIFLAG_FILESTREAM_BIT = 14 ; use filestream allocator +XFS_DIFLAG_REALTIME = (1 SHL XFS_DIFLAG_REALTIME_BIT) +XFS_DIFLAG_PREALLOC = (1 SHL XFS_DIFLAG_PREALLOC_BIT) +XFS_DIFLAG_NEWRTBM = (1 SHL XFS_DIFLAG_NEWRTBM_BIT) +XFS_DIFLAG_IMMUTABLE = (1 SHL XFS_DIFLAG_IMMUTABLE_BIT) +XFS_DIFLAG_APPEND = (1 SHL XFS_DIFLAG_APPEND_BIT) +XFS_DIFLAG_SYNC = (1 SHL XFS_DIFLAG_SYNC_BIT) +XFS_DIFLAG_NOATIME = (1 SHL XFS_DIFLAG_NOATIME_BIT) +XFS_DIFLAG_NODUMP = (1 SHL XFS_DIFLAG_NODUMP_BIT) +XFS_DIFLAG_RTINHERIT = (1 SHL XFS_DIFLAG_RTINHERIT_BIT) +XFS_DIFLAG_PROJINHERIT = (1 SHL XFS_DIFLAG_PROJINHERIT_BIT) +XFS_DIFLAG_NOSYMLINKS = (1 SHL XFS_DIFLAG_NOSYMLINKS_BIT) +XFS_DIFLAG_EXTSIZE = (1 SHL XFS_DIFLAG_EXTSIZE_BIT) +XFS_DIFLAG_EXTSZINHERIT = (1 SHL XFS_DIFLAG_EXTSZINHERIT_BIT) +XFS_DIFLAG_NODEFRAG = (1 SHL XFS_DIFLAG_NODEFRAG_BIT) +XFS_DIFLAG_FILESTREAM = (1 SHL XFS_DIFLAG_FILESTREAM_BIT) + + +; superblock _ondisk_ structure (xfs_sb.h) +; this is _not_ the partition structure +; for XFS partition structure see XFS below +struct xfs_sb + sb_magicnum dd ? ; signature, must be XFS_SB_MAGIC + sb_blocksize dd ? ; block is the minimal file system unit, in bytes + sb_dblocks dq ? ; number of data blocks + sb_rblocks dq ? ; number of realtime blocks (not supported yet!) + sb_rextents dq ? ; number of realtime extents (not supported yet!) + sb_uuid rb 16 ; file system unique identifier + sb_logstart dq ? ; starting block of log (for internal journal; journals on separate devices are not supported!) + sb_rootino dq ? ; root inode number + sb_rbmino dq ? ; bitmap inode for realtime extents (ignored) + sb_rsumino dq ? ; summary inode for rt bitmap (ignored) + sb_rextsize dd ? ; realtime extent size, blocks + sb_agblocks dd ? ; size of an allocation group (the last one may be smaller!) + sb_agcount dd ? ; number of allocation groups + sb_rbmblocks dd ? ; number of rt bitmap blocks + sb_logblocks dd ? ; number of log blocks + sb_versionnum dw ? ; header version == XFS_SB_VERSION + sb_sectsize dw ? ; volume sector size in bytes (only 512B sectors are supported) + sb_inodesize dw ? ; inode size, bytes + sb_inopblock dw ? ; inodes per block + sb_fname rb 12 ; inodes per block (aka label) + sb_blocklog db ? ; log2 of sb_blocksize + sb_sectlog db ? ; log2 of sb_blocksize + sb_inodelog db ? ; log2 of sb_inodesize + sb_inopblog db ? ; log2 of sb_inopblock + sb_agblklog db ? ; log2 of sb_agblocks (rounded up!) + sb_rextslog db ? ; log2 of sb_rextents + sb_inprogress db ? ; mkfs is in progress, don't mount + sb_imax_pct db ? ; max % of fs for inode space + ; statistics + sb_icount dq ? ; allocated inodes + sb_ifree dq ? ; free inodes + sb_fdblocks dq ? ; free data blocks + sb_frextents dq ? ; free realtime extents + + sb_uquotino dq ? ; user quota inode + sb_gquotino dq ? ; group quota inode + sb_qflags dw ? ; quota flags + sb_flags db ? ; misc. flags + sb_shared_vn db ? ; shared version number + sb_inoalignmt dd ? ; inode chunk alignment, fsblocks + sb_unit dd ? ; stripe or raid unit + sb_width dd ? ; stripe or raid width + sb_dirblklog db ? ; log2 of dir block size (fsbs) + sb_logsectlog db ? ; log2 of the log sector size + sb_logsectsize dw ? ; sector size for the log, bytes + sb_logsunit dd ? ; stripe unit size for the log + sb_features2 dd ? ; additional feature bits +ends + + +; allocation group inode (xfs_ag.h) +struct xfs_agi + agi_magicnum dd ? ; magic number == XFS_AGI_MAGIC + agi_versionnum dd ? ; header version == XFS_AGI_VERSION + agi_seqno dd ? ; sequence number starting from 0 + agi_length dd ? ; size in blocks of a.g. + agi_count dd ? ; count of allocated inodes + agi_root dd ? ; root of inode btree + agi_level dd ? ; levels in inode btree + agi_freecount dd ? ; number of free inodes + agi_newino dd ? ; new inode just allocated + agi_dirino dd ? ; last directory inode chunk + agi_unlinked rd XFS_AGI_UNLINKED_BUCKETS ; Hash table of inodes which have been unlinked but are still being referenced +ends + + +; superblock structure of b+tree node/leaf (same structure, bb_level matters) +struct xfs_btree_sblock + bb_magic dd ? + bb_level dw ? ; distinguishes nodeds and leaves + bb_numrecs dw ? + bb_leftsib dd ? + bb_rightsib dd ? +ends + + +; record of b+tree inode +struct xfs_inobt_rec + ir_startino dd ? + ir_freecount dd ? + ir_free dq ? +ends + + +; structure to store create, access and modification time in inode core +struct xfs_timestamp + t_sec dd ? + t_nsec dd ? ; nanoseconds +ends + + +; inode core structure: basic information about file +struct xfs_dinode_core + di_magic dw ? ; inode magic = XFS_DINODE_MAGIC + di_mode dw ? ; mode and type of file + di_version db ? ; inode version + di_format db ? ; format of di_c data + di_onlink dw ? ; old number of links to file + di_uid dd ? ; owner's user id + di_gid dd ? ; owner's group id + di_nlink dd ? ; number of links to file + di_projid dw ? ; owner's project id + di_pad rb 8 ; unused, zeroed space + di_flushiter dw ? ; incremented on flush + di_atime xfs_timestamp ; time last accessed + di_mtime xfs_timestamp ; time last modified + di_ctime xfs_timestamp ; time created/inode modified + di_size dq ? ; number of bytes in file + di_nblocks dq ? ; number of direct & btree blocks used + di_extsize dd ? ; basic/minimum extent size for file + di_nextents dd ? ; number of extents in data fork + di_anextents dw ? ; number of extents in attribute fork + di_forkoff db ? ; attr fork offs, <<3 for 64b align + di_aformat db ? ; format of attr fork's data + di_dmevmask dd ? ; DMIG event mask + di_dmstate dw ? ; DMIG state info + di_flags dw ? ; random flags, XFS_DIFLAG_... + di_gen dd ? ; generation number +ends + + +; shortform dir header +struct xfs_dir2_sf_hdr + count db ? ; the number of directory entries, used only if each inode number fits 4 bytes; zero otherwise + i8count db ? ; the number of directory entries, used only when count is zero + parent dq ? ; parent inode number: xfs_dir2_inou_t (4 or 8 bytes) +ends + + +; shortform dir entry +struct xfs_dir2_sf_entry + namelen db ? ; actual name length (ASCII) + offset rb 2 ; saved offset + name db ? ; name, variable size +; inumber dq ? ; xfs_dir2_inou_t +ends + + +; active entry in a data block +; aligned to 8 bytes +; tag appears as the last 2 bytes +struct xfs_dir2_data_entry + inumber dq ? ; inode number + namelen db ? ; name length + name db ? ; name bytes, no null +; tag dw ? ; starting offset of us +ends + + +; unused entry in a data block +; aligned to 8 bytes +; tag appears as the last 2 bytes +struct xfs_dir2_data_unused + freetag dw ? ; XFS_DIR2_DATA_FREE_TAG + length dw ? ; total free length +; tag dw ? ; starting offset of us +ends + + +; generic data entry +struct xfs_dir2_data_union + union + xentry xfs_dir2_data_entry + unused xfs_dir2_data_unused + ends +ends + + +; describe a free area in the data block +; the freespace will be formatted as a xfs_dir2_data_unused_t +struct xfs_dir2_data_free + offset dw ? ; start of freespace + length dw ? ; length of freespace +ends + + +; header for the data blocks +; always at the beginning of a directory-sized block +; the code knows that XFS_DIR2_DATA_FD_COUNT is 3 +struct xfs_dir2_data_hdr + magic dd ? ; XFS_DIR2_DATA_MAGIC or XFS_DIR2_BLOCK_MAGIC + bestfree xfs_dir2_data_free + bestfree2 xfs_dir2_data_free + bestfree3 xfs_dir2_data_free +ends + + +; leaf block entry +struct xfs_dir2_leaf_entry + hashval dd ? ; hash value of name + address dd ? ; address of data entry +ends + + +; the tail of directory block +struct xfs_dir2_block_tail + count dd ? ; count of leaf entries + stale dd ? ; count of stale leaf entries +ends + + +; generic single-block structure, for xfs_db +struct xfs_dir2_block + hdr xfs_dir2_data_hdr + u xfs_dir2_data_union +; leaf xfs_dir2_leaf_entry +; tail xfs_dir2_block_tail +ends + + +; +struct xfs_dir2_data + hdr xfs_dir2_data_hdr ; magic XFS_DIR2_DATA_MAGIC + u xfs_dir2_data_union +ends + + +; +struct xfs_da_blkinfo + forw dd ? ; previous block in list + back dd ? ; following block in list + magic dw ? ; validity check on block + pad dw ? ; unused +ends + + +; leaf block header +struct xfs_dir2_leaf_hdr + info xfs_da_blkinfo ; header for da routines + count dw ? ; count of entries + stale dw ? ; count of stale entries +ends + + +; leaf block tail +struct xfs_dir2_leaf_tail + bestcount dd ? +ends + + +; leaf block +; bests and tail are at the end of the block for single-leaf only +; (magic = XFS_DIR2_LEAF1_MAGIC not XFS_DIR2_LEAFN_MAGIC) +struct xfs_dir2_leaf + hdr xfs_dir2_leaf_hdr ; leaf header + ents xfs_dir2_leaf_entry ; entries +; bests dw ? ; best free counts +; tail xfs_dir2_leaf_tail ; leaf tail +ends + + +; header of 'free' block part +struct xfs_dir2_free_hdr + magic dd ? ; XFS_DIR2_FREE_MAGIC + firstdb dd ? ; db of first entry + nvalid dd ? ; count of valid entries + nused dd ? ; count of used entries +ends + + +; 'free' part of directiry block +struct xfs_dir2_free + hdr xfs_dir2_free_hdr ; block header + bests dw ? ; best free counts + ; unused entries are -1 (XFS_NULL) +ends + + +; b+tree node header +struct xfs_da_node_hdr + info xfs_da_blkinfo + count dw ? + level dw ? +ends + + +; b+tree node +struct xfs_da_node_entry + hashval dd ? ; hash value for this descendant + before dd ? ; Btree block before this key +ends + + +; +struct xfs_da_intnode + hdr xfs_da_node_hdr + btree xfs_da_node_entry +ends + + +; packet extent +struct xfs_bmbt_rec + l0 dq ? + l1 dq ? +ends + + +; unpacked extent +struct xfs_bmbt_irec + br_startoff dq ? ; starting file offset + br_startblock dq ? ; starting block number + br_blockcount dd ? ; number of blocks + br_state dd ? ; extent state +ends + + +; bmap root header, on-disk form only +struct xfs_bmdr_block + bb_level dw ? ; 0 is a leaf + bb_numrecs dw ? ; current number of data records +ends + + +; key structure for non-leaf levels of the tree +struct xfs_bmbt_key + br_startoff dq ? ; starting file offset +ends + + +sizeof.xfs_bmbt_ptr = 8 ; workaround +sizeof.xfs_bmdr_ptr = 8 ; workaround + + +; long form header: bmap btrees +; xfs_btree_lblock is xfs_bmbt_block (xfs_btree.h) +struct xfs_bmbt_block + bb_magic dd ? ; magic number for block type + bb_level dw ? ; 0 is a leaf + bb_numrecs dw ? ; current number of data records + bb_leftsib dq ? ; left sibling block or NULLDFSBNO + bb_rightsib dq ? ; right sibling block or NULLDFSBNO +ends + + +; high level inode structure +struct xfs_inode + di_core xfs_dinode_core ; main info, aka core + di_next_unlinked dd ? ; unlinked but still used inode (if any, XFS_NULL otherwise) + di_u db ? ; data fork inode part +; di_a db ? ; data attribute +ends + + +; internal data for every XFS partition +; this _is_ XFS partition structure +; most fields are unpacked or bswap'ed values from the superblock, so see xfs_sb structure above +struct XFS PARTITION + Lock MUTEX ? ; access mutex + blocksize dd ? + sectsize dd ? + dirblocksize dd ? + rootino dq ? + cur_block dd ? + cur_inode dd ? + cur_sect dd ? + cur_dirblock dd ? + tmp_inode dd ? + versionnum dd ? + features2 dd ? + inodesize dd ? + inopblock dd ? + blocklog dd ? + sectlog dd ? + inodelog dd ? + inopblog dd ? + agblklog dd ? + blockmsectlog dd ? + inodetoblocklog dd ? + dirblklog dd ? + sectpblock dd ? + agblocks dd ? + ; helpers, temporary vars, etc + agblockmask dq ? + extent xfs_bmbt_irec + left_extents dd ? + left_leaves dd ? + bytes_to_read dd ? + bytes_read dd ? + entries_read dd ? + file_offset dq ? + max_dirblockaddr dd ? + next_block_num dq ? + dir2_leaf_offset_blocks dd ? + dir2_free_offset_blocks dd ? + cur_inode_save dd ? + bytes_left_in_file dq ? + ro_nextents dd ? + bb_ptrs dd ? + maxnumrecs dd ? + buffer_pos dd ? + eof dd ? +ends + diff --git a/xfskos.asm b/xfskos.asm new file mode 100644 index 0000000..035e259 --- /dev/null +++ b/xfskos.asm @@ -0,0 +1,416 @@ +; lib +; +; Copyright (C) 2012-2013,2016 Ivan Baravy (dunkaist) +; +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 3 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program. If not, see . + +format ELF + +__DEBUG__ = 1 +__DEBUG_LEVEL__ = 2 + +include 'proc32.inc' +include 'struct.inc' +include 'macros.inc' +include 'const.inc' +include 'system.inc' +;include 'fdo.inc' +include 'debug-fdo.inc' +include 'disk.inc' +;include 'fs_lfn.inc' +include 'fs_common.inc' + +ERROR_SUCCESS = 0 +ERROR_DISK_BASE = 1 +ERROR_UNSUPPORTED_FS = 2 +ERROR_UNKNOWN_FS = 3 +ERROR_PARTITION = 4 +ERROR_FILE_NOT_FOUND = 5 +ERROR_END_OF_FILE = 6 +ERROR_MEMORY_POINTER = 7 +ERROR_DISK_FULL = 8 +ERROR_FS_FAIL = 9 +ERROR_ACCESS_DENIED = 10 +ERROR_DEVICE = 11 +ERROR_OUT_OF_MEMORY = 12 + + + +purge section,mov,add,sub +section '.text' executable align 16 + + +;public _start +_start: + +; pushfd +; pop eax +; or eax, 1 SHL 18 ; Alignment Check flag +; push eax +; popfd + + pop eax + cmp eax, 2 + jz .params_ok + .few_arguments: + mov eax, SYS_WRITE + mov ebx, STDOUT + mov ecx, msg_few_args + mov edx, msg_few_args.size + int 0x80 + jmp .error_quit + .params_ok: + pop eax + pop ebx + mov [filename], ebx + mov eax, SYS_OPEN + mov ecx, O_RDONLY OR O_LARGEFILE + int 0x80 + cmp eax, -2 ; FIXME RETURN VALUE + je .file_not_found + mov [fd], eax + + mov eax, 0 + mov ebx, mbr_buffer + mov ebp, partition + call fs_read32_sys + + mov esi, disk + mov [esi + DISK.MediaInfo.SectorSize], 512 + mov ebp, partition + mov [ebp + PARTITION.Disk], esi + mov ebx, mbr_buffer + call xfs_create_partition + test eax, eax + jz .not_xfs_partition + mov [fs_struct], eax + + .next_cmd: + call prompt + call read_cmd + mov eax, dword[cmd_buf] + cmp eax, dword 'exit' + jnz @f + jmp .quit + @@: + cmp ax, word 'ls' + jnz @f + call cmd_ls + jmp .next_cmd + @@: + .unknown: + call unknown_command + jmp .next_cmd + + .quit: + mov eax, SYS_EXIT + xor ebx, ebx + int 0x80 + .not_xfs_partition: + mov eax, SYS_WRITE + mov ebx, STDOUT + mov ecx, msg_not_xfs_partition + mov edx, msg_not_xfs_partition.size + int 0x80 + jmp .error_quit + .file_not_found: + mov eax, SYS_WRITE + mov ebx, STDOUT + mov ecx, msg_file_not_found + mov edx, msg_file_not_found.size + int 0x80 + stdcall print_filename, [filename] + jmp .error_quit + .error_quit: + mov eax, SYS_EXIT + mov ebx, 1 + int 0x80 + + +cmd_ls: + mov ebp, [fs_struct] + mov ebx, sf70_params + mov esi, cmd_buf + mov edi, esi + mov al, ' ' + mov ecx, 100 + repnz scasb + mov [ebx + 0x14], edi + mov eax, edi + sub eax, esi + push eax + mov al, 0x0a + repnz scasb + mov byte[edi-1], 0 + call xfs_ReadFolder + pop eax + + mov eax, sf70_buffer + mov ecx, [eax + 4] ; read bdfes + add eax, 0x20 ; skip header + .next_bdfe: + lea edx, [eax + 0x28] + push eax ecx + stdcall print_filename, edx + pop ecx eax + add eax, 304 + dec ecx + jnz .next_bdfe + + ret + + +public kos_fuse_init +kos_fuse_init: + push ebx esi edi ebp + + mov eax, [esp + 0x14] + mov [fd], eax + + mov eax, 0 + mov ebx, mbr_buffer + mov ebp, partition + call fs_read32_sys + + mov esi, disk + mov [esi + DISK.MediaInfo.SectorSize], 512 + mov ebp, partition + mov [ebp + PARTITION.Disk], esi + mov ebx, mbr_buffer + call xfs_create_partition + test eax, eax + jnz @f + mov eax, SYS_WRITE + mov ebx, STDOUT + mov ecx, msg_not_xfs_partition + mov edx, msg_not_xfs_partition.size + int 0x80 + @@: + mov [fs_struct], eax + + pop ebp edi esi ebx + ret + +;char *hello_readdir(const char *path, off_t offset) +public kos_fuse_readdir +kos_fuse_readdir: + push ebx esi edi ebp + + mov edx, sf70_params + mov dword[edx + 0x00], 1 + mov eax, [esp + 0x18] ; offset + mov [edx + 0x04], eax + mov dword[edx + 0x08], 1 + mov dword[edx + 0x0c], 100 + mov dword[edx + 0x10], sf70_buffer + mov eax, [esp + 0x14] ; path + inc eax ; skip '/' + mov [edx + 0x14], eax + + mov ebp, [fs_struct] + mov ebx, sf70_params + mov esi, eax + push 0 + call xfs_ReadFolder + pop eax + + pop ebp edi esi ebx + mov eax, sf70_buffer + ret + + +unknown_command: + pushad + mov eax, SYS_WRITE + mov ebx, STDOUT + mov ecx, msg_unknown_command + mov edx, msg_unknown_command.size + int 0x80 + popad + ret + + +prompt: + pushad + mov eax, SYS_WRITE + mov ebx, STDOUT + mov ecx, endl_prompt + mov edx, 2 + int 0x80 + popad + ret + +read_cmd: + pushad + mov eax, SYS_READ + mov ebx, STDIN + mov ecx, cmd_buf + mov edx, 4096 + int 0x80 + popad + ret + + +; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure +fs_read32_sys: + pushad + imul ecx, eax, 512 + add ecx, 2048*512 + mov eax, SYS_LSEEK + mov ebx, [fd] + mov edx, SEEK_SET + int 0x80 +;DEBUGF 1, "lseek: %x\n", eax + popad + + pushad + mov eax, SYS_READ + mov ecx, ebx + mov ebx, [fd] + mov edx, 512 + int 0x80 +;DEBUGF 1, "read: %d\n", eax + popad + + xor eax, eax + + ret + + +fs_read32_app: + ret + + +fs_read64_sys: + pushad + imul ecx, eax, 512 + add ecx, 2048*512 + mov eax, SYS_LSEEK + mov ebx, [fd] + mov edx, SEEK_SET + int 0x80 +;DEBUGF 1, "lseek: %x\n", eax + popad + + pushad + mov eax, SYS_READ + imul edx, ecx, 512 + mov ecx, ebx + mov ebx, [fd] + int 0x80 +;DEBUGF 1, "read: %d\n", eax + popad + + xor eax, eax + ret + + +fs_read64_app: + ret + + +malloc: + push [alloc_pos] + add [alloc_pos], eax + pop eax + ret + +free: + ret + + +kernel_free: + ret + + +mutex_init: + ret + + +mutex_lock: + ret + + +mutex_unlock: + ret + + +put_board: + pushad + mov eax, SYS_WRITE + mov ebx, STDOUT + push ecx + mov ecx, esp + mov edx, 1 + int 0x80 + pop ecx + popad +ret + + +proc print_filename _filename + stdcall strlen, [_filename] + mov byte[edi - 1], 0x0a + inc edx + mov ecx, [_filename] + mov eax, SYS_WRITE + mov ebx, STDOUT + int 0x80 + ret +endp + + +proc strlen _str + mov edi, [_str] + mov ecx, -1 + xor eax, eax + repnz scasb + not ecx + dec ecx + mov edx, ecx + ret +endp + + +include 'xfs.asm' + + +section '.data' writeable align 16 +msg_few_args db 'usage: xfskos image [offset]',0x0a +msg_few_args.size = $ - msg_few_args +msg_file_not_found db 'file not found: ' +msg_file_not_found.size = $ - msg_file_not_found +msg_unknown_command db 'unknown command',0x0a +msg_unknown_command.size = $ - msg_unknown_command +msg_not_xfs_partition db 'not xfs partition',0x0a +msg_not_xfs_partition.size = $ - msg_not_xfs_partition +endl_prompt db '> ' + +include_debug_strings + +partition_offset dd 2048*512 +alloc_pos dd alloc_base +sf70_params dd 1, 0, 1, 100, sf70_buffer, -1 + + +section '.bss' writeable align 16 +mbr_buffer rb 4096*3 +filename rd 1 +fd rd 1 +cmd_buf rb 4096 +partition PARTITION +disk DISK +alloc_base rb 1024*1024 +fs_struct rd 1 +sf70_buffer rb 1024*1024 diff --git a/xfskosfuse.c b/xfskosfuse.c new file mode 100644 index 0000000..69c04e0 --- /dev/null +++ b/xfskosfuse.c @@ -0,0 +1,115 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. + + gcc -Wall hello.c `pkg-config fuse --cflags --libs` -o hello +*/ + +#define FUSE_USE_VERSION 26 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *kos_fuse_readdir(const char *path, off_t offset); +void kos_fuse_init(int fd); + +static const char *hello_str = "Hello World!\n"; +static const char *hello_path = "/hello"; + +static int hello_getattr(const char *path, struct stat *stbuf) +{ + int res = 0; + + memset(stbuf, 0, sizeof(struct stat)); + if (strcmp(path, "/") == 0) { + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + } else if (strcmp(path, hello_path) == 0) { + stbuf->st_mode = S_IFREG | 0444; + stbuf->st_nlink = 1; + stbuf->st_size = strlen(hello_str); + } else + res = -ENOENT; + + return res; +} + +static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) +{ + (void) offset; + (void) fi; + + char *bdfe = kos_fuse_readdir(path, offset); + +// if (strcmp(path, "/") != 0) +// return -ENOENT; + uint32_t i = *(uint32_t*)(bdfe + 4); +// int f = open("/tmp/t", O_RDWR | O_CREAT); +// write(f, bdfe, 1000); +// write(f, &i, 4); +// close(f); + bdfe += 0x20; + for(; i>0; i--) { + filler(buf, bdfe + 0x28, NULL, 0); + bdfe += 304; + } + + return 0; +} + +static int hello_open(const char *path, struct fuse_file_info *fi) +{ + if (strcmp(path, hello_path) != 0) + return -ENOENT; + + if ((fi->flags & 3) != O_RDONLY) + return -EACCES; + + return 0; +} + +static int hello_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) +{ + size_t len; + (void) fi; + if(strcmp(path, hello_path) != 0) + return -ENOENT; + + len = strlen(hello_str); + if (offset < len) { + if (offset + size > len) + size = len - offset; + memcpy(buf, hello_str + offset, size); + } else + size = 0; + + return size; +} + +static struct fuse_operations hello_oper = { + .getattr = hello_getattr, + .readdir = hello_readdir, + .open = hello_open, + .read = hello_read, +}; + +int main(int argc, char *argv[]) +{ + int fd = open(argv[2], O_RDONLY); + kos_fuse_init(fd); + return fuse_main(argc-1, argv, &hello_oper, NULL); +}