Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 3910 → Rev 4265

/kernel/branches/Kolibri-acpi/blkdev/disk.inc
1006,6 → 1006,9
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
/kernel/branches/Kolibri-acpi/blkdev/disk_cache.inc
512,7 → 512,7
 
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
 
push edi
mov edi, [esi+DISK.AppCache.pointer]
lea ecx, [ecx*3]
lea ecx, [(ecx+1)*3]
xor eax, eax
rep stosd
pop edi
/kernel/branches/Kolibri-acpi/blkdev/flp_drv.inc
162,7 → 162,7
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
pusha
; Сбросить байт состояния операции
mov [FDC_Status], FDC_Normal
; Сбросить флаг прерывани
mov [FDD_IntFlag], 0
; Обнулить счетчик тиков
mov eax, [timer_ticks]
mov [TickCounter], eax
372,6 → 370,8
SeekTrack:
pusha
call save_timer_fdd_motor
; Сбросить флаг прерывания
mov [FDD_IntFlag], 0
; Подать команду "Поиск"
mov AL, 0Fh
call FDCDataOutput
431,6 → 431,8
ReadSector:
pushad
call save_timer_fdd_motor
; Сбросить флаг прерывания
mov [FDD_IntFlag], 0
; Установить скорость передачи 500 Кбайт/с
mov AX, 0
mov DX, 03F7h
531,6 → 533,8
WriteSector:
pushad
call save_timer_fdd_motor
; Сбросить флаг прерывания
mov [FDD_IntFlag], 0
; Установить скорость передачи 500 Кбайт/с
mov AX, 0
mov DX, 03F7h
/kernel/branches/Kolibri-acpi/boot/bootcode.inc
51,18 → 51,20
; 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
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
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
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
 
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
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
; _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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
/kernel/branches/Kolibri-acpi/boot/booten.inc
15,10 → 15,10
 
 
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
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
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
/kernel/branches/Kolibri-acpi/boot/bootet.inc
15,24 → 15,24
 
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,"║ "
39,67 → 39,68
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
/kernel/branches/Kolibri-acpi/boot/bootge.inc
15,10 → 15,8
 
 
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
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
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
/kernel/branches/Kolibri-acpi/boot/bootru.inc
15,89 → 15,90
 
 
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
/kernel/branches/Kolibri-acpi/boot/bootsp.inc
17,26 → 17,24
 
 
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,"║ "
43,67 → 41,68
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
/kernel/branches/Kolibri-acpi/boot/bootvesa.inc
79,6 → 79,7
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
/kernel/branches/Kolibri-acpi/boot/et.inc
9,7 → 9,7
 
 
; Full ASCII code font
; only õ and ä added
; only õ,ä,ü added
; Kaitz
ET_FNT:
fontfile file "ETFONT.FNT"
/kernel/branches/Kolibri-acpi/bus/usb/hub.inc
105,6 → 105,9
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
; 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
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
; 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
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
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
; 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
shr ecx, 3
inc ecx
sub ecx, [length]
jbe .restart
push eax edi
mov edi, [buffer]
add edi, [length]
/kernel/branches/Kolibri-acpi/bus/usb/protocol.inc
202,8 → 202,7
; 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
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
/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
;------------------------------------------------------------------------------
/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
/kernel/branches/Kolibri-acpi/core/dll.inc
458,7 → 458,6
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
 
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,8 → 515,22
 
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
509,7 → 537,6
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
@@:
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:
/kernel/branches/Kolibri-acpi/core/exports.inc
82,6 → 82,8
delete_keyboard, 'DelKeyboard', \
get_cpu_freq, 'GetCpuFreq', \
\
new_sys_threads, 'CreateThread', \ ; ebx, ecx, edx
\
srv_handler, 'ServiceHandler', \
fpu_save, 'FpuSave', \
fpu_restore, 'FpuRestore', \
/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
/kernel/branches/Kolibri-acpi/core/sys32.inc
247,7 → 247,84
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
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
restore reg_ss
/kernel/branches/Kolibri-acpi/core/syscall.inc
184,7 → 184,7
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
/kernel/branches/Kolibri-acpi/core/taskman.inc
924,10 → 924,17
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,8 → 942,8
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
943,8 → 950,7
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
 
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
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
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
 
