From 4a1560020b21c459de29eb9f374c6ac89374dddc Mon Sep 17 00:00:00 2001 From: "Marat Zakiyanov (Mario79)" Date: Sun, 18 Jun 2006 16:42:03 +0000 Subject: [PATCH] =?UTF-8?q?Added:=201)=20Low=20level=20procedures=20for=20?= =?UTF-8?q?=D0=A1D=20device:=20read=20sector,=20load=20tray,=20out=20tray;?= =?UTF-8?q?=202)=20Function=2070/0=20for=20ISO9660=20-=20read=20file=202)?= =?UTF-8?q?=20Function=2070/0=20for=20ISO9660=20-=20read=20directory=20in?= =?UTF-8?q?=20format=20of=20standard=201.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: svn://kolibrios.org@87 a494cfbc-eb01-0410-851d-a64ba20cac60 --- kernel/trunk/blkdev/cd_drv.inc | 546 ++++++++++++++++++++++++++++ kernel/trunk/fs/fs_lfn.inc | 130 +++++++ kernel/trunk/fs/iso9660.inc | 631 +++++++++++++++++++++++++++++++++ kernel/trunk/kernel32.inc | 2 + 4 files changed, 1309 insertions(+) create mode 100644 kernel/trunk/blkdev/cd_drv.inc create mode 100644 kernel/trunk/fs/iso9660.inc diff --git a/kernel/trunk/blkdev/cd_drv.inc b/kernel/trunk/blkdev/cd_drv.inc new file mode 100644 index 0000000000..36b5b5feb1 --- /dev/null +++ b/kernel/trunk/blkdev/cd_drv.inc @@ -0,0 +1,546 @@ +;********************************************************** +; Непосредственная работа с устройством СD (ATAPI) +;********************************************************** +; Автор исходного текста Кулаков Владимир Геннадьевич. +; Адаптация и доработка Mario79 + +; Процедура для полного считывания всех +; данных из сектора компакт-диска +; Автор текста программы Кулаков Владимир Геннадьевич. + + +; Максимальное количество повторений операции чтения +MaxRetr equ 3 +; Предельное время ожидания готовности к приему команды +; (в тиках) +BSYWaitTime equ 1000 ;2 + +;************************************************* +;* ПОЛНОЕ ЧТЕНИЕ СЕКТОРА КОМПАКТ-ДИСКА * +;* Считываются данные пользователя, информация * +;* субканала и контрольная информация * +;* Входные параметры передаются через глобальные * +;* перменные: * +;* ChannelNumber - номер канала; * +;* DiskNumber - номер диска на канале; * +;* CDSectorAddress - адрес считываемого сектора. * +;* Данные считывается в массив CDDataBuf. * +;************************************************* +ReadCD: + pusha +; Задать размер сектора + mov [CDBlockSize],2048 ;2352 +; Очистить буфер пакетной команды + call clear_packet_buffer +; Сформировать пакетную команду для считывания +; сектора данных + ; Задать код команды Read CD + mov [PacketCommand],byte 0x28 ;0xBE + ; Задать адрес сектора + mov AX,word [CDSectorAddress+2] + xchg AL,AH + mov word [PacketCommand+2],AX + mov AX,word [CDSectorAddress] + xchg AL,AH + mov word [PacketCommand+4],AX +; mov eax,[CDSectorAddress] +; mov [PacketCommand+2],eax + ; Задать количество считываемых секторов + mov [PacketCommand+8],byte 1 + ; Задать считывание данных в полном объеме +; mov [PacketCommand+9],byte 0xF8 +; Подать команду + call SendPacketDatCommand +; call test_mario79 + popa + ret + +;******************************************** +;* ЧТЕНИЕ СЕКТОРА С ПОВТОРАМИ * +;* Многократное повторение чтения при сбоях * +;******************************************** +ReadCDWRetr: + pusha +; Цикл, пока команда не выполнена успешно или не +; исчерпано количество попыток + mov ECX,MaxRetr +@@NextRetr: +; Подать команду + call ReadCD + cmp [DevErrorCode],0 + je @@End_4 +; Задержка на 2,5 секунды + mov EAX,[timer_ticks] + add EAX,250 ;50 +@@Wait: + call change_task + cmp EAX,[timer_ticks] + ja @@Wait + loop @@NextRetr +; call test_mario79 +; Сообщение об ошибке +; mov SI,offset ErrS +; call FatalError +@@End_4: + popa + ret + + +; Универсальные процедуры, обеспечивающие выполнение +; пакетных команд в режиме PIO +; +; Автор текста программы Кулаков Владимир Геннадьевич. + +; Максимально допустимое время ожидания реакции +; устройства на пакетную команду (в тиках) +MaxCDWaitTime equ 1000 ;200 ;10 секунд + +; Область памяти для формирования пакетной команды +PacketCommand: rb 12 ;DB 12 DUP (?) +; Область памяти для приема данных от дисковода +;CDDataBuf DB 4096 DUP (0) +; Размер принимаемого блока данных в байтах +CDBlockSize DW ? +; Адрес считываемого сектора данных +CDSectorAddress: DD ? +; Время начала очередной операции с диском +TickCounter_1 DD 0 +; Время начала ожидания готовности устройства +WURStartTime DD 0 +; указатель буфера для считывания +CDDataBuf_pointer dd 0 + +;**************************************************** +;* ПОСЛАТЬ УСТРОЙСТВУ ATAPI ПАКЕТНУЮ КОМАНДУ, * +;* ПРЕДУСМАТРИВАЮЩУЮ ПЕРЕДАЧУ ОДНОГО СЕКТОРА ДАННЫХ * +;* РАЗМЕРОМ 2048 БАЙТ ОТ УСТРОЙСТВА К ХОСТУ * +;* Входные параметры передаются через глобальные * +;* перменные: * +;* ChannelNumber - номер канала; * +;* DiskNumber - номер диска на канале; * +;* PacketCommand - 12-байтный командный пакет; * +;* CDBlockSize - размер принимаемого блока данных. * +;**************************************************** +SendPacketDatCommand: + pushad +; Задать режим CHS + mov [ATAAddressMode],0 +; Послать ATA-команду передачи пакетной команды + mov [ATAFeatures],0 + mov [ATASectorCount],0 + mov [ATASectorNumber],0 + ; Загрузить размер передаваемого блока + mov AX,[CDBlockSize] + mov [ATACylinder],AX + mov [ATAHead],0 + mov [ATACommand],0A0h + call SendCommandToHDD_1 +; call test_mario79 + cmp [DevErrorCode],0 ;проверить код ошибки + jne @@End_8 ;закончить, сохранив код ошибки + +; Ожидание готовности дисковода к приему +; пакетной команды + mov DX,[ATABasePortAddr] + add DX,7 ;порт 1х7h +@@WaitDevice0: + call change_task + ; Проверить время выполнения команды + mov EAX,[timer_ticks] + sub EAX,[TickCounter_1] + cmp EAX,BSYWaitTime + ja @@Err1_1 ;ошибка тайм-аута + ; Проверить готовность + in AL,DX + test AL,80h ;состояние сигнала BSY + jnz @@WaitDevice0 + test AL,1 ;состояние сигнала ERR + jnz @@Err6 + test AL,08h ;состояние сигнала DRQ + jz @@WaitDevice0 +; Послать пакетную команду + cli + mov DX,[ATABasePortAddr] + mov AX,[PacketCommand] + out DX,AX + mov AX,[PacketCommand+2] + out DX,AX + mov AX,[PacketCommand+4] + out DX,AX + mov AX,[PacketCommand+6] + out DX,AX + mov AX,[PacketCommand+8] + out DX,AX + mov AX,[PacketCommand+10] + out DX,AX + sti +; Ожидание готовности данных + mov DX,[ATABasePortAddr] + add DX,7 ;порт 1х7h +@@WaitDevice1: + call change_task + ; Проверить время выполнения команды + mov EAX,[timer_ticks] + sub EAX,[TickCounter_1] + cmp EAX,MaxCDWaitTime + ja @@Err1_1 ;ошибка тайм-аута + ; Проверить готовность + in AL,DX + test AL,80h ;состояние сигнала BSY + jnz @@WaitDevice1 + test AL,1 ;состояние сигнала ERR + jnz @@Err6_temp + test AL,08h ;состояние сигнала DRQ + jz @@WaitDevice1 + cli +; Принять блок данных от контроллера + mov EDI,[CDDataBuf_pointer] ;0x7000 ;CDDataBuf + ; Загрузить адрес регистра данных контроллера + mov DX,[ATABasePortAddr] ;порт 1x0h + ; Загрузить в счетчик размер блока в байтах + mov CX,[CDBlockSize] + ; Вычислить размер блока в 16-разрядных словах + shr CX,1 ;разделить размер блока на 2 + ; Принять блок данных + cld + rep insw + sti + ; Успешное завершение приема данных + jmp @@End_8 + +; Записать код ошибки +@@Err1_1: + mov [DevErrorCode],1 + jmp @@End_8 +@@Err6_temp: + mov [DevErrorCode],7 + jmp @@End_8 +@@Err6: + mov [DevErrorCode],6 + +@@End_8: + popad + ret + + + +;*********************************************** +;* ПОСЛАТЬ УСТРОЙСТВУ ATAPI ПАКЕТНУЮ КОМАНДУ, * +;* НЕ ПРЕДУСМАТРИВАЮЩУЮ ПЕРЕДАЧИ ДАННЫХ * +;* Входные параметры передаются через * +;* глобальные перменные: * +;* ChannelNumber - номер канала; * +;* DiskNumber - номер диска на канале; * +;* PacketCommand - 12-байтный командный пакет. * +;*********************************************** +SendPacketNoDatCommand: + pushad +; Задать режим CHS + mov [ATAAddressMode],0 +; Послать ATA-команду передачи пакетной команды + mov [ATAFeatures],0 + mov [ATASectorCount],0 + mov [ATASectorNumber],0 + mov [ATACylinder],0 + mov [ATAHead],0 + mov [ATACommand],0A0h + call SendCommandToHDD_1 + cmp [DevErrorCode],0 ;проверить код ошибки + jne @@End_9 ;закончить, сохранив код ошибки +; Ожидание готовности дисковода к приему +; пакетной команды + mov DX,[ATABasePortAddr] + add DX,7 ;порт 1х7h +@@WaitDevice0_1: + call change_task + ; Проверить время ожидания + mov EAX,[timer_ticks] + sub EAX,[TickCounter_1] + cmp EAX,BSYWaitTime + ja @@Err1_3 ;ошибка тайм-аута + ; Проверить готовность + in AL,DX + test AL,80h ;состояние сигнала BSY + jnz @@WaitDevice0_1 + test AL,1 ;состояние сигнала ERR + jnz @@Err6_1 + test AL,08h ;состояние сигнала DRQ + jz @@WaitDevice0_1 +; Послать пакетную команду +; cli + mov DX,[ATABasePortAddr] + mov AX,word [PacketCommand] + out DX,AX + mov AX,word [PacketCommand+2] + out DX,AX + mov AX,word [PacketCommand+4] + out DX,AX + mov AX,word [PacketCommand+6] + out DX,AX + mov AX,word [PacketCommand+8] + out DX,AX + mov AX,word [PacketCommand+10] + out DX,AX +; sti +; Ожидание подтверждения приема команды + mov DX,[ATABasePortAddr] + add DX,7 ;порт 1х7h +@@WaitDevice1_1: + call change_task + ; Проверить время выполнения команды + mov EAX,[timer_ticks] + sub EAX,[TickCounter_1] + cmp EAX,MaxCDWaitTime + ja @@Err1_3 ;ошибка тайм-аута + ; Ожидать освобождения устройства + in AL,DX + test AL,80h ;состояние сигнала BSY + jnz @@WaitDevice1_1 + test AL,1 ;состояние сигнала ERR + jnz @@Err6_1 + test AL,40h ;состояние сигнала DRDY + jz @@WaitDevice1_1 + jmp @@End_9 + +; Записать код ошибки +@@Err1_3: + mov [DevErrorCode],1 + jmp @@End_9 +@@Err6_1: + mov [DevErrorCode],6 +@@End_9: + popad + ret + +;**************************************************** +;* ПОСЛАТЬ КОМАНДУ ЗАДАННОМУ ДИСКУ * +;* Входные параметры передаются через глобальные * +;* переменные: * +;* ChannelNumber - номер канала (1 или 2); * +;* DiskNumber - номер диска (0 или 1); * +;* ATAFeatures - "особенности"; * +;* ATASectorCount - количество секторов; * +;* ATASectorNumber - номер начального сектора; * +;* ATACylinder - номер начального цилиндра; * +;* ATAHead - номер начальной головки; * +;* ATAAddressMode - режим адресации (0-CHS, 1-LBA); * +;* ATACommand - код команды. * +;* После успешного выполнения функции: * +;* в ATABasePortAddr - базовый адрес HDD; * +;* в DevErrorCode - ноль. * +;* При возникновении ошибки в DevErrorCode будет * +;* возвращен код ошибки. * +;**************************************************** +SendCommandToHDD_1: + pushad +; Проверить значение кода режима + cmp [ATAAddressMode],1 + ja @@Err2_4 +; Проверить корректность номера канала + mov BX,[ChannelNumber] + cmp BX,1 + jb @@Err3_4 + cmp BX,2 + ja @@Err3_4 +; Установить базовый адрес + dec BX + shl BX,1 + movzx ebx,bx + mov AX,[ebx+StandardATABases] + mov [ATABasePortAddr],AX +; Ожидание готовности HDD к приему команды + ; Выбрать нужный диск + mov DX,[ATABasePortAddr] + add DX,6 ;адрес регистра головок + mov AL,[DiskNumber] + cmp AL,1 ;проверить номера диска + ja @@Err4_4 + shl AL,4 + or AL,10100000b + out DX,AL + ; Ожидать, пока диск не будет готов + inc DX +; mov ecx,0xfff + mov eax,[timer_ticks] + mov [TickCounter_1],eax +@@WaitHDReady_2: + call change_task + ; Проверить время ожидания +; dec ecx +; cmp ecx,0 +; je @@Err1 + mov eax,[timer_ticks] + sub eax,[TickCounter_1] + cmp eax,BSYWaitTime ;300 ;ожидать 3 сек. + ja @@Err1_4 ;ошибка тайм-аута + ; Прочитать регистр состояния + in AL,DX + ; Проверить состояние сигнала BSY + test AL,80h + jnz @@WaitHDReady_2 + ; Проверить состояние сигнала DRQ + test AL,08h + jnz @@WaitHDReady_2 +; Загрузить команду в регистры контроллера + cli + mov DX,[ATABasePortAddr] + inc DX ;регистр "особенностей" + mov AL,[ATAFeatures] + out DX,AL + inc DX ;счетчик секторов + mov AL,[ATASectorCount] + out DX,AL + inc DX ;регистр номера сектора + mov AL,[ATASectorNumber] + out DX,AL + inc DX ;номер цилиндра (младший байт) + mov AX,[ATACylinder] + out DX,AL + inc DX ;номер цилиндра (старший байт) + mov AL,AH + out DX,AL + inc DX ;номер головки/номер диска + mov AL,[DiskNumber] + shl AL,4 + cmp [ATAHead],0Fh ;проверить номер головки + ja @@Err5_4 + or AL,[ATAHead] + or AL,10100000b + mov AH,[ATAAddressMode] + shl AH,6 + or AL,AH + out DX,AL +; Послать команду + mov AL,[ATACommand] + inc DX ;регистр команд + out DX,AL + sti +; Сбросить признак ошибки + mov [DevErrorCode],0 + jmp @@End_10 +; Записать код ошибки +@@Err1_4: + mov [DevErrorCode],1 + jmp @@End_10 +@@Err2_4: + mov [DevErrorCode],2 + jmp @@End_10 +@@Err3_4: + mov [DevErrorCode],3 + jmp @@End_10 +@@Err4_4: + mov [DevErrorCode],4 + jmp @@End_10 +@@Err5_4: + mov [DevErrorCode],5 +; Завершение работы программы +@@End_10: + sti + popad + ret + +;************************************************* +;* ОЖИДАНИЕ ГОТОВНОСТИ УСТРОЙСТВА К РАБОТЕ * +;* Входные параметры передаются через глобальные * +;* перменные: * +;* ChannelNumber - номер канала; * +;* DiskNumber - номер диска на канале. * +;************************************************* +WaitUnitReady: + pusha +; Запомнить время начала операции + mov EAX,[timer_ticks] + mov [WURStartTime],EAX +; Очистить буфер пакетной команды + call clear_packet_buffer +; Сформировать команду TEST UNIT READY + mov [PacketCommand],word 00h +; ЦИКЛ ОЖИДАНИЯ ГОТОВНОСТИ УСТРОЙСТВА +@@SendCommand: + ; Подать команду проверки готовности + call SendPacketNoDatCommand + call change_task + ; Проверить код ошибки + cmp [DevErrorCode],0 + je @@End_11 + ; Проверить время ожидания готовности + mov EAX,[timer_ticks] + sub EAX,[WURStartTime] + cmp EAX,MaxCDWaitTime + jb @@SendCommand + ; Ошибка тайм-аута + mov [DevErrorCode],1 +@@End_11: + popa + ret + + +;************************************************* +;* ЗАГРУЗИТЬ НОСИТЕЛЬ В ДИСКОВОД * +;* Входные параметры передаются через глобальные * +;* перменные: * +;* ChannelNumber - номер канала; * +;* DiskNumber - номер диска на канале. * +;************************************************* +LoadMedium: + pusha +; Очистить буфер пакетной команды + call clear_packet_buffer +; Сформировать команду START/STOP UNIT + ; Задать код команды + mov [PacketCommand],word 1Bh + ; Задать операцию загрузки носителя + mov [PacketCommand+4],word 00000011b +; Подать команду + call SendPacketNoDatCommand + popa + ret + +;************************************************* +;* ИЗВЛЕЧЬ НОСИТЕЛЬ ИЗ ДИСКОВОДА * +;* Входные параметры передаются через глобальные * +;* перменные: * +;* ChannelNumber - номер канала; * +;* DiskNumber - номер диска на канале. * +;************************************************* +UnloadMedium: + pusha +; Очистить буфер пакетной команды + call clear_packet_buffer +; Сформировать команду START/STOP UNIT + ; Задать код команды + mov [PacketCommand],word 1Bh + ; Задать операцию извлечения носителя + mov [PacketCommand+4],word 00000010b +; Подать команду + call SendPacketNoDatCommand + popa + ret + +;************************************************* +;* ОПРЕДЕЛИТЬ ОБЩЕЕ КОЛИЧЕСТВО СЕКТОРОВ НА ДИСКЕ * +;* Входные параметры передаются через глобальные * +;* переменные: * +;* ChannelNumber - номер канала; * +;* DiskNumber - номер диска на канале. * +;************************************************* +ReadCapacity: + pusha +; Очистить буфер пакетной команды + call clear_packet_buffer +; Задать размер буфера в байтах + mov [CDBlockSize],8 +; Сформировать команду READ CAPACITY + mov [PacketCommand],word 25h +; Подать команду + call SendPacketDatCommand + popa + ret + +clear_packet_buffer: +; Очистить буфер пакетной команды + mov [PacketCommand],dword 0 + mov [PacketCommand+4],dword 0 + mov [PacketCommand+8],dword 0 + ret + diff --git a/kernel/trunk/fs/fs_lfn.inc b/kernel/trunk/fs/fs_lfn.inc index 53929923c6..1b4699835a 100644 --- a/kernel/trunk/fs/fs_lfn.inc +++ b/kernel/trunk/fs/fs_lfn.inc @@ -28,8 +28,23 @@ rootdirs: db 3,'hd3' dd fs_OnHd3 dd fs_NextHd3 +;********************************************** + db 3,'cd0' + dd fs_OnCd0 + dd fs_NextCd + db 3,'cd1' + dd fs_OnCd1 + dd fs_NextCd + db 3,'cd2' + dd fs_OnCd2 + dd fs_NextCd + db 3,'cd3' + dd fs_OnCd3 + dd fs_NextCd +;*********************************************** db 0 + virtual_root_query: dd fs_HasRamdisk db 'rd',0 @@ -43,6 +58,16 @@ virtual_root_query: db 'hd2',0 dd fs_HasHd3 db 'hd3',0 +;********************************************** + dd fs_HasCd0 + db 'cd0',0 + dd fs_HasCd1 + db 'cd1',0 + dd fs_HasCd2 + db 'cd2',0 + dd fs_HasCd3 + db 'cd3',0 +;********************************************** dd 0 endg @@ -420,6 +445,71 @@ fs_HdServices: dd fs_HdSetFileInfo fs_NumHdServices = ($ - fs_HdServices)/4 +;******************************************************* +fs_OnCd0: + call reserve_cd + mov [ChannelNumber],1 + mov [DiskNumber],0 + push 6 + jmp fs_OnCd +fs_OnCd1: + call reserve_cd + mov [ChannelNumber],1 + mov [DiskNumber],1 + push 4 + jmp fs_OnCd +fs_OnCd2: + call reserve_cd + mov [ChannelNumber],2 + mov [DiskNumber],0 + push 2 + jmp fs_OnCd +fs_OnCd3: + call reserve_cd + mov [ChannelNumber],2 + mov [DiskNumber],1 + push 0 +fs_OnCd: + + pop eax + mov [hdpos], eax + cmp ecx, 0x100 + jae .nf + push cx bx + mov cl,al + mov bl,[0x40001] + shr bl,cl + test bl,2 + pop bx cx + + jnz @f +.nf: + and [cd_status], 0 + mov dword [esp+36], 5 ; not found + ret +@@: + mov ecx, [ebx+12] + mov edx, [ebx+16] + add edx, std_application_base_address + mov eax, [ebx] + cmp eax, 1 + ja .not_impl + add ebx, 4 + call dword [fs_CdServices + eax*4] + and [cd_status], 0 + mov [esp+36], eax + mov [esp+24], ebx + ret +.not_impl: + and [hd1_status], 0 + mov dword [esp+36], 2 ; not implemented + ret + +fs_CdServices: + dd fs_CdRead + dd fs_CdReadFolder +;******************************************************* + fs_HasRamdisk: mov al, 1 ; we always have ramdisk ret @@ -454,6 +544,33 @@ fs_HasHd3: setz al ret +;******************************************************* +fs_HasCd0: + mov al, [0x40001] + and al, 11000000b + cmp al, 10000000b + setz al + ret +fs_HasCd1: + mov al, [0x40001] + and al, 00110000b + cmp al, 00100000b + setz al + ret +fs_HasCd2: + mov al, [0x40001] + and al, 00001100b + cmp al, 00001000b + setz al + ret +fs_HasCd3: + mov al, [0x40001] + and al, 00000011b + cmp al, 00000010b + setz al + ret +;******************************************************* + ; fs_NextXXX functions: ; in: eax = partition number, from which start to scan ; out: CF=1 => no more partitions @@ -509,3 +626,16 @@ fs_NextHd: inc eax clc ret + +;******************************************************* +fs_NextCd: +; we always have /cdX/1 + test eax, eax + stc + jnz @f + mov al, 1 + clc +@@: + ret +;******************************************************* + diff --git a/kernel/trunk/fs/iso9660.inc b/kernel/trunk/fs/iso9660.inc new file mode 100644 index 0000000000..0a9be8533c --- /dev/null +++ b/kernel/trunk/fs/iso9660.inc @@ -0,0 +1,631 @@ +uglobal +cd_current_pointer_of_input dd 0 +cd_current_pointer_of_input_2 dd 0 +cd_mem_location dd 0 +cd_counter_block dd 0 +endg + +CDDataBuf equ 0x7000 + +reserve_cd: + + cli + cmp [cd_status],0 + je reserve_ok2 + + sti + call change_task + jmp reserve_hd1 + + reserve_ok2: + + push eax + mov eax,[0x3000] + shl eax,5 + mov eax,[eax+0x3000+4] + mov [cd_status],eax + pop eax + sti + ret + +cd_status dd 0 + +;---------------------------------------------------------------- +; +; fs_CdRead - LFN variant for reading CD disk +; +; esi points to filename /dir1/dir2/.../dirn/file,0 +; ebx pointer to 64-bit number = first wanted byte, 0+ +; may be ebx=0 - start from first byte +; ecx number of bytes to read, 0+ +; edx mem location to return data +; +; ret ebx = bytes read or 0xffffffff file not found +; eax = 0 ok read or other = errormsg +; +;-------------------------------------------------------------- +fs_CdRead: + push edi + cmp byte [esi], 0 + jnz @f +.noaccess: + pop edi +.noaccess_2: + or ebx, -1 + mov eax, ERROR_ACCESS_DENIED + ret + +.noaccess_3: + pop eax edx ecx edi + jmp .noaccess_2 + +@@: + call cd_find_lfn + jnc .found + pop edi + cmp [DevErrorCode],0 + jne .noaccess_2 + or ebx, -1 + mov eax, ERROR_FILE_NOT_FOUND + ret + +.found: + mov edi,[cd_current_pointer_of_input] + test byte [edi+25],10b ; do not allow read directories + jnz .noaccess + test ebx, ebx + jz .l1 + cmp dword [ebx+4], 0 + jz @f + xor ebx, ebx +.reteof: + mov eax, 6 ; end of file + pop edi + ret +@@: + mov ebx, [ebx] +.l1: + push ecx edx + push 0 + mov eax, [edi+10] ; реальный размер файловой секции + sub eax, ebx + jb .eof + cmp eax, ecx + jae @f + mov ecx, eax + mov byte [esp], 6 +@@: + mov eax,[edi+2] + mov [CDSectorAddress],eax +; now eax=cluster, ebx=position, ecx=count, edx=buffer for data +.new_sector: + test ecx, ecx + jz .done + sub ebx, 2048 + jae .new_sector + add ebx, 2048 + jnz .incomplete_sector + cmp ecx, 2048 + jb .incomplete_sector +; we may read and memmove complete sector + mov [CDDataBuf_pointer],edx + call ReadCDWRetr ; читаем сектор файла + cmp [DevErrorCode],0 + jne .noaccess_3 + inc dword [CDSectorAddress] + add edx, 2048 + sub ecx, 2048 + jmp .new_sector +.incomplete_sector: +; we must read and memmove incomplete sector + mov [CDDataBuf_pointer],CDDataBuf + call ReadCDWRetr ; читаем сектор файла + cmp [DevErrorCode],0 + jne .noaccess_3 + inc dword [CDSectorAddress] + mov eax,CDDataBuf + add eax, ebx + push ecx + add ecx, ebx + cmp ecx, 2048 + jbe @f + mov ecx, 2048 +@@: + sub ecx, ebx + push edi esi ecx + mov edi,edx + mov esi,eax ;0x7000 ; CD data buffer + cld + rep movsb + pop ecx esi edi + add edx, ecx + sub [esp], ecx + pop ecx + xor ebx, ebx + jmp .new_sector + +.done: + mov ebx, edx + pop eax edx ecx edi + sub ebx, edx + ret +.eof: + mov ebx, edx + pop eax edx ecx + sub ebx, edx + jmp .reteof + +;---------------------------------------------------------------- +; +; fs_CdReadFolder - LFN variant for reading CD disk folder +; +; esi points to filename /dir1/dir2/.../dirn/file,0 +; ebx pointer to structure 32-bit number = first wanted block, 0+ +; & flags (bitfields) +; flags: bit 0: 0=ANSI names, 1=UNICODE names +; ecx number of blocks to read, 0+ +; edx mem location to return data +; +; ret ebx = blocks read or 0xffffffff folder not found +; eax = 0 ok read or other = errormsg +; +;-------------------------------------------------------------- +fs_CdReadFolder: + push edi + call cd_find_lfn + jnc .found + pop edi + cmp [DevErrorCode],0 + jne .noaccess_1 + or ebx, -1 + mov eax, ERROR_FILE_NOT_FOUND + ret +.found: + mov edi,[cd_current_pointer_of_input] + test byte [edi+25],10b ; do not allow read directories + jnz .found_dir + pop edi +.noaccess_1: + or ebx, -1 + mov eax, ERROR_ACCESS_DENIED + ret +.found_dir: + mov eax,[edi+2] ; eax=cluster + mov [CDSectorAddress],eax + mov eax,[edi+10] ; размер директрории +.doit: +; init header + push eax ecx + mov edi, edx + mov ecx, 32/4 + xor eax, eax + rep stosd + pop ecx eax + mov byte [edx], 1 ; version + mov [cd_mem_location],edx + add [cd_mem_location],32 +; начинаем переброску БДВК в УСВК +;.mainloop: + mov [cd_counter_block],dword 0 + dec dword [CDSectorAddress] + push ecx +.read_to_buffer: + inc dword [CDSectorAddress] + mov [CDDataBuf_pointer],CDDataBuf + call ReadCDWRetr ; читаем сектор директории + cmp [DevErrorCode],0 + jne .noaccess_1 + call .get_names_from_buffer + sub eax,2048 +; директория закончилась? + cmp eax,0 + jg .read_to_buffer + mov edi,[cd_counter_block] + mov [edx+8],edi + mov edi,[ebx] + sub [edx+4],edi + pop ecx edi + xor ebx,ebx + mov eax,ERROR_SUCCESS + ret + +.get_names_from_buffer: + mov [cd_current_pointer_of_input_2],CDDataBuf + push eax esi edi edx +.get_names_from_buffer_1: + call cd_get_name + jc .end_buffer + inc dword [cd_counter_block] + mov eax,[cd_counter_block] + cmp [ebx],eax + jae .get_names_from_buffer_1 + test ecx, ecx + jz .get_names_from_buffer_1 + mov edi,[cd_counter_block] + mov [edx+4],edi + dec ecx + mov esi,ebp + mov edi,[cd_mem_location] + add edi,40 + test dword [ebx+4], 1 ; 0=ANSI, 1=UNICODE + jnz .unicode +; jmp .unicode +.ansi: + cmp [cd_counter_block],2 + jbe .ansi_parent_directory + cld + lodsw + xchg ah,al + call uni2ansi_char + cld + stosb +; проверка конца файла + mov al,[esi+1] + cmp al,byte 3Bh ; сепаратор конца файла ';' + je .cd_get_parameters_of_file_1 +; проверка для файлов не заканчивающихся сепаратором + movzx eax,byte [ebp-33] + add eax,ebp + sub eax,34 + cmp esi,eax + je .cd_get_parameters_of_file_1 +; проверка конца папки + movzx eax,byte [ebp-1] + add eax,ebp + cmp esi,eax + jb .ansi +.cd_get_parameters_of_file_1: + mov [edi],byte 0 + call .cd_get_parameters_of_file + add [cd_mem_location],304 + jmp .get_names_from_buffer_1 + +.ansi_parent_directory: + cmp [cd_counter_block],2 + je @f + mov [edi],byte '.' + inc edi + jmp .cd_get_parameters_of_file_1 +@@: + mov [edi],word '..' + add edi,2 + jmp .cd_get_parameters_of_file_1 + +.unicode: + cmp [cd_counter_block],2 + jbe .unicode_parent_directory + cld + movsw +; проверка конца файла + mov ax,[esi] + cmp ax,word 3B00h ; сепаратор конца файла ';' + je .cd_get_parameters_of_file_2 +; проверка для файлов не заканчивающихся сепаратором + movzx eax,byte [ebp-33] + add eax,ebp + sub eax,34 + cmp esi,eax + je .cd_get_parameters_of_file_2 +; проверка конца папки + movzx eax,byte [ebp-1] + add eax,ebp + cmp esi,eax + jb .unicode +.cd_get_parameters_of_file_2: + mov [edi],word 0 + call .cd_get_parameters_of_file + add [cd_mem_location],560 + jmp .get_names_from_buffer_1 + +.unicode_parent_directory: + cmp [cd_counter_block],2 + je @f + mov [edi],word 2E00h ; '.' + add edi,2 + jmp .cd_get_parameters_of_file_2 +@@: + mov [edi],dword 2E002E00h ; '..' + add edi,4 + jmp .cd_get_parameters_of_file_2 + +.cd_get_parameters_of_file: + mov edi,[cd_mem_location] +; получаем атрибуты файла + xor eax,eax +; файл не архивировался + inc al + shl eax,1 +; это каталог? + test [ebp-8],byte 2 + jz .file + inc al +.file: +; метка тома не как в FAT, в этом виде отсутсвует +; файл не является системным + shl eax,3 +; файл является скрытым? (атрибут существование) + test [ebp-8],byte 1 + jz .hidden + inc al +.hidden: + shl eax,1 +; файл всегда только для чтения, так как это CD + inc al + mov [edi],eax +; получаем время для файла +;час + movzx eax,byte [ebp-12] + shl eax,8 +;минута + mov al,[ebp-11] + shl eax,8 +;секунда + mov al,[ebp-10] +;время создания файла + mov [edi+8],eax +;время последнего доступа + mov [edi+16],eax +;время последней записи + mov [edi+24],eax +; получаем дату для файла +;год + movzx eax,byte [ebp-15] + add eax,1900 + shl eax,8 +;месяц + mov al,[ebp-14] + shl eax,8 +;день + mov al,[ebp-13] +;дата создания файла + mov [edi+12],eax +;время последнего доступа + mov [edi+20],eax +;время последней записи + mov [edi+28],eax +; получаем тип данных имени + xor eax,eax + test dword [ebx+4], 1 ; 0=ANSI, 1=UNICODE + jnz .unicode_1 + mov [edi+4],eax + jmp @f +.unicode_1: + inc eax + mov [edi+4],eax +@@: +; получаем размер файла в байтах + xor eax,eax + mov [edi+32+4],eax + mov eax,[ebp-23] + mov [edi+32],eax + ret + +.end_buffer: + pop edx edi esi eax + ret + +cd_find_lfn: +; in: esi->name +; out: CF=1 - file not found +; else CF=0 and [cd_current_pointer_of_input] direntry + push eax esi +; 16 сектор начало набора дескрипторов томов + mov [CDSectorAddress],dword 15 +.start: + inc dword [CDSectorAddress] + mov [CDDataBuf_pointer],CDDataBuf + call ReadCDWRetr + cmp [DevErrorCode],0 + jne .access_denied +; проверка на вшивость + cmp [CDDataBuf+1],dword 'CD00' + jne .access_denied + cmp [CDDataBuf+5],byte '1' + jne .access_denied +; сектор является терминатором набор дескрипторов томов? + cmp [CDDataBuf],byte 0xff + je .access_denied +; сектор является дополнительным и улучшенным дескриптором тома? + cmp [CDDataBuf],byte 0x2 + jne .start +; сектор является дополнительным дескриптором тома? + cmp [CDDataBuf+6],byte 0x1 + jne .start +; параметры root директрории + mov eax,[CDDataBuf+0x9c+2] ; начало root директрории + mov [CDSectorAddress],eax + mov eax,[CDDataBuf+0x9c+10] ; размер root директрории + cmp byte [esi], 0 + jnz @f + mov [cd_current_pointer_of_input],CDDataBuf+0x9c + jmp .done +@@: +; начинаем поиск +.mainloop: + dec dword [CDSectorAddress] +.read_to_buffer: + inc dword [CDSectorAddress] + mov [CDDataBuf_pointer],CDDataBuf + call ReadCDWRetr ; читаем сектор директории + cmp [DevErrorCode],0 + jne .access_denied + call cd_find_name_in_buffer + jnc .found + sub eax,2048 +; директория закончилась? + cmp eax,0 + jg .read_to_buffer +; нет искомого элемента цепочки +.access_denied: + pop esi eax + stc + ret +; искомый элемент цепочки найден + .found: +; конец пути файла + cmp byte [esi], 0 + jz .done + mov eax,[cd_current_pointer_of_input] + add eax,2 + mov eax,[eax] + mov [CDSectorAddress],eax ; начало директории + add eax,8 + mov eax,[eax] ; размер директории + jmp .mainloop +; указатель файла найден + .done: + pop esi eax + clc + ret + +cd_find_name_in_buffer: + mov [cd_current_pointer_of_input_2],CDDataBuf +.start: + call cd_get_name + jc .not_found + call cd_compare_name + jc .start +.found: + clc + ret +.not_found: + stc + ret + +cd_get_name: + push eax + mov ebp,[cd_current_pointer_of_input_2] + mov [cd_current_pointer_of_input],ebp + mov eax,[ebp] + cmp eax,0 ; входы закончились? + je .next_sector + cmp ebp,CDDataBuf+2048 ; буфер закончился? + jae .next_sector + movzx eax, byte [ebp] + add [cd_current_pointer_of_input_2],eax ; следующий вход каталога + add ebp,33 ; указатель установлен на начало имени + pop eax + clc + ret +.next_sector: + pop eax + stc + ret + +cd_compare_name: +; compares ASCIIZ-names, case-insensitive (cp866 encoding) +; in: esi->name, ebp->name +; out: if names match: ZF=1 and esi->next component of name +; else: ZF=0, esi is not changed +; destroys eax + push esi eax edi + mov edi,ebp +.loop: + cld + lodsb + push ax + call char_toupper + call ansi2uni_char + xchg ah,al + cld + scasw + pop ax + je .coincides + call char_todown + call ansi2uni_char + xchg ah,al + cld + sub edi,2 + scasw + jne .name_not_coincide +.coincides: + cmp [esi],byte '/' ; разделитель пути, конец имени текущего элемента + je .done + cmp [esi],byte 0 ; разделитель пути, конец имени текущего элемента + je .done + jmp .loop +.name_not_coincide: + pop edi eax esi + stc + ret +.done: +; проверка конца файла + cmp [edi],word 3B00h ; сепаратор конца файла ';' + je .done_1 +; проверка для файлов не заканчивающихся сепаратором + movzx eax,byte [ebp-33] + add eax,ebp + sub eax,34 + cmp edi,eax + je .done_1 +; проверка конца папки + movzx eax,byte [ebp-1] + add eax,ebp + cmp edi,eax + jne .name_not_coincide +.done_1: + pop edi eax + add esp,4 + inc esi + clc + ret + +char_todown: +; convert character to uppercase, using cp866 encoding +; in: al=symbol +; out: al=converted symbol + cmp al, 'A' + jb .ret + cmp al, 'Z' + jbe .az + cmp al, 'Ђ' + jb .ret + cmp al, 'ђ' + jb .rus1 + cmp al, 'џ' + ja .ret +; 0x90-0x9F -> 0xE0-0xEF + add al, 'а'-'ђ' +.ret: + ret +.rus1: +; 0x80-0x8F -> 0xA0-0xAF +.az: + add al, 0x20 + ret + +uni2ansi_char: +; convert UNICODE character in al to ANSI character in ax, using cp866 encoding +; in: ax=UNICODE character +; out: al=converted ANSI character + cmp ax, 0x80 + jb .ascii + cmp ax, 0x401 + jz .yo1 + cmp ax, 0x451 + jz .yo2 + cmp ax, 0x410 + jb .unk + cmp ax, 0x440 + jb .rus1 + cmp ax, 0x450 + jb .rus2 +.unk: + mov al, '_' + jmp .doit +.yo1: + mov al, 'р' + jmp .doit +.yo2: + mov al, 'с' + jmp .doit +.rus1: +; 0x410-0x43F -> 0x80-0xAF + add al, 0x70 + jmp .doit +.rus2: +; 0x440-0x44F -> 0xE0-0xEF + add al, 0xA0 +.ascii: +.doit: + ret diff --git a/kernel/trunk/kernel32.inc b/kernel/trunk/kernel32.inc index 30c090fc8d..294970f3d7 100644 --- a/kernel/trunk/kernel32.inc +++ b/kernel/trunk/kernel32.inc @@ -150,6 +150,7 @@ include "fs/fat32.inc" ; read / write for fat32 filesystem include "fs/fat12.inc" ; read / write for fat12 filesystem include "blkdev/rd.inc" ; ramdisk read /write include "fs/fs_lfn.inc" ; syscall, version 2 +include "fs/iso9660.inc" ; read for iso9660 filesystem CD ; sound @@ -186,6 +187,7 @@ include "blkdev/flp_drv.inc" ; CD drive controller include "blkdev/cdrom.inc" +include "blkdev/cd_drv.inc" ; Character devices