/kernel/trunk/blkdev/cd_drv.inc |
---|
768,6 → 768,8 |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_2], 1 |
mov ecx, ide_channel2_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 2 |
mov [DiskNumber], 1 |
791,6 → 793,8 |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_2], 1 |
mov ecx, ide_channel2_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 2 |
mov [DiskNumber], 0 |
814,6 → 818,8 |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_1], 1 |
mov ecx, ide_channel1_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 1 |
mov [DiskNumber], 1 |
837,6 → 843,8 |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_1], 1 |
mov ecx, ide_channel1_mutex |
call mutex_lock |
call reserve_ok2 |
mov [ChannelNumber], 1 |
mov [DiskNumber], 0 |
/kernel/trunk/blkdev/disk.inc |
---|
186,9 → 186,9 |
; Pointer to parent DISK structure. |
FSUserFunctions dd ? |
; Handlers for the sysfunction 70h. This field is a pointer to the following |
; array. The first dword is a number of supported subfunctions, other dwords |
; array. The first dword is pointer to disconnect handler. |
; The first dword is a number of supported subfunctions, other dwords |
; point to handlers of corresponding subfunctions. |
; This field is 0 if file system is not recognized. |
; ...fs-specific data may follow... |
ends |
501,7 → 501,8 |
jz .nofree |
.freeloop: |
lodsd |
call free |
mov ecx, [eax+PARTITION.FSUserFunctions] |
call dword [ecx] |
dec edi |
jnz .freeloop |
.nofree: |
727,7 → 728,7 |
; 10. This is not an MBR. The media is not partitioned. Create one partition |
; which covers all the media and abort the loop. |
stdcall disk_add_partition, 0, 0, \ |
dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4] |
dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4], esi |
jmp .done |
.mbr: |
; 11. Process all entries of the new MBR/EBR |
855,7 → 856,7 |
adc edx, 0 |
push ecx |
stdcall disk_add_partition, eax, edx, \ |
[ecx+PARTITION_TABLE_ENTRY.Length], 0 |
[ecx+PARTITION_TABLE_ENTRY.Length], 0, esi |
pop ecx |
.nothing: |
; 5. Return. |
869,7 → 870,10 |
; This is an internal function called from disk_scan_partitions and |
; process_partition_table_entry. It adds one partition to the list of |
; partitions for the media. |
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword |
; Important note: start, length, disk MUST be present and |
; MUST be in the same order as in PARTITION structure. |
; esi duplicates [disk]. |
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword, disk:dword |
; 1. Check that this partition will not exceed the limit on total number. |
cmp [esi+DISK.NumPartitions], MAX_NUM_PARTITIONS |
jae .nothing |
974,27 → 978,34 |
virtual at ebp+8 |
.start dq ? |
.length dq ? |
.disk dd ? |
end virtual |
; 1. Read the bootsector to the buffer. |
; When disk_add_partition is called, ebx contains a pointer to |
; a two-sectors-sized buffer. This function saves ebx in the stack |
; a three-sectors-sized buffer. This function saves ebx in the stack |
; immediately before ebp. |
virtual at ebp-4 |
.buffer dd ? |
end virtual |
; 1. Read the bootsector to the buffer. |
mov al, DISKFUNC.read |
mov ebx, [.buffer] |
add ebx, 512 |
push 1 |
stdcall disk_call_driver, ebx, dword [.start], dword [.start+4], esp |
mov ebx, [ebp-4] ; get buffer |
add ebx, 512 ; 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 |
push eax |
; 2. Run tests for all supported filesystems. If at least one test succeeded, |
; go to 4. |
; For tests: qword [ebp+8] = partition start, qword [ebp+10h] = partition |
; length, [esp] = 0 if reading bootsector failed or 1 if succeeded, |
; ebx points to the buffer for bootsector. |
; For tests: |
; 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. |
call fat_create_partition |
test eax, eax |
jnz .success |
call ntfs_create_partition |
test eax, eax |
jnz .success |
call ext2_create_partition |
test eax, eax |
jnz .success |
; 3. No file system has recognized the volume, so just allocate the PARTITION |
; structure without extra fields. |
movi eax, sizeof.PARTITION |
1001,22 → 1012,30 |
call malloc |
test eax, eax |
jz .nothing |
mov edx, dword [.start] |
mov edx, dword [ebp+PARTITION.FirstSector] |
mov dword [eax+PARTITION.FirstSector], edx |
mov edx, dword [.start+4] |
mov edx, dword [ebp+PARTITION.FirstSector+4] |
mov dword [eax+PARTITION.FirstSector+4], edx |
mov edx, dword [.length] |
mov edx, dword [ebp+PARTITION.Length] |
mov dword [eax+PARTITION.Length], edx |
mov edx, dword [.length+4] |
mov edx, dword [ebp+PARTITION.Length+4] |
mov dword [eax+PARTITION.Length+4], edx |
mov [eax+PARTITION.Disk], esi |
and [eax+PARTITION.FSUserFunctions], 0 |
mov [eax+PARTITION.FSUserFunctions], default_fs_functions |
.success: |
.nothing: |
sub ebp, 8 ; restore ebp |
; 4. Return with eax = pointer to PARTITION or NULL. |
pop ecx |
ret |
iglobal |
align 4 |
default_fs_functions: |
dd free |
dd 0 ; no user functions |
endg |
; This function is called from file_system_lfn. |
; This handler gets the control each time when fn 70 is called |
; with unknown item of root subdirectory. |
1200,15 → 1219,13 |
mov eax, [edx+DISK.Partitions] |
mov eax, [eax+ecx*4] |
mov edi, [eax+PARTITION.FSUserFunctions] |
test edi, edi |
jz .nofs |
mov ecx, [ebx] |
cmp [edi], ecx |
cmp [edi+4], ecx |
jbe .unsupported |
push edx |
push ebp |
mov ebp, eax |
call dword [edi+4+ecx*4] |
call dword [edi+8+ecx*4] |
pop ebp |
pop edx |
mov dword [esp+32], eax |
1225,6 → 1242,8 |
mov dword [esp+32], ERROR_FILE_NOT_FOUND |
jmp .cleanup |
.unsupported: |
cmp edi, default_fs_functions |
jz .nofs |
mov dword [esp+32], ERROR_UNSUPPORTED_FS |
jmp .cleanup |
.nomedia: |
/kernel/trunk/blkdev/disk_cache.inc |
---|
14,19 → 14,7 |
; eax is relative to partition start |
; out: eax = error code; 0 = ok |
fs_read32_sys: |
; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure, |
; this request should be processed by hd_read. |
cmp [ebp+PARTITION.Disk], 'old' |
jnz @f |
add eax, dword [ebp+PARTITION.FirstSector] |
mov [hdd_appl_data], 0 |
call hd_read |
mov [hdd_appl_data], 1 ; restore to default state |
mov eax, [hd_error] |
ret |
@@: |
; In the normal case, save ecx, set ecx to SysCache and let the common part |
; do its work. |
; 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 |
39,18 → 27,7 |
; eax is relative to partition start |
; out: eax = error code; 0 = ok |
fs_read32_app: |
; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure, |
; this request should be processed by hd_read. |
cmp [ebp+PARTITION.Disk], 'old' |
jnz @f |
add eax, dword [ebp+PARTITION.FirstSector] |
mov [hdd_appl_data], 1 |
call hd_read |
mov eax, [hd_error] |
ret |
@@: |
; In the normal case, save ecx, set ecx to AppCache and let the common part |
; do its work. |
; 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 |
185,19 → 162,7 |
; eax is relative to partition start |
; out: eax = error code; 0 = ok |
fs_write32_sys: |
; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure, |
; this request should be processed by hd_write. |
cmp [ebp+PARTITION.Disk], 'old' |
jnz @f |
add eax, dword [ebp+PARTITION.FirstSector] |
mov [hdd_appl_data], 0 |
call hd_write |
mov [hdd_appl_data], 1 ; restore to default state |
mov eax, [hd_error] |
ret |
@@: |
; In the normal case, save ecx, set ecx to SysCache and let the common part |
; do its work. |
; 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 |
210,18 → 175,7 |
; eax is relative to partition start |
; out: eax = error code; 0 = ok |
fs_write32_app: |
; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure, |
; this request should be processed by hd_write. |
cmp [ebp+PARTITION.Disk], 'old' |
jnz @f |
add eax, dword [ebp+PARTITION.FirstSector] |
mov [hdd_appl_data], 1 |
call hd_write |
mov eax, [hd_error] |
ret |
@@: |
; In the normal case, save ecx, set ecx to AppCache and let the common part |
; do its work. |
; 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 |
622,17 → 576,6 |
; This function flushes all modified data from both caches for the given DISK. |
; esi = pointer to DISK |
disk_sync: |
; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure, |
; this request should be processed by write_cache. |
cmp esi, 'old' |
jnz @f |
mov [hdd_appl_data], 0 |
call write_cache |
mov [hdd_appl_data], 1 |
call write_cache |
mov eax, [hd_error] |
ret |
@@: |
; The algorithm is straightforward. |
push esi |
push esi ; for second write_cache64 |
/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 |
;----------------------------------------------------------------------------- |
/kernel/trunk/blkdev/ide_cache.inc |
---|
23,546 → 23,7 |
$Revision$ |
align 4 |
write_cache: |
;----------------------------------------------------------- |
; write all changed sectors to disk |
;----------------------------------------------------------- |
push eax ecx edx esi edi |
; write difference ( 2 ) from cache to hd |
call calculate_cache |
add esi, 8 |
mov edi, 1 |
write_cache_more: |
cmp dword [esi+4], 2; if cache slot is not different |
jne .write_chain |
mov dword [esi+4], 1; same as in hd |
mov eax, [esi] ; eax = sector to write |
cmp eax, [PARTITION_START] |
jb danger |
cmp eax, [PARTITION_END] |
ja danger |
cmp [hdpos], 0x80 |
jae @f |
; DMA write is permitted only if [allow_dma_access]=1 |
cmp [allow_dma_access], 2 |
jae .nodma |
cmp [dma_hdd], 1 |
jnz .nodma |
@@: |
; Объединяем запись цепочки последовательных секторов в одно обращение к диску |
cmp ecx, 1 |
jz .nonext |
cmp dword [esi+8+4], 2 |
jnz .nonext |
push eax |
inc eax |
cmp eax, [esi+8] |
pop 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 |
@@: |
inc [cache_chain_size] |
cmp [cache_chain_size], 16 |
jnz .continue |
jmp .write_chain |
.nonext: |
call flush_cache_chain |
mov [cache_chain_size], 1 |
mov [cache_chain_ptr], esi |
call write_cache_sector |
jmp .continue |
.nodma: |
call cache_write_pio |
.write_chain: |
call flush_cache_chain |
.continue: |
danger: |
add esi, 8 |
inc edi |
dec ecx |
jnz write_cache_more |
call flush_cache_chain |
return_02: |
pop edi esi edx ecx eax |
ret |
flush_cache_chain: |
cmp [cache_chain_started], 0 |
jz @f |
call write_cache_chain |
mov [cache_chain_started], 0 |
@@: |
ret |
;-------------------------------------------------------------------- |
align 4 |
find_empty_slot: |
;----------------------------------------------------------- |
; find empty or read slot, flush cache if next 10% is used by write |
; output : edi = cache slot |
;----------------------------------------------------------- |
; push ecx esi |
search_again: |
call calculate_cache_3 |
shr ecx, 3 |
search_for_empty: |
inc edi |
call calculate_cache_4 |
jbe inside_cache |
mov edi, 1 |
inside_cache: |
push esi |
call calculate_cache_1 |
cmp dword [edi*8+esi+4], 2 |
pop esi |
jb found_slot ; it's empty or read |
dec ecx |
jnz search_for_empty |
call write_cache ; no empty slots found, write all |
cmp [hd_error], 0 |
jne found_slot_access_denied |
jmp search_again ; and start again |
found_slot: |
call calculate_cache_5 |
found_slot_access_denied: |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache: |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
mov ecx, [cache_ide0_system_sad_size] |
mov esi, [cache_ide0_pointer] |
ret |
.ide0_appl_data: |
mov ecx, [cache_ide0_appl_sad_size] |
mov esi, [cache_ide0_data_pointer] |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_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 [hdpos], 3 |
jne .ide3 |
cmp [hdd_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 [hdpos], 4 |
jne .noide |
cmp [hdd_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 |
.noide: |
push eax |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
mov ecx, [cache_ide0_system_sad_size-cache_ide0+eax] |
mov esi, [cache_ide0_pointer-cache_ide0+eax] |
pop eax |
ret |
.bd_appl_data: |
mov ecx, [cache_ide0_appl_sad_size-cache_ide0+eax] |
mov esi, [cache_ide0_data_pointer-cache_ide0+eax] |
pop eax |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache_1: |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
mov esi, [cache_ide0_pointer] |
ret |
.ide0_appl_data: |
mov esi, [cache_ide0_data_pointer] |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_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 [hdpos], 3 |
jne .ide3 |
cmp [hdd_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 [hdpos], 4 |
jne .noide |
cmp [hdd_appl_data], 0 |
jne .ide3_appl_data |
mov esi, [cache_ide3_pointer] |
ret |
.ide3_appl_data: |
mov esi, [cache_ide3_data_pointer] |
ret |
.noide: |
push eax |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
mov esi, [cache_ide0_pointer-cache_ide0+eax] |
pop eax |
ret |
.bd_appl_data: |
mov esi, [cache_ide0_data_pointer-cache_ide0+eax] |
pop eax |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache_2: |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
mov eax, [cache_ide0_system_data] |
ret |
.ide0_appl_data: |
mov eax, [cache_ide0_appl_data] |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_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 [hdpos], 3 |
jne .ide3 |
cmp [hdd_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 [hdpos], 4 |
jne .noide |
cmp [hdd_appl_data], 0 |
jne .ide3_appl_data |
mov eax, [cache_ide3_system_data] |
ret |
.ide3_appl_data: |
mov eax, [cache_ide3_appl_data] |
ret |
.noide: |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
mov eax, [cache_ide0_system_data-cache_ide0+eax] |
ret |
.bd_appl_data: |
mov eax, [cache_ide0_appl_data-cache_ide0+eax] |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache_3: |
; mov ecx,cache_max*10/100 |
; mov edi,[cache_search_start] |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
mov ecx, [cache_ide0_system_sad_size] |
mov edi, [cache_ide0_search_start] |
ret |
.ide0_appl_data: |
mov ecx, [cache_ide0_appl_sad_size] |
mov edi, [cache_ide0_appl_search_start] |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_appl_data], 0 |
jne .ide1_appl_data |
mov ecx, [cache_ide1_system_sad_size] |
mov edi, [cache_ide1_search_start] |
ret |
.ide1_appl_data: |
mov ecx, [cache_ide1_appl_sad_size] |
mov edi, [cache_ide1_appl_search_start] |
ret |
.ide2: |
cmp [hdpos], 3 |
jne .ide3 |
cmp [hdd_appl_data], 0 |
jne .ide2_appl_data |
mov ecx, [cache_ide2_system_sad_size] |
mov edi, [cache_ide2_search_start] |
ret |
.ide2_appl_data: |
mov ecx, [cache_ide2_appl_sad_size] |
mov edi, [cache_ide2_appl_search_start] |
ret |
.ide3: |
cmp [hdpos], 4 |
jne .noide |
cmp [hdd_appl_data], 0 |
jne .ide3_appl_data |
mov ecx, [cache_ide3_system_sad_size] |
mov edi, [cache_ide3_search_start] |
ret |
.ide3_appl_data: |
mov ecx, [cache_ide3_appl_sad_size] |
mov edi, [cache_ide3_appl_search_start] |
ret |
.noide: |
push eax |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
mov ecx, [cache_ide0_system_sad_size-cache_ide0+eax] |
mov edi, [cache_ide0_search_start-cache_ide0+eax] |
pop eax |
ret |
.bd_appl_data: |
mov ecx, [cache_ide0_appl_sad_size-cache_ide0+eax] |
mov edi, [cache_ide0_appl_search_start-cache_ide0+eax] |
pop eax |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache_4: |
; cmp edi,cache_max |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
cmp edi, [cache_ide0_system_sad_size] |
ret |
.ide0_appl_data: |
cmp edi, [cache_ide0_appl_sad_size] |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_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 [hdpos], 3 |
jne .ide3 |
cmp [hdd_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 [hdpos], 4 |
jne .noide |
cmp [hdd_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 |
.noide: |
push eax |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
cmp edi, [cache_ide0_system_sad_size-cache_ide0+eax] |
pop eax |
ret |
.bd_appl_data: |
cmp edi, [cache_ide0_appl_sad_size-cache_ide0+eax] |
pop eax |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache_5: |
; mov [cache_search_start],edi |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
mov [cache_ide0_search_start], edi |
ret |
.ide0_appl_data: |
mov [cache_ide0_appl_search_start], edi |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_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 [hdpos], 3 |
jne .ide3 |
cmp [hdd_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 [hdpos], 4 |
jne .noide |
cmp [hdd_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 |
.noide: |
push eax |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
mov [cache_ide0_search_start-cache_ide0+eax], edi |
pop eax |
ret |
.bd_appl_data: |
mov [cache_ide0_appl_search_start-cache_ide0+eax], edi |
pop eax |
ret |
;-------------------------------------------------------------------- |
align 4 |
find_empty_slot_CD_cache: |
;----------------------------------------------------------- |
; find empty or read slot, flush cache if next 10% is used by write |