/kernel/branches/Kolibri-acpi/data32.inc
49,48 → 49,50
 
 
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
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
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
 
/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
/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:
/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 .
---------------------------------------------------------------------------------------------
/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
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
* eax = 40 - номер функции
* ebx = маска: бит i соответствует событию i+1 (см. список событий)
(установленный бит разрешает извещение о событии)
bit 31: фильтр активности событий мыши
bit 31 = 0 - неактивное окно всегда получает события от мыши
bit 31 = 1 - неактивное окно не получает события от мыши
bit 30: фильтр позиции курсора
bit 30 = 0 - окно принимает события мыши, если курсор
за пределами окна
bit 30 = 1 - окно не принимает события мыши, если курсор
за пределами окна
Возвращаемое значение:
* eax = предыдущее значение маски
Замечания:
2420,6 → 2429,70
* иначе 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 =====================
========== Начать проигрывать данные на встроенном спикере. ==========
======================================================================
3495,6 → 3568,32
номер сигнала соответствует номеру исключения.
 
======================================================================
= Функция 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 - отладка. =======================
======================================================================
Процесс может загрузить другой процесс как отлаживаемый установкой
/kernel/branches/Kolibri-acpi/docs/sysfuncs.txt
33,7 → 33,7
* 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
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
* 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
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.
 
1785,7 → 1786,7
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
* 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
2411,6 → 2412,70
</UL>
 
======================================================================
==================== 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.
======================================================================
Parameters:
3953,7 → 4018,7
* +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
/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
/kernel/branches/Kolibri-acpi/drivers/imports.inc
60,6 → 60,7
CreateRingBuffer,\
\
GetPid,\
CreateThread,\
CreateObject,\
DestroyObject,\
CreateEvent,\
/kernel/branches/Kolibri-acpi/drivers/usbstor.asm
1002,13 → 1002,12
; 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
/kernel/branches/Kolibri-acpi/encoding.inc
97,6 → 97,12
end while
}
 
struc cp866 [arg]
{
common
cp866 arg
}
 
; Latin-1 encoding
; 0x00-0xFF - trivial map
macro latin1 [arg]
117,6 → 123,12
end while
}
 
struc latin1 [arg]
{
common
latin1 arg
}
 
; CP850 encoding
macro cp850 [arg]
{ local offs, char, graph
147,3 → 159,9
end if
end while
}
 
struc cp850 [arg]
{
common
cp850 arg
}
/kernel/branches/Kolibri-acpi/fs/ext2.inc
File deleted
Property changes:
Deleted: svn:keywords
-Rev
\ No newline at end of property
/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
/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
/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
/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
/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
/kernel/branches/Kolibri-acpi/fs/ext2
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/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
/kernel/branches/Kolibri-acpi/fs/fs.inc
24,6 → 24,8
 
if lang eq sp
include 'fs/fs-sp.inc'
else if lang eq et
include 'fs/fs-et.inc'
else
dir0:
db 'HARDDISK '
/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
/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
/kernel/branches/Kolibri-acpi/gui/font.inc
233,6 → 233,8
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
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
/kernel/branches/Kolibri-acpi/kernel.asm
144,6 → 144,8
 
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
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
@@:
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
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
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
 
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,7 → 3910,65
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
;--------------------------------------
align 4
5511,13 → 5587,13
 
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
/kernel/branches/Kolibri-acpi/kernel32.inc
171,6 → 171,7
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 "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
 
/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,$
/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
 
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
 
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
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
 
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
 
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
; 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
 
.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
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,14 → 334,14
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)
348,10 → 348,10
; 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
.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,33 → 401,33
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
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.FRAGMENT_entry + IPv4_header.TotalLength] ; Add total length
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
xchg cl, ch
454,18 → 454,18
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
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
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,11 → 497,9
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
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:
527,19 → 528,19
 
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,10 → 553,9
;
; IPv4_output
;
; IN: eax = dest ip
; ebx = output device ptr/0 for automatic choice
; IN: eax = Destination IP
; ecx = data length
; edx = source ip
; edx = Source IP
; di = TTL shl 8 + protocol
;
; OUT: eax = pointer to buffer start
573,10 → 573,10
cmp ecx, 65500 ; Max IPv4 packet size
ja .too_large
 
