/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 |