Subversion Repositories Kolibri OS

Rev

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

Rev 5363 Rev 8037
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
2
;;                                                              ;;
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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
7
 
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
14
; * memory blocks should not cross page boundary
15
; Hardware layer allocates fixed-size blocks.
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
-
 
63
.return:
-
 
64
; 3. Release the lock taken in step 1 and return.
16
; Thus, hardware layer uses the system slab allocator.
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
-
 
125
        ret     4
-
 
126
endp
-
 
127
 
17
 
128
; Helper procedure: translate physical address in ecx
18
; Helper procedure: translate physical address in ecx
129
; of some transfer descriptor to linear address.
19
; of some transfer descriptor to linear address.
130
; in: eax = address of first page
20
; in: eax = address of first page
131
proc usb_td_to_virt
21
proc usb_td_to_virt
132
; Traverse all pages used for transfer descriptors, looking for the one
22
; Traverse all pages used for transfer descriptors, looking for the one
133
; with physical address as in ecx.
23
; with physical address as in ecx.
134
@@:
24
@@:
135
        test    eax, eax
25
        test    eax, eax
136
        jz      .zero
26
        jz      .zero
137
        push    eax
27
        push    eax
138
        call    get_pg_addr
28
        call    get_pg_addr
139
        sub     eax, ecx
29
        sub     eax, ecx
140
        jz      .found
30
        jz      .found
141
        cmp     eax, -0x1000
31
        cmp     eax, -0x1000
142
        ja      .found
32
        ja      .found
143
        pop     eax
33
        pop     eax
144
        mov     eax, [eax+0x1000-4]
34
        mov     eax, [eax+0x1000-4]
145
        jmp     @b
35
        jmp     @b
146
.found:
36
.found:
147
; When found, combine page address from eax with page offset from ecx.
37
; When found, combine page address from eax with page offset from ecx.
148
        pop     eax
38
        pop     eax
149
        and     ecx, 0xFFF
39
        and     ecx, 0xFFF
150
        add     eax, ecx
40
        add     eax, ecx
151
.zero:
41
.zero:
152
        ret
42
        ret
153
endp
43
endp