7,13 → 7,12 |
|
$Revision$ |
|
; Memory management for USB structures. |
; Protocol layer uses the common kernel heap malloc/free. |
; Hardware layer has special requirements: |
; * memory blocks should be properly aligned |
; * memory blocks should not cross page boundary |
; Hardware layer allocates fixed-size blocks. |
; Thus, the specific allocator is quite easy to write: |
; Memory management for slab structures. |
; The allocator meets special requirements: |
; * memory blocks are properly aligned |
; * memory blocks do not cross page boundary |
; The allocator manages fixed-size blocks. |
; Thus, the specific allocator works as follows: |
; allocate one page, split into blocks, maintain the single-linked |
; list of all free blocks in each page. |
|
23,7 → 22,7 |
|
; Allocator for fixed-size blocks: allocate a block. |
; [ebx-4] = pointer to the first page, ebx = pointer to MUTEX structure. |
proc usb_allocate_common |
proc slab_alloc |
push edi ; save used register to be stdcall |
virtual at esp |
dd ? ; saved edi |
55,9 → 54,9 |
; 2f. Update the pointer to the first free block from eax to ecx. |
; Normally [edx-8] still contains eax, if so, atomically set it to ecx |
; and proceed to 3. |
; However, the price of simplicity of usb_free_common (in particular, it |
; doesn't take the lock) is that [edx-8] could (rarely) be changed while |
; we processed steps 2d+2e. If so, return to 2d and retry. |
; However, the price of simplicity of slab_free (in particular, it doesn't take |
; the lock) is that [edx-8] could (rarely) be changed while we processed steps |
; 2d+2e. If so, return to 2d and retry. |
lock cmpxchg [edx-8], ecx |
jnz @b |
.return: |
99,13 → 98,13 |
; 8. Return (start of page). |
jmp .return |
.nomemory: |
dbgstr 'no memory for USB descriptor' |
dbgstr 'no memory for slab allocation' |
xor eax, eax |
jmp .return |
endp |
|
; Allocator for fixed-size blocks: free a block. |
proc usb_free_common |
proc slab_free |
push ecx edx |
virtual at esp |
rd 2 ; saved registers |
124,30 → 123,3 |
pop edx ecx |
ret 4 |
endp |
|
; Helper procedure: translate physical address in ecx |
; of some transfer descriptor to linear address. |
; in: eax = address of first page |
proc usb_td_to_virt |
; Traverse all pages used for transfer descriptors, looking for the one |
; with physical address as in ecx. |
@@: |
test eax, eax |
jz .zero |
push eax |
call get_pg_addr |
sub eax, ecx |
jz .found |
cmp eax, -0x1000 |
ja .found |
pop eax |
mov eax, [eax+0x1000-4] |
jmp @b |
.found: |
; When found, combine page address from eax with page offset from ecx. |
pop eax |
and ecx, 0xFFF |
add eax, ecx |
.zero: |
ret |
endp |