Subversion Repositories Kolibri OS

Rev

Rev 3725 | Rev 5201 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3725 Rev 4423
1
; Memory management for USB structures.
1
; Memory management for USB structures.
2
; Protocol layer uses the common kernel heap malloc/free.
2
; Protocol layer uses the common kernel heap malloc/free.
3
; Hardware layer has special requirements:
3
; Hardware layer has special requirements:
4
; * memory blocks should be properly aligned
4
; * memory blocks should be properly aligned
5
; * memory blocks should not cross page boundary
5
; * memory blocks should not cross page boundary
6
; Hardware layer allocates fixed-size blocks.
6
; Hardware layer allocates fixed-size blocks.
7
; Thus, the specific allocator is quite easy to write:
7
; Thus, the specific allocator is quite easy to write:
8
; allocate one page, split into blocks, maintain the single-linked
8
; allocate one page, split into blocks, maintain the single-linked
9
; list of all free blocks in each page.
9
; list of all free blocks in each page.
10
 
10
 
11
; Note: size must be a multiple of required alignment.
11
; Note: size must be a multiple of required alignment.
12
 
12
 
13
; Data for one pool: dd pointer to the first page, MUTEX lock.
13
; Data for one pool: dd pointer to the first page, MUTEX lock.
14
 
-
 
15
uglobal
-
 
16
; Structures in UHCI and OHCI have equal sizes.
-
 
17
; Thus, functions and data for allocating/freeing can be shared;
-
 
18
; we keep them here rather than in controller-specific files.
-
 
19
align 4
-
 
20
; Data for UHCI and OHCI endpoints pool.
-
 
21
usb1_ep_first_page      dd      ?
-
 
22
usb1_ep_mutex           MUTEX
-
 
23
; Data for UHCI and OHCI general transfer descriptors pool.
-
 
24
usb_gtd_first_page      dd      ?
-
 
25
usb_gtd_mutex           MUTEX
-
 
26
endg
-
 
27
 
-
 
28
; sanity check: structures in UHCI and OHCI should be the same for allocation
-
 
29
if (sizeof.ohci_pipe = sizeof.uhci_pipe)
-
 
30
 
-
 
31
; Allocates one endpoint structure for UHCI/OHCI.
-
 
32
; Returns pointer to software part (usb_pipe) in eax.
-
 
33
proc usb1_allocate_endpoint
-
 
34
        push    ebx
-
 
35
        mov     ebx, usb1_ep_mutex
-
 
36
        stdcall usb_allocate_common, (sizeof.ohci_pipe + sizeof.usb_pipe + 0Fh) and not 0Fh
-
 
37
        test    eax, eax
-
 
38
        jz      @f
-
 
39
        add     eax, sizeof.ohci_pipe
-
 
40
@@:
-
 
41
        pop     ebx
-
 
42
        ret
-
 
43
endp
-
 
44
 
-
 
45
; Free one endpoint structure for UHCI/OHCI.
-
 
46
; Stdcall with one argument, pointer to software part (usb_pipe).
-
 
47
proc usb1_free_endpoint
-
 
48
        sub     dword [esp+4], sizeof.ohci_pipe
-
 
49
        jmp     usb_free_common
-
 
50
endp
-
 
51
 
-
 
52
else
-
 
53
; sanity check continued
-
 
54
.err allocate_endpoint/free_endpoint must be different for OHCI and UHCI
-
 
55
end if
-
 
56
 
-
 
57
; sanity check: structures in UHCI and OHCI should be the same for allocation
-
 
58
if (sizeof.ohci_gtd = sizeof.uhci_gtd)
-
 
59
 
-
 
60
; Allocates one general transfer descriptor structure for UHCI/OHCI.
-
 
61
; Returns pointer to software part (usb_gtd) in eax.
-
 
62
proc usb1_allocate_general_td
-
 
63
        push    ebx
-
 
64
        mov     ebx, usb_gtd_mutex
-
 
65
        stdcall usb_allocate_common, (sizeof.ohci_gtd + sizeof.usb_gtd + 0Fh) and not 0Fh
-
 
66
        test    eax, eax
-
 
67
        jz      @f
-
 
68
        add     eax, sizeof.ohci_gtd
-
 
69
@@:
-
 
70
        pop     ebx
-
 
71
        ret
-
 
72
endp
-
 
73
 
-
 
74
; Free one general transfer descriptor structure for UHCI/OHCI.
-
 
75
; Stdcall with one argument, pointer to software part (usb_gtd).
-
 
76
proc usb1_free_general_td
-
 
77
        sub     dword [esp+4], sizeof.ohci_gtd
-
 
78
        jmp     usb_free_common
-
 
79
endp
-
 
80
 
-
 
81
else
-
 
82
; sanity check continued
-
 
