Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 3741 → Rev 3742

/kernel/trunk/blkdev/hd_drv.inc
1,6 → 1,6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13,39 → 13,93
; Access through BIOS by diamond
; LBA48 support by Mario79
;-----------------------------------------------------------------------------
struct HD_DATA
hdbase dd ?
hdid dd ?
hdpos dd ?
ends
 
iglobal
align 4
hd_read:
;-----------------------------------------------------------
; input : eax = block to read
; ebx = destination
;-----------------------------------------------------------
and [hd_error], 0
push ecx esi edi ; scan cache
ide_callbacks:
dd ide_callbacks.end - ide_callbacks ; strucsize
dd 0 ; no close function
dd 0 ; no closemedia function
dd ide_querymedia
dd ide_read
dd ide_write
dd 0 ; no flush function
dd 0 ; use default cache size
.end:
 
call calculate_cache
add esi, 8
bd_callbacks:
dd bd_callbacks.end - bd_callbacks ; strucsize
dd 0 ; no close function
dd 0 ; no closemedia function
dd bd_querymedia
dd bd_read_interface
dd bd_write_interface
dd 0 ; no flush function
dd 0 ; use default cache size
.end:
 
mov edi, 1
hd0_data HD_DATA ?, 0, 1
hd1_data HD_DATA ?, 0x10, 2
hd2_data HD_DATA ?, 0, 3
hd3_data HD_DATA ?, 0x10, 4
endg
 
hdreadcache:
cmp dword [esi+4], 0 ; empty
je nohdcache
uglobal
ide_mutex MUTEX
ide_channel1_mutex MUTEX
ide_channel2_mutex MUTEX
endg
 
cmp [esi], eax ; correct sector
je yeshdcache
 
nohdcache:
add esi, 8
inc edi
dec ecx
jnz hdreadcache
 
call find_empty_slot ; ret in edi
cmp [hd_error], 0
jne return_01
; Read through BIOS?
cmp [hdpos], 0x80
jae .bios
proc ide_read stdcall uses edi, \
hd_data, buffer, startsector:qword, numsectors
; hd_data = pointer to hd*_data
; buffer = pointer to buffer for data
; startsector = 64-bit start sector
; numsectors = pointer to number of sectors on input,
; must be filled with number of sectors really read
locals
sectors_todo dd ?
channel_lock dd ?
endl
; 1. Initialize number of sectors: get number of requested sectors
; and say that no sectors were read yet.
mov ecx, [numsectors]
mov eax, [ecx]
mov dword [ecx], 0
mov [sectors_todo], eax
; 2. Acquire the global lock.
mov ecx, ide_mutex
call mutex_lock
mov ecx, ide_channel2_mutex
mov eax, [hd_data]
cmp [eax+HD_DATA.hdbase], 0x1F0
jne .IDE_Channel_2
mov ecx, ide_channel1_mutex
.IDE_Channel_2:
mov [channel_lock], ecx
call mutex_lock
; 3. Convert parameters to the form suitable for worker procedures.
; Underlying procedures do not know about 64-bit sectors.
; 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]
mov [hdbase], eax
mov eax, [ecx+HD_DATA.hdid]
mov [hdid], eax
mov eax, [ecx+HD_DATA.hdpos]
mov [hdpos], eax
mov eax, dword [startsector]
mov edi, [buffer]
; 4. Worker procedures take one sectors per time, so loop over all sectors to read.
.sectors_loop:
; DMA read is permitted if [allow_dma_access]=1 or 2
cmp [allow_dma_access], 2
ja .nodma
55,38 → 109,273
jmp @f
.nodma:
call hd_read_pio
jmp @f
.bios:
call bd_read
@@:
cmp [hd_error], 0
jne return_01
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
 