push ecx eax edx di
push ecx di eax
call IPv4_route ; outputs device number in edi, dest ip in eax, source IP in edx
push edx
 
call IPv4_route ; outputs device number in edi, dest ip in eax
 
test edi, edi
jz .loopback
 
586,12 → 586,12
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
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
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_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]
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
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
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:
/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,6 → 33,14
 
ends
 
struct ETH_queue_entry
 
device dd ?
packet dd ?
size dd ?
 
ends
 
iglobal
align 4
 
38,6 → 47,26
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,9 → 82,61
;-----------------------------------------------------------------
align 4
ETH_input:
mov eax, [esp]
mov ecx, [esp+4]
 
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,7 → 159,7
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"
/kernel/branches/Kolibri-acpi/network/icmp.inc
310,15 → 310,16
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
 
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,6 → 372,7
DEBUGF DEBUG_NETWORK_ERROR, "Creating ICMP Packet failed\n"
add esp, 2*4 + 2
ret
end if
 
 
 
380,7 → 379,7
 
;-----------------------------------------------------------------
;
; ICMP_output
; ICMP_output_raw
;
; IN: eax = socket ptr
; ecx = data length
/kernel/branches/Kolibri-acpi/network/socket.inc
39,6 → 39,7
 
snd_proc dd ?
rcv_proc dd ?
connect_proc dd ?
 
ends
 
131,6 → 132,7
timer_persist dd ?
timer_keepalive dd ? ; keepalive/syn timeout
timer_timed_wait dd ? ; also used as 2msl timer
timer_connect dd ?
 
; extra
 
142,6 → 144,7
temp_bits db ?
rb 3 ; align
 
 
ends
 
struct UDP_SOCKET IP_SOCKET
148,7 → 151,6
 
LocalPort dw ? ; network byte order
RemotePort dw ? ; network byte order
firstpacket db ?
 
ends
 
309,6 → 311,7
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
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
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
.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
.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
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
 
.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,9 → 510,19
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
mov dword[esp+32], -1
509,153 → 533,19
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
connect_notsupp:
xor eax, eax
dec eax
mov ebx, EOPNOTSUPP
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
ret
 
 
;-----------------------------------------------------------------
;
; SOCKET_listen
865,6 → 755,9
call [eax + SOCKET.rcv_proc]
pop edi
 
test [eax + SOCKET.state], SS_CANTRCVMORE
jnz .return
 
cmp ebx, EWOULDBLOCK
jne .return
 
871,9 → 764,6
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
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
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
.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,11 → 870,12
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
 
991,10 → 882,11
.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
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
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
call mutex_unlock
popa
 
.quickret:
ret
 
 
2390,10 → 2289,10
 
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
 
 
 
/kernel/branches/Kolibri-acpi/network/stack.inc
115,6 → 115,7
 
; Error Codes
ENOBUFS = 1
EINPROGRESS = 2
EOPNOTSUPP = 4
EWOULDBLOCK = 6
ENOTCONN = 9
125,6 → 126,7
EADDRINUSE = 20
ECONNREFUSED = 61
ECONNRESET = 52
EISCONN = 56
ETIMEDOUT = 60
ECONNABORTED = 53
 
248,6 → 250,8
mov ecx, (NET_DEVICES_MAX + 2)
rep stosd
 
ETH_init
 
PPPoE_init
 
IPv4_init
/kernel/branches/Kolibri-acpi/network/tcp.inc
71,6 → 71,8
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
/kernel/branches/Kolibri-acpi/network/tcp_output.inc
437,8 → 437,6
; 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
/kernel/branches/Kolibri-acpi/network/tcp_usreq.inc
74,8 → 74,139
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
 
 
 
 
;-------------------------
;
; TCP_disconnect
/kernel/branches/Kolibri-acpi/network/udp.inc
182,7 → 182,7
;
; 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
 
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
 
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_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