83
.err allocate_general_td/free_general_td must be different for OHCI and UHCI
-
 
84
end if
-
 
85
 
14
 
86
; Allocator for fixed-size blocks: allocate a block.
15
; Allocator for fixed-size blocks: allocate a block.
87
; [ebx-4] = pointer to the first page, ebx = pointer to MUTEX structure.
16
; [ebx-4] = pointer to the first page, ebx = pointer to MUTEX structure.
88
proc usb_allocate_common
17
proc usb_allocate_common
89
        push    edi     ; save used register to be stdcall
18
        push    edi     ; save used register to be stdcall
90
virtual at esp
19
virtual at esp
91
        dd      ?       ; saved edi
20
        dd      ?       ; saved edi
92
        dd      ?       ; return address
21
        dd      ?       ; return address
93
.size   dd      ?
22
.size   dd      ?
94
end virtual
23
end virtual
95
; 1. Take the lock.
24
; 1. Take the lock.
96
        mov     ecx, ebx
25
        mov     ecx, ebx
97
        call    mutex_lock
26
        call    mutex_lock
98
; 2. Find the first allocated page with a free block, if any.
27
; 2. Find the first allocated page with a free block, if any.
99
; 2a. Initialize for the loop.
28
; 2a. Initialize for the loop.
100
        mov     edx, ebx
29
        mov     edx, ebx
101
.pageloop:
30
.pageloop:
102
; 2b. Get the next page, keeping the current in eax.
31
; 2b. Get the next page, keeping the current in eax.
103
        mov     eax, edx
32
        mov     eax, edx
104
        mov     edx, [edx-4]
33
        mov     edx, [edx-4]
105
; 2c. If there is no next page, we're out of luck; go to 4.
34
; 2c. If there is no next page, we're out of luck; go to 4.
106
        test    edx, edx
35
        test    edx, edx
107
        jz      .newpage
36
        jz      .newpage
108
        add     edx, 0x1000
37
        add     edx, 0x1000
109
@@:
38
@@:
110
; 2d. Get the pointer to the first free block on this page.
39
; 2d. Get the pointer to the first free block on this page.
111
; If there is no free block, continue to 2b.
40
; If there is no free block, continue to 2b.
112
        mov     eax, [edx-8]
41
        mov     eax, [edx-8]
113
        test    eax, eax
42
        test    eax, eax
114
        jz      .pageloop
43
        jz      .pageloop
115
; 2e. Get the pointer to the next free block.
44
; 2e. Get the pointer to the next free block.
116
        mov     ecx, [eax]
45
        mov     ecx, [eax]