call calculate_cache_1
lea esi, [edi*8+esi]
proc ide_write stdcall uses esi edi, \
hd_data, buffer, startsector:qword, numsectors
; hd_data = pointer to hd*_data
; buffer = pointer to buffer with data
; startsector = 64-bit start sector
; numsectors = pointer to number of sectors on input,
; must be filled with number of sectors really written
locals
sectors_todo dd ?
channel_lock dd ?
endl
; 1. Initialize number of sectors: get number of requested sectors
; and say that no sectors were read yet.
mov ecx, [numsectors]
mov eax, [ecx]
mov dword [ecx], 0
mov [sectors_todo], eax
; 2. Acquire the global lock.
mov ecx, ide_mutex
call mutex_lock
mov ecx, ide_channel2_mutex
mov eax, [hd_data]
cmp [eax+HD_DATA.hdbase], 0x1F0
jne .IDE_Channel_2
mov ecx, ide_channel1_mutex
.IDE_Channel_2:
mov [channel_lock], ecx
call mutex_lock
; 3. Convert parameters to the form suitable for worker procedures.
; Underlying procedures do not know about 64-bit sectors.
; 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]
mov [hdbase], eax
mov eax, [ecx+HD_DATA.hdid]
mov [hdid], eax
mov eax, [ecx+HD_DATA.hdpos]
mov [hdpos], eax
mov esi, [buffer]
lea edi, [startsector]
mov [cache_chain_ptr], edi
; 4. Worker procedures take max 16 sectors per time,
; loop until all sectors will be processed.
.sectors_loop:
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
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
 
mov [esi], eax ; sector number
mov dword [esi+4], 1 ; hd read - mark as same as in hd
; This is a stub.
proc ide_querymedia stdcall, hd_data, mediainfo
mov eax, [mediainfo]
mov [eax+DISKMEDIAINFO.Flags], 0
mov [eax+DISKMEDIAINFO.SectorSize], 512
or dword [eax+DISKMEDIAINFO.Capacity], 0xFFFFFFFF
or dword [eax+DISKMEDIAINFO.Capacity+4], 0xFFFFFFFF
xor eax, eax
ret
endp
 
yeshdcache:
mov esi, edi
shl esi, 9
proc bd_read_interface stdcall uses edi, \
userdata, buffer, startsector:qword, numsectors
; userdata = old [hdpos] = 80h + index in NumBiosDisks
; buffer = pointer to buffer for data
; startsector = 64-bit start sector
; numsectors = pointer to number of sectors on input,
; must be filled with number of sectors really read
locals
sectors_todo dd ?
endl
; 1. Initialize number of sectors: get number of requested sectors
; and say that no sectors were read yet.
mov ecx, [numsectors]
mov eax, [ecx]
mov dword [ecx], 0
mov [sectors_todo], eax
; 2. Acquire the global lock.
mov ecx, ide_mutex
call mutex_lock
; 3. Convert parameters to the form suitable for worker procedures.
; Underlying procedures do not know about 64-bit sectors.
; Worker procedures use global variables and edi for [buffer].
cmp dword [startsector+4], 0
jnz .fail
and [hd_error], 0
mov eax, [userdata]
mov [hdpos], eax
mov eax, dword [startsector]
mov edi, [buffer]
; 4. Worker procedures take one sectors per time, so loop over all sectors to read.
.sectors_loop:
call bd_read
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, ide_mutex
call mutex_unlock
or eax, -1
ret
.done:
mov ecx, ide_mutex
call mutex_unlock
xor eax, eax
ret
endp
 
push eax
call calculate_cache_2
add esi, eax
pop eax
proc bd_write_interface stdcall uses esi edi, \
userdata, buffer, startsector:qword, numsectors
; userdata = old [hdpos] = 80h + index in NumBiosDisks
; buffer = pointer to buffer with data
; startsector = 64-bit start sector
; numsectors = pointer to number of sectors on input,
; must be filled with number of sectors really written
locals
sectors_todo dd ?
endl
; 1. Initialize number of sectors: get number of requested sectors
; and say that no sectors were read yet.
mov ecx, [numsectors]
mov eax, [ecx]
mov dword [ecx], 0
mov [sectors_todo], eax
; 2. Acquire the global lock.
mov ecx, ide_mutex
call mutex_lock
; 3. Convert parameters to the form suitable for worker procedures.
; Underlying procedures do not know about 64-bit sectors.
; Worker procedures use global variables and esi for [buffer].
cmp dword [startsector+4], 0
jnz .fail
and [hd_error], 0
mov eax, [userdata]
mov [hdpos], eax
mov esi, [buffer]
lea edi, [startsector]
mov [cache_chain_ptr], edi
; 4. Worker procedures take max 16 sectors per time,
; loop until all sectors will be processed.
.sectors_loop:
mov ecx, 16
cmp ecx, [sectors_todo]
jbe @f
mov ecx, [sectors_todo]
@@:
mov [cache_chain_size], cl
call bd_write_cache_chain
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, ide_mutex
call mutex_unlock
or eax, -1
ret
.done:
mov ecx, ide_mutex
call mutex_unlock
xor eax, eax
ret
endp
 
