From 080b8dcdc4407473e3fec59075c3a6e7636ba59c Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Thu, 21 Nov 2013 02:42:12 +0000 Subject: [PATCH] kolibri-acpi:update git-svn-id: svn://kolibrios.org@4265 a494cfbc-eb01-0410-851d-a64ba20cac60 --- kernel/branches/Kolibri-acpi/blkdev/disk.inc | 3 + .../Kolibri-acpi/blkdev/disk_cache.inc | 4 +- .../branches/Kolibri-acpi/blkdev/flp_drv.inc | 10 +- .../branches/Kolibri-acpi/boot/bootcode.inc | 78 +- kernel/branches/Kolibri-acpi/boot/booten.inc | 25 +- kernel/branches/Kolibri-acpi/boot/bootet.inc | 111 +- kernel/branches/Kolibri-acpi/boot/bootge.inc | 26 +- kernel/branches/Kolibri-acpi/boot/bootru.inc | 109 +- kernel/branches/Kolibri-acpi/boot/bootsp.inc | 111 +- .../branches/Kolibri-acpi/boot/bootvesa.inc | 1 + kernel/branches/Kolibri-acpi/boot/et.inc | 2 +- kernel/branches/Kolibri-acpi/bus/usb/hub.inc | 25 +- .../Kolibri-acpi/bus/usb/protocol.inc | 6 +- .../branches/Kolibri-acpi/core/clipboard.inc | 148 + .../Kolibri-acpi/core/conf_lib-sp.inc | 16 +- kernel/branches/Kolibri-acpi/core/dll.inc | 40 +- kernel/branches/Kolibri-acpi/core/exports.inc | 2 + .../branches/Kolibri-acpi/core/sys32-sp.inc | 4 +- kernel/branches/Kolibri-acpi/core/sys32.inc | 77 + kernel/branches/Kolibri-acpi/core/syscall.inc | 2 +- kernel/branches/Kolibri-acpi/core/taskman.inc | 31 +- kernel/branches/Kolibri-acpi/data32.inc | 80 +- kernel/branches/Kolibri-acpi/data32et.inc | 37 + .../branches/Kolibri-acpi/detect/vortex86.inc | 92 + .../Kolibri-acpi/docs/events_subsystem.txt | 232 ++ .../branches/Kolibri-acpi/docs/sysfuncr.txt | 107 +- .../branches/Kolibri-acpi/docs/sysfuncs.txt | 117 +- .../branches/Kolibri-acpi/docs/usbapi_ru.txt | 249 ++ .../branches/Kolibri-acpi/drivers/imports.inc | 1 + .../branches/Kolibri-acpi/drivers/usbstor.asm | 7 +- kernel/branches/Kolibri-acpi/encoding.inc | 18 + kernel/branches/Kolibri-acpi/fs/ext2.inc | 1343 -------- .../branches/Kolibri-acpi/fs/ext2/blocks.inc | 409 +++ kernel/branches/Kolibri-acpi/fs/ext2/ext2.asm | 1718 ++++++++++ kernel/branches/Kolibri-acpi/fs/ext2/ext2.inc | 670 ++++ .../branches/Kolibri-acpi/fs/ext2/inode.inc | 1850 +++++++++++ .../Kolibri-acpi/fs/ext2/resource.inc | 223 ++ kernel/branches/Kolibri-acpi/fs/fs-et.inc | 12 + kernel/branches/Kolibri-acpi/fs/fs.inc | 2 + kernel/branches/Kolibri-acpi/fs/xfs.asm | 2769 +++++++++++++++++ kernel/branches/Kolibri-acpi/fs/xfs.inc | 518 +++ kernel/branches/Kolibri-acpi/gui/font.inc | 4 + kernel/branches/Kolibri-acpi/kernel.asm | 90 +- kernel/branches/Kolibri-acpi/kernel32.inc | 4 +- kernel/branches/Kolibri-acpi/kernelsp.inc | 2 +- kernel/branches/Kolibri-acpi/network/IPv4.inc | 255 +- .../Kolibri-acpi/network/ethernet.inc | 91 +- kernel/branches/Kolibri-acpi/network/icmp.inc | 15 +- .../branches/Kolibri-acpi/network/socket.inc | 229 +- .../branches/Kolibri-acpi/network/stack.inc | 4 + kernel/branches/Kolibri-acpi/network/tcp.inc | 2 + .../Kolibri-acpi/network/tcp_output.inc | 2 - .../Kolibri-acpi/network/tcp_usreq.inc | 131 + kernel/branches/Kolibri-acpi/network/udp.inc | 83 +- 54 files changed, 10208 insertions(+), 1989 deletions(-) create mode 100644 kernel/branches/Kolibri-acpi/core/clipboard.inc create mode 100644 kernel/branches/Kolibri-acpi/data32et.inc create mode 100644 kernel/branches/Kolibri-acpi/detect/vortex86.inc create mode 100644 kernel/branches/Kolibri-acpi/docs/events_subsystem.txt create mode 100644 kernel/branches/Kolibri-acpi/docs/usbapi_ru.txt delete mode 100644 kernel/branches/Kolibri-acpi/fs/ext2.inc create mode 100644 kernel/branches/Kolibri-acpi/fs/ext2/blocks.inc create mode 100644 kernel/branches/Kolibri-acpi/fs/ext2/ext2.asm create mode 100644 kernel/branches/Kolibri-acpi/fs/ext2/ext2.inc create mode 100644 kernel/branches/Kolibri-acpi/fs/ext2/inode.inc create mode 100644 kernel/branches/Kolibri-acpi/fs/ext2/resource.inc create mode 100644 kernel/branches/Kolibri-acpi/fs/fs-et.inc create mode 100644 kernel/branches/Kolibri-acpi/fs/xfs.asm create mode 100644 kernel/branches/Kolibri-acpi/fs/xfs.inc diff --git a/kernel/branches/Kolibri-acpi/blkdev/disk.inc b/kernel/branches/Kolibri-acpi/blkdev/disk.inc index 47fa8063eb..8e5832c2ed 100644 --- a/kernel/branches/Kolibri-acpi/blkdev/disk.inc +++ b/kernel/branches/Kolibri-acpi/blkdev/disk.inc @@ -1006,6 +1006,9 @@ end virtual call ext2_create_partition test eax, eax jnz .success + call xfs_create_partition + test eax, eax + jnz .success ; 3. No file system has recognized the volume, so just allocate the PARTITION ; structure without extra fields. movi eax, sizeof.PARTITION diff --git a/kernel/branches/Kolibri-acpi/blkdev/disk_cache.inc b/kernel/branches/Kolibri-acpi/blkdev/disk_cache.inc index 2fa011e815..c2f179e6f8 100644 --- a/kernel/branches/Kolibri-acpi/blkdev/disk_cache.inc +++ b/kernel/branches/Kolibri-acpi/blkdev/disk_cache.inc @@ -512,7 +512,7 @@ disk_init_cache: push edi mov edi, [esi+DISK.SysCache.pointer] - lea ecx, [ecx*3] + lea ecx, [(ecx+1)*3] xor eax, eax rep stosd pop edi @@ -527,7 +527,7 @@ disk_init_cache: push edi mov edi, [esi+DISK.AppCache.pointer] - lea ecx, [ecx*3] + lea ecx, [(ecx+1)*3] xor eax, eax rep stosd pop edi diff --git a/kernel/branches/Kolibri-acpi/blkdev/flp_drv.inc b/kernel/branches/Kolibri-acpi/blkdev/flp_drv.inc index a0e15c87fa..14ed160b89 100644 --- a/kernel/branches/Kolibri-acpi/blkdev/flp_drv.inc +++ b/kernel/branches/Kolibri-acpi/blkdev/flp_drv.inc @@ -162,7 +162,7 @@ FDCDataInput: mov [FDC_Status], FDC_Normal ; Проверить готовность контроллера к передаче данных mov DX, 3F4h ;(порт состояния FDC) - xor CX, CX ;установить счетчик тайм-аута + mov ecx, 0x10000 ;установить счетчик тайм-аута @@TestRS_1: in AL, DX ;прочитать регистр RS and AL, 0C0h ;выдлить разряды 6 и 7 @@ -197,8 +197,6 @@ WaitFDCInterrupt: pusha ; Сбросить байт состояния операции mov [FDC_Status], FDC_Normal -; Сбросить флаг прерывани - mov [FDD_IntFlag], 0 ; Обнулить счетчик тиков mov eax, [timer_ticks] mov [TickCounter], eax @@ -372,6 +370,8 @@ RecalibrateFDD: SeekTrack: pusha call save_timer_fdd_motor +; Сбросить флаг прерывания + mov [FDD_IntFlag], 0 ; Подать команду "Поиск" mov AL, 0Fh call FDCDataOutput @@ -431,6 +431,8 @@ SeekTrack: ReadSector: pushad call save_timer_fdd_motor +; Сбросить флаг прерывания + mov [FDD_IntFlag], 0 ; Установить скорость передачи 500 Кбайт/с mov AX, 0 mov DX, 03F7h @@ -531,6 +533,8 @@ ReadSectWithRetr: WriteSector: pushad call save_timer_fdd_motor +; Сбросить флаг прерывания + mov [FDD_IntFlag], 0 ; Установить скорость передачи 500 Кбайт/с mov AX, 0 mov DX, 03F7h diff --git a/kernel/branches/Kolibri-acpi/boot/bootcode.inc b/kernel/branches/Kolibri-acpi/boot/bootcode.inc index bc8e1742f1..9f7d47079c 100644 --- a/kernel/branches/Kolibri-acpi/boot/bootcode.inc +++ b/kernel/branches/Kolibri-acpi/boot/bootcode.inc @@ -51,18 +51,20 @@ getkey: ; Use BIOS INT 16h to read a key from the keyboa ; get number in range [bl,bh] (bl,bh in ['0'..'9']) ; in: bx=range ; out: ax=digit (1..9, 10 for 0) - mov ah, 0 ; If 'int 16h' is called with 'ah' equal to zero, the BIOS will not return control - int 16h ; to the caller until a key is available in the system type ahead buffer. On return, - cmp al, bl ; 'al' contains the ASCII code for the key read from the buffer and 'ah' contains - jb getkey ; the keyboard scan code. Here we compare 'al' with the range of accepted characters. - cmp al, bh ; If the key pressed is not in the range, continue waiting for another key. - ja getkey + mov ah, 0 ; If 'int 16h' is called with 'ah' equal to zero, the BIOS will not return control to the caller + int 16h ; until a key is available in the system type ahead buffer. On return, 'al' contains the ASCII + cmp al, 27 ; code for the key read from the buffer and 'ah' contains the keyboard scan code. (27=>ESC) + jz @f ; If ESC is pressed, return (user doesn't want to change any value). + cmp al, bl ; Compare 'al' (ASCII code of key pressed) with 'bl' (lowest accepted char from the range). + jb getkey ; ASCII code is below lowest accepted value => continue waiting for another key. + cmp al, bh ; Compare 'al' (ASCII code of key pressed) with 'bh' (highest accepted char from the range). + ja getkey ; ASCII code is above highest accepted value => continue waiting for another key. push ax ; If the pressed key is in the accepted range, save it on the stack and echo to screen. call putchar pop ax - and ax, 0Fh ; ASCII code for '0' is 48 (110000b). 0F4=1111b. (110000b AND 1111b) = 0 - jnz @f ; So if key '0' was entered, return 10 in 'ax' - mov al, 10 + and ax, 0Fh ; Convert ASCII code to number: '1'->1, '2'->2, etc. 0Fh=1111b. + jnz @f ; ASCII code for '0' is 48 (110000b). (110000b AND 1111b) = 0 + mov al, 10 ; So if key '0' was entered, return 10 in 'ax' @@: ret @@ -79,6 +81,18 @@ macro _setcursor row,column call setcursor } +macro _ask_question question,range,variable_to_set +{ + _setcursor 16,0 + mov si, question ; Print the question + call print + mov bx, range ; range accepted for answer + call getkey + cmp al, 27 ; If ESC was pressed, do not change the value + jz .esc_pressed + mov [variable_to_set], al +} + boot_read_floppy: push si xor si, si @@ -433,7 +447,7 @@ sayerr: mov [es:BOOT_IDE_PI_16], cx xor si, si ; device index = 0 int 0x1A - jnc .found_1 ; Parallel IDE Controller + jnc .found ; Parallel IDE Controller ; Controller not found! xor ax, ax mov [es:BOOT_IDE_PI_16], ax @@ -775,25 +789,26 @@ end if cmp al, 'e' ; select boot origin jnz .show_remarks ; e) preboot_device = from where to boot? - _setcursor 16,0 - mov si, bdev - call print if defined extended_primary_loader - mov bx, '12' ; range accepted for answer: 1-2 + _ask_question bdev,'12',preboot_device ; range accepted for answer: 1-2 else - mov bx, '14' ; range accepted for answer: 1-4 + _ask_question bdev,'14',preboot_device ; range accepted for answer: 1-4 end if - call getkey - mov [preboot_device], al _setcursor 14,0 + .d: if ~ defined extended_primary_loader mov [.bSettingsChanged], 1 end if +.esc_pressed: call clear_vmodes_table ;clear vmodes_table jmp .printcfg + .change_a: call clear_vmodes_table ;clear vmodes_table + + mov si, word [cursor_pos] + mov word [cursor_pos_old], si .loops: call draw_vmodes_table _setcursor 25,0 ; out of screen @@ -803,6 +818,13 @@ end if mov si, word [cursor_pos] + cmp al, 27 ; If ESC was pressed, do not change the value + jnz @f ; Just exit the resolution selection box + + mov si, word [cursor_pos_old] + mov word [cursor_pos], si + jmp .esc_pressed +@@: cmp ah, 0x48;x,0x48E0 ; up jne .down cmp si, modes_table @@ -873,17 +895,13 @@ end if jmp .d .change_b: ; b) preboot_biosdisk = use BIOS disks through V86 emulation? - _setcursor 16,0 +; _setcursor 16,0 ; mov si, ask_dma // (earlier was: preboot_dma = use DMA access?) ; call print ; mov bx, '13' ; range accepted for answer: 1-3 ; call getkey ; mov [preboot_dma], al - mov si, ask_bd - call print - mov bx, '12' ; range accepted for answer: 1-2 - call getkey - mov [preboot_biosdisk], al + _ask_question ask_bd,'12',preboot_biosdisk ; range accepted for answer: 1-2 _setcursor 11,0 jmp .d ;.change_c: ; // VRR is an obsolete functionality, used only with CRT monitors @@ -896,21 +914,11 @@ end if ; _setcursor 12,0 ; jmp .d .change_c: ; c) preboot_debug = duplicates kernel debug output to the screen - _setcursor 16,0 - mov si, ask_debug - call print - mov bx, '12' ; range accepted for answer: 1-2 - call getkey - mov [preboot_debug], al + _ask_question ask_debug,'12',preboot_debug ; range accepted for answer: 1-2 _setcursor 12,0 jmp .d .change_d: ; d) preboot_launcher = start the first app (right now it's LAUNCHER) after kernel is loaded? - _setcursor 16,0 - mov si, ask_launcher - call print - mov bx, '12' ; range accepted for answer: 1-2 - call getkey - mov [preboot_launcher], al + _ask_question ask_launcher,'12',preboot_launcher ; range accepted for answer: 1-2 _setcursor 13,0 jmp .d ;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/kernel/branches/Kolibri-acpi/boot/booten.inc b/kernel/branches/Kolibri-acpi/boot/booten.inc index 039cf105a6..fdc56e6ff1 100644 --- a/kernel/branches/Kolibri-acpi/boot/booten.inc +++ b/kernel/branches/Kolibri-acpi/boot/booten.inc @@ -15,10 +15,10 @@ $Revision: 2455 $ d80x25_bottom: - db 186,' KolibriOS comes with ABSOLUTELY NO WARRANTY. See file COP' - db 'YING for details ',186 + db 186,' KolibriOS comes with ABSOLUTELY NO WARRANTY. See file COPYING for details ',186 + db 186,' If you find any bugs, please report them at: http://board.kolibrios.org ',186 line_full_bottom -d80x25_bottom_num = 2 +d80x25_bottom_num = 3 msg_apm db " APM x.x ", 0 novesa db "Display: EGA/CGA",13,10,0 @@ -79,7 +79,7 @@ preboot_device_msgs dw 0,pdm1,pdm2,0 pdm1 db "real floppy",13,10,0 pdm2 db "C:\kolibri.img (FAT32)",13,10,0 else -preboot_device_msgs dw 0,pdm1,pdm2,pdm3 +preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4,0 pdm1 db "real floppy",13,10,0 pdm2 db "C:\kolibri.img (FAT32)",13,10,0 pdm3 db "use already loaded image",13,10,0 @@ -93,13 +93,14 @@ save_quest db "Remember current settings? [y/n]: ",0 loader_block_error db "Bootloader data invalid, I cannot continue. Stopped.",0 end if -_st:latin1 '║ ┌───────────────────────────────┬─┐',13,10,0 -_r1:latin1 '║ │ 320x200 EGA/CGA 256 colors │ │',13,10,0 -_r2:latin1 '║ │ 640x480 VGA 16 colors │ │',13,10,0 -_rs:latin1 '║ │ ????x????@?? SVGA VESA │ │',13,10,0 -_bt:latin1 '║ └───────────────────────────────┴─┘',13,10,0 +_st latin1 '║ ┌───────────────────────────────┬─┐',13,10,0 +_r1 latin1 '║ │ 320x200 EGA/CGA 256 colors │ │',13,10,0 +_r2 latin1 '║ │ 640x480 VGA 16 colors │ │',13,10,0 +_rs latin1 '║ │ ????x????@?? SVGA VESA │ │',13,10,0 +_bt latin1 '║ └───────────────────────────────┴─┘',13,10,0 remark1 db "Default values were selected to match most of configurations, but not all.",0 -remark2 db "If the system does not boot, try to disable the item [b].",0 -remarks dw remark1, remark2 -num_remarks = 2 +remark2 db "If the system does not boot, try to disable option [b]. If the system gets",0 +remark3 db "stuck after booting, enable option [c], disable option [d] and make photo.",0 +remarks dw remark1, remark2, remark3 +num_remarks = 3 \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/boot/bootet.inc b/kernel/branches/Kolibri-acpi/boot/bootet.inc index d156a4a9e2..0b7d5ff483 100644 --- a/kernel/branches/Kolibri-acpi/boot/bootet.inc +++ b/kernel/branches/Kolibri-acpi/boot/bootet.inc @@ -15,91 +15,92 @@ $Revision$ d80x25_bottom: - latin1 '║ KolibriOS kaasas IGASUGUSE GARANTIITA. Naha faili COPY' - latin1 'ING detailid ║' + latin1 '║ KolibriOS on IGASUGUSE GARANTIITA. Vaata faili COPYING info saamiseks. Kui ║' + latin1 '║ leiate vigu, anna neist palun teada aadressil: http://board.kolibrios.org ║' line_full_bottom -d80x25_bottom_num = 2 +d80x25_bottom_num = 3 -msg_apm: latin1 " APM x.x ", 0 -novesa: latin1 "Ekraan: EGA/CGA",13,10,0 -s_vesa: latin1 "Vesa versioon: " +msg_apm latin1 " APM x.x ", 0 +novesa latin1 "Ekraan: EGA/CGA",13,10,0 +s_vesa latin1 "Vesa versioon: " .ver db "?.?",13,10,0 -gr_mode: latin1 "Vali videomode: ",13,10,0 +gr_mode latin1 "Vali video resolutsioon: ",13,10,0 -ask_bd: latin1 "Lisa kettad nahtavaks BIOS reziim V86? [1-jah, 2-no]: ",0 +ask_bd latin1 "Lisa V86 reziimis BIOSle nähtavad kettad? [1-jah, 2-ei]: ",0 if defined extended_primary_loader -bdev: latin1 "Paigalda mäluketas [1-diskett; 2-kolibri.img]: ",0 +bdev latin1 "Paigalda mäluketas [1-diskett; 2-kolibri.img]: ",0 else -bdev: latin1 "Paigalda mäluketas [1-diskett; 2-C:\kolibri.img (FAT32);" +bdev latin1 "Paigalda mäluketas [1-diskett; 2-C:\kolibri.img (FAT32);" latin1 13,10,"║ " latin1 "3-kasuta eellaaditud mäluketast kerneli restardist;" latin1 13,10,"║ " latin1 "4-loo tühi pilt]: ",0 end if -prnotfnd: latin1 "Fataalne - Videoreziimi ei leitud.",0 +prnotfnd latin1 "Fataalne - Video resolutsiooni ei leitud.",0 -not386: latin1 "Fataalne - CPU 386+ on vajalik.",0 -fatalsel: latin1 "Fataalne - Graafilist reziimi riistvara ei toeta.",0 -pres_key: latin1 "Vajutage suvalist klahvi, et valida uus videomode.",0 -badsect: latin1 13,10,"║ Fataalne - Vigane sektor. Asenda diskett.",0 -memmovefailed:latin1 13,10,"║ Fataalne - Int 0x15 liigutamine ebaõnnestus.",0 -okt: latin1 " ... OK" -linef: latin1 13,10,0 -diskload: latin1 "Loen disketti: 00 %",8,8,8,8,0 -pros: latin1 "00" -backspace2:latin1 8,8,0 +not386 latin1 "Fataalne - CPU 386+ on vajalik.",0 +fatalsel latin1 "Fataalne - Riistvara ei toeta graafilist resolutsiooni.",0 +pres_key latin1 "Vajutage suvalist klahvi, et valida uus videomode.",0 +badsect latin1 13,10,"║ Fataalne - Vigane sektor. Asenda diskett.",0 +memmovefailed latin1 13,10,"║ Fataalne - Int 0x15 liigutamine ebaõnnestus.",0 +okt latin1 " ... OK" +linef latin1 13,10,0 +diskload latin1 "Loen disketti: 00 %",8,8,8,8,0 +pros latin1 "00" +backspace2 latin1 8,8,0 boot_dev db 0 ; 0=floppy, 1=hd -start_msg:latin1 "Vajuta [abcde] seadete muutmiseks, vajuta [Enter] laadimise jätkamiseks",13,10,0 -time_msg: latin1 " või oota " -time_str: latin1 " 5 sekundit" +start_msg latin1 "Vajuta [abcde] seadete muutmiseks, vajuta [Enter] laadimise jätkamiseks",13,10,0 +time_msg latin1 " või oota " +time_str latin1 " 5 sekundit" latin1 " automaatseks jätkamiseks",13,10,0 -current_cfg_msg:latin1 "Praegused seaded:",13,10,0 -curvideo_msg:latin1 " [a] Videoreziim: ",0 +current_cfg_msg latin1 "Praegused seaded:",13,10,0 +curvideo_msg latin1 " [a] Video resolutsioon: ",0 -mode0: latin1 "320x200, EGA/CGA 256 värvi",0 -mode9: latin1 "640x480, VGA 16 värvi",0 +mode0 latin1 "320x200, EGA/CGA 256 värvi",0 +mode9 latin1 "640x480, VGA 16 värvi",0 -usebd_msg:latin1 " [b] Lisa kettad nahtavaks BIOS:",0 -on_msg: latin1 " sees",13,10,0 -off_msg: latin1 " väljas",13,10,0 +usebd_msg latin1 " [b] Lisa BIOSle nähtavad kettad:",0 +on_msg latin1 " sees",13,10,0 +off_msg latin1 " väljas",13,10,0 -debug_mode_msg: latin1 " [c] Duplicate siluda väljund ekraani:",0 -ask_debug: latin1 "Duplicate siluda väljund ekraani? [1-jah, 2-no]: ",0 +debug_mode_msg latin1 " [c] Dubleeri silumisinfo ekraanile:",0 +ask_debug latin1 "Dubleeri silumisinfo ekraanile? [1-jah, 2-ei]: ",0 -launcher_msg: latin1 " [d] Alusta LAUNCHER pärast kernel on koormatud:",0 -ask_launcher: latin1 "Alusta esimese taotluse (LAUNCHER) pärast kernel laetakse? [1-jah, 2-no]: ",0 +launcher_msg latin1 " [d] Käivita LAUNCHER pärast kerneli laadimist:",0 +ask_launcher latin1 "Käivita esimese programm (LAUNCHER) peale kerneli laadimist? [1-jah, 2-ei]: ",0 -preboot_device_msg:latin1 " [e] Disketi kujutis: ",0 +preboot_device_msg latin1 " [e] Disketi kujutis: ",0 if defined extended_primary_loader preboot_device_msgs dw 0,pdm1,pdm2,0 -pdm1: latin1 "reaalne diskett",13,10,0 -pdm2: latin1 "kolibri.img",13,10,0 +pdm1 latin1 "reaalne diskett",13,10,0 +pdm2 latin1 "kolibri.img",13,10,0 else -preboot_device_msgs dw 0,pdm1,pdm2,pdm3 -pdm1: latin1 "reaalne diskett",13,10,0 -pdm2: latin1 "C:\kolibri.img (FAT32)",13,10,0 -pdm3: latin1 "kasuta juba laaditud kujutist",13,10,0 -pdm4: latin1 "loo tühi pilt",13,10,0 +preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4,0 +pdm1 latin1 "reaalne diskett",13,10,0 +pdm2 latin1 "C:\kolibri.img (FAT32)",13,10,0 +pdm3 latin1 "kasuta juba laaditud kujutist",13,10,0 +pdm4 latin1 "loo tühi pilt",13,10,0 end if -loading_msg:latin1 "Laadin KolibriOS...",0 +loading_msg latin1 "Laadin KolibriOS...",0 if ~ defined extended_primary_loader -save_quest:latin1 "Jäta meelde praegused seaded? [y/n]: ",0 -loader_block_error:latin1 "Alglaaduri andmed vigased, ei saa jätkata. Peatatud.",0 +save_quest latin1 "Jäta meelde praegused seaded? [y/n]: ",0 +loader_block_error latin1 "Alglaaduri andmed vigased, ei saa jätkata. Peatatud.",0 end if -_st:latin1 '║ ┌───────────────────────────────┬─┐',13,10,0 -_r1:latin1 '║ │ 320x200 EGA/CGA 256 colors │ │',13,10,0 -_r2:latin1 '║ │ 640x480 VGA 16 colors │ │',13,10,0 -_rs:latin1 '║ │ ????x????@?? SVGA VESA │ │',13,10,0 -_bt:latin1 '║ └───────────────────────────────┴─┘',13,10,0 +_st latin1 '║ ┌───────────────────────────────┬─┐',13,10,0 +_r1 latin1 '║ │ 320x200 EGA/CGA 256 colors │ │',13,10,0 +_r2 latin1 '║ │ 640x480 VGA 16 colors │ │',13,10,0 +_rs latin1 '║ │ ????x????@?? SVGA VESA │ │',13,10,0 +_bt latin1 '║ └───────────────────────────────┴─┘',13,10,0 -remark1:latin1 "Vaikimisi maaratud vaartused on valitud mugavuse enamikes, kuid mitte koik.",0 -remark2:latin1 "Kui susteem ei kaivitu, proovige lulitada kirje [b].",0 -remarks dw remark1, remark2 -num_remarks = 2 +remark1 latin1 "Vaikimisi väärtused on kasutatavad enamikes arvutites, kuid mitte kõigis.",0 +remark2 latin1 "Kui süsteem ei käivitu, proovige lülitada kirje [b] välja. Kui see läheb",0 +remark3 latin1 "kinni pärast käivitamist, võimaldama valik [c], keelake [d] ja teha foto.",0 +remarks dw remark1, remark2, remark3 +num_remarks = 3 \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/boot/bootge.inc b/kernel/branches/Kolibri-acpi/boot/bootge.inc index 63b1f3c9f0..05f06ac759 100644 --- a/kernel/branches/Kolibri-acpi/boot/bootge.inc +++ b/kernel/branches/Kolibri-acpi/boot/bootge.inc @@ -15,10 +15,8 @@ $Revision$ d80x25_bottom: - db 186,' KolibriOS wird ohne jegliche Garantie vertrieben. ' - db ' ',186 - db 186,' Details stehen in der Datei COPYING ' - db ' ',186 + db 186,' KolibriOS wird ohne jegliche Garantie vertrieben. Details stehen in der ',186 + db 186,' Datei COPYING. Bitte melden Sie Fehler bei: http://board.kolibrios.org ',186 line_full_bottom d80x25_bottom_num = 3 @@ -81,7 +79,7 @@ preboot_device_msgs dw 0,pdm1,pdm2,0 pdm1 db "Echte Diskette",13,10,0 pdm2 db "kolibri.img",13,10,0 else -preboot_device_msgs dw 0,pdm1,pdm2,pdm3 +preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4,0 pdm1 db "Echte Diskette",13,10,0 pdm2 db "C:\kolibri.img (FAT32)",13,10,0 pdm3 db "Nutze bereits geladenes Image",13,10,0 @@ -95,13 +93,15 @@ save_quest db "Aktuelle Einstellungen speichern? [y/n]: ",0 loader_block_error db "Bootloader Daten ungueltig, Kann nicht fortfahren. Angehalten.",0 end if -_st:latin1 '║ ┌───────────────────────────────┬─┐',13,10,0 -_r1:latin1 '║ │ 320x200 EGA/CGA 256 colors │ │',13,10,0 -_r2:latin1 '║ │ 640x480 VGA 16 colors │ │',13,10,0 -_rs:latin1 '║ │ ????x????@?? SVGA VESA │ │',13,10,0 -_bt:latin1 '║ └───────────────────────────────┴─┘',13,10,0 +_st latin1 '║ ┌───────────────────────────────┬─┐',13,10,0 +_r1 latin1 '║ │ 320x200 EGA/CGA 256 colors │ │',13,10,0 +_r2 latin1 '║ │ 640x480 VGA 16 colors │ │',13,10,0 +_rs latin1 '║ │ ????x????@?? SVGA VESA │ │',13,10,0 +_bt latin1 '║ └───────────────────────────────┴─┘',13,10,0 remark1 db "Die Standardwerte sind fur die meisten gewahlt, aber nicht fur jedermann.",0 -remark2 db "Wenn das System nicht bootet, versuchen, das Element [b] deaktivieren.",0 -remarks dw remark1, remark2 -num_remarks = 2 +remark2 db "Wenn das System nicht bootet, das Option [b] deaktivieren versuchen. Wenn es",0 +remark3 db "nach dem Booten hangen bleibt, aktivieren Sie Option [c], deaktivieren [d]",0 +remark4 db "und machen Fotos.",0 +remarks dw remark1, remark2, remark3, remark4 +num_remarks = 4 \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/boot/bootru.inc b/kernel/branches/Kolibri-acpi/boot/bootru.inc index a73ce1096b..76205d3cd5 100644 --- a/kernel/branches/Kolibri-acpi/boot/bootru.inc +++ b/kernel/branches/Kolibri-acpi/boot/bootru.inc @@ -15,89 +15,90 @@ $Revision$ d80x25_bottom: - cp866 '║ KolibriOS НЕ ПРЕДОСТАВЛЯЕТ НИКАКИХ ГАРAНТИЙ. ║' - cp866 '║ Подробнее смотрите в файле COPYING.TXT ║' + cp866 '║ KolibriOS НЕ ПРЕДОСТАВЛЯЕТ НИКАКИХ ГАРAНТИЙ. Подробнее смотрите в файле ║' + cp866 '║ COPYING.TXT. О найденных ошибках сообщайте на http://board.kolibrios.org ║' line_full_bottom d80x25_bottom_num = 3 -msg_apm: cp866 " APM x.x ", 0 -novesa: cp866 "Видеокарта: EGA/CGA",13,10,0 -s_vesa: cp866 "Версия VESA: " +msg_apm cp866 " APM x.x ", 0 +novesa cp866 "Видеокарта: EGA/CGA",13,10,0 +s_vesa cp866 "Версия VESA: " .ver db "?.?",13,10,0 -gr_mode: cp866 "Выберите видеорежим: ",13,10,0 +gr_mode cp866 "Выберите видеорежим: ",13,10,0 -ask_bd: cp866 "Добавить диски, видимые через BIOS в режиме V86? [1-да, 2-нет]: ",0 +ask_bd cp866 "Добавить диски, видимые через BIOS в режиме V86? [1-да, 2-нет]: ",0 if defined extended_primary_loader -bdev: cp866 "Загрузить образ из [1-дискета; 2-kolibri.img из папки загрузки]: ",0 +bdev cp866 "Загрузить образ из [1-дискета; 2-kolibri.img из папки загрузки]: ",0 else -bdev: cp866 "Загрузить образ из [1-дискета; 2-C:\kolibri.img (FAT32);",13,10 +bdev cp866 "Загрузить образ из [1-дискета; 2-C:\kolibri.img (FAT32);",13,10 cp866 "║ 3-использовать уже загруженный образ;",13,10 cp866 "║ 4-создать чистый образ]: ",0 end if -prnotfnd: cp866 "Ошибка - Видеорежим не найден.",0 +prnotfnd cp866 "Ошибка - Видеорежим не найден.",0 -not386: cp866 "Ошибка - Требуется процессор 386+.",0 -fatalsel: cp866 "Ошибка - Выбранный видеорежим не поддерживается.",0 -pres_key: cp866 "Нажимите любую клавишу, для перехода в выбор режимов.",0 -badsect: cp866 13,10,"║ Ошибка - Дискета повреждена. Попробуйте другую.",0 -memmovefailed:cp866 13,10,"║ Ошибка - Int 0x15 move failed.",0 -okt: cp866 " ... OK" -linef: cp866 13,10,0 -diskload: cp866 "Загрузка дискеты: 00 %",8,8,8,8,0 -pros: cp866 "00" -backspace2:cp866 8,8,0 +not386 cp866 "Ошибка - Требуется процессор 386+.",0 +fatalsel cp866 "Ошибка - Выбранный видеорежим не поддерживается.",0 +pres_key cp866 "Нажимите любую клавишу, для перехода в выбор режимов.",0 +badsect cp866 13,10,"║ Ошибка - Дискета повреждена. Попробуйте другую.",0 +memmovefailed cp866 13,10,"║ Ошибка - Int 0x15 move failed.",0 +okt cp866 " ... OK" +linef cp866 13,10,0 +diskload cp866 "Загрузка дискеты: 00 %",8,8,8,8,0 +pros cp866 "00" +backspace2 cp866 8,8,0 boot_dev db 0 -start_msg:cp866 "Нажмите [abcde] для изменения настроек, [Enter] для продолжения загрузки",13,10,0 -time_msg: cp866 " или подождите " -time_str: cp866 " 5 секунд " +start_msg cp866 "Нажмите [abcde] для изменения настроек, [Enter] для продолжения загрузки",13,10,0 +time_msg cp866 " или подождите " +time_str cp866 " 5 секунд " cp866 " до автоматического продолжения",13,10,0 -current_cfg_msg:cp866 "Текущие настройки:",13,10,0 -curvideo_msg:cp866 " [a] Видеорежим: ",0 +current_cfg_msg cp866 "Текущие настройки:",13,10,0 +curvideo_msg cp866 " [a] Видеорежим: ",0 -mode0: cp866 "320x200, EGA/CGA 256 цветов",13,10,0 -mode9: cp866 "640x480, VGA 16 цветов",13,10,0 +mode0 cp866 "320x200, EGA/CGA 256 цветов",13,10,0 +mode9 cp866 "640x480, VGA 16 цветов",13,10,0 -usebd_msg:cp866 " [b] Добавить диски, видимые через BIOS:",0 -on_msg: cp866 " вкл",13,10,0 -off_msg: cp866 " выкл",13,10,0 +usebd_msg cp866 " [b] Добавить диски, видимые через BIOS:",0 +on_msg cp866 " вкл",13,10,0 +off_msg cp866 " выкл",13,10,0 -debug_mode_msg: cp866 " [c] Дублировать дебаг-вывод на экран монитора:",0 -ask_debug: cp866 "Дублировать дебаг-вывод на экран монитора? [1-да, 2-нет]: ",0 +debug_mode_msg cp866 " [c] Дублировать дебаг-вывод на экран монитора:",0 +ask_debug cp866 "Дублировать дебаг-вывод на экран монитора? [1-да, 2-нет]: ",0 -launcher_msg: cp866 " [d] Запустить программу LAUNCHER после загрузки ядра:",0 -ask_launcher: cp866 "Запустить первую программу (LAUNCHER) после загрузки ядра? [1-да, 2-нет]: ",0 +launcher_msg cp866 " [d] Запустить программу LAUNCHER после загрузки ядра:",0 +ask_launcher cp866 "Запустить первую программу (LAUNCHER) после загрузки ядра? [1-да, 2-нет]: ",0 -preboot_device_msg:cp866 " [e] Образ дискеты: ",0 +preboot_device_msg cp866 " [e] Образ дискеты: ",0 if defined extended_primary_loader preboot_device_msgs dw 0,pdm1,pdm2,0 -pdm1: cp866 "настоящая дискета",13,10,0 -pdm2: cp866 "kolibri.img из папки загрузки",13,10,0 +pdm1 cp866 "настоящая дискета",13,10,0 +pdm2 cp866 "kolibri.img из папки загрузки",13,10,0 else -preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4 -pdm1: cp866 "настоящая дискета",13,10,0 -pdm2: cp866 "C:\kolibri.img (FAT32)",13,10,0 -pdm3: cp866 "использовать уже загруженный образ",13,10,0 -pdm4: cp866 "создать чистый образ",13,10,0 +preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4,0 +pdm1 cp866 "настоящая дискета",13,10,0 +pdm2 cp866 "C:\kolibri.img (FAT32)",13,10,0 +pdm3 cp866 "использовать уже загруженный образ",13,10,0 +pdm4 cp866 "создать чистый образ",13,10,0 end if -loading_msg:cp866 "Идёт загрузка KolibriOS...",0 +loading_msg cp866 "Идёт загрузка KolibriOS...",0 if ~ defined extended_primary_loader ; saving not supported in this case -save_quest:cp866 "Запомнить текущие настройки? [y/n]: ",0 -loader_block_error:cp866 "Ошибка в данных начального загрузчика, продолжение невозможно.",0 +save_quest cp866 "Запомнить текущие настройки? [y/n]: ",0 +loader_block_error cp866 "Ошибка в данных начального загрузчика, продолжение невозможно.",0 end if -_st:cp866 '║ ┌───────────────────────────────┬─┐ ',13,10,0 -_r1:cp866 '║ │ 320x200 EGA/CGA 256 цветов │ │ ',13,10,0 -_r2:cp866 '║ │ 640x480 VGA 16 цветов │ │ ',13,10,0 -_rs:cp866 '║ │ ????x????@?? SVGA VESA │ │ ',13,10,0 -_bt:cp866 '║ └───────────────────────────────┴─┘ ',13,10,0 +_st cp866 '║ ┌───────────────────────────────┬─┐ ',13,10,0 +_r1 cp866 '║ │ 320x200 EGA/CGA 256 цветов │ │ ',13,10,0 +_r2 cp866 '║ │ 640x480 VGA 16 цветов │ │ ',13,10,0 +_rs cp866 '║ │ ????x????@?? SVGA VESA │ │ ',13,10,0 +_bt cp866 '║ └───────────────────────────────┴─┘ ',13,10,0 -remark1:cp866 "Значения по умолчанию выбраны для удобства большинства, но не всех.",0 -remark2:cp866 "Если у Вас не грузится система, попробуйте отключить пункт [b].",0 -remarks dw remark1, remark2 -num_remarks = 2 +remark1 cp866 "Значения по умолчанию выбраны для удобства большинства, но не всех. Если у",0 +remark2 cp866 "Вас не грузится система, попробуйте отключить пункт [b]. Если она зависла",0 +remark3 cp866 "после запуска, включите пункт [c], отключите пункт [d] и сделайте фото лога.",0 +remarks dw remark1, remark2, remark3 +num_remarks = 3 \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/boot/bootsp.inc b/kernel/branches/Kolibri-acpi/boot/bootsp.inc index a36b36e7c6..3f9a80db68 100644 --- a/kernel/branches/Kolibri-acpi/boot/bootsp.inc +++ b/kernel/branches/Kolibri-acpi/boot/bootsp.inc @@ -17,93 +17,92 @@ $Revision: 2455 $ d80x25_bottom: - cp850 '║ KolibriOS y viene ABSOLUTAMENTE SIN GARANTíA. ' - cp850 ' ║' - cp850 '║ Lee el archivo COPYING por más detalles ' - cp850 ' ║' + cp850 '║ KolibriOS viene ABSOLUTAMENTE SIN GARANTíA. Lee el archivo COPYING por más ║' + cp850 '║ detalles. Por favor, informar de los errores en: http://board.kolibrios.org ║' line_full_bottom d80x25_bottom_num = 3 -msg_apm: cp850 " APM x.x ", 0 -novesa: cp850 "Monitor: EGA/CGA",13,10,0 -s_vesa: cp850 "Versión de VESA: " +msg_apm cp850 " APM x.x ", 0 +novesa cp850 "Monitor: EGA/CGA",13,10,0 +s_vesa cp850 "Versión de VESA: " .ver db "?.?",13,10,0 -gr_mode: cp850 "Selecciona un modo de video: ",13,10,0 +gr_mode cp850 "Selecciona un modo de video: ",13,10,0 -ask_bd: cp850 "¿Agregar discos visibles por el BIOS emulados en modo V86? [1-si, 2-no]: ",0 +ask_bd cp850 "¿Agregar discos visibles por el BIOS emulados en modo V86? [1-si, 2-no]: ",0 if defined extended_primary_loader -bdev: cp850 "Cargar unidad ram desde [1-disquete; 2-kolibri.img]: ",0 +bdev cp850 "Cargar unidad ram desde [1-disquete; 2-kolibri.img]: ",0 else -bdev: cp850 "Cargar unidad ram desde [1-disquete; 2-C:\kolibri.img (FAT32);" +bdev cp850 "Cargar unidad ram desde [1-disquete; 2-C:\kolibri.img (FAT32);" cp850 13,10,"║ " cp850 "3-usar imagen precargada en el reinicio del núcleo;" cp850 13,10,"║ " cp850 "4-crear imagen vacía]: ",0 end if -prnotfnd: cp850 "Fatal - Modo de video no encontrado.",0 +prnotfnd cp850 "Fatal - Modo de video no encontrado.",0 -not386: cp850 "Fatal - CPU 386+ requerido.",0 -fatalsel: cp850 "Fatal - Modo de gráficos no soportado por hardware.",0 -pres_key: cp850 "Presiona una tecla para seleccionar otro modo de video.",0 -badsect: cp850 13,10,"║ Fatal - Sector mal. Reemplaze el disquete.",0 -memmovefailed:cp850 13,10,"║ Fatal - Int 0x15 move failed.",0 -okt: cp850 " ... BIEN" -linef: cp850 13,10,0 -diskload: cp850 "Cargando disquete: 00 %",8,8,8,8,0 -pros: cp850 "00" -backspace2:cp850 8,8,0 +not386 cp850 "Fatal - CPU 386+ requerido.",0 +fatalsel cp850 "Fatal - Modo de gráficos no soportado por hardware.",0 +pres_key cp850 "Presiona una tecla para seleccionar otro modo de video.",0 +badsect cp850 13,10,"║ Fatal - Sector mal. Reemplaze el disquete.",0 +memmovefailed cp850 13,10,"║ Fatal - Int 0x15 move failed.",0 +okt cp850 " ... BIEN" +linef cp850 13,10,0 +diskload cp850 "Cargando disquete: 00 %",8,8,8,8,0 +pros cp850 "00" +backspace2 cp850 8,8,0 boot_dev db 0 ; 0=floppy, 1=hd -start_msg:cp850 "Presiona [abcde] para cambiar la configuración, [Enter] para continuar",13,10,0 -time_msg: cp850 " o espera " -time_str: cp850 " 5 segundos" +start_msg cp850 "Presiona [abcde] para cambiar la configuración, [Enter] para continuar",13,10,0 +time_msg cp850 " o espera " +time_str cp850 " 5 segundos" cp850 " para que inicie automáticamente",13,10,0 -current_cfg_msg:cp850 "Configuración actual:",13,10,0 -curvideo_msg:cp850 " [a] Modo de video: ",0 +current_cfg_msg cp850 "Configuración actual:",13,10,0 +curvideo_msg cp850 " [a] Modo de video: ",0 -mode0: cp850 "320x200, EGA/CGA 256 colores",13,10,0 -mode9: cp850 "640x480, VGA 16 colores",13,10,0 +mode0 cp850 "320x200, EGA/CGA 256 colores",13,10,0 +mode9 cp850 "640x480, VGA 16 colores",13,10,0 -usebd_msg:cp850 " [b] Agregar discos visibles por el BIOS:",0 -on_msg: cp850 " activado",13,10,0 -off_msg: cp850 " desactivado",13,10,0 +usebd_msg cp850 " [b] Agregar discos visibles por el BIOS:",0 +on_msg cp850 " activado",13,10,0 +off_msg cp850 " desactivado",13,10,0 -debug_mode_msg: cp850 " [c] Duplicar depurar salida a la pantalla:",0 -ask_debug: cp850 "¿Duplicar depurar la salida a la pantalla? [1-si, 2-no]: ",0 +debug_mode_msg cp850 " [c] Duplicar depurar salida a la pantalla:",0 +ask_debug cp850 "¿Duplicar depurar la salida a la pantalla? [1-si, 2-no]: ",0 -launcher_msg: cp850 " [d] Iniciar LAUNCHER después de cargar kernel:",0 -ask_launcher: cp850 "¿Inicie la primera aplicación después de cargar el kernel? [1-si, 2-no]: ",0 +launcher_msg cp850 " [d] Iniciar LAUNCHER después de cargar kernel:",0 +ask_launcher cp850 "¿Inicie la primera aplicación después de cargar el kernel? [1-si, 2-no]: ",0 -preboot_device_msg:cp850 " [e] Imagen de disquete: ",0 +preboot_device_msg cp850 " [e] Imagen de disquete: ",0 if defined extended_primary_loader preboot_device_msgs dw 0,pdm1,pdm2,0 -pdm1: cp850 "disquete real",13,10,0 -pdm2: cp850 "C:\kolibri.img (FAT32)",13,10,0 +pdm1 cp850 "disquete real",13,10,0 +pdm2 cp850 "C:\kolibri.img (FAT32)",13,10,0 else -preboot_device_msgs dw 0,pdm1,pdm2,pdm3 -pdm1: cp850 "disquete real",13,10,0 -pdm2: cp850 "C:\kolibri.img (FAT32)",13,10,0 -pdm3: cp850 "usar imagen ya cargada",13,10,0 -pdm4: cp850 "crear imagen vacía",13,10,0 +preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4,0 +pdm1 cp850 "disquete real",13,10,0 +pdm2 cp850 "C:\kolibri.img (FAT32)",13,10,0 +pdm3 cp850 "usar imagen ya cargada",13,10,0 +pdm4 cp850 "crear imagen vacía",13,10,0 end if -loading_msg:cp850 "Cargando KolibriOS...",0 +loading_msg cp850 "Cargando KolibriOS...",0 if ~ defined extended_primary_loader -save_quest:cp850 "¿Recordar configuración actual? [s/n]: ",0 -loader_block_error:cp850 "Bootloader inválido, no puedo continuar. Detenido.",0 +save_quest cp850 "¿Recordar configuración actual? [s/n]: ",0 +loader_block_error cp850 "Bootloader inválido, no puedo continuar. Detenido.",0 end if -_st:cp850 '║ ┌───────────────────────────────┬─┐',13,10,0 -_r1:cp850 '║ │ 320x200 EGA/CGA 256 colores │ │',13,10,0 -_r2:cp850 '║ │ 640x480 VGA 16 colores │ │',13,10,0 -_rs:cp850 '║ │ ????x????@?? SVGA VESA │ │',13,10,0 -_bt:cp850 '║ └───────────────────────────────┴─┘',13,10,0 +_st cp850 '║ ┌───────────────────────────────┬─┐',13,10,0 +_r1 cp850 '║ │ 320x200 EGA/CGA 256 colores │ │',13,10,0 +_r2 cp850 '║ │ 640x480 VGA 16 colores │ │',13,10,0 +_rs cp850 '║ │ ????x????@?? SVGA VESA │ │',13,10,0 +_bt cp850 '║ └───────────────────────────────┴─┘',13,10,0 -remark1:cp850 "Los valores por defecto puede que no funcionen en algunas configuraciones.",0 -remark2:cp850 "Si el sistema no inicia, prueba deshabilitar la opción [b].",0 -remarks dw remark1, remark2 -num_remarks = 2 +remark1 cp850 "Los valores por defecto puede que no funcionen en algunas configuraciones.",0 +remark2 cp850 "Si el sistema no inicia, prueba deshabilitar la opción [b]. Si se bloquea",0 +remark3 cp850 "después de arrancar, habilite la opción [c], desactivar [d] y hacer fotos.",0 +remarks dw remark1, remark2, remark3 +num_remarks = 3 \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/boot/bootvesa.inc b/kernel/branches/Kolibri-acpi/boot/bootvesa.inc index 41932234b2..759256f85b 100644 --- a/kernel/branches/Kolibri-acpi/boot/bootvesa.inc +++ b/kernel/branches/Kolibri-acpi/boot/bootvesa.inc @@ -79,6 +79,7 @@ virtual at $A000 modes_table: end virtual cursor_pos dw 0 ;временное хранение курсора. +cursor_pos_old dw 0 home_cursor dw 0 ;current shows rows a table end_cursor dw 0 ;end of position current shows rows a table scroll_start dw 0 ;start position of scroll bar diff --git a/kernel/branches/Kolibri-acpi/boot/et.inc b/kernel/branches/Kolibri-acpi/boot/et.inc index c7a8fc501d..332107afc7 100644 --- a/kernel/branches/Kolibri-acpi/boot/et.inc +++ b/kernel/branches/Kolibri-acpi/boot/et.inc @@ -9,7 +9,7 @@ $Revision$ ; Full ASCII code font -; only õ and ä added +; only õ,ä,ü added ; Kaitz ET_FNT: fontfile file "ETFONT.FNT" diff --git a/kernel/branches/Kolibri-acpi/bus/usb/hub.inc b/kernel/branches/Kolibri-acpi/bus/usb/hub.inc index 17323da1d5..840b556acd 100644 --- a/kernel/branches/Kolibri-acpi/bus/usb/hub.inc +++ b/kernel/branches/Kolibri-acpi/bus/usb/hub.inc @@ -105,6 +105,9 @@ ConfigPipe dd ? StatusPipe dd ? NumPorts dd ? ; Number of downstream ports; from 1 to 255. +MaxPacketSize dd ? +; Maximum packet size for interrupt endpoint. +; Usually equals ceil((1+NumPorts)/8), but some hubs give additional bytes. Actions dd ? ; Bitfield with HUB_* constants. PoweredOnTime dd ? @@ -250,10 +253,11 @@ end virtual ; the pointer is in edx. ; 2. Allocate memory for the hub descriptor. ; Maximum length (assuming 255 downstream ports) is 40 bytes. +; Allocate 4 extra bytes to keep wMaxPacketSize. ; 2a. Save registers. push edx ; 2b. Call the allocator. - movi eax, 40 + movi eax, 44 call malloc ; 2c. Restore registers. pop ecx @@ -267,7 +271,11 @@ end virtual movzx eax, [ecx+usb_endpoint_descr.bEndpointAddress] movzx edx, [ecx+usb_endpoint_descr.bInterval] movzx ecx, [ecx+usb_endpoint_descr.wMaxPacketSize] + test ecx, (1 shl 11) - 1 + jz .free + push ecx stdcall usb_open_pipe, ebx, eax, ecx, INTERRUPT_PIPE, edx + pop ecx ; If failed, free the memory allocated in step 2, ; say something to the debug board and return error. test eax, eax @@ -275,6 +283,8 @@ end virtual ; 4. Send control query for the hub descriptor, ; pass status pipe as a callback parameter, ; allow short packets. + and ecx, (1 shl 11) - 1 + mov [esi+40], ecx mov dword [esi], 0xA0 + \ ; class-specific request (USB_GET_DESCRIPTOR shl 8) + \ (0 shl 16) + \ ; descriptor index 0 @@ -352,8 +362,9 @@ end if cmp [length], edx jb .invalid ; 5. Allocate the memory for usb_hub structure. -; Total size of variable-length data is ALIGN_UP(2*(floor(NumPorts/8)+1),4)+8*NumPorts. - lea edx, [sizeof.usb_hub+(edx-sizeof.usb_hub_descr)*2+3] +; Total size of variable-length data is ALIGN_UP(floor(NumPorts/8)+1+MaxPacketSize,4)+8*NumPorts. + add edx, [eax+40] + add edx, sizeof.usb_hub - sizeof.usb_hub_descr + 3 and edx, not 3 lea eax, [edx+ecx*8] push ecx edx @@ -374,6 +385,8 @@ end if mov [ebx+usb_hub.StatusPipe], eax push esi edi mov esi, [buffer] + mov eax, [esi+40] + mov [ebx+usb_hub.MaxPacketSize], eax ; The following commands load bNbrPorts, wHubCharacteristics, bPwrOn2PwrGood. mov edx, dword [esi+usb_hub_descr.bNbrPorts] mov dl, 0 @@ -487,11 +500,8 @@ endp ; Called when initial configuration is done and when a previous notification ; has been processed. proc usb_hub_wait_change - mov ecx, [eax+usb_hub.NumPorts] - shr ecx, 3 - inc ecx stdcall usb_normal_transfer_async, [eax+usb_hub.StatusPipe], \ - [eax+usb_hub.StatusChangePtr], ecx, usb_hub_changed, eax, 1 + [eax+usb_hub.StatusChangePtr], [eax+usb_hub.MaxPacketSize], usb_hub_changed, eax, 1 ret endp @@ -513,6 +523,7 @@ proc usb_hub_changed stdcall, pipe:dword, status:dword, buffer:dword, length:dwo shr ecx, 3 inc ecx sub ecx, [length] + jbe .restart push eax edi mov edi, [buffer] add edi, [length] diff --git a/kernel/branches/Kolibri-acpi/bus/usb/protocol.inc b/kernel/branches/Kolibri-acpi/bus/usb/protocol.inc index d6493c3b8f..3d2fb42625 100644 --- a/kernel/branches/Kolibri-acpi/bus/usb/protocol.inc +++ b/kernel/branches/Kolibri-acpi/bus/usb/protocol.inc @@ -202,8 +202,7 @@ proc usb_new_device ; For now, we need sizeof.usb_device_data and extra 8 bytes for GET_DESCRIPTOR ; input and output, see usb_after_set_address. Later we will reallocate it ; to actual size needed for descriptors. - push sizeof.usb_device_data + 8 - pop eax + movi eax, sizeof.usb_device_data + 8 push ecx call malloc pop ecx @@ -498,10 +497,7 @@ proc usb_after_set_endpoint_size pop edi esi call usb_reinit_pipe_list ; 1d. Free the old memory. -; Note that free destroys ebx. - push ebx call free - pop ebx pop eax ; 2. Issue control transfer GET_DESCRIPTOR(DEVICE) for full descriptor. ; restore length saved in step 1a diff --git a/kernel/branches/Kolibri-acpi/core/clipboard.inc b/kernel/branches/Kolibri-acpi/core/clipboard.inc new file mode 100644 index 0000000000..689064024b --- /dev/null +++ b/kernel/branches/Kolibri-acpi/core/clipboard.inc @@ -0,0 +1,148 @@ +;------------------------------------------------------------------------------ +align 4 +sys_clipboard: + xor eax, eax + dec eax +; check availability of main list + cmp [clipboard_main_list], eax + je .exit_1 ; main list area not found + + test ebx, ebx ; 0 - Get the number of slots in the clipboard + jnz .1 +; get the number of slots + mov eax, [clipboard_slots] + jmp .exit_1 +;------------------------------------------------------------------------------ +align 4 +.1: + dec ebx ; 1 - Read the data from the clipboard + jnz .2 +; verify the existence of slot + cmp ecx, [clipboard_slots] + jae .exit_2 +; get a pointer to the data of slot + shl ecx, 2 + add ecx, [clipboard_main_list] + mov esi, [ecx] + mov ecx, [esi] +; allocate memory for application for copy the data of slots + push ecx + stdcall user_alloc, ecx + pop ecx +; copying data of slots + mov edi, eax + cld + rep movsb + jmp .exit_1 +;------------------------------------------------------------------------------ +align 4 +.2: + dec ebx ; 2 - Write the data to the clipboard + jnz .3 +; check the lock + mov ebx, clipboard_write_lock + xor eax, eax + cmp [ebx], eax + jne .exit_2 +; lock last slot + inc eax + mov [ebx], eax +; check the overflow pointer of slots + cmp [clipboard_slots], 1024 + jae .exit_3 +; get memory for new slot + push ebx ecx edx + stdcall kernel_alloc, ecx + pop edx ecx ebx + test eax, eax + jz .exit_3 +; create a new slot + mov edi, eax + mov eax, [clipboard_slots] + shl eax, 2 + add eax, [clipboard_main_list] + mov [eax], edi +; copy the data into the slot + mov esi, edx + mov eax, ecx + cld + stosd ; store size of slot + sub ecx, 4 + add esi, 4 + rep movsb ; store slot data +; increase the counter of slots + inc [clipboard_slots] +; unlock last slot + xor eax, eax + mov [ebx], eax + jmp .exit_1 +;------------------------------------------------------------------------------ +align 4 +.3: + dec ebx ; 3 - Delete the last slot in the clipboard + jnz .4 +; check the availability of slots + mov eax, [clipboard_slots] + test eax, eax + jz .exit_2 +; check the lock + mov ebx, clipboard_write_lock + xor eax, eax + cmp [ebx], eax + jne .exit_2 +; lock last slot + inc eax + mov [ebx], eax +; decrease the counter of slots + mov eax, clipboard_slots + dec dword [eax] +; free of kernel memory allocated for the slot + mov eax, [eax] + shl eax, 2 + add eax, [clipboard_main_list] + mov eax, [eax] + push ebx + stdcall kernel_free, eax + pop ebx +; unlock last slot + xor eax, eax + mov [ebx], eax + jmp .exit_1 +;------------------------------------------------------------------------------ +align 4 +.4: + dec ebx ; 4 - Emergency discharge of clipboard + jnz .exit +; check the lock + mov ebx, clipboard_write_lock + xor eax, eax + cmp [ebx], eax + je .exit_2 + +; there should be a procedure for checking the integrity of the slots +; and I will do so in the future + +; unlock last slot + mov [ebx], eax + jmp .exit +;------------------------------------------------------------------------------ +align 4 +.exit_3: +; unlock last slot + xor eax, eax + mov [ebx], eax +.exit_2: + xor eax, eax + inc eax ; error +.exit_1: + mov [esp + 32], eax +.exit: + ret +;------------------------------------------------------------------------------ +uglobal +align 4 +clipboard_slots dd ? +clipboard_main_list dd ? +clipboard_write_lock dd ? +endg +;------------------------------------------------------------------------------ diff --git a/kernel/branches/Kolibri-acpi/core/conf_lib-sp.inc b/kernel/branches/Kolibri-acpi/core/conf_lib-sp.inc index c400336a0b..abf7cf5e3e 100644 --- a/kernel/branches/Kolibri-acpi/core/conf_lib-sp.inc +++ b/kernel/branches/Kolibri-acpi/core/conf_lib-sp.inc @@ -1,11 +1,11 @@ ; Éste archivo debe ser editado con codificación CP866 -ugui_mouse_speed:cp850 'velocidad del ratón',0 -ugui_mouse_delay:cp850 'demora del ratón',0 +ugui_mouse_speed cp850 'velocidad del ratón',0 +ugui_mouse_delay cp850 'demora del ratón',0 -udev:cp850 'disp',0 -unet:cp850 'red',0 -unet_active:cp850 'activa',0 -unet_addr:cp850 'direc',0 -unet_mask:cp850 'másc',0 -unet_gate:cp850 'puer',0 +udev cp850 'disp',0 +unet cp850 'red',0 +unet_active cp850 'activa',0 +unet_addr cp850 'direc',0 +unet_mask cp850 'másc',0 +unet_gate cp850 'puer',0 diff --git a/kernel/branches/Kolibri-acpi/core/dll.inc b/kernel/branches/Kolibri-acpi/core/dll.inc index f31d7c2cab..442c2a7c22 100644 --- a/kernel/branches/Kolibri-acpi/core/dll.inc +++ b/kernel/branches/Kolibri-acpi/core/dll.inc @@ -458,7 +458,6 @@ proc load_file_umode stdcall, file_name:dword push edi push ebx - lea eax, [attr] stdcall get_fileinfo, [file_name], eax ;find file and get info test eax, eax @@ -484,11 +483,26 @@ proc load_file_umode stdcall, file_name:dword mov ebx, [eax+4] ;get real size of file mov [file_size], ebx - stdcall user_alloc, ebx ;and allocate memory from user heap + stdcall user_alloc, ebx ;and allocate space from user heap mov [um_file], eax test eax, eax jz .err_2 + mov edx, [file_size] ;preallocate page memory + shr eax, 10 + lea edi, [page_tabs+eax] + add edx, 4095 + shr edx, 12 +@@: + call alloc_page + test eax, eax + jz .err_3 + + or eax, PG_UW + stosd + dec edx + jnz @B + pushad mov ecx, unpack_mutex call mutex_lock @@ -501,15 +515,28 @@ proc load_file_umode stdcall, file_name:dword stdcall kernel_free, [km_file] ;we don't need packed file anymore .exit: + + mov edi, [um_file] + mov esi, [um_file] + mov eax, [file_size] + mov edx, eax + + add edi, eax ;cleanup remain space + mov ecx, 4096 ;from file end + and eax, 4095 + jz @f + sub ecx, eax + xor eax, eax + cld + rep stosb +@@: mov eax, [um_file] - mov edx, [file_size] pop ebx pop edi pop esi ret - .raw_file: ; sometimes we load unpacked file stdcall user_alloc, ebx ; allocate space from user heap mov [um_file], eax @@ -533,13 +560,14 @@ proc load_file_umode stdcall, file_name:dword @@: lodsd and eax, 0xFFFFF000 - or eax, PG_USER + or eax, PG_UW stosd loop @B stdcall free_kernel_space, [km_file] ; release allocated kernel space jmp .exit ; physical pages still in use - +.err_3: + stdcall user_free, [um_file] .err_2: stdcall kernel_free, [km_file] .err_1: diff --git a/kernel/branches/Kolibri-acpi/core/exports.inc b/kernel/branches/Kolibri-acpi/core/exports.inc index f839282b0c..d6825558f5 100644 --- a/kernel/branches/Kolibri-acpi/core/exports.inc +++ b/kernel/branches/Kolibri-acpi/core/exports.inc @@ -81,6 +81,8 @@ __exports: register_keyboard, 'RegKeyboard', \ delete_keyboard, 'DelKeyboard', \ get_cpu_freq, 'GetCpuFreq', \ +\ + new_sys_threads, 'CreateThread', \ ; ebx, ecx, edx \ srv_handler, 'ServiceHandler', \ fpu_save, 'FpuSave', \ diff --git a/kernel/branches/Kolibri-acpi/core/sys32-sp.inc b/kernel/branches/Kolibri-acpi/core/sys32-sp.inc index 2bc437aa31..12a29eda4c 100644 --- a/kernel/branches/Kolibri-acpi/core/sys32-sp.inc +++ b/kernel/branches/Kolibri-acpi/core/sys32-sp.inc @@ -1,4 +1,4 @@ ; Éste archivo debe ser editado con codificación CP866 - msg_sel_ker: cp850 "núcleo", 0 - msg_sel_app: cp850 "aplicación", 0 + msg_sel_ker cp850 "núcleo", 0 + msg_sel_app cp850 "aplicación", 0 diff --git a/kernel/branches/Kolibri-acpi/core/sys32.inc b/kernel/branches/Kolibri-acpi/core/sys32.inc index 998b752f9c..7c9853c85b 100644 --- a/kernel/branches/Kolibri-acpi/core/sys32.inc +++ b/kernel/branches/Kolibri-acpi/core/sys32.inc @@ -247,6 +247,83 @@ show_error_parameters: DEBUGF 1, "K : EDX : %x ESI : %x EDI : %x\n", [reg_edx+4], [reg_esi+4], [reg_edi+4] DEBUGF 1, "K : EBP : %x EIP : %x ESP : %x\n", [reg_ebp+4], [reg_eip+4], ebx DEBUGF 1, "K : Flags : %x CS : %x (%s)\n", [reg_eflags+4], eax, edi + + DEBUGF 1, "K : Stack dump:\n" + push eax ebx ecx edx + call .check_ESP + test eax, eax + jnz .error_ESP + DEBUGF 1, "K : [ESP+00]: %x",[ebx] + add ebx, 4 + call .check_ESP + test eax, eax + jnz .error_ESP + DEBUGF 1, " [ESP+04]: %x",[ebx] + add ebx, 4 + call .check_ESP + test eax, eax + jnz .error_ESP + DEBUGF 1, " [ESP+08]: %x\n",[ebx] + add ebx, 4 + call .check_ESP + test eax, eax + jnz .error_ESP + DEBUGF 1, "K : [ESP+12]: %x",[ebx] + add ebx, 4 + call .check_ESP + test eax, eax + jnz .error_ESP + DEBUGF 1, " [ESP+16]: %x",[ebx] + add ebx, 4 + call .check_ESP + test eax, eax + jnz .error_ESP + DEBUGF 1, " [ESP+20]: %x\n",[ebx] + add ebx, 4 + call .check_ESP + test eax, eax + jnz .error_ESP + DEBUGF 1, "K : [ESP+24]: %x",[ebx] + add ebx, 4 + call .check_ESP + test eax, eax + jnz .error_ESP + DEBUGF 1, " [ESP+28]: %x",[ebx] + add ebx, 4 + call .check_ESP + test eax, eax + jnz .error_ESP + DEBUGF 1, " [ESP+32]: %x\n",[ebx] + pop edx ecx ebx eax + ret +.error_ESP: + pop edx ecx ebx eax + DEBUGF 1, "\n" + DEBUGF 1, "K : Unexpected end of the stack\n" + ret +;-------------------------------------- +.check_ESP: + push ebx + shr ebx, 12 + mov ecx, ebx + shr ecx, 10 + mov edx, [master_tab+ecx*4] + test edx, PG_MAP + jz .fail ;page table is not created + ;incorrect address in the program + + mov eax, [page_tabs+ebx*4] + test eax, 2 + jz .fail ;address not reserved for use. error + + pop ebx + xor eax, eax + ret + +.fail: + pop ebx + xor eax, eax + dec eax ret ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= diff --git a/kernel/branches/Kolibri-acpi/core/syscall.inc b/kernel/branches/Kolibri-acpi/core/syscall.inc index 7dd3449e6c..8aa8f61cf3 100644 --- a/kernel/branches/Kolibri-acpi/core/syscall.inc +++ b/kernel/branches/Kolibri-acpi/core/syscall.inc @@ -184,7 +184,7 @@ iglobal dd syscall_threads ; 51-Threads dd undefined_syscall ; 52- deprecated Stack driver status dd undefined_syscall ; 53- deprecated Socket interface - dd undefined_syscall ; 54-reserved + dd sys_clipboard ; 54-Custom clipboard dd sound_interface ; 55-Sound interface dd undefined_syscall ; 56-reserved dd sys_pcibios ; 57-PCI BIOS32 diff --git a/kernel/branches/Kolibri-acpi/core/taskman.inc b/kernel/branches/Kolibri-acpi/core/taskman.inc index c0443b4da9..fcd0fff234 100644 --- a/kernel/branches/Kolibri-acpi/core/taskman.inc +++ b/kernel/branches/Kolibri-acpi/core/taskman.inc @@ -924,10 +924,17 @@ proc write_process_memory ret endp +;ebx = 1 - kernel thread +;ecx=thread entry point +;edx=thread stack pointer +;creation flags 0x01 - debugged +; 0x02 - kernel + align 4 proc new_sys_threads locals slot dd ? + flags dd ? app_cmdline dd ? ;0x00 app_path dd ? ;0x04 app_eip dd ? ;0x08 @@ -935,16 +942,15 @@ proc new_sys_threads app_mem dd ? ;0x10 endl - cmp ebx, 1 - jne .failed ;other subfunctions + shl ebx, 1 + mov [flags], ebx xor eax, eax mov [app_eip], ecx mov [app_cmdline], eax mov [app_esp], edx mov [app_path], eax - ;mov esi,new_process_loading - ;call sys_msg_board_str + call lock_application_table call get_new_process_place @@ -998,10 +1004,8 @@ proc new_sys_threads lea eax, [app_cmdline] stdcall set_app_params , [slot], eax, dword 0, \ - dword 0,dword 0 + dword 0, [flags] - ;mov esi,new_process_running - ;call sys_msg_board_str ;output information about succefull startup mov eax, [process_number] ;set result call unlock_application_table ret @@ -1207,14 +1211,13 @@ proc set_app_params stdcall,slot:dword, params:dword,\ mov [ebx+REG_EIP], eax;app_entry mov [ebx+REG_CS], dword app_code mov ecx, USER_PRIORITY - mov eax, [CURRENT_TASK] - shl eax, 8 ; created by kernel? - cmp [SLOT_BASE+eax+APPDATA.dir_table], sys_pgdir - OS_BASE - jnz @f - cmp [app_path], 0 ; it is a thread? - jnz @f + + test byte [flags], 2 + jz @F + mov [ebx+REG_CS], dword os_code ; kernel thread mov ecx, MAX_PRIORITY + @@: mov [ebx+REG_EFLAGS], dword EFL_IOPL1+EFL_IF @@ -1238,8 +1241,6 @@ proc set_app_params stdcall,slot:dword, params:dword,\ mov [CURRENT_TASK+ebx+TASKDATA.state], dl lea edx, [SLOT_BASE+ebx*8] call scheduler_add_thread - ;mov esi,new_process_running - ;call sys_msg_board_str ;output information about succefull startup ret endp diff --git a/kernel/branches/Kolibri-acpi/data32.inc b/kernel/branches/Kolibri-acpi/data32.inc index ad6d99a64a..485711f3d4 100644 --- a/kernel/branches/Kolibri-acpi/data32.inc +++ b/kernel/branches/Kolibri-acpi/data32.inc @@ -49,48 +49,50 @@ keymap_alt: if lang eq ru - boot_initirq: cp866 'Инициализация IRQ',0 - boot_picinit: cp866 'Инициализация PIC',0 - boot_v86machine: cp866 'Инициализация системы V86 машины',0 - boot_inittimer: cp866 'Инициализация системного таймера (IRQ0)',0 - boot_initapic: cp866 'Попытка инициализации APIC',0 - boot_enableirq: cp866 'Включить прерывания 2, 13',0 - boot_disabling_ide:cp866 'Запрещение прерываний в контроллере IDE',0 - boot_enabling_ide:cp866 'Разрешение прерываний в контроллере IDE',0 - boot_set_int_IDE: cp866 'Установка обработчиков прерываний IDE',0 - boot_detectfloppy:cp866 'Поиск floppy дисководов',0 - boot_detecthdcd: cp866 'Поиск жестких дисков и ATAPI приводов',0 - boot_getcache: cp866 'Получение памяти для кэша',0 - boot_detectpart: cp866 'Поиск разделов на дисковых устройствах',0 - boot_init_sys: cp866 'Инициализация системного каталога /sys',0 - boot_loadlibs: cp866 'Загрузка библиотек (.obj)',0 - boot_memdetect: cp866 'Количество оперативной памяти',' ',' Мб',0 - boot_tss: cp866 'Установка TSSs',0 - boot_cpuid: cp866 'Чтение CPUIDs',0 -; boot_devices: cp866 'Поиск устройств',0 - boot_timer: cp866 'Установка таймера',0 - boot_irqs: cp866 'Переопределение IRQ',0 - boot_setmouse: cp866 'Установка мыши',0 - boot_windefs: cp866 'Установка настроек окон по умолчанию',0 - boot_bgr: cp866 'Установка фона',0 - boot_resirqports: cp866 'Резервирование IRQ и портов',0 - boot_setrports: cp866 'Установка адресов IRQ',0 - boot_setostask: cp866 'Создание процесса ядра',0 - boot_allirqs: cp866 'Открытие всех IRQ',0 - boot_tsc: cp866 'Чтение TSC',0 - boot_cpufreq: cp866 'Частота процессора ',' ',' МГц',0 - boot_pal_ega: cp866 'Установка EGA/CGA 320x200 палитры',0 - boot_pal_vga: cp866 'Установка VGA 640x480 палитры',0 - boot_failed: cp866 'Загрузка первого приложения не удалась',0 - boot_mtrr: cp866 'Установка MTRR',0 + boot_initirq cp866 'Инициализация IRQ',0 + boot_picinit cp866 'Инициализация PIC',0 + boot_v86machine cp866 'Инициализация системы V86 машины',0 + boot_inittimer cp866 'Инициализация системного таймера (IRQ0)',0 + boot_initapic cp866 'Попытка инициализации APIC',0 + boot_enableirq cp866 'Включить прерывания 2, 13',0 + boot_disabling_ide cp866 'Запрещение прерываний в контроллере IDE',0 + boot_enabling_ide cp866 'Разрешение прерываний в контроллере IDE',0 + boot_set_int_IDE cp866 'Установка обработчиков прерываний IDE',0 + boot_detectfloppy cp866 'Поиск floppy дисководов',0 + boot_detecthdcd cp866 'Поиск жестких дисков и ATAPI приводов',0 + boot_getcache cp866 'Получение памяти для кэша',0 + boot_detectpart cp866 'Поиск разделов на дисковых устройствах',0 + boot_init_sys cp866 'Инициализация системного каталога /sys',0 + boot_loadlibs cp866 'Загрузка библиотек (.obj)',0 + boot_memdetect cp866 'Количество оперативной памяти',' ',' Мб',0 + boot_tss cp866 'Установка TSSs',0 + boot_cpuid cp866 'Чтение CPUIDs',0 +; boot_devices cp866 'Поиск устройств',0 + boot_timer cp866 'Установка таймера',0 + boot_irqs cp866 'Переопределение IRQ',0 + boot_setmouse cp866 'Установка мыши',0 + boot_windefs cp866 'Установка настроек окон по умолчанию',0 + boot_bgr cp866 'Установка фона',0 + boot_resirqports cp866 'Резервирование IRQ и портов',0 + boot_setrports cp866 'Установка адресов IRQ',0 + boot_setostask cp866 'Создание процесса ядра',0 + boot_allirqs cp866 'Открытие всех IRQ',0 + boot_tsc cp866 'Чтение TSC',0 + boot_cpufreq cp866 'Частота процессора ',' ',' МГц',0 + boot_pal_ega cp866 'Установка EGA/CGA 320x200 палитры',0 + boot_pal_vga cp866 'Установка VGA 640x480 палитры',0 + boot_failed cp866 'Загрузка первого приложения не удалась',0 + boot_mtrr cp866 'Установка MTRR',0 - boot_APIC_found: cp866 'APIC включен', 0 - boot_APIC_nfound: cp866 'APIC не найден', 0 + boot_APIC_found cp866 'APIC включен', 0 + boot_APIC_nfound cp866 'APIC не найден', 0 if preboot_blogesc - boot_tasking: cp866 'Все готово для запуска, нажмитре ESC для старта',0 + boot_tasking cp866 'Все готово для запуска, нажмитре ESC для старта',0 end if else if lang eq sp include 'data32sp.inc' +else if lang eq et + include 'data32et.inc' else boot_initirq db 'Initialize IRQ',0 boot_picinit db 'Initialize PIC',0 @@ -163,7 +165,7 @@ read_firstapp db '/sys/' firstapp db 'LAUNCHER',0 notifyapp db '@notify',0 if lang eq ru -ud_user_message: cp866 'Ошибка: неподдерживаемая инструкция процессора',0 +ud_user_message cp866 'Ошибка: неподдерживаемая инструкция процессора',0 else if ~ lang eq sp ud_user_message db 'Error: unsupported processor instruction',0 end if @@ -385,7 +387,7 @@ end if REDRAW_BACKGROUND rb 4 align 4 -draw_data: rb 16*256 +draw_data: rb 32*256 BPSLine_calc_area rd 1440 d_width_calc_area rd 1140 diff --git a/kernel/branches/Kolibri-acpi/data32et.inc b/kernel/branches/Kolibri-acpi/data32et.inc new file mode 100644 index 0000000000..ceb3ce3d55 --- /dev/null +++ b/kernel/branches/Kolibri-acpi/data32et.inc @@ -0,0 +1,37 @@ + boot_initirq latin1 'Algväärtustan IRQ',0 + boot_picinit latin1 'Algväärtustan PIC',0 + boot_v86machine latin1 'Algväärtustan süsteemi V86 masinat',0 + boot_inittimer latin1 'Algväärtustan süsteemi taimerit (IRQ0)',0 + boot_initapic latin1 'Proovin Algväärtustada APIC',0 + boot_enableirq latin1 'Luban katkestused 2, 13',0 + boot_disabling_ide latin1 'Keelan IDE kontrolleri katkestused',0 + boot_enabling_ide latin1 'Luban IDE kontrolleri katkestused',0 + boot_set_int_IDE latin1 'Määran IDE kontrolleri halduri',0 + boot_detectfloppy latin1 'Otsin floppi kettaid',0 + boot_detecthdcd latin1 'Otsin kõvakettaid ja ATAPI seadmeid',0 + boot_getcache latin1 'Küsin puhvri mälu',0 + boot_detectpart latin1 'Otsin kettaseadmete partitsioone',0 + boot_init_sys latin1 'Algväärtustan süsteemi kataloogi /sys',0 + boot_loadlibs latin1 'Laadin mooduleid (.obj)',0 + boot_memdetect latin1 'Avastan mälu mahtu',0 + boot_tss latin1 'Määran TSSe',0 + boot_cpuid latin1 'Loen CPUIDd',0 +; boot_devices db 'Detecting devices',0 + boot_setmouse latin1 'Seadistan hiirt',0 + boot_windefs latin1 'Seadistan akende vaikeväärtusi',0 + boot_bgr latin1 'Kalkuleerin tausta',0 + boot_resirqports latin1 'Reserveerin IRQsi ja porte',0 + boot_setostask latin1 'Seadistan OS protsessi',0 + boot_allirqs latin1 'Unmasking IRQs',0 + boot_tsc latin1 'Loen TSC',0 + boot_cpufreq latin1 'CPU sagedus on ',' ',' MHz',0 + boot_pal_ega latin1 'Seadistan EGA/CGA 320x200 paletti',0 + boot_pal_vga latin1 'Seadistan VGA 640x480 paletti',0 + boot_failed latin1 'Esimese programmi käivitamine ebaõnnestus',0 + boot_mtrr latin1 'Määran MTRR',0 + + boot_APIC_found latin1 'APIC aktiveeritud', 0 + boot_APIC_nfound latin1 'APIC ei leitud', 0 +if preboot_blogesc + boot_tasking latin1 'Kõik valmis - vajuta ESC alustamiseks',0 +end if \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/detect/vortex86.inc b/kernel/branches/Kolibri-acpi/detect/vortex86.inc new file mode 100644 index 0000000000..06aa9d3c94 --- /dev/null +++ b/kernel/branches/Kolibri-acpi/detect/vortex86.inc @@ -0,0 +1,92 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; 20/11/2013 yogev_ezra: Initial version ;; +;; Thanks for help to: dunkaist, eAndrew, hidnplayr, Mario ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +$Revision: 4261 $ + +VORTEX86DEBUG = 0 ; For testing in emulators and in non-Vortex86 CPU computers, set this to 1 +VORTEX86DEBUGVALUE = 0x35504d44 ; FAKE port output = used for testing + +; Detect Vortex86 CPU and generate CPU name in string format (PCI address at 93H~90H in Vortex86 North Bridge contains SoC type) +; Available Vortex86 CPU codes taken from Coreboot project. New codes should be added to "Vortex86SoClist" below +; #define DMP_CPUID_SX 0x31504d44 ("DMP1") +; #define DMP_CPUID_DX 0x32504d44 ("DMP2") +; #define DMP_CPUID_MX 0x33504d44 ("DMP3") +; #define DMP_CPUID_DX2 0x34504d44 ("DMP4") +; #define DMP_CPUID_MX_PLUS 0x35504d44 ("DMP5") +; #define DMP_CPUID_EX 0x37504d44 ("DMP7") + +iglobal +Vortex86CPUcode dd ? ; Vortex86 CPU code in HEX format (4 bytes), can be shown as string if converted to ASCII characters +Vortex86CPUid db 0 ; Vortex86 CPU id in integer format (1=Vortex86SX, 2=Vortex86DX, ...) +Vortex86SoCname db 'Vortex86 ',0 ; This variable will hold the full name of Vortex86 SoC +Vortex86SoClist: ; List of Vortex86 CPUs known today. Add new record to this list when new CPU becomes available + db 0x31, 'SX ' ; id=1 + db 0x32, 'DX ' ; id=2 + db 0x33, 'MX ' ; id=3 + db 0x34, 'DX2' ; id=4 + db 0x35, 'MX+' ; id=5 + db 0x37, 'EX ' ; id=6 +Vortex86SoCnum = ($ - Vortex86SoClist) / 4 ; Calculate the total number of known Vortex86 CPUs (if id=Vortex86SoCnum+1 --> unknown SoC) +endg + + mov dx, 0xcf8 ; CF8h = Vortex86 PCI Configuration Address port + mov eax, 0x80000090 ; 0x80000090 = Starting PCI address to read from (32-bit register - accessed as DWORD) + out dx, eax ; Send request to PCI address port to retrieve data from this address + mov dx, 0xcfc ; CFCh = Vortex86 PCI Configuration Data port + in eax, dx ; Read data (SoC type) from PCI data port + +if VORTEX86DEBUG +; // Used for debug purposes: testing in emulator and in non-Vortex86 CPU computers + mov eax, VORTEX86DEBUGVALUE +end if + + DEBUGF 1, "K : Vortex86 SoC register returned 0x" + test eax, eax ; We need to break out in case the result is '\0' since otherwise we will fail at NULL string + jz .nullPCIoutput + mov [Vortex86CPUcode], eax + DEBUGF 1, "%x (%s): ", eax, Vortex86CPUcode + cmp ax, 4d44h ; Check whether it's Vortex86 family (all Vortex86 SoC have ID in form of "0xNN504d44") + jnz .notVortex86 + shr eax, 16 ; Discard lower word in EAX which is always 4d44h in Vortex86 family + cmp al, 50h ; The 3rd byte is always 50h in Vortex86 SoC + jnz .notVortex86 + shr ax, 8 ; Discard 3rd byte in EAX, the highest byte determines the SoC type + mov bl, al ; Copy SoC type to BL since EAX (that contains AL) is used implicitly in "LODSD" command below + mov esi, Vortex86SoClist ; ESI points to the start of Vortex86SoClist (used implicitly in "LODSD" command below) + xor ecx, ecx ; Zero ECX (it is used as counter) + cld ; Clears the DF flag in the EFLAGS register (DF=0 --> String operations increment ESI) +@@: + cmp ecx, Vortex86SoCnum ; Check if we iterated Vortex86SoCnum times already (i.e. went over the entire Vortex86SoClist) + ja .unknownVortex86 ; If the entire list was tested and our CPU is not in that list, it is unknown Vortex86 SoC + inc ecx ; Increment our counter + lodsd ; Load DWORD at address DS:ESI into EAX (puts 1 line from Vortex86SoClist into EAX, then increments ESI) + cmp bl, al ; Check if our CPU matches the current record in the list + jne @b ; No match --> repeat with next record + + shr eax, 8 ; Match found --> drop the SoC type code from Vortex86SoClist name and replace it with \0 + mov dword [Vortex86SoCname+8], eax ; Concatenate it with prefix to receive complete SoC name (\0 is string termination) + mov [Vortex86CPUid], cl ; Save the CPUid (1=Vortex86SX, 2=Vortex86DX, ..., Vortex86SoCnum+1=Unknown Vortex86) + + DEBUGF 1, "%s (id=%d)\n", Vortex86SoCname, [Vortex86CPUid]:1 + jmp .Vortex86end ; Say what we have found (CPU name and id) and exit + +.nullPCIoutput: ; Emulators and non-Vortex86 CPU computers will usually return \0 in this register + DEBUGF 1, "0 (NULL)\n" + jmp .Vortex86end + +.unknownVortex86: + mov [Vortex86CPUid], cl ; Save the CPUid (Vortex86SoCnum+1=Unknown Vortex86) + DEBUGF 1, "unknown Vortex86 CPU (has id=%d, last known is %d)\n", [Vortex86CPUid]:1, Vortex86SoCnum + jmp .Vortex86end + +.notVortex86: ; In case this register is used by other CPUs for other purpose, it's interesting what it contains + DEBUGF 1, "not a Vortex86 CPU\n" + +.Vortex86end: \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/docs/events_subsystem.txt b/kernel/branches/Kolibri-acpi/docs/events_subsystem.txt new file mode 100644 index 0000000000..ffd2f83913 --- /dev/null +++ b/kernel/branches/Kolibri-acpi/docs/events_subsystem.txt @@ -0,0 +1,232 @@ +Дата последней правки 26/07/2013. +Подсистема событий ядра может понадобиться при написании драйверов и сервисов, работающих в режиме ядра. +Она не имеет отношения к подсистеме событий пользовательского интерфейса. +С точки зрения ядра событие - объект ядра и принадлежит создавшему его потоку. + +struc EVENT +{ + .magic dd ? ; 'EVNT' + .destroy dd ? ; internal destructor + .fd dd ? ; next object in list + .bk dd ? ; prev object in list + .pid dd ? ; owner id. идентификатор владельца (потока) + .id dd ? ; event uid. уникальный идентификатор события (просто номерок) + .state dd ? ; internal flags; см. далее. + .code dd ? ; старший байт класс события, ; следующий байт приоритет + ; (будет использоваться только внутри ядра, при чтении всегда 0), + ; Чем больше численное значение двойного слова тем важнее событие. + ; два младших байта код события. + rd 5 ; .data - точная структура этого поля не определена и зависит + ; от поля .code. (Здесь можно передавать какие-то свои данные, + ; при необходимости :) + .size = $ - .magic + .codesize = $ - .code +} + +События реального времени получили класс 0хFF. Пока определёны только: +EVENT.code= ;(Используется в звуковой подсистеме). + RT_INP_EMPTY equ 0xFF000001 + RT_OUT_EMPTY equ 0xFF000002 + RT_INP_FULL equ 0xFF000003 + RT_OUT_FULL equ 0xFF000004 + + +Флаги поля EVENT.state определены в gui/event.inc. + EVENT_SIGNALED equ 0x20000000 ;Бит 29 событие активно/неактивно; + EVENT_WATCHED equ 0x10000000 ;бит 28, поток-владелец ожидает активации события; + MANUAL_RESET equ 0x40000000 ;бит 30, не деактивировать событие автоматически по получении; + MANUAL_DESTROY equ 0x80000000 ;бит 31, не возвращать событие в список свободных по получении. + +На момент ревизии 3732 (и далее по тексту то же) определение находится в \kernel\trunk\const.inc +и выглядит так: + +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 EVENT APPOBJ + id dd ? ;event uid + state dd ? ;internal flags + code dd ? + rd 5 ; .data +ends + +Код находится в gui/event.inc. +Сами события как обьекты существуют в памяти ядра в виде двусвязного списка (см. поля .bk и .fd). +При инициализации ядро резервирует память и создает 512 таких обьектов, помещая их в список FreeEvents +(свободных событий). При нехватке событий (все заняты, а нужно ещё) ядро создает ещё 512 свободных +и т.д. Каждый поток имеет свои (двусвязные) списки (в которые может быть помещено событие): +ObjList - список объектов ядра, ассоциированных с этим потоком; +EventList - список событий ядра для потока. +Сами события, физически, при перемещении между списками и смене очередности в списке не перемещаются +и не копируются. Это происходит только благодаря модификации полей .fd и .bk. Принцип работы списков, +как очередей - FIFO. Использутся неблокирующая отправка и блокирующее получение. Адресация - прямая +(у события всегда есть поток-владелец), по идентификатору потока. + +Жизненый цикл событий определяется флагами при создании. По умолчанию ядро использует значения +MANUAL_RESET = 0 и MANUAL_DESTROY = 0. Такое событие является "одноразовым", и автоматически освобождается +ядром, возвращаясь в список свободных событий после получения. +Событие с флагом MANUAL_DESTROY = 1 после получения переходит в неактивное состояние, но остаётся в списке +объектов потока и может использоваться снова. Событие с флагами MANUAL_DESTROY =1 и MANUAL_RESET = 1 +остаётся активным после получения и может быть сброшено вызовом ClearEvent. + +Пример (вариант) жизненного цикла события из звуковой подсистемы: +Для зукового буфера (их может быть несколько) драйвер создает событие в списке ObjList с помощью +CreateEvent и флагом MANUAL_DESTROY. Далее драйвер вызывает WaitEvent для этого события (ожидает флага +EVENT_SIGNALED в событии) и блокируется, в ожидании запроса на пополнение буфера. Запрос отправляется +с помощью RaiseEvent из другого потока. Отправка (RaiseEvent) и получение (WaitEvent) циклически +повторяются при опустошении буфера. При остановке воспроизведения драйвер деактивирует событие с помощью +ClearEvent. + +Вообще говоря, структура события приведена здесь только лишь для понимания принципов работы подсистемы. +Самостоятельная работа с полями не приветствуется, ввиду возможных в будущем проблем с совместимостью. +Работа должна производится только через API (функции подсистемы), с доступом только к тем полям, доступ к +которым предоставляет функция. При этом пару "указатель на событие" и "уникальный идентификатор события" +следует рассматривать как один 64-х битный уникальный идентификатор. (Если вы вызвали CreateEvent, напимер, +его нужно запомнить где-нибудь [если это нужно] для дальнейшей работы с событием). + +Функции для работы с событиями экспортитуемые ядром: +(для драйверов и т.п.; вызываются в режиме ядра) + + CreateEvent + RaiseEvent + ClearEvent + SendEvent + DestroyEvent + WaitEvent + WaitEventTimeout + GetEvent + Для пользовательских приложений Ф68.14 (GetEvent с обёрткой) + +--------------------------------------------------------------------------------------------- +CreateEvent: + Создаёт новое событие в очереди ObjList текущего потока. + Устанавливает: + EVENT.destroy <= внутренний деструктор по умолчанию; + EVENT.pid <= текущий Process id; + EVENT.id <= уникальный идентификатор; + EVENT.state <= ecx - флаги; + EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword; + Возвращает: + eax - указатель на событие или 0 при ошибке. + edx - Event.id. + Портит: eax,ebx,edx,ecx,esi,edi +--------------------------------------------------------------------------------------------- +RaiseEvent: + Активирует уже существующее событие (может принадлежать другому потоку) установкой + флага EVENT_SIGNALED. Если необходимо, - устанавливает данные EVENT.code. + Если флаг EVENT_SIGNALED в самом событии уже активен - больше ничего не делает. + Если EVENT_SIGNALED не установлен в самом событии, то он будет установлен, кроме случая + {EVENT_WATCHED в edx=1 и EVENT_WATCHED в событии=0}. + Т.е. при установке EVENT_WATCHED в edx, проверяется, ожидает ли поток-владелец активации + события. + Кроме EVENT_SIGNALED в событии никакие другие флаги не модифицируются. + Принимает: + eax - указатель на событие; + ebx - id, уникальный идентификатор события; + edx - флаги для операции (формат EVENT.state); + EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword; + Возвращает: ? + Портит: eax,ebx,edx,ecx,esi,edi . +--------------------------------------------------------------------------------------------- +ClearEvent: + Перемещает событие в список ObjList потока-владельца. (Возможно оно там и находилось.) + Сбрасывает флаги EVENT_SIGNALED, EVENT_WATCHED. С остальными полями (.code, .id), + ничего не делает. + Принимает: + eax - указатель на событие; + ebx - id, уникальный идентификатор события. + Возвращает: ? + Портит: eax,ebx,ecx,edi . +--------------------------------------------------------------------------------------------- +SendEvent: + Создаёт новое событие в списке событий целевого потока. Устанавливает в событии + флаг EVENT_SIGNALED. + Принимает: + EVENT.pid <= eax - pid, идентификатор целевого потока; + EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword; + Возвращает: + eax - указатель на событие или 0 при ошибке. + edx - Event.id. уникальный идентификатор. + Портит: eax,ebx,ecx,esi,edi . +--------------------------------------------------------------------------------------------- +DestroyEvent: + Переносит EVENT в список FreeEvents, чистит поля .magic,.destroy,.pid,.id. + Событие может принадлежать другому потоку. + Принимает: + eax - указатель на событие; + ebx - id, уникальный идентификатор события. + Возвращает: + eax - 0 при ошибке, не 0 при успехе. + Портит: eax,ebx,ecx . +--------------------------------------------------------------------------------------------- +WaitEvent: + Бесконечно ожидает установки флага EVENT_SIGNALED в конкретном событии, принадлежащем + вызывающему WaitEvent потоку. Сигнализирующий поток устанавливат этот флаг через + RaiseEvent. Ожидающий поток замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5. + Перед заморозкой устанавливается флаг EVENT_WATCHED в событии. + Если в полученном событии НЕ установлен MANUAL_RESET, то: + {EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются. + При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent), + а при активном - перемещается в список ObjList текущего слота.} + Принимает: + eax - указатель на событие; + ebx - id, уникальный идентификатор события. + Возвращает: ? + Портит: eax,ebx,edx,ecx,esi,edi . +--------------------------------------------------------------------------------------------- +WaitEventTimeout: + Ожидает с таймаутом установки флага EVENT_SIGNALED в конкретном событии, принадлежащем + вызывающему WaitEventTimeout потоку. Сигнализирующий поток устанавливат этот флаг через + RaiseEvent. Ожидающий поток замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5. + Перед заморозкой устанавливается флаг EVENT_WATCHED в событии. + Если в полученном событии НЕ установлен MANUAL_RESET, то: + {EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются. + При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent), + а при активном - перемещается в список ObjList текущего слота.} + Принимает: + eax - указатель на событие; + ebx - id, уникальный идентификатор события. + ecx - время ожидания в тиках системного таймера. + Возвращает: + eax - 0 - таймаут, если событие не активировалось, или + не 0, если было активировано. + Портит: eax,ebx,edx,ecx,esi,edi . +--------------------------------------------------------------------------------------------- +GetEvent: + Бесконечно ожидает любое событие в очереди событий текущего потока. Поток замораживается + путем перевода TASKDATA.state<=TSTATE_WAITING=5. Данные события (EVENT.code+5*dword) + по получении копируются в указанный буфер. Сбрасывает байт приоритета (см. выше) в буфере. + Если в полученном событии НЕ установлен MANUAL_RESET, то: + {EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются. + При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent), + а при активном - перемещается в список ObjList текущего слота.} + Принимает: + edi - указатель на буфер, куда копировать данные. + Возвращает: + буфер, содержащий следующую информацию: + +0: (EVENT.code) dword: идентификатор последующих данных сигнала + +4: (EVENT.data, поле формально не определено) данные принятого + сигнала (5*dword), формат которых определяется первым dword-ом. + Портит: eax,ebx,edx,ecx,esi,edi . +-------------------------------------------------------------------------------------------- +Ф 68.14 для приложений: ;это тот же GetEvent, но с обёрткой. + Бесконечно ожидает любое событие в очереди событий текущего потока. Ожидающий поток + замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5. Данные события (EVENT.code+5*dword) + копируются в указанный буфер. Сбрасывает байт приоритета (см. выше) в буфере. + Принимает: + eax - 68 - номер функции + ebx - 14 - номер подфункции + ecx - указатель на буфер для информации (размер 6*dword) + Возвращает: + буфер, на который указывает ecx, содержит следующую информацию: + +0: (EVENT.code) dword: идентификатор последующих данных сигнала + +4: (EVENT.data, поле формально не определено) данные принятого + сигнала (5*dword), формат которых определяется первым dword-ом. + Портит: + eax . +--------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/docs/sysfuncr.txt b/kernel/branches/Kolibri-acpi/docs/sysfuncr.txt index fb327e6299..241ddcd883 100644 --- a/kernel/branches/Kolibri-acpi/docs/sysfuncr.txt +++ b/kernel/branches/Kolibri-acpi/docs/sysfuncr.txt @@ -34,7 +34,7 @@ вызов функции с такими Y игнорируется * RR, GG, BB = соответственно красная, зеленая, синяя составляющие цвета рабочей области окна - (игнорируется для стиля Y=2) + (игнорируется для стиля Y=1) * X = DCBA (биты) * A = 1 - у окна есть заголовок; для стилей Y=3,4 адрес строки заголовка задаётся в edi, для прочих стилей @@ -47,7 +47,7 @@ игнорируются для стилей Y=1,3: * esi = 0xXYRRGGBB - цвет заголовка * RR, GG, BB определяют сам цвет - * Y=0 - обычное окно, Y=1 - неперемещаемое окно + * Y=0 - обычное окно, Y=1 - неперемещаемое окно (работает для всех стилей окон) * X определяет градиент заголовка: X=0 - нет градиента, X=8 - обычный градиент, для окон типа II X=4 - негативный градиент @@ -372,6 +372,7 @@ * бит 1 (маска 2): окно минимизировано в панель задач * бит 2 (маска 4): окно свёрнуто в заголовок * +71 = +0x47: dword: маска событий + * +75 = +0x4B: byte: режим ввода с клавиатуры(ASCII = 0; SCAN = 1) Замечания: * Слоты нумеруются с 1. * Возвращаемое значение не есть общее число потоков, поскольку @@ -416,7 +417,7 @@ положение и размеры этого окна полагаются нулями. * Координаты клиентской области окна берутся относительно окна. * В данный момент используется только часть буфера размером - 71 = 0x47 байта. Тем не менее рекомендуется использовать буфер + 76 = 0x4C байта. Тем не менее рекомендуется использовать буфер размером 1 Кб для будущей совместимости, в будущем могут быть добавлены некоторые поля. @@ -1803,7 +1804,7 @@ dd 1675 sysdir_path rb 64 Пример: dir_name1 db 'KolibriOS',0 - rb 64-8 + rb 64-10 dir_path1 db 'HD0/1',0 rb 64-6 Возвращаемое значение: @@ -2027,6 +2028,14 @@ dir_path1 db 'HD0/1',0 * eax = 40 - номер функции * ebx = маска: бит i соответствует событию i+1 (см. список событий) (установленный бит разрешает извещение о событии) + bit 31: фильтр активности событий мыши + bit 31 = 0 - неактивное окно всегда получает события от мыши + bit 31 = 1 - неактивное окно не получает события от мыши + bit 30: фильтр позиции курсора + bit 30 = 0 - окно принимает события мыши, если курсор + за пределами окна + bit 30 = 1 - окно не принимает события мыши, если курсор + за пределами окна Возвращаемое значение: * eax = предыдущее значение маски Замечания: @@ -2419,6 +2428,70 @@ dword-значение цвета 0x00RRGGBB * eax = -1 - ошибка (в системе слишком много потоков) * иначе eax = TID - идентификатор потока +====================================================================== +====================== Функция 54, подфункция 0 ====================== +============== Узнать количество слотов в буфере обмена. ============= +====================================================================== +Параметры: + * eax = 54 - номер функции + * ebx = 0 - номер подфункции +Возвращаемое значение: + * eax = количество слотов в буфере + * eax = -1 - отсутствует область главного списка + +====================================================================== +====================== Функция 54, подфункция 1 ====================== +================== Считать данные из буфера обмена. ================== +====================================================================== +Параметры: + * eax = 54 - номер функции + * ebx = 1 - номер подфункции + * eсx = номер слота +Возвращаемое значение: + * eax = если успешно - указатель на область памяти с данными + * eax = 1 - ошибка + * eax = -1 - отсутствует область главного списка + +====================================================================== +====================== Функция 54, подфункция 2 ====================== +================== Записать данные в буфер обмена. =================== +====================================================================== +Параметры: + * eax = 54 - номер функции + * ebx = 2 - номер подфункции + * eсx = количество копируемых байт + * edx = указатель на буфер под копируемые данные +Возвращаемое значение: + * eax = 0 - успешно + * eax = 1 - ошибка + * eax = -1 - отсутствует область главного списка + +====================================================================== +====================== Функция 54, подфункция 3 ====================== +========= Удалить последний слот с данными в буфере обмена =========== +====================================================================== +Параметры: + * eax = 54 - номер функции + * ebx = 3 - номер подфункции +Возвращаемое значение: + * eax = 0 - успешно + * eax = 1 - ошибка + * eax = -1 - отсутствует область главного списка + +====================================================================== +====================== Функция 54, подфункция 4 ====================== +=================== Аварийный сброс блокировки буфера ================ +====================================================================== +Параметры: + * eax = 54 - номер функции + * ebx = 4 - номер подфункции +Возвращаемое значение: + * eax = 0 - успешно + * eax = -1 - отсутствует область главного списка или нет блокировки +Замечания: + * Используется в исключительных случаях, когда зависшее или убитое + приложение заблокировало работу с буфером обмена. + ====================================================================== ====================== Функция 55, подфункция 55 ===================== ========== Начать проигрывать данные на встроенном спикере. ========== @@ -3494,6 +3567,32 @@ Architecture Software Developer's Manual, Volume 3, Appendix B); обработчика исключений, установленного подфункцией 24. При этом номер сигнала соответствует номеру исключения. +====================================================================== += Функция 68, подфункция 26 - освободить страницы памяти ============ +====================================================================== +Параметры: + * eax = 68 - номер функции + * ebx = 26 - номер подфункции + * ecx = указатель на блок памяти выделенный подфункцией 12 + * edx = смещение от начала блока + * esi = размер высвобождаемого блока памяти, в байтах +Примечания: + * функция освобождает страницы с ecx+edx по ecx+edx+esi + и устанавливает виртуальную память в зарезервированное состояние. + +====================================================================== += Функция 68, подфункция 27 - загрузить файл =================== +====================================================================== +Параметры: + * eax = 68 - номер функции + * ebx = 27 - номер подфункции + * ecx = указатель на ASCIIZ-строку с именем файла +Возвращаемое значение: + * eax = указатель на загруженный файл или 0 + * edx = размер загруженного файла или 0 +Примечания: + * функция загружает и, при необходимости, распаковывает файл (kunpack) + ====================================================================== ======================== Функция 69 - отладка. ======================= ====================================================================== diff --git a/kernel/branches/Kolibri-acpi/docs/sysfuncs.txt b/kernel/branches/Kolibri-acpi/docs/sysfuncs.txt index 1e223844ef..6eae185b2c 100644 --- a/kernel/branches/Kolibri-acpi/docs/sysfuncs.txt +++ b/kernel/branches/Kolibri-acpi/docs/sysfuncs.txt @@ -33,7 +33,7 @@ Parameters: * other possible values (from 5 up to 15) are reserved, function call with such Y is ignored * RR, GG, BB = accordingly red, green, blue components of a color - of the working area of the window (are ignored for style Y=2) + of the working area of the window (are ignored for style Y=1) * X = DCBA (bits) * A = 1 - window has caption; for styles Y=3,4 caption string must be passed in edi, for other styles use @@ -46,7 +46,7 @@ Parameters: of a type I and II, and ignored for styles Y=1,3: * esi = 0xXYRRGGBB - color of the header * RR, GG, BB define color - * Y=0 - usual window, Y=1 - unmovable window + * Y=0 - usual window, Y=1 - unmovable window (works for all window styles) * X defines a gradient of header: X=0 - no gradient, X=8 - usual gradient, for windows of a type II X=4 - negative gradient @@ -367,6 +367,7 @@ Returned value: * bit 1 (mask 2): window is minimized to panel * bit 2 (mask 4): window is rolled up * +71 = +0x47: dword: event mask + * +75 = +0x4B: byte: keyboard mode(ASCII = 0; SCAN = 1) Remarks: * Slots are numbered starting from 1. * Returned value is not a total number of threads, because there @@ -411,7 +412,7 @@ Remarks: of its window are considered to be zero. * Coordinates of the client area are relative to the window. * At the moment only the part of the buffer by a size - 71 = 0x37 bytes is used. Nevertheless it is recommended to use + 76 = 0x4C bytes is used. Nevertheless it is recommended to use 1-Kb buffer for the future compatibility, in the future some fields can be added. @@ -1566,26 +1567,26 @@ Returned value: Remarks: * The function is supported only for ATAPI devices (CD and DVD). * An example of usage of the function is the application CD_tray. - -====================================================================== -======= Function 25 - put image area on the background layer. ======== -====================================================================== -Paramters: - * eax = 25 - function number - * ebx = pointer to the previously allocated memory area, - where placed the source images in a format BBGGRRTTBBGGRRTT... - * ecx = [size on axis x]*65536 + [size on axis y] - * edx = [coordinate on axis x]*65536 + [coordinate on axis y] -Returned value: - * function does not return value -Remarks: - * Coordinates of the image are coordinates of the upper left corner - of the image relative to the screen. - * Size of the image in bytes is 4*xsize*ysize - * TT - byte pointer of transparency, at current version: - 1 to FF - opaque, 0 - transparent. - * The function places the image directly to LFB. It is not for - background image f.15. Options f.15 to f.25 does not make sense. + +====================================================================== +======= Function 25 - put image area on the background layer. ======== +====================================================================== +Paramters: + * eax = 25 - function number + * ebx = pointer to the previously allocated memory area, + where placed the source images in a format BBGGRRTTBBGGRRTT... + * ecx = [size on axis x]*65536 + [size on axis y] + * edx = [coordinate on axis x]*65536 + [coordinate on axis y] +Returned value: + * function does not return value +Remarks: + * Coordinates of the image are coordinates of the upper left corner + of the image relative to the screen. + * Size of the image in bytes is 4*xsize*ysize + * TT - byte pointer of transparency, at current version: + 1 to FF - opaque, 0 - transparent. + * The function places the image directly to LFB. It is not for + background image f.15. Options f.15 to f.25 does not make sense. ====================================================================== ======== Function 26, subfunction 1 - get MPU MIDI base port. ======== @@ -1785,7 +1786,7 @@ Parameters: sysdir_path rb 64 For example: dir_name1 db 'KolibriOS',0 - rb 64-8 + rb 64-10 dir_path1 db 'HD0/1',0 rb 64-6 Returned value: @@ -2010,7 +2011,7 @@ Parameters: * eax = 40 - function number * ebx = mask: bit i corresponds to event i+1 (see list of events) (set bit permits notice on event) - bit 31: active/inactive filter + bit 31: mouse active/inactive filter bit 31 = 0 - inactive window receive mouse events bit 31 = 1 - inactive window does not receive mouse events bit 30: cursor position filter @@ -2410,6 +2411,70 @@ Returned value: * otherwise eax = TID - thread identifier +====================================================================== +==================== Function 54, subfunction 0 ====================== +============== Get the number of slots in the clipboard. ============= +====================================================================== +Parameters: + * eax = 54 - function number + * ebx = 0 - subfunction number +Returned value: + * eax = slots in the clipboard + * eax = -1 - main list area not found + +====================================================================== +==================== Function 54, subfunction 1 ====================== +================= Read the data from the clipboard. ================== +====================================================================== +Parameters: + * eax = 54 - function number + * ebx = 1 - subfunction number + * eсx = slot number +Returned value: + * eax = if successful - pointer to a memory with data + * eax = 1 - error + * eax = -1 - main list area not found + +====================================================================== +==================== Function 54, subfunction 2 ====================== +================= Write the data to the clipboard. =================== +====================================================================== +Parameters: + * eax = 54 - function number + * ebx = 2 - subfunction number + * eсx = the number of bytes to be copied + * edx = a pointer to a buffer for data to be copied +Returned value: + * eax = 0 - success + * eax = 1 - error + * eax = -1 - main list area not found + +====================================================================== +===================== Function 54, subfunction 3 ===================== +================ Delete the last slot in the clipboard =============== +====================================================================== +Parameters: + * eax = 54 - function number + * ebx = 3 - subfunction number +Returned value: + * eax = 0 - success + * eax = 1 - error + * eax = -1 - main list area not found + +====================================================================== +===================== Function 54, subfunction 4 ===================== +===================== Alarm reset the lock buffer ==================== +====================================================================== +Parameters: + * eax = 54 - function number + * ebx = 4 - subfunction number +Returned value: + * eax = 0 - success + * eax = -1 - main list area not found or no blocking +Remarks: + * Used in exceptional cases, where no responsible or killed + application blocked the clipboard operations. + ====================================================================== Function 55, subfunction 55 - begin to play data on built-in speaker. ====================================================================== @@ -3953,7 +4018,7 @@ Format of the information structure: * +0: dword: 2 = subfunction number * +4: dword: 0 (reserved) * +8: dword: 0 (reserved) - * +12 = +0xC: dword: number of bytes to read + * +12 = +0xC: dword: number of bytes to write * +16 = +0x10: dword: pointer to data * +20 = +0x14: ASCIIZ-name of file, the rules of names forming are given in the general description diff --git a/kernel/branches/Kolibri-acpi/docs/usbapi_ru.txt b/kernel/branches/Kolibri-acpi/docs/usbapi_ru.txt new file mode 100644 index 0000000000..cf89079d4e --- /dev/null +++ b/kernel/branches/Kolibri-acpi/docs/usbapi_ru.txt @@ -0,0 +1,249 @@ +Когда ядро ​​обнаруживает подключенное устройство USB, оно настраивает его +согласно USB-протокола - SET_ADDRESS + SET_CONFIGURATION. Всегда +устанавливается первая конфигурация. Ядро также читает дескриптор +устройства, чтобы показать некоторую информацию, читает и анализирует +дескриптор конфигурации. Для каждого интерфейса ядро будет искать класс этого +интерфейса и попытается загрузить соответствующий драйвер COFF. В настоящее +время соответствие кодов классов и имен драйверов жестко прописано в коде ядра +и выглядит следующим образом: +3 = usbhid.obj, +7 = usbprint.obj, +8 = usbstor.obj, +9 = поддерживаются самим ядром, +другие = usbother.obj. + +Драйвер должен быть стандартным драйвером в формате COFF, экспортирующим +процедуру под названием "START" и переменную "version". Загрузчик вызывает +процедуру "START" как STDCALL с одним параметром DRV_ENTRY = 1. При завершении +работы системы, если инициализация драйвера была успешна, "START" процедуру +также вызывает код остановки системы с одним параметром DRV_EXIT = -1. + +Драйвер должен зарегистрировать себя в качестве драйвера USB в процедуре +"START". Это делается путем вызова экспортируемой ядром функции RegUSBDriver и +возврата её результата в качестве результата "START" процедуры. + +void* __stdcall RegUSBDriver( + const char* name, + void* handler, + const USBFUNC* usbfunc +); + +Параметр 'name' должен совпадать с именем драйвера, например "usbhid" для +usbhid.obj. + +Параметр 'handler' является необязательным. Если он не NULL, то он должен +указывать на стандартный обработчик IOCTL интерфейса, как в обычном (не-USB) +драйвере. + +Параметр "Usbfunc" представляет собой указатель на следующую структуру: + +struc USBFUNC +{ + .strucsize dd ? ; размер структуры, включая это поле + .add_device dd ? ; указатель на AddDevice процедуру в драйвере + ; (необходимо) + .device_disconnect dd ? ; указатель на DeviceDisconnected процедуру в драйвере + ; опционально, может быть NULL +; В будущем могут быть добавлены другие функции +} + +Драйвер ДОЛЖЕН реализовать функцию: + +void* __stdcall AddDevice( + void* pipe0, + void* configdescr, + void* interfacedescr +); + +Параметр "Pipe0" - хэндл контрольного канала для нулевой конечной точки +устройства. Он может быть использован в качестве аргумента для +USBControlTransferAsync (см. далее). + +Параметр 'configdescr' указывает на дескриптор конфигурации и все связанные с +ним данные, представленные так, как их возвращает запрос GET_DESCRIPTOR. +Полный размер данных содержится в поле Length самого дескриптора. +(см. USB2.0 spec.) + +Параметр 'interfacedescr' указывает на дескриптор интерфейса инициализируемого +в данный момент. Это указатель на данные находящиеся внутри структуры +"configdescr". (Помним, что структура INTERFACE_DESCRIPTOR, находится внутри +структуры CONFIGURATION_DESCRIPTOR. См. USB2.0 Spec.) Обратите внимание, что +одно устройство может реализовывать много интерфейсов и AddDevice может быть +вызвана несколько раз с одним "configdescr" но разными "interfacedescr". + +Возвращенное значение NULL показывает, что инициализация не была успешной. +Любое другое значение означает инициализацию устройства. Ядро не делает попыток +как-то интерпретировать это значение. Это может быть, например, указатель на +внутренние данные драйвера в памяти, выделенной с помощью Kmalloc или индексом +в какой-то своей таблице. (Помните, что Kmalloc() НЕ stdcall-функция! Она +портит регистр ebx!) + +Драйвер МОЖЕТ реализовать функцию: + +void __stdcall DeviceDisconnected( + void* devicedata +); + +Если данная функция реализована, то ядро вызывает её, когда устройство +отключено, посылая ей в качестве параметра "devicedata" то, что было возвращено +ему функцией "AddDevice" при старте драйвера. + +Драйвер может использовать следующие функции экспортируемые ядром: + +void* __stdcall USBOpenPipe( + void* pipe0, + int endpoint, + int maxpacketsize, + int type, + int interval +); + +Параметр "Pipe0" - хэндл контрольного канала для нулевой конечной точки +устройства. Используется для идентификации устройства. + +Параметр "endpoint" номер конечной точки USB. Младшие 4 бита, собственно, номер +точки, а бит 7 имеет следующее значение: 0 - для OUT точки, 1 - для IN точки. +Остальные биты должны быть равны нулю. + +Параметр "maxpacketsize" устанавливает максимальный размер пакета для канала. + +Параметр "type" устанавливает тип передачи для конечной точки, как это прописано +в USB спецификации: + +0 = control, +1 = isochronous (сейчас не поддерживается), +2 = bulk, +3 = interrupt. + +Параметр "interval" игнорируется для control и bulk передач. Для конечных точек +по прерываниям устанавливает периодичность опроса в миллисекундах. + +Функция возвращает хэндл канала при успешном его открытии либо NULL при ошибке. +Хэндл канала обращается в NULL когда: +а) канал будет явно закрыт функцией USBClosePipe (см. ниже); +б) была выполнена предоставленная драйвером функция "DeviceDisconnected". + +void __stdcall USBClosePipe( + void* pipe +); + +Освобождает все ресурсы, связанные с выбранным каналом. Единственный параметр - +указатель на хэндл, который был возвращен функцией USBOpenPipe при открытии +канала. Когда устройство отключается, все связанные с ним каналы закрываются +ядром; нет необходимости в самостоятельном вызове этой функции. + +void* __stdcall USBNormalTransferAsync( + void* pipe, + void* buffer, + int size, + void* callback, + void* calldata, + int flags +); +void* __stdcall USBControlTransferAsync( + void* pipe, + void* setup, + void* buffer, + int size, + void* callback, + void* calldata, + int flags +); + +Первая функция ставит в очередь bulk или interrupt передачу для выбранного +канала. Тип и направление передачи фиксированы для bulk и interrupt типов +конечных точек, как это было выбрано функцией USBOpenPipe. +Вторая функция ставит в очередь control передачу для выбранного канала. +Направление этой передачи определяется битом 7 байта 0 пакета "setup" +(0 - для OUT, 1 - для IN передачи). Эта функция возвращает управление немедленно. +По окончании передачи вызывается функция "callback" заданная как аргумент +USB______TransferAsync. + +Параметр "pipe" - хэндл, возвращенный функцией USBOpenPipe. + +Параметр 'setup' функции USBControlTransferAsync указывает на 8-байтный +конфигурационный пакет (см. USB2.0 Spec). + +Параметр "buffer" - это указатель на буфер. Для IN передач он будет заполнен +принятыми данными. Для OUT передач он должен быть заполнен данными, которые мы +хотим передать. Указатель может быть NULL для пустых передач, либо для передач +control, если дополнительных данных не требуется. + +Параметр "size" - это размер данных для передачи. Он может быть равен 0 для +пустых передач, либо для передач control, если дополнительных данных не требуется. + +Параметр "callback" - это указатель на функцию, которая будет вызвана по +окончании передачи. + +Параметр "calldata" будет передан функции "callback" вызываемой по окончании +передачи. Например, он может быть NULL или указывать на данные устройства или +указывать на данные используемые как дополнительные параметры, передаваемые от +вызывающей USB_____TransferAsync функции в callback функцию. + +Другие данные, связанные с передачей, могут быть помещены до буфера (по смещению) +или после него. Они могут быть использованы из callback-функции, при необходимости. + +Параметр "flags" - это битовое поле. Бит 0 игнорируется для OUT передач. Для IN +передач он означает, может ли устройство передать меньше данных (бит=1), чем +определено в "size" или нет (бит=0). Остальные биты не используются и должны +быть равны 0. + +Возвращаемое функциями значение равно NULL в случае ошибки и не NULL если +передача успешно поставлена в очередь. Если происходит ошибка при передаче, то +callback функция будет об этом оповещена. + +void __stdcall CallbackFunction( + void* pipe, + int status, + void* buffer, + int length, + void* calldata +); + +Параметры 'pipe', 'buffer', 'calldata' значат то же, что и для +USB_____TransferAsync. + +Параметр "length" это счетчик переданных байт. Для control передач он отражает +дополнительные 8 байт этапа SETUP. Т.е. 0 означает ошибку на этапе SETUP, а +"size"+8 успешную передачу. + +Параметр "status" не равен 0 в случае ошибки: +USB_STATUS_OK = 0 ; без ошибок +USB_STATUS_CRC = 1 ; ошибка контрольной суммы +USB_STATUS_BITSTUFF = 2 ; ошибка инверсии битов (bitstuffing) +USB_STATUS_TOGGLE = 3 ; data toggle mismatch + ; (Нарушение последовательности DAT0/DAT1) +USB_STATUS_STALL = 4 ; устройство возвратило STALL статус (остановлено) +USB_STATUS_NORESPONSE = 5 ; устройство не отвечает +USB_STATUS_PIDCHECK = 6 ; ошибка в поле PacketID (PID) +USB_STATUS_WRONGPID = 7 ; неожидаемое PacketID (PID) значение +USB_STATUS_OVERRUN = 8 ; слишком много данных от конечной точки +USB_STATUS_UNDERRUN = 9 ; слишком мало данных от конечной точки +USB_STATUS_BUFOVERRUN = 12 ; переполнение внутреннего буфера контроллера + ; возможна только для изохронных передач +USB_STATUS_BUFUNDERRUN = 13 ; опустошение внутреннего буфера контроллера + ; возможна только для изохронных передач +USB_STATUS_CLOSED = 16 ; канал закрыт либо через ClosePipe, либо в + ; результате отключения устройства + +Если несколько передач были поставлены в очередь для одного канала, то callback +функции для них будут вызываться в порядке постановки передач в очередь. +Если канал был закрыт ввиду USBClosePipe или отключения устройства, то callback +функции (если очередь передач не пуста) получат USB_STATUS_CLOSED. +Вызов DeviceDisconnected() последует после отработки всех оставшихся в очереди +callback функций. + +void* __stdcall USBGetParam(void* pipe0, int param); + +Возвращает указатель на некоторые параметры устройства запомненные ядром при +инициализации первой конфигурации. Не передает ничего устройству по шине. + +pipe0 - хэндл контрольного канала для нулевой конечной точки устройства. + +param - выбор возвращаемого параметра: +0 - возвратить указатель на дескриптор устройства; +1 - возвратить указатель на дескриптор конфигурации; +2 - возвратить режим шины устройства: + USB_SPEED_FS = 0 ; full-speed + USB_SPEED_LS = 1 ; low-speed + USB_SPEED_HS = 2 ; high-speed \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/drivers/imports.inc b/kernel/branches/Kolibri-acpi/drivers/imports.inc index 870aa8a95c..d1b17fc484 100644 --- a/kernel/branches/Kolibri-acpi/drivers/imports.inc +++ b/kernel/branches/Kolibri-acpi/drivers/imports.inc @@ -60,6 +60,7 @@ kernel_export \ CreateRingBuffer,\ \ GetPid,\ + CreateThread,\ CreateObject,\ DestroyObject,\ CreateEvent,\ diff --git a/kernel/branches/Kolibri-acpi/drivers/usbstor.asm b/kernel/branches/Kolibri-acpi/drivers/usbstor.asm index f82307be11..f9d3ec3529 100644 --- a/kernel/branches/Kolibri-acpi/drivers/usbstor.asm +++ b/kernel/branches/Kolibri-acpi/drivers/usbstor.asm @@ -1002,13 +1002,12 @@ proc inquiry_callback ; to allow the USB thread to continue working and handling those requests. ; 4. Thus, create a temporary kernel thread which would do it. mov edx, [esp+8] - push ebx ecx - movi eax, 51 + push ebx ecx esi edi movi ebx, 1 mov ecx, new_disk_thread ; edx = parameter - int 0x40 - pop ecx ebx + call CreateThread + pop edi esi ecx ebx cmp eax, -1 jnz .nothing ; on error, reverse step 3 diff --git a/kernel/branches/Kolibri-acpi/encoding.inc b/kernel/branches/Kolibri-acpi/encoding.inc index cdf1e13f26..c492d6af86 100644 --- a/kernel/branches/Kolibri-acpi/encoding.inc +++ b/kernel/branches/Kolibri-acpi/encoding.inc @@ -97,6 +97,12 @@ macro cp866 [arg] end while } +struc cp866 [arg] +{ +common + cp866 arg +} + ; Latin-1 encoding ; 0x00-0xFF - trivial map macro latin1 [arg] @@ -117,6 +123,12 @@ macro latin1 [arg] end while } +struc latin1 [arg] +{ +common + latin1 arg +} + ; CP850 encoding macro cp850 [arg] { local offs, char, graph @@ -147,3 +159,9 @@ macro cp850 [arg] end if end while } + +struc cp850 [arg] +{ +common + cp850 arg +} diff --git a/kernel/branches/Kolibri-acpi/fs/ext2.inc b/kernel/branches/Kolibri-acpi/fs/ext2.inc deleted file mode 100644 index ca88c754e2..0000000000 --- a/kernel/branches/Kolibri-acpi/fs/ext2.inc +++ /dev/null @@ -1,1343 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; 02.02.2010 turbanoff - support 70.5 ;; -;; 23.01.2010 turbanoff - support 70.0 70.1 ;; -;; 21.06.2013 yogev_ezra - Translate Russian comments ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - -EXT2_BAD_INO = 1 -EXT2_ROOT_INO = 2 -EXT2_ACL_IDX_INO = 3 -EXT2_ACL_DATA_INO = 4 -EXT2_BOOT_LOADER_INO = 5 -EXT2_UNDEL_DIR_INO = 6 - -;RUS: флаги, указываемые в inode файла ;ENG: flags specified in file inode -EXT2_S_IFREG = 0x8000 -EXT2_S_IFDIR = 0x4000 -EXT2_S_IFMT = 0xF000 ;RUS: маска для типа файла ;ENG: mask for file type - -;RUS: флаги, указываемые в linked list родительской папки -;ENG: flags specified in linked list of parent folder -EXT2_FT_REG_FILE = 1 ;RUS: это файл, запись в родительском каталоге - ;ENG: this is a file, record in parent catalog -EXT2_FT_DIR = 2 ;RUS: это папка ;ENG: this is a folder - -;RUS: флаги используемые KolibriOS ;ENG: flags used by KolibriOS -FS_FT_HIDDEN = 2 -FS_FT_DIR = 0x10 ;RUS: это папка ;ENG: this is a folder -FS_FT_ASCII = 0 ;RUS: имя в ascii ;ENG: name in ASCII -FS_FT_UNICODE = 1 ;RUS: имя в unicode ;ENG: name in UNICODE - -EXT2_FEATURE_INCOMPAT_FILETYPE = 0x0002 ;RUS: тип файла должен указываться в директории - ;ENG: file type must be specified in the folder -EXT4_FEATURE_INCOMPAT_EXTENTS = 0x0040 ;RUS: экстенты ;ENG: extents -EXT4_FEATURE_INCOMPAT_FLEX_BG = 0x0200 ;RUS: гибкие группы блоков ;ENG: flexible block groups - -;RUS: реализованные ext[234] features ;ENG: implemented ext[234] features -EXT4_FEATURE_INCOMPAT_SUPP = EXT2_FEATURE_INCOMPAT_FILETYPE \ - or EXT4_FEATURE_INCOMPAT_EXTENTS \ - or EXT4_FEATURE_INCOMPAT_FLEX_BG - -;RUS: флаги, указываемые для inode в i_flags ;ENG: flags specified for inode in i_flags -EXT2_EXTENTS_FL = 0x00080000 - -struct EXT2_INODE_STRUC - i_mode dw ? - i_uid dw ? - i_size dd ? - i_atime dd ? - i_ctime dd ? - i_mtime dd ? - i_dtime dd ? - i_gid dw ? - i_links_count dw ? - i_blocks dd ? - i_flags dd ? - i_osd1 dd ? - i_block rd 15 - i_generation dd ? - i_file_acl dd ? - i_dir_acl dd ? - i_faddr dd ? - i_osd2 dd ? ; 1..12 -ends - -struct EXT2_DIR_STRUC - inode dd ? - rec_len dw ? - name_len db ? - file_type db ? - name db ? ; 0..255 -ends - -struct EXT2_BLOCK_GROUP_DESC - block_bitmap dd ? ;+0 - inode_bitmap dd ? ;+4 - inode_table dd ? ;+8 - free_blocks_count dw ? ;+12 - free_inodes_count dw ? ;+14 - used_dirs_count dw ? ;+16 - pad dw ? ;+18 - reserved rb 12;+20 -ends - -struct EXT2_SB_STRUC - inodes_count dd ? ;+0 - blocks_count dd ? ;+4 - r_block_count dd ? ;+8 - free_block_count dd ? ;+12 - free_inodes_count dd ? ;+16 - first_data_block dd ? ;+20 - log_block_size dd ? ;+24 - log_frag_size dd ? ;+28 - blocks_per_group dd ? ;+32 - frags_per_group dd ? ;+36 - inodes_per_group dd ? ;+40 - mtime dd ? ;+44 - wtime dd ? ;+48 - mnt_count dw ? ;+52 - max_mnt_count dw ? ;+54 - magic dw ? ;+56 - state dw ? ;+58 - errors dw ? ;+60 - minor_rev_level dw ? ;+62 - lastcheck dd ? ;+64 - check_intervals dd ? ;+68 - creator_os dd ? ;+72 - rev_level dd ? ;+76 - def_resuid dw ? ;+80 - def_resgid dw ? ;+82 - first_ino dd ? ;+84 - inode_size dw ? ;+88 - block_group_nr dw ? ;+90 - feature_compat dd ? ;+92 - feature_incompat dd ? ;+96 - feature_ro_compat dd ? ;+100 - uuid rb 16 ;+104 - volume_name rb 16 ;+120 - last_mounted rb 64 ;+136 - algo_bitmap dd ? ;+200 - prealloc_blocks db ? ;+204 - preallock_dir_blocks db ? ;+205 - reserved_gdt_blocks dw ? ;+206 - journal_uuid rb 16 ;+208 - journal_inum dd ? ;+224 - journal_dev dd ? ;+228 - last_orphan dd ? ;+232 - hash_seed rd 4 ;+236 - def_hash_version db ? ;+252 - rb 3 ;+253 reserved - default_mount_options dd ? ;+256 - first_meta_bg dd ? ;+260 - mkfs_time dd ? ;+264 - jnl_blocks rd 17 ;+268 - blocks_count_hi dd ? ;+336 - r_blocks_count_hi dd ? ;+340 - free_blocks_count_hi dd ? ;+344 - min_extra_isize dw ? ;+348 - want_extra_isize dw ? ;+350 - flags dd ? ;+352 - raid_stride dw ? ;+356 - mmp_interval dw ? ;+358 - mmp_block dq ? ;+360 - raid_stripe_width dd ? ;+368 - log_groups_per_flex db ? ;+372 -ends - -struct EXT4_EXTENT_HEADER ;RUS: заголовок блока экстентов/индексов - eh_magic dw ? ;RUS: в текущей реализации ext4 должно быть 0xF30A - eh_entries dw ? ;RUS: количество экстентов/индексов в блоке - eh_max dw ? ;RUS: max количество (используется при записи) - eh_depth dw ? ;RUS: глубина дерева (0, если это блок экстентов) - eh_generation dd ? ;??? -ends - -struct EXT4_EXTENT ;RUS: экстент ;ENG: extent - ee_block dd ? ;RUS: номер ext4 блока ;ENG: number of ext4 block - ee_len dw ? ;RUS: длина экстента ;ENG: extent length - ee_start_hi dw ? ;RUS: старшие 16 бит 48-битного адреса (пока не используются в KOS) - ;ENG: upper 16 bits of the 48-bit address (not used in KolibriOS yet) - ee_start_lo dd ? ;RUS: младшие 32 бита 48-битного адреса - ;ENG: lower 32 bits of the 48-bit address -ends - -struct EXT4_EXTENT_IDX ;RUS: индекс - указатель на блок с экстентами/индексами - ;ENG: index - pointer to block of extents/indexes - ei_block dd ? ;RUS: номер ext4 блока ;ENG: number of ext4 block - ei_leaf_lo dd ? ;RUS: младшие 32 бит 48-битного адреса - ;ENG: lower 32 bits of the 48-bit address - ei_leaf_hi dw ? ;RUS: старшие 16 бит 48-битного адреса (пока не используются в KOS) - ;ENG: upper 16 bits of the 48-bit address (not used in KolibriOS yet) - ei_unused dw ? ;RUS: зарезервировано ;ENG: reserved -ends - -struct EXTFS PARTITION - Lock MUTEX - log_block_size dd ? - block_size dd ? - count_block_in_block dd ? - blocks_per_group dd ? - global_desc_table dd ? - root_inode dd ? ; pointer to root inode in memory - inode_size dd ? - count_pointer_in_block dd ? ; block_size / 4 - count_pointer_in_block_square dd ? ; (block_size / 4)**2 - ext2_save_block dd ? ;RUS: блок на глобальную 1 процедуру ;ENG: block for 1 global procedure - ext2_temp_block dd ? ;RUS: блок для мелких процедур ;ENG: block for small procedures - ext2_save_inode dd ? ;RUS: inode на глобальную процедуру ;ENG: inode for global procedure - ext2_temp_inode dd ? ;RUS: inode для мелких процедур ;ENG: inode for small procedures - groups_count dd ? - superblock rd 512/4 -ends - -iglobal -align 4 -ext2_user_functions: - dd ext2_free - dd (ext2_user_functions_end - ext2_user_functions - 4) / 4 - dd ext2_Read - dd ext2_ReadFolder - dd ext2_Rewrite - dd ext2_Write - dd ext2_SetFileEnd - dd ext2_GetFileInfo - dd ext2_SetFileInfo - dd 0 - dd ext2_Delete - dd ext2_CreateFolder -ext2_user_functions_end: -endg - -proc ext2_create_partition - push ebx - - mov eax, 2 ;superblock start at 1024b - add ebx, 512 ; get pointer to fs-specific buffer - call fs_read32_sys - - cmp [ebx + EXT2_SB_STRUC.log_block_size], 3 ;0,1,2,3 - ja .no - cmp [ebx + EXT2_SB_STRUC.magic], 0xEF53 - jne .no - cmp [ebx + EXT2_SB_STRUC.state], 1 ;EXT_VALID_FS=1 - jne .no - cmp [ebx + EXT2_SB_STRUC.inodes_per_group], 0 - je .no - - mov eax, [ebx + EXT2_SB_STRUC.feature_incompat] - test eax, EXT2_FEATURE_INCOMPAT_FILETYPE - jz .no - test eax, not EXT4_FEATURE_INCOMPAT_SUPP - jz ext2_setup - - .no: - ; No, this superblock isn't EXT2 - pop ebx - xor eax, eax - ret - - ; OK, this is correct EXT2 superblock -ext2_setup: - movi eax, sizeof.EXTFS - call malloc - test eax, eax - jz ext2_create_partition.no - - mov ecx, dword [ebp+PARTITION.FirstSector] - mov dword [eax+EXTFS.FirstSector], ecx - mov ecx, dword [ebp+PARTITION.FirstSector+4] - mov dword [eax+EXTFS.FirstSector+4], ecx - mov ecx, dword [ebp+PARTITION.Length] - mov dword [eax+EXTFS.Length], ecx - mov ecx, dword [ebp+PARTITION.Length+4] - mov dword [eax+EXTFS.Length+4], ecx - mov ecx, [ebp+PARTITION.Disk] - mov [eax+EXTFS.Disk], ecx - mov [eax+EXTFS.FSUserFunctions], ext2_user_functions - push ebp esi edi - mov ebp, eax - lea ecx, [eax+EXTFS.Lock] - call mutex_init - - mov esi, ebx - lea edi, [ebp+EXTFS.superblock] - mov ecx, 512/4 - rep movsd ; copy sb to reserved mem - - mov eax, [ebx + EXT2_SB_STRUC.blocks_count] - sub eax, [ebx + EXT2_SB_STRUC.first_data_block] - dec eax - xor edx, edx - div [ebx + EXT2_SB_STRUC.blocks_per_group] - inc eax - mov [ebp+EXTFS.groups_count], eax - - mov ecx, [ebx + EXT2_SB_STRUC.log_block_size] - inc ecx - mov [ebp+EXTFS.log_block_size], ecx ; 1, 2, 3, 4 equ 1kb, 2kb, 4kb, 8kb - - mov eax, 1 - shl eax, cl - mov [ebp+EXTFS.count_block_in_block], eax - - shl eax, 7 - mov [ebp+EXTFS.count_pointer_in_block], eax - mov edx, eax ;RUS: потом еще квадрат найдем ;ENG: we'll find a square later - - shl eax, 2 - mov [ebp+EXTFS.block_size], eax - - push eax eax ; 2 kernel_alloc - - mov eax, edx - mul edx - mov [ebp+EXTFS.count_pointer_in_block_square], eax - - call kernel_alloc - mov [ebp+EXTFS.ext2_save_block], eax ; and for temp block - call kernel_alloc - mov [ebp+EXTFS.ext2_temp_block], eax ; and for get_inode proc - - movzx eax, word [ebx + EXT2_SB_STRUC.inode_size] - mov ecx, [ebx + EXT2_SB_STRUC.blocks_per_group] - - mov [ebp+EXTFS.inode_size], eax - mov [ebp+EXTFS.blocks_per_group], ecx - - push eax eax eax ;3 kernel_alloc - call kernel_alloc - mov [ebp+EXTFS.ext2_save_inode], eax - call kernel_alloc - mov [ebp+EXTFS.ext2_temp_inode], eax - call kernel_alloc - mov [ebp+EXTFS.root_inode], eax - - mov ebx, eax - mov eax, EXT2_ROOT_INO - call ext2_get_inode ; read root inode - - mov eax, ebp ; return pointer to EXTFS - pop edi esi ebp ebx - ret -endp - -proc ext2_free - push ebp - xchg ebp, eax - stdcall kernel_free, [ebp+EXTFS.ext2_save_block] - stdcall kernel_free, [ebp+EXTFS.ext2_temp_block] - stdcall kernel_free, [ebp+EXTFS.ext2_save_inode] - stdcall kernel_free, [ebp+EXTFS.ext2_temp_inode] - stdcall kernel_free, [ebp+EXTFS.root_inode] - xchg ebp, eax - call free - pop ebp - ret -endp - -proc ext2_lock - lea ecx, [ebp+EXTFS.Lock] - jmp mutex_lock -endp - -proc ext2_unlock - lea ecx, [ebp+EXTFS.Lock] - jmp mutex_unlock -endp - -;================================================================== -;read ext2 block form FS to memory -;in: eax = i_block (address of block in ext2 terms) -; ebx = pointer to return memory -; ebp = pointer to EXTFS -;out: eax - error code (0 = no_error) -ext2_get_block: - push ebx ecx - mov ecx, [ebp+EXTFS.log_block_size] - shl eax, cl - mov ecx, eax - push [ebp+EXTFS.count_block_in_block] - @@: - mov eax, ecx - call fs_read32_sys - test eax, eax - jnz .fail - inc ecx - add ebx, 512 - dec dword [esp] - jnz @B - pop ecx - xor eax, eax - @@: - pop ecx ebx - ret - .fail: - mov eax, ERROR_DEVICE - jmp @B - - -;=================================================================== -;RUS: получает номер блока из extent inode ;ENG: receives block number from extent inode -;RUS: in: ecx = номер блока по порядку ;ENG: in: ecx = consecutive block number -;RUS: esi = адрес extent header`а ;ENG: esi = address of extent header -;RUS: ebp = указатель на структуру EXTFS ;ENG: ebp = pointer to EXTFS -;RUS: out: ecx - адрес очередного блока в случае успеха ;ENG: out: ecx - address of next block, if successful -;RUS: eax - номер ошибки (если равно 0, то ошибки нет) ;ENG: eax - error number (0 - no error) -ext4_block_recursive_search: - cmp word [esi + EXT4_EXTENT_HEADER.eh_magic], 0xF30A ;EXT4_EXT_MAGIC - jne .fail - - movzx ebx, [esi + EXT4_EXTENT_HEADER.eh_entries] - add esi, sizeof.EXT4_EXTENT_HEADER - cmp word [esi - sizeof.EXT4_EXTENT_HEADER + EXT4_EXTENT_HEADER.eh_depth], 0 - je .leaf_block ;листовой ли это блок? - - ;не листовой блок, а индексный ; eax - ext4_extent_idx - test ebx, ebx - jz .fail ;пустой индексный блок -> ошибка - - ;цикл по индексам экстентов - @@: - cmp ebx, 1 ;у индексов не хранится длина, - je .end_search_index ;поэтому, если остался последний - то это нужный - - cmp ecx, [esi + EXT4_EXTENT_IDX.ei_block] - jb .fail - - cmp ecx, [esi + sizeof.EXT4_EXTENT_IDX + EXT4_EXTENT_IDX.ei_block] ;блок слeдующего индекса - jb .end_search_index ;следующий дальше - значит текущий, то что нам нужен - - add esi, sizeof.EXT4_EXTENT_IDX - dec ebx - jmp @B - - .end_search_index: - ;ebp указывает на нужный extent_idx, считываем следующий блок - mov ebx, [ebp+EXTFS.ext2_temp_block] - mov eax, [esi + EXT4_EXTENT_IDX.ei_leaf_lo] - call ext2_get_block - test eax, eax - jnz .fail - mov esi, ebx - jmp ext4_block_recursive_search ;рекурсивно прыгаем в начало - - .leaf_block: ;листовой блок esi - ext4_extent - ;цикл по экстентам - @@: - test ebx, ebx - jz .fail ;ни один узел не подошел - ошибка - - mov edx, [esi + EXT4_EXTENT.ee_block] - cmp ecx, edx - jb .fail ;если меньше, значит он был в предыдущих блоках -> ошибка - - movzx edi, [esi + EXT4_EXTENT.ee_len] - add edx, edi - cmp ecx, edx - jb .end_search_extent ;нашли нужный блок - - add esi, sizeof.EXT4_EXTENT - dec ebx - jmp @B - - .end_search_extent: - mov edx, [esi + EXT4_EXTENT.ee_start_lo] - sub ecx, [esi + EXT4_EXTENT.ee_block] ;разница в ext4 блоках - add ecx, edx - xor eax, eax - ret - - .fail: - mov eax, ERROR_FS_FAIL - ret - -;=================================================================== -;получает адрес ext2 блока из inode с определнным номером -;RUS: in: ecx = номер блока в inode (0..) ;ENG: in: ecx = number of block in inode (0..) -;RUS: esi = адрес inode ;ENG: esi = inode address -;RUS: ebp = указатель на структуру EXTFS;ENG: ebp = pointer to EXTFS -;RUS: out: ecx = адрес очередного блока ;ENG: out: ecx = next block address -;RUS: eax - error code ;ENG: eax - error code -ext2_get_inode_block: - test [esi + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL - jz @F - - pushad - add esi, EXT2_INODE_STRUC.i_block ;esi - extent_header - call ext4_block_recursive_search - mov PUSHAD_ECX, ecx - mov PUSHAD_EAX, eax - popad - ret - - @@: - cmp ecx, 12 ; 0..11 - direct block address - jb .get_direct_block - - sub ecx, 12 - cmp ecx, [ebp+EXTFS.count_pointer_in_block] ; 12.. - indirect blocks - jb .get_indirect_block - - sub ecx, [ebp+EXTFS.count_pointer_in_block] - cmp ecx, [ebp+EXTFS.count_pointer_in_block_square] - jb .get_double_indirect_block - - sub ecx, [ebp+EXTFS.count_pointer_in_block_square] - ;triple indirect block - push edx ebx - - mov eax, [esi + EXT2_INODE_STRUC.i_block + 14*4] - mov ebx, [ebp+EXTFS.ext2_temp_block] - call ext2_get_block - test eax, eax - jnz .fail - - xor edx, edx - mov eax, ecx - div [ebp+EXTFS.count_pointer_in_block_square] - - ;RUS: eax - номер в полученном блоке edx - номер дальше - ;ENG: eax - current block number, edx - next block number - mov eax, [ebx + eax*4] - call ext2_get_block - test eax, eax - jnz .fail - - mov eax, edx - jmp @F - - .get_double_indirect_block: - push edx ebx - - mov eax, [esi + EXT2_INODE_STRUC.i_block + 13*4] - mov ebx, [ebp+EXTFS.ext2_temp_block] - call ext2_get_block - test eax, eax - jnz .fail - - mov eax, ecx - @@: - xor edx, edx - div [ebp+EXTFS.count_pointer_in_block] - - mov eax, [ebx + eax*4] - call ext2_get_block - test eax, eax - jnz .fail - - mov ecx, [ebx + edx*4] - .fail: - pop ebx edx - ret - - .get_indirect_block: - push ebx - mov eax, [esi + EXT2_INODE_STRUC.i_block + 12*4] - mov ebx, [ebp+EXTFS.ext2_temp_block] - call ext2_get_block - test eax, eax - jnz @F ;RUS: если не было ошибки ;ENG: if there was no error - - mov ecx, [ebx + ecx*4] ;RUS: заносим результат ;ENG: ??? - @@: - pop ebx - ret - - .get_direct_block: - mov ecx, [esi + EXT2_INODE_STRUC.i_block + ecx*4] - xor eax, eax - ret - -;=================================================================== -;get content inode by num -;in: eax = inode_num -; ebx = address of inode content -; ebp = pointer to EXTFS -;out: eax - error code -ext2_get_inode: - pushad - mov edi, ebx ;сохраним адрес inode - dec eax - xor edx, edx - - div [ebp + EXT2_SB_STRUC.inodes_per_group + EXTFS.superblock] - - push edx ;locale num in group - - mov edx, 32 - mul edx ; address block_group in global_desc_table - - ;RUS: в eax - смещение группы с inode-ом относительно начала глобальной дескрипторной таблицы - ;RUS: найдем блок в котором он находится - ;ENG: in eax - inode group offset relative to global descriptor table start - ;ENG: let's find the block this inode is in - div [ebp+EXTFS.block_size] - add eax, [ebp + EXT2_SB_STRUC.first_data_block + EXTFS.superblock] - inc eax - mov ebx, [ebp+EXTFS.ext2_temp_block] - call ext2_get_block - test eax, eax - jnz .fail - - add ebx, edx ;RUS: локальный номер в блоке ;ENG: local number inside block - mov eax, [ebx + EXT2_BLOCK_GROUP_DESC.inode_table] ;RUS: номер блока - в терминах ext2 - ;ENG: block number - in ext2 terms - mov ecx, [ebp+EXTFS.log_block_size] - shl eax, cl - ;RUS: eax - указывает на таблицу inode-ов на hdd ;ENG: eax - points to inode table on HDD - mov esi, eax ;RUS: сохраним его пока в esi ;ENG: let's save it in esi for now - - ;RUS: прибавим локальный адрес inode-а ;ENG: add local address of inode - pop eax ; index - mov ecx, [ebp+EXTFS.inode_size] - mul ecx ; (index * inode_size) - ;RUS: поделим на размер блока ;ENG: divide by block size - mov ecx, eax - and ecx, 512 - 1 - shrd eax, edx, 9 - - add eax, esi ;RUS: нашли адрес блока для чтения ;ENG: found block address to read - mov ebx, [ebp+EXTFS.ext2_temp_block] - call fs_read32_sys - test eax, eax - jnz .fail - - mov esi, ecx ;RUS: добавим "остаток" ;ENG: add the "remainder" - mov ecx, [ebp+EXTFS.inode_size] - add esi, ebx ;RUS: к адресу ;ENG: to the address - rep movsb ;RUS: копируем inode ;ENG: copy inode - xor eax, eax - .fail: - mov PUSHAD_EAX, eax - popad - ret - -;---------------------------------------------------------------- -; ext2_ReadFolder - EXT2FS implementation of reading a folder -; in: ebp = pointer to EXTFS structure -; in: esi+[esp+4] = name -; in: ebx = pointer to parameters from sysfunc 70 -; out: eax, ebx = return values for sysfunc 70 -;---------------------------------------------------------------- -ext2_ReadFolder: - call ext2_lock - cmp byte [esi], 0 - jz .root_folder - - push ebx - stdcall ext2_find_lfn, [esp+4+4] ;вернет в esi адрес inode - pop ebx - test eax, eax - jnz .error_ret - test [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR - jz .error_not_found - jmp @F - - .root_folder: - mov esi, [ebp+EXTFS.root_inode] - test [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR - jz .error_root - ;придется копировать inode - mov edi, [ebp+EXTFS.ext2_save_inode] - mov ecx, [ebp+EXTFS.inode_size] - shr ecx, 2 - push edi - rep movsd - pop esi - @@: - cmp [esi + EXT2_INODE_STRUC.i_size], 0 ;папка пуста - je .error_empty_dir - - mov edx, [ebx + 16] - push edx ;адрес результата [edi + 28] - push 0 ;конец очередного блока папки [edi + 24] - push dword [ebx +12];сколько файлов нужно прочитать [edi + 20] - push dword [ebx + 4];первый "нужный" файл [edi + 16] - push dword [ebx + 8];флаги [edi + 12] - push 0 ;[EXT2_read_in_folder] [edi + 8] - push 0 ;[EXT2_files_in_folder] [edi + 4] - push 0 ;номер блока по порядку [edi] - - mov edi, edx - mov ecx, 32/4 - rep stosd ; fill header zero - - mov edi, esp ; edi - указатель на локальные переменные - add edx, 32 ; edx = current mem for return - - xor ecx, ecx ; получим номер первого блока - call ext2_get_inode_block - test eax, eax - jnz .error_get_block - - mov eax, ecx - mov ebx, [ebp+EXTFS.ext2_save_block] - call ext2_get_block ; и считываем блок с hdd - test eax, eax - jnz .error_get_block - - mov eax, ebx ; ebx = current dir record - add eax, [ebp+EXTFS.block_size] - mov [edi + 24], eax ; запомним конец очередного блока - - mov ecx, [edi + 16] ; ecx = first wanted (flags ommited) - - .find_wanted_start: - jecxz .find_wanted_end - .find_wanted_cycle: - cmp [ebx + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used - jz @F - inc dword [edi + 4] ; EXT2_files_in_folder - dec ecx - @@: - movzx eax, [ebx + EXT2_DIR_STRUC.rec_len] - - cmp eax, 12 ; минимальная длина записи - jb .error_bad_len - test eax, 0x3 ; длина записи должна делиться на 4 - jnz .error_bad_len - - sub [esi + EXT2_INODE_STRUC.i_size], eax ;вычитаем напрямую из структуры inode - add ebx, eax ; к следующей записи - cmp ebx, [edi + 24] ; сравниваем с концом блока - jb .find_wanted_start - - push .find_wanted_start - .end_block: ;вылетели из цикла - cmp [esi + EXT2_INODE_STRUC.i_size], 0 - jle .end_dir - - inc dword [edi] ;получаем новый блок - push ecx - mov ecx, [edi] - call ext2_get_inode_block - test eax, eax - jnz .error_get_block - - mov eax, ecx - mov ebx, [ebp+EXTFS.ext2_save_block] - call ext2_get_block - test eax, eax - jnz .error_get_block - - pop ecx - mov eax, ebx - add eax, [ebp+EXTFS.block_size] - mov [edi + 24], eax ;запомним конец блока - ret ; опять в цикл - - .wanted_end: - loop .find_wanted_cycle ; ecx 0 => -1 нужно посчитать сколько файлов - - ;дошли до первого "нужного" файла - .find_wanted_end: - mov ecx, [edi + 20] - .wanted_start: ; ищем first_wanted+count - jecxz .wanted_end - cmp [ebx + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used - jz .empty_rec - inc dword [edi + 8] - inc dword [edi + 4] - - push edi ecx - mov edi, edx ;обнуляем место под очереное имя файла/папки - xor eax, eax - mov ecx, 40 / 4 - rep stosd - pop ecx edi - - push ebx edi edx - mov eax, [ebx + EXT2_DIR_STRUC.inode] ;получим дочерний inode - mov ebx, [ebp+EXTFS.ext2_temp_inode] - call ext2_get_inode - test eax, eax - jnz .error_read_subinode - - lea edi, [edx + 8] - - mov eax, [ebx + EXT2_INODE_STRUC.i_ctime] ; переведем время в ntfs формат - xor edx, edx - add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600 - adc edx, 2 - call ntfs_datetime_to_bdfe.sec - - mov eax, [ebx + EXT2_INODE_STRUC.i_atime] - xor edx, edx - add eax, 3054539008 - adc edx, 2 - call ntfs_datetime_to_bdfe.sec - - mov eax, [ebx + EXT2_INODE_STRUC.i_mtime] - xor edx, edx - add eax, 3054539008 - adc edx, 2 - call ntfs_datetime_to_bdfe.sec - - pop edx ; пока достаем только буфер - test [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR ; для папки размер - jnz @F ; не возвращаем - - mov eax, [ebx + EXT2_INODE_STRUC.i_size] ;low size - stosd - mov eax, [ebx + EXT2_INODE_STRUC.i_dir_acl] ;high size - stosd - xor dword [edx], FS_FT_DIR ;помечаем, что это файл(2 раза xor) - @@: - xor dword [edx], FS_FT_DIR ;помечаем, что это файл - - ;теперь скопируем имя, сконвертировав из UTF-8 в CP866 - push ecx esi ;edi уже сохранен в стеке - mov esi, [esp+12] - movzx ecx, [esi + EXT2_DIR_STRUC.name_len] - lea edi, [edx + 40] - lea esi, [esi + EXT2_DIR_STRUC.name] - call utf8_to_cp866 - and byte [edi], 0 - pop esi ecx edi ebx - - cmp byte [edx + 40], '.' ; в linux файл, начинающийся с точки - скрытый - jne @F - or dword [edx], FS_FT_HIDDEN - @@: - - add edx, 40 + 264 ; go to next record - dec ecx ; если запись пустая ecx не надо уменьшать - .empty_rec: - movzx eax, [ebx + EXT2_DIR_STRUC.rec_len] - cmp eax, 12 ; минимальная длина записи - jb .error_bad_len - test eax, 0x3 ; длина записи должна делиться на 4 - jnz .error_bad_len - - sub [esi + EXT2_INODE_STRUC.i_size], eax ;вычитаем напрямую из структуры inode - add ebx, eax - cmp ebx, [edi + 24] ;дошли ли до конца блока? - jb .wanted_start - - push .wanted_start ; дошли - jmp .end_block - - .end_dir: ;конец папки, когда еще не дошли до нужного файла - call ext2_unlock - mov edx, [edi + 28] ;адрес структуры результата - mov ebx, [edi + 8] ;EXT2_read_in_folder - mov ecx, [edi + 4] ;EXT2_files_in_folder - mov dword [edx], 1 ;version - mov [edx + 4], ebx - mov [edx + 8], ecx - - lea esp, [edi + 32] - - xor eax, eax ;RUS: зарезервировано: нули в текущей реализации - ;ENG: reserved: zeros in current implementation - lea edi, [edx + 12] - mov ecx, 20 / 4 - rep stosd - ret - - .error_bad_len: - mov eax, ERROR_FS_FAIL - .error_read_subinode: - .error_get_block: - lea esp, [edi + 32] - .error_ret: - or ebx, -1 - push eax - call ext2_unlock - pop eax - ret - - .error_empty_dir: ;RUS: inode папки без блоков ;ENG: inode of folder without blocks - .error_root: ;RUS: root - не папка ;ENG: root is not a folder - mov eax, ERROR_FS_FAIL - jmp .error_ret - - .error_not_found: ;RUS: файл не найден ;ENG: file not found - mov eax, ERROR_FILE_NOT_FOUND - jmp .error_ret - -;============================================ -;convert UTF-8 string to ASCII-string (codepage 866) -;in: ecx = length source -; esi = source -; edi = buffer -; destroys: eax,esi,edi -utf8_to_cp866: - jecxz .ret - .start: - lodsw - cmp al, 0x80 - jb .ascii - - xchg al, ah ; big-endian - cmp ax, 0xd080 - jz .yo1 - cmp ax, 0xd191 - jz .yo2 - cmp ax, 0xd090 - jb .unk - cmp ax, 0xd180 - jb .rus1 - cmp ax, 0xd190 - jb .rus2 - .unk: - mov al, '_' - jmp .doit - .yo1: - mov al, 0xf0 ; Ё capital - jmp .doit - .yo2: - mov al, 0xf1 ; ё small - jmp .doit - .rus1: - sub ax, 0xd090 - 0x80 - jmp .doit - .rus2: - sub ax, 0xd18f - 0xEF - .doit: - stosb - sub ecx, 2 - ja .start - ret - - .ascii: - stosb - dec esi - dec ecx - jnz .start - .ret: - ret - -;---------------------------------------------------------------- -; ext2_Read - EXT2FS implementation of reading a file -; in: ebp = pointer to FAT structure -; in: esi+[esp+4] = name -; in: ebx = pointer to parameters from sysfunc 70 -; out: eax, ebx = return values for sysfunc 70 -;---------------------------------------------------------------- -ext2_Read: - call ext2_lock - cmp byte [esi], 0 - jnz @F - - .this_is_nofile: - call ext2_unlock - or ebx, -1 - mov eax, ERROR_ACCESS_DENIED - ret - - @@: - push ebx - stdcall ext2_find_lfn, [esp+4+4] - pop ebx - test eax, eax - jz @F - - call ext2_unlock - or ebx, -1 - mov eax, ERROR_FILE_NOT_FOUND - ret - - @@: - mov ax, [esi + EXT2_INODE_STRUC.i_mode] - and ax, EXT2_S_IFMT ;оставляем только тип inode в ax - cmp ax, EXT2_S_IFREG - jne .this_is_nofile - - mov edi, [ebx+16] ; edi = pointer to return mem - mov ecx, [ebx+12] - - mov eax, [ebx+4] - mov edx, [ebx+8] ;RUS: edx : eax - стартовый номер байта ;ENG: edx : eax - start byte number - - ;RUS: ///// сравним хватит ли нам файла или нет ;ENG: ///// check if file is big enough for us - cmp [esi + EXT2_INODE_STRUC.i_dir_acl], edx - ja .size_great - jb .size_less - - cmp [esi + EXT2_INODE_STRUC.i_size], eax - ja .size_great - - .size_less: - call ext2_unlock - xor ebx, ebx - mov eax, ERROR_END_OF_FILE - ret - - .size_great: - add eax, ecx ;RUS: add to first_wanted кол-во байт для чтения - ;ENG: add to first_wanted number of bytes to read - adc edx, 0 - - cmp [esi + EXT2_INODE_STRUC.i_dir_acl], edx - ja .size_great_great - jb .size_great_less - cmp [esi + EXT2_INODE_STRUC.i_size], eax - jae .size_great_great ; and if it's equal, no matter where we jump - - .size_great_less: - push 1 ;RUS: читаем по границе размера ;ENG: reading till the end of file - mov ecx, [esi + EXT2_INODE_STRUC.i_size] - sub ecx, [ebx+4] ;RUS: (размер - старт) = сколько читать ;ENG: to read = (size - start) - jmp @F - - .size_great_great: - push 0 ;RUS: читаем столько, сколько запросили ;ENG: reading as much as requested - - @@: - ;здесь мы точно знаем сколько байт читать - ecx - ;edi - return memory - ;esi -> first wanted - - push ecx ;количество считанных байт - - ;получим кусок из первого блока - mov edx, [ebx+8] - mov eax, [ebx+4] - div [ebp+EXTFS.block_size] - - push eax ;счетчик блоков ложим в стек - - push ecx - mov ecx, eax - call ext2_get_inode_block - test eax, eax - jnz .error_at_first_block - mov ebx, [ebp+EXTFS.ext2_save_block] - mov eax, ecx - call ext2_get_block - test eax, eax - jnz .error_at_first_block - pop ecx - add ebx, edx - - neg edx - add edx, [ebp+EXTFS.block_size] ;RUS: block_size - стартовый байт = сколько байт 1-го блока - ;ENG: block_size - start byte = number of bytes in 1st block - cmp ecx, edx - jbe .only_one_block - - mov eax, ecx - sub eax, edx - mov ecx, edx - - push esi - mov esi, ebx - rep movsb ;RUS: кусок 1-го блока ;ENG: part of 1st block - pop esi - - ;теперь в eax кол-во оставшихся байт для чтения - .calc_blocks_count: - mov ebx, edi ;чтение блока прям в ->ebx - xor edx, edx - div [ebp+EXTFS.block_size] ;кол-во байт в последнем блоке (остаток) в edx - mov edi, eax ;кол-во целых блоков в edi - @@: - test edi, edi - jz .finish_block - inc dword [esp] - mov ecx, [esp] - call ext2_get_inode_block - test eax, eax - jnz .error_at_read_cycle - - mov eax, ecx ;а ebx уже забит нужным значением - call ext2_get_block - test eax, eax - jnz .error_at_read_cycle - add ebx, [ebp+EXTFS.block_size] - - dec edi - jmp @B - - .finish_block: ;в edx - кол-во байт в последнем блоке - test edx, edx - jz .end_read - - pop ecx ;счетчик блоков -> ecx - inc ecx - call ext2_get_inode_block - test eax, eax - jnz .error_at_finish_block - - mov edi, ebx - mov eax, ecx - mov ebx, [ebp+EXTFS.ext2_save_block] - call ext2_get_block - test eax, eax - jnz .error_at_finish_block - - mov ecx, edx - mov esi, ebx - rep movsb ;кусок last блока - jmp @F - - .end_read: - pop ecx ;счетчик блоков, который хранился в стеке - @@: - pop ebx ;количество считанных байт - call ext2_unlock - pop eax ; 1 или 0 - достигли ли конца файла - test eax, eax - jz @F - - mov eax, ERROR_END_OF_FILE - ret - @@: - xor eax, eax - ret - - .only_one_block: - mov esi, ebx - rep movsb ;кусок last блока - jmp .end_read - - .error_at_first_block: - pop edx - .error_at_read_cycle: - pop ebx - .error_at_finish_block: - pop ecx edx - or ebx, -1 - push eax - call ext2_unlock - pop eax - ret - -;---------------------------------------------------------------- -; in: esi = file path -; ebx = pointer to dir block -; ebp = pointer to EXTFS structure -; out: esi - name without parent or not_changed -; ebx - dir_rec of inode children -ext2_test_block_by_name: - sub esp, 256 ;EXT2_filename - mov edx, ebx - add edx, [ebp+EXTFS.block_size] ;RUS: запомним конец блока ;ENG: save block end - - .start_rec: - cmp [ebx + EXT2_DIR_STRUC.inode], 0 - jz .next_rec - - mov edi, esp - push esi - movzx ecx, [ebx + EXT2_DIR_STRUC.name_len] - lea esi, [ebx + EXT2_DIR_STRUC.name] - call utf8_to_cp866 - - mov ecx, edi - lea edi, [esp + 4] - sub ecx, edi ;RUS: кол-во байт в получившейся строке ;ENG: number of bytes in resulting string - - mov esi, [esp] - @@: - jecxz .test_find - dec ecx - - lodsb - call char_toupper - - mov ah, [edi] - inc edi - xchg al, ah - call char_toupper - cmp al, ah - je @B - @@: ;RUS: не подошло ;ENG: didn't fit - pop esi - .next_rec: - movzx eax, [ebx + EXT2_DIR_STRUC.rec_len] - add ebx, eax ;RUS: к след. записи ;ENG: go to next record - cmp ebx, edx ;RUS: проверим конец ли ;ENG: check if this is the end - jb .start_rec - add esp, 256 - ret - - .test_find: - cmp byte [esi], 0 - je .ret ;RUS: нашли конец ;ENG: the end reached - cmp byte [esi], '/' - jne @B - inc esi - .ret: - add esp, 256 + 4 - ret - -;======================== -;Ищет inode по строке пути -;in: esi+[esp+4] = name -; ebp = pointer to EXTFS -;out: eax - error code -; esi = inode -; dl - первый байт из имени файла/папки -ext2_find_lfn: - mov edx, [ebp+EXTFS.root_inode] - cmp [edx + EXT2_INODE_STRUC.i_blocks], 0 - je .error_empty_root - - .next_path_part: - push [edx + EXT2_INODE_STRUC.i_blocks] - xor ecx, ecx - .folder_block_cycle: - push ecx - xchg esi, edx - call ext2_get_inode_block - xchg esi, edx - test eax, eax - jnz .error_get_inode_block - - mov eax, ecx - mov ebx, [ebp+EXTFS.ext2_save_block] ;ebx = cur dir record - call ext2_get_block - test eax, eax - jnz .error_get_block - - push esi - push edx - call ext2_test_block_by_name - pop edx - pop edi ecx - - cmp edi, esi ;RUS: нашли имя? ;ENG: did we find a name? - je .next_folder_block ;RUS: не нашли -> к след. блоку ;ENG: we didn't -> moving to next block - - cmp byte [esi], 0 ;RUS: дошли до "конца" пути -> возваращаемся - ;ENG: reached the "end" of path -> returning - jnz @f - cmp dword [esp+8], 0 - jz .get_inode_ret - mov esi, [esp+8] - mov dword [esp+8], 0 - @@: - - cmp [ebx + EXT2_DIR_STRUC.file_type], EXT2_FT_DIR ;RUS: нашли, но это не папка - jne .not_found ;ENG: found, but it's not a folder - - mov eax, [ebx + EXT2_DIR_STRUC.inode] - mov ebx, [ebp+EXTFS.ext2_save_inode] ;RUS: все же папка. ;ENG: it's a folder afterall - call ext2_get_inode - test eax, eax - jnz .error_get_inode - pop ecx ;RUS: в стеке лежит кол-во блоков ;ENG: stack top contains number of blocks - mov edx, ebx - jmp .next_path_part - - .next_folder_block: - ;к следующему блоку в текущей папке - pop eax ;RUS: счетчик блоков ;ENG: blocks counter - sub eax, [ebp+EXTFS.count_block_in_block] - jle .not_found - - push eax - inc ecx - jmp .folder_block_cycle - - .not_found: - mov eax, ERROR_FILE_NOT_FOUND - ret 4 - - .get_inode_ret: - pop ecx ;RUS: в стеке лежит кол-во блоков ;ENG: stack top contains number of blocks - mov dl, [ebx + EXT2_DIR_STRUC.name] ;RUS: в dl - первый символ () ;ENG: ??? - mov eax, [ebx + EXT2_DIR_STRUC.inode] - mov ebx, [ebp+EXTFS.ext2_save_inode] - call ext2_get_inode - mov esi, ebx - xor eax, eax - ret 4 - - .error_get_inode_block: - .error_get_block: - pop ecx - .error_get_inode: - pop ebx - .error_empty_root: - mov eax, ERROR_FS_FAIL - ret 4 - -;---------------------------------------------------------------- -; ext2_GetFileInfo - EXT2 implementation of getting file info -; in: ebp = pointer to EXTFS structure -; in: esi+[esp+4] = name -; in: ebx = pointer to parameters from sysfunc 70 -; out: eax, ebx = return values for sysfunc 70 -;---------------------------------------------------------------- -ext2_GetFileInfo: - call ext2_lock - mov edx, [ebx+16] - cmp byte [esi], 0 - jz .is_root - - push edx - stdcall ext2_find_lfn, [esp+4+4] - mov ebx, edx - pop edx - test eax, eax - jz @F - push eax - call ext2_unlock - pop eax - ret - - .is_root: - xor ebx, ebx ;RUS: root не может быть скрытым ;ENG: root cannot be hidden - mov esi, [ebp+EXTFS.root_inode] - @@: - xor eax, eax - mov edi, edx - mov ecx, 40/4 - rep stosd ; fill zero - - cmp bl, '.' - jne @F - or dword [edx], FS_FT_HIDDEN - @@: - - test [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR - jnz @F - mov eax, [esi + EXT2_INODE_STRUC.i_size] ;low size - mov ebx, [esi + EXT2_INODE_STRUC.i_dir_acl] ;high size - mov dword [edx+32], eax - mov dword [edx+36], ebx - xor dword [edx], FS_FT_DIR - @@: - xor dword [edx], FS_FT_DIR - - lea edi, [edx + 8] - mov eax, [esi + EXT2_INODE_STRUC.i_ctime] - xor edx, edx - add eax, 3054539008 - adc edx, 2 - call ntfs_datetime_to_bdfe.sec - - mov eax, [esi + EXT2_INODE_STRUC.i_atime] - xor edx, edx - add eax, 3054539008 - adc edx, 2 - call ntfs_datetime_to_bdfe.sec - - mov eax, [esi + EXT2_INODE_STRUC.i_mtime] - xor edx, edx - add eax, 3054539008 - adc edx, 2 - call ntfs_datetime_to_bdfe.sec - - call ext2_unlock - xor eax, eax - ret - -ext2_Rewrite: -ext2_Write: -ext2_SetFileEnd: -ext2_SetFileInfo: -ext2_Delete: -ext2_CreateFolder: - xor ebx, ebx - mov eax, ERROR_UNSUPPORTED_FS - ret diff --git a/kernel/branches/Kolibri-acpi/fs/ext2/blocks.inc b/kernel/branches/Kolibri-acpi/fs/ext2/blocks.inc new file mode 100644 index 0000000000..f9d11aacb4 --- /dev/null +++ b/kernel/branches/Kolibri-acpi/fs/ext2/blocks.inc @@ -0,0 +1,409 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Contains ext2 block handling code. ;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under the terms of the new BSD license. ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;--------------------------------------------------------------------- +; Write ext2 block from memory to disk. +; Input: eax = i_block (block number in ext2 terms); +; ebx = buffer address +; ebp = pointer to EXTFS +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_block_write: + push edx ebx ecx + + mov edx, fs_write32_sys + jmp ext2_block_modify + +;--------------------------------------------------------------------- +; Read ext2 block from disk to memory. +; Input: eax = i_block (block number in ext2 terms); +; ebx = address of where to read block +; ebp = pointer to EXTFS +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_block_read: + push edx ebx ecx + + mov edx, fs_read32_sys + jmp ext2_block_modify + +;--------------------------------------------------------------------- +; Modify ext2 block. +; Input: eax = i_block (block number in ext2 terms); +; ebx = I/O buffer address; +; edx = fs_read/write32_sys +; ebp = pointer to EXTFS +; edx, ebx, ecx on stack. +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_block_modify: + ; Get block number in hard-disk terms in eax. + mov ecx, [ebp + EXTFS.log_block_size] + shl eax, cl + mov ecx, eax + push [ebp + EXTFS.count_block_in_block] + + @@: + mov eax, ecx + call edx + test eax, eax + jnz .fail + + inc ecx + add ebx, 512 + dec dword[esp] + jnz @B + + xor eax, eax + @@: + pop ecx + pop ecx ebx edx + ret + + .fail: + mov eax, ERROR_DEVICE + jmp @B + +;--------------------------------------------------------------------- +; Zeroes a block. +; Input: ebx = block ID. +; ebp = pointer to EXTFS. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_block_zero: + push ebx + + mov eax, ebx + mov ebx, [ebp + EXTFS.ext2_temp_block] + + call ext2_block_read + test eax, eax + jnz .return + + push edi ecx + xor eax, eax + mov ecx, [ebp + EXTFS.block_size] + mov edi, [ebp + EXTFS.ext2_temp_block] + rep stosb + pop ecx edi + + mov eax, [esp] + call ext2_block_write + + .return: + pop ebx + ret + +;--------------------------------------------------------------------- +; Allocates a block. +; Input: eax = inode ID for "preference". +; ebp = pointer to EXTFS. +; Output: Block marked as set in block group. +; eax = error code. +; ebx = block ID. +;--------------------------------------------------------------------- +ext2_block_alloc: + push [ebp + EXTFS.superblock + EXT2_SB_STRUC.blocks_count] + push EXT2_BLOCK_GROUP_DESC.free_blocks_count + push [ebp + EXTFS.superblock + EXT2_SB_STRUC.blocks_per_group] + + lea ebx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.free_block_count] + push ebx + + push ext2_bg_read_blk_bitmap + + call ext2_resource_alloc + + ret + +;--------------------------------------------------------------------- +; Zero-allocates a block. +; Input: eax = inode ID for "preference". +; ebp = pointer to EXTFS. +; Output: Block marked as set in block group. +; eax = error code. +; ebx = block ID. +;--------------------------------------------------------------------- +ext2_block_calloc: + call ext2_block_alloc + test eax, eax + jnz @F + + call ext2_block_zero + @@: + ret + +;--------------------------------------------------------------------- +; Frees a block. +; Input: eax = block ID. +; ebp = pointer to EXTFS. +; Output: Block marked as free in block group. +; eax = error code. +;--------------------------------------------------------------------- +ext2_block_free: + push edi ecx + + mov edi, ext2_bg_read_blk_bitmap + xor ecx, ecx + call ext2_resource_free + + pop ecx edi + ret + +;--------------------------------------------------------------------- +; Find parent from file path in block. +; Input: esi = file path. +; ebx = pointer to directory block. +; ebp = pointer to EXTFS structure. +; Output: esi = name without parent, or not changed. +; ebx = directory record matched. +;--------------------------------------------------------------------- +ext2_block_find_parent: + sub esp, 256 ; Space for EXT2 filename. + mov edx, ebx + add edx, [ebp + EXTFS.block_size] ; Save block end. + + .start_rec: + cmp [ebx + EXT2_DIR_STRUC.inode], 0 + jz .next_rec + + mov edi, esp + push esi + movzx ecx, [ebx + EXT2_DIR_STRUC.name_len] + lea esi, [ebx + EXT2_DIR_STRUC.name] + call utf8_to_cp866 + + mov ecx, edi + lea edi, [esp + 4] + sub ecx, edi ; Number of bytes in resulting string. + + mov esi, [esp] + + ; esi: original file path. + ; edi: converted string stored on stack. + ; ecx: size of converted string. + @@: + ; If no bytes left in resulting string, test it. + jecxz .test_find + dec ecx + + lodsb + call char_toupper + + mov ah, [edi] + inc edi + xchg al, ah + call char_toupper + + ; If both are same, check next byte. + cmp al, ah + je @B + @@: ; Doesn't match. + pop esi + + .next_rec: + movzx eax, [ebx + EXT2_DIR_STRUC.rec_len] + add ebx, eax ; Go to next record. + cmp ebx, edx ; Check if this is the end. + jb .start_rec + + add esp, 256 + ret + + .test_find: + cmp byte [esi], 0 + je .ret ; The end reached. + cmp byte [esi], '/' ; If not end of directory name, not matched. + jne @B + inc esi + + .ret: + add esp, 256 + 4 + ret + +;--------------------------------------------------------------------- +; Finds free space in a directory block, modifying last entry appropriately. +; Input: ebp = pointer to EXTFS. +; ecx = size of free space required. +; [EXTFS.ext2_temp_block] contains the block relevant. +; Output: edi = free entry. +; rec_len of free entry is set. +; eax = error code; if the block doesn't link to the next one, this is 0x00000001 on failure. +; ; else, 0xFFFFFFFF. +;--------------------------------------------------------------------- +ext2_block_find_fspace: + push ebx edx + + mov edi, [ebp + EXTFS.ext2_temp_block] + mov edx, edi + add edx, [ebp + EXTFS.block_size] + + @@: + movzx eax, [edi + EXT2_DIR_STRUC.rec_len] + test eax, eax + jz .zero_len + + cmp [edi + EXT2_DIR_STRUC.inode], 0 + je .unused_entry + + ; It's a used entry, so see if we can fit it between current one and next. + ; Subtract the size used by the name and the structure from rec_len. + movzx ebx, [edi + EXT2_DIR_STRUC.name_len] + add ebx, 8 + 3 + and ebx, 0xfffffffc ; Align it on the next 4-byte boundary. + + sub eax, ebx + add edi, ebx + cmp eax, ecx + jb .next_iter + + sub edi, ebx + mov [edi + EXT2_DIR_STRUC.rec_len], bx ; Make previous entry point to us. + add edi, ebx + + mov [edi + EXT2_DIR_STRUC.rec_len], ax ; Make current entry point to next one. + jmp .found + + .unused_entry: + ; It's an unused inode. + cmp eax, ecx + jge .found + + .next_iter: + add edi, eax + cmp edi, edx + jb @B + + .not_found: + xor eax, eax + not eax + jmp .ret + + ; Zero length entry means we have the rest of the block for us. + .zero_len: + mov eax, edx + sub eax, edi + + ; Point to next block. + mov [edi + EXT2_DIR_STRUC.rec_len], ax + + cmp eax, ecx + jge .fits + + mov [edi + EXT2_DIR_STRUC.inode], 0 + + ; It doesn't fit, but the block doesn't link to the next block. + xor eax, eax + inc eax + jmp .ret + + .fits: + mov [edi + EXT2_DIR_STRUC.rec_len], cx + + .found: + xor eax, eax + + .ret: + pop edx ebx + ret + +;--------------------------------------------------------------------- +; Gets the block group's descriptor. +; Input: eax = block group. +; Output: eax = if zero, error; else, points to block group descriptor. +; [EXTFS.ext2_temp_block] contains relevant block. +; ebp = pointer to EXTFS. +;--------------------------------------------------------------------- +ext2_bg_read_desc: + push edx ebx + mov edx, 32 + mul edx ; Get index of descriptor in global_desc_table. + + ; eax: block group descriptor offset relative to global descriptor table start + ; Find the block this block descriptor is in. + div [ebp + EXTFS.block_size] + add eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.first_data_block] + inc eax + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz .fail + + add ebx, edx ; edx: local index of descriptor inside block + mov eax, ebx + + .return: + pop ebx edx + ret + + .fail: + xor eax, eax + jmp .return + +;--------------------------------------------------------------------- +; Writes a block group's descriptor. +; Input: eax = block group. +; [EXTFS.ext2_temp_data] contains the block relevant. +; ebp = pointer to EXTFS. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_bg_write_desc: + push edx ebx + mov edx, 32 + mul edx ; Get index of descriptor in global_desc_table. + + ; eax: block group descriptor offset relative to global descriptor table start + ; Find the block this block descriptor is in. + div [ebp + EXTFS.block_size] + add eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.first_data_block] + inc eax + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_write + + .return: + pop ebx edx + ret + +;--------------------------------------------------------------------- +; Gets the block group's block bitmap. +; Input: eax = block group. +; Output: eax = if zero, error; else, points to block group descriptor. +; ebx = block bitmap's block (hard disk). +;--------------------------------------------------------------------- +ext2_bg_read_blk_bitmap: + push ecx + + call ext2_bg_read_desc + test eax, eax + jz .fail + + mov ebx, [eax + EXT2_BLOCK_GROUP_DESC.block_bitmap] ; Block number of block group bitmap - in ext2 terms. + + .return: + pop ecx + ret + + .fail: + xor eax, eax + jmp .return + +;--------------------------------------------------------------------- +; Updates superblock, plus backups. +; Input: ebp = pointer to EXTFS. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_sb_update: + push ebx + + mov eax, 2 + lea ebx, [ebp + EXTFS.superblock] + call fs_write32_sys + + pop ebx + ret diff --git a/kernel/branches/Kolibri-acpi/fs/ext2/ext2.asm b/kernel/branches/Kolibri-acpi/fs/ext2/ext2.asm new file mode 100644 index 0000000000..a8f518ae62 --- /dev/null +++ b/kernel/branches/Kolibri-acpi/fs/ext2/ext2.asm @@ -0,0 +1,1718 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Contains ext2 initialization, plus syscall handling code. ;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under the terms of the new BSD license. ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +include 'ext2.inc' +include 'blocks.inc' +include 'inode.inc' +include 'resource.inc' + +iglobal +align 4 +ext2_user_functions: + dd ext2_free + dd (ext2_user_functions_end - ext2_user_functions - 4) / 4 + dd ext2_Read + dd ext2_ReadFolder + dd ext2_Rewrite + dd ext2_Write + dd ext2_SetFileEnd + dd ext2_GetFileInfo + dd ext2_SetFileInfo + dd 0 + dd ext2_Delete + dd ext2_CreateFolder +ext2_user_functions_end: +endg + +;--------------------------------------------------------------------- +; Locks up an ext2 partition. +; Input: ebp = pointer to EXTFS. +;--------------------------------------------------------------------- +proc ext2_lock + lea ecx, [ebp + EXTFS.lock] + jmp mutex_lock +endp + +;--------------------------------------------------------------------- +; Unlocks up an ext2 partition. +; Input: ebp = pointer to EXTFS. +;--------------------------------------------------------------------- +proc ext2_unlock + lea ecx, [ebp + EXTFS.lock] + jmp mutex_unlock +endp + +;--------------------------------------------------------------------- +; Check if it's a valid ext* superblock. +; Input: ebp: first three fields of PARTITION structure. +; ebx + 512: points to 512-bytes buffer that can be used for anything. +; Output: eax: clear if can't create partition; set to EXTFS otherwise. +;--------------------------------------------------------------------- +proc ext2_create_partition + push ebx + + mov eax, 2 ; Superblock starts at 1024-bytes. + add ebx, 512 ; Get pointer to fs-specific buffer. + call fs_read32_sys + test eax, eax + jnz .fail + + ; Allowed 1KiB, 2KiB, 4KiB, 8KiB. + cmp [ebx + EXT2_SB_STRUC.log_block_size], 3 + ja .fail + + cmp [ebx + EXT2_SB_STRUC.magic], EXT2_SUPER_MAGIC + jne .fail + + cmp [ebx + EXT2_SB_STRUC.state], EXT2_VALID_FS + jne .fail + + ; Can't have no inodes per group. + cmp [ebx + EXT2_SB_STRUC.inodes_per_group], 0 + je .fail + + ; If incompatible features required, unusable superblock. + mov eax, [ebx + EXT2_SB_STRUC.feature_incompat] + test eax, not EXT4_FEATURE_INCOMPAT_SUPP + jz .setup + + .fail: + ; Not a (valid/usable) EXT2 superblock. + pop ebx + xor eax, eax + ret + + .setup: + movi eax, sizeof.EXTFS + call malloc + test eax, eax + jz ext2_create_partition.fail + + ; Store the first sector field. + mov ecx, dword[ebp + PARTITION.FirstSector] + mov dword[eax + EXTFS.FirstSector], ecx + mov ecx, dword [ebp + PARTITION.FirstSector+4] + mov dword [eax + EXTFS.FirstSector+4], ecx + + ; The length field. + mov ecx, dword[ebp + PARTITION.Length] + mov dword[eax + EXTFS.Length], ecx + mov ecx, dword[ebp + PARTITION.Length+4] + mov dword[eax + EXTFS.Length+4], ecx + + ; The disk field. + mov ecx, [ebp + PARTITION.Disk] + mov [eax + EXTFS.Disk], ecx + + mov [eax + EXTFS.FSUserFunctions], ext2_user_functions + + push ebp esi edi + + mov ebp, eax + lea ecx, [eax + EXTFS.lock] + call mutex_init + + ; Copy superblock from buffer to reserved memory. + mov esi, ebx + lea edi, [ebp + EXTFS.superblock] + mov ecx, 512/4 + rep movsd + + ; Get total groups. + mov eax, [ebx + EXT2_SB_STRUC.blocks_count] + sub eax, [ebx + EXT2_SB_STRUC.first_data_block] + dec eax + xor edx, edx + div [ebx + EXT2_SB_STRUC.blocks_per_group] + inc eax + mov [ebp + EXTFS.groups_count], eax + + ; Get log(block_size), such that 1,2,3,4 equ 1KiB,2KiB,4KiB,8KiB. + mov ecx, [ebx + EXT2_SB_STRUC.log_block_size] + inc ecx + mov [ebp + EXTFS.log_block_size], ecx + + ; 512-byte blocks in ext2 blocks. + mov eax, 1 + shl eax, cl + mov [ebp + EXTFS.count_block_in_block], eax + + ; Get block_size/4 (we'll find square later). + shl eax, 7 + mov [ebp + EXTFS.count_pointer_in_block], eax + mov edx, eax + + ; Get block size. + shl eax, 2 + mov [ebp + EXTFS.block_size], eax + + ; Save block size for 2 kernel_alloc calls. + push eax eax + + mov eax, edx + mul edx + mov [ebp + EXTFS.count_pointer_in_block_square], eax + + ; Have temporary block storage for get_inode procedure, and one for global procedure. + KERNEL_ALLOC [ebp + EXTFS.ext2_save_block], .error + KERNEL_ALLOC [ebp + EXTFS.ext2_temp_block], .error + + mov [ebp + EXTFS.partition_flags], 0x00000000 + mov eax, [ebx + EXT2_SB_STRUC.feature_ro_compat] + and eax, not EXT2_FEATURE_RO_COMPAT_SUPP + jnz .read_only + + mov eax, [ebx + EXT2_SB_STRUC.feature_incompat] + and eax, EXT4_FEATURE_INCOMPAT_W_NOT_SUPP + jz @F + + .read_only: + ; Mark as read-only. + or [ebp + EXTFS.partition_flags], EXT2_RO + @@: + mov ecx, [ebx + EXT2_SB_STRUC.blocks_per_group] + mov [ebp + EXTFS.blocks_per_group], ecx + + movzx ecx, word[ebx + EXT2_SB_STRUC.inode_size] + mov [ebp + EXTFS.inode_size], ecx + + ; Allocate for three inodes (loop would be overkill). + push ecx ecx ecx + + KERNEL_ALLOC [ebp + EXTFS.ext2_save_inode], .error + KERNEL_ALLOC [ebp + EXTFS.ext2_temp_inode], .error + KERNEL_ALLOC [ebp + EXTFS.root_inode], .error + + ; Read root inode. + mov ebx, eax + mov eax, EXT2_ROOT_INO + call ext2_inode_read + + test eax, eax + jnz .error + + ;call ext2_sb_update + ; Sync the disk. + ;mov esi, [ebp + PARTITION.Disk] + ;call disk_sync ; eax contains error code, if any. + + mov eax, ebp ; Return pointer to EXTFS. + pop edi esi ebp ebx + ret + + ; Error in setting up. + .error: + ; Free save block. + KERNEL_FREE [ebp + EXTFS.ext2_save_block], .fail + + ; Temporary block. + KERNEL_FREE [ebp + EXTFS.ext2_temp_block], .fail + + ; All inodes. + KERNEL_FREE [ebp + EXTFS.ext2_save_inode], .fail + KERNEL_FREE [ebp + EXTFS.ext2_temp_inode], .fail + KERNEL_FREE [ebp + EXTFS.root_inode], .fail + + mov eax, ebp + call free + + jmp .fail +endp + +; FUNCTIONS PROVIDED BY SYSCALLS. + +;--------------------------------------------------------------------- +; Frees up all ext2 structures. +; Input: eax = pointer to EXTFS. +;--------------------------------------------------------------------- +proc ext2_free + push ebp + + xchg ebp, eax + stdcall kernel_free, [ebp+EXTFS.ext2_save_block] + stdcall kernel_free, [ebp+EXTFS.ext2_temp_block] + stdcall kernel_free, [ebp+EXTFS.ext2_save_inode] + stdcall kernel_free, [ebp+EXTFS.ext2_temp_inode] + stdcall kernel_free, [ebp+EXTFS.root_inode] + + xchg ebp, eax + call free + + pop ebp + ret +endp + +;--------------------------------------------------------------------- +; Read disk folder. +; Input: ebp = pointer to EXTFS structure. +; esi + [esp + 4] = file name. +; ebx = pointer to parameters from sysfunc 70. +; Output: ebx = blocks read (or 0xFFFFFFFF, folder not found) +; eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_ReadFolder: + ;DEBUGF 1, "Reading folder.\n" + call ext2_lock + cmp byte [esi], 0 + jz .root_folder + + push ebx + stdcall ext2_inode_find, [esp + 4 + 4] ; Get inode. + pop ebx + + mov esi, [ebp + EXTFS.ext2_save_inode] + test eax, eax + jnz .error_ret + + ; If not a directory, then return with error. + test [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR + jz .error_not_found + jmp @F + + .root_folder: + mov esi, [ebp + EXTFS.root_inode] + test [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR + jz .error_root + + ; Copy the inode. + mov edi, [ebp + EXTFS.ext2_save_inode] + mov ecx, [ebp + EXTFS.inode_size] + shr ecx, 2 + + push edi + rep movsd + pop esi + + @@: + cmp [esi + EXT2_INODE_STRUC.i_size], 0 ; Folder is empty. + je .error_empty_dir + + mov edx, [ebx + 16] + push edx ; Result address [edi + 28]. + push 0 ; End of the current block in folder [edi + 24] + push dword[ebx + 12] ; Blocks to read [edi + 20] + push dword[ebx + 4] ; The first wanted file [edi + 16] + push dword[ebx + 8] ; Flags [edi + 12] + push 0 ; Read files [edi + 8] + push 0 ; Files in folder [edi + 4] + push 0 ; Number of blocks read in dir (and current block index) [edi] + + ; Fill header with zeroes. + mov edi, edx + mov ecx, 32/4 + rep stosd + + mov edi, esp ; edi = pointer to local variables. + add edx, 32 ; edx = mem to return. + + xor ecx, ecx ; Get number of first block. + call ext2_inode_get_block + test eax, eax + jnz .error_get_block + + mov eax, ecx + mov ebx, [ebp + EXTFS.ext2_save_block] + call ext2_block_read ; Read the block. + test eax, eax + jnz .error_get_block + + mov eax, ebx ; esi: current directory record + add eax, [ebp + EXTFS.block_size] + + mov [edi + 24], eax + + mov ecx, [edi + 16] ; ecx = first wanted (flags ommited) + + .find_wanted_start: + jecxz .find_wanted_end + + .find_wanted_cycle: + cmp [ebx + EXT2_DIR_STRUC.inode], 0 ; Don't count unused inode in total files. + jz @F + + inc dword [edi + 4] ; EXT2 files in folder. + dec ecx + @@: + movzx eax, [ebx + EXT2_DIR_STRUC.rec_len] + + cmp eax, 12 ; Minimum record length. + jb .error_bad_len + test eax, 0x3 ; Record length must be divisible by four. + jnz .error_bad_len + + sub [esi + EXT2_INODE_STRUC.i_size], eax ; Subtract "processed record" length directly from inode. + add ebx, eax ; Go to next record. + cmp ebx, [edi + 24] ; If not reached the next block, continue. + jb .find_wanted_start + + push .find_wanted_start + .end_block: ; Get the next block. + cmp [esi + EXT2_INODE_STRUC.i_size], 0 + jle .end_dir + + inc dword [edi] ; Number of blocks read. + + ; Read the next block. + push ecx + mov ecx, [edi] + call ext2_inode_get_block + test eax, eax + jnz .error_get_block + + mov eax, ecx + mov ebx, [ebp + EXTFS.ext2_save_block] + call ext2_block_read + test eax, eax + jnz .error_get_block + pop ecx + + mov eax, ebx + add eax, [ebp + EXTFS.block_size] + mov [edi + 24], eax ; Update the end of the current block variable. + ret + + .wanted_end: + loop .find_wanted_cycle ; Skip files till we reach wanted one. + + ; First requisite file. + .find_wanted_end: + mov ecx, [edi + 20] + .wanted_start: ; Look for first_wanted + count. + jecxz .wanted_end + + cmp [ebx + EXT2_DIR_STRUC.inode], 0 ; if (inode == 0): not used; + jz .empty_rec + + ; Increment "files in dir" and "read files" count. + inc dword [edi + 8] + inc dword [edi + 4] + + push edi ecx + mov edi, edx ; Zero out till the name field. + xor eax, eax + mov ecx, 40 / 4 + rep stosd + pop ecx edi + + push ebx edi edx + mov eax, [ebx + EXT2_DIR_STRUC.inode] ; Get the child inode. + mov ebx, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_read + test eax, eax + jnz .error_read_subinode + + lea edi, [edx + 8] + + mov eax, [ebx + EXT2_INODE_STRUC.i_ctime] ; Convert time in NTFS format. + xor edx, edx + add eax, 3054539008 ; (369 * 365 + 89) * 24 * 3600 + adc edx, 2 + call ntfs_datetime_to_bdfe.sec + + mov eax, [ebx + EXT2_INODE_STRUC.i_atime] + xor edx, edx + add eax, 3054539008 + adc edx, 2 + call ntfs_datetime_to_bdfe.sec + + mov eax, [ebx + EXT2_INODE_STRUC.i_mtime] + xor edx, edx + add eax, 3054539008 + adc edx, 2 + call ntfs_datetime_to_bdfe.sec + + pop edx + test [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR ; If folder, don't report size. + jnz @F + + mov eax, [ebx + EXT2_INODE_STRUC.i_size] ; Low size + stosd + mov eax, [ebx + EXT2_INODE_STRUC.i_dir_acl] ; High size + stosd + + xor dword [edx], FS_FT_DIR ; Mark as file. + @@: + xor dword [edx], FS_FT_DIR ; Mark as directory. + + ; Copy name after converting from UTF-8 to CP866. + push ecx esi + mov esi, [esp + 12] + movzx ecx, [esi + EXT2_DIR_STRUC.name_len] + lea edi, [edx + 40] + lea esi, [esi + EXT2_DIR_STRUC.name] + call utf8_to_cp866 + and byte [edi], 0 + pop esi ecx edi ebx + + cmp byte [edx + 40], '.' ; If it begins with ".", mark it as hidden. + jne @F + or dword [edx], FS_FT_HIDDEN + + @@: + add edx, 40 + 264 ; Go to next record. + dec ecx + .empty_rec: + movzx eax, [ebx + EXT2_DIR_STRUC.rec_len] + + cmp eax, 12 ; Illegal length. + jb .error_bad_len + test eax, 0x3 ; Not a multiple of four. + jnz .error_bad_len + + sub [esi + EXT2_INODE_STRUC.i_size], eax ; Subtract directly from the inode. + add ebx, eax + cmp ebx, [edi + 24] ; Are we at the end of the block? + jb .wanted_start + + push .wanted_start + jmp .end_block + + .end_dir: ; End of the directory. + call ext2_unlock + mov edx, [edi + 28] ; Address of where to return data. + mov ebx, [edi + 8] ; EXT2_read_in_folder + mov ecx, [edi + 4] ; EXT2_files_in_folder + mov dword [edx], 1 ; Version + mov [edx + 4], ebx + mov [edx + 8], ecx + + lea esp, [edi + 32] + + xor eax, eax ; Reserved in current implementation. + lea edi, [edx + 12] + mov ecx, 20 / 4 + rep stosd + + ;DEBUGF 1, "Returning with: %x.\n", eax + ret + + .error_bad_len: + mov eax, ERROR_FS_FAIL + + .error_read_subinode: + .error_get_block: + ; Fix the stack. + lea esp, [edi + 32] + + .error_ret: + or ebx, -1 + push eax + call ext2_unlock + pop eax + ;DEBUGF 1, "Returning with: %x.\n", eax + ret + + .error_empty_dir: ; inode of folder without blocks. + .error_root: ; Root has to be a folder. + mov eax, ERROR_FS_FAIL + jmp .error_ret + + .error_not_found: ; Directory not found. + mov eax, ERROR_FILE_NOT_FOUND + jmp .error_ret + +;--------------------------------------------------------------------- +; Read file from the hard disk. +; Input: esi + [esp + 4] = points to file name. +; ebx = pointer to paramteres from sysfunc 70. +; ebp = pointer to EXTFS structure. +; Output: ebx = bytes read (0xFFFFFFFF -> file not found) +; eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_Read: + ;DEBUGF 1, "Attempting read.\n" + call ext2_lock + cmp byte [esi], 0 + jnz @F + + .this_is_nofile: + call ext2_unlock + or ebx, -1 + mov eax, ERROR_ACCESS_DENIED + ret + + @@: + push ebx + stdcall ext2_inode_find, [esp + 4 + 4] + pop ebx + + mov esi, [ebp + EXTFS.ext2_save_inode] + test eax, eax + jz @F + + call ext2_unlock + or ebx, -1 + mov eax, ERROR_FILE_NOT_FOUND + ret + + @@: + mov ax, [esi + EXT2_INODE_STRUC.i_mode] + and ax, EXT2_S_IFMT ; Leave the file format in AX. + + ; Check if file. + cmp ax, EXT2_S_IFREG + jne .this_is_nofile + + mov edi, [ebx + 16] + mov ecx, [ebx + 12] + + mov eax, [ebx + 4] + mov edx, [ebx + 8] ; edx:eax = start byte number. + + ; Check if file is big enough for us. + cmp [esi + EXT2_INODE_STRUC.i_dir_acl], edx + ja .size_greater + jb .size_less + + cmp [esi + EXT2_INODE_STRUC.i_size], eax + ja .size_greater + + .size_less: + call ext2_unlock + xor ebx, ebx + mov eax, ERROR_END_OF_FILE + ret + + @@: + .size_greater: + add eax, ecx ; Get last byte. + adc edx, 0 + + ; Check if we've to read whole file, or till requested. + cmp [esi + EXT2_INODE_STRUC.i_dir_acl], edx + ja .read_till_requested + jb .read_whole_file + cmp [esi + EXT2_INODE_STRUC.i_size], eax + jae .read_till_requested + + .read_whole_file: + push 1 ; Read till the end of file. + mov ecx, [esi + EXT2_INODE_STRUC.i_size] + sub ecx, [ebx + 4] ; To read = (size - starting byte) + jmp @F + + .read_till_requested: + push 0 ; Read as much as requested. + + @@: + ; ecx = bytes to read. + ; edi = return memory + ; [esi] = starting byte. + + push ecx ; Number of bytes to read. + + ; Get part of the first block. + mov edx, [ebx + 8] + mov eax, [ebx + 4] + div [ebp + EXTFS.block_size] + + push eax ; Save block counter to stack. + + push ecx + mov ecx, eax + call ext2_inode_get_block + test eax, eax + jnz .error_at_first_block + + mov ebx, [ebp + EXTFS.ext2_save_block] + mov eax, ecx + call ext2_block_read + test eax, eax + jnz .error_at_first_block + + pop ecx + ; Get index inside block. + add ebx, edx + + neg edx + add edx, [ebp + EXTFS.block_size] ; Get number of bytes in this block. + + ; If it's smaller than total bytes to read, then only one block. + cmp ecx, edx + jbe .only_one_block + + mov eax, ecx + sub eax, edx + mov ecx, edx + + push esi + mov esi, ebx + rep movsb ; Copy part of 1st block. + pop esi + + ; eax -> bytes to read. + .calc_blocks_count: + mov ebx, edi ; Read the block in ebx. + xor edx, edx + div [ebp + EXTFS.block_size] ; Get number of bytes in last block in edx. + mov edi, eax ; Get number of blocks in edi. + + @@: + ; Test if all blocks are done. + test edi, edi + jz .finish_block + + inc dword [esp] + mov ecx, [esp] + call ext2_inode_get_block + + test eax, eax + jnz .error_at_read_cycle + + mov eax, ecx ; ebx already contains desired values. + call ext2_block_read + + test eax, eax + jnz .error_at_read_cycle + + add ebx, [ebp + EXTFS.block_size] + + dec edi + jmp @B + + ; In edx -- number of bytes in the last block. + .finish_block: + test edx, edx + jz .end_read + + pop ecx ; Pop block counter in ECX. + inc ecx + call ext2_inode_get_block + + test eax, eax + jnz .error_at_finish_block + + mov edi, ebx + mov eax, ecx + mov ebx, [ebp + EXTFS.ext2_save_block] + call ext2_block_read + + test eax, eax + jnz .error_at_finish_block + + mov ecx, edx + mov esi, ebx + rep movsb ; Copy last piece of block. + jmp @F + + .end_read: + pop ecx ; Pop block counter in ECX. + @@: + pop ebx ; Number of bytes read. + call ext2_unlock + pop eax ; If we were asked to read more, say EOF. + test eax, eax + jz @F + + mov eax, ERROR_END_OF_FILE + ret + @@: + xor eax, eax + ;DEBUGF 1, "Returning with: %x.\n", eax + ret + + .only_one_block: + mov esi, ebx + rep movsb ; Copy last piece of block. + jmp .end_read + + .error_at_first_block: + pop edx + .error_at_read_cycle: + pop ebx + .error_at_finish_block: + pop ecx edx + or ebx, -1 + push eax + call ext2_unlock + pop eax + + ;DEBUGF 1, "Returning with: %x.\n", eax + ret + +;--------------------------------------------------------------------- +; Read file information from block device. +; Input: esi + [esp + 4] = file name. +; ebx = pointer to paramteres from sysfunc 70. +; ebp = pointer to EXTFS structure. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_GetFileInfo: + ;DEBUGF 1, "Calling for file info, for: %s.\n", esi + call ext2_lock + mov edx, [ebx + 16] + cmp byte [esi], 0 + jz .is_root + + push edx + stdcall ext2_inode_find, [esp + 4 + 4] + mov ebx, edx + pop edx + + mov esi, [ebp + EXTFS.ext2_save_inode] + test eax, eax + jz @F + + push eax + call ext2_unlock + pop eax + ;DEBUGF 1, "Returning with: %x.\n", eax + ret + + .is_root: + xor ebx, ebx ; Clear out first char, since we don't want to set hidden flag on root. + mov esi, [ebp + EXTFS.root_inode] + + @@: + xor eax, eax + mov edi, edx + mov ecx, 40/4 + rep stosd ; Zero fill buffer. + + cmp bl, '.' + jne @F + or dword [edx], FS_FT_HIDDEN + + @@: + test [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR + jnz @F ; If a directory, don't put in file size. + + mov eax, [esi + EXT2_INODE_STRUC.i_size] ; Low file size. + mov ebx, [esi + EXT2_INODE_STRUC.i_dir_acl] ; High file size. + mov dword [edx+32], eax + mov dword [edx+36], ebx + + xor dword [edx], FS_FT_DIR ; Next XOR will clean this, to mark it as a file. + @@: + xor dword [edx], FS_FT_DIR ; Mark as directory. + + lea edi, [edx + 8] + + ; Store all time. + mov eax, [esi + EXT2_INODE_STRUC.i_ctime] + xor edx, edx + add eax, 3054539008 + adc edx, 2 + call ntfs_datetime_to_bdfe.sec + + mov eax, [esi + EXT2_INODE_STRUC.i_atime] + xor edx, edx + add eax, 3054539008 + adc edx, 2 + call ntfs_datetime_to_bdfe.sec + + mov eax, [esi + EXT2_INODE_STRUC.i_mtime] + xor edx, edx + add eax, 3054539008 + adc edx, 2 + call ntfs_datetime_to_bdfe.sec + + call ext2_unlock + xor eax, eax + ;DEBUGF 1, "Returning with: %x.\n", eax + ret + +;--------------------------------------------------------------------- +; Set file information for block device. +; Input: esi + [esp + 4] = file name. +; ebx = pointer to paramteres from sysfunc 70. +; ebp = pointer to EXTFS structure. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_SetFileInfo: + test [ebp + EXTFS.partition_flags], EXT2_RO + jz @F + + mov eax, ERROR_UNSUPPORTED_FS + ret + + @@: + push edx esi edi ebx + call ext2_lock + mov edx, [ebx + 16] + + ; Is this read-only? + test [ebp + EXTFS.partition_flags], EXT2_RO + jnz .fail + + ; Not supported for root. + cmp byte [esi], 0 + je .fail + + .get_inode: + push edx + stdcall ext2_inode_find, [esp + 4 + 20] + pop edx + + test eax, eax + jnz @F + + ; Save inode number. + push esi + mov esi, [ebp + EXTFS.ext2_save_inode] + + ; From the BDFE, we ignore read-only file flags, hidden file flags; + ; We ignore system file flags, file was archived or not. + + ; Also ignored is file creation time. ext2 stores "inode modification" + ; time in the ctime field, which is updated by the respective inode_write + ; procedure, and any writes on it would be overwritten anyway. + + ; Access time. + lea edi, [esi + EXT2_INODE_STRUC.i_atime] + lea esi, [edx + 16] + call bdfe_to_unix_time + + ; Modification time. + add esi, 8 + add edi, 8 + call bdfe_to_unix_time + + mov ebx, [ebp + EXTFS.ext2_save_inode] ; Get address of inode into ebx. + pop eax ; Get inode number in eax. + call ext2_inode_write ; eax contains error code, if any. + test eax, eax + jnz @F + + call ext2_sb_update + ; Sync the disk. + mov esi, [ebp + PARTITION.Disk] + call disk_sync ; eax contains error code, if any. + + @@: + push eax + call ext2_unlock + pop eax + + pop ebx edi esi edx + ret + + .fail: + call ext2_sb_update + ; Sync the disk. + mov esi, [ebp + PARTITION.Disk] + call disk_sync ; eax contains error code, if any. + + mov eax, ERROR_UNSUPPORTED_FS + jmp @B + +;--------------------------------------------------------------------- +; Set file information for block device. +; Input: esi + [esp + 4] = file name. +; ebx = pointer to paramteres from sysfunc 70. +; ebp = pointer to EXTFS structure. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_Delete: + ;DEBUGF 1, "Attempting Delete.\n" + test [ebp + EXTFS.partition_flags], EXT2_RO + jz @F + + mov eax, ERROR_UNSUPPORTED_FS + ret + + @@: + push ebx ecx edx esi edi + call ext2_lock + + add esi, [esp + 20 + 4] + + ; Can't delete root. + cmp byte [esi], 0 + jz .error_access_denied + + push esi + stdcall ext2_inode_find, 0 + mov ebx, esi + pop esi + + test eax, eax + jnz .error_access_denied + + mov edx, [ebp + EXTFS.ext2_save_inode] + movzx edx, [edx + EXT2_INODE_STRUC.i_mode] + and edx, EXT2_S_IFMT ; Get the mask. + cmp edx, EXT2_S_IFDIR + jne @F ; If not a directory, we don't need to check if it's empty. + + call ext2_dir_empty ; 0 means directory is empty. + + test eax, eax + jnz .error_access_denied + + @@: + ; Find parent. + call ext2_inode_find_parent + test eax, eax + jnz .error_access_denied + mov eax, esi + + ; Save file/dir & parent inode. + push ebx eax + + cmp edx, EXT2_S_IFDIR + jne @F + + ; Unlink '.' + mov eax, [esp + 4] + call ext2_inode_unlink + cmp eax, 0xFFFFFFFF + je .error_stack8 + + ; Unlink '..' + mov eax, [esp + 4] + mov ebx, [esp] + call ext2_inode_unlink + cmp eax, 0xFFFFFFFF + je .error_stack8 + + @@: + pop eax + mov ebx, [esp] + ; Unlink the inode. + call ext2_inode_unlink + cmp eax, 0xFFFFFFFF + je .error_stack4 + + ; If hardlinks aren't zero, shouldn't completely free. + test eax, eax + jz @F + + add esp, 4 + jmp .disk_sync + + @@: + ; Read the inode. + mov eax, [esp] + mov ebx, [ebp + EXTFS.ext2_save_inode] + call ext2_inode_read + test eax, eax + jnz .error_stack4 + + ; Free inode data. + mov esi, [ebp + EXTFS.ext2_save_inode] + xor ecx, ecx + + @@: + push ecx + call ext2_inode_get_block + test eax, eax + jnz .error_stack8 + mov eax, ecx + pop ecx + + ; If 0, we're done. + test eax, eax + jz @F + + call ext2_block_free + test eax, eax + jnz .error_stack4 + + inc ecx + jmp @B + + @@: + ; Free indirect blocks. + call ext2_inode_free_indirect_blocks + test eax, eax + jnz .error_stack4 + + ; Clear the inode, and add deletion time. + mov edi, [ebp + EXTFS.ext2_save_inode] + xor eax, eax + mov ecx, [ebp + EXTFS.inode_size] + rep stosb + + mov edi, [ebp + EXTFS.ext2_save_inode] + add edi, EXT2_INODE_STRUC.i_dtime + call current_unix_time + + ; Write the inode. + mov eax, [esp] + mov ebx, [ebp + EXTFS.ext2_save_inode] + call ext2_inode_write + test eax, eax + jnz .error_stack4 + + ; Check if directory. + cmp edx, EXT2_S_IFDIR + jne @F + + ; If it is, decrement used_dirs_count. + + ; Get block group. + mov eax, [esp] + dec eax + xor edx, edx + div [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group] + + push eax + call ext2_bg_read_desc + test eax, eax + jz .error_stack8 + + dec [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count] + + pop eax + call ext2_bg_write_desc + + @@: + pop eax + call ext2_inode_free + test eax, eax + jnz .error_access_denied + + .disk_sync: + call ext2_sb_update + + ; Sync the disk. + mov esi, [ebp + PARTITION.Disk] + call disk_sync ; eax contains error code, if any. + + .return: + push eax + call ext2_unlock + pop eax + + pop edi esi edx ecx ebx + ;DEBUGF 1, "And returning with: %x.\n", eax + ret + + .error_stack8: + add esp, 4 + .error_stack4: + add esp, 4 + .error_access_denied: + call ext2_sb_update + + ; Sync the disk. + mov esi, [ebp + PARTITION.Disk] + call disk_sync ; eax contains error code, if any. + + mov eax, ERROR_ACCESS_DENIED + jmp .return + +;--------------------------------------------------------------------- +; Set file information for block device. +; Input: esi + [esp + 4] = file name. +; ebx = pointer to paramteres from sysfunc 70. +; ebp = pointer to EXTFS structure. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_CreateFolder: + ;DEBUGF 1, "Attempting to create folder.\n" + test [ebp + EXTFS.partition_flags], EXT2_RO + jz @F + + mov eax, ERROR_UNSUPPORTED_FS + ret + + @@: + push ebx ecx edx esi edi + call ext2_lock + + add esi, [esp + 20 + 4] + + ; Can't create root, but for CreateFolder already existing directory is success. + cmp byte [esi], 0 + jz .success + + push esi + stdcall ext2_inode_find, 0 + pop esi + + ; If the directory is there, we've succeeded. + test eax, eax + jz .success + + ; Find parent. + call ext2_inode_find_parent + test eax, eax + jnz .error + + ; Inode ID for preference. + mov eax, esi + call ext2_inode_alloc + test eax, eax + jnz .error_full + + ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI. + mov edx, ebx + + push edi + + xor al, al + mov edi, [ebp + EXTFS.ext2_temp_inode] + mov ecx, [ebp + EXTFS.inode_size] + rep stosb + + mov edi, [ebp + EXTFS.ext2_temp_inode] + add edi, EXT2_INODE_STRUC.i_atime + call current_unix_time + + add edi, 8 + call current_unix_time + + pop edi + + mov ebx, [ebp + EXTFS.ext2_temp_inode] + mov [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR or PERMISSIONS + mov eax, edx + call ext2_inode_write + test eax, eax + jnz .error + + ; Link to self. + push edx esi + + mov eax, edx + mov ebx, eax + mov dl, EXT2_FT_DIR + mov esi, self_link + call ext2_inode_link + + pop esi edx + + test eax, eax + jnz .error + + ; Link to parent. + push edx esi + + mov eax, ebx + mov ebx, esi + mov dl, EXT2_FT_DIR + mov esi, parent_link + call ext2_inode_link + + pop esi edx + + test eax, eax + jnz .error + + ; Link parent to child. + mov eax, esi + mov ebx, edx + mov esi, edi + mov dl, EXT2_FT_DIR + call ext2_inode_link + test eax, eax + jnz .error + + ; Get block group descriptor for allocated inode's block. + mov eax, ebx + dec eax + xor edx, edx + + ; EAX = block group. + div [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group] + mov edx, eax + + call ext2_bg_read_desc + test eax, eax + jz .error + + inc [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count] + mov eax, edx + call ext2_bg_write_desc + test eax, eax + jnz .error + + .success: + call ext2_sb_update + + ; Sync the disk. + mov esi, [ebp + PARTITION.Disk] + call disk_sync ; eax contains error code, if any. + + .return: + push eax + call ext2_unlock + pop eax + + pop edi esi edx ecx ebx + ;DEBUGF 1, "Returning with: %x.\n", eax + ret + + .error: + call ext2_sb_update + + ; Sync the disk. + mov esi, [ebp + PARTITION.Disk] + call disk_sync ; eax contains error code, if any. + + mov eax, ERROR_ACCESS_DENIED + jmp .return + + .error_full: + mov eax, ERROR_DISK_FULL + jmp .return + +self_link db ".", 0 +parent_link db "..", 0 + +;--------------------------------------------------------------------- +; Rewrite a file. +; Input: esi + [esp + 4] = file name. +; ebx = pointer to paramteres from sysfunc 70. +; ebp = pointer to EXTFS structure. +; Output: eax = error code. +; ebx = bytes written. +;--------------------------------------------------------------------- +ext2_Rewrite: + ;DEBUGF 1, "Attempting Rewrite.\n" + test [ebp + EXTFS.partition_flags], EXT2_RO + jz @F + + mov eax, ERROR_UNSUPPORTED_FS + ret + + @@: + push ecx edx esi edi + pushad + + call ext2_lock + + add esi, [esp + 16 + 32 + 4] + ; Can't create root. + cmp byte [esi], 0 + jz .error_access_denied + + push esi + stdcall ext2_inode_find, 0 + pop esi + + ; If the file is there, delete it. + test eax, eax + jnz @F + + pushad + + push eax + call ext2_unlock + pop eax + + push dword 0x00000000 + call ext2_Delete + add esp, 4 + + push eax + call ext2_lock + pop eax + + test eax, eax + jnz .error_access_denied_delete + + popad + @@: + ; Find parent. + call ext2_inode_find_parent + test eax, eax + jnz .error_access_denied + + ; Inode ID for preference. + mov eax, esi + call ext2_inode_alloc + test eax, eax + jnz .error_full + + ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI. + mov edx, ebx + + push edi + + xor al, al + mov edi, [ebp + EXTFS.ext2_temp_inode] + mov ecx, [ebp + EXTFS.inode_size] + rep stosb + + mov edi, [ebp + EXTFS.ext2_temp_inode] + add edi, EXT2_INODE_STRUC.i_atime + call current_unix_time + + add edi, 8 + call current_unix_time + + pop edi + + mov ebx, [ebp + EXTFS.ext2_temp_inode] + mov [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG or PERMISSIONS + mov eax, edx + call ext2_inode_write + test eax, eax + jnz .error + + ; Link parent to child. + mov eax, esi + mov ebx, edx + mov esi, edi + mov dl, EXT2_FT_REG_FILE + call ext2_inode_link + test eax, eax + jnz .error + + popad + push eax + call ext2_unlock + pop eax + + push dword 0x00000000 + call ext2_Write + add esp, 4 + + push eax + call ext2_lock + pop eax + + .success: + push eax + call ext2_sb_update + + ; Sync the disk. + mov esi, [ebp + PARTITION.Disk] + call disk_sync ; eax contains error code, if any. + pop eax + + .return: + push eax + call ext2_unlock + pop eax + + pop edi esi edx ecx + + ;DEBUGF 1, "And returning with: %x.\n", eax + ret + + .error: + mov eax, ERROR_ACCESS_DENIED + jmp .success + + .error_access_denied_delete: + popad + + .error_access_denied: + popad + xor ebx, ebx + + mov eax, ERROR_ACCESS_DENIED + jmp .return + + .error_full: + popad + xor ebx, ebx + + mov eax, ERROR_DISK_FULL + jmp .return + +;--------------------------------------------------------------------- +; Write to a file. +; Input: esi + [esp + 4] = file name. +; ebx = pointer to paramteres from sysfunc 70. +; ebp = pointer to EXTFS structure. +; Output: eax = error code. +; ebx = number of bytes written. +;--------------------------------------------------------------------- +ext2_Write: + ;DEBUGF 1, "Attempting write, " + test [ebp + EXTFS.partition_flags], EXT2_RO + jz @F + + mov eax, ERROR_UNSUPPORTED_FS + ret + + @@: + push ecx edx esi edi + call ext2_lock + + add esi, [esp + 16 + 4] + + ; Can't write to root. + cmp byte [esi], 0 + jz .error + + push ebx ecx edx + stdcall ext2_inode_find, 0 + pop edx ecx ebx + ; If file not there, error. + xor ecx, ecx + test eax, eax + jnz .error_file_not_found + + ; Save the inode. + push esi + + ; Check if it's a file. + mov edx, [ebp + EXTFS.ext2_save_inode] + test [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG + jz .error + + mov eax, esi + mov ecx, [ebx + 4] + + call ext2_inode_extend + xor ecx, ecx + test eax, eax + jnz .error_device + + ; ECX contains the size to write, and ESI points to it. + mov ecx, [ebx + 0x0C] + mov esi, [ebx + 0x10] + + ; Save the size of the inode. + mov eax, [edx + EXT2_INODE_STRUC.i_size] + push eax + + xor edx, edx + div [ebp + EXTFS.block_size] + + test edx, edx + jz .start_aligned + + ; Start isn't aligned, so deal with the non-aligned bytes. + mov ebx, [ebp + EXTFS.block_size] + sub ebx, edx + + cmp ebx, ecx + jbe @F + + ; If the size to copy fits in current block, limit to that, instead of the entire block. + mov ebx, ecx + + @@: + ; Copy EBX bytes, in EAX indexed block. + push eax + call ext2_inode_read_entry + test eax, eax + pop eax + jnz .error_inode_size + + push ecx + + mov ecx, ebx + mov edi, ebx + add edi, edx + rep movsb + + pop ecx + + ; Write the block. + call ext2_inode_write_entry + test eax, eax + jnz .error_inode_size + + add [esp], ebx + sub ecx, ebx + jz .write_inode + + .start_aligned: + cmp ecx, [ebp + EXTFS.block_size] + jb @F + + mov eax, [esp] + xor edx, edx + div [ebp + EXTFS.block_size] + + push eax + mov edx, [esp + 8] + call ext2_inode_blank_entry + test eax, eax + pop eax + jnz .error_inode_size + + push ecx + + mov ecx, [ebp + EXTFS.block_size] + mov edi, [ebp + EXTFS.ext2_save_block] + rep movsb + + pop ecx + + call ext2_inode_write_entry + test eax, eax + jnz .error_inode_size + + mov eax, [ebp + EXTFS.block_size] + sub ecx, eax + add [esp], eax + jmp .start_aligned + + ; Handle the remaining bytes. + @@: + test ecx, ecx + jz .write_inode + + mov eax, [esp] + xor edx, edx + div [ebp + EXTFS.block_size] + + push eax + call ext2_inode_read_entry + test eax, eax + pop eax + jz @F + + push eax + mov edx, [esp + 8] + + call ext2_inode_blank_entry + test eax, eax + pop eax + jnz .error_inode_size + + @@: + push ecx + mov edi, [ebp + EXTFS.ext2_save_block] + rep movsb + pop ecx + + call ext2_inode_write_entry + test eax, eax + jnz .error_inode_size + + add [esp], ecx + xor ecx, ecx + + .write_inode: + mov ebx, [ebp + EXTFS.ext2_temp_inode] + pop eax + mov [ebx + EXT2_INODE_STRUC.i_size], eax + mov eax, [esp] + + call ext2_inode_write + test eax, eax + jnz .error_device + + .success: + call ext2_sb_update + + ; Sync the disk. + mov esi, [ebp + PARTITION.Disk] + call disk_sync ; eax contains error code, if any. + + .return: + push eax + call ext2_unlock + pop eax + + add esp, 4 + + mov ebx, [esp + 12] + sub ebx, ecx + pop edi esi edx ecx + + ;DEBUGF 1, "and returning with: %x.\n", eax + ret + + .error: + mov eax, ERROR_ACCESS_DENIED + jmp .return + + .error_file_not_found: + mov eax, ERROR_FILE_NOT_FOUND + jmp .return + + .error_inode_size: + mov ebx, [ebp + EXTFS.ext2_temp_inode] + pop eax + mov [ebx + EXT2_INODE_STRUC.i_size], eax + mov eax, [esp] + + call ext2_inode_write + + .error_device: + call ext2_sb_update + + ; Sync the disk. + mov esi, [ebp + PARTITION.Disk] + call disk_sync ; eax contains error code, if any. + + mov eax, ERROR_DEVICE + jmp .return + +;--------------------------------------------------------------------- +; Set the end of a file. +; Input: esi + [esp + 4] = file name. +; ebx = pointer to paramteres from sysfunc 70. +; ebp = pointer to EXTFS structure. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_SetFileEnd: + test [ebp + EXTFS.partition_flags], EXT2_RO + jz @F + + mov eax, ERROR_UNSUPPORTED_FS + ret + + @@: + push ebx ecx edx esi edi + call ext2_lock + + add esi, [esp + 20 + 4] + + ; Can't write to root. + cmp byte [esi], 0 + jz .error + + stdcall ext2_inode_find, 0 + ; If file not there, error. + test eax, eax + jnz .error_file_not_found + + ; Check if it's a file. + mov edx, [ebp + EXTFS.ext2_save_inode] + cmp [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG + jne .error + + mov eax, esi + mov ecx, [ebx + 4] + call ext2_inode_extend + test eax, eax + jnz .error_disk_full + + mov eax, esi + call ext2_inode_truncate + test eax, eax + jnz .error_disk_full + + mov eax, esi + mov ebx, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_write + + call ext2_sb_update + + ; Sync the disk. + mov esi, [ebp + PARTITION.Disk] + call disk_sync ; eax contains error code, if any. + + .return: + push eax + call ext2_unlock + pop eax + + pop edi esi edx ecx ebx + ret + + .error: + mov eax, ERROR_ACCESS_DENIED + jmp .return + + .error_file_not_found: + mov eax, ERROR_FILE_NOT_FOUND + jmp .return + + .error_disk_full: + call ext2_sb_update + + ; Sync the disk. + mov esi, [ebp + PARTITION.Disk] + call disk_sync ; eax contains error code, if any. + + mov eax, ERROR_DISK_FULL + jmp .return diff --git a/kernel/branches/Kolibri-acpi/fs/ext2/ext2.inc b/kernel/branches/Kolibri-acpi/fs/ext2/ext2.inc new file mode 100644 index 0000000000..e2b9aea194 --- /dev/null +++ b/kernel/branches/Kolibri-acpi/fs/ext2/ext2.inc @@ -0,0 +1,670 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Contains ext2 structures, and macros. ;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under the terms of the new BSD license. ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Future jobs for driver, in order of preference: +; * clean up existing extents support. +; * add b-tree directories support. +; * add long file support. +; * add journal support. +; * add minor features that come with ext3/4. + +; Recommended move to some kernel-wide bitmap handling code (with a bit of abstraction, of course). + +;--------------------------------------------------------------------- +; Clears a bit. +; Input: eax = index into bitmap. +; [EXTFS.ext2_save_block] = address of bitmap. +; ebp = address of EXTFS. +; Output: Bit cleared. +; eax = non-zero, if already cleared. +;--------------------------------------------------------------------- +bitmap_clear_bit: + push ebx ecx edx + + xor edx, edx + mov ecx, 8 + div ecx + + add eax, [ebp + EXTFS.ext2_save_block] + + ; Get the mask. + mov ebx, 1 + mov ecx, edx + shl ebx, cl + + test [eax], ebx + jz .cleared + + not ebx + and [eax], ebx + + xor eax, eax + .return: + pop edx ecx ebx + ret + + ; Already cleared. + .cleared: + xor eax, eax + not eax + jmp .return + +;--------------------------------------------------------------------- +; Finds free bit in the bitmap. +; Input: ecx = number of bits in the bitmap. +; [EXTFS.ext2_save_block] = address of bitmap. +; ebp = address of EXTFS. +; Output: eax = index of free bit in the bitmap; marked set. +; 0xFFFFFFFF if no free bit found. +;--------------------------------------------------------------------- +ext2_find_free_bit: +bitmap_find_free_bit: + push esi ebx ecx edx + mov esi, [ebp + EXTFS.ext2_save_block] + + ; Get total DWORDS in eax; total bits in last dword, if any, in edx. + xor edx, edx + mov eax, ecx + mov ecx, 32 + div ecx + + mov ecx, eax + xor eax, eax + push edx + + test ecx, ecx + jz .last_bits + + ; Check in the DWORDS. + .dwords: + mov ebx, [esi] + not ebx + + bsf edx, ebx + + ; If 0, then the original value would be 0xFFFFFFFF, hence no free bits. + jz @F + + ; We found the value. Let's return with it. + add esp, 4 + + add eax, edx + jmp .return + + @@: + add esi, 4 + add eax, 32 + loop .dwords + + .last_bits: + ; Check in the last few bits. + pop ecx + test ecx, ecx + jz @F + + mov ebx, [esi] + not ebx + bsf ebx, edx + + ; If 0, no free bits. + jz @F + + ; If free bit is greater than the last known bit, then error. + cmp edx, ecx + jg @F + + add eax, edx + jmp .return + + @@: + ; Didn't find any free bits. + xor eax, eax + not eax + jmp @F + + .return: + mov ecx, edx + mov edx, 1 + shl edx, cl + or [esi], edx + + @@: + pop edx ecx ebx esi + ret + +; Recommended move to some kernel-wide string handling code. +;--------------------------------------------------------------------- +; Find the length of a string. +; Input: esi = source. +; Output: length in ecx +;--------------------------------------------------------------------- +strlen: + push eax esi + xor ecx, ecx + + @@: + lodsb + test al, al + jz .ret + + inc ecx + jmp @B + + .ret: + pop esi eax + ret + +;--------------------------------------------------------------------- +; Convert UTF-8 string to ASCII-string (codepage 866) +; Input: esi = source. +; edi = buffer. +; ecx = length of source. +; Output: destroys eax, esi, edi +;--------------------------------------------------------------------- +utf8_to_cp866: + ; Check for zero-length string. + jecxz .return + + .start: + lodsw + cmp al, 0x80 + jb .ascii + + xchg al, ah ; Big-endian. + cmp ax, 0xd080 + jz .yo1 + + cmp ax, 0xd191 + jz .yo2 + + cmp ax, 0xd090 + jb .unk + + cmp ax, 0xd180 + jb .rus1 + + cmp ax, 0xd190 + jb .rus2 + + .unk: + mov al, '_' + jmp .doit + + .yo1: + mov al, 0xf0 ; Ё capital. + jmp .doit + + .yo2: + mov al, 0xf1 ; ё small. + jmp .doit + + .rus1: + sub ax, 0xd090 - 0x80 + jmp .doit + + .rus2: + sub ax, 0xd18f - 0xEF + + .doit: + stosb + sub ecx, 2 + ja .start + ret + + .ascii: + stosb + dec esi + dec ecx + jnz .start + + .return: + ret + +; Recommended move to some kernel-wide time handling code. + +; Total cumulative seconds till each month. +cumulative_seconds_in_month: + .january: dd 0 * (60 * 60 * 24) + .february: dd 31 * (60 * 60 * 24) + .march: dd 59 * (60 * 60 * 24) + .april: dd 90 * (60 * 60 * 24) + .may: dd 120 * (60 * 60 * 24) + .june: dd 151 * (60 * 60 * 24) + .july: dd 181 * (60 * 60 * 24) + .august: dd 212 * (60 * 60 * 24) + .september: dd 243 * (60 * 60 * 24) + .october: dd 273 * (60 * 60 * 24) + .november: dd 304 * (60 * 60 * 24) + .december: dd 334 * (60 * 60 * 24) + +current_bdfe_time: + dd 0 +current_bdfe_date: + dd 0 + +;--------------------------------------------------------------------- +; Stores current unix time. +; Input: edi = buffer to output Unix time. +;--------------------------------------------------------------------- +current_unix_time: + push eax esi + mov esi, current_bdfe_time + + ; Just a small observation: + ; The CMOS is a pretty bad source to get time from. One shouldn't rely on it, + ; since it messes up the time by tiny bits. Of course, this is all technical, + ; but one can look it up on the osdev wiki. What is better is to get the time + ; from CMOS during boot, then update system time using a more accurate timer. + ; I'll probably add that after the Summer of Code, so TODO! TODO! TODO!. + + ; Get time from CMOS. + ; Seconds. + mov al, 0x00 + out 0x70, al + in al, 0x71 + call bcd2bin + mov [esi + 0], al + + ; Minute. + mov al, 0x02 + out 0x70, al + in al, 0x71 + call bcd2bin + mov [esi + 1], al + + ; Hour. + mov al, 0x04 + out 0x70, al + in al, 0x71 + call bcd2bin + mov [esi + 2], al + + ; Get date. + + ; Day. + mov al, 0x7 + out 0x70, al + in al, 0x71 + call bcd2bin + mov [esi + 4], al + + ; Month. + mov al, 0x8 + out 0x70, al + in al, 0x71 + call bcd2bin + mov [esi + 5], al + + ; Year. + mov al, 0x9 + out 0x70, al + in al, 0x71 + call bcd2bin + add ax, 2000 ; CMOS only returns last two digits. + ; Note that everywhere in KolibriOS this is used. + ; This is hacky, since the RTC can be incorrectly set + ; to something before 2000. + mov [esi + 6], ax + + call bdfe_to_unix_time + pop esi eax + ret + +;--------------------------------------------------------------------- +; Convert time+date from BDFE to Unix time. +; Input: esi = pointer to BDFE time+date. +; edi = buffer to output Unix time. +;--------------------------------------------------------------------- +bdfe_to_unix_time: + push eax ebx ecx edx + mov dword[edi], 0x00000000 + + ; The minimum representable time is 1901-12-13. + cmp word[esi + 6], 1901 + jb .ret + jg .max + + cmp byte[esi + 5], 12 + jb .ret + + cmp byte[esi + 4], 13 + jbe .ret + jg .convert + + ; Check if it is more than the maximum representable time. + .max: + ; The maximum representable time is 2038-01-19. + cmp word[esi + 6], 2038 + jg .ret + jb .convert + + cmp byte[esi + 5], 1 + jg .ret + + cmp byte[esi + 4], 19 + jge .ret + + ; Convert the time. + .convert: + ; Get if current year is leap year in ECX. + xor ecx, ecx + mov ebx, 4 + xor edx, edx + + cmp word[esi + 6], 1970 + jb .negative + + movzx eax, word[esi + 6] ; Year. + cmp byte[esi + 5], 3 ; If the month is less than March, than that year doesn't matter. + jge @F + + test eax, 3 + ; Not a leap year. + jnz @F + + inc ecx + @@: + ; Number of leap years between two years = ((end date - 1)/4) - (1970/4) + dec eax + div ebx + sub eax, 1970/4 + + ; EAX is the number of leap years. + add eax, ecx + mov ecx, (60 * 60 * 24) ; Seconds in a day. + mul ecx + + ; Account for leap years, i.e., one day extra for each. + add [edi], eax + + ; Get total days in EAX. + movzx eax, byte[esi + 4] + dec eax + mul ecx + + ; Account for days. + add [edi], eax + + ; Account for month. + movzx eax, byte[esi + 5] + dec eax + mov eax, [cumulative_seconds_in_month + (eax * 4)] + add [edi], eax + + ; Account for year. + movzx eax, word[esi + 6] + sub eax, 1970 + mov ecx, (60 * 60 * 24) * 365 ; Seconds in a year. + mul ecx + add [edi], eax + + ; Seconds. + movzx eax, byte[esi + 0] + add [edi], eax + + ; Minutes. + movzx eax, byte[esi + 1] + mov ecx, 60 + mul ecx + add [edi], eax + + ; Hours. + movzx eax, byte[esi + 2] + mov ecx, (60 * 60) + mul ecx + add [edi], eax + + ; The time wanted is before the epoch; handle it here. + .negative: + ; TODO. + + .ret: + pop edx ecx ebx eax + ret + +; Recommended move to some kernel-wide alloc handling code. +macro KERNEL_ALLOC store, label +{ + call kernel_alloc + mov store, eax + test eax, eax + jz label +} + +macro KERNEL_FREE data, label +{ + cmp data, 0 + jz label + push data + call kernel_free +} + +struct EXTFS PARTITION + lock MUTEX + partition_flags dd ? + log_block_size dd ? + block_size dd ? + count_block_in_block dd ? + blocks_per_group dd ? + global_desc_table dd ? + root_inode dd ? ; Pointer to root inode in memory. + inode_size dd ? + count_pointer_in_block dd ? ; (block_size / 4) + count_pointer_in_block_square dd ? ; (block_size / 4)**2 + ext2_save_block dd ? ; Block for 1 global procedure. + ext2_temp_block dd ? ; Block for small procedures. + ext2_save_inode dd ? ; inode for global procedures. + ext2_temp_inode dd ? ; inode for small procedures. + groups_count dd ? + superblock rd 1024/4 +ends + +; EXT2 revisions. +EXT2_GOOD_OLD_REV = 0 + +; For fs_type. +FS_TYPE_UNDEFINED = 0 +FS_TYPE_EXT = 2 + +; Some set inodes. +EXT2_BAD_INO = 1 +EXT2_ROOT_INO = 2 +EXT2_ACL_IDX_INO = 3 +EXT2_ACL_DATA_INO = 4 +EXT2_BOOT_LOADER_INO = 5 +EXT2_UNDEL_DIR_INO = 6 + +; EXT2_SUPER_MAGIC. +EXT2_SUPER_MAGIC = 0xEF53 +EXT2_VALID_FS = 1 + +; Flags defining i_mode values. +EXT2_S_IFMT = 0xF000 ; Mask for file type. + +EXT2_S_IFREG = 0x8000 ; Regular file. +EXT2_S_IFDIR = 0x4000 ; Directory. + +EXT2_S_IRUSR = 0x0100 ; User read +EXT2_S_IWUSR = 0x0080 ; User write +EXT2_S_IXUSR = 0x0040 ; User execute +EXT2_S_IRGRP = 0x0020 ; Group read +EXT2_S_IWGRP = 0x0010 ; Group write +EXT2_S_IXGRP = 0x0008 ; Group execute +EXT2_S_IROTH = 0x0004 ; Others read +EXT2_S_IWOTH = 0x0002 ; Others write +EXT2_S_IXOTH = 0x0001 ; Others execute + +PERMISSIONS = EXT2_S_IRUSR or EXT2_S_IWUSR \ + or EXT2_S_IRGRP or EXT2_S_IWGRP \ + or EXT2_S_IROTH or EXT2_S_IWOTH + +; File type defining values in directory entry. +EXT2_FT_REG_FILE = 1 ; Regular file. +EXT2_FT_DIR = 2 ; Directory. + +; Flags used by KolibriOS. +FS_FT_HIDDEN = 2 +FS_FT_DIR = 0x10 ; Directory. + +; ext2 partition flags. +EXT2_RO = 0x01 + +FS_FT_ASCII = 0 ; Name in ASCII. +FS_FT_UNICODE = 1 ; Name in Unicode. + +EXT2_FEATURE_INCOMPAT_FILETYPE = 0x0002 ; Have file type in directory entry. +EXT4_FEATURE_INCOMPAT_EXTENTS = 0x0040 ; Extents. +EXT4_FEATURE_INCOMPAT_FLEX_BG = 0x0200 ; Flexible block groups. + +EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER = 0x0001 ; Sparse Superblock +EXT2_FEATURE_RO_COMPAT_LARGE_FILE = 0x0002 ; Large file support (64-bit file size) + +; Implemented ext[2,3,4] features. +EXT4_FEATURE_INCOMPAT_SUPP = EXT2_FEATURE_INCOMPAT_FILETYPE \ + or EXT4_FEATURE_INCOMPAT_EXTENTS \ + or EXT4_FEATURE_INCOMPAT_FLEX_BG + +; Implemented features which otherwise require "read-only" mount. +EXT2_FEATURE_RO_COMPAT_SUPP = EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER \ + or EXT2_FEATURE_RO_COMPAT_LARGE_FILE + +; ext4 features not support for write. +EXT4_FEATURE_INCOMPAT_W_NOT_SUPP = EXT4_FEATURE_INCOMPAT_EXTENTS \ + or EXT4_FEATURE_INCOMPAT_FLEX_BG + +; Flags specified in i_flags. +EXT2_EXTENTS_FL = 0x00080000 ; Extents. + +struct EXT2_INODE_STRUC + i_mode dw ? + i_uid dw ? + i_size dd ? + i_atime dd ? + i_ctime dd ? + i_mtime dd ? + i_dtime dd ? + i_gid dw ? + i_links_count dw ? + i_blocks dd ? + i_flags dd ? + i_osd1 dd ? + i_block rd 15 + i_generation dd ? + i_file_acl dd ? + i_dir_acl dd ? + i_faddr dd ? + i_osd2 dd ? ; 12 bytes. +ends + +struct EXT2_DIR_STRUC + inode dd ? + rec_len dw ? + name_len db ? + file_type db ? + name db ? ; 255 (max) bytes. +ends + +struct EXT2_BLOCK_GROUP_DESC + block_bitmap dd ? ; +0 + inode_bitmap dd ? ; +4 + inode_table dd ? ; +8 + free_blocks_count dw ? ; +12 + free_inodes_count dw ? ; +14 + used_dirs_count dw ? ; +16 + pad dw ? ; +18 + reserved rb 12 ; +20 +ends + +struct EXT2_SB_STRUC + inodes_count dd ? ; +0 + blocks_count dd ? ; +4 + r_block_count dd ? ; +8 + free_block_count dd ? ; +12 + free_inodes_count dd ? ; +16 + first_data_block dd ? ; +20 + log_block_size dd ? ; +24 + log_frag_size dd ? ; +28 + blocks_per_group dd ? ; +32 + frags_per_group dd ? ; +36 + inodes_per_group dd ? ; +40 + mtime dd ? ; +44 + wtime dd ? ; +48 + mnt_count dw ? ; +52 + max_mnt_count dw ? ; +54 + magic dw ? ; +56 + state dw ? ; +58 + errors dw ? ; +60 + minor_rev_level dw ? ; +62 + lastcheck dd ? ; +64 + check_intervals dd ? ; +68 + creator_os dd ? ; +72 + rev_level dd ? ; +76 + def_resuid dw ? ; +80 + def_resgid dw ? ; +82 + first_ino dd ? ; +84 + inode_size dw ? ; +88 + block_group_nr dw ? ; +90 + feature_compat dd ? ; +92 + feature_incompat dd ? ; +96 + feature_ro_compat dd ? ; +100 + uuid rb 16 ; +104 + volume_name rb 16 ; +120 + last_mounted rb 64 ; +136 + algo_bitmap dd ? ; +200 + prealloc_blocks db ? ; +204 + preallock_dir_blocks db ? ; +205 + reserved_gdt_blocks dw ? ; +206 + journal_uuid rb 16 ; +208 + journal_inum dd ? ; +224 + journal_dev dd ? ; +228 + last_orphan dd ? ; +232 + hash_seed rd 4 ; +236 + def_hash_version db ? ; +252 + reserved rb 3 ; +253 (reserved) + default_mount_options dd ? ; +256 + first_meta_bg dd ? ; +260 + mkfs_time dd ? ; +264 + jnl_blocks rd 17 ; +268 + blocks_count_hi dd ? ; +336 + r_blocks_count_hi dd ? ; +340 + free_blocks_count_hi dd ? ; +344 + min_extra_isize dw ? ; +348 + want_extra_isize dw ? ; +350 + flags dd ? ; +352 + raid_stride dw ? ; +356 + mmp_interval dw ? ; +358 + mmp_block dq ? ; +360 + raid_stripe_width dd ? ; +368 + log_groups_per_flex db ? ; +372 +ends + +; Header block extents. +struct EXT4_EXTENT_HEADER + eh_magic dw ? ; Magic value of 0xF30A, for ext4. + eh_entries dw ? ; Number of blocks covered by the extent. + eh_max dw ? ; Capacity of entries. + eh_depth dw ? ; Tree depth (if 0, extents in the array are not extent indexes) + eh_generation dd ? ; ??? +ends + +; Extent. +struct EXT4_EXTENT + ee_block dd ? ; First logical block extent covers. + ee_len dw ? ; Number of blocks covered by extent. + ee_start_hi dw ? ; Upper 16 bits of 48-bit address (unused in KOS) + ee_start_lo dd ? ; Lower 32 bits of 48-bit address. +ends + +; Index on-disk structure; pointer to block of extents/indexes. +struct EXT4_EXTENT_IDX + ei_block dd ? ; Covers logical blocks from here. + ei_leaf_lo dd ? ; Lower 32-bits of pointer to the physical block of the next level. + ei_leaf_hi dw ? ; Higher 16-bits (unused in KOS). + ei_unused dw ? ; Reserved. +ends \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/fs/ext2/inode.inc b/kernel/branches/Kolibri-acpi/fs/ext2/inode.inc new file mode 100644 index 0000000000..a743064fa7 --- /dev/null +++ b/kernel/branches/Kolibri-acpi/fs/ext2/inode.inc @@ -0,0 +1,1850 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Contains ext2 inode handling code. ;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under the terms of the new BSD license. ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;--------------------------------------------------------------------- +; Receives block number from extent-based inode. +; Input: ecx = number of block in inode +; esi = address of extent header +; ebp = pointer to EXTFS +; Output: ecx = address of next block, if successful +; eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext4_block_recursive_search: + cmp word [esi + EXT4_EXTENT_HEADER.eh_magic], 0xF30A ;EXT4_EXT_MAGIC + jne .fail + + movzx ebx, [esi + EXT4_EXTENT_HEADER.eh_entries] + add esi, sizeof.EXT4_EXTENT_HEADER + cmp word [esi - sizeof.EXT4_EXTENT_HEADER + EXT4_EXTENT_HEADER.eh_depth], 0 + je .leaf_block ;листовой ли это блок? + + ;не листовой блок, а индексный ; eax - ext4_extent_idx + test ebx, ebx + jz .fail ;пустой индексный блок -> ошибка + + ;цикл по индексам экстентов + @@: + cmp ebx, 1 ;у индексов не хранится длина, + je .end_search_index ;поэтому, если остался последний - то это нужный + + cmp ecx, [esi + EXT4_EXTENT_IDX.ei_block] + jb .fail + + cmp ecx, [esi + sizeof.EXT4_EXTENT_IDX + EXT4_EXTENT_IDX.ei_block] ;блок слeдующего индекса + jb .end_search_index ;следующий дальше - значит текущий, то что нам нужен + + add esi, sizeof.EXT4_EXTENT_IDX + dec ebx + jmp @B + + .end_search_index: + ;ebp указывает на нужный extent_idx, считываем следующий блок + mov ebx, [ebp + EXTFS.ext2_temp_block] + mov eax, [esi + EXT4_EXTENT_IDX.ei_leaf_lo] + call ext2_block_read + test eax, eax + jnz .fail + mov esi, ebx + jmp ext4_block_recursive_search ;рекурсивно прыгаем в начало + + .leaf_block: ;листовой блок esi - ext4_extent + ;цикл по экстентам + @@: + test ebx, ebx + jz .fail ;ни один узел не подошел - ошибка + + mov edx, [esi + EXT4_EXTENT.ee_block] + cmp ecx, edx + jb .fail ;если меньше, значит он был в предыдущих блоках -> ошибка + + movzx edi, [esi + EXT4_EXTENT.ee_len] + add edx, edi + cmp ecx, edx + jb .end_search_extent ;нашли нужный блок + + add esi, sizeof.EXT4_EXTENT + dec ebx + jmp @B + + .end_search_extent: + mov edx, [esi + EXT4_EXTENT.ee_start_lo] + sub ecx, [esi + EXT4_EXTENT.ee_block] ;разница в ext4 блоках + add ecx, edx + xor eax, eax + ret + + .fail: + mov eax, ERROR_FS_FAIL + ret + +;--------------------------------------------------------------------- +; Frees triply indirect block. +; Input: eax = triply indirect block. +; [ebp + EXTFS.ext2_save_inode] = the inode. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_inode_free_triply_indirect: + push ebx edx + + test eax, eax + jz .success + push eax + ; Read the triple indirect block. + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + pop eax + jnz .fail + + ; Free the triple indirect block. + call ext2_block_free + test eax, eax + jnz .fail + + mov edx, ebx + add edx, [ebp + EXTFS.block_size] + + @@: + mov eax, [ebx] + test eax, eax + jz .success + + call ext2_inode_free_doubly_indirect + cmp eax, 1 + je .success + cmp eax, 0xFFFFFFFF + je .fail + + add ebx, 4 + cmp ebx, edx + jb @B + + .success: + xor eax, eax + .ret: + pop edx ebx + ret + + .fail: + xor eax, eax + not eax + jmp .ret + +;--------------------------------------------------------------------- +; Frees double indirect block. +; Input: eax = double indirect block. +; [ebp + EXTFS.ext2_save_inode] = the inode. +; Output: eax = error code, 1 implies finished, ~0 implies error +;--------------------------------------------------------------------- +ext2_inode_free_doubly_indirect: + push ebx edx + + test eax, eax + jz .complete + push eax + ; Read the double indirect block. + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + pop eax + jnz .fail + + call ext2_block_free + test eax, eax + jnz .fail + + mov edx, ebx + add edx, [ebp + EXTFS.block_size] + + @@: + mov eax, [ebx] + test eax, eax + jz .complete + + call ext2_block_free + test eax, eax + jnz .fail + + add ebx, 4 + cmp ebx, edx + jb @B + + .success: + xor eax, eax + .ret: + pop edx ebx + ret + + .complete: + xor eax, eax + inc eax + jmp .ret + + .fail: + xor eax, eax + not eax + jmp .ret + +;--------------------------------------------------------------------- +; Frees all indirect blocks. +; Input: ebp = pointer to EXTFS. +; [ebp + EXTFS.ext2_save_inode] = the inode. +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_inode_free_indirect_blocks: + push edi + + mov edi, [ebp + EXTFS.ext2_save_inode] + + ; Free indirect block. + mov eax, [edi + EXT2_INODE_STRUC.i_block + 12*4] + test eax, eax + jz .success + + call ext2_block_free + test eax, eax + jnz .fail + + mov eax, [edi + EXT2_INODE_STRUC.i_block + 13*4] + call ext2_inode_free_doubly_indirect + cmp eax, 1 + je .success + cmp eax, 0xFFFFFFFF + je .fail + + mov eax, [edi + EXT2_INODE_STRUC.i_block + 14*4] + call ext2_inode_free_triply_indirect + test eax, eax + jnz .fail + + .success: + xor eax, eax + .ret: + pop edi + ret + + .fail: + xor eax, eax + not eax + jmp .ret + +;--------------------------------------------------------------------- +; Allocates block for inode. +; Input: esi = address of inode +; ebp = pointer to EXTFS. +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_inode_calloc_block: + push ecx + + ; TODO: fix to have correct preference. + mov eax, EXT2_ROOT_INO + call ext2_block_calloc + test eax, eax + jnz .fail + + mov ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size] + mov eax, 2 + shl eax, cl + add [esi + EXT2_INODE_STRUC.i_blocks], eax + + .success: + xor eax, eax + .ret: + pop ecx + ret + + .fail: + xor eax, eax + not eax + jmp .ret + +;--------------------------------------------------------------------- +; Sets block ID for indirect-addressing inode. +; Input: ecx = index of block in inode +; edi = block ID to set to +; esi = address of inode +; ebp = pointer to EXTFS. +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_inode_set_block: + push ebx ecx edx + + ; 0 to 11: direct blocks. + cmp ecx, 12 + jb .direct_block + + ; Indirect blocks + sub ecx, 12 + cmp ecx, [ebp + EXTFS.count_pointer_in_block] + jb .indirect_block + + ; Double indirect blocks. + sub ecx, [ebp + EXTFS.count_pointer_in_block] + cmp ecx, [ebp + EXTFS.count_pointer_in_block_square] + jb .double_indirect_block + + ; Triple indirect blocks. + sub ecx, [ebp + EXTFS.count_pointer_in_block_square] + + ; Get triply-indirect block in temp_block. + mov eax, [esi + EXT2_INODE_STRUC.i_block + 14*4] + test eax, eax + jnz @F + + call ext2_inode_calloc_block + test eax, eax + jnz .fail_alloc + + mov [esi + EXT2_INODE_STRUC.i_block + 14*4], ebx + mov eax, ebx + + @@: + push eax + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz .fail_alloc_4 + + ; Get index in triply-indirect block. + xor edx, edx + mov eax, ecx + div [ebp + EXTFS.count_pointer_in_block_square] + + ; eax: index in triply-indirect block, edx: index in doubly-indirect block. + lea ecx, [ebx + eax*4] + mov eax, [ebx + eax*4] + test eax, eax + jnz @F + + call ext2_inode_calloc_block + test eax, eax + jnz .fail_alloc_4 + + mov [ecx], ebx + + mov eax, [esp] + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_write + test eax, eax + jnz .fail_alloc_4 + + mov eax, [ecx] + @@: + mov [esp], eax + call ext2_block_read + test eax, eax + jnz .fail_alloc_4 + + mov eax, edx + jmp @F + + .double_indirect_block: + ; Get doubly-indirect block. + mov eax, [esi + EXT2_INODE_STRUC.i_block + 13*4] + test eax, eax + jnz .double_indirect_present + + call ext2_inode_calloc_block + test eax, eax + jnz .fail_alloc + + mov [esi + EXT2_INODE_STRUC.i_block + 13*4], ebx + mov eax, ebx + + .double_indirect_present: + ; Save block we're at. + push eax + + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz .fail_alloc_4 + + mov eax, ecx + @@: + xor edx, edx + div [ebp + EXTFS.count_pointer_in_block] + + ; eax: index in doubly-indirect block, edx: index in indirect block. + lea ecx, [ebx + edx*4] + push ecx + + lea ecx, [ebx + eax*4] + cmp dword[ecx], 0 + jne @F + + call ext2_inode_calloc_block + test eax, eax + jnz .fail_alloc_8 + + mov [ecx], ebx + + mov eax, [esp + 4] + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_write + test eax, eax + jnz .fail_alloc_8 + + @@: + mov eax, [ecx] + push eax + call ext2_block_read + test eax, eax + jnz .fail_alloc_12 + + pop eax + pop ecx + mov [ecx], edi + call ext2_block_write + + add esp, 4 + jmp .return + + .indirect_block: + ; Get index of indirect block. + mov eax, [esi + EXT2_INODE_STRUC.i_block + 12*4] + test eax, eax + jnz @F + + call ext2_inode_calloc_block + test eax, eax + jnz .fail_alloc + + mov [esi + EXT2_INODE_STRUC.i_block + 12*4], ebx + mov eax, ebx + + @@: + push eax + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz .fail_alloc_4 + + ; Get the block ID. + mov [ebx + ecx*4], edi + pop eax + call ext2_block_write + jmp .return + + .direct_block: + mov [esi + EXT2_INODE_STRUC.i_block + ecx*4], edi + xor eax, eax + + .return: + pop edx ecx ebx + ret + + .fail_alloc: + xor eax, eax + not eax + jmp .return + + .fail_alloc_12: + add esp, 4 + .fail_alloc_8: + add esp, 4 + .fail_alloc_4: + add esp, 4 + jmp .fail_alloc + +;--------------------------------------------------------------------- +; Receives block ID from indirect-addressing inode. +; Input: ecx = index of block in inode +; esi = address of inode +; ebp = pointer to EXTFS +; Output: ecx = block ID, if successful +; eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_inode_get_block: + ; If inode is extent-based, use ext4_block_recursive_search. + test [esi + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL + jz @F + + pushad + + ; Get extent header in EBP. + add esi, EXT2_INODE_STRUC.i_block + call ext4_block_recursive_search + mov PUSHAD_ECX, ecx + mov PUSHAD_EAX, eax + + popad + ret + + @@: + ; 0 to 11: direct blocks. + cmp ecx, 12 + jb .get_direct_block + + ; Indirect blocks + sub ecx, 12 + cmp ecx, [ebp + EXTFS.count_pointer_in_block] + jb .get_indirect_block + + ; Double indirect blocks. + sub ecx, [ebp + EXTFS.count_pointer_in_block] + cmp ecx, [ebp + EXTFS.count_pointer_in_block_square] + jb .get_double_indirect_block + + ; Triple indirect blocks. + sub ecx, [ebp + EXTFS.count_pointer_in_block_square] + push edx ebx + + ; Get triply-indirect block in temp_block. + mov eax, [esi + EXT2_INODE_STRUC.i_block + 14*4] + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz .fail + + ; Get index in triply-indirect block. + xor edx, edx + mov eax, ecx + div [ebp + EXTFS.count_pointer_in_block_square] + + ; eax: index in triply-indirect block, edx: index in doubly-indirect block. + mov eax, [ebx + eax*4] + test eax, eax + jz .fail_triple_indirect_block + + call ext2_block_read + test eax, eax + jnz .fail + + mov eax, edx + jmp @F + + .get_double_indirect_block: + push edx ebx + + ; Get doubly-indirect block. + mov eax, [esi + EXT2_INODE_STRUC.i_block + 13*4] + test eax, eax + jz .fail_double_indirect_block + + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz .fail + + mov eax, ecx + @@: + xor edx, edx + div [ebp + EXTFS.count_pointer_in_block] + + ; eax: index in doubly-indirect block, edx: index in indirect block. + mov eax, [ebx + eax*4] + test eax, eax + jz .fail_double_indirect_block + + call ext2_block_read + test eax, eax + jnz .fail + + mov ecx, [ebx + edx*4] + .fail: + pop ebx edx + + ret + + .get_indirect_block: + push ebx + + ; Get index of indirect block. + mov eax, [esi + EXT2_INODE_STRUC.i_block + 12*4] + test eax, eax + jz .fail_indirect_block + + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz @F + + mov ecx, [ebx + ecx*4] + @@: + pop ebx + + ret + + .get_direct_block: + mov ecx, [esi + EXT2_INODE_STRUC.i_block + ecx*4] + xor eax, eax + + ret + + .fail_indirect_block: + pop ebx + + .fail_triple_indirect_block: + xor eax, eax + xor ecx, ecx + ret + + .fail_double_indirect_block: + pop ebx edx + jmp .fail_triple_indirect_block + +;--------------------------------------------------------------------- +; Get block containing inode. +; Input: eax = inode number. +; ebp = pointer to EXTFS. +; Output: ebx = block (hard disk) containing inode. +; edx = index inside block. +; eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_read_block_of_inode: + pushad + + dec eax + xor edx, edx + + ; EAX = block group. + div [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group] + + push edx ; Index in group. + + mov edx, 32 + mul edx ; Get index of descriptor in global_desc_table. + + ; eax: inode group offset relative to global descriptor table start + ; Find the block this block descriptor is in. + div [ebp + EXTFS.block_size] + add eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.first_data_block] + inc eax + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz .return + + add ebx, edx ; edx: local index of descriptor inside block + mov eax, [ebx + EXT2_BLOCK_GROUP_DESC.inode_table] ; Block number of inode table - in ext2 terms. + mov ecx, [ebp + EXTFS.log_block_size] + shl eax, cl + + ; eax: points to inode table on HDD. + mov esi, eax + + ; Add local address of inode. + pop eax + mov ecx, [ebp + EXTFS.inode_size] + mul ecx ; (index * inode_size) + + mov ebp, 512 + div ebp ; Divide by hard disk block size. + + add eax, esi ; Found block to read. + mov ebx, eax ; Get it inside ebx. + + xor eax, eax + .return: + mov PUSHAD_EAX, eax + mov PUSHAD_EBX, ebx + mov PUSHAD_EDX, edx + + popad + ret + +;--------------------------------------------------------------------- +; Sets content of inode by number. +; Input: eax = inode number. +; ebx = address from where to write inode content. +; ebp = pointer to EXTFS. +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_inode_write: + push edx edi esi ecx ebx + mov esi, ebx + + ; Ext2 actually stores time of modification of inode in ctime. + lea edi, [ebx + EXT2_INODE_STRUC.i_ctime] + call current_unix_time + + ; Get block where inode is situated. + call ext2_read_block_of_inode + test eax, eax + jnz .error + + mov eax, ebx ; Get block into EAX. + mov ebx, [ebp + EXTFS.ext2_temp_block] + + mov ecx, eax ; Save block. + call fs_read32_sys + test eax, eax + jz @F + + .error: + mov eax, ERROR_DEVICE + jmp .return + + @@: + mov eax, ecx + mov ecx, [ebp + EXTFS.inode_size] + mov edi, edx ; The index into the block. + add edi, ebx + rep movsb + + ; Write the block. + call fs_write32_sys + + .return: + pop ebx ecx esi edi edx + ret + +;--------------------------------------------------------------------- +; Get content of inode by number. +; Input: eax = inode number. +; ebx = address where to store inode content. +; ebp = pointer to EXTFS. +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_inode_read: + push edx edi esi ecx ebx + mov edi, ebx + + ; Get block where inode is situated. + call ext2_read_block_of_inode + test eax, eax + jnz .error + + mov eax, ebx ; Get block into EAX. + mov ebx, [ebp + EXTFS.ext2_temp_block] + call fs_read32_sys + test eax, eax + jz @F + + .error: + mov eax, ERROR_DEVICE + jmp .return + + @@: + mov ecx, [ebp + EXTFS.inode_size] + mov esi, edx ; The index into the inode. + add esi, ebx + rep movsb + + xor eax, eax + .return: + pop ebx ecx esi edi edx + ret + +;--------------------------------------------------------------------- +; Seek inode from the path. +; Input: esi + [esp + 4] = name. +; ebp = pointer to EXTFS. +; Output: eax = error code (0 implies no error) +; esi = inode number. +; dl = first byte of file/folder name. +; [ext2_data.ext2_save_inode] stores the inode. +;--------------------------------------------------------------------- +ext2_inode_find: + mov edx, [ebp + EXTFS.root_inode] + + ; Check for empty root. + cmp [edx + EXT2_INODE_STRUC.i_blocks], 0 + je .error_empty_root + + ; Check for root. + cmp byte[esi], 0 + jne .next_path_part + + push edi ecx + mov esi, [ebp + EXTFS.root_inode] + mov edi, [ebp + EXTFS.ext2_save_inode] + mov ecx, [ebp + EXTFS.inode_size] + rep movsb + pop ecx edi + + xor eax, eax + xor dl, dl + mov esi, EXT2_ROOT_INO + ret 4 + + .next_path_part: + push [edx + EXT2_INODE_STRUC.i_blocks] + xor ecx, ecx + + .folder_block_cycle: + push ecx + xchg esi, edx + call ext2_inode_get_block + xchg esi, edx + test eax, eax + jnz .error_get_inode_block + + mov eax, ecx + mov ebx, [ebp + EXTFS.ext2_save_block] ; Get directory records from directory. + call ext2_block_read + test eax, eax + jnz .error_get_block + + push esi + push edx + call ext2_block_find_parent + pop edx + pop edi ecx + + cmp edi, esi ; Did something match? + je .next_folder_block ; No, move to next block. + + cmp byte [esi], 0 ; Reached the "end" of path successfully. + jnz @F + cmp dword[esp + 8], 0 + je .get_inode_ret + mov esi, [esp + 8] + mov dword[esp + 8], 0 + + @@: + mov eax, [ebx + EXT2_DIR_STRUC.inode] + mov ebx, [ebp + EXTFS.ext2_save_inode] + call ext2_inode_read + test eax, eax + jnz .error_get_inode + + movzx eax, [ebx + EXT2_INODE_STRUC.i_mode] + and eax, EXT2_S_IFMT ; Get the mask. + cmp eax, EXT2_S_IFDIR + jne .not_found ; Matched till part, but directory entry we got doesn't point to folder. + + pop ecx ; Stack top contains number of blocks. + mov edx, ebx + jmp .next_path_part + + .next_folder_block: + ; Next block in current folder. + pop eax ; Get blocks counter. + sub eax, [ebp + EXTFS.count_block_in_block] + jle .not_found + + push eax + inc ecx + jmp .folder_block_cycle + + .not_found: + mov eax, ERROR_FILE_NOT_FOUND + ret 4 + + .get_inode_ret: + pop ecx ; Stack top contains number of blocks. + + mov dl, [ebx + EXT2_DIR_STRUC.name] ; First character of file-name. + mov eax, [ebx + EXT2_DIR_STRUC.inode] + mov ebx, [ebp + EXTFS.ext2_save_inode] + mov esi, eax + + ; If we can't get the inode, eax contains the error. + call ext2_inode_read + ret 4 + + .error_get_inode_block: + .error_get_block: + pop ecx + .error_get_inode: + pop ebx + .error_empty_root: + mov eax, ERROR_FS_FAIL + ret 4 + +;--------------------------------------------------------------------- +; Seeks parent inode from path. +; Input: esi = path. +; ebp = pointer to EXTFS. +; Output: eax = error code. +; esi = inode. +; edi = pointer to file name. +;--------------------------------------------------------------------- +ext2_inode_find_parent: + push esi + xor edi, edi + + .loop: + cmp byte[esi], '/' + jne @F + + mov edi, esi + inc esi + jmp .loop + + @@: + inc esi + cmp byte[esi - 1], 0 + jne .loop + + ; If it was just a filename (without any additional directories), + ; use the last byte as "parent path". + cmp edi, 0 + jne @F + + pop edi + dec esi + jmp .get_inode + + ; It had some additional directories, so handle it that way. + @@: + mov byte[edi], 0 + inc edi + pop esi + + .get_inode: + push ebx edx + stdcall ext2_inode_find, 0 + pop edx ebx + + .return: + ret + +;--------------------------------------------------------------------- +; Link an inode. +; Input: eax = inode on which to link. +; ebx = inode to link. +; dl = file type. +; esi = name. +; ebp = pointer to EXTFS. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_inode_link: + push eax + push esi edi ebx ecx edx + + ; Get string length, and then directory entry structure size. + call strlen + add ecx, 8 + + push esi ebx ecx + + xor ecx, ecx + mov esi, [ebp + EXTFS.ext2_temp_inode] + mov ebx, esi + + call ext2_inode_read + test eax, eax + jnz .error_inode_read + + ; Get the maximum addressible i_block index by (i_blocks/(2 << s_log_block_size)). + ; Note that i_blocks contains number of reserved 512B blocks, which is why we've to + ; find out the ext2 blocks. + mov eax, 2 + mov ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size] + shl eax, cl + mov ecx, eax + + mov eax, [esi + EXT2_INODE_STRUC.i_blocks] + xor edx, edx + + div ecx + + ; EAX is the maximum index inside i_block we can go. + push eax + push dword 0 + + ; ECX contains the "block inside i_block" index. + xor ecx, ecx + @@: + call ext2_inode_get_block + test eax, eax + jnz .error_get_inode_block + test ecx, ecx + jz .alloc_block ; We've got no block here, so allocate one. + + push ecx ; Save block number. + + mov eax, ecx + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz .error_block_read + + ; Try to find free space in current block. + mov ecx, [esp + 8] + call ext2_block_find_fspace + test eax, eax + jz .found + + cmp eax, 0x00000001 + jne .next_iter + + ; This block wasn't linking to the next block, so fix that, and use the next one. + ; Write the block. + pop eax + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_write + test eax, eax + jnz .error_get_inode_block + + inc dword [esp] + mov ecx, [esp] + call ext2_inode_get_block + test eax, eax + jnz .error_get_inode_block + + test ecx, ecx + jz .alloc_block + + ; If there was a block there, prepare it for our use! + push ecx + jmp .prepare_block + + .next_iter: + add esp, 4 + + inc dword [esp] + mov ecx, [esp] + cmp ecx, [esp + 4] + jbe @B + + .alloc_block: + mov eax, [esp + 12] ; Get inode ID of what we're linking. + call ext2_block_calloc + test eax, eax + jnz .error_get_inode_block + + mov ecx, [esp] ; Get the index of it inside the inode. + mov edi, ebx ; And what to set to. + call ext2_inode_set_block + test eax, eax + jnz .error_get_inode_block + + ; Update i_size. + mov eax, [ebp + EXTFS.block_size] + add [esi + EXT2_INODE_STRUC.i_size], eax + + ; Update i_blocks. + mov ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size] + mov eax, 2 + shl eax, cl + add [esi + EXT2_INODE_STRUC.i_blocks], eax + + ; Write the inode. + mov eax, [esp + 40] + mov ebx, esi + call ext2_inode_write + test eax, eax + jnz .error_get_inode_block + + push edi ; Save the block we just allocated. + + ; If we've allocated/using-old-block outside of loop, prepare it. + .prepare_block: + mov eax, [esp] + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz .error_block_read + + mov edi, ebx + mov eax, [ebp + EXTFS.block_size] + mov [edi + EXT2_DIR_STRUC.rec_len], ax + + .found: + pop edx + add esp, 8 + pop ecx ebx esi + + push ebx + mov [edi], ebx ; Save inode. + + mov eax, [esp + 4] ; Get EDX off the stack -- contains the file_type. + cmp [ebp + EXTFS.superblock + EXT2_SB_STRUC.rev_level], EXT2_GOOD_OLD_REV + je .name + + ; Set the file-type. + mov [edi + EXT2_DIR_STRUC.file_type], al + + .name: + ; Save name. + sub ecx, 8 + mov [edi + EXT2_DIR_STRUC.name_len], cl + add edi, 8 + rep movsb + + ; Write block. + mov eax, edx + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_write + test eax, eax + jnz .error_block_write + + mov eax, [esp] + mov ebx, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_read + test eax, eax + jnz .error_block_write + + pop eax + inc [ebx + EXT2_INODE_STRUC.i_links_count] + call ext2_inode_write + test eax, eax + jnz .error + + xor eax, eax + .ret: + pop edx ecx ebx edi esi + add esp, 4 + ret + + .error_block_read: + add esp, 4 + .error_get_inode_block: + add esp, 8 + .error_inode_read: + add esp, 8 + .error_block_write: + add esp, 4 + .error: + xor eax, eax + not eax + jmp .ret + +;--------------------------------------------------------------------- +; Unlink an inode. +; Input: eax = inode from which to unlink. +; ebx = inode to unlink. +; ebp = pointer to EXTFS. +; Output: eax = number of links to inode, after unlinking (0xFFFFFFFF implies error) +;--------------------------------------------------------------------- +ext2_inode_unlink: + push ebx ecx edx esi edi + + push ebx + mov ebx, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_read + + test eax, eax + jnz .fail_get_inode + + ; The index into the inode block data. + push dword 0 + mov esi, [ebp + EXTFS.ext2_temp_inode] + + .loop: + mov ecx, [esp] + call ext2_inode_get_block + + test eax, eax + jnz .fail_loop + test ecx, ecx + jz .fail_loop + + mov eax, ecx + mov edi, eax + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz .fail_loop + + ; edi -> block. + .first_dir_entry: + mov eax, [esp + 4] + cmp [ebx], eax + jne @F + + mov dword[ebx], 0 ; inode. + mov word[ebx + 6], 0 ; name_len + file_type. + jmp .write_block + + @@: + mov edx, ebx + add edx, [ebp + EXTFS.block_size] + push edx + + mov edx, ebx + movzx ecx, [ebx + EXT2_DIR_STRUC.rec_len] + add ebx, ecx + + .dir_entry: + cmp [ebx], eax + jne @F + + mov cx, [ebx + EXT2_DIR_STRUC.rec_len] + add [edx + EXT2_DIR_STRUC.rec_len], cx + add esp, 4 + jmp .write_block + + @@: + mov edx, ebx + movzx ecx, [ebx + EXT2_DIR_STRUC.rec_len] + + ; If it's a zero length entry, error. + test ecx, ecx + jz .fail_inode + + add ebx, ecx + + cmp ebx, [esp] + jb .dir_entry + + add esp, 4 + inc dword[esp] + jmp .loop + + .write_block: + mov eax, edi + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_write + test eax, eax + jnz .fail_loop + + add esp, 4 + mov ebx, [ebp + EXTFS.ext2_temp_inode] + mov eax, [esp] + call ext2_inode_read + test eax, eax + jnz .fail_get_inode + + dec word[ebx + EXT2_INODE_STRUC.i_links_count] + movzx eax, word[ebx + EXT2_INODE_STRUC.i_links_count] + push eax + + mov eax, [esp + 4] + call ext2_inode_write + test eax, eax + jnz .fail_loop + + pop eax + add esp, 4 + .return: + pop edi esi edx ecx ebx + ret + + .fail_inode: + add esp, 4 + + .fail_loop: + add esp, 4 + + .fail_get_inode: + add esp, 4 + + .fail: + xor eax, eax + not eax + jmp .return + +;--------------------------------------------------------------------- +; Checks if a directory is empty. +; Input: ebx = inode to check. +; ebp = pointer to EXTFS. +; [EXTFS.ext2_save_inode] = points to saved inode. +; Output: eax = 0 signifies empty directory. +;--------------------------------------------------------------------- +ext2_dir_empty: + push ebx ecx edx + + ; The index into the inode block data. + push dword 0 + mov esi, [ebp + EXTFS.ext2_save_inode] + + .loop: + mov ecx, [esp] + call ext2_inode_get_block + + ; Treat a failure as not-empty. + test eax, eax + jnz .not_empty + test ecx, ecx + jz .empty + + mov eax, ecx + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_read + test eax, eax + jnz .not_empty + + mov edx, ebx + add edx, [ebp + EXTFS.block_size] + + movzx ecx, [ebx + EXT2_DIR_STRUC.rec_len] + add ebx, ecx + + .dir_entry: + ; Process entry. + cmp byte[ebx + EXT2_DIR_STRUC.name_len], 1 + jne @F + + cmp byte[ebx + EXT2_DIR_STRUC.name], '.' + jne .not_empty + + @@: + cmp byte[ebx + EXT2_DIR_STRUC.name_len], 2 + jne .not_empty + + cmp word[ebx + EXT2_DIR_STRUC.name], '..' + jne .not_empty + + @@: + movzx ecx, [ebx + EXT2_DIR_STRUC.rec_len] + add ebx, ecx + + cmp ebx, edx + jb .dir_entry + + inc dword[esp] + jmp .loop + + .empty: + xor eax, eax + .return: + add esp, 4 + pop edx ecx ebx + ret + + .not_empty: + xor eax, eax + not eax + jmp .return + +;--------------------------------------------------------------------- +; Gets the block group's inode bitmap. +; Input: eax = block group. +; Output: eax = if zero, error; else, points to block group descriptor. +; ebx = inode bitmap's block (hard disk). +;--------------------------------------------------------------------- +ext2_bg_read_inode_bitmap: + push ecx + + call ext2_bg_read_desc + test eax, eax + jz .fail + + mov ebx, [eax + EXT2_BLOCK_GROUP_DESC.inode_bitmap] ; Block number of inode bitmap - in ext2 terms. + + .return: + pop ecx + ret + + .fail: + xor eax, eax + jmp .return + +;--------------------------------------------------------------------- +; Allocates a inode. +; Input: eax = inode ID for "preference". +; ebp = pointer to EXTFS. +; Output: Inode marked as set in inode group. +; eax = error code. +; ebx = inode ID. +;--------------------------------------------------------------------- +ext2_inode_alloc: + push [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_count] + push EXT2_BLOCK_GROUP_DESC.free_inodes_count + push [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group] + + lea ebx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.free_inodes_count] + push ebx + + push ext2_bg_read_inode_bitmap + + call ext2_resource_alloc + + ; Inode table starts with 1. + inc ebx + + ret + +;--------------------------------------------------------------------- +; Frees a inode. +; Input: eax = inode ID. +; ebp = pointer to EXTFS. +; Output: inode marked as free in block group. +; eax = error code. +;--------------------------------------------------------------------- +ext2_inode_free: + push edi ecx + + ; Inode table starts with 1. + dec eax + + mov edi, ext2_bg_read_inode_bitmap + xor ecx, ecx + inc cl + call ext2_resource_free + + pop ecx edi + ret + +;--------------------------------------------------------------------- +; Blanks a particular entry in an inode. +; Input: eax = index into block. +; edx = inode. +; ebp = pointer to EXTFS. +; [ebp + EXTFS.ext2_temp_inode] = the inode. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_inode_blank_entry: + push ebx ecx edx edi esi + + mov edi, eax + + mov ecx, eax + mov esi, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_get_block + test eax, eax + jnz .error + + test ecx, ecx + jz .allocate + + mov edx, ecx + mov ecx, [ebp + EXTFS.block_size] + mov edi, [ebp + EXTFS.ext2_temp_block] + xor eax, eax + rep stosb + + mov eax, edx + mov ebx, [ebp + EXTFS.ext2_temp_block] + call ext2_block_write + test eax, eax + jnz .error + + jmp .success + + ; Need to allocate a block. + .allocate: + mov eax, edx + call ext2_block_calloc + test eax, eax + jnz .error + + mov ecx, edi + mov edi, ebx + mov esi, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_set_block + test eax, eax + jnz .error + + mov ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size] + mov eax, 2 + shl eax, cl + add [esi + EXT2_INODE_STRUC.i_blocks], eax + + .success: + xor eax, eax + + .ret: + pop esi edi edx ecx ebx + ret + + .error: + xor eax, eax + not eax + jmp .ret + +;--------------------------------------------------------------------- +; Frees a particular entry in an inode. +; Input: eax = index into block. +; ebp = pointer to EXTFS. +; [ebp + EXTFS.ext2_temp_inode] = the inode. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_inode_free_entry: + push ebx ecx edi esi + + mov edi, eax + + mov ecx, eax + mov esi, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_get_block + test eax, eax + jnz .error + + test ecx, ecx + jz .success + + mov eax, ecx + call ext2_block_free + test eax, eax + jnz .error + + mov ecx, edi + xor edi, edi + mov esi, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_set_block + + mov ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size] + mov eax, 2 + shl eax, cl + sub [esi + EXT2_INODE_STRUC.i_blocks], eax + + .success: + xor eax, eax + + .ret: + pop esi edi ecx ebx + ret + + .error: + xor eax, eax + not eax + jmp .ret + +;--------------------------------------------------------------------- +; Reads a particular entry from an inode. +; Input: eax = index into block. +; ebp = pointer to EXTFS. +; [ebp + EXTFS.ext2_temp_inode] = the inode. +; Output: eax = error code. +; [ebp + EXTFS.ext2_save_block] = the read block. +;--------------------------------------------------------------------- +ext2_inode_read_entry: + push ebx ecx edx esi + + mov ecx, eax + mov esi, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_get_block + test eax, eax + jnz .error + + test ecx, ecx + jz .error + + mov eax, ecx + mov ebx, [ebp + EXTFS.ext2_save_block] + call ext2_block_read + test eax, eax + jnz .error + + .ret: + pop esi edx ecx ebx + ret + + .error: + xor eax, eax + not eax + jmp .ret + +;--------------------------------------------------------------------- +; Writes a particular entry from an inode. +; Input: eax = index into block. +; ebp = pointer to EXTFS. +; [ebp + EXTFS.ext2_temp_inode] = the inode. +; [ebp + EXTFS.ext2_save_block] = the block to write. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_inode_write_entry: + push ebx ecx edx esi + + mov ecx, eax + mov esi, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_get_block + test eax, eax + jnz .error + + test ecx, ecx + jz .error + + mov eax, ecx + mov ebx, [ebp + EXTFS.ext2_save_block] + call ext2_block_write + test eax, eax + jnz .error + + .ret: + pop esi edx ecx ebx + ret + + .error: + xor eax, eax + not eax + jmp .ret + +;--------------------------------------------------------------------- +; Extends inode to said size. +; Input: eax = inode ID. +; ecx = size to extend to. +; ebp = pointer to EXTFS. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_inode_extend: + push ebx ecx edx esi edi + + ; Save the inode. + push eax + + ; Read the inode. + mov ebx, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_read + test eax, eax + jnz .error + + mov eax, [ebx + EXT2_INODE_STRUC.i_size] + cmp eax, ecx + jge .success + + ; Save the size of the inode. + push eax + + ; ECX contains the size we've to write. + sub ecx, eax + xor edx, edx + div [ebp + EXTFS.block_size] + + test edx, edx + jz .start_aligned + + ; Start isn't aligned, so deal with the non-aligned bytes. + mov esi, [ebp + EXTFS.block_size] + sub esi, edx + + cmp esi, ecx + jbe @F + + ; If the size to entend to fits in current block, limit to that. + mov esi, ecx + + @@: + ; Clear ESI bytes, in EAX indexed block. + push eax + call ext2_inode_read_entry + test eax, eax + pop eax + jnz .error_inode_size + + push eax ecx + + xor eax, eax + mov ecx, esi + mov edi, ebx + add edi, edx + + rep stosb + + pop ecx eax + + ; Write the block. + call ext2_inode_write_entry + test eax, eax + jnz .error_inode_size + + add [esp], esi + sub ecx, esi + jz .write_inode + + .start_aligned: + cmp ecx, [ebp + EXTFS.block_size] + jb @F + + mov eax, [esp] + xor edx, edx + div [ebp + EXTFS.block_size] + + mov edx, [esp + 4] + call ext2_inode_blank_entry + + test eax, eax + jnz .error_inode_size + + mov eax, [ebp + EXTFS.block_size] + sub ecx, eax + add [esp], eax + jmp .start_aligned + + ; Handle the remaining bytes. + @@: + test ecx, ecx + jz .write_inode + + mov eax, [esp] + xor edx, edx + div [ebp + EXTFS.block_size] + + mov edx, [esp + 4] + call ext2_inode_blank_entry + + test eax, eax + jnz .error_inode_size + add [esp], ecx + + .write_inode: + mov ebx, [ebp + EXTFS.ext2_temp_inode] + pop eax + mov [ebx + EXT2_INODE_STRUC.i_size], eax + mov eax, [esp] + call ext2_inode_write + + test eax, eax + jnz .error + + .success: + xor eax, eax + + .ret: + add esp, 4 + + pop edi esi edx ecx ebx + ret + + .error_inode_size: + mov ebx, [ebp + EXTFS.ext2_temp_inode] + pop eax + mov [ebx + EXT2_INODE_STRUC.i_size], eax + mov eax, [esp] + call ext2_inode_write + + .error: + xor eax, eax + not eax + jmp .ret + +;--------------------------------------------------------------------- +; Truncates inode to said size. +; Input: eax = inode ID. +; ecx = size to truncate to. +; ebp = pointer to EXTFS. +; Output: eax = error code. +;--------------------------------------------------------------------- +ext2_inode_truncate: + push ebx ecx edx esi edi + + ; Save the inode. + push eax + + ; Read the inode. + mov ebx, [ebp + EXTFS.ext2_temp_inode] + call ext2_inode_read + test eax, eax + jnz .error + + mov eax, [ebx + EXT2_INODE_STRUC.i_size] + cmp ecx, eax + jge .success + + ; Save the size of the inode. + push eax + + ; ECX contains the size we've to truncate. + sub ecx, eax + not ecx + inc ecx + xor edx, edx + div [ebp + EXTFS.block_size] + + test edx, edx + jz .start_aligned + + ; Start isn't aligned, so deal with the non-aligned bytes. + mov esi, edx + + cmp esi, ecx + jbe @F + + ; If the size to truncate is smaller than the un-aligned bytes + ; we're going to have to mark neccessary bytes from the EOF + ; as 0. + push eax + call ext2_inode_read_entry + test eax, eax + pop eax + jnz .error_inode_size + + mov edi, [ebp + EXTFS.ext2_save_block] + sub edx, ecx + add edi, edx + + push ecx eax + xor eax, eax + rep stosb + pop eax ecx + + call ext2_inode_write_entry + test eax, eax + jnz .error_inode_size + + sub [esp], ecx + jmp .write_inode + + @@: + ; Since ECX is greater than or equal to the bytes here un-aligned + ; just free the block. + call ext2_inode_free_entry + + sub [esp], esi + sub ecx, esi + jz .write_inode + + .start_aligned: + cmp ecx, [ebp + EXTFS.block_size] + jb @F + + mov eax, [esp] + xor edx, edx + div [ebp + EXTFS.block_size] + dec eax + + call ext2_inode_free_entry + + test eax, eax + jnz .error_inode_size + + mov eax, [ebp + EXTFS.block_size] + sub ecx, eax + sub [esp], eax + jmp .start_aligned + + ; Handle the remaining bytes. + @@: + test ecx, ecx + jz .write_inode + + mov eax, [esp] + xor edx, edx + div [ebp + EXTFS.block_size] + dec eax + + push eax + call ext2_inode_read_entry + test eax, eax + pop eax + jnz .error_inode_size + + mov edi, [ebp + EXTFS.ext2_save_block] + mov edx, [ebp + EXTFS.block_size] + sub edx, ecx + add edi, edx + + push ecx eax + xor eax, eax + rep stosb + pop eax ecx + + call ext2_inode_write_entry + test eax, eax + jnz .error_inode_size + + sub [esp], ecx + + .write_inode: + mov ebx, [ebp + EXTFS.ext2_temp_inode] + pop eax + mov [ebx + EXT2_INODE_STRUC.i_size], eax + mov eax, [esp] + call ext2_inode_write + + test eax, eax + jnz .error + + .success: + xor eax, eax + + .ret: + add esp, 4 + + pop edi esi edx ecx ebx + ret + + .error_inode_size: + mov ebx, [ebp + EXTFS.ext2_temp_inode] + pop eax + mov [ebx + EXT2_INODE_STRUC.i_size], eax + mov eax, [esp] + call ext2_inode_write + + .error: + xor eax, eax + not eax + jmp .ret diff --git a/kernel/branches/Kolibri-acpi/fs/ext2/resource.inc b/kernel/branches/Kolibri-acpi/fs/ext2/resource.inc new file mode 100644 index 0000000000..663632e368 --- /dev/null +++ b/kernel/branches/Kolibri-acpi/fs/ext2/resource.inc @@ -0,0 +1,223 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Contains common resource allocation + freeing code. ;; +;; ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; +;; Distributed under the terms of the new BSD license. ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;--------------------------------------------------------------------- +; Frees a resource (block/inode). +; Input: eax = resource ID. +; edi = function pointer of ext2_bg_*_bitmap form, to +; get bitmap of resource. +; ecx = 0, block; 1, inode. +; ebp = pointer to EXTFS. +; Output: Block marked as free in block group. +; eax = error code. +;--------------------------------------------------------------------- +ext2_resource_free: + push ebx edx esi + + ; Get block group. + sub eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.first_data_block] + xor edx, edx + div [ebp + EXTFS.superblock + EXT2_SB_STRUC.blocks_per_group] + push eax edx + + call edi + test eax, eax + jz .fail + mov esi, eax + + ; Read the bitmap. + mov eax, ebx + mov edx, eax + mov ebx, [ebp + EXTFS.ext2_save_block] + call ext2_block_read + test eax, eax + jnz .fail + + pop eax + ; Mark bit free. + call bitmap_clear_bit + test eax, eax + jz @F + + ; No need to save anything. + xor eax, eax + + add esp, 4 + jmp .return + + @@: + mov eax, edx + mov ebx, [ebp + EXTFS.ext2_save_block] + call ext2_block_write + test eax, eax + jnz .fail + + ; Read the descriptor. + mov eax, [esp] + call ext2_bg_read_desc + test eax, eax + jz .fail_bg_desc_read + + lea eax, [eax + EXT2_BLOCK_GROUP_DESC.free_blocks_count] + shl ecx, 1 + add eax, ecx + inc word[eax] + + lea eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.free_block_count] + shl ecx, 1 + add eax, ecx + inc dword[eax] + + pop eax + call ext2_bg_write_desc + + .return: + pop esi edx ebx + ret + + .fail: + add esp, 4 + .fail_bg_desc_read: + add esp, 4 + xor eax, eax + not eax + jmp .return + +;--------------------------------------------------------------------- +; Allocates a resource. +; Input: eax = inode ID for "preference". +; ebp = pointer to EXTFS. +; [esp + 4], func pointer to ext2_bg_*_bitmap +; [esp + 8], pointer to free_*_count in SB. +; [esp + 12], *_per_group +; [esp + 16], offset to free_*_count in bg descriptor. +; [esp + 20], *_count +; Output: Resource marked as set in block group. +; eax = error code. +; ebx = resource ID. +;--------------------------------------------------------------------- +ext2_resource_alloc: + ; Block allocation is a pretty serious area, since bad allocation + ; can lead to fragmentation. Thus, the best way to allocate that + ; comes to mind is to allocate around an inode as much as possible. + ; On the other hand, this isn't about a single inode/file/directory, + ; and focusing just around the preferred inode would lead to + ; congestion. Thus, after much thought, the chosen allocation algorithm + ; is to search forward, then backward. + push ecx edx esi edi + + cmp dword[esp + 16 + 8], 0 + jnz @F + + ; No free blocks. + xor eax, eax + not eax + pop edi esi edx ecx + ret 20 + + @@: + ; Calculate which block group the preferred inode belongs to. + dec eax + xor edx, edx + + ; EAX = block group. + div [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group] + push eax + push eax + + mov edi, .forward + + .test_block_group: + call dword[esp + 16 + 8 + 4] + test eax, eax + jz .fail + mov esi, eax + + mov eax, ebx + mov edx, eax + mov ebx, [ebp + EXTFS.ext2_save_block] + call ext2_block_read + test eax, eax + jnz .fail + + mov ecx, [esp + 16 + 8 + 12] + call ext2_find_free_bit + cmp eax, 0xFFFFFFFF + jne @F + + mov eax, edi + jmp eax + + @@: + mov ecx, eax + + mov eax, edx + mov ebx, [ebp + EXTFS.ext2_save_block] + call ext2_block_write + test eax, eax + jnz .fail + + ; ecx: the index of the matched entry. + ; [esp]: block group where we found. + ; [esp + 4]: starting block group. + ; esi: block group descriptor. + mov eax, [esp] ; Index of block group in which we found. + mul dword[esp + 16 + 8 + 12] + add eax, ecx + mov ebx, eax + + mov eax, [esp + 16 + 8 + 8] + dec dword[eax] + + mov eax, esi + add eax, [esp + 16 + 8 + 16] + dec word[eax] + + pop eax + call ext2_bg_write_desc + + add esp, 4 + jmp .return + + ; Continue forward. + .forward: + inc dword[esp] + mov eax, [esp] + mul dword[esp + 16 + 8 + 12] + cmp eax, [esp + 16 + 8 + 20] + jbe @F + + ; We need to go backward. + mov eax, [esp + 4] + mov [esp], eax + mov edi, .backward + jmp .backward + + @@: + mov eax, [esp] + jmp .test_block_group + + ; Continue backward. + .backward: + cmp dword[esp], 0 + je .fail + + dec dword[esp] + mov eax, [esp] + jmp .test_block_group + + .return: + pop edi esi edx ecx + ret 20 + + .fail: + add esp, 8 + xor eax, eax + not eax + jmp .return \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/fs/fs-et.inc b/kernel/branches/Kolibri-acpi/fs/fs-et.inc new file mode 100644 index 0000000000..82a23d86c7 --- /dev/null +++ b/kernel/branches/Kolibri-acpi/fs/fs-et.inc @@ -0,0 +1,12 @@ +dir0: + db 'KÕVAKETAS ' + db 'MÄLUKETAS ' + db 'FLOPPIKETAS' + db 0 + +dir1: + db 'ESIMENE ' + db 'TEINE ' + db 'KOLAMS ' + db 'NELJAS ' + db 0 \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/fs/fs.inc b/kernel/branches/Kolibri-acpi/fs/fs.inc index fc9ff61684..65e6862098 100644 --- a/kernel/branches/Kolibri-acpi/fs/fs.inc +++ b/kernel/branches/Kolibri-acpi/fs/fs.inc @@ -24,6 +24,8 @@ iglobal if lang eq sp include 'fs/fs-sp.inc' +else if lang eq et +include 'fs/fs-et.inc' else dir0: db 'HARDDISK ' diff --git a/kernel/branches/Kolibri-acpi/fs/xfs.asm b/kernel/branches/Kolibri-acpi/fs/xfs.asm new file mode 100644 index 0000000000..0ab3de2fac --- /dev/null +++ b/kernel/branches/Kolibri-acpi/fs/xfs.asm @@ -0,0 +1,2769 @@ +include 'xfs.inc' + +; +; This file contains XFS related code. +; For more information on XFS check sources below. +; +; 1. XFS Filesystem Structure, 2nd Edition, Revision 1. Silicon Graphics Inc. 2006 +; 2. Linux source http://kernel.org +; + + +; test partition type (valid XFS one?) +; alloc and fill XFS (see xfs.inc) structure +; this function is called for each partition +; returns 0 (not XFS or invalid) / pointer to partition structure +xfs_create_partition: + push ebx ecx edx esi edi + 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 + + +iglobal +align 4 +xfs_user_functions: + dd xfs_free + dd (xfs_user_functions_end - xfs_user_functions - 4) / 4 + dd xfs_Read + dd xfs_ReadFolder + dd 0;xfs_Rewrite + dd 0;xfs_Write + 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 + + +; 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 -- inode_lo +; edx -- inode_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 + + cmp word[ebx], XFS_DINODE_MAGIC ; test signature + jne .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, '..' + je .shortdir.parent2 + cmp eax, '../' + je .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 + je .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: + + .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 + @@: + + ; 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 + xor edx, edx + add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600 + adc edx, 2 + call ntfs_datetime_to_bdfe.sec + pop edx + + mov eax, [edx + xfs_inode.di_core.di_atime.t_sec] + bswap eax + push edx + xor edx, edx + add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600 + adc edx, 2 + call ntfs_datetime_to_bdfe.sec + pop edx + + mov eax, [edx + xfs_inode.di_core.di_mtime.t_sec] + bswap eax + push edx + xor edx, edx + add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600 + adc edx, 2 + call ntfs_datetime_to_bdfe.sec + 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_Read - 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_Read: + push ebx ecx edx esi edi + call xfs_lock + + add esi, [esp + 24] +;DEBUGF 1,"xfs_Read: %d %d |%s|\n",[ebx+4],[ebx+12],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 + 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/kernel/branches/Kolibri-acpi/fs/xfs.inc b/kernel/branches/Kolibri-acpi/fs/xfs.inc new file mode 100644 index 0000000000..7ba2ce68f8 --- /dev/null +++ b/kernel/branches/Kolibri-acpi/fs/xfs.inc @@ -0,0 +1,518 @@ +; 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 ; those 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/kernel/branches/Kolibri-acpi/gui/font.inc b/kernel/branches/Kolibri-acpi/gui/font.inc index 9bae06b8bd..f1395531bb 100644 --- a/kernel/branches/Kolibri-acpi/gui/font.inc +++ b/kernel/branches/Kolibri-acpi/gui/font.inc @@ -233,6 +233,8 @@ align 4 FONT_I: if lang eq sp file 'char_sp.mt' + else if lang eq et + file 'char_et.mt' else file 'char.mt' end if @@ -241,6 +243,8 @@ align 4 FONT_II: if lang eq sp file 'char2_sp.mt' + else if lang eq et + file 'char2_et.mt' else file 'char2.mt' end if diff --git a/kernel/branches/Kolibri-acpi/kernel.asm b/kernel/branches/Kolibri-acpi/kernel.asm index ebf2705791..565ffa2452 100644 --- a/kernel/branches/Kolibri-acpi/kernel.asm +++ b/kernel/branches/Kolibri-acpi/kernel.asm @@ -144,6 +144,8 @@ use16 if lang eq sp include "kernelsp.inc" ; spanish kernel messages +else if lang eq et +version db 'Kolibri OS versioon 0.7.7.0+ ',13,10,13,10,0 else version db 'Kolibri OS version 0.7.7.0+ ',13,10,13,10,0 end if @@ -696,6 +698,19 @@ no_mode_0x12: mov [mem_BACKGROUND], 4 mov [img_background], static_background_data +; set clipboard + + xor eax, eax + mov [clipboard_slots], eax + mov [clipboard_write_lock], eax + stdcall kernel_alloc, 4096 + test eax, eax + jnz @f + + dec eax +@@: + mov [clipboard_main_list], eax + ; SET UP OS TASK mov esi, boot_setostask @@ -1093,6 +1108,8 @@ end if @@: DEBUGF 1, "K : %d CPU detected\n", eax +include "detect/vortex86.inc" ; Vortex86 SoC detection code + DEBUGF 1, "K : BAR0 %x \n", [IDE_BAR0_val]:4 DEBUGF 1, "K : BAR1 %x \n", [IDE_BAR1_val]:4 DEBUGF 1, "K : BAR2 %x \n", [IDE_BAR2_val]:4 @@ -1100,6 +1117,7 @@ end if DEBUGF 1, "K : BAR4 %x \n", [IDEContrRegsBaseAddr]:4 DEBUGF 1, "K : IDEContrProgrammingInterface %x \n", [IDEContrProgrammingInterface]:4 DEBUGF 1, "K : IDE_Interrupt %x \n", [IDE_Interrupt]:4 + ; START MULTITASKING ; A 'All set - press ESC to start' messages if need @@ -3248,6 +3266,10 @@ sys_cpuusage: mov EAX, dword [ECX+CURRENT_TASK+TASKDATA.event_mask] stosd + ; Keyboard mode (+75) + mov al, byte [ecx*8 + SLOT_BASE + APPDATA.keyboard_mode] + stosb + pop esi pop edi @@ -3790,10 +3812,6 @@ newdw2: mov eax, [edi + WDATA.box.left] mov ebx, [edi + WDATA.box.top] - mov ecx, [edi + WDATA.box.width] - mov edx, [edi + WDATA.box.height] - add ecx, eax - add edx, ebx mov ecx, [draw_limits.bottom] ; ecx = area y end ebx = window y start cmp ecx, ebx @@ -3892,6 +3910,64 @@ align 4 align 4 newdw8: nobgrd: +;-------------------------------------- + push eax edi ebp + mov edi, [esp+12] + cmp edi, 1 + je .found + + mov eax, [draw_limits.left] + mov ebx, [draw_limits.top] + mov ecx, [draw_limits.right] + sub ecx, eax + test ecx, ecx + jz .not_found + + mov edx, [draw_limits.bottom] + sub edx, ebx + test edx, edx + jz .not_found + +; eax - x, ebx - y +; ecx - size x, edx - size y + add ebx, edx +;-------------------------------------- +align 4 +.start_y: + push ecx +;-------------------------------------- +align 4 +.start_x: + add eax, ecx + mov ebp, [d_width_calc_area + ebx*4] + add ebp, [_WinMapAddress] + movzx ebp, byte[eax+ebp] ; get value for current point + cmp ebp, edi + jne @f + + pop ecx + jmp .found +;-------------------------------------- +align 4 +@@: + sub eax, ecx + + dec ecx + jnz .start_x + + pop ecx + dec ebx + dec edx + jnz .start_y +;-------------------------------------- +align 4 +.not_found: + pop ebp edi eax + jmp ricino +;-------------------------------------- +align 4 +.found: + pop ebp edi eax mov [eax + WDATA.fl_redraw], byte 1 ; mark as redraw ;-------------------------------------- @@ -5511,13 +5587,13 @@ syscall_reserveportarea: ; ReservePortArea and FreePortArea align 4 syscall_threads: ; CreateThreads -; eax=1 create thread ; -; ebx=thread start -; ecx=thread stack value +; ecx=thread entry point +; edx=thread stack pointer ; ; on return : eax = pid + xor ebx, ebx call new_sys_threads mov [esp+32], eax diff --git a/kernel/branches/Kolibri-acpi/kernel32.inc b/kernel/branches/Kolibri-acpi/kernel32.inc index 6f1dfa6963..391e2771f6 100644 --- a/kernel/branches/Kolibri-acpi/kernel32.inc +++ b/kernel/branches/Kolibri-acpi/kernel32.inc @@ -171,6 +171,7 @@ include "core/v86.inc" ; virtual-8086 manager include "core/irq.inc" ; irq handling functions include "core/apic.inc" ; Interrupt Controller functions include "core/timers.inc" +include "core/clipboard.inc" ; custom clipboard ; GUI stuff include "gui/window.inc" @@ -191,7 +192,8 @@ include "fs/fat12.inc" ; read / write for fat12 filesystem include "blkdev/rd.inc" ; ramdisk read /write include "fs/fs_lfn.inc" ; syscall, version 2 include "fs/iso9660.inc" ; read for iso9660 filesystem CD -include "fs/ext2.inc" ; read / write for ext2 filesystem +include "fs/ext2/ext2.asm" ; read / write for ext2 filesystem +include "fs/xfs.asm" ; read / write for xfs filesystem ; sound diff --git a/kernel/branches/Kolibri-acpi/kernelsp.inc b/kernel/branches/Kolibri-acpi/kernelsp.inc index 97beb2423e..661889dbb5 100644 --- a/kernel/branches/Kolibri-acpi/kernelsp.inc +++ b/kernel/branches/Kolibri-acpi/kernelsp.inc @@ -1,4 +1,4 @@ ; Éste archivo debe ser editado con codificación CP866 -version: cp850 'Kolibri OS versión 0.7.7.0+ ',13,10,13,10,0 +version cp850 'Kolibri OS versión 0.7.7.0+ ',13,10,13,10,0 diff16 "fin del código del kernel",0,$ diff --git a/kernel/branches/Kolibri-acpi/network/IPv4.inc b/kernel/branches/Kolibri-acpi/network/IPv4.inc index cf2b6a6734..a0ba259c47 100644 --- a/kernel/branches/Kolibri-acpi/network/IPv4.inc +++ b/kernel/branches/Kolibri-acpi/network/IPv4.inc @@ -18,7 +18,7 @@ $Revision: 3515 $ -MAX_FRAGMENTS = 64 +IPv4_MAX_FRAGMENTS = 64 struct IPv4_header @@ -35,7 +35,7 @@ struct IPv4_header ends -struct FRAGMENT_slot +struct IPv4_FRAGMENT_slot ttl dw ? ; Time to live for this entry, 0 for empty slot's id dw ? ; Identification field from IP header @@ -45,7 +45,7 @@ struct FRAGMENT_slot ends -struct FRAGMENT_entry ; This structure will replace the ethernet header in fragmented ip packets +struct IPv4_FRAGMENT_entry ; This structure will replace the ethernet header in fragmented ip packets PrevPtr dd ? ; Pointer to previous fragment entry (-1 for first packet) NextPtr dd ? ; Pointer to next fragment entry (-1 for last packet) @@ -64,11 +64,11 @@ align 4 GATEWAY_LIST rd NET_DEVICES_MAX BROADCAST_LIST rd NET_DEVICES_MAX - IP_packets_tx rd NET_DEVICES_MAX - IP_packets_rx rd NET_DEVICES_MAX - IP_packets_dumped rd NET_DEVICES_MAX + IPv4_packets_tx rd NET_DEVICES_MAX + IPv4_packets_rx rd NET_DEVICES_MAX + IPv4_packets_dumped rd NET_DEVICES_MAX - FRAGMENT_LIST rb MAX_FRAGMENTS * sizeof.FRAGMENT_slot + IPv4_FRAGMENT_LIST rb IPv4_MAX_FRAGMENTS * sizeof.IPv4_FRAGMENT_slot endg @@ -84,7 +84,7 @@ macro IPv4_init { xor eax, eax mov edi, IP_LIST - mov ecx, 7*NET_DEVICES_MAX + (sizeof.FRAGMENT_slot*MAX_FRAGMENTS)/4 + mov ecx, 7*NET_DEVICES_MAX + (sizeof.IPv4_FRAGMENT_slot*IPv4_MAX_FRAGMENTS)/4 rep stosd } @@ -99,15 +99,15 @@ macro IPv4_decrease_fragment_ttls { local .loop, .next - mov esi, FRAGMENT_LIST - mov ecx, MAX_FRAGMENTS + mov esi, IPv4_FRAGMENT_LIST + mov ecx, IPv4_MAX_FRAGMENTS .loop: - cmp [esi + FRAGMENT_slot.ttl], 0 + cmp [esi + IPv4_FRAGMENT_slot.ttl], 0 je .next - dec [esi + FRAGMENT_slot.ttl] + dec [esi + IPv4_FRAGMENT_slot.ttl] jz .died .next: - add esi, sizeof.FRAGMENT_slot + add esi, sizeof.IPv4_FRAGMENT_slot dec ecx jnz .loop jmp .done @@ -263,7 +263,7 @@ IPv4_input: ; TODO: add IPv4 ; Now we can update stats .ip_ok: - inc [IP_packets_rx + edi] + inc [IPv4_packets_rx + edi] ;---------------------------------- ; Check if the packet is fragmented @@ -304,7 +304,7 @@ IPv4_input: ; TODO: add IPv4 .dump: DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: dumping\n" - inc [IP_packets_dumped] ; FIXME: use correct interface + inc [IPv4_packets_dumped] ; FIXME: use correct interface call NET_packet_free add esp, 4 ; pop (balance stack) ret @@ -319,7 +319,7 @@ IPv4_input: ; TODO: add IPv4 xchg al, ah shl ax, 3 - DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: fragmented packet offset=%u id=%x\n", ax, [edx + IPv4_header.Identification]:4 + DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: fragmented packet offset=%u id=%x ptr=0x%x\n", ax, [edx + IPv4_header.Identification]:4, edx test ax, ax ; Is this the first packet of the fragment? jz .is_first_fragment @@ -334,24 +334,24 @@ IPv4_input: ; TODO: add IPv4 cmp esi, -1 je .dump - mov [esi + FRAGMENT_slot.ttl], 15 ; Reset the ttl - mov esi, [esi + FRAGMENT_slot.ptr] + mov [esi + IPv4_FRAGMENT_slot.ttl], 15 ; Reset the ttl + mov esi, [esi + IPv4_FRAGMENT_slot.ptr] or edi, -1 .find_last_entry: ; The following routine will try to find the last entry - cmp edi, [esi + FRAGMENT_entry.PrevPtr] + cmp edi, [esi + IPv4_FRAGMENT_entry.PrevPtr] jne .destroy_slot ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!) mov edi, esi - mov esi, [esi + FRAGMENT_entry.NextPtr] + mov esi, [esi + IPv4_FRAGMENT_entry.NextPtr] cmp esi, -1 jne .find_last_entry ; We found the last entry (pointer is now in edi) ; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure pop eax ; pointer to packet - mov [edi + FRAGMENT_entry.NextPtr], eax ; update pointer of previous entry to the new entry - mov [eax + FRAGMENT_entry.NextPtr], -1 - mov [eax + FRAGMENT_entry.PrevPtr], edi - mov [eax + FRAGMENT_entry.Owner], ebx + mov [edi + IPv4_FRAGMENT_entry.NextPtr], eax ; update pointer of previous entry to the new entry + mov [eax + IPv4_FRAGMENT_entry.NextPtr], -1 + mov [eax + IPv4_FRAGMENT_entry.PrevPtr], edi + mov [eax + IPv4_FRAGMENT_entry.Owner], ebx add esp, 4 ret @@ -363,29 +363,29 @@ IPv4_input: ; TODO: add IPv4 .is_first_fragment: DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: First fragment packet received!\n" ; try to locate a free slot.. - mov ecx, MAX_FRAGMENTS - mov esi, FRAGMENT_LIST + mov ecx, IPv4_MAX_FRAGMENTS + mov esi, IPv4_FRAGMENT_LIST .find_free_slot: - cmp word [esi + FRAGMENT_slot.ttl], 0 + cmp word [esi + IPv4_FRAGMENT_slot.ttl], 0 je .found_free_slot - add esi, sizeof.FRAGMENT_slot + add esi, sizeof.IPv4_FRAGMENT_slot loop .find_free_slot jmp .dump ; If no free slot was found, dump the packet .found_free_slot: ; We found a free slot, let's fill in the FRAGMENT_slot structure - mov [esi + FRAGMENT_slot.ttl], 15 ; RFC recommends 15 secs as ttl + mov [esi + IPv4_FRAGMENT_slot.ttl], 15 ; RFC recommends 15 secs as ttl mov ax, [edx + IPv4_header.Identification] - mov [esi + FRAGMENT_slot.id], ax + mov [esi + IPv4_FRAGMENT_slot.id], ax mov eax, [edx + IPv4_header.SourceAddress] - mov [esi + FRAGMENT_slot.SrcIP], eax + mov [esi + IPv4_FRAGMENT_slot.SrcIP], eax mov eax, [edx + IPv4_header.DestinationAddress] - mov [esi + FRAGMENT_slot.DstIP], eax + mov [esi + IPv4_FRAGMENT_slot.DstIP], eax pop eax - mov [esi + FRAGMENT_slot.ptr], eax + mov [esi + IPv4_FRAGMENT_slot.ptr], eax ; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure - mov [eax + FRAGMENT_entry.NextPtr], -1 - mov [eax + FRAGMENT_entry.PrevPtr], -1 - mov [eax + FRAGMENT_entry.Owner], ebx + mov [eax + IPv4_FRAGMENT_entry.NextPtr], -1 + mov [eax + IPv4_FRAGMENT_entry.PrevPtr], -1 + mov [eax + IPv4_FRAGMENT_entry.Owner], ebx add esp, 4 ; balance stack and exit ret @@ -401,35 +401,35 @@ IPv4_input: ; TODO: add IPv4 cmp esi, -1 je .dump - mov esi, [esi + FRAGMENT_slot.ptr] ; We found the first entry, let's calculate total size of the packet in eax, so we can allocate a buffer + mov esi, [esi + IPv4_FRAGMENT_slot.ptr] ; We found the first entry, let's calculate total size of the packet in eax, so we can allocate a buffer push esi xor eax, eax or edi, -1 .count_bytes: - cmp [esi + FRAGMENT_entry.PrevPtr], edi - jne .destroy_slot_pop ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!) - mov cx, [esi + sizeof.FRAGMENT_entry + IPv4_header.TotalLength] ; Add total length + cmp [esi + IPv4_FRAGMENT_entry.PrevPtr], edi + jne .destroy_slot_pop ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!) + mov cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength] ; Add total length xchg cl, ch DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx add ax, cx - movzx cx, [esi + sizeof.FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Sub Header length + movzx cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Sub Header length and cx, 0x000F shl cx, 2 DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Header size=%u\n", cx sub ax, cx mov edi, esi - mov esi, [esi + FRAGMENT_entry.NextPtr] + mov esi, [esi + IPv4_FRAGMENT_entry.NextPtr] cmp esi, -1 jne .count_bytes mov esi, [esp+4] - mov [edi + FRAGMENT_entry.NextPtr], esi ; Add this packet to the chain, this simplifies the following code - mov [esi + FRAGMENT_entry.NextPtr], -1 - mov [esi + FRAGMENT_entry.PrevPtr], edi - mov [esi + FRAGMENT_entry.Owner], ebx + mov [edi + IPv4_FRAGMENT_entry.NextPtr], esi ; Add this packet to the chain, this simplifies the following code + mov [esi + IPv4_FRAGMENT_entry.NextPtr], -1 + mov [esi + IPv4_FRAGMENT_entry.PrevPtr], edi + mov [esi + IPv4_FRAGMENT_entry.Owner], ebx - mov cx, [edx + IPv4_header.TotalLength] ; Note: This time we dont substract Header length + mov cx, [edx + IPv4_header.TotalLength] ; Note: This time we dont substract Header length xchg cl, ch DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx add ax, cx @@ -454,18 +454,18 @@ IPv4_input: ; TODO: add IPv4 mov edx, [esp+4] ; Get pointer to first fragment entry back in edx .rebuild_packet_loop: - movzx ecx, [edx + sizeof.FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset] ; Calculate the fragment offset + movzx ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset] ; Calculate the fragment offset xchg cl, ch ; intel byte order shl cx, 3 ; multiply by 8 and clear first 3 bits DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Fragment offset=%u\n", cx lea edi, [eax + ecx] ; Notice that edi will be equal to eax for first fragment - movzx ebx, [edx + sizeof.FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Find header size (in ebx) of fragment + movzx ebx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Find header size (in ebx) of fragment and bx, 0x000F ; shl bx, 2 ; - lea esi, [edx + sizeof.FRAGMENT_entry] ; Set esi to the correct begin of fragment - movzx ecx, [edx + sizeof.FRAGMENT_entry + IPv4_header.TotalLength] ; Calculate total length of fragment + lea esi, [edx + sizeof.IPv4_FRAGMENT_entry] ; Set esi to the correct begin of fragment + movzx ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength] ; Calculate total length of fragment xchg cl, ch ; intel byte order cmp edi, eax ; Is this packet the first fragment ? @@ -474,6 +474,8 @@ IPv4_input: ; TODO: add IPv4 add esi, ebx ; .first_fragment: + + DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Copying %u bytes from 0x%x to 0x%x\n", ecx, esi, edi push cx ; First copy dword-wise, then byte-wise shr cx, 2 ; rep movsd ; @@ -482,11 +484,12 @@ IPv4_input: ; TODO: add IPv4 rep movsb ; push eax + push [edx + IPv4_FRAGMENT_entry.Owner] ; we need to remeber the owner, in case this is the last packet + push [edx + IPv4_FRAGMENT_entry.NextPtr] ; Set edx to the next pointer push edx ; Push pointer to fragment onto stack - mov ebx, [edx + FRAGMENT_entry.Owner] ; we need to remeber the owner, in case this is the last packet - mov edx, [edx + FRAGMENT_entry.NextPtr] ; Set edx to the next pointer + DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Next Fragment: 0x%x\n", edx call NET_packet_free ; free the previous fragment buffer (this uses the value from stack) - pop eax + pop edx ebx eax cmp edx, -1 ; Check if it is last fragment in chain jne .rebuild_packet_loop @@ -494,12 +497,10 @@ IPv4_input: ; TODO: add IPv4 xchg cl, ch mov edx, eax mov [edx + IPv4_header.TotalLength], cx - add esp, 8 + add esp, 12 xchg cl, ch - push ecx - - push eax - jmp .handle_it ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr + push ecx edx ; size and pointer + jmp .handle_it ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr .destroy_slot_pop: add esp, 4 @@ -527,19 +528,19 @@ IPv4_find_fragment_slot: push eax ebx ecx edx mov ax, [edx + IPv4_header.Identification] - mov ecx, MAX_FRAGMENTS - mov esi, FRAGMENT_LIST + mov ecx, IPv4_MAX_FRAGMENTS + mov esi, IPv4_FRAGMENT_LIST mov ebx, [edx + IPv4_header.SourceAddress] mov edx, [edx + IPv4_header.DestinationAddress] .find_slot: - cmp [esi + FRAGMENT_slot.id], ax + cmp [esi + IPv4_FRAGMENT_slot.id], ax jne .try_next - cmp [esi + FRAGMENT_slot.SrcIP], ebx + cmp [esi + IPv4_FRAGMENT_slot.SrcIP], ebx jne .try_next - cmp [esi + FRAGMENT_slot.DstIP], edx + cmp [esi + IPv4_FRAGMENT_slot.DstIP], edx je .found_slot .try_next: - add esi, sizeof.FRAGMENT_slot + add esi, sizeof.IPv4_FRAGMENT_slot loop .find_slot or esi, -1 @@ -552,17 +553,16 @@ IPv4_find_fragment_slot: ; ; IPv4_output ; -; IN: eax = dest ip -; ebx = output device ptr/0 for automatic choice -; ecx = data length -; edx = source ip -; di = TTL shl 8 + protocol +; IN: eax = Destination IP +; ecx = data length +; edx = Source IP +; di = TTL shl 8 + protocol ; -; OUT: eax = pointer to buffer start -; ebx = pointer to device struct (needed for sending procedure) -; ecx = unchanged (packet size of embedded data) -; edx = size of complete buffer -; edi = pointer to start of data (0 on error) +; OUT: eax = pointer to buffer start +; ebx = pointer to device struct (needed for sending procedure) +; ecx = unchanged (packet size of embedded data) +; edx = size of complete buffer +; edi = pointer to start of data (0 on error) ; ;------------------------------------------------------------------ align 4 @@ -573,9 +573,9 @@ IPv4_output: cmp ecx, 65500 ; Max IPv4 packet size ja .too_large - push ecx eax edx di - - call IPv4_route ; outputs device number in edi, dest ip in eax + push ecx di eax + call IPv4_route ; outputs device number in edi, dest ip in eax, source IP in edx + push edx test edi, edi jz .loopback @@ -586,12 +586,12 @@ IPv4_output: push ebx ; push the mac onto the stack push ax - inc [IP_packets_tx + edi] ; update stats + inc [IPv4_packets_tx + edi] ; update stats mov ebx, [NET_DRV_LIST + edi] lea eax, [ebx + ETH_DEVICE.mac] mov edx, esp - mov ecx, [esp + 10 + 6] + mov ecx, [esp + 6 + 8 + 2] add ecx, sizeof.IPv4_header mov di, ETHER_PROTO_IPv4 call ETH_output @@ -605,12 +605,14 @@ IPv4_output: mov [edi + IPv4_header.TotalLength], cx mov [edi + IPv4_header.Identification], 0 ; fragment id: FIXME mov [edi + IPv4_header.FlagsAndFragmentOffset], 0 - pop word [edi + IPv4_header.TimeToLive] ; ttl shl 8 + protocol -; [edi + IPv4_header.Protocol] + mov [edi + IPv4_header.HeaderChecksum], 0 popd [edi + IPv4_header.SourceAddress] popd [edi + IPv4_header.DestinationAddress] + pop word[edi + IPv4_header.TimeToLive] ; ttl shl 8 + protocol +; [edi + IPv4_header.Protocol] + pop ecx IPv4_checksum edi @@ -677,7 +679,7 @@ IPv4_output_raw: push ebx ; push the mac push ax - inc [IP_packets_tx + 4*edi] + inc [IPv4_packets_tx + 4*edi] mov ebx, [NET_DRV_LIST + 4*edi] lea eax, [ebx + ETH_DEVICE.mac] mov edx, esp @@ -857,40 +859,44 @@ IPv4_fragment: ; IPv4_route ; ; IN: eax = Destination IP -; OUT: edi = device number*4 -; eax = ip of gateway if nescessary, unchanged otherwise +; edx = Source IP +; OUT: eax = Destination IP (or gateway IP) +; edx = Source IP +; edi = device number*4 +; DESTROYED: +; ecx ; ;--------------------------------------------------------------------------- align 4 -IPv4_route: +IPv4_route: ; TODO: return error if no valid route found cmp eax, 0xffffffff je .broadcast xor edi, edi - mov ecx, NET_DEVICES_MAX .loop: - mov ebx, [IP_LIST+edi] - and ebx, [SUBNET_LIST+edi] + mov ebx, [IP_LIST + edi] + and ebx, [SUBNET_LIST + edi] jz .next - mov edx, eax - and edx, [SUBNET_LIST+edi] - - cmp ebx, edx - jne .next - - DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi - ret - + mov ecx, eax + and ecx, [SUBNET_LIST + edi] + cmp ebx, ecx + je .got_it .next: add edi, 4 - dec ecx - jnz .loop + cmp edi, 4*NET_DEVICES_MAX + jb .loop - .invalid: - mov eax, [GATEWAY_LIST+4] ;;; FIXME + mov eax, [GATEWAY_LIST + 4] ; TODO: let user (or a user space daemon) configure default route .broadcast: - mov edi, 4 ; if none found, use device 1 as default ;;;; FIXME + mov edi, 4 ; TODO: same as above + .got_it: + DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi + test edx, edx + jnz @f + mov edx, [IP_LIST + edi] + @@: + ret @@ -910,6 +916,45 @@ IPv4_get_frgmnt_num: ret +;----------------------------------------------------------------- +; +; IPv4_connect +; +; IN: eax = socket pointer +; OUT: eax = 0 ok / -1 error +; ebx = error code +; +;------------------------- +align 4 +IPv4_connect: + + push eax edx + lea ecx, [eax + SOCKET.mutex] + call mutex_lock + pop edx eax + +; Fill in local IP + cmp [eax + IP_SOCKET.LocalIP], 0 + jne @f + push [IP_LIST + 4] ; FIXME: use correct local IP + pop [eax + IP_SOCKET.LocalIP] + +; Fill in remote IP + pushd [edx + 4] + pop [eax + IP_SOCKET.RemoteIP] + +; Set up data receiving queue + push eax + init_queue (eax + SOCKET_QUEUE_LOCATION) + pop eax + + lea ecx, [eax + SOCKET.mutex] + call mutex_unlock + + xor eax, eax + ret + + ;--------------------------------------------------------------------------- ; ; IPv4_API @@ -952,11 +997,11 @@ IPv4_api: ret .packets_tx: - mov eax, [IP_packets_tx + eax] + mov eax, [IPv4_packets_tx + eax] ret .packets_rx: - mov eax, [IP_packets_rx + eax] + mov eax, [IPv4_packets_rx + eax] ret .read_ip: diff --git a/kernel/branches/Kolibri-acpi/network/ethernet.inc b/kernel/branches/Kolibri-acpi/network/ethernet.inc index 72cd2a3527..05fa7e6484 100644 --- a/kernel/branches/Kolibri-acpi/network/ethernet.inc +++ b/kernel/branches/Kolibri-acpi/network/ethernet.inc @@ -17,6 +17,7 @@ $Revision: 3346 $ ETH_FRAME_MINIMUM = 60 +ETH_QUEUE_SIZE = 255 struct ETH_header @@ -32,12 +33,40 @@ struct ETH_DEVICE NET_DEVICE ends +struct ETH_queue_entry + + device dd ? + packet dd ? + size dd ? + +ends + iglobal align 4 ETH_BROADCAST dp 0xffffffffffff endg +uglobal +align 4 + ETH_input_event dd ? + ETH_queue rd (ETH_QUEUE_SIZE*sizeof.ETH_queue_entry + sizeof.queue)/4 +endg + +macro ETH_init { + + init_queue ETH_queue + + movi ebx, 1 + mov ecx, ETH_process_input + call new_sys_threads + test eax, eax + jns @f + DEBUGF DEBUG_NETWORK_ERROR,'K : cannot create kernel thread for ethernet, error %d\n', eax + @@: + +} + ;----------------------------------------------------------------- ; ; ETH_input @@ -53,10 +82,62 @@ endg ;----------------------------------------------------------------- align 4 ETH_input: - mov eax, [esp] - mov ecx, [esp+4] - DEBUGF DEBUG_NETWORK_VERBOSE,"ETH_input: size=%u\n", ecx + push ebx + mov esi, esp + + pushf + cli + add_to_queue ETH_queue, ETH_QUEUE_SIZE, sizeof.ETH_queue_entry, .fail + popf + + add esp, sizeof.ETH_queue_entry + + xor edx, edx + mov eax, [ETH_input_event] + mov ebx, [eax + EVENT.id] + xor esi, esi + call raise_event + + ret + + .fail: + popf + DEBUGF DEBUG_NETWORK_VERBOSE, "ETH incoming queue is full, discarding packet!\n" + + add esp, sizeof.ETH_queue_entry - 8 + call NET_packet_free + add esp, 4 + + ret + + + + +align 4 +ETH_process_input: + + xor esi, esi + mov ecx, MANUAL_DESTROY + call create_event + mov [ETH_input_event], eax + + .wait: + mov eax, [ETH_input_event] + mov ebx, [eax + EVENT.id] + call wait_event + + .loop: + get_from_queue ETH_queue, ETH_QUEUE_SIZE, sizeof.ETH_queue_entry, .wait + + mov eax, [esi + ETH_queue_entry.packet] + mov ecx, [esi + ETH_queue_entry.size] + mov ebx, [esi + ETH_queue_entry.device] + + pushd .loop ; return address + push ecx eax + + DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_input: size=%u\n", ecx sub ecx, sizeof.ETH_header jb .dump @@ -78,10 +159,10 @@ ETH_input: cmp ax, ETHER_PROTO_PPP_SESSION je PPPoE_session_input - DEBUGF DEBUG_NETWORK_ERROR, "ETH_input: Unknown packet type=%x\n", ax + DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_input: Unknown packet type=%x\n", ax .dump: - DEBUGF DEBUG_NETWORK_VERBOSE,"ETH_input: dumping\n" + DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_input: dumping\n" call NET_packet_free add esp, 4 ret diff --git a/kernel/branches/Kolibri-acpi/network/icmp.inc b/kernel/branches/Kolibri-acpi/network/icmp.inc index cc5092ecc3..b30b3f1d80 100644 --- a/kernel/branches/Kolibri-acpi/network/icmp.inc +++ b/kernel/branches/Kolibri-acpi/network/icmp.inc @@ -310,15 +310,16 @@ ICMP_input: ret +if 0 ;----------------------------------------------------------------- ; ; ICMP_output ; ; IN: eax = dest ip -; ebx = source ip +; bh = type +; bl = code ; ecx = data length -; dh = type -; dl = code +; edx = source ip ; esi = data offset ; edi = identifier shl 16 + sequence number ; @@ -328,10 +329,7 @@ ICMP_output: DEBUGF DEBUG_NETWORK_VERBOSE, "Creating ICMP Packet\n" - push esi edi dx - - mov edx, [eax + IP_SOCKET.LocalIP] - mov eax, [eax + IP_SOCKET.RemoteIP] + push esi edi bx add ecx, sizeof.ICMP_header mov di, IP_PROTO_ICMP SHL 8 + 128 ; TTL call IPv4_output @@ -374,13 +372,14 @@ ICMP_output: DEBUGF DEBUG_NETWORK_ERROR, "Creating ICMP Packet failed\n" add esp, 2*4 + 2 ret +end if ;----------------------------------------------------------------- ; -; ICMP_output +; ICMP_output_raw ; ; IN: eax = socket ptr ; ecx = data length diff --git a/kernel/branches/Kolibri-acpi/network/socket.inc b/kernel/branches/Kolibri-acpi/network/socket.inc index 03f9002f4c..e154149126 100644 --- a/kernel/branches/Kolibri-acpi/network/socket.inc +++ b/kernel/branches/Kolibri-acpi/network/socket.inc @@ -39,6 +39,7 @@ struct SOCKET snd_proc dd ? rcv_proc dd ? + connect_proc dd ? ends @@ -131,6 +132,7 @@ struct TCP_SOCKET IP_SOCKET timer_persist dd ? timer_keepalive dd ? ; keepalive/syn timeout timer_timed_wait dd ? ; also used as 2msl timer + timer_connect dd ? ; extra @@ -142,13 +144,13 @@ struct TCP_SOCKET IP_SOCKET temp_bits db ? rb 3 ; align + ends struct UDP_SOCKET IP_SOCKET LocalPort dw ? ; network byte order RemotePort dw ? ; network byte order - firstpacket db ? ends @@ -309,6 +311,7 @@ SOCKET_open: mov [eax + SOCKET.Domain], ecx mov [eax + SOCKET.Type], edx mov [eax + SOCKET.Protocol], esi + mov [eax + SOCKET.connect_proc], connect_notsupp cmp ecx, AF_INET4 jne .no_inet4 @@ -357,6 +360,7 @@ align 4 mov [eax + SOCKET.Protocol], IP_PROTO_UDP mov [eax + SOCKET.snd_proc], SOCKET_send_udp mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram + mov [eax + SOCKET.connect_proc], UDP_connect ret align 4 @@ -364,6 +368,7 @@ align 4 mov [eax + SOCKET.Protocol], IP_PROTO_TCP mov [eax + SOCKET.snd_proc], SOCKET_send_tcp mov [eax + SOCKET.rcv_proc], SOCKET_receive_stream + mov [eax + SOCKET.connect_proc], TCP_connect TCP_init_socket eax ret @@ -373,6 +378,7 @@ align 4 .raw_ip: mov [eax + SOCKET.snd_proc], SOCKET_send_ip mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram + mov [eax + SOCKET.connect_proc], IPv4_connect ret @@ -380,6 +386,7 @@ align 4 .raw_icmp: mov [eax + SOCKET.snd_proc], SOCKET_send_icmp mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram + mov [eax + SOCKET.connect_proc], IPv4_connect ret align 4 @@ -414,6 +421,9 @@ SOCKET_bind: cmp esi, 2 jb .invalid + cmp [eax + UDP_SOCKET.LocalPort], 0 ; Socket can only be bound once + jnz .invalid + cmp word [edx], AF_INET4 je .af_inet4 @@ -449,17 +459,21 @@ SOCKET_bind: .tcp: .udp: - mov ebx, [edx + 4] ; First, fill in the IP - test ebx, ebx ; If IP is 0, use default - jnz @f - mov ebx, [IP_LIST + 4] ;;;;; FIXME !i!i!i - @@: - mov [eax + IP_SOCKET.LocalIP], ebx - mov bx, [edx + 2] ; Now fill in the local port if it's still available - call SOCKET_check_port - jz .addrinuse ; ZF is set by socket_check_port, on error + pushd [edx + 4] ; First, fill in the IP + popd [eax + IP_SOCKET.LocalIP] + mov bx, [edx + 2] ; Did caller specify a local port? + test bx, bx + jnz .just_check + call SOCKET_find_port ; Nope, find an ephemeral one + jmp .done + + .just_check: + call SOCKET_check_port ; Yes, check if it's still available + jz .addrinuse ; ZF is set by socket_check_port on error + + .done: DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_bind: local ip=%u.%u.%u.%u\n",\ [eax + IP_SOCKET.LocalIP + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\ [eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1 @@ -496,8 +510,18 @@ SOCKET_connect: cmp esi, 8 jb .invalid - cmp word [edx], AF_INET4 - je .af_inet4 + cmp [eax + SOCKET.state], SS_ISCONNECTING + je .already + + test [eax + SOCKET.options], SO_ACCEPTCON + jnz .notsupp + + call [eax + SOCKET.connect_proc] + + mov dword[esp+20], ebx + mov dword[esp+32], eax + ret + .notsupp: mov dword[esp+20], EOPNOTSUPP @@ -509,150 +533,16 @@ SOCKET_connect: mov dword[esp+32], -1 ret - .af_inet4: - cmp [eax + IP_SOCKET.LocalIP], 0 - jne @f - push [IP_LIST + 4] ; FIXME !i!i!i! - pop [eax + IP_SOCKET.LocalIP] - @@: - - cmp [eax + SOCKET.Protocol], IP_PROTO_UDP - je .udp - - cmp [eax + SOCKET.Protocol], IP_PROTO_TCP - je .tcp - - cmp [eax + SOCKET.Protocol], IP_PROTO_IP - je .ip - - cmp [eax + SOCKET.Protocol], IP_PROTO_ICMP - je .ip - - jmp .notsupp - -align 4 - .udp: - pusha - lea ecx, [eax + SOCKET.mutex] - call mutex_lock - popa - - pushw [edx + 2] - pop [eax + UDP_SOCKET.RemotePort] - - pushd [edx + 4] - pop [eax + IP_SOCKET.RemoteIP] - - cmp [eax + UDP_SOCKET.LocalPort], 0 - jne @f - call SOCKET_find_port - @@: - - mov [eax + UDP_SOCKET.firstpacket], 0 - - push eax - init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue - pop eax - - lea ecx, [eax + SOCKET.mutex] - call mutex_unlock - - mov dword[esp+32], 0 - ret - -align 4 - .tcp: - pusha - lea ecx, [eax + SOCKET.mutex] - call mutex_lock - popa - - pushw [edx + 2] - pop [eax + TCP_SOCKET.RemotePort] - - pushd [edx + 4] - pop [eax + IP_SOCKET.RemoteIP] - - cmp [eax + TCP_SOCKET.LocalPort], 0 - jne @f - call SOCKET_find_port - @@: - - mov [eax + TCP_SOCKET.timer_persist], 0 - mov [eax + TCP_SOCKET.t_state], TCPS_SYN_SENT - - push [TCP_sequence_num] - add [TCP_sequence_num], 6400 - pop [eax + TCP_SOCKET.ISS] - mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init - - TCP_sendseqinit eax -; mov [ebx + TCP_SOCKET.timer_retransmission], ;; todo: create macro to set retransmission timer - - mov ebx, eax - lea eax, [ebx + STREAM_SOCKET.snd] - call SOCKET_ring_create ; TODO: check if memory was available or not - - lea eax, [ebx + STREAM_SOCKET.rcv] - call SOCKET_ring_create ; TODO: same here - - pusha - lea ecx, [ebx + SOCKET.mutex] - call mutex_unlock - popa - - push ebx - mov eax, ebx - call TCP_output - pop eax - - .block: - test [eax + SOCKET.options], SO_NONBLOCK - jz .loop - - mov dword[esp+20], EWOULDBLOCK + .already: + mov dword[esp+20], EALREADY mov dword[esp+32], -1 ret - .loop: - cmp [eax + TCP_SOCKET.t_state], TCPS_CLOSED - je .fail - cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED - je .established - ja .fail - call SOCKET_block - jmp .loop - - .fail: - mov eax, [eax + SOCKET.errorcode] - mov [esp+20], eax - mov dword[esp+32], -1 - ret - - .established: - mov dword[esp+32], 0 - ret - - -align 4 - .ip: - pusha - lea ecx, [eax + SOCKET.mutex] - call mutex_lock - popa - - pushd [edx + 4] - pop [eax + IP_SOCKET.RemoteIP] - - push eax - init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue - pop eax - - lea ecx, [eax + SOCKET.mutex] - call mutex_unlock - - mov dword[esp+32], 0 +connect_notsupp: + xor eax, eax + dec eax + mov ebx, EOPNOTSUPP ret @@ -865,15 +755,15 @@ SOCKET_receive: call [eax + SOCKET.rcv_proc] pop edi + test [eax + SOCKET.state], SS_CANTRCVMORE + jnz .return + cmp ebx, EWOULDBLOCK jne .return test edi, MSG_DONTWAIT jnz .return_err - test [eax + SOCKET.state], SS_CANTRCVMORE - jnz .return_err - ; test [eax + SOCKET.options], SO_NONBLOCK ; jnz .return_err @@ -885,10 +775,10 @@ SOCKET_receive: push EINVAL pop ebx .return_err: - mov eax, -1 + mov ecx, -1 .return: mov [esp+20], ebx - mov [esp+32], eax + mov [esp+32], ecx ret @@ -909,7 +799,7 @@ SOCKET_receive_dgram: cmp ecx, ebx ; If data segment does not fit in applications buffer, abort ja .too_small - push ecx + push eax ecx push [esi + socket_queue_entry.buf_ptr] ; save the buffer addr so we can clear it later mov esi, [esi + socket_queue_entry.data_ptr] DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_receive: Source buffer=%x real addr=%x\n", [esp], esi @@ -930,12 +820,12 @@ SOCKET_receive_dgram: .nd: call NET_packet_free - pop eax ; return number of bytes copied to application + pop ecx eax ; return number of bytes copied to application xor ebx, ebx ret .too_small: - mov eax, -1 + mov ecx, -1 push EMSGSIZE pop ebx ret @@ -980,21 +870,23 @@ SOCKET_receive_stream: mov edi, edx xor edx, edx + push eax add eax, STREAM_SOCKET.rcv call SOCKET_ring_read ; copy data from kernel buffer to application buffer call SOCKET_ring_free ; free read memory + pop eax - mov eax, ecx ; return number of bytes copied xor ebx, ebx ; errorcode = 0 (no error) ret .wouldblock: push EWOULDBLOCK pop ebx + xor ecx, ecx ret .peek: - mov eax, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size] + mov ecx, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size] xor ebx, ebx ret @@ -2193,6 +2085,7 @@ SOCKET_num_to_ptr: mov eax, [eax + SOCKET.NextPtr] or eax, eax jz .error + diff16 "tetten", 0, $ cmp [eax + SOCKET.Number], ecx jne .next_socket @@ -2321,6 +2214,11 @@ SOCKET_check_owner: align 4 SOCKET_process_end: + cmp [net_sockets + SOCKET.NextPtr], 0 ; Are there any active sockets at all? + je .quickret ; nope, exit immediately + +; TODO: run the following code in another thread, to avoid deadlock + DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: %x\n", edx pusha @@ -2371,6 +2269,7 @@ SOCKET_process_end: call mutex_unlock popa + .quickret: ret @@ -2390,10 +2289,10 @@ SOCKET_is_connecting: DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_is_connecting: %x\n", eax - and [eax + SOCKET.options], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING) - or [eax + SOCKET.options], SS_ISCONNECTING + and [eax + SOCKET.state], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING) + or [eax + SOCKET.state], SS_ISCONNECTING - jmp SOCKET_notify + ret diff --git a/kernel/branches/Kolibri-acpi/network/stack.inc b/kernel/branches/Kolibri-acpi/network/stack.inc index 1bc1bf0b7c..64eebc9112 100644 --- a/kernel/branches/Kolibri-acpi/network/stack.inc +++ b/kernel/branches/Kolibri-acpi/network/stack.inc @@ -115,6 +115,7 @@ MAX_backlog = 20 ; maximum backlog for stream sockets ; Error Codes ENOBUFS = 1 +EINPROGRESS = 2 EOPNOTSUPP = 4 EWOULDBLOCK = 6 ENOTCONN = 9 @@ -125,6 +126,7 @@ ENOMEM = 18 EADDRINUSE = 20 ECONNREFUSED = 61 ECONNRESET = 52 +EISCONN = 56 ETIMEDOUT = 60 ECONNABORTED = 53 @@ -248,6 +250,8 @@ stack_init: mov ecx, (NET_DEVICES_MAX + 2) rep stosd + ETH_init + PPPoE_init IPv4_init diff --git a/kernel/branches/Kolibri-acpi/network/tcp.inc b/kernel/branches/Kolibri-acpi/network/tcp.inc index 63b183002d..5e05e03867 100644 --- a/kernel/branches/Kolibri-acpi/network/tcp.inc +++ b/kernel/branches/Kolibri-acpi/network/tcp.inc @@ -71,6 +71,8 @@ TCP_time_rtt_default = 5 ; default Round Trip Time (3,2s) TCP_time_srtt_default = 0 ; TCP_time_max_idle = 8*TCP_time_keep_interval ; FIXME +TCP_time_connect = 300 ; in 1/100s (default=3s) + ; timer constants TCP_max_rxtshift = 12 ; max retransmissions waiting for ACK TCP_max_keepcnt = 8 ; max keepalive probes diff --git a/kernel/branches/Kolibri-acpi/network/tcp_output.inc b/kernel/branches/Kolibri-acpi/network/tcp_output.inc index 5a164fb28e..0b3b74555d 100644 --- a/kernel/branches/Kolibri-acpi/network/tcp_output.inc +++ b/kernel/branches/Kolibri-acpi/network/tcp_output.inc @@ -437,8 +437,6 @@ TCP_send: ; Create the IP packet mov ecx, esi - - mov ebx, [eax + SOCKET.device] mov edx, [eax + IP_SOCKET.LocalIP] ; source ip mov eax, [eax + IP_SOCKET.RemoteIP] ; dest ip mov di, IP_PROTO_TCP shl 8 + 128 diff --git a/kernel/branches/Kolibri-acpi/network/tcp_usreq.inc b/kernel/branches/Kolibri-acpi/network/tcp_usreq.inc index 04d61118a6..9c3e8db0a4 100644 --- a/kernel/branches/Kolibri-acpi/network/tcp_usreq.inc +++ b/kernel/branches/Kolibri-acpi/network/tcp_usreq.inc @@ -74,6 +74,137 @@ TCP_usrclosed: ret +;------------------------- +; +; TCP_connect +; +; IN: eax = socket ptr +; OUT: eax = 0 ok / -1 error +; ebx = error code +; +;------------------------- +align 4 +TCP_connect: + + test [eax + SOCKET.state], SS_ISCONNECTED + jnz .eisconn + + push eax edx + lea ecx, [eax + SOCKET.mutex] + call mutex_lock + pop edx eax + +; Fill in local IP + cmp [eax + IP_SOCKET.LocalIP], 0 + jne @f + push [IP_LIST + 4] ; FIXME: use correct local IP + pop [eax + IP_SOCKET.LocalIP] + +; Fill in remote port and IP + pushw [edx + 2] + pop [eax + TCP_SOCKET.RemotePort] + + pushd [edx + 4] + pop [eax + IP_SOCKET.RemoteIP] + +; Find a local port, if user didnt define one + cmp [eax + TCP_SOCKET.LocalPort], 0 + jne @f + call SOCKET_find_port + @@: + +; Start the TCP sequence + mov [eax + TCP_SOCKET.timer_persist], 0 + mov [eax + TCP_SOCKET.t_state], TCPS_SYN_SENT + + push [TCP_sequence_num] + add [TCP_sequence_num], 6400 + pop [eax + TCP_SOCKET.ISS] + mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init + + TCP_sendseqinit eax + + mov ebx, eax + lea eax, [ebx + STREAM_SOCKET.snd] + call SOCKET_ring_create + test eax, eax + jz .nomem + + lea eax, [ebx + STREAM_SOCKET.rcv] + call SOCKET_ring_create + test eax, eax + jz .nomem + + push ebx + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + pop eax + + call SOCKET_is_connecting + +; Now send the SYN packet to remote end + push eax + call TCP_output + pop eax + + .block: + test [eax + SOCKET.options], SO_NONBLOCK + jz .waitforit + + xor eax, eax + dec eax + mov ebx, EINPROGRESS + ret + + .nomem: + xor eax, eax + dec eax + mov ebx, ENOMEM + ret + + .eisconn: + xor eax, eax + dec eax + mov ebx, EISCONN + ret + + .waitforit: + push eax + stdcall timer_hs, TCP_time_connect, 0, .timeout, eax + pop ebx + mov [ebx + TCP_SOCKET.timer_connect], eax + mov eax, ebx + + .loop: + cmp [eax + SOCKET.errorcode], 0 + jne .fail + cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED + je .established + + call SOCKET_block + jmp .loop + + .timeout: + mov eax, [esp+4] + mov [eax + SOCKET.errorcode], ETIMEDOUT + and [eax + SOCKET.state], not SS_ISCONNECTING + call SOCKET_notify.unblock + ret 4 + + .fail: + mov ebx, [eax + SOCKET.errorcode] + mov [eax + SOCKET.errorcode], 0 ; Clear the error, we only need to send it to the caller once + xor eax, eax + dec eax + ret + + .established: + stdcall cancel_timer_hs, [eax + TCP_SOCKET.timer_connect] + + xor eax, eax + ret + + ;------------------------- diff --git a/kernel/branches/Kolibri-acpi/network/udp.inc b/kernel/branches/Kolibri-acpi/network/udp.inc index 11fa12059d..3640b765ea 100644 --- a/kernel/branches/Kolibri-acpi/network/udp.inc +++ b/kernel/branches/Kolibri-acpi/network/udp.inc @@ -182,7 +182,7 @@ UDP_input: ; ; FIXME: UDP should check remote IP, but not under all circumstances! - cmp [eax + UDP_SOCKET.firstpacket], 0 + cmp [eax + UDP_SOCKET.RemotePort], 0 je .updateport cmp [eax + UDP_SOCKET.RemotePort], cx @@ -211,8 +211,6 @@ UDP_input: DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: new remote port=%x\n", cx ; FIXME: find a way to print big endian values with debugf mov [eax + UDP_SOCKET.RemotePort], cx - inc [eax + UDP_SOCKET.firstpacket] - jmp .updatesock .dump_: @@ -262,7 +260,6 @@ UDP_output: sub esp, 8 ; Data ptr and data size will be placed here push edx esi - mov ebx, [eax + SOCKET.device] mov edx, [eax + IP_SOCKET.LocalIP] mov eax, [eax + IP_SOCKET.RemoteIP] mov di, IP_PROTO_UDP shl 8 + 128 @@ -311,6 +308,84 @@ UDP_output: + +;----------------------------------------------------------------- +; +; UDP_connect +; +; IN: eax = socket pointer +; OUT: eax = 0 ok / -1 error +; ebx = error code +; +;------------------------- +align 4 +UDP_connect: + + test [eax + SOCKET.state], SS_ISCONNECTED + jz @f + call UDP_disconnect + @@: + + push eax edx + lea ecx, [eax + SOCKET.mutex] + call mutex_lock + pop edx eax + +; Fill in local IP + cmp [eax + IP_SOCKET.LocalIP], 0 + jne @f + push [IP_LIST + 4] ; FIXME: use correct local IP + pop [eax + IP_SOCKET.LocalIP] + +; Fill in remote port and IP, overwriting eventually previous values + pushw [edx + 2] + pop [eax + UDP_SOCKET.RemotePort] + + pushd [edx + 4] + pop [eax + IP_SOCKET.RemoteIP] + +; Find a local port, if user didnt define one + cmp [eax + UDP_SOCKET.LocalPort], 0 + jne @f + call SOCKET_find_port + @@: + + push eax + init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue + pop eax + + push eax + lea ecx, [eax + SOCKET.mutex] + call mutex_unlock + pop eax + + call SOCKET_is_connected + + xor eax, eax + ret + + +;----------------------------------------------------------------- +; +; UDP_disconnect +; +; IN: eax = socket pointer +; OUT: eax = socket pointer +; +;------------------------- +align 4 +UDP_disconnect: + + ; TODO: remove the pending received data + + call SOCKET_is_disconnected + + ret + + + + + ;--------------------------------------------------------------------------- ; ; UDP_API