117
; 2f. Update the pointer to the first free block from eax to ecx.
46
; 2f. Update the pointer to the first free block from eax to ecx.
118
; Normally [edx-8] still contains eax, if so, atomically set it to ecx
47
; Normally [edx-8] still contains eax, if so, atomically set it to ecx
119
; and proceed to 3.
48
; and proceed to 3.
120
; However, the price of simplicity of usb_free_common (in particular, it
49
; However, the price of simplicity of usb_free_common (in particular, it
121
; doesn't take the lock) is that [edx-8] could (rarely) be changed while
50
; doesn't take the lock) is that [edx-8] could (rarely) be changed while
122
; we processed steps 2d+2e. If so, return to 2d and retry.
51
; we processed steps 2d+2e. If so, return to 2d and retry.
123
        lock cmpxchg [edx-8], ecx
52
        lock cmpxchg [edx-8], ecx
124
        jnz     @b
53
        jnz     @b
125
.return:
54
.return:
126
; 3. Release the lock taken in step 1 and return.
55
; 3. Release the lock taken in step 1 and return.
127
        push    eax
56
        push    eax
128
        mov     ecx, ebx
57
        mov     ecx, ebx
129
        call    mutex_unlock
58
        call    mutex_unlock
130
        pop     eax
59
        pop     eax
131
        pop     edi     ; restore used register to be stdcall
60
        pop     edi     ; restore used register to be stdcall
132
        ret     4
61
        ret     4
133
.newpage:
62
.newpage:
134
; 4. Allocate a new page.
63
; 4. Allocate a new page.
135
        push    eax
64
        push    eax
136
        stdcall kernel_alloc, 0x1000
65
        stdcall kernel_alloc, 0x1000
137
        pop     edx
66
        pop     edx
138
; If failed, say something to the debug board and return zero.
67
; If failed, say something to the debug board and return zero.
139
        test    eax, eax
68
        test    eax, eax
140
        jz      .nomemory
69
        jz      .nomemory
141
; 5. Add the new page to the tail of list of allocated pages.
70
; 5. Add the new page to the tail of list of allocated pages.
142
        mov     [edx-4], eax
71
        mov     [edx-4], eax
143
; 6. Initialize two service dwords in the end of page:
72
; 6. Initialize two service dwords in the end of page:
144
; first free block is (start of page) + (block size)
73
; first free block is (start of page) + (block size)
145
; (we will return first block at (start of page), so consider it allocated),
74
; (we will return first block at (start of page), so consider it allocated),
146
; no next page.
75
; no next page.
147
        mov     edx, eax
76
        mov     edx, eax
148
        lea     edi, [eax+0x1000-8]
77
        lea     edi, [eax+0x1000-8]
149
        add     edx, [.size]
78
        add     edx, [.size]
150
        mov     [edi], edx
79
        mov     [edi], edx
151
        and     dword [edi+4], 0
80
        and     dword [edi+4], 0
152
; 7. All blocks starting from edx are free; join them in a single-linked list.
81
; 7. All blocks starting from edx are free; join them in a single-linked list.
153
@@:
82
@@:
154
        mov     ecx, edx
83
        mov     ecx, edx
155
        add     edx, [.size]
84
        add     edx, [.size]
156
        mov     [ecx], edx
85
        mov     [ecx], edx
157
        cmp     edx, edi
86
        cmp     edx, edi
158
        jbe     @b
87
        jbe     @b
159
        sub     ecx, [.size]
88
        sub     ecx, [.size]
160
        and     dword [ecx], 0
89
        and     dword [ecx], 0
161
; 8. Return (start of page).
90
; 8. Return (start of page).
162
        jmp     .return
91
        jmp     .return
163
.nomemory:
92
.nomemory:
164
        dbgstr 'no memory for USB descriptor'
93
        dbgstr 'no memory for USB descriptor'
165
        xor     eax, eax
94
        xor     eax, eax
166
        jmp     .return
95
        jmp     .return
167
endp
96
endp
168
 
97
 
169
; Allocator for fixed-size blocks: free a block.
98
; Allocator for fixed-size blocks: free a block.
170
proc usb_free_common
99
proc usb_free_common
171
        push    ecx edx
100
        push    ecx edx
172
virtual at esp
101
virtual at esp
173
        rd      2       ; saved registers
102
        rd      2       ; saved registers
174
        dd      ?       ; return address
103
        dd      ?       ; return address
175
.block  dd      ?
104
.block  dd      ?
176
end virtual
105
end virtual
177
; Insert the given block to the head of free blocks in this page.
106
; Insert the given block to the head of free blocks in this page.
178
        mov     ecx, [.block]
107
        mov     ecx, [.block]
179
        mov     edx, ecx
108
        mov     edx, ecx
180
        or      edx, 0xFFF
109
        or      edx, 0xFFF
181
@@:
110
@@:
182
        mov     eax, [edx+1-8]
111
        mov     eax, [edx+1-8]
183
        mov     [ecx], eax
112
        mov     [ecx], eax
184
        lock cmpxchg [edx+1-8], ecx
113
        lock cmpxchg [edx+1-8], ecx
185
        jnz     @b
114
        jnz     @b
186
        pop     edx ecx
115
        pop     edx ecx
187
        ret     4
116
        ret     4
188
endp
117
endp
189
 
118
 
190
; Helper procedure for OHCI: translate physical address in ecx
119
; Helper procedure: translate physical address in ecx
-
 
120
; of some transfer descriptor to linear address.
191
; of some transfer descriptor to linear address.
121
; in: eax = address of first page
192
proc usb_td_to_virt
122
proc usb_td_to_virt
193
; Traverse all pages used for transfer descriptors, looking for the one
123
; Traverse all pages used for transfer descriptors, looking for the one
194
; with physical address as in ecx.
124
; with physical address as in ecx.
195
        mov     eax, [usb_gtd_first_page]
-
 
196
@@:
125
@@:
197
        test    eax, eax
126
        test    eax, eax
198
        jz      .zero
127
        jz      .zero
199
        push    eax
128
        push    eax
200
        call    get_pg_addr
129
        call    get_pg_addr
201
        sub     eax, ecx
130
        sub     eax, ecx
202
        jz      .found
131
        jz      .found
203
        cmp     eax, -0x1000
132
        cmp     eax, -0x1000
204
        ja      .found
133
        ja      .found
205
        pop     eax
134
        pop     eax
206
        mov     eax, [eax+0x1000-4]
135
        mov     eax, [eax+0x1000-4]
207
        jmp     @b
136
        jmp     @b
208
.found:
137
.found:
209
; When found, combine page address from eax with page offset from ecx.
138
; When found, combine page address from eax with page offset from ecx.
210
        pop     eax
139
        pop     eax
211
        and     ecx, 0xFFF
140
        and     ecx, 0xFFF
212
        add     eax, ecx
141
        add     eax, ecx
213
.zero:
142
.zero:
214
        ret
143
        ret
215
endp
144
endp