Support GUID Partition Table (GPT) disk layout
git-svn-id: svn://kolibrios.org@6827 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
46ae9b5169
commit
34df6be0da
@ -216,6 +216,50 @@ struct PARTITION_TABLE_ENTRY
|
|||||||
; Length of the partition in sectors.
|
; Length of the partition in sectors.
|
||||||
ends
|
ends
|
||||||
|
|
||||||
|
; GUID Partition Table Header, UEFI 2.6, Table 18
|
||||||
|
struct GPTH
|
||||||
|
Signature rb 8
|
||||||
|
; 'EFI PART'
|
||||||
|
Revision dd ?
|
||||||
|
; 0x00010000
|
||||||
|
HeaderSize dd ?
|
||||||
|
; Size of this header in bytes, must fit to one sector.
|
||||||
|
HeaderCRC32 dd ?
|
||||||
|
; Set this field to zero, compute CRC32 via 0xEDB88320, compare.
|
||||||
|
Reserved dd ?
|
||||||
|
; Myst be zero.
|
||||||
|
MyLBA dq ?
|
||||||
|
; LBA of the sector containing this GPT header.
|
||||||
|
AlternateLBA dq ?
|
||||||
|
; LBA of the sector containing the other GPT header.
|
||||||
|
; AlternateLBA of Primary GPTH points to Backup one and vice versa.
|
||||||
|
FirstUsableLBA dq ?
|
||||||
|
; Only sectors between first and last UsableLBA may form partitions
|
||||||
|
LastUsableLBA dq ?
|
||||||
|
DiskGUID rb 16
|
||||||
|
; Globally Unique IDentifier
|
||||||
|
PartitionEntryLBA dq ?
|
||||||
|
; First LBA of Partition Entry Array.
|
||||||
|
; Length in bytes is computed as a product of two following fields.
|
||||||
|
NumberOfPartitionEntries dd ?
|
||||||
|
; Actual number of partitions depends on the contents of Partition Entry Array.
|
||||||
|
; A partition entry is unused if zeroed.
|
||||||
|
SizeOfPartitionEntry dd ? ; in bytes
|
||||||
|
PartitionEntryArrayCRC32 dd ?
|
||||||
|
; Same CRC as for GPT header.
|
||||||
|
ends
|
||||||
|
|
||||||
|
; GPT Partition Entry, UEFI 2.6, Table 19
|
||||||
|
struct GPE
|
||||||
|
PartitionTypeGUID rb 16
|
||||||
|
UniquePartitionGUID rb 16
|
||||||
|
StartingLBA dq ?
|
||||||
|
EndingLBA dq ?
|
||||||
|
; Length in sectors is EndingLBA - StartingLBA + 1.
|
||||||
|
Attributes dq ?
|
||||||
|
PartitionName rb 72
|
||||||
|
ends
|
||||||
|
|
||||||
; =============================================================================
|
; =============================================================================
|
||||||
; ================================ Global data ================================
|
; ================================ Global data ================================
|
||||||
; =============================================================================
|
; =============================================================================
|
||||||
@ -667,7 +711,7 @@ disk_scan_partitions:
|
|||||||
xor ebp, ebp ; start from sector zero
|
xor ebp, ebp ; start from sector zero
|
||||||
push ebp ; no extended partition yet
|
push ebp ; no extended partition yet
|
||||||
; 4. MBR is 512 bytes long. If sector size is less than 512 bytes,
|
; 4. MBR is 512 bytes long. If sector size is less than 512 bytes,
|
||||||
; assume no MBR, no partitions and go to 10.
|
; assume no MBR, no partitions and go to 11.
|
||||||
cmp [esi+DISK.MediaInfo.SectorSize], 512
|
cmp [esi+DISK.MediaInfo.SectorSize], 512
|
||||||
jb .notmbr
|
jb .notmbr
|
||||||
.new_mbr:
|
.new_mbr:
|
||||||
@ -689,9 +733,19 @@ disk_scan_partitions:
|
|||||||
cmp word [ecx+0x40], 0xaa55
|
cmp word [ecx+0x40], 0xaa55
|
||||||
jnz .mbr_failed
|
jnz .mbr_failed
|
||||||
; 8. The MBR is treated differently from EBRs. For MBR we additionally need to
|
; 8. The MBR is treated differently from EBRs. For MBR we additionally need to
|
||||||
; execute step 9 and possibly step 10.
|
; execute step 10 and possibly step 11.
|
||||||
test ebp, ebp
|
test ebp, ebp
|
||||||
jnz .mbr
|
jnz .mbr
|
||||||
|
; 9. Handle GUID Partition Table
|
||||||
|
; 9a. Check if MBR is protective
|
||||||
|
call is_protective_mbr
|
||||||
|
jnz .no_gpt
|
||||||
|
; 9b. If so, try to scan GPT headers
|
||||||
|
call disk_scan_gpt
|
||||||
|
; 9c. If any GPT header is valid, ignore MBR
|
||||||
|
jz .done
|
||||||
|
; Otherwise process legacy/protective MBR
|
||||||
|
.no_gpt:
|
||||||
; The partition table can be present or not present. In the first case, we just
|
; The partition table can be present or not present. In the first case, we just
|
||||||
; read the MBR. In the second case, we just read the bootsector for a
|
; read the MBR. In the second case, we just read the bootsector for a
|
||||||
; filesystem.
|
; filesystem.
|
||||||
@ -703,8 +757,8 @@ disk_scan_partitions:
|
|||||||
; byte is jmp opcode (0EBh or 0E9h), this is a bootsector which happens to
|
; byte is jmp opcode (0EBh or 0E9h), this is a bootsector which happens to
|
||||||
; have zeros in the place of partition table.
|
; have zeros in the place of partition table.
|
||||||
; C. Otherwise, this is an MBR.
|
; C. Otherwise, this is an MBR.
|
||||||
; 9. Test for MBR vs bootsector.
|
; 10. Test for MBR vs bootsector.
|
||||||
; 9a. Check entries. If any is invalid, go to 10 (rule A).
|
; 10a. Check entries. If any is invalid, go to 11 (rule A).
|
||||||
call is_partition_table_entry
|
call is_partition_table_entry
|
||||||
jc .notmbr
|
jc .notmbr
|
||||||
add ecx, 10h
|
add ecx, 10h
|
||||||
@ -716,25 +770,25 @@ disk_scan_partitions:
|
|||||||
add ecx, 10h
|
add ecx, 10h
|
||||||
call is_partition_table_entry
|
call is_partition_table_entry
|
||||||
jc .notmbr
|
jc .notmbr
|
||||||
; 9b. Check types of the entries. If at least one is nonzero, go to 11 (rule C).
|
; 10b. Check types of the entries. If at least one is nonzero, go to 12 (rule C).
|
||||||
mov al, [ecx-30h+PARTITION_TABLE_ENTRY.Type]
|
mov al, [ecx-30h+PARTITION_TABLE_ENTRY.Type]
|
||||||
or al, [ecx-20h+PARTITION_TABLE_ENTRY.Type]
|
or al, [ecx-20h+PARTITION_TABLE_ENTRY.Type]
|
||||||
or al, [ecx-10h+PARTITION_TABLE_ENTRY.Type]
|
or al, [ecx-10h+PARTITION_TABLE_ENTRY.Type]
|
||||||
or al, [ecx+PARTITION_TABLE_ENTRY.Type]
|
or al, [ecx+PARTITION_TABLE_ENTRY.Type]
|
||||||
jnz .mbr
|
jnz .mbr
|
||||||
; 9c. Empty partition table or bootsector with many zeroes? (rule B)
|
; 10c. Empty partition table or bootsector with many zeroes? (rule B)
|
||||||
cmp byte [ebx], 0EBh
|
cmp byte [ebx], 0EBh
|
||||||
jz .notmbr
|
jz .notmbr
|
||||||
cmp byte [ebx], 0E9h
|
cmp byte [ebx], 0E9h
|
||||||
jnz .mbr
|
jnz .mbr
|
||||||
.notmbr:
|
.notmbr:
|
||||||
; 10. This is not an MBR. The media is not partitioned. Create one partition
|
; 11. This is not an MBR. The media is not partitioned. Create one partition
|
||||||
; which covers all the media and abort the loop.
|
; which covers all the media and abort the loop.
|
||||||
stdcall disk_add_partition, 0, 0, \
|
stdcall disk_add_partition, 0, 0, \
|
||||||
dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4], esi
|
dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4], esi
|
||||||
jmp .done
|
jmp .done
|
||||||
.mbr:
|
.mbr:
|
||||||
; 11. Process all entries of the new MBR/EBR
|
; 12. Process all entries of the new MBR/EBR
|
||||||
lea ecx, [ebx+0x1be] ; ecx -> partition table
|
lea ecx, [ebx+0x1be] ; ecx -> partition table
|
||||||
push 0 ; assume no extended partition
|
push 0 ; assume no extended partition
|
||||||
call process_partition_table_entry
|
call process_partition_table_entry
|
||||||
@ -745,12 +799,12 @@ disk_scan_partitions:
|
|||||||
add ecx, 10h
|
add ecx, 10h
|
||||||
call process_partition_table_entry
|
call process_partition_table_entry
|
||||||
pop ebp
|
pop ebp
|
||||||
; 12. Test whether we found a new EBR and should continue the loop.
|
; 13. Test whether we found a new EBR and should continue the loop.
|
||||||
; 12a. If there was no next EBR, return.
|
; 13a. If there was no next EBR, return.
|
||||||
test ebp, ebp
|
test ebp, ebp
|
||||||
jz .done
|
jz .done
|
||||||
; Ok, we have EBR.
|
; Ok, we have EBR.
|
||||||
; 12b. EBRs addresses are relative to the start of extended partition.
|
; 13b. EBRs addresses are relative to the start of extended partition.
|
||||||
; For simplicity, just abort if an 32-bit overflow occurs; large disks
|
; For simplicity, just abort if an 32-bit overflow occurs; large disks
|
||||||
; are most likely partitioned with GPT, not MBR scheme, since the precise
|
; are most likely partitioned with GPT, not MBR scheme, since the precise
|
||||||
; calculation here would increase limit just twice at the price of big
|
; calculation here would increase limit just twice at the price of big
|
||||||
@ -758,34 +812,231 @@ disk_scan_partitions:
|
|||||||
pop eax ; load extended partition
|
pop eax ; load extended partition
|
||||||
add ebp, eax
|
add ebp, eax
|
||||||
jc .mbr_failed
|
jc .mbr_failed
|
||||||
; 12c. If extended partition has not yet started, start it.
|
; 13c. If extended partition has not yet started, start it.
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jnz @f
|
jnz @f
|
||||||
mov eax, ebp
|
mov eax, ebp
|
||||||
@@:
|
@@:
|
||||||
; 12c. If the limit is not exceeded, continue the loop.
|
; 13d. If the limit is not exceeded, continue the loop.
|
||||||
dec dword [esp]
|
dec dword [esp]
|
||||||
push eax ; store extended partition
|
push eax ; store extended partition
|
||||||
jnz .new_mbr
|
jnz .new_mbr
|
||||||
.mbr_failed:
|
.mbr_failed:
|
||||||
.done:
|
.done:
|
||||||
; 13. Cleanup after the loop.
|
; 14. Cleanup after the loop.
|
||||||
pop eax ; not important anymore
|
pop eax ; not important anymore
|
||||||
pop eax ; not important anymore
|
pop eax ; not important anymore
|
||||||
pop ebp ; restore ebp
|
pop ebp ; restore ebp
|
||||||
; 14. Release the buffer.
|
; 15. Release the buffer.
|
||||||
; 14a. Test whether it is the global buffer or we have allocated it.
|
; 15a. Test whether it is the global buffer or we have allocated it.
|
||||||
cmp ebx, mbr_buffer
|
cmp ebx, mbr_buffer
|
||||||
jz .release_partition_buffer
|
jz .release_partition_buffer
|
||||||
; 14b. If we have allocated it, free it.
|
; 15b. If we have allocated it, free it.
|
||||||
xchg eax, ebx
|
xchg eax, ebx
|
||||||
call free
|
call free
|
||||||
jmp .nothing
|
jmp .nothing
|
||||||
; 14c. Otherwise, release reference.
|
; 15c. Otherwise, release reference.
|
||||||
.release_partition_buffer:
|
.release_partition_buffer:
|
||||||
lock dec [partition_buffer_users]
|
lock dec [partition_buffer_users]
|
||||||
.nothing:
|
.nothing:
|
||||||
; 15. Return.
|
; 16. Return.
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
; This function is called from disk_scan_partitions to validate and parse
|
||||||
|
; primary and backup GPTs.
|
||||||
|
proc disk_scan_gpt
|
||||||
|
; Scan primary GPT (second sector)
|
||||||
|
stdcall scan_gpt, 1, 0
|
||||||
|
test eax, eax
|
||||||
|
; There is no code to restore backup GPT if it's corrupt.
|
||||||
|
; Therefore just exit if Primary GPT has been parsed successfully.
|
||||||
|
jz .exit
|
||||||
|
DEBUGF 1, 'K : Primary GPT is corrupt, trying backup one\n'
|
||||||
|
mov eax, dword[esi+DISK.MediaInfo.Capacity+0]
|
||||||
|
mov edx, dword[esi+DISK.MediaInfo.Capacity+4]
|
||||||
|
sub eax, 1
|
||||||
|
sbb edx, 0
|
||||||
|
; Scan backup GPT (last sector)
|
||||||
|
stdcall scan_gpt, eax, edx
|
||||||
|
test eax, eax
|
||||||
|
jz .exit
|
||||||
|
DEBUGF 1, 'K : Backup GPT is also corrupt, fallback to legacy MBR\n'
|
||||||
|
.exit:
|
||||||
|
; Return value is ZF
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
|
||||||
|
; This function is called from disk_scan_gpt to process a single GPT.
|
||||||
|
proc scan_gpt _mylba:qword
|
||||||
|
locals
|
||||||
|
GPEA_len dd ? ; Length of GPT Partition Entry Array in bytes
|
||||||
|
endl
|
||||||
|
push ebx edi
|
||||||
|
; Allocalte memory for GPT header
|
||||||
|
mov eax, [esi+DISK.MediaInfo.SectorSize]
|
||||||
|
stdcall kernel_alloc, eax
|
||||||
|
test eax, eax
|
||||||
|
jz .fail
|
||||||
|
; Save pointer to stack, just in case
|
||||||
|
push eax
|
||||||
|
mov ebx, eax
|
||||||
|
; Read GPT header
|
||||||
|
mov al, DISKFUNC.read
|
||||||
|
push 1
|
||||||
|
stdcall disk_call_driver, ebx, dword[_mylba+0], dword[_mylba+4], esp
|
||||||
|
pop ecx
|
||||||
|
test eax, eax
|
||||||
|
jnz .fail_free_gpt
|
||||||
|
; Check signature
|
||||||
|
cmp dword[ebx+GPTH.Signature+0], 'EFI '
|
||||||
|
jnz .fail_free_gpt
|
||||||
|
cmp dword[ebx+GPTH.Signature+4], 'PART'
|
||||||
|
jnz .fail_free_gpt
|
||||||
|
; Check Revision
|
||||||
|
cmp [ebx+GPTH.Revision], 0x00010000
|
||||||
|
jnz .fail_free_gpt
|
||||||
|
; Compute and check CRC32
|
||||||
|
xor edx, edx
|
||||||
|
xchg edx, [ebx+GPTH.HeaderCRC32]
|
||||||
|
mov eax, -1
|
||||||
|
stdcall crc_32, 0xEDB88320, ebx, [ebx+GPTH.HeaderSize]
|
||||||
|
xor eax, -1
|
||||||
|
cmp eax, edx
|
||||||
|
jnz .fail_free_gpt
|
||||||
|
; Reserved must be zero
|
||||||
|
cmp [ebx+GPTH.Reserved], 0
|
||||||
|
jnz .fail_free_gpt
|
||||||
|
; MyLBA of GPT header at LBA X must equal X
|
||||||
|
mov eax, dword[ebx+GPTH.MyLBA+0]
|
||||||
|
mov edx, dword[ebx+GPTH.MyLBA+4]
|
||||||
|
cmp eax, dword[_mylba+0]
|
||||||
|
jnz .fail_free_gpt
|
||||||
|
cmp edx, dword[_mylba+4]
|
||||||
|
jnz .fail_free_gpt
|
||||||
|
; Capacity - MyLBA = AlternateLBA
|
||||||
|
mov eax, dword[esi+DISK.MediaInfo.Capacity+0]
|
||||||
|
mov edx, dword[esi+DISK.MediaInfo.Capacity+4]
|
||||||
|
sub eax, dword[_mylba+0]
|
||||||
|
sbb edx, dword[_mylba+4]
|
||||||
|
cmp eax, dword[ebx+GPTH.AlternateLBA+0]
|
||||||
|
; DISK.MediaInfo.Capacity is -1 for ATA devices, disable this check for now.
|
||||||
|
; jnz .fail_free_gpt
|
||||||
|
cmp edx, dword[ebx+GPTH.AlternateLBA+4]
|
||||||
|
; jnz .fail_free_gpt
|
||||||
|
|
||||||
|
; Compute GPT Partition Entry Array (GPEA) length in bytes
|
||||||
|
mov eax, [ebx+GPTH.NumberOfPartitionEntries]
|
||||||
|
mul [ebx+GPTH.SizeOfPartitionEntry]
|
||||||
|
test edx, edx ; far too big
|
||||||
|
jnz .fail_free_gpt
|
||||||
|
; Round up to sector boundary
|
||||||
|
mov ecx, [esi+DISK.MediaInfo.SectorSize] ; power of two
|
||||||
|
dec ecx
|
||||||
|
add eax, ecx
|
||||||
|
jc .fail_free_gpt ; too big
|
||||||
|
not ecx
|
||||||
|
and eax, ecx
|
||||||
|
; We will need this length to compute CRC32 of GPEA
|
||||||
|
mov [GPEA_len], eax
|
||||||
|
; Allocate memory for GPEA
|
||||||
|
stdcall kernel_alloc, eax
|
||||||
|
test eax, eax
|
||||||
|
jz .fail_free_gpt
|
||||||
|
; Save to not juggle with registers
|
||||||
|
push eax
|
||||||
|
mov edi, eax
|
||||||
|
mov eax, [GPEA_len]
|
||||||
|
xor edx, edx
|
||||||
|
; Get the number of sectors GPEA fits into
|
||||||
|
div [esi+DISK.MediaInfo.SectorSize]
|
||||||
|
push eax ; esp = pointer to the number of sectors
|
||||||
|
mov al, DISKFUNC.read
|
||||||
|
stdcall disk_call_driver, edi, dword[ebx+GPTH.PartitionEntryLBA+0], \
|
||||||
|
dword[ebx+GPTH.PartitionEntryLBA+4], esp
|
||||||
|
pop ecx
|
||||||
|
test eax, eax
|
||||||
|
jnz .fail_free_gpea_gpt
|
||||||
|
; Compute and check CRC32 of GPEA
|
||||||
|
mov edx, [ebx+GPTH.PartitionEntryArrayCRC32]
|
||||||
|
mov eax, -1
|
||||||
|
stdcall crc_32, 0xEDB88320, edi, [GPEA_len]
|
||||||
|
xor eax, -1
|
||||||
|
cmp eax, edx
|
||||||
|
jnz .fail_free_gpea_gpt
|
||||||
|
|
||||||
|
; Process partitions, skip zeroed ones.
|
||||||
|
.next_gpe:
|
||||||
|
xor eax, eax
|
||||||
|
mov ecx, [ebx+GPTH.SizeOfPartitionEntry]
|
||||||
|
repz scasb
|
||||||
|
jz .skip
|
||||||
|
add edi, ecx
|
||||||
|
sub edi, [ebx+GPTH.SizeOfPartitionEntry]
|
||||||
|
; Length of a partition in sectors is EndingLBA - StartingLBA + 1
|
||||||
|
mov eax, dword[edi+GPE.EndingLBA+0]
|
||||||
|
mov edx, dword[edi+GPE.EndingLBA+4]
|
||||||
|
sub eax, dword[edi+GPE.StartingLBA+0]
|
||||||
|
sbb edx, dword[edi+GPE.StartingLBA+4]
|
||||||
|
add eax, 1
|
||||||
|
adc edx, 0
|
||||||
|
stdcall disk_add_partition, dword[edi+GPE.StartingLBA+0], \
|
||||||
|
dword[edi+GPE.StartingLBA+4], eax, edx, esi
|
||||||
|
add edi, [ebx+GPTH.SizeOfPartitionEntry]
|
||||||
|
.skip:
|
||||||
|
dec [ebx+GPTH.NumberOfPartitionEntries]
|
||||||
|
jnz .next_gpe
|
||||||
|
|
||||||
|
; Pointers to GPT header and GPEA are on the stack
|
||||||
|
stdcall kernel_free
|
||||||
|
stdcall kernel_free
|
||||||
|
pop edi ebx
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
.fail_free_gpea_gpt:
|
||||||
|
stdcall kernel_free
|
||||||
|
.fail_free_gpt:
|
||||||
|
stdcall kernel_free
|
||||||
|
.fail:
|
||||||
|
pop edi ebx
|
||||||
|
xor eax, eax
|
||||||
|
inc eax
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
; ecx = pointer to partition records array (MBR + 446)
|
||||||
|
is_protective_mbr:
|
||||||
|
push ecx edi
|
||||||
|
xor eax, eax
|
||||||
|
cmp [ecx-6], eax
|
||||||
|
jnz .exit
|
||||||
|
cmp [ecx-2], eax
|
||||||
|
jnz .exit
|
||||||
|
; Partition record 0 has specific fields
|
||||||
|
cmp dword[ecx+0], 0x00020000
|
||||||
|
jnz .exit
|
||||||
|
cmp byte[ecx+4], 0xEE
|
||||||
|
jnz .exit
|
||||||
|
cmp dword[ecx+8], 1
|
||||||
|
jnz .exit
|
||||||
|
; DISK.MediaInfo.Capacity is -1 for ATA devices, disable this check for now.
|
||||||
|
; cmp dword[esi+DISK.MediaInfo.Capacity+4], eax
|
||||||
|
; mov edi, 0xFFFFFFFF
|
||||||
|
; jnz @f
|
||||||
|
; mov edi, dword[esi+DISK.MediaInfo.Capacity+0]
|
||||||
|
; dec edi
|
||||||
|
;@@:
|
||||||
|
; cmp dword[ecx+12], edi
|
||||||
|
; jnz .exit
|
||||||
|
|
||||||
|
; Check that partition records 1-3 are filled with zero
|
||||||
|
lea edi, [ecx+16]
|
||||||
|
mov ecx, 16*3/2 ; 3 partitions
|
||||||
|
repz scasw
|
||||||
|
.exit:
|
||||||
|
pop edi ecx
|
||||||
|
; Return value is ZF
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; This is an internal function called from disk_scan_partitions. It checks
|
; This is an internal function called from disk_scan_partitions. It checks
|
||||||
|
40
kernel/trunk/crc.inc
Normal file
40
kernel/trunk/crc.inc
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; ;;
|
||||||
|
;; Copyright (C) KolibriOS team 2004-2017. All rights reserved. ;;
|
||||||
|
;; Distributed under terms of the GNU General Public License. ;;
|
||||||
|
;; ;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
; This crc32 routine doesn't use precomputed table to allow different
|
||||||
|
; polynomials, which is the first param.
|
||||||
|
; Partial hash in assumed to be eax (both in and out).
|
||||||
|
; Usage:
|
||||||
|
; 1. mov eax, -1
|
||||||
|
; 2. stdcall crypto.crc32 zero or more times
|
||||||
|
; 3. xor eax, -1
|
||||||
|
proc crc_32 _poly, _buffer, _length
|
||||||
|
push ebx ecx edx esi
|
||||||
|
|
||||||
|
mov esi, [_buffer]
|
||||||
|
.next_byte:
|
||||||
|
dec [_length]
|
||||||
|
js .done
|
||||||
|
movzx ebx, byte[esi]
|
||||||
|
inc esi
|
||||||
|
mov ecx, 8
|
||||||
|
.next_bit:
|
||||||
|
mov edx, eax
|
||||||
|
xor edx, ebx
|
||||||
|
shr eax, 1
|
||||||
|
test edx, 1
|
||||||
|
jz @f
|
||||||
|
xor eax, [_poly]
|
||||||
|
@@:
|
||||||
|
shr ebx, 1
|
||||||
|
dec ecx
|
||||||
|
jnz .next_bit
|
||||||
|
jmp .next_byte
|
||||||
|
.done:
|
||||||
|
pop esi edx ecx ebx
|
||||||
|
ret
|
||||||
|
endp
|
@ -65,6 +65,8 @@ include "fs/fs_lfn.inc" ; sysfunction 70
|
|||||||
|
|
||||||
include "network/stack.inc"
|
include "network/stack.inc"
|
||||||
|
|
||||||
|
include "crc.inc" ; checksums
|
||||||
|
|
||||||
; include "imports.inc"
|
; include "imports.inc"
|
||||||
; include "core/ext_lib.inc"
|
; include "core/ext_lib.inc"
|
||||||
; include "core/conf_lib.inc"
|
; include "core/conf_lib.inc"
|
||||||
|
Loading…
Reference in New Issue
Block a user