Subversion Repositories Kolibri OS

Rev

Rev 5363 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 5363 Rev 8037
Line 3... Line 3...
3
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
3
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
4
;; Distributed under terms of the GNU General Public License    ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Line 7... Line 7...
7
 
7
 
Line 8... Line 8...
8
$Revision: 5363 $
8
$Revision: 8037 $
9
 
9
 
10
; Memory management for USB structures.
10
; Memory management for USB structures.
11
; Protocol layer uses the common kernel heap malloc/free.
11
; Protocol layer uses the common kernel heap malloc/free.
12
; Hardware layer has special requirements:
12
; Hardware layer has special requirements:
13
; * memory blocks should be properly aligned
13
; * memory blocks should be properly aligned
14
; * memory blocks should not cross page boundary
-
 
15
; Hardware layer allocates fixed-size blocks.
-
 
16
; Thus, the specific allocator is quite easy to write:
-
 
17
; allocate one page, split into blocks, maintain the single-linked
-
 
18
; list of all free blocks in each page.
-
 
19
 
-
 
20
; Note: size must be a multiple of required alignment.
-
 
21
 
-
 
22
; Data for one pool: dd pointer to the first page, MUTEX lock.
-
 
23
 
-
 
24
; Allocator for fixed-size blocks: allocate a block.
-
 
25
; [ebx-4] = pointer to the first page, ebx = pointer to MUTEX structure.
-
 
26
proc usb_allocate_common
-
 
27
        push    edi     ; save used register to be stdcall
-
 
28
virtual at esp
-
 
29
        dd      ?       ; saved edi
-
 
30
        dd      ?       ; return address
-
 
31
.size   dd      ?
-
 
32
end virtual
-
 
33
; 1. Take the lock.
-
 
34
        mov     ecx, ebx
-
 
35
        call    mutex_lock
-
 
36
; 2. Find the first allocated page with a free block, if any.
-
 
37
; 2a. Initialize for the loop.
-
 
38
        mov     edx, ebx
-
 
39
.pageloop:
-
 
40
; 2b. Get the next page, keeping the current in eax.
-
 
41
        mov     eax, edx
-
 
42
        mov     edx, [edx-4]
-
 
43
; 2c. If there is no next page, we're out of luck; go to 4.
-
 
44
        test    edx, edx
-
 
45
        jz      .newpage
-
 
46
        add     edx, 0x1000
-
 
47
@@:
-
 
48
; 2d. Get the pointer to the first free block on this page.
-
 
49
; If there is no free block, continue to 2b.
-
 
50
        mov     eax, [edx-8]
-
 
51
        test    eax, eax
-
 
52
        jz      .pageloop
-
 
53
; 2e. Get the pointer to the next free block.
-
 
54
        mov     ecx, [eax]
-
 
55
; 2f. Update the pointer to the first free block from eax to ecx.
-
 
56
; Normally [edx-8] still contains eax, if so, atomically set it to ecx
-
 
57
; and proceed to 3.
-
 
58
; However, the price of simplicity of usb_free_common (in particular, it
-
 
59
; doesn't take the lock) is that [edx-8] could (rarely) be changed while
-
 
60
; we processed steps 2d+2e. If so, return to 2d and retry.
-
 
61
        lock cmpxchg [edx-8], ecx
-
 
62
        jnz     @b
14
; * memory blocks should not cross page boundary
63
.return:
-
 
64
; 3. Release the lock taken in step 1 and return.
-
 
65
        push    eax
-
 
66
        mov     ecx, ebx
-
 
67
        call    mutex_unlock
-
 
68
        pop     eax
-
 
69
        pop     edi     ; restore used register to be stdcall
-
 
70
        ret     4
-
 
71
.newpage:
-
 
72
; 4. Allocate a new page.
-
 
73
        push    eax
-
 
74
        stdcall kernel_alloc, 0x1000
-
 
75
        pop     edx
-
 
76
; If failed, say something to the debug board and return zero.
-
 
77
        test    eax, eax
-
 
78
        jz      .nomemory
-
 
79
; 5. Add the new page to the tail of list of allocated pages.
-
 
80
        mov     [edx-4], eax
-
 
81
; 6. Initialize two service dwords in the end of page:
-
 
82
; first free block is (start of page) + (block size)
-
 
83
; (we will return first block at (start of page), so consider it allocated),
-
 
84
; no next page.
-
 
85
        mov     edx, eax
-
 
86
        lea     edi, [eax+0x1000-8]
-
 
87
        add     edx, [.size]
-
 
88
        mov     [edi], edx
-
 
89
        and     dword [edi+4], 0
-
 
90
; 7. All blocks starting from edx are free; join them in a single-linked list.
-
 
91
@@:
-
 
92
        mov     ecx, edx
-
 
93
        add     edx, [.size]
-
 
94
        mov     [ecx], edx
-
 
95
        cmp     edx, edi
-
 
96
        jbe     @b
-
 
97
        sub     ecx, [.size]
-
 
98
        and     dword [ecx], 0
-
 
99
; 8. Return (start of page).
-
 
100
        jmp     .return
-
 
101
.nomemory:
-
 
102
        dbgstr 'no memory for USB descriptor'
-
 
103
        xor     eax, eax
-
 
104
        jmp     .return
-
 
105
endp
-
 
106
 
-
 
107
; Allocator for fixed-size blocks: free a block.
-
 
108
proc usb_free_common
-
 
109
        push    ecx edx
-
 
110
virtual at esp
-
 
111
        rd      2       ; saved registers
-
 
112
        dd      ?       ; return address
-
 
113
.block  dd      ?
-
 
114
end virtual
-
 
115
; Insert the given block to the head of free blocks in this page.
-
 
116
        mov     ecx, [.block]
-
 
117
        mov     edx, ecx
-
 
118
        or      edx, 0xFFF
-
 
119
@@:
-
 
120
        mov     eax, [edx+1-8]
-
 
121
        mov     [ecx], eax
-
 
122
        lock cmpxchg [edx+1-8], ecx
-
 
123
        jnz     @b
-
 
124
        pop     edx ecx
-
 
Line 125... Line 15...
125
        ret     4
15
; Hardware layer allocates fixed-size blocks.
126
endp
16
; Thus, hardware layer uses the system slab allocator.
127
 
17
 
128
; Helper procedure: translate physical address in ecx
18
; Helper procedure: translate physical address in ecx