mov edi, ebx
mov ecx, 512/4
cld
rep movsd ; move data
; This is a stub.
proc bd_querymedia stdcall, hd_data, mediainfo
mov eax, [mediainfo]
mov [eax+DISKMEDIAINFO.Flags], 0
mov [eax+DISKMEDIAINFO.SectorSize], 512
or dword [eax+DISKMEDIAINFO.Capacity], 0xFFFFFFFF
or dword [eax+DISKMEDIAINFO.Capacity+4], 0xFFFFFFFF
xor eax, eax
ret
endp
 
return_01:
pop edi esi ecx
ret
;-----------------------------------------------------------------------------
align 4
; input: eax = sector, edi -> buffer
; output: edi = edi + 512
hd_read_pio:
push eax edx
 
184,19 → 473,11
 
pushfd
cli
push edi
shl edi, 9
 
push eax
call calculate_cache_2
add edi, eax
pop eax
 
mov ecx, 256
mov edx, [hdbase]
cld
rep insw
pop edi
popfd
 
pop edx eax
203,61 → 484,7
ret
;-----------------------------------------------------------------------------
align 4
hd_write:
;-----------------------------------------------------------
; input : eax = block
; ebx = pointer to memory
;-----------------------------------------------------------
push ecx esi edi
 
; check if the cache already has the sector and overwrite it
call calculate_cache
add esi, 8
mov edi, 1
 
hdwritecache:
cmp dword [esi+4], 0 ; if cache slot is empty
je not_in_cache_write
 
cmp [esi], eax ; if the slot has the sector
je yes_in_cache_write
 
not_in_cache_write:
add esi, 8
inc edi
dec ecx
jnz hdwritecache
 
; sector not found in cache
; write the block to a new location
call find_empty_slot ; ret in edi
cmp [hd_error], 0
jne hd_write_access_denied
 
call calculate_cache_1
lea esi, [edi*8+esi]
mov [esi], eax ; sector number
 
yes_in_cache_write:
mov dword [esi+4], 2 ; write - differs from hd
 
shl edi, 9
 
push eax
call calculate_cache_2
add edi, eax
pop eax
 
mov esi, ebx
mov ecx, 512/4
cld
rep movsd ; move data
 
hd_write_access_denied:
pop edi esi ecx
ret
;-----------------------------------------------------------------------------
align 4
; edi -> sector, esi -> data
cache_write_pio:
; Select the desired drive
mov edx, [hdbase]
271,7 → 498,7
jne hd_write_error
 
; ATA with 28 or 48 bit for sector number?
mov eax, [esi]
mov eax, [edi]
cmp eax, 0x10000000
jae .lba48
;--------------------------------------
286,7 → 513,7
inc eax
out dx, al ; ATA Sector Counter счётчик секторов
inc edx
mov eax, [esi] ; eax = sector to write
mov eax, [edi] ; eax = sector to write
out dx, al ; LBA Low LBA (7:0)
shr eax, 8
inc edx
319,7 → 546,7
inc eax
out dx, al ; Sector Count Current Sector count (7:0)
inc edx
mov eax, [esi]
mov eax, [edi]
rol eax, 8
out dx, al ; LBA Low Previous LBA (31:24)
xor eax, eax ; because only 32 bit cache
328,7 → 555,7
inc edx
out dx, al ; LBA High Previous LBA (47:40)
sub edx, 2
mov eax, [esi]
mov eax, [edi]
out dx, al ; LBA Low Current LBA (7:0)
shr eax, 8
inc edx
355,14 → 582,6
 
pushfd
cli
mov esi, edi
shl esi, 9
 
push eax
call calculate_cache_2
add esi, eax
pop eax
 
mov ecx, 256
mov edx, [hdbase]
cld
605,19 → 824,13
sub eax, [dma_cur_sector]
shl eax, 9
add eax, (OS_BASE+IDE_DMA)
push ecx esi edi
push ecx esi
mov esi, eax
shl edi, 9
 
