/kernel/branches/Kolibri-acpi/blkdev/cd_drv.inc |
---|
7,7 → 7,7 |
$Revision$ |
;----------------------------------------------------------------------------- |
;********************************************************** |
; Непосредственная работа с устройством СD (ATAPI) |
;********************************************************** |
37,16 → 37,17 |
xor edi, edi |
add esi, 8 |
inc edi |
;-------------------------------------- |
align 4 |
.hdreadcache: |
; cmp dword [esi+4],0 ; empty |
; je .nohdcache |
cmp [esi], eax ; correct sector |
je .yeshdcache |
.nohdcache: |
add esi, 8 |
inc edi |
dec ecx |
jnz .hdreadcache |
call find_empty_slot_CD_cache ; ret in edi |
push edi |
66,7 → 67,7 |
call cd_calculate_cache_1 |
lea esi, [edi*8+esi] |
mov [esi], eax ; sector number |
; mov dword [esi+4],1 ; hd read - mark as same as in hd |
;-------------------------------------- |
.yeshdcache: |
mov esi, edi |
shl esi, 11;9 |
78,16 → 79,18 |
mov ecx, 512;/4 |
cld |
rep movsd ; move data |
;-------------------------------------- |
.exit: |
popad |
ret |
;----------------------------------------------------------------------------- |
ReadCDWRetr_1: |
pushad |
; Цикл, пока команда не выполнена успешно или не |
; исчерпано количество попыток |
mov ECX, MaxRetr |
mov ecx, MaxRetr |
;-------------------------------------- |
align 4 |
@@NextRetr: |
; Подать команду |
;************************************************* |
103,9 → 106,6 |
;************************************************* |
;ReadCD: |
push ecx |
; pusha |
; Задать размер сектора |
; mov [CDBlockSize],2048 ;2352 |
; Очистить буфер пакетной команды |
call clear_packet_buffer |
; Сформировать пакетную команду для считывания |
113,79 → 113,67 |
; Задать код команды 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 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 [PacketCommand+8], byte 1 |
; Задать считывание данных в полном объеме |
; mov [PacketCommand+9],byte 0xF8 |
; Подать команду |
call SendPacketDatCommand |
pop ecx |
; ret |
; cmp [DevErrorCode],0 |
test eax, eax |
jz @@End_4 |
or ecx, ecx ;{SPraid.simba} (for cd load) |
jz @@End_4 |
dec ecx |
cmp [timer_ticks_enable], 0 |
jne @f |
mov eax, NoTickWaitTime |
;-------------------------------------- |
align 4 |
.wait: |
dec eax |
; test eax,eax |
jz @@NextRetr |
jmp .wait |
;-------------------------------------- |
align 4 |
@@: |
; Задержка на 2,5 секунды |
; mov EAX,[timer_ticks] |
; add EAX,50 ;250 |
;@@Wait: |
; call change_task |
; cmp EAX,[timer_ticks] |
; ja @@Wait |
loop @@NextRetr |
;-------------------------------------- |
@@End_4: |
mov dword [DevErrorCode], eax |
popad |
ret |
;----------------------------------------------------------------------------- |
; Универсальные процедуры, обеспечивающие выполнение |
; пакетных команд в режиме PIO |
; Максимально допустимое время ожидания реакции |
; устройства на пакетную команду (в тиках) |
;----------------------------------------------------------------------------- |
MaxCDWaitTime equ 1000 ;200 ;10 секунд |
uglobal |
; Область памяти для формирования пакетной команды |
PacketCommand: |
rb 12 ;DB 12 DUP (?) |
; Область памяти для приема данных от дисковода |
;CDDataBuf DB 4096 DUP (0) |
; Размер принимаемого блока данных в байтах |
;CDBlockSize DW ? |
; Адрес считываемого сектора данных |
CDSectorAddress: |
DD ? |
CDSectorAddress: dd ? |
; Время начала очередной операции с диском |
TickCounter_1 DD 0 |
TickCounter_1 dd 0 |
; Время начала ожидания готовности устройства |
WURStartTime DD 0 |
WURStartTime dd 0 |
; указатель буфера для считывания |
CDDataBuf_pointer dd 0 |
endg |
;----------------------------------------------------------------------------- |
;**************************************************** |
;* ПОСЛАТЬ УСТРОЙСТВУ ATAPI ПАКЕТНУЮ КОМАНДУ, * |
;* ПРЕДУСМАТРИВАЮЩУЮ ПЕРЕДАЧУ ОДНОГО СЕКТОРА ДАННЫХ * |
200,7 → 188,6 |
;**************************************************** |
SendPacketDatCommand: |
xor eax, eax |
; mov byte [DevErrorCode],al |
; Задать режим CHS |
mov byte [ATAAddressMode], al |
; Послать ATA-команду передачи пакетной команды |
209,125 → 196,134 |
mov byte [ATASectorNumber], al |
; Загрузить размер передаваемого блока |
mov [ATAHead], al |
; mov AX,[CDBlockSize] |
mov [ATACylinder], CDBlockSize |
mov [ATACommand], 0A0h |
mov [ATACommand], 0xA0 |
call SendCommandToHDD_1 |
test eax, eax |
; cmp [DevErrorCode],0 ;проверить код ошибки |
jnz @@End_8 ;закончить, сохранив код ошибки |
; Ожидание готовности дисковода к приему |
; пакетной команды |
mov DX, [ATABasePortAddr] |
add DX, 7 ;порт 1х7h |
mov dx, [ATABasePortAddr] |
add dx, 7 ;порт 1х7h |
mov ecx, NoTickWaitTime |
;-------------------------------------- |
align 4 |
@@WaitDevice0: |
cmp [timer_ticks_enable], 0 |
jne @f |
dec ecx |
; test ecx,ecx |
jz @@Err1_1 |
jmp .test |
;-------------------------------------- |
align 4 |
@@: |
call change_task |
; Проверить время выполнения команды |
mov EAX, [timer_ticks] |
sub EAX, [TickCounter_1] |
cmp EAX, BSYWaitTime |
mov eax, [timer_ticks] |
sub eax, [TickCounter_1] |
cmp eax, BSYWaitTime |
ja @@Err1_1 ;ошибка тайм-аута |
; Проверить готовность |
;-------------------------------------- |
align 4 |
.test: |
in AL, DX |
test AL, 80h ;состояние сигнала BSY |
in al, dx |
test al, 0x80 ;состояние сигнала BSY |
jnz @@WaitDevice0 |
test AL, 1 ;состояние сигнала ERR |
test al, 1 ;состояние сигнала ERR |
jnz @@Err6 |
test AL, 08h ;состояние сигнала DRQ |
test al, 0x8 ;состояние сигнала 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 |
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 |
mov dx, [ATABasePortAddr] |
add dx, 7 ;порт 1х7h |
mov ecx, NoTickWaitTime |
;-------------------------------------- |
align 4 |
@@WaitDevice1: |
cmp [timer_ticks_enable], 0 |
jne @f |
dec ecx |
; test ecx,ecx |
jz @@Err1_1 |
jmp .test_1 |
;-------------------------------------- |
align 4 |
@@: |
call change_task |
; Проверить время выполнения команды |
mov EAX, [timer_ticks] |
sub EAX, [TickCounter_1] |
cmp EAX, MaxCDWaitTime |
mov eax, [timer_ticks] |
sub eax, [TickCounter_1] |
cmp eax, MaxCDWaitTime |
ja @@Err1_1 ;ошибка тайм-аута |
; Проверить готовность |
;-------------------------------------- |
align 4 |
.test_1: |
in AL, DX |
test AL, 80h ;состояние сигнала BSY |
in al, dx |
test al, 0x80 ;состояние сигнала BSY |
jnz @@WaitDevice1 |
test AL, 1 ;состояние сигнала ERR |
test al, 1 ;состояние сигнала ERR |
jnz @@Err6_temp |
test AL, 08h ;состояние сигнала DRQ |
test al, 0x8 ;состояние сигнала DRQ |
jz @@WaitDevice1 |
; Принять блок данных от контроллера |
mov EDI, [CDDataBuf_pointer];0x7000 ;CDDataBuf |
mov edi, [CDDataBuf_pointer] |
; Загрузить адрес регистра данных контроллера |
mov DX, [ATABasePortAddr];порт 1x0h |
mov dx, [ATABasePortAddr] |
; Загрузить в счетчик размер блока в байтах |
xor ecx, ecx |
mov CX, CDBlockSize |
mov cx, CDBlockSize |
; Вычислить размер блока в 16-разрядных словах |
shr CX, 1;разделить размер блока на 2 |
shr cx, 1 ;разделить размер блока на 2 |
; Принять блок данных |
cli |
cld |
rep insw |
sti |
;-------------------------------------- |
; Успешное завершение приема данных |
@@End_8: |
xor eax, eax |
ret |
;-------------------------------------- |
; Записать код ошибки |
@@Err1_1: |
xor eax, eax |
inc eax |
ret |
; mov [DevErrorCode],1 |
; ret |
;-------------------------------------- |
@@Err6_temp: |
mov eax, 7 |
ret |
; mov [DevErrorCode],7 |
; ret |
;-------------------------------------- |
@@Err6: |
mov eax, 6 |
ret |
; mov [DevErrorCode],6 |
;@@End_8: |
; ret |
;----------------------------------------------------------------------------- |
;*********************************************** |
;* ПОСЛАТЬ УСТРОЙСТВУ ATAPI ПАКЕТНУЮ КОМАНДУ, * |
;* НЕ ПРЕДУСМАТРИВАЮЩУЮ ПЕРЕДАЧИ ДАННЫХ * |
340,7 → 336,6 |
SendPacketNoDatCommand: |
pushad |
xor eax, eax |
; mov byte [DevErrorCode],al |
; Задать режим CHS |
mov byte [ATAAddressMode], al |
; Послать ATA-команду передачи пакетной команды |
349,82 → 344,93 |
mov byte [ATASectorNumber], al |
mov word [ATACylinder], ax |
mov byte [ATAHead], al |
mov [ATACommand], 0A0h |
mov [ATACommand], 0xA0 |
call SendCommandToHDD_1 |
; cmp [DevErrorCode],0 ;проверить код ошибки |
test eax, eax |
jnz @@End_9 ;закончить, сохранив код ошибки |
; Ожидание готовности дисковода к приему |
; пакетной команды |
mov DX, [ATABasePortAddr] |
add DX, 7 ;порт 1х7h |
mov dx, [ATABasePortAddr] |
add dx, 7 ;порт 1х7h |
;-------------------------------------- |
align 4 |
@@WaitDevice0_1: |
call change_task |
; Проверить время ожидания |
mov EAX, [timer_ticks] |
sub EAX, [TickCounter_1] |
cmp EAX, BSYWaitTime |
mov eax, [timer_ticks] |
sub eax, [TickCounter_1] |
cmp eax, BSYWaitTime |
ja @@Err1_3 ;ошибка тайм-аута |
; Проверить готовность |
in AL, DX |
test AL, 80h ;состояние сигнала BSY |
in al, dx |
test al, 0x80 ;состояние сигнала BSY |
jnz @@WaitDevice0_1 |
test AL, 1 ;состояние сигнала ERR |
test al, 1 ;состояние сигнала ERR |
jnz @@Err6_1 |
test AL, 08h ;состояние сигнала DRQ |
test al, 0x8 ;состояние сигнала 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 |
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 |
cmp [ignore_CD_eject_wait], 1 |
je @@clear_DEC |
; Ожидание подтверждения приема команды |
mov DX, [ATABasePortAddr] |
add DX, 7 ;порт 1х7h |
mov dx, [ATABasePortAddr] |
add dx, 7 ;порт 1х7h |
;-------------------------------------- |
align 4 |
@@WaitDevice1_1: |
call change_task |
; Проверить время выполнения команды |
mov EAX, [timer_ticks] |
sub EAX, [TickCounter_1] |
cmp EAX, MaxCDWaitTime |
mov eax, [timer_ticks] |
sub eax, [TickCounter_1] |
cmp eax, MaxCDWaitTime |
ja @@Err1_3 ;ошибка тайм-аута |
; Ожидать освобождения устройства |
in AL, DX |
test AL, 80h ;состояние сигнала BSY |
in al, dx |
test al, 0x80 ;состояние сигнала BSY |
jnz @@WaitDevice1_1 |
test AL, 1 ;состояние сигнала ERR |
test al, 1 ;состояние сигнала ERR |
jnz @@Err6_1 |
test AL, 40h ;состояние сигнала DRDY |
test al, 0x40 ;состояние сигнала DRDY |
jz @@WaitDevice1_1 |
;-------------------------------------- |
@@clear_DEC: |
and [DevErrorCode], 0 |
popad |
ret |
;-------------------------------------- |
; Записать код ошибки |
@@Err1_3: |
xor eax, eax |
inc eax |
jmp @@End_9 |
;-------------------------------------- |
@@Err6_1: |
mov eax, 6 |
;-------------------------------------- |
@@End_9: |
mov [DevErrorCode], eax |
popad |
ret |
;----------------------------------------------------------------------------- |
;**************************************************** |
;* ПОСЛАТЬ КОМАНДУ ЗАДАННОМУ ДИСКУ * |
;* Входные параметры передаются через глобальные * |
445,45 → 451,56 |
;* возвращен код ошибки в eax * |
;**************************************************** |
SendCommandToHDD_1: |
; pushad |
; mov [DevErrorCode],0 not need |
; Проверить значение кода режима |
cmp [ATAAddressMode], 1 |
ja @@Err2_4 |
; Проверить корректность номера канала |
mov BX, [ChannelNumber] |
cmp BX, 1 |
mov bx, [ChannelNumber] |
cmp bx, 1 |
jb @@Err3_4 |
cmp BX, 2 |
cmp bx, 2 |
ja @@Err3_4 |
; Установить базовый адрес |
dec BX |
shl BX, 1 |
dec bx |
shl ebx, 2 |
movzx ebx, bx |
mov AX, [ebx+StandardATABases] |
mov [ATABasePortAddr], AX |
mov eax, [cdpos] |
dec eax |
shr eax, 2 |
imul eax, sizeof.IDE_DATA |
add eax, IDE_controller_1 |
add eax, ebx |
mov ax, [eax+IDE_DATA.BAR0_val] |
mov [ATABasePortAddr], ax |
; Ожидание готовности HDD к приему команды |
; Выбрать нужный диск |
mov DX, [ATABasePortAddr] |
add DX, 6 ;адрес регистра головок |
mov AL, [DiskNumber] |
cmp AL, 1 ;проверить номера диска |
mov dx, [ATABasePortAddr] |
add dx, 6 ;адрес регистра головок |
mov al, [DiskNumber] |
cmp al, 1 ;проверить номера диска |
ja @@Err4_4 |
shl AL, 4 |
or AL, 10100000b |
out DX, AL |
shl al, 4 |
or al, 10100000b |
out dx, al |
; Ожидать, пока диск не будет готов |
inc DX |
inc dx |
mov eax, [timer_ticks] |
mov [TickCounter_1], eax |
mov ecx, NoTickWaitTime |
;-------------------------------------- |
align 4 |
@@WaitHDReady_2: |
cmp [timer_ticks_enable], 0 |
jne @f |
dec ecx |
; test ecx,ecx |
jz @@Err1_4 |
jmp .test |
;-------------------------------------- |
align 4 |
@@: |
call change_task |
; Проверить время ожидания |
491,81 → 508,78 |
sub eax, [TickCounter_1] |
cmp eax, BSYWaitTime;300 ;ожидать 3 сек. |
ja @@Err1_4 ;ошибка тайм-аута |
; Прочитать регистр состояния |
;-------------------------------------- |
align 4 |
.test: |
in AL, DX |
in al, dx ; Прочитать регистр состояния |
; Проверить состояние сигнала BSY |
test AL, 80h |
test al, 0x80 |
jnz @@WaitHDReady_2 |
; Проверить состояние сигнала DRQ |
test AL, 08h |
test al, 0x8 |
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;проверить номер головки |
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], 0xF ;проверить номер головки |
ja @@Err5_4 |
or AL, [ATAHead] |
or AL, 10100000b |
mov AH, [ATAAddressMode] |
shl AH, 6 |
or AL, AH |
out DX, AL |
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 |
mov al, [ATACommand] |
inc dx ;регистр команд |
out dx, al |
sti |
; Сбросить признак ошибки |
; mov [DevErrorCode],0 |
;-------------------------------------- |
@@End_10: |
xor eax, eax |
ret |
;-------------------------------------- |
; Записать код ошибки |
@@Err1_4: |
xor eax, eax |
inc eax |
; mov [DevErrorCode],1 |
ret |
;-------------------------------------- |
@@Err2_4: |
mov eax, 2 |
; mov [DevErrorCode],2 |
ret |
;-------------------------------------- |
@@Err3_4: |
mov eax, 3 |
; mov [DevErrorCode],3 |
ret |
;-------------------------------------- |
@@Err4_4: |
mov eax, 4 |
; mov [DevErrorCode],4 |
ret |
;-------------------------------------- |
@@Err5_4: |
mov eax, 5 |
; mov [DevErrorCode],5 |
; Завершение работы программы |
ret |
; sti |
; popad |
;----------------------------------------------------------------------------- |
;************************************************* |
;* ОЖИДАНИЕ ГОТОВНОСТИ УСТРОЙСТВА К РАБОТЕ * |
;* Входные параметры передаются через глобальные * |
576,25 → 590,31 |
WaitUnitReady: |
pusha |
; Запомнить время начала операции |
mov EAX, [timer_ticks] |
mov [WURStartTime], EAX |
mov eax, [timer_ticks] |
mov [WURStartTime], eax |
; Очистить буфер пакетной команды |
call clear_packet_buffer |
; Сформировать команду TEST UNIT READY |
mov [PacketCommand], word 00h |
mov [PacketCommand], word 0 |
; ЦИКЛ ОЖИДАНИЯ ГОТОВНОСТИ УСТРОЙСТВА |
mov ecx, NoTickWaitTime |
;-------------------------------------- |
align 4 |
@@SendCommand: |
; Подать команду проверки готовности |
call SendPacketNoDatCommand |
cmp [timer_ticks_enable], 0 |
jne @f |
cmp [DevErrorCode], 0 |
je @@End_11 |
dec ecx |
; cmp ecx,0 |
jz .Error |
jmp @@SendCommand |
;-------------------------------------- |
align 4 |
@@: |
call change_task |
; Проверить код ошибки |
601,17 → 621,19 |
cmp [DevErrorCode], 0 |
je @@End_11 |
; Проверить время ожидания готовности |
mov EAX, [timer_ticks] |
sub EAX, [WURStartTime] |
cmp EAX, MaxCDWaitTime |
mov eax, [timer_ticks] |
sub eax, [WURStartTime] |
cmp eax, MaxCDWaitTime |
jb @@SendCommand |
;-------------------------------------- |
.Error: |
; Ошибка тайм-аута |
mov [DevErrorCode], 1 |
;-------------------------------------- |
@@End_11: |
popa |
ret |
;----------------------------------------------------------------------------- |
;************************************************* |
;* ЗАПРЕТИТЬ СМЕНУ ДИСКА * |
;* Входные параметры передаются через глобальные * |
635,7 → 657,7 |
mov [eax], byte 1 |
popa |
ret |
;----------------------------------------------------------------------------- |
;************************************************* |
;* РАЗРЕШИТЬ СМЕНУ ДИСКА * |
;* Входные параметры передаются через глобальные * |
650,7 → 672,7 |
; Задать код команды |
mov [PacketCommand], byte 0x1E |
; Задать код запрета |
mov [PacketCommand+4], byte 00b |
mov [PacketCommand+4], byte 0 |
; Подать команду |
call SendPacketNoDatCommand |
mov eax, ATAPI_IDE0_lock |
659,7 → 681,7 |
mov [eax], byte 0 |
popa |
ret |
;----------------------------------------------------------------------------- |
;************************************************* |
;* ЗАГРУЗИТЬ НОСИТЕЛЬ В ДИСКОВОД * |
;* Входные параметры передаются через глобальные * |
673,7 → 695,7 |
call clear_packet_buffer |
; Сформировать команду START/STOP UNIT |
; Задать код команды |
mov [PacketCommand], word 1Bh |
mov [PacketCommand], word 0x1B |
; Задать операцию загрузки носителя |
mov [PacketCommand+4], word 00000011b |
; Подать команду |
680,7 → 702,7 |
call SendPacketNoDatCommand |
popa |
ret |
;----------------------------------------------------------------------------- |
;************************************************* |
;* ИЗВЛЕЧЬ НОСИТЕЛЬ ИЗ ДИСКОВОДА * |
;* Входные параметры передаются через глобальные * |
694,7 → 716,7 |
call clear_packet_buffer |
; Сформировать команду START/STOP UNIT |
; Задать код команды |
mov [PacketCommand], word 1Bh |
mov [PacketCommand], word 0x1B |
; Задать операцию извлечения носителя |
mov [PacketCommand+4], word 00000010b |
; Подать команду |
701,7 → 723,7 |
call SendPacketNoDatCommand |
popa |
ret |
;----------------------------------------------------------------------------- |
;************************************************* |
;* Проверить событие нажатия кнопки извлечения * |
;* диска * |
715,15 → 737,16 |
sub eax, [timer_ATAPI_check] |
cmp eax, 100 |
jb .no |
.yes: |
xor eax, eax |
inc eax |
ret |
;-------------------------------------- |
.no: |
xor eax, eax |
ret |
endp |
;----------------------------------------------------------------------------- |
align 4 |
check_ATAPI_device_event: |
pusha |
731,43 → 754,96 |
sub eax, [timer_ATAPI_check] |
cmp eax, 100 |
jb .end_1 |
pushfd |
mov al, [DRIVE_DATA+1] |
and al, 11b |
cmp al, 10b |
jz .ide3 |
;-------------------------------------- |
.ide2_1: |
mov al, [DRIVE_DATA+1] |
and al, 1100b |
cmp al, 1000b |
jz .ide2 |
;-------------------------------------- |
.ide1_1: |
mov al, [DRIVE_DATA+1] |
and al, 110000b |
cmp al, 100000b |
jz .ide1 |
;-------------------------------------- |
.ide0_1: |
mov al, [DRIVE_DATA+1] |
and al, 11000000b |
cmp al, 10000000b |
jz .ide0 |
;-------------------------------------- |
.ide7_1: |
mov al, [DRIVE_DATA+6] |
and al, 11b |
cmp al, 10b |
jz .ide7 |
;-------------------------------------- |
.ide6_1: |
mov al, [DRIVE_DATA+6] |
and al, 1100b |
cmp al, 1000b |
jz .ide6 |
;-------------------------------------- |
.ide5_1: |
mov al, [DRIVE_DATA+6] |
and al, 110000b |
cmp al, 100000b |
jz .ide5 |
;-------------------------------------- |
.ide4_1: |
mov al, [DRIVE_DATA+6] |
and al, 11000000b |
cmp al, 10000000b |
jz .ide4 |
;-------------------------------------- |
.ide11_1: |
mov al, [DRIVE_DATA+11] |
and al, 11b |
cmp al, 10b |
jz .ide11 |
;-------------------------------------- |
.ide10_1: |
mov al, [DRIVE_DATA+11] |
and al, 1100b |
cmp al, 1000b |
jz .ide10 |
;-------------------------------------- |
.ide9_1: |
mov al, [DRIVE_DATA+11] |
and al, 110000b |
cmp al, 100000b |
jz .ide9 |
;-------------------------------------- |
.ide8_1: |
mov al, [DRIVE_DATA+11] |
and al, 11000000b |
cmp al, 10000000b |
jz .ide8 |
;-------------------------------------- |
.end: |
sti |
popfd |
mov eax, [timer_ticks] |
mov [timer_ATAPI_check], eax |
;-------------------------------------- |
.end_1: |
popa |
ret |
;----------------------------------------------------------------------------- |
.ide3: |
cli |
cmp [ATAPI_IDE3_lock], 1 |
jne .ide2_1 |
cmp [IDE_Channel_2], 0 |
jne .ide1_1 |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_2], 1 |
mov ecx, ide_channel2_mutex |
call mutex_lock |
call reserve_ok2 |
776,23 → 852,22 |
mov [cdpos], 4 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
je .eject_ide3 |
call syscall_cdaudio.free |
jmp .ide2_1 |
.eject_ide3: |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .ide2_1 |
;----------------------------------------------------------------------------- |
.ide2: |
cli |
cmp [ATAPI_IDE2_lock], 1 |
jne .ide1_1 |
cmp [IDE_Channel_2], 0 |
jne .ide1_1 |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_2], 1 |
mov ecx, ide_channel2_mutex |
call mutex_lock |
call reserve_ok2 |
801,23 → 876,22 |
mov [cdpos], 3 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
je .eject_ide2 |
call syscall_cdaudio.free |
jmp .ide1_1 |
.eject_ide2: |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .ide1_1 |
;----------------------------------------------------------------------------- |
.ide1: |
cli |
cmp [ATAPI_IDE1_lock], 1 |
jne .ide0_1 |
cmp [IDE_Channel_1], 0 |
jne .end |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_1], 1 |
mov ecx, ide_channel1_mutex |
call mutex_lock |
call reserve_ok2 |
826,23 → 900,22 |
mov [cdpos], 2 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
je .eject_ide1 |
call syscall_cdaudio.free |
jmp .ide0_1 |
.eject_ide1: |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .ide0_1 |
;----------------------------------------------------------------------------- |
.ide0: |
cli |
cmp [ATAPI_IDE0_lock], 1 |
jne .end |
cmp [IDE_Channel_1], 0 |
jne .end |
jne .ide7_1 |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_1], 1 |
mov ecx, ide_channel1_mutex |
call mutex_lock |
call reserve_ok2 |
851,14 → 924,206 |
mov [cdpos], 1 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
je .eject_ide0 |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .end |
.eject_ide0: |
jmp .ide7_1 |
;----------------------------------------------------------------------------- |
.ide7: |
cli |
cmp [ATAPI_IDE7_lock], 1 |
jne .ide6_1 |
cmp [cd_status], 0 |
jne .end |
mov ecx, ide_channel4_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 2 |
mov [DiskNumber], 1 |
mov [cdpos], 8 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .ide6_1 |
;----------------------------------------------------------------------------- |
.ide6: |
cli |
cmp [ATAPI_IDE6_lock], 1 |
jne .ide5_1 |
cmp [cd_status], 0 |
jne .end |
mov ecx, ide_channel4_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 2 |
mov [DiskNumber], 0 |
mov [cdpos], 7 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .ide5_1 |
;----------------------------------------------------------------------------- |
.ide5: |
cli |
cmp [ATAPI_IDE5_lock], 1 |
jne .ide4_1 |
cmp [cd_status], 0 |
jne .end |
mov ecx, ide_channel3_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 1 |
mov [DiskNumber], 1 |
mov [cdpos], 6 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .ide4_1 |
;----------------------------------------------------------------------------- |
.ide4: |
cli |
cmp [ATAPI_IDE4_lock], 1 |
jne .ide11_1 |
cmp [cd_status], 0 |
jne .end |
mov ecx, ide_channel3_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 1 |
mov [DiskNumber], 0 |
mov [cdpos], 5 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .ide11_1 |
;----------------------------------------------------------------------------- |
.ide11: |
cli |
cmp [ATAPI_IDE11_lock], 1 |
jne .ide10_1 |
cmp [cd_status], 0 |
jne .end |
mov ecx, ide_channel6_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 2 |
mov [DiskNumber], 1 |
mov [cdpos], 12 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .ide10_1 |
;----------------------------------------------------------------------------- |
.ide10: |
cli |
cmp [ATAPI_IDE10_lock], 1 |
jne .ide9_1 |
cmp [cd_status], 0 |
jne .end |
mov ecx, ide_channel6_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 2 |
mov [DiskNumber], 0 |
mov [cdpos], 11 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .ide9_1 |
;----------------------------------------------------------------------------- |
.ide9: |
cli |
cmp [ATAPI_IDE9_lock], 1 |
jne .ide8_1 |
cmp [cd_status], 0 |
jne .end |
mov ecx, ide_channel5_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 1 |
mov [DiskNumber], 1 |
mov [cdpos], 10 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .ide8_1 |
;----------------------------------------------------------------------------- |
.ide8: |
cli |
cmp [ATAPI_IDE8_lock], 1 |
jne .end |
cmp [cd_status], 0 |
jne .end |
mov ecx, ide_channel5_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 1 |
mov [DiskNumber], 0 |
mov [cdpos], 9 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
jne @f |
call .eject |
;-------------------------------------- |
@@: |
call syscall_cdaudio.free |
jmp .end |
;----------------------------------------------------------------------------- |
.eject: |
call clear_CD_cache |
call allow_medium_removal |
866,6 → 1131,7 |
call EjectMedium |
mov [ignore_CD_eject_wait], 0 |
ret |
;----------------------------------------------------------------------------- |
iglobal |
timer_ATAPI_check dd 0 |
ATAPI_IDE0_lock db 0 |
872,8 → 1138,17 |
ATAPI_IDE1_lock db 0 |
ATAPI_IDE2_lock db 0 |
ATAPI_IDE3_lock db 0 |
ATAPI_IDE4_lock db 0 |
ATAPI_IDE5_lock db 0 |
ATAPI_IDE6_lock db 0 |
ATAPI_IDE7_lock db 0 |
ATAPI_IDE8_lock db 0 |
ATAPI_IDE9_lock db 0 |
ATAPI_IDE10_lock db 0 |
ATAPI_IDE11_lock db 0 |
ignore_CD_eject_wait db 0 |
endg |
;----------------------------------------------------------------------------- |
;************************************************* |
;* Получить сообщение о событии или состоянии * |
;* устройства * |
899,7 → 1174,7 |
call SendPacketDatCommand |
popa |
ret |
;----------------------------------------------------------------------------- |
;************************************************* |
; прочитать информацию из TOC |
;* Входные параметры передаются через глобальные * |
924,7 → 1199,7 |
call SendPacketDatCommand |
popa |
ret |
;----------------------------------------------------------------------------- |
;************************************************* |
;* ОПРЕДЕЛИТЬ ОБЩЕЕ КОЛИЧЕСТВО СЕКТОРОВ НА ДИСКЕ * |
;* Входные параметры передаются через глобальные * |
944,7 → 1219,7 |
; call SendPacketDatCommand |
; popa |
; ret |
;----------------------------------------------------------------------------- |
clear_packet_buffer: |
; Очистить буфер пакетной команды |
and [PacketCommand], dword 0 |
951,3 → 1226,4 |
and [PacketCommand+4], dword 0 |
and [PacketCommand+8], dword 0 |
ret |
;----------------------------------------------------------------------------- |
/kernel/branches/Kolibri-acpi/blkdev/disk.inc |
---|
1,6 → 1,6 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2011-2012. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2011-2014. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
16,6 → 16,7 |
DISK_STATUS_INVALID_CALL = 1 ; invalid input parameters |
DISK_STATUS_NO_MEDIA = 2 ; no media present |
DISK_STATUS_END_OF_MEDIA = 3 ; end of media while reading/writing data |
DISK_STATUS_NO_MEMORY = 4 ; insufficient memory for driver operation |
; Driver flags. Represent bits in DISK.DriverFlags. |
DISK_NO_INSERT_NOTIFICATION = 1 |
; Media flags. Represent bits in DISKMEDIAINFO.Flags. |
101,8 → 102,6 |
; there are two distinct caches for a disk, one for "system" data,and the other |
; for "application" data. |
struct DISKCACHE |
mutex MUTEX |
; Lock to protect the cache. |
; The following fields are inherited from data32.inc:cache_ideX. |
pointer dd ? |
data_size dd ? ; unused |
109,6 → 108,7 |
data dd ? |
sad_size dd ? |
search_start dd ? |
sector_size_log dd ? |
ends |
; This structure represents a disk device and its media for the kernel. |
169,6 → 169,8 |
; Pointer to array of .NumPartitions pointers to PARTITION structures. |
cache_size dd ? |
; inherited from cache_ideX_size |
CacheLock MUTEX |
; Lock to protect both caches. |
SysCache DISKCACHE |
AppCache DISKCACHE |
; Two caches for the disk. |
270,13 → 272,13 |
endg |
iglobal |
; The function 'disk_scan_partitions' needs three 512-byte buffers for |
; The function 'disk_scan_partitions' needs three sector-sized buffers for |
; MBR, bootsector and fs-temporary sector data. It can not use the static |
; buffers always, since it can be called for two or more disks in parallel. |
; However, this case is not typical. We reserve three static 512-byte buffers |
; and a flag that these buffers are currently used. If 'disk_scan_partitions' |
; detects that the buffers are currently used, it allocates buffers from the |
; heap. |
; heap. Also, the heap is used when sector size is other than 512. |
; The flag is implemented as a global dword variable. When the static buffers |
; are not used, the value is -1. When the static buffers are used, the value |
; is normally 0 and temporarily can become greater. The function increments |
637,21 → 639,18 |
; 1. Initialize .NumPartitions and .Partitions fields as zeros: empty list. |
and [esi+DISK.NumPartitions], 0 |
and [esi+DISK.Partitions], 0 |
; 2. Currently we can work only with 512-bytes sectors. Check this restriction. |
; The only exception is 2048-bytes CD/DVD, but they are not supported yet by |
; this code. |
cmp [esi+DISK.MediaInfo.SectorSize], 512 |
jz .doscan |
DEBUGF 1,'K : sector size is %d, only 512 is supported\n',[esi+DISK.MediaInfo.SectorSize] |
ret |
.doscan: |
; 3. Acquire the buffer for MBR and bootsector tests. See the comment before |
; 2. Acquire the buffer for MBR and bootsector tests. See the comment before |
; the 'partition_buffer_users' variable. |
mov eax, [esi+DISK.MediaInfo.SectorSize] |
cmp eax, 512 |
jnz @f |
mov ebx, mbr_buffer ; assume the global buffer is free |
lock inc [partition_buffer_users] |
jz .buffer_acquired ; yes, it is free |
lock dec [partition_buffer_users] ; no, we must allocate |
stdcall kernel_alloc, 512*3 |
@@: |
lea eax, [eax*3] |
stdcall kernel_alloc, eax |
test eax, eax |
jz .nothing |
xchg eax, ebx |
658,7 → 657,7 |
.buffer_acquired: |
; MBR/EBRs are organized in the chain. We use a loop over MBR/EBRs, but no |
; more than MAX_NUM_PARTITION times. |
; 4. Prepare things for the loop. |
; 3. Prepare things for the loop. |
; ebp will hold the sector number for current MBR/EBR. |
; [esp] will hold the sector number for current extended partition, if there |
; is one. |
667,6 → 666,10 |
push MAX_NUM_PARTITIONS ; the counter of max MBRs to process |
xor ebp, ebp ; start from sector zero |
push ebp ; no extended partition yet |
; 4. MBR is 512 bytes long. If sector size is less than 512 bytes, |
; assume no MBR, no partitions and go to 10. |
cmp [esi+DISK.MediaInfo.SectorSize], 512 |
jb .notmbr |
.new_mbr: |
; 5. Read the current sector. |
; Note that 'read' callback operates with 64-bit sector numbers, so we must |
985,7 → 988,7 |
; a three-sectors-sized buffer. This function saves ebx in the stack |
; immediately before ebp. |
mov ebx, [ebp-4] ; get buffer |
add ebx, 512 ; advance over MBR data to bootsector data |
add ebx, [esi+DISK.MediaInfo.SectorSize] ; advance over MBR data to bootsector data |
add ebp, 8 ; ebp points to part of PARTITION structure |
xor eax, eax ; first sector of the partition |
call fs_read32_sys |
996,7 → 999,7 |
; ebp -> first three fields of PARTITION structure, .start, .length, .disk; |
; [esp] = error code after bootsector read: 0 = ok, otherwise = failed, |
; ebx points to the buffer for bootsector, |
; ebx+512 points to 512-bytes buffer that can be used for anything. |
; ebx+[esi+DISK.MediaInfo.SectorSize] points to sector-sized buffer that can be used for anything. |
call fat_create_partition |
test eax, eax |
jnz .success |
/kernel/branches/Kolibri-acpi/blkdev/disk_cache.inc |
---|
1,6 → 1,6 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2011-2012. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2011-2014. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
7,6 → 7,515 |
$Revision: 3742 $ |
; Read/write functions try to do large operations, |
; it is significantly faster than several small operations. |
; This requires large buffers. |
; We can't use input/output buffers directly - they can be controlled |
; by user-mode application, so they can be modified between the operation |
; and copying to/from cache, giving invalid data in cache. |
; It is unclear how to use cache directly, currently cache items are |
; allocated/freed sector-wise, so items for sequential sectors can be |
; scattered over all the cache. |
; So read/write functions allocate a temporary buffer which is |
; 1) not greater than half of free memory and |
; 2) not greater than the following constant. |
CACHE_MAX_ALLOC_SIZE = 4 shl 20 |
; Legacy interface for filesystems fs_{read,write}32_{sys,app} |
; gives only one sector for FS. However, per-sector reading is inefficient, |
; so internally fs_read32_{sys,app} reads to the cache several sequential |
; sectors, hoping that they will be useful. |
; Total number of sectors is given by the following constant. |
CACHE_LEGACY_READ_SIZE = 16 |
; This structure describes one item in the cache. |
struct CACHE_ITEM |
SectorLo dd ? ; low 32 bits of sector |
SectorHi dd ? ; high 32 bits of sector |
Status dd ? ; one of CACHE_ITEM_* |
ends |
; Possible values for CACHE_ITEM_* |
CACHE_ITEM_EMPTY = 0 |
CACHE_ITEM_COPY = 1 |
CACHE_ITEM_MODIFIED = 2 |
; Read several sequential sectors using cache #1. |
; in: edx:eax = start sector, relative to start of partition |
; in: ecx = number of sectors to read |
; in: ebx -> buffer |
; in: ebp -> PARTITION |
; out: eax = error code, 0 = ok |
; out: ecx = number of sectors that were read |
fs_read64_sys: |
; Save ebx, set ebx to SysCache and let the common part do its work. |
push ebx ebx |
mov ebx, [ebp+PARTITION.Disk] |
add ebx, DISK.SysCache |
jmp fs_read64_common |
; Read several sequential sectors using cache #2. |
; in: edx:eax = start sector, relative to start of partition |
; in: ecx = number of sectors to read |
; in: edi -> buffer |
; in: ebp -> PARTITION |
; out: eax = error code, 0 = ok |
; out: ecx = number of sectors that were read |
fs_read64_app: |
; Save ebx, set ebx to AppCache and let the common part do its work. |
push ebx ebx |
mov ebx, [ebp+PARTITION.Disk] |
add ebx, DISK.AppCache |
; Common part of fs_read64_{app,sys}: |
; read several sequential sectors using the given cache. |
fs_read64_common: |
; 1. Setup stack frame. |
push esi edi ; save used registers to be stdcall |
push 0 ; initialize .error_code |
push ebx edx eax ecx ecx ; initialize stack variables |
virtual at esp |
.local_vars: |
.num_sectors_orig dd ? |
; Number of sectors that should be read. Used to generate output value of ecx. |
.num_sectors dd ? |
; Number of sectors that remain to be read. Decreases from .num_sectors_orig to 0. |
.sector_lo dd ? ; low 32 bits of the current sector |
.sector_hi dd ? ; high 32 bits of the current sector |
.cache dd ? ; pointer to DISKCACHE |
.error_code dd ? ; current status |
.local_vars_size = $ - .local_vars |
.saved_regs rd 2 |
.buffer dd ? ; filled by fs_read64_{sys,app} |
end virtual |
; 2. Validate parameters against partition length: |
; immediately return error if edx:eax are beyond partition end, |
; decrease .num_sectors and .num_sectors_orig, if needed, |
; so that the entire operation fits in the partition limits. |
mov eax, dword [ebp+PARTITION.Length] |
mov edx, dword [ebp+PARTITION.Length+4] |
sub eax, [.sector_lo] |
sbb edx, [.sector_hi] |
jb .end_of_media |
jnz .no_end_of_media |
cmp ecx, eax |
jbe .no_end_of_media |
; If .num_sectors got decreased, set status to DISK_STATUS_END_OF_MEDIA; |
; if all subsequent operations would be successful, this would become the final |
; status, otherwise this would be rewritten by failed operation. |
mov [.num_sectors], eax |
mov [.num_sectors_orig], eax |
mov [.error_code], DISK_STATUS_END_OF_MEDIA |
.no_end_of_media: |
; 3. If number of sectors to read is zero, either because zero-sectors operation |
; was requested or because it got decreased to zero due to partition limits, |
; just return the current status. |
cmp [.num_sectors], 0 |
jz .return |
; 4. Shift sector from partition-relative to absolute. |
mov eax, dword [ebp+PARTITION.FirstSector] |
mov edx, dword [ebp+PARTITION.FirstSector+4] |
add [.sector_lo], eax |
adc [.sector_hi], edx |
; 5. If the cache is disabled, pass the request directly to the driver. |
cmp [ebx+DISKCACHE.pointer], 0 |
jz .nocache |
; 6. Look for sectors in the cache, sequentially from the beginning. |
; Stop at the first sector that is not in the cache |
; or when all sectors were read from the cache. |
; 6a. Acquire the lock. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_lock |
.lookup_in_cache_loop: |
; 6b. For each sector, call the lookup function without adding to the cache. |
mov eax, [.sector_lo] |
mov edx, [.sector_hi] |
call cache_lookup_read |
; 6c. If it has failed, the sector is not in cache; |
; release the lock and go to 7. |
jc .not_found_in_cache |
; The sector is found in cache. |
; 6d. Copy data for the caller, advance [.buffer]. |
mov esi, edi |
mov edi, [.buffer] |
mov eax, 1 |
shl eax, cl |
mov ecx, eax |
shr ecx, 2 |
rep movsd |
mov [.buffer], edi |
; 6e. Advance the sector. |
add [.sector_lo], 1 |
adc [.sector_hi], 0 |
; 6f. Decrement number of sectors left. |
; If all sectors were read, release the lock and return. |
dec [.num_sectors] |
jnz .lookup_in_cache_loop |
; Release the lock acquired at 6a. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_unlock |
.return: |
mov eax, [.error_code] |
mov ecx, [.num_sectors_orig] |
sub ecx, [.num_sectors] |
.nothing: |
add esp, .local_vars_size |
pop edi esi ebx ebx ; restore used registers to be stdcall |
ret |
.not_found_in_cache: |
; Release the lock acquired at 6a. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_unlock |
; The current sector is not present in the cache. |
; Ask the driver to read all requested not-yet-read sectors, |
; put results in the cache. |
; Also, see the comment before the definition of CACHE_MAX_ALLOC_SIZE. |
; 7. Allocate buffer for operations. |
; Normally, create buffer that is sufficient for all remaining data. |
; However, for extra-large requests make an upper limit: |
; do not use more than half of the free memory |
; or more than CACHE_MAX_ALLOC_SIZE bytes. |
mov ecx, [ebx+DISKCACHE.sector_size_log] |
mov ebx, [pg_data.pages_free] |
shr ebx, 1 |
jz .nomemory |
cmp ebx, CACHE_MAX_ALLOC_SIZE shr 12 |
jbe @f |
mov ebx, CACHE_MAX_ALLOC_SIZE shr 12 |
@@: |
shl ebx, 12 |
shr ebx, cl |
jz .nomemory |
cmp ebx, [.num_sectors] |
jbe @f |
mov ebx, [.num_sectors] |
@@: |
mov eax, ebx |
shl eax, cl |
stdcall kernel_alloc, eax |
; If failed, return the appropriate error code. |
test eax, eax |
jz .nomemory |
mov esi, eax |
; Split the request to chunks that fit in the allocated buffer. |
.read_loop: |
; 8. Get iteration size: either size of allocated buffer in sectors |
; or number of sectors left, select what is smaller. |
cmp ebx, [.num_sectors] |
jbe @f |
mov ebx, [.num_sectors] |
@@: |
; 9. Create second portion of local variables. |
; Note that variables here and above are esp-relative; |
; it means that all addresses should be corrected when esp is changing. |
push ebx esi esi |
push ebx |
; In particular, num_sectors is now [.num_sectors+.local_vars2_size]. |
virtual at esp |
.local_vars2: |
.current_num_sectors dd ? ; number of sectors that were read |
.current_buffer dd ? |
; pointer inside .allocated_buffer that points |
; to the beginning of not-processed data |
.allocated_buffer dd ? ; saved in safe place |
.iteration_size dd ? ; saved in safe place |
.local_vars2_size = $ - .local_vars2 |
end virtual |
; 10. Call the driver, reading the next chunk. |
push esp ; numsectors |
push [.sector_hi+.local_vars2_size+4] ; startsector |
push [.sector_lo+.local_vars2_size+8] ; startsector |
push esi ; buffer |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.read |
call disk_call_driver |
; If failed, save error code. |
test eax, eax |
jz @f |
mov [.error_code+.local_vars2_size], eax |
@@: |
; 11. Copy data for the caller, advance .buffer. |
cmp [.current_num_sectors], 0 |
jz .copy_done |
mov ebx, [.cache+.local_vars2_size] |
mov eax, [.current_num_sectors] |
mov ecx, [ebx+DISKCACHE.sector_size_log] |
shl eax, cl |
mov esi, [.allocated_buffer] |
mov edi, [.buffer+.local_vars2_size] |
mov ecx, eax |
shr ecx, 2 |
rep movsd |
mov [.buffer+.local_vars2_size], edi |
; 12. Copy data to the cache. |
; 12a. Acquire the lock. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_lock |
; 12b. Prepare for the loop: create a local variable that |
; stores number of sectors to be copied. |
push [.current_num_sectors] |
.store_to_cache: |
; 12c. For each sector, call the lookup function with adding to the cache, if not yet. |
mov eax, [.sector_lo+.local_vars2_size+4] |
mov edx, [.sector_hi+.local_vars2_size+4] |
call cache_lookup_write |
test eax, eax |
jnz .cache_error |
; 12d. If the sector was already present in the cache as modified, |
; data that were read at step 10 for this sector are obsolete, |
; so rewrite data for the caller from the cache. |
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
jnz .not_modified |
mov esi, edi |
mov edi, [.buffer+.local_vars2_size+4] |
mov eax, [esp] |
shl eax, cl |
sub edi, eax |
mov eax, 1 |
shl eax, cl |
mov ecx, eax |
shr ecx, 2 |
rep movsd |
add [.current_buffer+4], eax |
jmp .sector_done |
.not_modified: |
; 12e. For each not-modified sector, |
; copy data, mark the item as not-modified copy of the disk, |
; advance .current_buffer and .sector_hi:.sector_lo to the next sector. |
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY |
mov eax, 1 |
shl eax, cl |
mov esi, [.current_buffer+4] |
mov ecx, eax |
shr ecx, 2 |
rep movsd |
mov [.current_buffer+4], esi |
.sector_done: |
add [.sector_lo+.local_vars2_size+4], 1 |
adc [.sector_hi+.local_vars2_size+4], 0 |
; 12f. Continue the loop 12c-12e until all sectors are read. |
dec dword [esp] |
jnz .store_to_cache |
.cache_error: |
; 12g. Restore after the loop: pop the local variable. |
pop ecx |
; 12h. Release the lock. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_unlock |
.copy_done: |
; 13. Remove portion of local variables created at step 9. |
pop ecx |
pop esi esi ebx |
; 14. Continue iterations while number of sectors read by the driver |
; is equal to number of sectors requested and there are additional sectors. |
cmp ecx, ebx |
jnz @f |
sub [.num_sectors], ebx |
jnz .read_loop |
@@: |
; 15. Free the buffer allocated at step 7 and return. |
stdcall kernel_free, esi |
jmp .return |
; Special branches: |
.nomemory: |
; memory allocation failed at step 7: return the corresponding error |
mov [.error_code], DISK_STATUS_NO_MEMORY |
jmp .return |
.nocache: |
; step 5, after correcting number of sectors to fit in partition limits |
; and advancing partition-relative sector to absolute, |
; sees that cache is disabled: pass corrected request to the driver |
lea eax, [.num_sectors] |
push eax ; numsectors |
push [.sector_hi+4] ; startsector |
push [.sector_lo+8] ; startsector |
push [.buffer+12] ; buffer |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.read |
call disk_call_driver |
test eax, eax |
jnz @f |
mov eax, [.error_code] |
@@: |
mov ecx, [.num_sectors] |
jmp .nothing |
.end_of_media: |
; requested sector is beyond the partition end: return the corresponding error |
mov [.error_code], DISK_STATUS_END_OF_MEDIA |
jmp .return |
; Write several sequential sectors using cache #1. |
; in: edx:eax = start sector |
; in: ecx = number of sectors to write |
; in: ebx -> buffer |
; in: ebp -> PARTITION |
; out: eax = error code, 0 = ok |
; out: ecx = number of sectors that were written |
fs_write64_sys: |
; Save ebx, set ebx to SysCache and let the common part do its work. |
push ebx |
mov ebx, [ebp+PARTITION.Disk] |
add ebx, DISK.SysCache |
jmp fs_write64_common |
; Write several sequential sectors using cache #2. |
; in: edx:eax = start sector |
; in: ecx = number of sectors to write |
; in: ebx -> buffer |
; in: ebp -> PARTITION |
; out: eax = error code, 0 = ok |
; out: ecx = number of sectors that were written |
fs_write64_app: |
; Save ebx, set ebx to AppCache and let the common part do its work. |
push ebx |
mov ebx, [ebp+PARTITION.Disk] |
add ebx, DISK.AppCache |
; Common part of fs_write64_{app,sys}: |
; write several sequential sectors using the given cache. |
fs_write64_common: |
; 1. Setup stack frame. |
push esi edi ; save used registers to be stdcall |
push 0 ; initialize .error_code |
push edx eax ecx ecx ; initialize stack variables |
push [.buffer-4] ; copy [.buffer] to [.cur_buffer] |
; -4 is due to esp-relative addressing |
virtual at esp |
.local_vars: |
.cur_buffer dd ? ; pointer to data that are currently copying |
.num_sectors_orig dd ? |
; Number of sectors that should be written. Used to generate output value of ecx. |
.num_sectors dd ? |
; Number of sectors that remain to be written. |
.sector_lo dd ? ; low 32 bits of the current sector |
.sector_hi dd ? ; high 32 bits of the current sector |
.error_code dd ? ; current status |
.local_vars_size = $ - .local_vars |
.saved_regs rd 2 |
.buffer dd ? ; filled by fs_write64_{sys,app} |
end virtual |
; 2. Validate parameters against partition length: |
; immediately return error if edx:eax are beyond partition end, |
; decrease .num_sectors and .num_sectors_orig, if needed, |
; so that the entire operation fits in the partition limits. |
mov eax, dword [ebp+PARTITION.Length] |
mov edx, dword [ebp+PARTITION.Length+4] |
sub eax, [.sector_lo] |
sbb edx, [.sector_hi] |
jb .end_of_media |
jnz .no_end_of_media |
cmp ecx, eax |
jbe .no_end_of_media |
; If .num_sectors got decreased, set status to DISK_STATUS_END_OF_MEDIA; |
; if all subsequent operations would be successful, this would become the final |
; status, otherwise this would be rewritten by failed operation. |
mov [.num_sectors], eax |
mov [.num_sectors_orig], eax |
mov [.error_code], DISK_STATUS_END_OF_MEDIA |
.no_end_of_media: |
; 3. If number of sectors to write is zero, either because zero-sectors operation |
; was requested or because it got decreased to zero due to partition limits, |
; just return the current status. |
cmp [.num_sectors], 0 |
jz .return |
; 4. Shift sector from partition-relative to absolute. |
mov eax, dword [ebp+PARTITION.FirstSector] |
mov edx, dword [ebp+PARTITION.FirstSector+4] |
add [.sector_lo], eax |
adc [.sector_hi], edx |
; 5. If the cache is disabled, pass the request directly to the driver. |
cmp [ebx+DISKCACHE.pointer], 0 |
jz .nocache |
; 6. Store sectors in the cache, sequentially from the beginning. |
; 6a. Acquire the lock. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_lock |
.lookup_in_cache_loop: |
; 6b. For each sector, call the lookup function with adding to the cache, if not yet. |
mov eax, [.sector_lo] |
mov edx, [.sector_hi] |
call cache_lookup_write |
test eax, eax |
jnz .cache_error |
; 6c. For each sector, copy data, mark the item as modified and not saved, |
; advance .current_buffer to the next sector. |
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
mov eax, 1 |
shl eax, cl |
mov esi, [.cur_buffer] |
mov ecx, eax |
shr ecx, 2 |
rep movsd |
mov [.cur_buffer], esi |
; 6d. Remove the sector from the other cache. |
; Normally it should not be there, but prefetching could put to the app cache |
; data that normally should belong to the sys cache and vice versa. |
; Note: this requires that both caches must be protected by the same lock. |
mov eax, [.sector_lo] |
mov edx, [.sector_hi] |
push ebx |
sub ebx, [ebp+PARTITION.Disk] |
xor ebx, DISK.SysCache xor DISK.AppCache |
add ebx, [ebp+PARTITION.Disk] |
call cache_lookup_read |
jc @f |
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_EMPTY |
@@: |
pop ebx |
; 6e. Advance .sector_hi:.sector_lo to the next sector. |
add [.sector_lo], 1 |
adc [.sector_hi], 0 |
; 6f. Continue the loop at 6b-6e until all sectors are processed. |
dec [.num_sectors] |
jnz .lookup_in_cache_loop |
.unlock_return: |
; 6g. Release the lock and return. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_unlock |
.return: |
mov eax, [.error_code] |
mov ecx, [.num_sectors_orig] |
sub ecx, [.num_sectors] |
.nothing: |
add esp, .local_vars_size |
pop edi esi ebx |
ret |
; Special branches: |
.cache_error: |
; error at flushing the cache while adding sector to the cache: |
; return the error from the lookup function |
mov [.error_code], eax |
jmp .unlock_return |
.end_of_media: |
; requested sector is beyond the partition end: return the corresponding error |
mov eax, DISK_STATUS_END_OF_MEDIA |
xor ecx, ecx |
jmp .nothing |
.nocache: |
; step 5, after correcting number of sectors to fit in partition limits |
; and advancing partition-relative sector to absolute, |
; sees that cache is disabled: pass corrected request to the driver |
lea eax, [.num_sectors] |
push eax ; numsectors |
push [.sector_hi+4] ; startsector |
push [.sector_lo+8] ; startsector |
push [.buffer+12] ; buffer |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.write |
call disk_call_driver |
mov ecx, [.num_sectors] |
jmp .nothing |
; Legacy. Use fs_read64_sys instead. |
; This function is intended to replace the old 'hd_read' function when |
; [hdd_appl_data] = 0, so its input/output parameters are the same, except |
; that it can't use the global variables 'hd_error' and 'hdd_appl_data'. |
14,12 → 523,13 |
; eax is relative to partition start |
; out: eax = error code; 0 = ok |
fs_read32_sys: |
; Save ecx, set ecx to SysCache and let the common part do its work. |
push ecx |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.SysCache |
; Save ebx, set ebx to SysCache and let the common part do its work. |
push ebx |
mov ebx, [ebp+PARTITION.Disk] |
add ebx, DISK.SysCache |
jmp fs_read32_common |
; Legacy. Use fs_read64_app instead. |
; This function is intended to replace the old 'hd_read' function when |
; [hdd_appl_data] = 1, so its input/output parameters are the same, except |
; that it can't use the global variables 'hd_error' and 'hdd_appl_data'. |
27,10 → 537,10 |
; eax is relative to partition start |
; out: eax = error code; 0 = ok |
fs_read32_app: |
; Save ecx, set ecx to AppCache and let the common part do its work. |
push ecx |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.AppCache |
; Save ebx, set ebx to AppCache and let the common part do its work. |
push ebx |
mov ebx, [ebp+PARTITION.Disk] |
add ebx, DISK.AppCache |
; This label is the common part of fs_read32_sys and fs_read32_app. |
fs_read32_common: |
41,119 → 551,224 |
cmp dword [ebp+PARTITION.Length], eax |
ja @f |
mov eax, DISK_STATUS_END_OF_MEDIA |
pop ecx |
pop ebx |
ret |
@@: |
; 2. Get the absolute sector on the disk. |
push edx esi |
push ecx edx esi edi |
xor edx, edx |
add eax, dword [ebp+PARTITION.FirstSector] |
adc edx, dword [ebp+PARTITION.FirstSector+4] |
; 3. If there is no cache for this disk, just pass the request to the driver. |
cmp [ecx+DISKCACHE.pointer], 0 |
cmp [ebx+DISKCACHE.pointer], 0 |
jnz .scancache |
push 1 |
push esp ; numsectors |
push edx ; startsector |
push eax ; startsector |
push ebx ; buffer |
pushd [esp+32]; buffer |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.read |
call disk_call_driver |
pop ecx |
pop esi edx |
pop ecx |
pop edi esi edx ecx |
pop ebx |
ret |
.scancache: |
; 4. Scan the cache. |
push edi ecx ; scan cache |
push edx eax |
push ebx edx eax |
virtual at esp |
.local_vars: |
.sector_lo dd ? |
.sector_hi dd ? |
.cache dd ? |
.local_vars_size = $ - .local_vars |
.saved_regs rd 4 |
.buffer dd ? |
end virtual |
; The following code is inherited from hd_read. The differences are: |
; all code is protected by the cache lock; instead of static calls |
; to hd_read_dma/hd_read_pio/bd_read the dynamic call to DISKFUNC.read is used; |
; sector is 64-bit, not 32-bit. |
; 4. Scan for the requested sector in the cache. |
; If found, copy the data and return. |
; 4a. Acquire the lock. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_lock |
; 4b. Call the lookup function without adding to the cache. |
mov eax, [.sector_lo] |
mov edx, [.sector_hi] |
mov esi, [ecx+DISKCACHE.pointer] |
mov ecx, [ecx+DISKCACHE.sad_size] |
add esi, 12 |
mov edi, 1 |
.hdreadcache: |
cmp dword [esi+8], 0 ; empty |
je .nohdcache |
cmp [esi], eax ; correct sector |
jne .nohdcache |
cmp [esi+4], edx ; correct sector |
je .yeshdcache |
.nohdcache: |
add esi, 12 |
inc edi |
dec ecx |
jnz .hdreadcache |
mov esi, [.cache] |
call find_empty_slot64 ; ret in edi |
call cache_lookup_read |
; If not found, go to 5. |
jc .not_found_in_cache |
.found_in_cache: |
; 4c. Copy the data. |
mov esi, edi |
mov edi, [.buffer] |
mov eax, 1 |
shl eax, cl |
mov ecx, eax |
shr ecx, 2 |
rep movsd |
; 4d. Release the lock and return success. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_unlock |
.return: |
xor eax, eax |
.return_eax: |
add esp, .local_vars_size |
pop edi esi edx ecx |
pop ebx |
ret |
.not_found_in_cache: |
; 5. Decide whether we need to prefetch further sectors. |
; If so, advance to 6. If not, go to 13. |
; Assume that devices < 3MB are floppies which are slow |
; (ramdisk does not have a cache, so we don't even get here for ramdisk). |
; This is a dirty hack, but the entire function is somewhat hacky. Use fs_read64*. |
mov ecx, [ebp+PARTITION.Disk] |
cmp dword [ecx+DISK.MediaInfo.Capacity+4], 0 |
jnz @f |
cmp dword [ecx+DISK.MediaInfo.Capacity], 3 shl (20-9) |
jb .floppy |
@@: |
; We want to prefetch CACHE_LEGACY_READ_SIZE sectors. |
; 6. Release the lock acquired at step 4a. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_unlock |
; 7. Allocate buffer for CACHE_LEGACY_READ_SIZE sectors. |
mov eax, CACHE_LEGACY_READ_SIZE |
mov ecx, [ebx+DISKCACHE.sector_size_log] |
shl eax, cl |
stdcall kernel_alloc, eax |
; If failed, return the corresponding error code. |
test eax, eax |
jnz .read_done |
jz .nomemory |
; 8. Create second portion of local variables. |
push eax eax |
push CACHE_LEGACY_READ_SIZE |
virtual at esp |
.local_vars2: |
.num_sectors dd ? ; number of sectors left |
.current_buffer dd ? ; pointer to data that are currently copying |
.allocated_buffer dd ? ; saved at safe place |
.local_vars2_size = $ - .local_vars2 |
end virtual |
; 9. Call the driver to read CACHE_LEGACY_READ_SIZE sectors. |
push esp ; numsectors |
push [.sector_hi+.local_vars2_size+4] ; startsector |
push [.sector_lo+.local_vars2_size+8] ; startsector |
push eax ; buffer |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.read |
call disk_call_driver |
; Note: we're ok if at least one sector is read, |
; read error somewhere after that just limits data to be put in cache. |
cmp [.num_sectors], 0 |
jz .read_error |
; 10. Copy data for the caller. |
mov esi, [.allocated_buffer] |
mov edi, [.buffer+.local_vars2_size] |
mov ecx, [ebx+DISKCACHE.sector_size_log] |
mov eax, 1 |
shl eax, cl |
mov ecx, eax |
shr ecx, 2 |
rep movsd |
; 11. Store all sectors that were successfully read to the cache. |
; 11a. Acquire the lock. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_lock |
.store_to_cache: |
; 11b. For each sector, call the lookup function with adding to the cache, if not yet. |
mov eax, [.sector_lo+.local_vars2_size] |
mov edx, [.sector_hi+.local_vars2_size] |
call cache_lookup_write |
test eax, eax |
jnz .cache_error |
; 11c. Ignore sectors marked as modified: for them the cache is more recent that disk data. |
mov eax, 1 |
shl eax, cl |
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
jnz .not_modified |
add [.current_buffer], eax |
jmp .sector_done |
.not_modified: |
; 11d. For each sector, copy data, mark the item as not-modified copy of the disk, |
; advance .current_buffer and .sector_hi:.sector_lo to the next sector. |
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY |
mov esi, [.current_buffer] |
mov ecx, eax |
shr ecx, 2 |
rep movsd |
mov [.current_buffer], esi |
.sector_done: |
add [.sector_lo+.local_vars2_size], 1 |
adc [.sector_hi+.local_vars2_size], 0 |
; 11e. Continue the loop at 11b-11d until all sectors are processed. |
dec [.num_sectors] |
jnz .store_to_cache |
.cache_error: |
; 11f. Release the lock. |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
call mutex_unlock |
.copy_done: |
; 12. Remove portion of local variables created at step 8, |
; free the buffer allocated at step 7 and return. |
pop ecx ecx |
stdcall kernel_free |
jmp .return |
.read_error: |
; If no sectors were read, free the buffer allocated at step 7 |
; and pass the error to the caller. |
push eax |
stdcall kernel_free, [.allocated_buffer+4] |
pop eax |
add esp, .local_vars2_size |
jmp .return_eax |
.nomemory: |
mov eax, DISK_STATUS_NO_MEMORY |
jmp .return_eax |
.floppy: |
; We don't want to prefetch anything, just read one sector. |
; We are still holding the lock acquired at step 4a. |
; 13. Call the lookup function adding sector to the cache. |
call cache_lookup_write |
test eax, eax |
jnz .floppy_cache_error |
push esi |
; 14. Call the driver to read one sector. |
push 1 |
push esp |
push edx |
push [.sector_lo+12] |
mov ecx, [.cache+16] |
mov eax, edi |
shl eax, 9 |
add eax, [ecx+DISKCACHE.data] |
push eax |
push [.sector_lo+16] |
push edi |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.read |
call disk_call_driver |
pop ecx |
dec ecx |
jnz .read_done |
jnz .floppy_read_error |
; 15. Get the slot and pointer to the cache item, |
; change the status to not-modified copy of the disk |
; and go to 4c. |
pop esi |
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY |
mov ecx, [ebx+DISKCACHE.sector_size_log] |
jmp .found_in_cache |
mov ecx, [.cache] |
lea eax, [edi*3] |
mov esi, [ecx+DISKCACHE.pointer] |
lea esi, [eax*4+esi] |
mov eax, [.sector_lo] |
mov edx, [.sector_hi] |
mov [esi], eax ; sector number |
mov [esi+4], edx ; sector number |
mov dword [esi+8], 1; hd read - mark as same as in hd |
.yeshdcache: |
mov esi, edi |
mov ecx, [.cache] |
shl esi, 9 |
add esi, [ecx+DISKCACHE.data] |
mov edi, ebx |
mov ecx, 512/4 |
rep movsd ; move data |
xor eax, eax ; successful read |
.read_done: |
mov ecx, [.cache] |
; On error at steps 13-14, release the lock |
; and pass the error to the caller. |
.floppy_read_error: |
pop ecx |
.floppy_cache_error: |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.CacheLock |
push eax |
call mutex_unlock |
pop eax |
add esp, 12 |
pop edi esi edx ecx |
ret |
jmp .return_eax |
; This function is intended to replace the old 'hd_write' function when |
; [hdd_appl_data] = 0, so its input/output parameters are the same, except |
162,11 → 777,13 |
; eax is relative to partition start |
; out: eax = error code; 0 = ok |
fs_write32_sys: |
; Save ecx, set ecx to SysCache and let the common part do its work. |
push ecx |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.SysCache |
jmp fs_write32_common |
; Just call the advanced function. |
push ecx edx |
xor edx, edx |
mov ecx, 1 |
call fs_write64_sys |
pop edx ecx |
ret |
; This function is intended to replace the old 'hd_write' function when |
; [hdd_appl_data] = 1, so its input/output parameters are the same, except |
175,144 → 792,93 |
; eax is relative to partition start |
; out: eax = error code; 0 = ok |
fs_write32_app: |
; Save ecx, set ecx to AppCache and let the common part do its work. |
push ecx |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.AppCache |
; This label is the common part of fs_read32_sys and fs_read32_app. |
fs_write32_common: |
; 1. Check that the required sector is inside the partition. If no, return |
; DISK_STATUS_END_OF_MEDIA. |
cmp dword [ebp+PARTITION.Length+4], 0 |
jnz @f |
cmp dword [ebp+PARTITION.Length], eax |
ja @f |
mov eax, DISK_STATUS_END_OF_MEDIA |
pop ecx |
ret |
@@: |
push edx esi |
; 2. Get the absolute sector on the disk. |
; Just call the advanced function. |
push ecx edx |
xor edx, edx |
add eax, dword [ebp+PARTITION.FirstSector] |
adc edx, dword [ebp+PARTITION.FirstSector+4] |
; 3. If there is no cache for this disk, just pass request to the driver. |
cmp [ecx+DISKCACHE.pointer], 0 |
jnz .scancache |
push 1 |
push esp ; numsectors |
push edx ; startsector |
push eax ; startsector |
push ebx ; buffer |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.write |
call disk_call_driver |
pop ecx |
pop esi edx |
pop ecx |
mov ecx, 1 |
call fs_write64_app |
pop edx ecx |
ret |
.scancache: |
; 4. Scan the cache. |
push edi ecx ; scan cache |
push edx eax |
virtual at esp |
.sector_lo dd ? |
.sector_hi dd ? |
.cache dd ? |
end virtual |
; The following code is inherited from hd_write. The differences are: |
; all code is protected by the cache lock; |
; sector is 64-bit, not 32-bit. |
call mutex_lock |
; check if the cache already has the sector and overwrite it |
mov eax, [.sector_lo] |
mov edx, [.sector_hi] |
mov esi, [ecx+DISKCACHE.pointer] |
mov ecx, [ecx+DISKCACHE.sad_size] |
add esi, 12 |
; Lookup for the given sector in the given cache. |
; If the sector is not present, return error. |
; The caller must acquire the cache lock. |
; in: edx:eax = sector |
; in: ebx -> DISKCACHE structure |
; out: CF set if sector is not in cache |
; out: ecx = sector_size_log |
; out: esi -> sector:status |
; out: edi -> sector data |
proc cache_lookup_read |
mov esi, [ebx+DISKCACHE.pointer] |
add esi, sizeof.CACHE_ITEM |
mov edi, 1 |
.hdwritecache: |
cmp dword [esi+8], 0 ; if cache slot is empty |
je .not_in_cache_write |
.hdreadcache: |
cmp [esi], eax ; if the slot has the sector |
jne .not_in_cache_write |
cmp [esi+4], edx ; if the slot has the sector |
je .yes_in_cache_write |
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_EMPTY |
je .nohdcache |
.not_in_cache_write: |
cmp [esi+CACHE_ITEM.SectorLo], eax |
jne .nohdcache |
cmp [esi+CACHE_ITEM.SectorHi], edx |
jne .nohdcache |
mov ecx, [ebx+DISKCACHE.sector_size_log] |
shl edi, cl |
add edi, [ebx+DISKCACHE.data] |
clc |
ret |
add esi, 12 |
.nohdcache: |
add esi, sizeof.CACHE_ITEM |
inc edi |
dec ecx |
jnz .hdwritecache |
; sector not found in cache |
; write the block to a new location |
mov esi, [.cache] |
call find_empty_slot64 ; ret in edi |
test eax, eax |
jne .hd_write_access_denied |
mov ecx, [.cache] |
lea eax, [edi*3] |
mov esi, [ecx+DISKCACHE.pointer] |
lea esi, [eax*4+esi] |
mov eax, [.sector_lo] |
mov edx, [.sector_hi] |
mov [esi], eax ; sector number |
mov [esi+4], edx ; sector number |
.yes_in_cache_write: |
mov dword [esi+8], 2 ; write - differs from hd |
shl edi, 9 |
mov ecx, [.cache] |
add edi, [ecx+DISKCACHE.data] |
mov esi, ebx |
mov ecx, 512/4 |
rep movsd ; move data |
xor eax, eax ; success |
.hd_write_access_denied: |
mov ecx, [.cache] |
push eax |
call mutex_unlock |
pop eax |
add esp, 12 |
pop edi esi edx ecx |
cmp edi, [ebx+DISKCACHE.sad_size] |
jbe .hdreadcache |
stc |
ret |
endp |
; This internal function is called from fs_read32_* and fs_write32_*. It is the |
; analogue of find_empty_slot for 64-bit sectors. |
find_empty_slot64: |
; Lookup for the given sector in the given cache. |
; If the sector is not present, allocate space for it, |
; possibly flushing data. |
; in: edx:eax = sector |
; in: ebx -> DISKCACHE structure |
; in: ebp -> PARTITION structure |
; out: eax = error code |
; out: esi -> sector:status |
; out: edi -> sector data |
proc cache_lookup_write |
call cache_lookup_read |
jnc .return0 |
push edx eax |
;----------------------------------------------------------- |
; find empty or read slot, flush cache if next 12.5% is used by write |
; output : edi = cache slot |
; output : ecx = cache slot |
;----------------------------------------------------------- |
; Note: the code is essentially inherited, so probably |
; no analysis of efficiency were done. |
; However, it works. |
.search_again: |
mov ecx, [esi+DISKCACHE.sad_size] |
mov edi, [esi+DISKCACHE.search_start] |
shr ecx, 3 |
mov eax, [ebx+DISKCACHE.sad_size] |
mov ecx, [ebx+DISKCACHE.search_start] |
shr eax, 3 |
lea esi, [ecx*sizeof.CACHE_ITEM/4] |
shl esi, 2 |
add esi, [ebx+DISKCACHE.pointer] |
.search_for_empty: |
inc edi |
cmp edi, [esi+DISKCACHE.sad_size] |
inc ecx |
add esi, sizeof.CACHE_ITEM |
cmp ecx, [ebx+DISKCACHE.sad_size] |
jbe .inside_cache |
mov edi, 1 |
mov ecx, 1 |
mov esi, [ebx+DISKCACHE.pointer] |
add esi, sizeof.CACHE_ITEM |
.inside_cache: |
lea eax, [edi*3] |
shl eax, 2 |
add eax, [esi+DISKCACHE.pointer] |
cmp dword [eax+8], 2 |
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
jb .found_slot ; it's empty or read |
dec ecx |
dec eax |
jnz .search_for_empty |
stdcall write_cache64, [ebp+PARTITION.Disk] ; no empty slots found, write all |
test eax, eax |
319,125 → 885,338 |
jne .found_slot_access_denied |
jmp .search_again ; and start again |
.found_slot: |
mov [esi+DISKCACHE.search_start], edi |
mov [ebx+DISKCACHE.search_start], ecx |
popd [esi+CACHE_ITEM.SectorLo] |
popd [esi+CACHE_ITEM.SectorHi] |
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_EMPTY |
mov edi, ecx |
mov ecx, [ebx+DISKCACHE.sector_size_log] |
shl edi, cl |
add edi, [ebx+DISKCACHE.data] |
.return0: |
xor eax, eax ; success |
ret |
.found_slot_access_denied: |
add esp, 8 |
ret |
endp |
; This function is intended to replace the old 'write_cache' function. |
proc write_cache64 uses ecx edx esi edi, disk:dword |
locals |
cache_chain_started dd 0 |
cache_chain_size dd ? |
cache_chain_pos dd ? |
cache_chain_ptr dd ? |
endl |
saved_esi_pos = 16+12 ; size of local variables + size of registers before esi |
; If there is no cache for this disk, nothing to do. |
cmp [esi+DISKCACHE.pointer], 0 |
jz .flush |
;----------------------------------------------------------- |
; write all changed sectors to disk |
;----------------------------------------------------------- |
; write difference ( 2 ) from cache to DISK |
mov ecx, [esi+DISKCACHE.sad_size] |
mov esi, [esi+DISKCACHE.pointer] |
add esi, 12 |
; Flush the given cache. |
; The caller must acquire the cache lock. |
; in: ebx -> DISKCACHE |
; in: first argument in stdcall convention -> PARTITION |
proc write_cache64 |
; 1. Setup stack frame. |
push esi edi ; save used registers to be stdcall |
sub esp, .local_vars_size ; reserve space for local vars |
virtual at esp |
.local_vars: |
.cache_end dd ? ; item past the end of the cache |
.size_left dd ? ; items left to scan |
.current_ptr dd ? ; pointer to the current item |
; |
; Write operations are coalesced in chains, |
; one chain describes a sequential interval of sectors, |
; they can be sequential or scattered in the cache. |
.sequential dd ? |
; boolean variable, 1 if the current chain is sequential in the cache, |
; 0 if additional buffer is needed to perform the operation |
.chain_start_pos dd ? ; data of chain start item |
.chain_start_ptr dd ? ; pointer to chain start item |
.chain_size dd ? ; chain size (thanks, C.O.) |
.iteration_size dd ? |
; If the chain size is too large, split the operation to several iterations. |
; This is size in sectors for one iterations. |
.iteration_buffer dd ? ; temporary buffer for non-sequential chains |
.local_vars_size = $ - .local_vars |
rd 2 ; saved registers |
dd ? ; return address |
.disk dd ? ; first argument |
end virtual |
; 1. If there is no cache for this disk, nothing to do, just return zero. |
cmp [ebx+DISKCACHE.pointer], 0 |
jz .return0 |
; 2. Prepare for the loop: initialize current pointer and .size_left, |
; calculate .cache_end. |
mov ecx, [ebx+DISKCACHE.sad_size] |
mov [.size_left], ecx |
lea ecx, [ecx*sizeof.CACHE_ITEM/4] |
shl ecx, 2 |
mov esi, [ebx+DISKCACHE.pointer] |
add esi, sizeof.CACHE_ITEM |
add ecx, esi |
mov [.cache_end], ecx |
; 3. Main loop: go over all items, go to 5 for every modified item. |
.look: |
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
jz .begin_write |
.look_next: |
add esi, sizeof.CACHE_ITEM |
dec [.size_left] |
jnz .look |
; 4. Return success. |
.return0: |
xor eax, eax |
.return: |
add esp, .local_vars_size |
pop edi esi ; restore used registers to be stdcall |
ret 4 ; return popping one argument |
.begin_write: |
; We have found a modified item. |
; 5. Prepare for chain finding: save the current item, initialize chain variables. |
mov [.current_ptr], esi |
; Initialize chain as sequential zero-length starting at the current item. |
mov [.chain_start_ptr], esi |
mov eax, [ebx+DISKCACHE.sad_size] |
sub eax, [.size_left] |
inc eax |
mov ecx, [ebx+DISKCACHE.sector_size_log] |
shl eax, cl |
add eax, [ebx+DISKCACHE.data] |
mov [.chain_start_pos], eax |
mov [.chain_size], 0 |
mov [.sequential], 1 |
; 6. Expand the chain backward. |
; Note: the main loop in step 2 looks for items sequentially, |
; so the previous item is not modified. If the previous sector |
; is present in the cache, it automatically makes the chain scattered. |
; 6a. Calculate sector number: one before the sector for the current item. |
mov eax, [esi+CACHE_ITEM.SectorLo] |
mov edx, [esi+CACHE_ITEM.SectorHi] |
sub eax, 1 |
sbb edx, 0 |
.find_chain_start: |
; 6b. For each sector where the previous item does not expand the chain, |
; call the lookup function without adding to the cache. |
call cache_lookup_read |
; 6c. If the sector is not found in cache or is not modified, stop expanding |
; and advance to step 7. |
jc .found_chain_start |
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
jnz .found_chain_start |
; 6d. We have found a new block that expands the chain backwards. |
; It makes the chain non-sequential. |
; Normally, sectors come in sequential blocks, so try to look at previous items |
; before returning to 6b; if there is a sequential block indeed, this saves some |
; time instead of many full-fledged lookups. |
mov [.sequential], 0 |
mov [.chain_start_pos], edi |
.look_backward: |
; 6e. For each sector, update chain start pos/ptr, decrement sector number, |
; look at the previous item. |
mov [.chain_start_ptr], esi |
inc [.chain_size] |
sub eax, 1 |
sbb edx, 0 |
sub esi, sizeof.CACHE_ITEM |
; If the previous item exists... |
cmp esi, [ebx+DISKCACHE.pointer] |
jbe .find_chain_start |
; ...describes the correct sector... |
cmp [esi+CACHE_ITEM.SectorLo], eax |
jnz .find_chain_start |
cmp [esi+CACHE_ITEM.SectorHi], edx |
jnz .find_chain_start |
; ...and is modified... |
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
jnz .found_chain_start |
; ...expand the chain one sector backwards and continue the loop at 6e. |
; Otherwise, advance to step 7 if the previous item describes the correct sector |
; but is not modified, and return to step 6b otherwise. |
mov edi, 1 |
.write_cache_more: |
cmp dword [esi+8], 2 ; if cache slot is not different |
jne .write_chain |
mov dword [esi+8], 1 ; same as in hd |
mov eax, [esi] |
mov edx, [esi+4] ; edx:eax = sector to write |
; Объединяем запись цепочки последовательных секторов в одно обращение к диску |
cmp ecx, 1 |
jz .nonext |
cmp dword [esi+12+8], 2 |
jnz .nonext |
push eax edx |
shl edi, cl |
sub [.chain_start_pos], edi |
jmp .look_backward |
.found_chain_start: |
; 7. Expand the chain forward. |
; 7a. Prepare for the loop at 7b: |
; set esi = pointer to current item, edx:eax = current sector. |
mov esi, [.current_ptr] |
mov eax, [esi+CACHE_ITEM.SectorLo] |
mov edx, [esi+CACHE_ITEM.SectorHi] |
.look_forward: |
; 7b. First, look at the next item. If it describes the next sector: |
; if it is modified, expand the chain with that sector and continue this step, |
; if it is not modified, the chain is completed, so advance to step 8. |
inc [.chain_size] |
add eax, 1 |
adc edx, 0 |
cmp eax, [esi+12] |
jnz @f |
cmp edx, [esi+12+4] |
add esi, sizeof.CACHE_ITEM |
cmp esi, [.cache_end] |
jae .find_chain_end |
cmp [esi+CACHE_ITEM.SectorLo], eax |
jnz .find_chain_end |
cmp [esi+CACHE_ITEM.SectorHi], edx |
jnz .find_chain_end |
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
jnz .found_chain_end |
jmp .look_forward |
.find_chain_end: |
; 7c. Otherwise, call the lookup function. |
call cache_lookup_read |
; 7d. If the next sector is present in the cache and is modified, |
; mark the chain as non-sequential and continue to step 7b. |
jc .found_chain_end |
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
jnz .found_chain_end |
mov [.sequential], 0 |
jmp .look_forward |
.found_chain_end: |
; 8. Decide whether the chain is sequential or scattered. |
; Advance to step 9 for sequential chains, go to step 10 for scattered chains. |
cmp [.sequential], 0 |
jz .write_non_sequential |
.write_sequential: |
; 9. Write a sequential chain to disk. |
; 9a. Pass the entire chain to the driver. |
mov eax, [.chain_start_ptr] |
lea ecx, [.chain_size] |
push ecx ; numsectors |
pushd [eax+CACHE_ITEM.SectorHi] ; startsector |
pushd [eax+CACHE_ITEM.SectorLo] ; startsector |
push [.chain_start_pos+12] ; buffer |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.write |
call disk_call_driver |
; 9b. If failed, pass the error code to the driver. |
test eax, eax |
jnz .return |
; 9c. If succeeded, mark all sectors in the chain as not-modified, |
; advance current item and number of items left to skip the chain. |
mov esi, [.current_ptr] |
mov eax, [.chain_size] |
sub [.size_left], eax |
@@: |
pop edx eax |
jnz .nonext |
cmp [cache_chain_started], 1 |
jz @f |
mov [cache_chain_started], 1 |
mov [cache_chain_size], 0 |
mov [cache_chain_pos], edi |
mov [cache_chain_ptr], esi |
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY |
add esi, sizeof.CACHE_ITEM |
dec eax |
jnz @b |
; 9d. Continue the main loop at step 2 if there are more sectors. |
; Return success otherwise. |
cmp [.size_left], 0 |
jnz .look |
jmp .return0 |
.write_non_sequential: |
; Write a non-sequential chain to the disk. |
; 10. Allocate a temporary buffer. |
; Use [.chain_size] sectors, but |
; not greater than CACHE_MAX_ALLOC_SIZE bytes |
; and not greater than half of free memory. |
mov eax, [pg_data.pages_free] |
shr eax, 1 |
jz .nomemory |
cmp eax, CACHE_MAX_ALLOC_SIZE shr 12 |
jbe @f |
mov eax, CACHE_MAX_ALLOC_SIZE shr 12 |
@@: |
inc [cache_chain_size] |
cmp [cache_chain_size], 16 |
jnz .continue |
jmp .write_chain |
.nonext: |
call .flush_cache_chain |
shl eax, 12 |
shr eax, cl |
jz .nomemory |
cmp eax, [.chain_size] |
jbe @f |
mov eax, [.chain_size] |
@@: |
mov [.iteration_size], eax |
shl eax, cl |
stdcall kernel_alloc, eax |
test eax, eax |
jnz .nothing |
mov [cache_chain_size], 1 |
mov [cache_chain_ptr], esi |
call .write_cache_sector |
test eax, eax |
jnz .nothing |
jmp .continue |
.write_chain: |
call .flush_cache_chain |
test eax, eax |
jnz .nothing |
.continue: |
add esi, 12 |
inc edi |
dec ecx |
jnz .write_cache_more |
call .flush_cache_chain |
test eax, eax |
jnz .nothing |
.flush: |
mov esi, [disk] |
mov al, DISKFUNC.flush |
call disk_call_driver |
.nothing: |
ret |
.flush_cache_chain: |
xor eax, eax |
cmp [cache_chain_started], eax |
jz @f |
call .write_cache_chain |
mov [cache_chain_started], 0 |
jz .nomemory |
mov [.iteration_buffer], eax |
.write_non_sequential_iteration: |
; 11. Split the chain so that each iteration fits in the allocated buffer. |
; Iteration size is the minimum of chain size and allocated size. |
mov eax, [.chain_size] |
cmp eax, [.iteration_size] |
jae @f |
mov [.iteration_size], eax |
@@: |
retn |
.write_cache_sector: |
mov [cache_chain_size], 1 |
mov [cache_chain_pos], edi |
.write_cache_chain: |
pusha |
mov edi, [cache_chain_pos] |
mov ecx, [ebp-saved_esi_pos] |
shl edi, 9 |
add edi, [ecx+DISKCACHE.data] |
mov ecx, [cache_chain_size] |
push ecx |
; 12. Prepare arguments for the driver. |
mov esi, [.chain_start_ptr] |
mov edi, [.iteration_buffer] |
push [.iteration_size] |
push esp ; numsectors |
mov eax, [cache_chain_ptr] |
pushd [eax+4] |
pushd [eax] ; startsector |
push [esi+CACHE_ITEM.SectorHi] ; startsector |
push [esi+CACHE_ITEM.SectorLo] ; startsector |
push edi ; buffer |
mov esi, [ebp] |
mov esi, [esi+PARTITION.Disk] |
; 13. Copy data from the cache to the temporary buffer, |
; advancing chain_start pos/ptr and marking sectors as not-modified. |
; 13a. Prepare for the loop: push number of sectors to process. |
push [.iteration_size+20] ; temporary variable |
.copy_loop: |
; 13b. For each sector, copy the data. |
; Note that edi is advanced automatically. |
mov esi, [.chain_start_pos+24] |
mov ecx, [ebx+DISKCACHE.sector_size_log] |
mov eax, 1 |
shl eax, cl |
mov ecx, eax |
shr ecx, 2 |
rep movsd |
mov ecx, eax ; keep for 13e |
; 13c. Mark the item as not-modified. |
mov esi, [.chain_start_ptr+24] |
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY |
; 13d. Check whether the next sector continues the chain. |
; If so, advance to 13e. Otherwise, go to 13f. |
mov eax, [esi+CACHE_ITEM.SectorLo] |
mov edx, [esi+CACHE_ITEM.SectorHi] |
add esi, sizeof.CACHE_ITEM |
add eax, 1 |
adc edx, 0 |
cmp esi, [.cache_end+24] |
jae .no_forward |
cmp [esi+CACHE_ITEM.SectorLo], eax |
jnz .no_forward |
cmp [esi+CACHE_ITEM.SectorHi], edx |
jnz .no_forward |
; 13e. Increment position/pointer to the chain and |
; continue the loop. |
add [.chain_start_pos+24], ecx |
mov [.chain_start_ptr+24], esi |
dec dword [esp] |
jnz .copy_loop |
jmp .copy_done |
.no_forward: |
; 13f. Call the lookup function without adding to the cache. |
; Update position/pointer with returned value. |
; Note: for the last sector in the chain, edi/esi may contain |
; garbage; we are not going to use them in this case. |
push edi |
call cache_lookup_read |
mov [.chain_start_pos+28], edi |
mov [.chain_start_ptr+28], esi |
pop edi |
dec dword [esp] |
jnz .copy_loop |
.copy_done: |
; 13g. Restore the stack after 13a. |
pop ecx |
; 14. Call the driver. |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.write |
call disk_call_driver |
pop ecx |
mov [esp+28], eax |
popa |
retn |
pop ecx ; numsectors |
; 15. If the driver has returned an error, free the buffer allocated at step 10 |
; and pass the error to the caller. |
; Otherwise, remove the processed part from the chain and continue iterations |
; starting in step 11 if there are more data to process. |
test eax, eax |
jnz .nonsequential_error |
sub [.chain_size], ecx |
jnz .write_non_sequential_iteration |
; 16. The chain is written. Free the temporary buffer |
; and continue the loop at step 2. |
stdcall kernel_free, [.iteration_buffer] |
mov esi, [.current_ptr] |
jmp .look_next |
.nonsequential_error: |
push eax |
stdcall kernel_free, [.iteration_buffer+4] |
pop eax |
jmp .return |
.nomemory: |
mov eax, DISK_STATUS_NO_MEMORY |
jmp .return |
endp |
; This internal function is called from disk_add to initialize the caching for |
452,13 → 1231,32 |
; is most useful example of a non-trivial adjustment. |
; esi = pointer to DISK structure |
disk_init_cache: |
; 1. Calculate the suggested cache size. |
; 1a. Get the size of free physical memory in pages. |
; 1. Verify sector size. The code requires it to be a power of 2 not less than 4. |
; In the name of sanity check that sector size is not too small or too large. |
bsf ecx, [esi+DISK.MediaInfo.SectorSize] |
jz .invalid_sector_size |
mov eax, 1 |
shl eax, cl |
cmp eax, [esi+DISK.MediaInfo.SectorSize] |
jnz .invalid_sector_size |
cmp ecx, 6 |
jb .invalid_sector_size |
cmp ecx, 14 |
jbe .normal_sector_size |
.invalid_sector_size: |
DEBUGF 1,'K : sector size %x is invalid\n',[esi+DISK.MediaInfo.SectorSize] |
xor eax, eax |
ret |
.normal_sector_size: |
mov [esi+DISK.SysCache.sector_size_log], ecx |
mov [esi+DISK.AppCache.sector_size_log], ecx |
; 2. Calculate the suggested cache size. |
; 2a. Get the size of free physical memory in pages. |
mov eax, [pg_data.pages_free] |
; 1b. Use the value to calculate the size. |
; 2b. Use the value to calculate the size. |
shl eax, 12 - 5 ; 1/32 of it in bytes |
and eax, -8*4096 ; round down to the multiple of 8 pages |
; 1c. Force lower and upper limits. |
; 2c. Force lower and upper limits. |
cmp eax, 1024*1024 |
jb @f |
mov eax, 1024*1024 |
467,7 → 1265,7 |
ja @f |
mov eax, 128*1024 |
@@: |
; 1d. Give a chance to the driver to adjust the size. |
; 2d. Give a chance to the driver to adjust the size. |
push eax |
mov al, DISKFUNC.adjust_cache_size |
call disk_call_driver |
475,21 → 1273,19 |
mov [esi+DISK.cache_size], eax |
test eax, eax |
jz .nocache |
; 2. Allocate memory for the cache. |
; 2a. Call the allocator. |
; 3. Allocate memory for the cache. |
; 3a. Call the allocator. |
stdcall kernel_alloc, eax |
test eax, eax |
jnz @f |
; 2b. If it failed, say a message and return with eax = 0. |
; 3b. If it failed, say a message and return with eax = 0. |
dbgstr 'no memory for disk cache' |
jmp .nothing |
@@: |
; 3. Fill two DISKCACHE structures. |
; 4. Fill two DISKCACHE structures. |
mov [esi+DISK.SysCache.pointer], eax |
lea ecx, [esi+DISK.SysCache.mutex] |
lea ecx, [esi+DISK.CacheLock] |
call mutex_init |
lea ecx, [esi+DISK.AppCache.mutex] |
call mutex_init |
; The following code is inherited from getcache.inc. |
mov edx, [esi+DISK.SysCache.pointer] |
and [esi+DISK.SysCache.search_start], 0 |
503,9 → 1299,7 |
mov [esi+DISK.AppCache.pointer], edx |
mov eax, [esi+DISK.SysCache.data_size] |
push ebx |
call calculate_for_hd64 |
pop ebx |
call calculate_cache_slots |
add eax, [esi+DISK.SysCache.pointer] |
mov [esi+DISK.SysCache.data], eax |
mov [esi+DISK.SysCache.sad_size], ecx |
518,9 → 1312,7 |
pop edi |
mov eax, [esi+DISK.AppCache.data_size] |
push ebx |
call calculate_for_hd64 |
pop ebx |
call calculate_cache_slots |
add eax, [esi+DISK.AppCache.pointer] |
mov [esi+DISK.AppCache.data], eax |
mov [esi+DISK.AppCache.sad_size], ecx |
532,9 → 1324,9 |
rep stosd |
pop edi |
; 4. Return with nonzero al. |
; 5. Return with nonzero al. |
mov al, 1 |
; 5. Return. |
; 6. Return. |
.nothing: |
ret |
; No caching is required for this driver. Zero cache pointers and return with |
545,18 → 1337,16 |
mov al, 1 |
ret |
calculate_for_hd64: |
calculate_cache_slots: |
push eax |
mov ebx, eax |
shr eax, 9 |
lea eax, [eax*3] |
shl eax, 2 |
sub ebx, eax |
shr ebx, 9 |
mov ecx, ebx |
shl ebx, 9 |
mov ecx, [esi+DISK.MediaInfo.SectorSize] |
add ecx, sizeof.CACHE_ITEM |
xor edx, edx |
div ecx |
mov ecx, eax |
imul eax, [esi+DISK.MediaInfo.SectorSize] |
sub [esp], eax |
pop eax |
sub eax, ebx |
dec ecx |
ret |
577,12 → 1367,21 |
; esi = pointer to DISK |
disk_sync: |
; The algorithm is straightforward. |
push esi |
cmp [esi+DISK.SysCache.pointer], 0 |
jz .nothing |
lea ecx, [esi+DISK.CacheLock] |
call mutex_lock |
push ebx |
push esi ; for second write_cache64 |
push esi ; for first write_cache64 |
add esi, DISK.SysCache |
lea ebx, [esi+DISK.SysCache] |
call write_cache64 |
add esi, DISK.AppCache - DISK.SysCache |
add ebx, DISK.AppCache - DISK.SysCache |
call write_cache64 |
pop esi |
pop ebx |
lea ecx, [esi+DISK.CacheLock] |
call mutex_unlock |
.nothing: |
mov al, DISKFUNC.flush |
call disk_call_driver |
ret |
/kernel/branches/Kolibri-acpi/blkdev/flp_drv.inc |
---|
379,10 → 379,16 |
mov al, 8 |
call FDCDataOutput |
call FDCDataInput |
push eax |
; DEBUGF 1,' %x',al |
call FDCDataInput |
; DEBUGF 1,' %x',al |
; DEBUGF 1,'\n' |
pop eax |
test al, 0xC0 |
jz @f |
mov [FDC_Status], FDC_DiskNotFound |
@@: |
.fail: |
call save_timer_fdd_motor |
popa |
/kernel/branches/Kolibri-acpi/blkdev/hd_drv.inc |
---|
17,7 → 17,7 |
hdid dd ? |
hdpos dd ? |
ends |
;----------------------------------------------------------------------------- |
iglobal |
align 4 |
ide_callbacks: |
35,18 → 35,34 |
hd1_data HD_DATA ?, 0x10, 2 |
hd2_data HD_DATA ?, 0, 3 |
hd3_data HD_DATA ?, 0x10, 4 |
hd4_data HD_DATA ?, 0, 5 |
hd5_data HD_DATA ?, 0x10, 6 |
hd6_data HD_DATA ?, 0, 7 |
hd7_data HD_DATA ?, 0x10, 8 |
hd8_data HD_DATA ?, 0, 9 |
hd9_data HD_DATA ?, 0x10, 10 |
hd10_data HD_DATA ?, 0, 11 |
hd11_data HD_DATA ?, 0x10, 12 |
hd_address_table: |
dd 0x1f0, 0x00, 0x1f0, 0x10 |
dd 0x170, 0x00, 0x170, 0x10 |
ide_mutex_table: |
dd ide_channel1_mutex |
dd ide_channel2_mutex |
dd ide_channel3_mutex |
dd ide_channel4_mutex |
dd ide_channel5_mutex |
dd ide_channel6_mutex |
endg |
;----------------------------------------------------------------------------- |
uglobal |
ide_mutex MUTEX |
ide_channel1_mutex MUTEX |
ide_channel2_mutex MUTEX |
ide_channel3_mutex MUTEX |
ide_channel4_mutex MUTEX |
ide_channel5_mutex MUTEX |
ide_channel6_mutex MUTEX |
endg |
;----------------------------------------------------------------------------- |
proc ide_read stdcall uses edi, \ |
hd_data, buffer, startsector:qword, numsectors |
; hd_data = pointer to hd*_data |
67,15 → 83,13 |
; 2. Acquire the global lock. |
mov ecx, ide_mutex |
call mutex_lock |
mov ecx, ide_channel2_mutex |
mov eax, [hd_data] |
push ecx |
mov ecx, [hd_address_table] |
cmp [eax+HD_DATA.hdbase], ecx ; 0x1F0 |
pop ecx |
jne .IDE_Channel_2 |
mov ecx, ide_channel1_mutex |
.IDE_Channel_2: |
mov ecx, [hd_data] |
mov ecx, [ecx+HD_DATA.hdpos] |
dec ecx |
shr ecx, 1 |
shl ecx, 2 |
mov ecx, [ecx + ide_mutex_table] |
mov [channel_lock], ecx |
call mutex_lock |
; 3. Convert parameters to the form suitable for worker procedures. |
83,6 → 97,7 |
; Worker procedures use global variables and edi for [buffer]. |
cmp dword [startsector+4], 0 |
jnz .fail |
and [hd_error], 0 |
mov ecx, [hd_data] |
mov eax, [ecx+HD_DATA.hdbase] |
98,55 → 113,65 |
; DMA read is permitted if [allow_dma_access]=1 or 2 |
cmp [allow_dma_access], 2 |
ja .nodma |
cmp [dma_hdd], 1 |
jnz .nodma |
;-------------------------------------- |
push eax |
mov eax, [hd_address_table] |
cmp [hdbase], eax ; 0x1F0 |
pop eax |
jnz @f |
test [DRIVE_DATA+1], byte 10100000b |
push eax ecx |
mov ecx, [hdpos] |
dec ecx |
shr ecx, 2 |
imul ecx, sizeof.IDE_DATA |
add ecx, IDE_controller_1 |
mov [IDE_controller_pointer], ecx |
mov eax, [hdpos] |
dec eax |
and eax, 11b |
shr eax, 1 |
add eax, ecx |
cmp [eax+IDE_DATA.dma_hdd_channel_1], 1 |
pop ecx eax |
jnz .nodma |
jmp .dma |
@@: |
test [DRIVE_DATA+1], byte 1010b |
jnz .nodma |
.dma: |
;-------------------------------------- |
call hd_read_dma |
jmp @f |
;-------------------------------------- |
.nodma: |
call hd_read_pio |
;-------------------------------------- |
@@: |
cmp [hd_error], 0 |
jnz .fail |
mov ecx, [numsectors] |
inc dword [ecx] ; one more sector is read |
dec [sectors_todo] |
jz .done |
inc eax |
jnz .sectors_loop |
;-------------------------------------- |
; 5. Loop is done, either due to error or because everything is done. |
; Release the global lock and return the corresponding status. |
.fail: |
mov ecx, [channel_lock] |
call mutex_unlock |
mov ecx, ide_mutex |
call mutex_unlock |
or eax, -1 |
ret |
;-------------------------------------- |
.done: |
mov ecx, [channel_lock] |
call mutex_unlock |
mov ecx, ide_mutex |
call mutex_unlock |
xor eax, eax |
ret |
endp |
;----------------------------------------------------------------------------- |
proc ide_write stdcall uses esi edi, \ |
hd_data, buffer, startsector:qword, numsectors |
; hd_data = pointer to hd*_data |
167,15 → 192,13 |
; 2. Acquire the global lock. |
mov ecx, ide_mutex |
call mutex_lock |
mov ecx, ide_channel2_mutex |
mov eax, [hd_data] |
push ecx |
mov ecx, [hd_address_table] |
cmp [eax+HD_DATA.hdbase], ecx ; 0x1F0 |
pop ecx |
jne .IDE_Channel_2 |
mov ecx, ide_channel1_mutex |
.IDE_Channel_2: |
mov ecx, [hd_data] |
mov ecx, [ecx+HD_DATA.hdpos] |
dec ecx |
shr ecx, 1 |
shl ecx, 2 |
mov ecx, [ecx + ide_mutex_table] |
mov [channel_lock], ecx |
call mutex_lock |
; 3. Convert parameters to the form suitable for worker procedures. |
183,6 → 206,7 |
; Worker procedures use global variables and esi for [buffer]. |
cmp dword [startsector+4], 0 |
jnz .fail |
and [hd_error], 0 |
mov ecx, [hd_data] |
mov eax, [ecx+HD_DATA.hdbase] |
200,66 → 224,79 |
mov ecx, 16 |
cmp ecx, [sectors_todo] |
jbe @f |
mov ecx, [sectors_todo] |
;-------------------------------------- |
@@: |
mov [cache_chain_size], cl |
; DMA write is permitted only if [allow_dma_access]=1 |
cmp [allow_dma_access], 2 |
jae .nodma |
cmp [dma_hdd], 1 |
jnz .nodma |
;-------------------------------------- |
push eax |
mov eax, [hd_address_table] |
cmp [hdbase], eax ; 0x1F0 |
pop eax |
jnz @f |
test [DRIVE_DATA+1], byte 10100000b |
push eax ecx |
mov ecx, [hdpos] |
dec ecx |
shr ecx, 2 |
imul ecx, sizeof.IDE_DATA |
add ecx, IDE_controller_1 |
mov [IDE_controller_pointer], ecx |
mov eax, [hdpos] |
dec eax |
and eax, 11b |
shr eax, 1 |
add eax, ecx |
cmp [eax+IDE_DATA.dma_hdd_channel_1], 1 |
pop ecx eax |
jnz .nodma |
jmp .dma |
@@: |
test [DRIVE_DATA+1], byte 1010b |
jnz .nodma |
.dma: |
;-------------------------------------- |
call cache_write_dma |
jmp .common |
;-------------------------------------- |
.nodma: |
mov [cache_chain_size], 1 |
call cache_write_pio |
;-------------------------------------- |
.common: |
cmp [hd_error], 0 |
jnz .fail |
movzx ecx, [cache_chain_size] |
mov eax, [numsectors] |
add [eax], ecx |
sub [sectors_todo], ecx |
jz .done |
add [edi], ecx |
jc .fail |
shl ecx, 9 |
add esi, ecx |
jmp .sectors_loop |
;-------------------------------------- |
; 5. Loop is done, either due to error or because everything is done. |
; Release the global lock and return the corresponding status. |
.fail: |
mov ecx, [channel_lock] |
call mutex_unlock |
mov ecx, ide_mutex |
call mutex_unlock |
or eax, -1 |
ret |
;-------------------------------------- |
.done: |
mov ecx, [channel_lock] |
call mutex_unlock |
mov ecx, ide_mutex |
call mutex_unlock |
xor eax, eax |
ret |
endp |
;----------------------------------------------------------------------------- |
; This is a stub. |
proc ide_querymedia stdcall, hd_data, mediainfo |
mov eax, [mediainfo] |
270,7 → 307,6 |
xor eax, eax |
ret |
endp |
;----------------------------------------------------------------------------- |
align 4 |
; input: eax = sector, edi -> buffer |
277,7 → 313,6 |
; output: edi = edi + 512 |
hd_read_pio: |
push eax edx |
; Select the desired drive |
mov edx, [hdbase] |
add edx, 6 ;адрес регистра головок |
286,9 → 321,9 |
out dx, al; номер головки/номер диска |
call wait_for_hd_idle |
cmp [hd_error], 0 |
jne hd_read_error |
; ATA with 28 or 48 bit for sector number? |
mov eax, [esp+4] |
cmp eax, 0x10000000 |
372,7 → 407,6 |
pushfd |
cli |
mov ecx, 256 |
mov edx, [hdbase] |
cld |
393,6 → 427,7 |
out dx, al ; номер головки/номер диска |
call wait_for_hd_idle |
cmp [hd_error], 0 |
jne hd_write_error |
550,6 → 585,7 |
align 4 |
wfhil1: |
call check_hd_wait_timeout |
cmp [hd_error], 0 |
jne @f |
556,7 → 592,7 |
in al, dx |
test al, 128 |
jnz wfhil1 |
;-------------------------------------- |
@@: |
pop edx eax |
ret |
573,6 → 609,7 |
align 4 |
hdwait_sbuf: ; wait for sector buffer to be ready |
call check_hd_wait_timeout |
cmp [hd_error], 0 |
jne @f |
587,9 → 624,10 |
test al, 1 ; previous command ended up with an error |
jz buf_wait_ok |
;-------------------------------------- |
@@: |
mov [hd_error], 1 |
;-------------------------------------- |
buf_wait_ok: |
pop edx eax |
ret |
606,22 → 644,17 |
align 4 |
.wait: |
call change_task |
cmp [IDE_common_irq_param], 0 |
jz .done |
call check_hd_wait_timeout |
cmp [hd_error], 0 |
jz .wait |
; clear Bus Master IDE Command register |
pushfd |
cli |
mov [IDE_common_irq_param], 0 |
mov dx, [IDEContrRegsBaseAddr] |
mov al, 0 |
out dx, al |
popfd |
;-------------------------------------- |
align 4 |
.done: |
pop edx |
pop eax |
636,23 → 669,17 |
align 4 |
.wait: |
call change_task |
cmp [IDE_common_irq_param], 0 |
jz .done |
call check_hd_wait_timeout |
cmp [hd_error], 0 |
jz .wait |
; clear Bus Master IDE Command register |
pushfd |
cli |
mov [IDE_common_irq_param], 0 |
mov dx, [IDEContrRegsBaseAddr] |
add dx, 8 |
mov al, 0 |
out dx, al |
popfd |
;-------------------------------------- |
align 4 |
.done: |
pop edx |
pop eax |
660,7 → 687,8 |
;----------------------------------------------------------------------------- |
iglobal |
align 4 |
; note that IDE descriptor table must be 4-byte aligned and do not cross 4K boundary |
; note that IDE descriptor table must be 4-byte aligned |
; and do not cross 4K boundary |
IDE_descriptor_table: |
dd IDE_DMA |
dw 0x2000 |
673,19 → 701,14 |
;----------------------------------------------------------------------------- |
uglobal |
; all uglobals are zeroed at boot |
dma_process dd 0 |
dma_slot_ptr dd 0 |
cache_chain_pos dd 0 |
cache_chain_ptr dd 0 |
cache_chain_size db 0 |
cache_chain_started db 0 |
dma_task_switched db 0 |
dma_hdd db 0 |
allow_dma_access db 0 |
endg |
;----------------------------------------------------------------------------- |
align 4 |
IDE_irq_14_handler: |
; DEBUGF 1, 'K : IDE_irq_14_handler %x\n', [IDE_common_irq_param]:2 |
cmp [IDE_common_irq_param], irq14_num |
jne .exit |
693,7 → 716,8 |
cli |
pushad |
mov [IDE_common_irq_param], 0 |
mov dx, [IDEContrRegsBaseAddr] |
mov ecx, [IDE_controller_pointer] |
mov dx, [ecx+IDE_DATA.RegsBaseAddres] |
; test whether it is our interrupt? |
add edx, 2 |
in al, dx |
715,12 → 739,10 |
mov al, 1 |
ret |
;-------------------------------------- |
align 4 |
@@: |
popad |
popfd |
;-------------------------------------- |
align 4 |
.exit: |
mov al, 0 |
ret |
727,6 → 749,7 |
;----------------------------------------------------------------------------- |
align 4 |
IDE_irq_15_handler: |
; DEBUGF 1, 'K : IDE_irq_15_handler %x\n', [IDE_common_irq_param]:2 |
cmp [IDE_common_irq_param], irq15_num |
jne .exit |
734,7 → 757,8 |
cli |
pushad |
mov [IDE_common_irq_param], 0 |
mov dx, [IDEContrRegsBaseAddr] |
mov ecx, [IDE_controller_pointer] |
mov dx, [ecx+IDE_DATA.RegsBaseAddres] |
add dx, 8 |
; test whether it is our interrupt? |
add edx, 2 |
757,12 → 781,10 |
mov al, 1 |
ret |
;-------------------------------------- |
align 4 |
@@: |
popad |
popfd |
;-------------------------------------- |
align 4 |
.exit: |
mov al, 0 |
ret |
769,14 → 791,16 |
;----------------------------------------------------------------------------- |
align 4 |
IDE_common_irq_handler: |
; DEBUGF 1, 'K : IDE_common_irq_handler %x\n', [IDE_common_irq_param]:2 |
pushfd |
cli |
cmp [IDE_common_irq_param], 0 |
je .exit |
pushfd |
cli |
pushad |
xor ebx, ebx |
mov dx, [IDEContrRegsBaseAddr] |
mov ecx, [IDE_controller_pointer] |
mov dx, [ecx+IDE_DATA.RegsBaseAddres] |
mov eax, IDE_common_irq_param |
cmp [eax], irq14_num |
mov [eax], bl |
784,7 → 808,6 |
add dx, 8 |
;-------------------------------------- |
align 4 |
@@: |
; test whether it is our interrupt? |
add edx, 2 |
807,13 → 830,11 |
mov al, 1 |
ret |
;-------------------------------------- |
align 4 |
@@: |
popad |
popfd |
;-------------------------------------- |
align 4 |
.exit: |
popfd |
mov al, 0 |
ret |
;----------------------------------------------------------------------------- |
824,26 → 845,31 |
mov edx, [dma_hdpos] |
cmp edx, [hdpos] |
jne .notread |
mov edx, [dma_cur_sector] |
cmp eax, edx |
jb .notread |
add edx, 15 |
cmp [esp+4], edx |
ja .notread |
mov eax, [esp+4] |
sub eax, [dma_cur_sector] |
shl eax, 9 |
add eax, (OS_BASE+IDE_DMA) |
push ecx esi |
mov esi, eax |
mov ecx, 512/4 |
cld |
rep movsd |
pop esi ecx |
pop edx |
pop eax |
ret |
;-------------------------------------- |
.notread: |
; set data for PRD Table |
mov eax, IDE_descriptor_table |
851,13 → 877,18 |
mov word [eax+4], 0x2000 |
sub eax, OS_BASE |
; select controller Primary or Secondary |
mov dx, [IDEContrRegsBaseAddr] |
mov ecx, [IDE_controller_pointer] |
mov dx, [ecx+IDE_DATA.RegsBaseAddres] |
push eax |
mov eax, [hd_address_table] |
cmp [hdbase], eax ; 0x1F0 |
mov eax, [hdpos] |
dec eax |
test eax, 10b |
pop eax |
jz @f |
add edx, 8 |
;-------------------------------------- |
@@: |
push edx |
; Bus Master IDE PRD Table Address |
881,9 → 912,9 |
out dx, al ; номер головки/номер диска |
call wait_for_hd_idle |
cmp [hd_error], 0 |
jnz hd_read_error |
; ATA with 28 or 48 bit for sector number? |
mov eax, [esp+4] |
; -10h because the PreCache hits the boundary between lba28 and lba48 |
961,47 → 992,55 |
;-------------------------------------- |
.continue: |
; select controller Primary or Secondary |
mov dx, [IDEContrRegsBaseAddr] |
mov eax, [hd_address_table] |
cmp [hdbase], eax ; 0x1F0 |
mov ecx, [IDE_controller_pointer] |
mov dx, [ecx+IDE_DATA.RegsBaseAddres] |
mov eax, [hdpos] |
dec eax |
test eax, 10b |
jz @f |
add dx, 8 |
;-------------------------------------- |
@@: |
; set write to memory and Start Bus Master |
mov al, 9 |
out dx, al |
mov eax, [CURRENT_TASK] |
mov [dma_process], eax |
mov eax, [TASK_BASE] |
mov [dma_slot_ptr], eax |
mov eax, [hd_address_table] |
cmp [hdbase], eax ; 0x1F0 |
mov eax, [hdpos] |
dec eax |
test eax, 10b |
jnz .ide1 |
mov [IDE_common_irq_param], irq14_num |
jmp @f |
;-------------------------------------- |
.ide1: |
mov [IDE_common_irq_param], irq15_num |
;-------------------------------------- |
@@: |
popfd |
; wait for interrupt |
mov eax, [hd_address_table] |
cmp [hdbase], eax ; 0x1F0 |
mov eax, [hdpos] |
dec eax |
test eax, 10b |
jnz .wait_ide1 |
call wait_for_sector_dma_ide0 |
jmp @f |
;-------------------------------------- |
.wait_ide1: |
call wait_for_sector_dma_ide1 |
;-------------------------------------- |
@@: |
cmp [hd_error], 0 |
jnz hd_read_error |
mov eax, [hdpos] |
mov [dma_hdpos], eax |
pop edx |
pop eax |
mov [dma_cur_sector], eax |
jmp hd_read_dma |
;----------------------------------------------------------------------------- |
1011,6 → 1050,7 |
; set data for PRD Table |
mov eax, IDE_descriptor_table |
mov edx, eax |
pusha |
mov edi, (OS_BASE+IDE_DMA) |
mov dword [edx], IDE_DMA |
1021,15 → 1061,21 |
cld |
rep movsd |
popa |
sub eax, OS_BASE |
; select controller Primary or Secondary |
mov dx, [IDEContrRegsBaseAddr] |
mov ecx, [IDE_controller_pointer] |
mov dx, [ecx+IDE_DATA.RegsBaseAddres] |
push eax |
mov eax, [hd_address_table] |
cmp [hdbase], eax ; 0x1F0 |
mov eax, [hdpos] |
dec eax |
test eax, 10b |
pop eax |
jz @f |
add edx, 8 |
;-------------------------------------- |
@@: |
push edx |
; Bus Master IDE PRD Table Address |
1053,9 → 1099,9 |
out dx, al ; номер головки/номер диска |
call wait_for_hd_idle |
cmp [hd_error], 0 |
jnz hd_write_error_dma |
; ATA with 28 or 48 bit for sector number? |
mov esi, [cache_chain_ptr] |
mov eax, [esi] |
1134,38 → 1180,49 |
;-------------------------------------- |
.continue: |
; select controller Primary or Secondary |
mov dx, [IDEContrRegsBaseAddr] |
mov eax, [hd_address_table] |
cmp [hdbase], eax ; 0x1F0 |
mov ecx, [IDE_controller_pointer] |
mov dx, [ecx+IDE_DATA.RegsBaseAddres] |
mov eax, [hdpos] |
dec eax |
test eax, 10b |
jz @f |
add dx, 8 |
;-------------------------------------- |
@@: |
; set write to device and Start Bus Master |
mov al, 1 |
out dx, al |
mov eax, [CURRENT_TASK] |
mov [dma_process], eax |
mov eax, [TASK_BASE] |
mov [dma_slot_ptr], eax |
mov eax, [hd_address_table] |
cmp [hdbase], eax ; 0x1F0 |
mov eax, [hdpos] |
dec eax |
test eax, 10b |
jnz .ide1 |
mov [IDE_common_irq_param], irq14_num |
jmp @f |
;-------------------------------------- |
.ide1: |
mov [IDE_common_irq_param], irq15_num |
;-------------------------------------- |
@@: |
popfd |
; wait for interrupt |
mov [dma_cur_sector], not 0x40 |
mov eax, [hd_address_table] |
cmp [hdbase], eax ; 0x1F0 |
mov eax, [hdpos] |
dec eax |
test eax, 10b |
jnz .wait_ide1 |
call wait_for_sector_dma_ide0 |
jmp @f |
;-------------------------------------- |
.wait_ide1: |
call wait_for_sector_dma_ide1 |
;-------------------------------------- |
@@: |
cmp [hd_error], 0 |
jnz hd_write_error_dma |
1172,14 → 1229,44 |
pop esi |
ret |
;----------------------------------------------------------------------------- |
uglobal |
proc clear_pci_ide_interrupts |
mov esi, pcidev_list |
;-------------------------------------- |
align 4 |
IDE_Interrupt dw ? |
IDEContrRegsBaseAddr dw ? |
IDEContrProgrammingInterface dw ? |
IDE_BAR0_val dw ? |
IDE_BAR1_val dw ? |
IDE_BAR2_val dw ? |
IDE_BAR3_val dw ? |
endg |
.loop: |
mov esi, [esi+PCIDEV.fd] |
cmp esi, pcidev_list |
jz .done |
; cmp [esi+PCIDEV.class], 0x01018F |
mov eax, [esi+PCIDEV.class] |
shr eax, 4 |
cmp eax, 0x01018 |
jnz .loop |
mov ah, [esi+PCIDEV.bus] |
mov al, 2 |
mov bh, [esi+PCIDEV.devfn] |
mov bl, 0x20 |
call pci_read_reg |
and eax, 0FFFCh |
mov edx, eax |
add edx, 2 |
in al, dx |
DEBUGF 1,'K : clear_pci_ide_interrupts: port[%x] = %x ',dx,al |
out dx, al |
in al, dx |
DEBUGF 1,'-> %x; ',al |
add edx, 8 |
in al, dx |
DEBUGF 1,'port[%x] = %x ',dx,al |
out dx, al |
in al, dx |
DEBUGF 1,'-> %x\n',al |
jmp .loop |
;-------------------------------------- |
.done: |
ret |
endp |
;----------------------------------------------------------------------------- |
/kernel/branches/Kolibri-acpi/blkdev/ide_cache.inc |
---|
41,53 → 41,29 |
ret |
;-------------------------------------------------------------------- |
clear_CD_cache: |
DEBUGF 1, 'K : clear_CD_cache\n' |
pusha |
.ide0: |
mov esi, [cdpos] |
dec esi |
imul esi, sizeof.IDE_CACHE |
add esi, cache_ide0 |
xor eax, eax |
cmp [cdpos], 1 |
jne .ide1 |
mov [cache_ide0_search_start], eax |
mov ecx, [cache_ide0_system_sad_size] |
mov edi, [cache_ide0_pointer] |
mov [esi+IDE_CACHE.search_start], eax |
mov ecx, [esi+IDE_CACHE.system_sad_size] |
mov edi, [esi+IDE_CACHE.pointer] |
call .clear |
mov [cache_ide0_appl_search_start], eax |
mov ecx, [cache_ide0_appl_sad_size] |
mov edi, [cache_ide0_data_pointer] |
jmp .continue |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
mov [cache_ide1_search_start], eax |
mov ecx, [cache_ide1_system_sad_size] |
mov edi, [cache_ide1_pointer] |
mov [esi+IDE_CACHE.appl_search_start], eax |
mov ecx, [esi+IDE_CACHE.appl_sad_size] |
mov edi, [esi+IDE_CACHE.data_pointer] |
call .clear |
mov [cache_ide1_appl_search_start], eax |
mov ecx, [cache_ide1_appl_sad_size] |
mov edi, [cache_ide1_data_pointer] |
jmp .continue |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
mov [cache_ide2_search_start], eax |
mov ecx, [cache_ide2_system_sad_size] |
mov edi, [cache_ide2_pointer] |
call .clear |
mov [cache_ide2_appl_search_start], eax |
mov ecx, [cache_ide2_appl_sad_size] |
mov edi, [cache_ide2_data_pointer] |
jmp .continue |
.ide3: |
mov [cache_ide3_search_start], eax |
mov ecx, [cache_ide3_system_sad_size] |
mov edi, [cache_ide3_pointer] |
call .clear |
mov [cache_ide3_appl_search_start], eax |
mov ecx, [cache_ide3_appl_sad_size] |
mov edi, [cache_ide3_data_pointer] |
.continue: |
call .clear |
popa |
ret |
;-------------------------------------- |
.clear: |
shl ecx, 1 |
cld |
96,272 → 72,131 |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache: |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
; 1 - IDE0 ... 12 - IDE11 |
push eax |
mov eax, [cdpos] |
dec eax |
imul eax, sizeof.IDE_CACHE |
add eax, cache_ide0 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
mov ecx, [cache_ide0_system_sad_size] |
mov esi, [cache_ide0_pointer] |
jne @f |
mov ecx, [eax+IDE_CACHE.system_sad_size] |
mov esi, [eax+IDE_CACHE.pointer] |
pop eax |
ret |
.ide0_appl_data: |
mov ecx, [cache_ide0_appl_sad_size] |
mov esi, [cache_ide0_data_pointer] |
;-------------------------------------- |
@@: |
mov ecx, [eax+IDE_CACHE.appl_sad_size] |
mov esi, [eax+IDE_CACHE.data_pointer] |
pop eax |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
mov ecx, [cache_ide1_system_sad_size] |
mov esi, [cache_ide1_pointer] |
ret |
.ide1_appl_data: |
mov ecx, [cache_ide1_appl_sad_size] |
mov esi, [cache_ide1_data_pointer] |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
mov ecx, [cache_ide2_system_sad_size] |
mov esi, [cache_ide2_pointer] |
ret |
.ide2_appl_data: |
mov ecx, [cache_ide2_appl_sad_size] |
mov esi, [cache_ide2_data_pointer] |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
mov ecx, [cache_ide3_system_sad_size] |
mov esi, [cache_ide3_pointer] |
ret |
.ide3_appl_data: |
mov ecx, [cache_ide3_appl_sad_size] |
mov esi, [cache_ide3_data_pointer] |
ret |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache_1: |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
; 1 - IDE0 ... 12 - IDE11 |
push eax |
mov eax, [cdpos] |
dec eax |
imul eax, sizeof.IDE_CACHE |
add eax, cache_ide0 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
mov esi, [cache_ide0_pointer] |
jne @f |
mov esi, [eax+IDE_CACHE.pointer] |
pop eax |
ret |
.ide0_appl_data: |
mov esi, [cache_ide0_data_pointer] |
;-------------------------------------- |
@@: |
mov esi, [eax+IDE_CACHE.data_pointer] |
pop eax |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
mov esi, [cache_ide1_pointer] |
ret |
.ide1_appl_data: |
mov esi, [cache_ide1_data_pointer] |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
mov esi, [cache_ide2_pointer] |
ret |
.ide2_appl_data: |
mov esi, [cache_ide2_data_pointer] |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
mov esi, [cache_ide3_pointer] |
ret |
.ide3_appl_data: |
mov esi, [cache_ide3_data_pointer] |
ret |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache_2: |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
; 1 - IDE0 ... 12 - IDE11 |
mov eax, [cdpos] |
dec eax |
imul eax, sizeof.IDE_CACHE |
add eax, cache_ide0 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
mov eax, [cache_ide0_system_data] |
jne @f |
mov eax, [eax+IDE_CACHE.system_data] |
ret |
.ide0_appl_data: |
mov eax, [cache_ide0_appl_data] |
;-------------------------------------- |
@@: |
mov eax, [eax+IDE_CACHE.appl_data] |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
mov eax, [cache_ide1_system_data] |
ret |
.ide1_appl_data: |
mov eax, [cache_ide1_appl_data] |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
mov eax, [cache_ide2_system_data] |
ret |
.ide2_appl_data: |
mov eax, [cache_ide2_appl_data] |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
mov eax, [cache_ide3_system_data] |
ret |
.ide3_appl_data: |
mov eax, [cache_ide3_appl_data] |
ret |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache_3: |
; mov ecx,cache_max*10/100 |
; mov edi,[cache_search_start] |
; 1 - IDE0 ... 12 - IDE11 |
push eax |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
mov eax, [cdpos] |
dec eax |
imul eax, sizeof.IDE_CACHE |
add eax, cache_ide0 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
mov edi, [cache_ide0_search_start] |
jne @f |
mov edi, [eax+IDE_CACHE.search_start] |
pop eax |
ret |
.ide0_appl_data: |
mov edi, [cache_ide0_appl_search_start] |
;-------------------------------------- |
@@: |
mov edi, [eax+IDE_CACHE.appl_search_start] |
pop eax |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
mov edi, [cache_ide1_search_start] |
ret |
.ide1_appl_data: |
mov edi, [cache_ide1_appl_search_start] |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
mov edi, [cache_ide2_search_start] |
ret |
.ide2_appl_data: |
mov edi, [cache_ide2_appl_search_start] |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
mov edi, [cache_ide3_search_start] |
ret |
.ide3_appl_data: |
mov edi, [cache_ide3_appl_search_start] |
ret |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache_4: |
; cmp edi,cache_max |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
; 1 - IDE0 ... 12 - IDE11 |
push eax |
mov eax, [cdpos] |
dec eax |
imul eax, sizeof.IDE_CACHE |
add eax, cache_ide0 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
cmp edi, [cache_ide0_system_sad_size] |
jne @f |
cmp edi, [eax+IDE_CACHE.system_sad_size] |
pop eax |
ret |
.ide0_appl_data: |
cmp edi, [cache_ide0_appl_sad_size] |
;-------------------------------------- |
@@: |
cmp edi, [eax+IDE_CACHE.appl_sad_size] |
pop eax |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
cmp edi, [cache_ide1_system_sad_size] |
ret |
.ide1_appl_data: |
cmp edi, [cache_ide1_appl_sad_size] |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
cmp edi, [cache_ide2_system_sad_size] |
ret |
.ide2_appl_data: |
cmp edi, [cache_ide2_appl_sad_size] |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
cmp edi, [cache_ide3_system_sad_size] |
ret |
.ide3_appl_data: |
cmp edi, [cache_ide3_appl_sad_size] |
ret |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache_5: |
; mov [cache_search_start],edi |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
; 1 - IDE0 ... 12 - IDE11 |
push eax |
mov eax, [cdpos] |
dec eax |
imul eax, sizeof.IDE_CACHE |
add eax, cache_ide0 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
mov [cache_ide0_search_start], edi |
jne @f |
mov [eax+IDE_CACHE.search_start], edi |
pop eax |
ret |
.ide0_appl_data: |
mov [cache_ide0_appl_search_start], edi |
;-------------------------------------- |
@@: |
mov [eax+IDE_CACHE.appl_search_start], edi |
pop eax |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
mov [cache_ide1_search_start], edi |
ret |
.ide1_appl_data: |
mov [cache_ide1_appl_search_start], edi |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
mov [cache_ide2_search_start], edi |
ret |
.ide2_appl_data: |
mov [cache_ide2_appl_search_start], edi |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
mov [cache_ide3_search_start], edi |
ret |
.ide3_appl_data: |
mov [cache_ide3_appl_search_start], edi |
ret |
;-------------------------------------------------------------------- |
;align 4 |
;calculate_linear_to_real: |
; shr eax, 12 |
; mov eax, [page_tabs+eax*4] |
; and eax, 0xFFFFF000 |
; ret |
/kernel/branches/Kolibri-acpi/blkdev/rd.inc |
---|
22,11 → 22,6 |
.size = $ - ramdisk_functions |
endg |
; See memmap.inc. |
; Currently size of memory allocated for the ramdisk is fixed. |
; This should be revisited when/if memory map would become more dynamic. |
RAMDISK_CAPACITY = 2880 ; in sectors |
iglobal |
align 4 |
ramdisk_actual_size dd RAMDISK_CAPACITY |