Rev 5201 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
431 | serge | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
527 | diamond | 2 | ;; ;; |
5565 | serge | 3 | ;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;; |
431 | serge | 4 | ;; Distributed under terms of the GNU General Public License ;; |
5 | ;; ;; |
||
527 | diamond | 6 | ;; RAMDISK functions ;; |
431 | serge | 7 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
1 | ha | 8 | |
593 | mikedld | 9 | $Revision: 5565 $ |
10 | |||
4287 | Serge | 11 | iglobal |
12 | align 4 |
||
13 | ramdisk_functions: |
||
14 | dd .size |
||
15 | dd 0 ; no close() function |
||
16 | dd 0 ; no closemedia() function |
||
17 | dd ramdisk_querymedia |
||
18 | dd ramdisk_read |
||
19 | dd ramdisk_write |
||
20 | dd 0 ; no flush() function |
||
21 | dd ramdisk_adjust_cache_size |
||
22 | .size = $ - ramdisk_functions |
||
23 | endg |
||
593 | mikedld | 24 | |
4287 | Serge | 25 | iglobal |
26 | align 4 |
||
27 | ramdisk_actual_size dd RAMDISK_CAPACITY |
||
171 | diamond | 28 | endg |
29 | |||
4287 | Serge | 30 | ; This function is called early in boot process. |
31 | ; It creates filesystem /rd/1 based on raw image data loaded by somebody before |
||
32 | ; to memory named as RAMDISK with max size RAMDISK_CAPACITY, may be less. |
||
33 | proc ramdisk_init |
||
83 | diamond | 34 | iglobal |
4287 | Serge | 35 | ramdisk_name db 'rd',0 |
83 | diamond | 36 | endg |
4287 | Serge | 37 | push ebx esi ; save used registers to be stdcall |
38 | ; 1. Register the device and the (always inserted) media in the disk subsystem. |
||
39 | stdcall disk_add, ramdisk_functions, ramdisk_name, 0, 0 |
||
40 | test eax, eax |
||
41 | jz .fail |
||
42 | mov ebx, eax |
||
43 | stdcall disk_media_changed, eax, 1 |
||
44 | ; 2. We don't know actual size of loaded image, |
||
45 | ; so try to calculate it using partition structure, |
||
46 | ; assuming that file systems fill the real size based on contents of the partition. |
||
47 | ; 2a. Prepare for loop over partitions. |
||
3555 | Serge | 48 | xor ecx, ecx |
4287 | Serge | 49 | xor edx, edx |
50 | ; 2b. Check that at least one partition was recognized. |
||
51 | cmp [ebx+DISK.NumPartitions], ecx |
||
52 | jz .fail |
||
53 | ; 2c. Loop over partitions. |
||
54 | .partitions: |
||
55 | ; For every partition, set edx to maximum between edx and end of partition. |
||
56 | mov esi, [ebx+DISK.Partitions] |
||
57 | mov esi, [esi+ecx*4] |
||
58 | mov eax, dword [esi+PARTITION.FirstSector] |
||
59 | add eax, dword [esi+PARTITION.Length] |
||
60 | cmp eax, edx |
||
61 | jb @f |
||
62 | mov edx, eax |
||
83 | diamond | 63 | @@: |
3555 | Serge | 64 | inc ecx |
4287 | Serge | 65 | cmp ecx, [ebx+DISK.NumPartitions] |
66 | jb .partitions |
||
67 | ; 3. Reclaim unused memory, if any. |
||
68 | mov [ramdisk_actual_size], edx |
||
69 | add edx, 7 ; aligning up |
||
70 | shr edx, 3 ; 512-byte sectors -> 4096-byte pages |
||
71 | mov esi, RAMDISK_CAPACITY / 8 ; aligning down |
||
72 | sub esi, edx |
||
73 | jbe .no_reclaim |
||
74 | shl edx, 12 |
||
75 | add edx, RAMDISK - OS_BASE |
||
83 | diamond | 76 | @@: |
4287 | Serge | 77 | mov eax, edx |
78 | call free_page |
||
79 | add edx, 0x1000 |
||
80 | dec esi |
||
3555 | Serge | 81 | jnz @b |
4287 | Serge | 82 | .no_reclaim: |
83 | pop esi ebx ; restore used registers to be stdcall |
||
3555 | Serge | 84 | ret |
4287 | Serge | 85 | .fail: |
86 | dbgstr 'Failed to initialize ramdisk' |
||
87 | pop esi ebx ; restore used registers to be stdcall |
||
3555 | Serge | 88 | ret |
4287 | Serge | 89 | endp |
83 | diamond | 90 | |
4287 | Serge | 91 | ; Returns information about disk media. |
92 | proc ramdisk_querymedia |
||
93 | virtual at esp+4 |
||
94 | .userdata dd ? |
||
95 | .info dd ? |
||
96 | end virtual |
||
97 | ; Media is always present, sector size is always 512 bytes. |
||
98 | mov edx, [.userdata] |
||
99 | mov ecx, [.info] |
||
100 | mov [ecx+DISKMEDIAINFO.Flags], 0 |
||
101 | mov [ecx+DISKMEDIAINFO.SectorSize], 512 |
||
102 | mov eax, [ramdisk_actual_size] |
||
103 | mov dword [ecx+DISKMEDIAINFO.Capacity], eax |
||
104 | mov dword [ecx+DISKMEDIAINFO.Capacity+4], 0 |
||
105 | ; Return zero as an indicator of success. |
||
3555 | Serge | 106 | xor eax, eax |
4287 | Serge | 107 | retn 8 |
108 | endp |
||
83 | diamond | 109 | |
4287 | Serge | 110 | ; Common procedure for reading and writing. |
111 | ; operation = 0 for reading, operation = 1 for writing. |
||
112 | ; Arguments of ramdisk_read and ramdisk_write are the same. |
||
113 | macro ramdisk_read_write operation |
||
114 | { |
||
115 | push esi edi ; save used registers to be stdcall |
||
116 | mov esi, [userdata] |
||
117 | mov edi, [numsectors_ptr] |
||
118 | ; 1. Determine number of sectors to be transferred. |
||
119 | ; This is either the requested number of sectors or number of sectors |
||
120 | ; up to the disk boundary, depending of what is less. |
||
3555 | Serge | 121 | xor ecx, ecx |
4287 | Serge | 122 | ; 1a. Test whether [start_sector] is less than RAMDISK_CAPACITY. |
123 | ; If so, calculate number of sectors between [start_sector] and RAMDISK_CAPACITY. |
||
124 | ; Otherwise, the actual number of sectors is zero. |
||
125 | cmp dword [start_sector+4], ecx |
||
126 | jnz .got_number |
||
127 | mov eax, [ramdisk_actual_size] |
||
128 | sub eax, dword [start_sector] |
||
129 | jbe .got_number |
||
130 | ; 1b. Get the requested number of sectors. |
||
131 | mov ecx, [edi] |
||
132 | ; 1c. If it is greater than number of sectors calculated in 1a, use the value |
||
133 | ; from 1a. |
||
3555 | Serge | 134 | cmp ecx, eax |
4287 | Serge | 135 | jb .got_number |
136 | mov ecx, eax |
||
137 | .got_number: |
||
138 | ; 2. Compare the actual number of sectors with requested. If they are |
||
139 | ; equal, set eax (it will be the returned value) to zero. Otherwise, |
||
140 | ; use DISK_STATUS_END_OF_MEDIA. |
||
3555 | Serge | 141 | xor eax, eax |
4287 | Serge | 142 | cmp ecx, [edi] |
3555 | Serge | 143 | jz @f |
4287 | Serge | 144 | mov al, DISK_STATUS_END_OF_MEDIA |
3555 | Serge | 145 | @@: |
4287 | Serge | 146 | ; 3. Store the actual number of sectors. |
147 | mov [edi], ecx |
||
148 | ; 4. Calculate source and destination addresses. |
||
149 | if operation = 0 ; reading? |
||
150 | mov esi, dword [start_sector] |
||
151 | shl esi, 9 |
||
152 | add esi, RAMDISK |
||
153 | mov edi, [buffer] |
||
154 | else ; writing? |
||
155 | mov edi, dword [start_sector] |
||
3555 | Serge | 156 | shl edi, 9 |
4287 | Serge | 157 | add edi, RAMDISK |
158 | mov esi, [buffer] |
||
159 | end if |
||
160 | ; 5. Calculate number of dwords to be transferred. |
||
161 | shl ecx, 9-2 |
||
162 | ; 6. Copy data. |
||
3555 | Serge | 163 | rep movsd |
4287 | Serge | 164 | ; 7. Return. The value in eax was calculated in step 2. |
165 | pop edi esi ; restore used registers to be stdcall |
||
166 | } |
||
83 | diamond | 167 | |
4287 | Serge | 168 | ; Reads one or more sectors from the device. |
169 | proc ramdisk_read userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword |
||
170 | ramdisk_read_write 0 |
||
3555 | Serge | 171 | ret |
4287 | Serge | 172 | endp |
83 | diamond | 173 | |
4287 | Serge | 174 | ; Writes one or more sectors to the device. |
175 | proc ramdisk_write userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword |
||
176 | ramdisk_read_write 1 |
||
3555 | Serge | 177 | ret |
4287 | Serge | 178 | endp |
83 | diamond | 179 | |
4287 | Serge | 180 | ; The kernel calls this function when initializing cache subsystem for |
181 | ; the media. This call allows the driver to adjust the cache size. |
||
182 | proc ramdisk_adjust_cache_size |
||
183 | virtual at esp+4 |
||
184 | .userdata dd ? |
||
185 | .suggested_size dd ? |
||
186 | end virtual |
||
187 | ; Since ramdisk does not need cache, just return 0. |
||
3555 | Serge | 188 | xor eax, eax |
4287 | Serge | 189 | retn 8 |
190 | endp |