push eax
call calculate_cache_2
add edi, eax
pop eax
 
mov ecx, 512/4
cld
rep movsd
pop edi esi ecx
pop esi ecx
pop edx
pop eax
ret
766,24 → 979,12
mov [dma_cur_sector], eax
jmp hd_read_dma
;-----------------------------------------------------------------------------
align 4
write_cache_sector:
mov [cache_chain_size], 1
mov [cache_chain_pos], edi
;--------------------------------------
align 4
write_cache_chain:
cmp [hdpos], 0x80
jae bd_write_cache_chain
cache_write_dma:
mov eax, [cache_chain_ptr]
push esi
mov eax, IDE_descriptor_table
mov edx, eax
pusha
mov esi, [cache_chain_pos]
shl esi, 9
call calculate_cache_2
add esi, eax
mov edi, (OS_BASE+IDE_DMA)
mov dword [edx], IDE_DMA
movzx ecx, [cache_chain_size]
965,19 → 1166,12
sub eax, [bios_cur_sector]
shl eax, 9
add eax, (OS_BASE+0x9A000)
push ecx esi edi
push ecx esi
mov esi, eax
shl edi, 9
 
push eax
call calculate_cache_2
add edi, eax
pop eax
 
mov ecx, 512/4
cld
rep movsd
pop edi esi ecx
pop esi ecx
pop edx
pop eax
ret
1006,10 → 1200,6
align 4
bd_write_cache_chain:
pusha
mov esi, [cache_chain_pos]
shl esi, 9
call calculate_cache_2
add esi, eax
mov edi, OS_BASE + 0x9A000
movzx ecx, [cache_chain_size]
push ecx
1041,7 → 1231,7
int13_call:
; Because this code uses fixed addresses,
; it can not be run simultaniously by many threads.
; In current implementation it is protected by common mutex 'hd1_status'
; In current implementation it is protected by common mutex 'ide_status'
mov word [OS_BASE + 510h], 10h ; packet length
mov word [OS_BASE + 512h], cx ; number of sectors
mov dword [OS_BASE + 514h], 9A000000h ; buffer 9A00:0000
1088,82 → 1278,3
@@:
ret
; \end{diamond}
;-----------------------------------------------------------------------------
align 4
reserve_hd1:
cli
cmp [hd1_status], 0
je reserve_ok1
 
sti
call change_task
jmp reserve_hd1
 
reserve_ok1:
push eax
mov eax, [CURRENT_TASK]
shl eax, 5
mov eax, [eax+CURRENT_TASK+TASKDATA.pid]
mov [hd1_status], eax
pop eax
sti
ret
;-----------------------------------------------------------------------------
uglobal
hd_in_cache db ?
endg
;-----------------------------------------------------------------------------
align 4
reserve_hd_channel:
; BIOS disk accesses are protected with common mutex hd1_status
; This must be modified when hd1_status will not be valid!
cmp [hdpos], 0x80
jae .ret
cmp [hdbase], 0x1F0
jne .IDE_Channel_2
.IDE_Channel_1:
cli
cmp [IDE_Channel_1], 0
je .reserve_ok_1
sti
call change_task
jmp .IDE_Channel_1
.IDE_Channel_2:
cli
cmp [IDE_Channel_2], 0
je .reserve_ok_2
sti
call change_task
jmp .IDE_Channel_2
.reserve_ok_1:
mov [IDE_Channel_1], 1
push eax
mov al, 1
jmp @f
.reserve_ok_2:
mov [IDE_Channel_2], 1
push eax
mov al, 3
@@:
cmp [hdid], 1
sbb al, -1
mov [hd_in_cache], al
pop eax
sti
.ret:
ret
;-----------------------------------------------------------------------------
free_hd_channel:
; see comment at reserve_hd_channel
cmp [hdpos], 0x80
jae .ret
cmp [hdbase], 0x1F0
jne .IDE_Channel_2
.IDE_Channel_1:
mov [IDE_Channel_1], 0
.ret:
ret
.IDE_Channel_2:
mov [IDE_Channel_2], 0
ret
;-----------------------------------------------------------------------------