Subversion Repositories Kolibri OS

Rev

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

Rev 3460 Rev 3598
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
2
;;                                                              ;;
3
;; Copyright (C) KolibriOS team 2011-2012. All rights reserved. ;;
3
;; Copyright (C) KolibriOS team 2011-2012. 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: 3460 $
8
$Revision: 3598 $
9
 
9
 
10
; =============================================================================
10
; =============================================================================
11
; ================================= Constants =================================
11
; ================================= Constants =================================
12
; =============================================================================
12
; =============================================================================
13
; Error codes for callback functions.
13
; Error codes for callback functions.
14
DISK_STATUS_OK              = 0 ; success
14
DISK_STATUS_OK              = 0 ; success
15
DISK_STATUS_GENERAL_ERROR   = -1; if no other code is suitable
15
DISK_STATUS_GENERAL_ERROR   = -1; if no other code is suitable
16
DISK_STATUS_INVALID_CALL    = 1 ; invalid input parameters
16
DISK_STATUS_INVALID_CALL    = 1 ; invalid input parameters
17
DISK_STATUS_NO_MEDIA        = 2 ; no media present
17
DISK_STATUS_NO_MEDIA        = 2 ; no media present
18
DISK_STATUS_END_OF_MEDIA    = 3 ; end of media while reading/writing data
18
DISK_STATUS_END_OF_MEDIA    = 3 ; end of media while reading/writing data
19
; Driver flags. Represent bits in DISK.DriverFlags.
19
; Driver flags. Represent bits in DISK.DriverFlags.
20
DISK_NO_INSERT_NOTIFICATION = 1
20
DISK_NO_INSERT_NOTIFICATION = 1
21
; Media flags. Represent bits in DISKMEDIAINFO.Flags.
21
; Media flags. Represent bits in DISKMEDIAINFO.Flags.
22
DISK_MEDIA_READONLY = 1
22
DISK_MEDIA_READONLY = 1
23
 
23
 
24
; If too many partitions are detected,there is probably an error on the disk.
24
; If too many partitions are detected,there is probably an error on the disk.
25
; 256 partitions should be enough for any reasonable use.
25
; 256 partitions should be enough for any reasonable use.
26
; Also, the same number is limiting the number of MBRs to process; if
26
; Also, the same number is limiting the number of MBRs to process; if
27
; too many MBRs are visible,there probably is a loop in the MBR structure.
27
; too many MBRs are visible,there probably is a loop in the MBR structure.
28
MAX_NUM_PARTITIONS = 256
28
MAX_NUM_PARTITIONS = 256
29
 
29
 
30
; =============================================================================
30
; =============================================================================
31
; ================================ Structures =================================
31
; ================================ Structures =================================
32
; =============================================================================
32
; =============================================================================
33
; This structure defines all callback functions for working with the physical
33
; This structure defines all callback functions for working with the physical
34
; device. They are implemented by a driver. Objects with this structure reside
34
; device. They are implemented by a driver. Objects with this structure reside
35
; in a driver.
35
; in a driver.
36
struct  DISKFUNC
36
struct  DISKFUNC
37
        strucsize       dd ?
37
        strucsize       dd ?
38
; Size of the structure. This field is intended for possible extensions of
38
; Size of the structure. This field is intended for possible extensions of
39
; this structure. If a new function is added to this structure and a driver
39
; this structure. If a new function is added to this structure and a driver
40
; implements an old version, the caller can detect this by checking .strucsize,
40
; implements an old version, the caller can detect this by checking .strucsize,
41
; so the driver remains compatible.
41
; so the driver remains compatible.
42
        close           dd ?
42
        close           dd ?
43
; The pointer to the function which frees all driver-specific resources for
43
; The pointer to the function which frees all driver-specific resources for
44
; the disk.
44
; the disk.
45
; Optional, may be NULL.
45
; Optional, may be NULL.
46
; void close(void* userdata);
46
; void close(void* userdata);
47
        closemedia      dd ?
47
        closemedia      dd ?
48
; The pointer to the function which informs the driver that the kernel has
48
; The pointer to the function which informs the driver that the kernel has
49
; finished all processing with the current media. If media is removed, the
49
; finished all processing with the current media. If media is removed, the
50
; driver should decline all requests to that media with DISK_STATUS_NO_MEDIA,
50
; driver should decline all requests to that media with DISK_STATUS_NO_MEDIA,
51
; even if new media is inserted, until this function is called. If media is
51
; even if new media is inserted, until this function is called. If media is
52
; removed, a new call to 'disk_media_changed' is not allowed until this
52
; removed, a new call to 'disk_media_changed' is not allowed until this
53
; function is called.
53
; function is called.
54
; Optional, may be NULL (if media is not removable).
54
; Optional, may be NULL (if media is not removable).
55
; void closemedia(void* userdata);
55
; void closemedia(void* userdata);
56
        querymedia      dd ?
56
        querymedia      dd ?
57
; The pointer to the function which determines capabilities of the media.
57
; The pointer to the function which determines capabilities of the media.
58
; int querymedia(void* userdata, DISKMEDIAINFO* info);
58
; int querymedia(void* userdata, DISKMEDIAINFO* info);
59
; Return value: one of DISK_STATUS_*
59
; Return value: one of DISK_STATUS_*
60
        read            dd ?
60
        read            dd ?
61
; The pointer to the function which reads data from the device.
61
; The pointer to the function which reads data from the device.
62
; int read(void* userdata, void* buffer, __int64 startsector, int* numsectors);
62
; int read(void* userdata, void* buffer, __int64 startsector, int* numsectors);
63
; input: *numsectors = number of sectors to read
63
; input: *numsectors = number of sectors to read
64
; output: *numsectors = number of sectors which were successfully read
64
; output: *numsectors = number of sectors which were successfully read
65
; Return value: one of DISK_STATUS_*
65
; Return value: one of DISK_STATUS_*
66
        write           dd ?
66
        write           dd ?
67
; The pointer to the function which writes data to the device.
67
; The pointer to the function which writes data to the device.
68
; Optional, may be NULL.
68
; Optional, may be NULL.
69
; int write(void* userdata, void* buffer, __int64 startsector, int* numsectors);
69
; int write(void* userdata, void* buffer, __int64 startsector, int* numsectors);
70
; input: *numsectors = number of sectors to write
70
; input: *numsectors = number of sectors to write
71
; output: *numsectors = number of sectors which were successfully written
71
; output: *numsectors = number of sectors which were successfully written
72
; Return value: one of DISK_STATUS_*
72
; Return value: one of DISK_STATUS_*
73
        flush           dd ?
73
        flush           dd ?
74
; The pointer to the function which flushes the internal device cache.
74
; The pointer to the function which flushes the internal device cache.
75
; Optional, may be NULL.
75
; Optional, may be NULL.
76
; int flush(void* userdata);
76
; int flush(void* userdata);
77
; Return value: one of DISK_STATUS_*
77
; Return value: one of DISK_STATUS_*
78
; Note that read/write are called by the cache manager, so a driver should not
78
; Note that read/write are called by the cache manager, so a driver should not
79
; create a software cache. This function is implemented for flushing a hardware
79
; create a software cache. This function is implemented for flushing a hardware
80
; cache, if it exists.
80
; cache, if it exists.
81
        adjust_cache_size       dd ?
81
        adjust_cache_size       dd ?
82
; The pointer to the function which returns the cache size for this device.
82
; The pointer to the function which returns the cache size for this device.
83
; Optional, may be NULL.
83
; Optional, may be NULL.
84
; unsigned int adjust_cache_size(unsigned int suggested_size);
84
; unsigned int adjust_cache_size(unsigned int suggested_size);
85
; Return value: 0 = disable cache, otherwise = used cache size in bytes.
85
; Return value: 0 = disable cache, otherwise = used cache size in bytes.
86
ends
86
ends
87
 
87
 
88
; This structure holds information on a medium.
88
; This structure holds information on a medium.
89
; Objects with this structure are allocated by the kernel as a part of the DISK
89
; Objects with this structure are allocated by the kernel as a part of the DISK
90
; structure and are filled by a driver in the 'querymedia' callback.
90
; structure and are filled by a driver in the 'querymedia' callback.
91
struct  DISKMEDIAINFO
91
struct  DISKMEDIAINFO
92
        Flags           dd ?
92
        Flags           dd ?
93
; Combination of DISK_MEDIA_* bits.
93
; Combination of DISK_MEDIA_* bits.
94
        SectorSize      dd ?
94
        SectorSize      dd ?
95
; Size of the sector.
95
; Size of the sector.
96
        Capacity        dq ?
96
        Capacity        dq ?
97
; Size of the media in sectors.
97
; Size of the media in sectors.
98
ends
98
ends
99
 
99
 
100
; This structure represents the disk cache. To follow the old implementation,
100
; This structure represents the disk cache. To follow the old implementation,
101
; there are two distinct caches for a disk, one for "system" data,and the other
101
; there are two distinct caches for a disk, one for "system" data,and the other
102
; for "application" data.
102
; for "application" data.
103
struct  DISKCACHE
103
struct  DISKCACHE
104
        mutex           MUTEX
104
        mutex           MUTEX
105
; Lock to protect the cache.
105
; Lock to protect the cache.
106
; The following fields are inherited from data32.inc:cache_ideX.
106
; The following fields are inherited from data32.inc:cache_ideX.
107
        pointer         dd ?
107
        pointer         dd ?
108
        data_size       dd ?    ; unused
108
        data_size       dd ?    ; unused
109
        data            dd ?
109
        data            dd ?
110
        sad_size        dd ?
110
        sad_size        dd ?
111
        search_start    dd ?
111
        search_start    dd ?
112
ends
112
ends
113
 
113
 
114
; This structure represents a disk device and its media for the kernel.
114
; This structure represents a disk device and its media for the kernel.
115
; This structure is allocated by the kernel in the 'disk_add' function,
115
; This structure is allocated by the kernel in the 'disk_add' function,
116
; freed in the 'disk_dereference' function.
116
; freed in the 'disk_dereference' function.
117
struct  DISK
117
struct  DISK
118
; Fields of disk object
118
; Fields of disk object
119
        Next            dd ?
119
        Next            dd ?
120
        Prev            dd ?
120
        Prev            dd ?
121
; All disk devices are linked in one list with these two fields.
121
; All disk devices are linked in one list with these two fields.
122
; Head of the list is the 'disk_list' variable.
122
; Head of the list is the 'disk_list' variable.
123
        Functions       dd ?
123
        Functions       dd ?
124
; Pointer to the 'DISKFUNC' structure with driver functions.
124
; Pointer to the 'DISKFUNC' structure with driver functions.
125
        Name            dd ?
125
        Name            dd ?
126
; Pointer to the string used for accesses through the global filesystem.
126
; Pointer to the string used for accesses through the global filesystem.
127
        UserData        dd ?
127
        UserData        dd ?
128
; This field is passed to all callback functions so a driver can decide which
128
; This field is passed to all callback functions so a driver can decide which
129
; physical device is addressed.
129
; physical device is addressed.
130
        DriverFlags     dd ?
130
        DriverFlags     dd ?
131
; Bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit is defined.
131
; Bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit is defined.
132
; If it is set, the driver will never issue 'disk_media_changed' notification
132
; If it is set, the driver will never issue 'disk_media_changed' notification
133
; with argument set to true, so the kernel must try to detect media during
133
; with argument set to true, so the kernel must try to detect media during
134
; requests from the file system.
134
; requests from the file system.
135
        RefCount        dd ?
135
        RefCount        dd ?
136
; Count of active references to this structure. One reference is kept during
136
; Count of active references to this structure. One reference is kept during
137
; the lifetime of the structure between 'disk_add' and 'disk_del'.
137
; the lifetime of the structure between 'disk_add' and 'disk_del'.
138
; Another reference is taken during any filesystem operation for this disk.
138
; Another reference is taken during any filesystem operation for this disk.
139
; One reference is added if media is inserted.
139
; One reference is added if media is inserted.
140
; The structure is destroyed when the reference count decrements to zero:
140
; The structure is destroyed when the reference count decrements to zero:
141
; this usually occurs in 'disk_del', but can be delayed to the end of last
141
; this usually occurs in 'disk_del', but can be delayed to the end of last
142
; filesystem operation, if one is active.
142
; filesystem operation, if one is active.
143
        MediaLock       MUTEX
143
        MediaLock       MUTEX
144
; Lock to protect the MEDIA structure. See the description after
144
; Lock to protect the MEDIA structure. See the description after
145
; 'disk_list_mutex' for the locking strategy.
145
; 'disk_list_mutex' for the locking strategy.
146
; Fields of media object
146
; Fields of media object
147
        MediaInserted   db ?
147
        MediaInserted   db ?
148
; 0 if media is not inserted, nonzero otherwise.
148
; 0 if media is not inserted, nonzero otherwise.
149
        MediaUsed       db ?
149
        MediaUsed       db ?
150
; 0 if media fields are not used, nonzero otherwise. If .MediaRefCount is
150
; 0 if media fields are not used, nonzero otherwise. If .MediaRefCount is
151
; nonzero, this field is nonzero too; however, when .MediaRefCount goes
151
; nonzero, this field is nonzero too; however, when .MediaRefCount goes
152
; to zero, there is some time interval during which media object is still used.
152
; to zero, there is some time interval during which media object is still used.
153
                        dw ? ; padding
153
                        dw ? ; padding
154
; The following fields are not valid unless either .MediaInserted is nonzero
154
; The following fields are not valid unless either .MediaInserted is nonzero
155
; or they are accessed from a code which has obtained the reference when
155
; or they are accessed from a code which has obtained the reference when
156
; .MediaInserted was nonzero.
156
; .MediaInserted was nonzero.
157
        MediaRefCount   dd ?
157
        MediaRefCount   dd ?
158
; Count of active references to the media object. One reference is kept during
158
; Count of active references to the media object. One reference is kept during
159
; the lifetime of the media between two calls to 'disk_media_changed'.
159
; the lifetime of the media between two calls to 'disk_media_changed'.
160
; Another reference is taken during any filesystem operation for this media.
160
; Another reference is taken during any filesystem operation for this media.
161
; The callback 'closemedia' is called when the reference count decrements to
161
; The callback 'closemedia' is called when the reference count decrements to
162
; zero: this usually occurs in 'disk_media_changed', but can be delayed to the
162
; zero: this usually occurs in 'disk_media_changed', but can be delayed to the
163
; end of the last filesystem operation, if one is active.
163
; end of the last filesystem operation, if one is active.
164
        MediaInfo       DISKMEDIAINFO
164
        MediaInfo       DISKMEDIAINFO
165
; This field keeps information on the current media.
165
; This field keeps information on the current media.
166
        NumPartitions   dd ?
166
        NumPartitions   dd ?
167
; Number of partitions on this media.
167
; Number of partitions on this media.
168
        Partitions      dd ?
168
        Partitions      dd ?
169
; Pointer to array of .NumPartitions pointers to PARTITION structures.
169
; Pointer to array of .NumPartitions pointers to PARTITION structures.
170
        cache_size      dd ?
170
        cache_size      dd ?
171
; inherited from cache_ideX_size
171
; inherited from cache_ideX_size
172
        SysCache        DISKCACHE
172
        SysCache        DISKCACHE
173
        AppCache        DISKCACHE
173
        AppCache        DISKCACHE
174
; Two caches for the disk.
174
; Two caches for the disk.
175
ends
175
ends
176
 
176
 
177
; This structure represents one partition for the kernel. This is a base
177
; This structure represents one partition for the kernel. This is a base
178
; template, the actual contents after common fields is determined by the
178
; template, the actual contents after common fields is determined by the
179
; file system code for this partition.
179
; file system code for this partition.
180
struct  PARTITION
180
struct  PARTITION
181
        FirstSector     dq ?
181
        FirstSector     dq ?
182
; First sector of the partition.
182
; First sector of the partition.
183
        Length          dq ?
183
        Length          dq ?
184
; Length of the partition in sectors.
184
; Length of the partition in sectors.
185
        Disk            dd ?
185
        Disk            dd ?
186
; Pointer to parent DISK structure.
186
; Pointer to parent DISK structure.
187
        FSUserFunctions dd ?
187
        FSUserFunctions dd ?
188
; Handlers for the sysfunction 70h. This field is a pointer to the following
188
; Handlers for the sysfunction 70h. This field is a pointer to the following
189
; array. The first dword is a number of supported subfunctions, other dwords
189
; array. The first dword is a number of supported subfunctions, other dwords
190
; point to handlers of corresponding subfunctions.
190
; point to handlers of corresponding subfunctions.
191
; This field is 0 if file system is not recognized.
191
; This field is 0 if file system is not recognized.
192
; ...fs-specific data may follow...
192
; ...fs-specific data may follow...
193
ends
193
ends
194
 
194
 
195
; This is an external structure, it represents an entry in the partition table.
195
; This is an external structure, it represents an entry in the partition table.
196
struct  PARTITION_TABLE_ENTRY
196
struct  PARTITION_TABLE_ENTRY
197
        Bootable        db ?
197
        Bootable        db ?
198
; 80h = bootable partition, 0 = non-bootable partition, other values = invalid
198
; 80h = bootable partition, 0 = non-bootable partition, other values = invalid
199
        FirstHead       db ?
199
        FirstHead       db ?
200
        FirstSector     db ?
200
        FirstSector     db ?
201
        FirstTrack      db ?
201
        FirstTrack      db ?
202
; Coordinates of first sector in CHS.
202
; Coordinates of first sector in CHS.
203
        Type            db ?
203
        Type            db ?
204
; Partition type, one of predefined constants. 0 = empty, several types denote
204
; Partition type, one of predefined constants. 0 = empty, several types denote
205
; extended partition (see process_partition_table_entry), we are not interested
205
; extended partition (see process_partition_table_entry), we are not interested
206
; in other values.
206
; in other values.
207
        LastHead        db ?
207
        LastHead        db ?
208
        LastSector      db ?
208
        LastSector      db ?
209
        LastTrack       db ?
209
        LastTrack       db ?
210
; Coordinates of last sector in CHS.
210
; Coordinates of last sector in CHS.
211
        FirstAbsSector  dd ?
211
        FirstAbsSector  dd ?
212
; Coordinate of first sector in LBA.
212
; Coordinate of first sector in LBA.
213
        Length          dd ?
213
        Length          dd ?
214
; Length of the partition in sectors.
214
; Length of the partition in sectors.
215
ends
215
ends
216
 
216
 
217
; =============================================================================
217
; =============================================================================
218
; ================================ Global data ================================
218
; ================================ Global data ================================
219
; =============================================================================
219
; =============================================================================
220
iglobal
220
iglobal
221
; The pseudo-item for the list of all DISK structures.
221
; The pseudo-item for the list of all DISK structures.
222
; Initialized to the empty list.
222
; Initialized to the empty list.
223
disk_list:
223
disk_list:
224
        dd      disk_list
224
        dd      disk_list
225
        dd      disk_list
225
        dd      disk_list
226
endg
226
endg
227
uglobal
227
uglobal
228
; This mutex guards all operations with the global list of DISK structures.
228
; This mutex guards all operations with the global list of DISK structures.
229
disk_list_mutex MUTEX
229
disk_list_mutex MUTEX
230
; * There are two dependent objects, a disk and a media. In the simplest case,
230
; * There are two dependent objects, a disk and a media. In the simplest case,
231
;   disk and media are both non-removable. However, in the general case both
231
;   disk and media are both non-removable. However, in the general case both
232
;   can be removed at any time, simultaneously or only media,and this makes things
232
;   can be removed at any time, simultaneously or only media,and this makes things
233
;   complicated.
233
;   complicated.
234
; * For efficiency, both disk and media objects are located in the one
234
; * For efficiency, both disk and media objects are located in the one
235
;   structure named DISK. However, logically they are different.
235
;   structure named DISK. However, logically they are different.
236
; * The following operations use data of disk object: adding (disk_add);
236
; * The following operations use data of disk object: adding (disk_add);
237
;   deleting (disk_del); filesystem (fs_lfn which eventually calls
237
;   deleting (disk_del); filesystem (fs_lfn which eventually calls
238
;   dyndisk_handler or dyndisk_enum_root).
238
;   dyndisk_handler or dyndisk_enum_root).
239
; * The following operations use data of media object: adding/removing
239
; * The following operations use data of media object: adding/removing
240
;   (disk_media_changed); filesystem (fs_lfn which eventually calls
240
;   (disk_media_changed); filesystem (fs_lfn which eventually calls
241
;   dyndisk_handler; dyndisk_enum_root doesn't work with media).
241
;   dyndisk_handler; dyndisk_enum_root doesn't work with media).
242
; * Notifications disk_add, disk_media_changed, disk_del are synchronized
242
; * Notifications disk_add, disk_media_changed, disk_del are synchronized
243
;   between themselves, this is a requirement for the driver. However, file
243
;   between themselves, this is a requirement for the driver. However, file
244
;   system operations are asynchronous, can be issued at any time by any
244
;   system operations are asynchronous, can be issued at any time by any
245
;   thread.
245
;   thread.
246
; * We must prevent a situation when a filesystem operation thinks that the
246
; * We must prevent a situation when a filesystem operation thinks that the
247
;   object is still valid but in fact the notification has destroyed the
247
;   object is still valid but in fact the notification has destroyed the
248
;   object. So we keep a reference counter for both disk and media and destroy
248
;   object. So we keep a reference counter for both disk and media and destroy
249
;   the object when this counter goes to zero.
249
;   the object when this counter goes to zero.
250
; * The driver must know when it is safe to free driver-allocated resources.
250
; * The driver must know when it is safe to free driver-allocated resources.
251
;   The object can be alive even after death notification has completed.
251
;   The object can be alive even after death notification has completed.
252
;   We use special callbacks to satisfy both assertions: 'close' for the disk
252
;   We use special callbacks to satisfy both assertions: 'close' for the disk
253
;   and 'closemedia' for the media. The destruction of the object includes
253
;   and 'closemedia' for the media. The destruction of the object includes
254
;   calling the corresponding callback.
254
;   calling the corresponding callback.
255
; * Each filesystem operation keeps one reference for the disk and one
255
; * Each filesystem operation keeps one reference for the disk and one
256
;   reference for the media. Notification disk_del forces notification on the
256
;   reference for the media. Notification disk_del forces notification on the
257
;   media death, so the reference counter for the disk is always not less than
257
;   media death, so the reference counter for the disk is always not less than
258
;   the reference counter for the media.
258
;   the reference counter for the media.
259
; * Two operations "get the object" and "increment the reference counter" can
259
; * Two operations "get the object" and "increment the reference counter" can
260
;   not be done simultaneously. We use a mutex to guard the consistency here.
260
;   not be done simultaneously. We use a mutex to guard the consistency here.
261
;   It must be a part of the container for the object, so that this mutex can
261
;   It must be a part of the container for the object, so that this mutex can
262
;   be acquired as a part of getting the object from the container. The
262
;   be acquired as a part of getting the object from the container. The
263
;   container for disk object is the global list, and this list is guarded by
263
;   container for disk object is the global list, and this list is guarded by
264
;   'disk_list_mutex'. The container for media object is the disk object, and
264
;   'disk_list_mutex'. The container for media object is the disk object, and
265
;   the corresponding mutex is DISK.MediaLock.
265
;   the corresponding mutex is DISK.MediaLock.
266
; * Notifications do not change the data of objects, they can only remove
266
; * Notifications do not change the data of objects, they can only remove
267
;   objects. Thus we don't need another synchronization at this level. If two
267
;   objects. Thus we don't need another synchronization at this level. If two
268
;   filesystem operations are referencing the same filesystem data, this is
268
;   filesystem operations are referencing the same filesystem data, this is
269
;   better resolved at the level of the filesystem.
269
;   better resolved at the level of the filesystem.
270
endg
270
endg
271
 
271
 
272
iglobal
272
iglobal
273
; The function 'disk_scan_partitions' needs three 512-byte buffers for
273
; The function 'disk_scan_partitions' needs three 512-byte buffers for
274
; MBR, bootsector and fs-temporary sector data. It can not use the static
274
; MBR, bootsector and fs-temporary sector data. It can not use the static
275
; buffers always, since it can be called for two or more disks in parallel.
275
; buffers always, since it can be called for two or more disks in parallel.
276
; However, this case is not typical. We reserve three static 512-byte buffers
276
; However, this case is not typical. We reserve three static 512-byte buffers
277
; and a flag that these buffers are currently used. If 'disk_scan_partitions'
277
; and a flag that these buffers are currently used. If 'disk_scan_partitions'
278
; detects that the buffers are currently used, it allocates buffers from the
278
; detects that the buffers are currently used, it allocates buffers from the
279
; heap.
279
; heap.
280
; The flag is implemented as a global dword variable. When the static buffers
280
; The flag is implemented as a global dword variable. When the static buffers
281
; are not used, the value is -1. When the static buffers are used, the value
281
; are not used, the value is -1. When the static buffers are used, the value
282
; is normally 0 and temporarily can become greater. The function increments
282
; is normally 0 and temporarily can become greater. The function increments
283
; this value. If the resulting value is zero, it uses the buffers and
283
; this value. If the resulting value is zero, it uses the buffers and
284
; decrements the value when the job is done. Otherwise, it immediately
284
; decrements the value when the job is done. Otherwise, it immediately
285
; decrements the value and uses buffers from the heap, allocated in the
285
; decrements the value and uses buffers from the heap, allocated in the
286
; beginning and freed in the end.
286
; beginning and freed in the end.
287
partition_buffer_users  dd      -1
287
partition_buffer_users  dd      -1
288
endg
288
endg
289
uglobal
289
uglobal
290
; The static buffers for MBR, bootsector and fs-temporary sector data.
290
; The static buffers for MBR, bootsector and fs-temporary sector data.
291
align 16
291
align 16
292
mbr_buffer      rb      512
292
mbr_buffer      rb      512
293
bootsect_buffer rb      512
293
bootsect_buffer rb      512
294
fs_tmp_buffer   rb      512
294
fs_tmp_buffer   rb      512
295
endg
295
endg
296
 
296
 
297
iglobal
297
iglobal
298
; This is the array of default implementations of driver callbacks.
298
; This is the array of default implementations of driver callbacks.
299
; Same as DRIVERFUNC structure except for the first field; all functions must
299
; Same as DRIVERFUNC structure except for the first field; all functions must
300
; have the default implementations.
300
; have the default implementations.
301
align 4
301
align 4
302
disk_default_callbacks:
302
disk_default_callbacks:
303
        dd      disk_default_close
303
        dd      disk_default_close
304
        dd      disk_default_closemedia
304
        dd      disk_default_closemedia
305
        dd      disk_default_querymedia
305
        dd      disk_default_querymedia
306
        dd      disk_default_read
306
        dd      disk_default_read
307
        dd      disk_default_write
307
        dd      disk_default_write
308
        dd      disk_default_flush
308
        dd      disk_default_flush
309
        dd      disk_default_adjust_cache_size
309
        dd      disk_default_adjust_cache_size
310
endg
310
endg
311
 
311
 
312
; =============================================================================
312
; =============================================================================
313
; ================================= Functions =================================
313
; ================================= Functions =================================
314
; =============================================================================
314
; =============================================================================
315
 
315
 
316
; This function registers a disk device.
316
; This function registers a disk device.
317
; This includes:
317
; This includes:
318
; - allocating an internal structure describing this device;
318
; - allocating an internal structure describing this device;
319
; - registering this structure in the global filesystem.
319
; - registering this structure in the global filesystem.
320
; The function initializes the disk as if there is no media. If a media is
320
; The function initializes the disk as if there is no media. If a media is
321
; present, the function 'disk_media_changed' should be called after this
321
; present, the function 'disk_media_changed' should be called after this
322
; function succeeds.
322
; function succeeds.
323
; Parameters:
323
; Parameters:
324
; [esp+4] = pointer to DISKFUNC structure with the callbacks
324
; [esp+4] = pointer to DISKFUNC structure with the callbacks
325
; [esp+8] = pointer to name (ASCIIZ string)
325
; [esp+8] = pointer to name (ASCIIZ string)
326
; [esp+12] = userdata to be passed to the callbacks as is.
326
; [esp+12] = userdata to be passed to the callbacks as is.
327
; [esp+16] = flags, bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit
327
; [esp+16] = flags, bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit
328
;            is defined.
328
;            is defined.
329
; Return value:
329
; Return value:
330
; NULL = operation has failed
330
; NULL = operation has failed
331
; non-NULL = handle of the disk. This handle can be used
331
; non-NULL = handle of the disk. This handle can be used
332
; in the operations with other Disk* functions.
332
; in the operations with other Disk* functions.
333
; The handle is the pointer to the internal structure DISK.
333
; The handle is the pointer to the internal structure DISK.
334
disk_add:
334
disk_add:
335
        push    ebx esi         ; save used registers to be stdcall
335
        push    ebx esi         ; save used registers to be stdcall
336
; 1. Allocate the DISK structure.
336
; 1. Allocate the DISK structure.
337
; 1a. Call the heap manager.
337
; 1a. Call the heap manager.
338
        push    sizeof.DISK
338
        movi    eax, sizeof.DISK
339
        pop     eax
-
 
340
        call    malloc
339
        call    malloc
341
; 1b. Check the result. If allocation failed, return (go to 9) with eax = 0.
340
; 1b. Check the result. If allocation failed, return (go to 9) with eax = 0.
342
        test    eax, eax
341
        test    eax, eax
343
        jz      .nothing
342
        jz      .nothing
344
; 2. Copy the disk name to the DISK structure.
343
; 2. Copy the disk name to the DISK structure.
345
; 2a. Get length of the name, including the terminating zero.
344
; 2a. Get length of the name, including the terminating zero.
346
        mov     ebx, [esp+8+8]  ; ebx = pointer to name
345
        mov     ebx, [esp+8+8]  ; ebx = pointer to name
347
        push    eax             ; save allocated pointer to DISK
346
        push    eax             ; save allocated pointer to DISK
348
        xor     eax, eax        ; the argument of malloc() is in eax
347
        xor     eax, eax        ; the argument of malloc() is in eax
349
@@:
348
@@:
350
        inc     eax
349
        inc     eax
351
        cmp     byte [ebx+eax-1], 0
350
        cmp     byte [ebx+eax-1], 0
352
        jnz     @b
351
        jnz     @b
353
; 2b. Call the heap manager. Note that it can change ebx.
352
; 2b. Call the heap manager. Note that it can change ebx.
354
        push    ebx
353
        push    ebx
355
        call    malloc
354
        call    malloc
356
        pop     ebx
355
        pop     ebx
357
; 2c. Check the result. If allocation failed, go to 7.
356
; 2c. Check the result. If allocation failed, go to 7.
358
        pop     esi             ; restore allocated pointer to DISK
357
        pop     esi             ; restore allocated pointer to DISK
359
        test    eax, eax
358
        test    eax, eax
360
        jz      .free
359
        jz      .free
361
; 2d. Store the allocated pointer to the DISK structure.
360
; 2d. Store the allocated pointer to the DISK structure.
362
        mov     [esi+DISK.Name], eax
361
        mov     [esi+DISK.Name], eax
363
; 2e. Copy the name.
362
; 2e. Copy the name.
364
@@:
363
@@:
365
        mov     dl, [ebx]
364
        mov     dl, [ebx]
366
        mov     [eax], dl
365
        mov     [eax], dl
367
        inc     ebx
366
        inc     ebx
368
        inc     eax
367
        inc     eax
369
        test    dl, dl
368
        test    dl, dl
370
        jnz     @b
369
        jnz     @b
371
; 3. Copy other arguments of the function to the DISK structure.
370
; 3. Copy other arguments of the function to the DISK structure.
372
        mov     eax, [esp+4+8]
371
        mov     eax, [esp+4+8]
373
        mov     [esi+DISK.Functions], eax
372
        mov     [esi+DISK.Functions], eax
374
        mov     eax, [esp+12+8]
373
        mov     eax, [esp+12+8]
375
        mov     [esi+DISK.UserData], eax
374
        mov     [esi+DISK.UserData], eax
376
        mov     eax, [esp+16+8]
375
        mov     eax, [esp+16+8]
377
        mov     [esi+DISK.DriverFlags], eax
376
        mov     [esi+DISK.DriverFlags], eax
378
; 4. Initialize other fields of the DISK structure.
377
; 4. Initialize other fields of the DISK structure.
379
; Media is not inserted, reference counter is 1.
378
; Media is not inserted, reference counter is 1.
380
        lea     ecx, [esi+DISK.MediaLock]
379
        lea     ecx, [esi+DISK.MediaLock]
381
        call    mutex_init
380
        call    mutex_init
382
        xor     eax, eax
381
        xor     eax, eax
383
        mov     dword [esi+DISK.MediaInserted], eax
382
        mov     dword [esi+DISK.MediaInserted], eax
384
        mov     [esi+DISK.MediaRefCount], eax
383
        mov     [esi+DISK.MediaRefCount], eax
385
        inc     eax
384
        inc     eax
386
        mov     [esi+DISK.RefCount], eax
385
        mov     [esi+DISK.RefCount], eax
387
; The DISK structure is initialized.
386
; The DISK structure is initialized.
388
; 5. Insert the new structure to the global list.
387
; 5. Insert the new structure to the global list.
389
; 5a. Acquire the mutex.
388
; 5a. Acquire the mutex.
390
        mov     ecx, disk_list_mutex
389
        mov     ecx, disk_list_mutex
391
        call    mutex_lock
390
        call    mutex_lock
392
; 5b. Insert item to the tail of double-linked list.
391
; 5b. Insert item to the tail of double-linked list.
393
        mov     edx, disk_list
392
        mov     edx, disk_list
394
        list_add_tail esi, edx     ;esi= new edx= list head
393
        list_add_tail esi, edx     ;esi= new edx= list head
395
; 5c. Release the mutex.
394
; 5c. Release the mutex.
396
        call    mutex_unlock
395
        call    mutex_unlock
397
; 6. Return with eax = pointer to DISK.
396
; 6. Return with eax = pointer to DISK.
398
        xchg    eax, esi
397
        xchg    eax, esi
399
        jmp     .nothing
398
        jmp     .nothing
400
.free:
399
.free:
401
; Memory allocation for DISK structure succeeded, but for disk name failed.
400
; Memory allocation for DISK structure succeeded, but for disk name failed.
402
; 7. Free the DISK structure.
401
; 7. Free the DISK structure.
403
        xchg    eax, esi
402
        xchg    eax, esi
404
        call    free
403
        call    free
405
; 8. Return with eax = 0.
404
; 8. Return with eax = 0.
406
        xor     eax, eax
405
        xor     eax, eax
407
.nothing:
406
.nothing:
408
; 9. Return.
407
; 9. Return.
409
        pop     esi ebx         ; restore used registers to be stdcall
408
        pop     esi ebx         ; restore used registers to be stdcall
410
        ret     16              ; purge 4 dword arguments to be stdcall
409
        ret     16              ; purge 4 dword arguments to be stdcall
411
 
410
 
412
; This function deletes a disk device from the global filesystem.
411
; This function deletes a disk device from the global filesystem.
413
; This includes:
412
; This includes:
414
; - removing a media including all partitions;
413
; - removing a media including all partitions;
415
; - deleting this structure from the global filesystem;
414
; - deleting this structure from the global filesystem;
416
; - dereferencing the DISK structure and possibly destroying it.
415
; - dereferencing the DISK structure and possibly destroying it.
417
; Parameters:
416
; Parameters:
418
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
417
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
419
; Return value: none.
418
; Return value: none.
420
disk_del:
419
disk_del:
421
        push    esi         ; save used registers to be stdcall
420
        push    esi         ; save used registers to be stdcall
422
; 1. Force media to be removed. If the media is already removed, the
421
; 1. Force media to be removed. If the media is already removed, the
423
; call does nothing.
422
; call does nothing.
424
        mov     esi, [esp+4+4]  ; esi = handle of the disk
423
        mov     esi, [esp+4+4]  ; esi = handle of the disk
425
        stdcall disk_media_changed, esi, 0
424
        stdcall disk_media_changed, esi, 0
426
; 2. Delete the structure from the global list.
425
; 2. Delete the structure from the global list.
427
; 2a. Acquire the mutex.
426
; 2a. Acquire the mutex.
428
        mov     ecx, disk_list_mutex
427
        mov     ecx, disk_list_mutex
429
        call    mutex_lock
428
        call    mutex_lock
430
; 2b. Delete item from double-linked list.
429
; 2b. Delete item from double-linked list.
431
        mov     eax, [esi+DISK.Next]
430
        mov     eax, [esi+DISK.Next]
432
        mov     edx, [esi+DISK.Prev]
431
        mov     edx, [esi+DISK.Prev]
433
        mov     [eax+DISK.Prev], edx
432
        mov     [eax+DISK.Prev], edx
434
        mov     [edx+DISK.Next], eax
433
        mov     [edx+DISK.Next], eax
435
; 2c. Release the mutex.
434
; 2c. Release the mutex.
436
        call    mutex_unlock
435
        call    mutex_unlock
437
; 3. The structure still has one reference created in disk_add. Remove this
436
; 3. The structure still has one reference created in disk_add. Remove this
438
; reference. If there are no other references, disk_dereference will free the
437
; reference. If there are no other references, disk_dereference will free the
439
; structure.
438
; structure.
440
        call    disk_dereference
439
        call    disk_dereference
441
; 4. Return.
440
; 4. Return.
442
        pop     esi             ; restore used registers to be stdcall
441
        pop     esi             ; restore used registers to be stdcall
443
        ret     4               ; purge 1 dword argument to be stdcall
442
        ret     4               ; purge 1 dword argument to be stdcall
444
 
443
 
445
; This is an internal function which removes a previously obtained reference
444
; This is an internal function which removes a previously obtained reference
446
; to the disk. If this is the last reference, this function lets the driver
445
; to the disk. If this is the last reference, this function lets the driver
447
; finalize all associated data, and afterwards frees the DISK structure.
446
; finalize all associated data, and afterwards frees the DISK structure.
448
; esi = pointer to DISK structure
447
; esi = pointer to DISK structure
449
disk_dereference:
448
disk_dereference:
450
; 1. Decrement reference counter. Use atomic operation to correctly handle
449
; 1. Decrement reference counter. Use atomic operation to correctly handle
451
; possible simultaneous calls.
450
; possible simultaneous calls.
452
        lock dec [esi+DISK.RefCount]
451
        lock dec [esi+DISK.RefCount]
453
; 2. If the result is nonzero, there are other references, so nothing to do.
452
; 2. If the result is nonzero, there are other references, so nothing to do.
454
; In this case, return (go to 4).
453
; In this case, return (go to 4).
455
        jnz     .nothing
454
        jnz     .nothing
456
; 3. If we are here, we just removed the last reference and must destroy the
455
; 3. If we are here, we just removed the last reference and must destroy the
457
; disk object.
456
; disk object.
458
; 3a. Call the driver.
457
; 3a. Call the driver.
459
        mov     al, DISKFUNC.close
458
        mov     al, DISKFUNC.close
460
        stdcall disk_call_driver
459
        stdcall disk_call_driver
461
; 3b. Free the structure.
460
; 3b. Free the structure.
462
        xchg    eax, esi
461
        xchg    eax, esi
463
        push    ebx
462
        push    ebx
464
        call    free
463
        call    free
465
        pop     ebx
464
        pop     ebx
466
; 4. Return.
465
; 4. Return.
467
.nothing:
466
.nothing:
468
        ret
467
        ret
469
 
468
 
470
; This is an internal function which removes a previously obtained reference
469
; This is an internal function which removes a previously obtained reference
471
; to the media. If this is the last reference, this function calls 'closemedia'
470
; to the media. If this is the last reference, this function calls 'closemedia'
472
; callback to signal the driver that the processing has finished and it is safe
471
; callback to signal the driver that the processing has finished and it is safe
473
; to inform about a new media.
472
; to inform about a new media.
474
; esi = pointer to DISK structure
473
; esi = pointer to DISK structure
475
disk_media_dereference:
474
disk_media_dereference:
476
; 1. Decrement reference counter. Use atomic operation to correctly handle
475
; 1. Decrement reference counter. Use atomic operation to correctly handle
477
; possible simultaneous calls.
476
; possible simultaneous calls.
478
        lock dec [esi+DISK.MediaRefCount]
477
        lock dec [esi+DISK.MediaRefCount]
479
; 2. If the result is nonzero, there are other references, so nothing to do.
478
; 2. If the result is nonzero, there are other references, so nothing to do.
480
; In this case, return (go to 4).
479
; In this case, return (go to 4).
481
        jnz     .nothing
480
        jnz     .nothing
482
; 3. If we are here, we just removed the last reference and must destroy the
481
; 3. If we are here, we just removed the last reference and must destroy the
483
; media object.
482
; media object.
484
; Note that the same place inside the DISK structure is reused for all media
483
; Note that the same place inside the DISK structure is reused for all media
485
; objects, so we must guarantee that reusing does not happen while freeing.
484
; objects, so we must guarantee that reusing does not happen while freeing.
486
; Reusing is only possible when someone processes a new media. There are two
485
; Reusing is only possible when someone processes a new media. There are two
487
; mutually exclusive variants:
486
; mutually exclusive variants:
488
; * driver issues media insert notifications (DISK_NO_INSERT_NOTIFICATION bit
487
; * driver issues media insert notifications (DISK_NO_INSERT_NOTIFICATION bit
489
;   in DISK.DriverFlags is not set). In this case, we require from the driver
488
;   in DISK.DriverFlags is not set). In this case, we require from the driver
490
;   that such notification (except for the first one) can occur only after a
489
;   that such notification (except for the first one) can occur only after a
491
;   call to 'closemedia' callback.
490
;   call to 'closemedia' callback.
492
; * driver does not issue media insert notifications. In this case, the kernel
491
; * driver does not issue media insert notifications. In this case, the kernel
493
;   itself must sometimes check whether media is inserted. We have the flag
492
;   itself must sometimes check whether media is inserted. We have the flag
494
;   DISK.MediaUsed, visible to the kernel. This flag signals to the other parts
493
;   DISK.MediaUsed, visible to the kernel. This flag signals to the other parts
495
;   of kernel that the way is free.
494
;   of kernel that the way is free.
496
; In the first case other parts of the kernel do not use DISK.MediaUsed, so it
495
; In the first case other parts of the kernel do not use DISK.MediaUsed, so it
497
; does not matter when this flag is cleared. In the second case this flag must
496
; does not matter when this flag is cleared. In the second case this flag must
498
; be cleared after all other actions, including call to 'closemedia'.
497
; be cleared after all other actions, including call to 'closemedia'.
499
; 3a. Free all partitions.
498
; 3a. Free all partitions.
500
        push    esi edi
499
        push    esi edi
501
        mov     edi, [esi+DISK.NumPartitions]
500
        mov     edi, [esi+DISK.NumPartitions]
502
        mov     esi, [esi+DISK.Partitions]
501
        mov     esi, [esi+DISK.Partitions]
503
        test    edi, edi
502
        test    edi, edi
504
        jz      .nofree
503
        jz      .nofree
505
.freeloop:
504
.freeloop:
506
        lodsd
505
        lodsd
507
        call    free
506
        call    free
508
        dec     edi
507
        dec     edi
509
        jnz     .freeloop
508
        jnz     .freeloop
510
.nofree:
509
.nofree:
511
        pop     edi esi
510
        pop     edi esi
512
; 3b. Free the cache.
511
; 3b. Free the cache.
513
        call    disk_free_cache
512
        call    disk_free_cache
514
; 3c. Call the driver.
513
; 3c. Call the driver.
515
        mov     al, DISKFUNC.closemedia
514
        mov     al, DISKFUNC.closemedia
516
        stdcall disk_call_driver
515
        stdcall disk_call_driver
517
; 3d. Clear the flag.
516
; 3d. Clear the flag.
518
        mov     [esi+DISK.MediaUsed], 0
517
        mov     [esi+DISK.MediaUsed], 0
519
.nothing:
518
.nothing:
520
        ret
519
        ret
521
 
520
 
522
; This function is called by the driver and informs the kernel that the media
521
; This function is called by the driver and informs the kernel that the media
523
; has changed. If the media is non-removable, it is called exactly once
522
; has changed. If the media is non-removable, it is called exactly once
524
; immediately after 'disk_add' and once from 'disk_del'.
523
; immediately after 'disk_add' and once from 'disk_del'.
525
; Parameters:
524
; Parameters:
526
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
525
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
527
; [esp+8] = new status of the media: zero = no media, nonzero = media inserted.
526
; [esp+8] = new status of the media: zero = no media, nonzero = media inserted.
528
disk_media_changed:
527
disk_media_changed:
529
        push    ebx esi edi             ; save used registers to be stdcall
528
        push    ebx esi edi             ; save used registers to be stdcall
530
; 1. Remove the existing media, if it is present.
529
; 1. Remove the existing media, if it is present.
531
        mov     esi, [esp+4+12]         ; esi = pointer to DISK
530
        mov     esi, [esp+4+12]         ; esi = pointer to DISK
532
; 1a. Check whether it is present. Since DISK.MediaInserted is changed only
531
; 1a. Check whether it is present. Since DISK.MediaInserted is changed only
533
; in this function and calls to this function are synchronized, no lock is
532
; in this function and calls to this function are synchronized, no lock is
534
; required for checking.
533
; required for checking.
535
        cmp     [esi+DISK.MediaInserted], 0
534
        cmp     [esi+DISK.MediaInserted], 0
536
        jz      .noremove
535
        jz      .noremove
537
; We really need to remove the media.
536
; We really need to remove the media.
538
; 1b. Acquire mutex.
537
; 1b. Acquire mutex.
539
        lea     ecx, [esi+DISK.MediaLock]
538
        lea     ecx, [esi+DISK.MediaLock]
540
        call    mutex_lock
539
        call    mutex_lock
541
; 1c. Clear the flag.
540
; 1c. Clear the flag.
542
        mov     [esi+DISK.MediaInserted], 0
541
        mov     [esi+DISK.MediaInserted], 0
543
; 1d. Release mutex.
542
; 1d. Release mutex.
544
        call    mutex_unlock
543
        call    mutex_unlock
545
; 1e. Remove the "lifetime" reference and possibly destroy the structure.
544
; 1e. Remove the "lifetime" reference and possibly destroy the structure.
546
        call    disk_media_dereference
545
        call    disk_media_dereference
547
.noremove:
546
.noremove:
548
; 2. Test whether there is new media.
547
; 2. Test whether there is new media.
549
        cmp     dword [esp+8+12], 0
548
        cmp     dword [esp+8+12], 0
550
        jz      .noinsert
549
        jz      .noinsert
551
; Yep, there is.
550
; Yep, there is.
552
; 3. Process the new media. We assume that all media fields are available to
551
; 3. Process the new media. We assume that all media fields are available to
553
; use, see comments in 'disk_media_dereference' (this covers using by previous
552
; use, see comments in 'disk_media_dereference' (this covers using by previous
554
; media referencers) and note that calls to this function are synchronized
553
; media referencers) and note that calls to this function are synchronized
555
; (this covers using by new media referencers).
554
; (this covers using by new media referencers).
556
; 3a. Call the 'querymedia' callback.
555
; 3a. Call the 'querymedia' callback.
557
; .Flags are set to zero for possible future extensions.
556
; .Flags are set to zero for possible future extensions.
558
        lea     edx, [esi+DISK.MediaInfo]
557
        lea     edx, [esi+DISK.MediaInfo]
559
        and     [edx+DISKMEDIAINFO.Flags], 0
558
        and     [edx+DISKMEDIAINFO.Flags], 0
560
        mov     al, DISKFUNC.querymedia
559
        mov     al, DISKFUNC.querymedia
561
        stdcall disk_call_driver, edx
560
        stdcall disk_call_driver, edx
562
; 3b. Check the result of the callback. Abort if it failed.
561
; 3b. Check the result of the callback. Abort if it failed.
563
        test    eax, eax
562
        test    eax, eax
564
        jnz     .noinsert
563
        jnz     .noinsert
565
; 3c. Allocate the cache unless disabled by the driver. Abort if failed.
564
; 3c. Allocate the cache unless disabled by the driver. Abort if failed.
566
        call    disk_init_cache
565
        call    disk_init_cache
567
        test    al, al
566
        test    al, al
568
        jz      .noinsert
567
        jz      .noinsert
569
; 3d. Acquire the lifetime reference for the media object.
568
; 3d. Acquire the lifetime reference for the media object.
570
        inc     [esi+DISK.MediaRefCount]
569
        inc     [esi+DISK.MediaRefCount]
571
; 3e. Scan for partitions. Ignore result; the list of partitions is valid even
570
; 3e. Scan for partitions. Ignore result; the list of partitions is valid even
572
; on errors.
571
; on errors.
573
        call    disk_scan_partitions
572
        call    disk_scan_partitions
574
; 3f. Media is inserted and available for use.
573
; 3f. Media is inserted and available for use.
575
        inc     [esi+DISK.MediaInserted]
574
        inc     [esi+DISK.MediaInserted]
576
.noinsert:
575
.noinsert:
577
; 4. Return.
576
; 4. Return.
578
        pop     edi esi ebx             ; restore used registers to be stdcall
577
        pop     edi esi ebx             ; restore used registers to be stdcall
579
        ret     8                       ; purge 2 dword arguments to be stdcall
578
        ret     8                       ; purge 2 dword arguments to be stdcall
580
 
579
 
581
; This function is a thunk for all functions of a disk driver.
580
; This function is a thunk for all functions of a disk driver.
582
; It checks whether the referenced function is implemented in the driver.
581
; It checks whether the referenced function is implemented in the driver.
583
; If so, this function jumps to the function in the driver.
582
; If so, this function jumps to the function in the driver.
584
; Otherwise, it jumps to the default implementation.
583
; Otherwise, it jumps to the default implementation.
585
; al = offset of function in the DISKFUNC structure;
584
; al = offset of function in the DISKFUNC structure;
586
; esi = pointer to the DISK structure;
585
; esi = pointer to the DISK structure;
587
; stack is the same as for the corresponding function except that the
586
; stack is the same as for the corresponding function except that the
588
; first parameter (void* userdata) is prepended automatically.
587
; first parameter (void* userdata) is prepended automatically.
589
disk_call_driver:
588
disk_call_driver:
590
        movzx   eax, al ; eax = offset of function in the DISKFUNC structure
589
        movzx   eax, al ; eax = offset of function in the DISKFUNC structure
591
; 1. Prepend the first argument to the stack.
590
; 1. Prepend the first argument to the stack.
592
        pop     ecx     ; ecx = return address
591
        pop     ecx     ; ecx = return address
593
        push    [esi+DISK.UserData]     ; add argument
592
        push    [esi+DISK.UserData]     ; add argument
594
        push    ecx     ; save return address
593
        push    ecx     ; save return address
595
; 2. Check that the required function is inside the table. If not, go to 5.
594
; 2. Check that the required function is inside the table. If not, go to 5.
596
        mov     ecx, [esi+DISK.Functions]
595
        mov     ecx, [esi+DISK.Functions]
597
        cmp     eax, [ecx+DISKFUNC.strucsize]
596
        cmp     eax, [ecx+DISKFUNC.strucsize]
598
        jae     .default
597
        jae     .default
599
; 3. Check that the required function is implemented. If not, go to 5.
598
; 3. Check that the required function is implemented. If not, go to 5.
600
        mov     ecx, [ecx+eax]
599
        mov     ecx, [ecx+eax]
601
        test    ecx, ecx
600
        test    ecx, ecx
602
        jz      .default
601
        jz      .default
603
; 4. Jump to the required function.
602
; 4. Jump to the required function.
604
        jmp     ecx
603
        jmp     ecx
605
.default:
604
.default:
606
; 5. Driver does not implement the required function; use default implementation.
605
; 5. Driver does not implement the required function; use default implementation.
607
        jmp     dword [disk_default_callbacks+eax-4]
606
        jmp     dword [disk_default_callbacks+eax-4]
608
 
607
 
609
; The default implementation of DISKFUNC.querymedia.
608
; The default implementation of DISKFUNC.querymedia.
610
disk_default_querymedia:
609
disk_default_querymedia:
611
        push    DISK_STATUS_INVALID_CALL
610
        movi    eax, DISK_STATUS_INVALID_CALL
612
        pop     eax
-
 
613
        ret     8
611
        ret     8
614
 
612
 
615
; The default implementation of DISKFUNC.read and DISKFUNC.write.
613
; The default implementation of DISKFUNC.read and DISKFUNC.write.
616
disk_default_read:
614
disk_default_read:
617
disk_default_write:
615
disk_default_write:
618
        push    DISK_STATUS_INVALID_CALL
616
        movi    eax, DISK_STATUS_INVALID_CALL
619
        pop     eax
-
 
620
        ret     20
617
        ret     20
621
 
618
 
622
; The default implementation of DISKFUNC.close, DISKFUNC.closemedia and
619
; The default implementation of DISKFUNC.close, DISKFUNC.closemedia and
623
; DISKFUNC.flush.
620
; DISKFUNC.flush.
624
disk_default_close:
621
disk_default_close:
625
disk_default_closemedia:
622
disk_default_closemedia:
626
disk_default_flush:
623
disk_default_flush:
627
        xor     eax, eax
624
        xor     eax, eax
628
        ret     4
625
        ret     4
629
 
626
 
630
; The default implementation of DISKFUNC.adjust_cache_size.
627
; The default implementation of DISKFUNC.adjust_cache_size.
631
disk_default_adjust_cache_size:
628
disk_default_adjust_cache_size:
632
        mov     eax, [esp+8]
629
        mov     eax, [esp+8]
633
        ret     8
630
        ret     8
634
 
631
 
635
; This is an internal function called from 'disk_media_changed' when a new media
632
; This is an internal function called from 'disk_media_changed' when a new media
636
; is detected. It creates the list of partitions for the media.
633
; is detected. It creates the list of partitions for the media.
637
; If media is not partitioned, then the list consists of one partition which
634
; If media is not partitioned, then the list consists of one partition which
638
; covers all the media.
635
; covers all the media.
639
; esi = pointer to the DISK structure.
636
; esi = pointer to the DISK structure.
640
disk_scan_partitions:
637
disk_scan_partitions:
641
; 1. Initialize .NumPartitions and .Partitions fields as zeros: empty list.
638
; 1. Initialize .NumPartitions and .Partitions fields as zeros: empty list.
642
        and     [esi+DISK.NumPartitions], 0
639
        and     [esi+DISK.NumPartitions], 0
643
        and     [esi+DISK.Partitions], 0
640
        and     [esi+DISK.Partitions], 0
644
; 2. Currently we can work only with 512-bytes sectors. Check this restriction.
641
; 2. Currently we can work only with 512-bytes sectors. Check this restriction.
645
; The only exception is 2048-bytes CD/DVD, but they are not supported yet by
642
; The only exception is 2048-bytes CD/DVD, but they are not supported yet by
646
; this code.
643
; this code.
647
        cmp     [esi+DISK.MediaInfo.SectorSize], 512
644
        cmp     [esi+DISK.MediaInfo.SectorSize], 512
648
        jz      .doscan
645
        jz      .doscan
649
        DEBUGF 1,'K : sector size is %d, only 512 is supported\n',[esi+DISK.MediaInfo.SectorSize]
646
        DEBUGF 1,'K : sector size is %d, only 512 is supported\n',[esi+DISK.MediaInfo.SectorSize]
650
        ret
647
        ret
651
.doscan:
648
.doscan:
652
; 3. Acquire the buffer for MBR and bootsector tests. See the comment before
649
; 3. Acquire the buffer for MBR and bootsector tests. See the comment before
653
; the 'partition_buffer_users' variable.
650
; the 'partition_buffer_users' variable.
654
        mov     ebx, mbr_buffer         ; assume the global buffer is free
651
        mov     ebx, mbr_buffer         ; assume the global buffer is free
655
        lock inc [partition_buffer_users]
652
        lock inc [partition_buffer_users]
656
        jz      .buffer_acquired        ; yes, it is free
653
        jz      .buffer_acquired        ; yes, it is free
657
        lock dec [partition_buffer_users]       ; no, we must allocate
654
        lock dec [partition_buffer_users]       ; no, we must allocate
658
        stdcall kernel_alloc, 512*3
655
        stdcall kernel_alloc, 512*3
659
        test    eax, eax
656
        test    eax, eax
660
        jz      .nothing
657
        jz      .nothing
661
        xchg    eax, ebx
658
        xchg    eax, ebx
662
.buffer_acquired:
659
.buffer_acquired:
663
; MBR/EBRs are organized in the chain. We use a loop over MBR/EBRs, but no
660
; MBR/EBRs are organized in the chain. We use a loop over MBR/EBRs, but no
664
; more than MAX_NUM_PARTITION times.
661
; more than MAX_NUM_PARTITION times.
665
; 4. Prepare things for the loop.
662
; 4. Prepare things for the loop.
666
; ebp will hold the sector number for current MBR/EBR.
663
; ebp will hold the sector number for current MBR/EBR.
667
; [esp] will hold the sector number for current extended partition, if there
664
; [esp] will hold the sector number for current extended partition, if there
668
; is one.
665
; is one.
669
; [esp+4] will hold the counter that prevents long loops.
666
; [esp+4] will hold the counter that prevents long loops.
670
        push    ebp             ; save ebp
667
        push    ebp             ; save ebp
671
        push    MAX_NUM_PARTITIONS      ; the counter of max MBRs to process
668
        push    MAX_NUM_PARTITIONS      ; the counter of max MBRs to process
672
        xor     ebp, ebp        ; start from sector zero
669
        xor     ebp, ebp        ; start from sector zero
673
        push    ebp             ; no extended partition yet
670
        push    ebp             ; no extended partition yet
674
.new_mbr:
671
.new_mbr:
675
; 5. Read the current sector.
672
; 5. Read the current sector.
676
; Note that 'read' callback operates with 64-bit sector numbers, so we must
673
; Note that 'read' callback operates with 64-bit sector numbers, so we must
677
; push additional zero as a high dword of sector number.
674
; push additional zero as a high dword of sector number.
678
        mov     al, DISKFUNC.read
675
        mov     al, DISKFUNC.read
679
        push    1
676
        push    1
680
        stdcall disk_call_driver, ebx, ebp, 0, esp
677
        stdcall disk_call_driver, ebx, ebp, 0, esp
681
        pop     ecx
678
        pop     ecx
682
; 6. If the read has failed, abort the loop.
679
; 6. If the read has failed, abort the loop.
683
        dec     ecx
680
        dec     ecx
684
        jnz     .mbr_failed
681
        jnz     .mbr_failed
685
; 7. Check the MBR/EBR signature. If it is wrong, abort the loop.
682
; 7. Check the MBR/EBR signature. If it is wrong, abort the loop.
686
; Soon we will access the partition table which starts at ebx+0x1BE,
683
; Soon we will access the partition table which starts at ebx+0x1BE,
687
; so we can fill its address right now. If we do it now, then the addressing
684
; so we can fill its address right now. If we do it now, then the addressing
688
; [ecx+0x40] is shorter than [ebx+0x1fe]: one-byte offset vs 4-bytes offset.
685
; [ecx+0x40] is shorter than [ebx+0x1fe]: one-byte offset vs 4-bytes offset.
689
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
686
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
690
        cmp     word [ecx+0x40], 0xaa55
687
        cmp     word [ecx+0x40], 0xaa55
691
        jnz     .mbr_failed
688
        jnz     .mbr_failed
692
; 8. The MBR is treated differently from EBRs. For MBR we additionally need to
689
; 8. The MBR is treated differently from EBRs. For MBR we additionally need to
693
; execute step 9 and possibly step 10.
690
; execute step 9 and possibly step 10.
694
        test    ebp, ebp
691
        test    ebp, ebp
695
        jnz     .mbr
692
        jnz     .mbr
696
; The partition table can be present or not present. In the first case, we just
693
; The partition table can be present or not present. In the first case, we just
697
; read the MBR. In the second case, we just read the bootsector for a
694
; read the MBR. In the second case, we just read the bootsector for a
698
; filesystem.
695
; filesystem.
699
; The following algorithm is used to distinguish between these cases.
696
; The following algorithm is used to distinguish between these cases.
700
; A. If at least one entry of the partition table is invalid, this is
697
; A. If at least one entry of the partition table is invalid, this is
701
;    a bootsector. See the description of 'is_partition_table_entry' for
698
;    a bootsector. See the description of 'is_partition_table_entry' for
702
;    definition of validity.
699
;    definition of validity.
703
; B. If all entries are empty (filesystem type field is zero) and the first
700
; B. If all entries are empty (filesystem type field is zero) and the first
704
;    byte is jmp opcode (0EBh or 0E9h), this is a bootsector which happens to
701
;    byte is jmp opcode (0EBh or 0E9h), this is a bootsector which happens to
705
;    have zeros in the place of partition table.
702
;    have zeros in the place of partition table.
706
; C. Otherwise, this is an MBR.
703
; C. Otherwise, this is an MBR.
707
; 9. Test for MBR vs bootsector.
704
; 9. Test for MBR vs bootsector.
708
; 9a. Check entries. If any is invalid, go to 10 (rule A).
705
; 9a. Check entries. If any is invalid, go to 10 (rule A).
709
        call    is_partition_table_entry
706
        call    is_partition_table_entry
710
        jc      .notmbr
707
        jc      .notmbr
711
        add     ecx, 10h
708
        add     ecx, 10h
712
        call    is_partition_table_entry
709
        call    is_partition_table_entry
713
        jc      .notmbr
710
        jc      .notmbr
714
        add     ecx, 10h
711
        add     ecx, 10h
715
        call    is_partition_table_entry
712
        call    is_partition_table_entry
716
        jc      .notmbr
713
        jc      .notmbr
717
        add     ecx, 10h
714
        add     ecx, 10h
718
        call    is_partition_table_entry
715
        call    is_partition_table_entry
719
        jc      .notmbr
716
        jc      .notmbr
720
; 9b. Check types of the entries. If at least one is nonzero, go to 11 (rule C).
717
; 9b. Check types of the entries. If at least one is nonzero, go to 11 (rule C).
721
        mov     al, [ecx-30h+PARTITION_TABLE_ENTRY.Type]
718
        mov     al, [ecx-30h+PARTITION_TABLE_ENTRY.Type]
722
        or      al, [ecx-20h+PARTITION_TABLE_ENTRY.Type]
719
        or      al, [ecx-20h+PARTITION_TABLE_ENTRY.Type]
723
        or      al, [ecx-10h+PARTITION_TABLE_ENTRY.Type]
720
        or      al, [ecx-10h+PARTITION_TABLE_ENTRY.Type]
724
        or      al, [ecx+PARTITION_TABLE_ENTRY.Type]
721
        or      al, [ecx+PARTITION_TABLE_ENTRY.Type]
725
        jnz     .mbr
722
        jnz     .mbr
726
; 9c. Empty partition table or bootsector with many zeroes? (rule B)
723
; 9c. Empty partition table or bootsector with many zeroes? (rule B)
727
        cmp     byte [ebx], 0EBh
724
        cmp     byte [ebx], 0EBh
728
        jz      .notmbr
725
        jz      .notmbr
729
        cmp     byte [ebx], 0E9h
726
        cmp     byte [ebx], 0E9h
730
        jnz     .mbr
727
        jnz     .mbr
731
.notmbr:
728
.notmbr:
732
; 10. This is not an  MBR. The media is not partitioned. Create one partition
729
; 10. This is not an  MBR. The media is not partitioned. Create one partition
733
; which covers all the media and abort the loop.
730
; which covers all the media and abort the loop.
734
        stdcall disk_add_partition, 0, 0, \
731
        stdcall disk_add_partition, 0, 0, \
735
                dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4]
732
                dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4]
736
        jmp     .done
733
        jmp     .done
737
.mbr:
734
.mbr:
738
; 11. Process all entries of the new MBR/EBR
735
; 11. Process all entries of the new MBR/EBR
739
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
736
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
740
        push    0       ; assume no extended partition
737
        push    0       ; assume no extended partition
741
        call    process_partition_table_entry
738
        call    process_partition_table_entry
742
        add     ecx, 10h
739
        add     ecx, 10h
743
        call    process_partition_table_entry
740
        call    process_partition_table_entry
744
        add     ecx, 10h
741
        add     ecx, 10h
745
        call    process_partition_table_entry
742
        call    process_partition_table_entry
746
        add     ecx, 10h
743
        add     ecx, 10h
747
        call    process_partition_table_entry
744
        call    process_partition_table_entry
748
        pop     ebp
745
        pop     ebp
749
; 12. Test whether we found a new EBR and should continue the loop.
746
; 12. Test whether we found a new EBR and should continue the loop.
750
; 12a. If there was no next EBR, return.
747
; 12a. If there was no next EBR, return.
751
        test    ebp, ebp
748
        test    ebp, ebp
752
        jz      .done
749
        jz      .done
753
; Ok, we have EBR.
750
; Ok, we have EBR.
754
; 12b. EBRs addresses are relative to the start of extended partition.
751
; 12b. EBRs addresses are relative to the start of extended partition.
755
; For simplicity, just abort if an 32-bit overflow occurs; large disks
752
; For simplicity, just abort if an 32-bit overflow occurs; large disks
756
; are most likely partitioned with GPT, not MBR scheme, since the precise
753
; are most likely partitioned with GPT, not MBR scheme, since the precise
757
; calculation here would increase limit just twice at the price of big
754
; calculation here would increase limit just twice at the price of big
758
; compatibility problems.
755
; compatibility problems.
759
        pop     eax     ; load extended partition
756
        pop     eax     ; load extended partition
760
        add     ebp, eax
757
        add     ebp, eax
761
        jc      .mbr_failed
758
        jc      .mbr_failed
762
; 12c. If extended partition has not yet started, start it.
759
; 12c. If extended partition has not yet started, start it.
763
        test    eax, eax
760
        test    eax, eax
764
        jnz     @f
761
        jnz     @f
765
        mov     eax, ebp
762
        mov     eax, ebp
766
@@:
763
@@:
767
; 12c. If the limit is not exceeded, continue the loop.
764
; 12c. If the limit is not exceeded, continue the loop.
768
        dec     dword [esp]
765
        dec     dword [esp]
769
        push    eax     ; store extended partition
766
        push    eax     ; store extended partition
770
        jnz     .new_mbr
767
        jnz     .new_mbr
771
.mbr_failed:
768
.mbr_failed:
772
.done:
769
.done:
773
; 13. Cleanup after the loop.
770
; 13. Cleanup after the loop.
774
        pop     eax     ; not important anymore
771
        pop     eax     ; not important anymore
775
        pop     eax     ; not important anymore
772
        pop     eax     ; not important anymore
776
        pop     ebp     ; restore ebp
773
        pop     ebp     ; restore ebp
777
; 14. Release the buffer.
774
; 14. Release the buffer.
778
; 14a. Test whether it is the global buffer or we have allocated it.
775
; 14a. Test whether it is the global buffer or we have allocated it.
779
        cmp     ebx, mbr_buffer
776
        cmp     ebx, mbr_buffer
780
        jz      .release_partition_buffer
777
        jz      .release_partition_buffer
781
; 14b. If we have allocated it, free it.
778
; 14b. If we have allocated it, free it.
782
        xchg    eax, ebx
779
        xchg    eax, ebx
783
        call    free
780
        call    free
784
        jmp     .nothing
781
        jmp     .nothing
785
; 14c. Otherwise, release reference.
782
; 14c. Otherwise, release reference.
786
.release_partition_buffer:
783
.release_partition_buffer:
787
        lock dec [partition_buffer_users]
784
        lock dec [partition_buffer_users]
788
.nothing:
785
.nothing:
789
; 15. Return.
786
; 15. Return.
790
        ret
787
        ret
791
 
788
 
792
; This is an internal function called from disk_scan_partitions. It checks
789
; This is an internal function called from disk_scan_partitions. It checks
793
; whether the entry pointed to by ecx is a valid entry of partition table.
790
; whether the entry pointed to by ecx is a valid entry of partition table.
794
; The entry is valid if the first byte is 0 or 80h, the first sector plus the
791
; The entry is valid if the first byte is 0 or 80h, the first sector plus the
795
; length is less than twice the size of media. Multiplication by two is
792
; length is less than twice the size of media. Multiplication by two is
796
; required since the size mentioned in the partition table can be slightly
793
; required since the size mentioned in the partition table can be slightly
797
; greater than the real size.
794
; greater than the real size.
798
is_partition_table_entry:
795
is_partition_table_entry:
799
; 1. Check .Bootable field.
796
; 1. Check .Bootable field.
800
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Bootable]
797
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Bootable]
801
        and     al, 7Fh
798
        and     al, 7Fh
802
        jnz     .invalid
799
        jnz     .invalid
803
; 3. Calculate first sector + length. Note that .FirstAbsSector is relative
800
; 3. Calculate first sector + length. Note that .FirstAbsSector is relative
804
; to the MBR/EBR, so the real sum is ebp + .FirstAbsSector + .Length.
801
; to the MBR/EBR, so the real sum is ebp + .FirstAbsSector + .Length.
805
        mov     eax, ebp
802
        mov     eax, ebp
806
        xor     edx, edx
803
        xor     edx, edx
807
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
804
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
808
        adc     edx, 0
805
        adc     edx, 0
809
        add     eax, [ecx+PARTITION_TABLE_ENTRY.Length]
806
        add     eax, [ecx+PARTITION_TABLE_ENTRY.Length]
810
        adc     edx, 0
807
        adc     edx, 0
811
; 4. Divide by two.
808
; 4. Divide by two.
812
        shr     edx, 1
809
        shr     edx, 1
813
        rcr     eax, 1
810
        rcr     eax, 1
814
; 5. Compare with capacity. If the subtraction (edx:eax) - .Capacity does not
811
; 5. Compare with capacity. If the subtraction (edx:eax) - .Capacity does not
815
; overflow, this is bad.
812
; overflow, this is bad.
816
        sub     eax, dword [esi+DISK.MediaInfo.Capacity]
813
        sub     eax, dword [esi+DISK.MediaInfo.Capacity]
817
        sbb     edx, dword [esi+DISK.MediaInfo.Capacity+4]
814
        sbb     edx, dword [esi+DISK.MediaInfo.Capacity+4]
818
        jnc     .invalid
815
        jnc     .invalid
819
.valid:
816
.valid:
820
; 5. Return success: CF is cleared.
817
; 5. Return success: CF is cleared.
821
        clc
818
        clc
822
        ret
819
        ret
823
.invalid:
820
.invalid:
824
; 6. Return fail: CF is set.
821
; 6. Return fail: CF is set.
825
        stc
822
        stc
826
        ret
823
        ret
827
 
824
 
828
; This is an internal function called from disk_scan_partitions. It processes
825
; This is an internal function called from disk_scan_partitions. It processes
829
; the entry pointed to by ecx.
826
; the entry pointed to by ecx.
830
; * If the entry is invalid, just ignore this entry.
827
; * If the entry is invalid, just ignore this entry.
831
; * If the type is zero, just ignore this entry.
828
; * If the type is zero, just ignore this entry.
832
; * If the type is one of types for extended partition, store the address
829
; * If the type is one of types for extended partition, store the address
833
;   of this partition as the new MBR in [esp+4].
830
;   of this partition as the new MBR in [esp+4].
834
; * Otherwise, add the partition to the list of partitions for this disk.
831
; * Otherwise, add the partition to the list of partitions for this disk.
835
;   We don't use the type from the entry to identify the file system;
832
;   We don't use the type from the entry to identify the file system;
836
;   fs-specific checks do this more reliably.
833
;   fs-specific checks do this more reliably.
837
process_partition_table_entry:
834
process_partition_table_entry:
838
; 1. Check for valid entry. If invalid, return (go to 5).
835
; 1. Check for valid entry. If invalid, return (go to 5).
839
        call    is_partition_table_entry
836
        call    is_partition_table_entry
840
        jc      .nothing
837
        jc      .nothing
841
; 2. Check for empty entry. If invalid, return (go to 5).
838
; 2. Check for empty entry. If invalid, return (go to 5).
842
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Type]
839
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Type]
843
        test    al, al
840
        test    al, al
844
        jz      .nothing
841
        jz      .nothing
845
; 3. Check for extended partition. If extended, go to 6.
842
; 3. Check for extended partition. If extended, go to 6.
846
irp type,\
843
irp type,\
847
    0x05,\                 ; DOS: extended partition
844
    0x05,\                 ; DOS: extended partition
848
    0x0f,\                 ; WIN95: extended partition, LBA-mapped
845
    0x0f,\                 ; WIN95: extended partition, LBA-mapped
849
    0xc5,\                 ; DRDOS/secured: extended partition
846
    0xc5,\                 ; DRDOS/secured: extended partition
850
    0xd5                   ; Old Multiuser DOS secured: extended partition
847
    0xd5                   ; Old Multiuser DOS secured: extended partition
851
{
848
{
852
        cmp     al, type
849
        cmp     al, type
853
        jz      .extended
850
        jz      .extended
854
}
851
}
855
; 4. If we are here, that is a normal partition. Add it to the list.
852
; 4. If we are here, that is a normal partition. Add it to the list.
856
; Note that the first sector is relative to MBR/EBR.
853
; Note that the first sector is relative to MBR/EBR.
857
        mov     eax, ebp
854
        mov     eax, ebp
858
        xor     edx, edx
855
        xor     edx, edx
859
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
856
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
860
        adc     edx, 0
857
        adc     edx, 0
861
        push    ecx
858
        push    ecx
862
        stdcall disk_add_partition, eax, edx, \
859
        stdcall disk_add_partition, eax, edx, \
863
                [ecx+PARTITION_TABLE_ENTRY.Length], 0
860
                [ecx+PARTITION_TABLE_ENTRY.Length], 0
864
        pop     ecx
861
        pop     ecx
865
.nothing:
862
.nothing:
866
; 5. Return.
863
; 5. Return.
867
        ret
864
        ret
868
.extended:
865
.extended:
869
; 6. If we are here, that is an extended partition. Store the address.
866
; 6. If we are here, that is an extended partition. Store the address.
870
        mov     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
867
        mov     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
871
        mov     [esp+4], eax
868
        mov     [esp+4], eax
872
        ret
869
        ret
873
 
870
 
874
; This is an internal function called from disk_scan_partitions and
871
; This is an internal function called from disk_scan_partitions and
875
; process_partition_table_entry. It adds one partition to the list of
872
; process_partition_table_entry. It adds one partition to the list of
876
; partitions for the media.
873
; partitions for the media.
877
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword
874
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword
878
; 1. Check that this partition will not exceed the limit on total number.
875
; 1. Check that this partition will not exceed the limit on total number.
879
        cmp     [esi+DISK.NumPartitions], MAX_NUM_PARTITIONS
876
        cmp     [esi+DISK.NumPartitions], MAX_NUM_PARTITIONS
880
        jae     .nothing
877
        jae     .nothing
881
; 2. Check that this partition does not overlap with any already registered
878
; 2. Check that this partition does not overlap with any already registered
882
; partition. Since any file system assumes that the disk data will not change
879
; partition. Since any file system assumes that the disk data will not change
883
; outside of its control, such overlap could be destructive.
880
; outside of its control, such overlap could be destructive.
884
; Since the number of partitions is usually very small and is guaranteed not
881
; Since the number of partitions is usually very small and is guaranteed not
885
; to be large, the simple linear search is sufficient.
882
; to be large, the simple linear search is sufficient.
886
; 2a. Prepare the loop: edi will point to the current item of .Partitions
883
; 2a. Prepare the loop: edi will point to the current item of .Partitions
887
; array, ecx will be the current item, ebx will hold number of items left.
884
; array, ecx will be the current item, ebx will hold number of items left.
888
        mov     edi, [esi+DISK.Partitions]
885
        mov     edi, [esi+DISK.Partitions]
889
        mov     ebx, [esi+DISK.NumPartitions]
886
        mov     ebx, [esi+DISK.NumPartitions]
890
        test    ebx, ebx
887
        test    ebx, ebx
891
        jz      .partitionok
888
        jz      .partitionok
892
.scan_existing:
889
.scan_existing:
893
; 2b. Get the next partition.
890
; 2b. Get the next partition.
894
        mov     ecx, [edi]
891
        mov     ecx, [edi]
895
        add     edi, 4
892
        add     edi, 4
896
; The range [.FirstSector, .FirstSector+.Length) must be either entirely to
893
; The range [.FirstSector, .FirstSector+.Length) must be either entirely to
897
; the left of [start, start+length) or entirely to the right.
894
; the left of [start, start+length) or entirely to the right.
898
; 2c. Subtract .FirstSector - start. The possible overflow distinguish between
895
; 2c. Subtract .FirstSector - start. The possible overflow distinguish between
899
; cases "to the left" (2e) and "to the right" (2d).
896
; cases "to the left" (2e) and "to the right" (2d).
900
        mov     eax, dword [ecx+PARTITION.FirstSector]
897
        mov     eax, dword [ecx+PARTITION.FirstSector]
901
        mov     edx, dword [ecx+PARTITION.FirstSector+4]
898
        mov     edx, dword [ecx+PARTITION.FirstSector+4]
902
        sub     eax, dword [start]
899
        sub     eax, dword [start]
903
        sbb     edx, dword [start+4]
900
        sbb     edx, dword [start+4]
904
        jb      .less
901
        jb      .less
905
; 2d. .FirstSector is greater than or equal to start. Check that .FirstSector
902
; 2d. .FirstSector is greater than or equal to start. Check that .FirstSector
906
; is greater than or equal to start+length; the subtraction
903
; is greater than or equal to start+length; the subtraction
907
; (.FirstSector-start) - length must not cause overflow. Go to 2g if life is
904
; (.FirstSector-start) - length must not cause overflow. Go to 2g if life is
908
; good or to 2f in the other case.
905
; good or to 2f in the other case.
909
        sub     eax, dword [length]
906
        sub     eax, dword [length]
910
        sbb     edx, dword [length+4]
907
        sbb     edx, dword [length+4]
911
        jb      .overlap
908
        jb      .overlap
912
        jmp     .next_existing
909
        jmp     .next_existing
913
.less:
910
.less:
914
; 2e. .FirstSector is less than start. Check that .FirstSector+.Length is less
911
; 2e. .FirstSector is less than start. Check that .FirstSector+.Length is less
915
; than or equal to start. If the addition (.FirstSector-start) + .Length does
912
; than or equal to start. If the addition (.FirstSector-start) + .Length does
916
; not cause overflow, then .FirstSector + .Length is strictly less than start;
913
; not cause overflow, then .FirstSector + .Length is strictly less than start;
917
; since the equality is also valid, use decrement preliminarily. Go to 2g or
914
; since the equality is also valid, use decrement preliminarily. Go to 2g or
918
; 2f depending on the overflow.
915
; 2f depending on the overflow.
919
        sub     eax, 1
916
        sub     eax, 1
920
        sbb     edx, 0
917
        sbb     edx, 0
921
        add     eax, dword [ecx+PARTITION.Length]
918
        add     eax, dword [ecx+PARTITION.Length]
922
        adc     edx, dword [ecx+PARTITION.Length+4]
919
        adc     edx, dword [ecx+PARTITION.Length+4]
923
        jnc     .next_existing
920
        jnc     .next_existing
924
.overlap:
921
.overlap:
925
; 2f. The partition overlaps with previously registered partition. Say warning
922
; 2f. The partition overlaps with previously registered partition. Say warning
926
; and return with nothing done.
923
; and return with nothing done.
927
        dbgstr 'two partitions overlap, ignoring the last one'
924
        dbgstr 'two partitions overlap, ignoring the last one'
928
        jmp     .nothing
925
        jmp     .nothing
929
.next_existing:
926
.next_existing:
930
; 2g. The partition does not overlap with the current partition. Continue the
927
; 2g. The partition does not overlap with the current partition. Continue the
931
; loop.
928
; loop.
932
        dec     ebx
929
        dec     ebx
933
        jnz     .scan_existing
930
        jnz     .scan_existing
934
.partitionok:
931
.partitionok:
935
; 3. The partition has passed tests. Reallocate the partitions array for a new
932
; 3. The partition has passed tests. Reallocate the partitions array for a new
936
; entry.
933
; entry.
937
; 3a. Call the allocator.
934
; 3a. Call the allocator.
938
        mov     eax, [esi+DISK.NumPartitions]
935
        mov     eax, [esi+DISK.NumPartitions]
939
        inc     eax     ; one more entry
936
        inc     eax     ; one more entry
940
        shl     eax, 2  ; each entry is dword
937
        shl     eax, 2  ; each entry is dword
941
        call    malloc
938
        call    malloc
942
; 3b. Test the result. If failed, return with nothing done.
939
; 3b. Test the result. If failed, return with nothing done.
943
        test    eax, eax
940
        test    eax, eax
944
        jz      .nothing
941
        jz      .nothing
945
; 3c. Copy the old array to the new array.
942
; 3c. Copy the old array to the new array.
946
        mov     edi, eax
943
        mov     edi, eax
947
        push    esi
944
        push    esi
948
        mov     ecx, [esi+DISK.NumPartitions]
945
        mov     ecx, [esi+DISK.NumPartitions]
949
        mov     esi, [esi+DISK.Partitions]
946
        mov     esi, [esi+DISK.Partitions]
950
        rep movsd
947
        rep movsd
951
        pop     esi
948
        pop     esi
952
; 3d. Set the field in the DISK structure to the new array.
949
; 3d. Set the field in the DISK structure to the new array.
953
        xchg    [esi+DISK.Partitions], eax
950
        xchg    [esi+DISK.Partitions], eax
954
; 3e. Free the old array.
951
; 3e. Free the old array.
955
        call    free
952
        call    free
956
; 4. Recognize the file system.
953
; 4. Recognize the file system.
957
; 4a. Call the filesystem recognizer. It will allocate the PARTITION structure
954
; 4a. Call the filesystem recognizer. It will allocate the PARTITION structure
958
; with possible filesystem-specific fields.
955
; with possible filesystem-specific fields.
959
        call    disk_detect_partition
956
        call    disk_detect_partition
960
; 4b. Check return value. If zero, return with list not changed; so far only
957
; 4b. Check return value. If zero, return with list not changed; so far only
961
; the array was reallocated, this is ok for other code.
958
; the array was reallocated, this is ok for other code.
962
        test    eax, eax
959
        test    eax, eax
963
        jz      .nothing
960
        jz      .nothing
964
; 5. Insert the new partition to the list.
961
; 5. Insert the new partition to the list.
965
        stosd
962
        stosd
966
        inc     [esi+DISK.NumPartitions]
963
        inc     [esi+DISK.NumPartitions]
967
; 6. Return.
964
; 6. Return.
968
.nothing:
965
.nothing:
969
        ret
966
        ret
970
endp
967
endp
971
 
968
 
972
; This is an internal function called from disk_add_partition.
969
; This is an internal function called from disk_add_partition.
973
; It tries to recognize the file system on the partition and allocates the
970
; It tries to recognize the file system on the partition and allocates the
974
; corresponding PARTITION structure with filesystem-specific fields.
971
; corresponding PARTITION structure with filesystem-specific fields.
975
disk_detect_partition:
972
disk_detect_partition:
976
; This function inherits the stack frame from disk_add_partition. In stdcall
973
; This function inherits the stack frame from disk_add_partition. In stdcall
977
; with ebp-based frame arguments start from ebp+8, since [ebp]=saved ebp
974
; with ebp-based frame arguments start from ebp+8, since [ebp]=saved ebp
978
; and [ebp+4]=return address.
975
; and [ebp+4]=return address.
979
virtual at ebp+8
976
virtual at ebp+8
980
.start  dq      ?
977
.start  dq      ?
981
.length dq      ?
978
.length dq      ?
982
end virtual
979
end virtual
983
; When disk_add_partition is called, ebx contains a pointer to
980
; When disk_add_partition is called, ebx contains a pointer to
984
; a two-sectors-sized buffer. This function saves ebx in the stack
981
; a two-sectors-sized buffer. This function saves ebx in the stack
985
; immediately before ebp.
982
; immediately before ebp.
986
virtual at ebp-4
983
virtual at ebp-4
987
.buffer dd      ?
984
.buffer dd      ?
988
end virtual
985
end virtual
989
; 1. Read the bootsector to the buffer.
986
; 1. Read the bootsector to the buffer.
990
        mov     al, DISKFUNC.read
987
        mov     al, DISKFUNC.read
991
        mov     ebx, [.buffer]
988
        mov     ebx, [.buffer]
992
        add     ebx, 512
989
        add     ebx, 512
993
        push    1
990
        push    1
994
        stdcall disk_call_driver, ebx, dword [.start], dword [.start+4], esp
991
        stdcall disk_call_driver, ebx, dword [.start], dword [.start+4], esp
995
; 2. Run tests for all supported filesystems. If at least one test succeeded,
992
; 2. Run tests for all supported filesystems. If at least one test succeeded,
996
; go to 4.
993
; go to 4.
997
; For tests: qword [ebp+8] = partition start, qword [ebp+10h] = partition
994
; For tests: qword [ebp+8] = partition start, qword [ebp+10h] = partition
998
; length, [esp] = 0 if reading bootsector failed or 1 if succeeded,
995
; length, [esp] = 0 if reading bootsector failed or 1 if succeeded,
999
; ebx points to the buffer for bootsector.
996
; ebx points to the buffer for bootsector.
1000
        call    fat_create_partition
997
        call    fat_create_partition
1001
        test    eax, eax
998
        test    eax, eax
1002
        jnz     .success
999
        jnz     .success
1003
; 3. No file system has recognized the volume, so just allocate the PARTITION
1000
; 3. No file system has recognized the volume, so just allocate the PARTITION
1004
; structure without extra fields.
1001
; structure without extra fields.
1005
        push    sizeof.PARTITION
1002
        movi    eax, sizeof.PARTITION
1006
        pop     eax
-
 
1007
        call    malloc
1003
        call    malloc
1008
        test    eax, eax
1004
        test    eax, eax
1009
        jz      .nothing
1005
        jz      .nothing
1010
        mov     edx, dword [.start]
1006
        mov     edx, dword [.start]
1011
        mov     dword [eax+PARTITION.FirstSector], edx
1007
        mov     dword [eax+PARTITION.FirstSector], edx
1012
        mov     edx, dword [.start+4]
1008
        mov     edx, dword [.start+4]
1013
        mov     dword [eax+PARTITION.FirstSector+4], edx
1009
        mov     dword [eax+PARTITION.FirstSector+4], edx
1014
        mov     edx, dword [.length]
1010
        mov     edx, dword [.length]
1015
        mov     dword [eax+PARTITION.Length], edx
1011
        mov     dword [eax+PARTITION.Length], edx
1016
        mov     edx, dword [.length+4]
1012
        mov     edx, dword [.length+4]
1017
        mov     dword [eax+PARTITION.Length+4], edx
1013
        mov     dword [eax+PARTITION.Length+4], edx
1018
        mov     [eax+PARTITION.Disk], esi
1014
        mov     [eax+PARTITION.Disk], esi
1019
        and     [eax+PARTITION.FSUserFunctions], 0
1015
        and     [eax+PARTITION.FSUserFunctions], 0
1020
.success:
1016
.success:
1021
.nothing:
1017
.nothing:
1022
; 4. Return with eax = pointer to PARTITION or NULL.
1018
; 4. Return with eax = pointer to PARTITION or NULL.
1023
        pop     ecx
1019
        pop     ecx
1024
        ret
1020
        ret
1025
 
1021
 
1026
; This function is called from file_system_lfn.
1022
; This function is called from file_system_lfn.
1027
; This handler gets the control each time when fn 70 is called
1023
; This handler gets the control each time when fn 70 is called
1028
; with unknown item of root subdirectory.
1024
; with unknown item of root subdirectory.
1029
; in: esi -> name
1025
; in: esi -> name
1030
;     ebp = 0 or rest of name relative to esi
1026
;     ebp = 0 or rest of name relative to esi
1031
; out: if the handler processes path, it must not return in file_system_lfn,
1027
; out: if the handler processes path, it must not return in file_system_lfn,
1032
;      but instead pop return address and return directly to the caller
1028
;      but instead pop return address and return directly to the caller
1033
;      otherwise simply return
1029
;      otherwise simply return
1034
dyndisk_handler:
1030
dyndisk_handler:
1035
        push    ebx edi         ; save registers used in file_system_lfn
1031
        push    ebx edi         ; save registers used in file_system_lfn
1036
; 1. Acquire the mutex.
1032
; 1. Acquire the mutex.
1037
        mov     ecx, disk_list_mutex
1033
        mov     ecx, disk_list_mutex
1038
        call    mutex_lock
1034
        call    mutex_lock
1039
; 2. Loop over the list of DISK structures.
1035
; 2. Loop over the list of DISK structures.
1040
; 2a. Initialize.
1036
; 2a. Initialize.
1041
        mov     ebx, disk_list
1037
        mov     ebx, disk_list
1042
.scan:
1038
.scan:
1043
; 2b. Get the next item.
1039
; 2b. Get the next item.
1044
        mov     ebx, [ebx+DISK.Next]
1040
        mov     ebx, [ebx+DISK.Next]
1045
; 2c. Check whether the list is done. If so, go to 3.
1041
; 2c. Check whether the list is done. If so, go to 3.
1046
        cmp     ebx, disk_list
1042
        cmp     ebx, disk_list
1047
        jz      .notfound
1043
        jz      .notfound
1048
; 2d. Compare names. If names match, go to 5.
1044
; 2d. Compare names. If names match, go to 5.
1049
        mov     edi, [ebx+DISK.Name]
1045
        mov     edi, [ebx+DISK.Name]
1050
        push    esi
1046
        push    esi
1051
@@:
1047
@@:
1052
; esi points to the name from fs operation; it is terminated by zero or slash.
1048
; esi points to the name from fs operation; it is terminated by zero or slash.
1053
        lodsb
1049
        lodsb
1054
        test    al, al
1050
        test    al, al
1055
        jz      .eoin_dec
1051
        jz      .eoin_dec
1056
        cmp     al, '/'
1052
        cmp     al, '/'
1057
        jz      .eoin
1053
        jz      .eoin
1058
; edi points to the disk name.
1054
; edi points to the disk name.
1059
        inc     edi
1055
        inc     edi
1060
; edi points to lowercase name, this is a requirement for the driver.
1056
; edi points to lowercase name, this is a requirement for the driver.
1061
; Characters at esi can have any register. Lowercase the current character.
1057
; Characters at esi can have any register. Lowercase the current character.
1062
; This lowercasing works for latin letters and digits; since the disk name
1058
; This lowercasing works for latin letters and digits; since the disk name
1063
; should not contain other symbols, this is ok.
1059
; should not contain other symbols, this is ok.
1064
        or      al, 20h
1060
        or      al, 20h
1065
        cmp     al, [edi-1]
1061
        cmp     al, [edi-1]
1066
        jz      @b
1062
        jz      @b
1067
.wrongname:
1063
.wrongname:
1068
; 2f. Names don't match. Continue the loop.
1064
; 2f. Names don't match. Continue the loop.
1069
        pop     esi
1065
        pop     esi
1070
        jmp     .scan
1066
        jmp     .scan
1071
.notfound:
1067
.notfound:
1072
; The loop is done and no name matches.
1068
; The loop is done and no name matches.
1073
; 3. Release the mutex.
1069
; 3. Release the mutex.
1074
        call    mutex_unlock
1070
        call    mutex_unlock
1075
; 4. Return normally.
1071
; 4. Return normally.
1076
        pop     edi ebx         ; restore registers used in file_system_lfn
1072
        pop     edi ebx         ; restore registers used in file_system_lfn
1077
        ret
1073
        ret
1078
; part of 2d: the name matches partially, but we must check that this is full
1074
; part of 2d: the name matches partially, but we must check that this is full
1079
; equality.
1075
; equality.
1080
.eoin_dec:
1076
.eoin_dec:
1081
        dec     esi
1077
        dec     esi
1082
.eoin:
1078
.eoin:
1083
        cmp     byte [edi], 0
1079
        cmp     byte [edi], 0
1084
        jnz     .wrongname
1080
        jnz     .wrongname
1085
; We found the addressed DISK structure.
1081
; We found the addressed DISK structure.
1086
; 5. Reference the disk.
1082
; 5. Reference the disk.
1087
        lock inc [ebx+DISK.RefCount]
1083
        lock inc [ebx+DISK.RefCount]
1088
; 6. Now we are sure that the DISK structure is not going to die at least
1084
; 6. Now we are sure that the DISK structure is not going to die at least
1089
; while we are working with it, so release the global mutex.
1085
; while we are working with it, so release the global mutex.
1090
        call    mutex_unlock
1086
        call    mutex_unlock
1091
        pop     ecx             ; pop from the stack saved value of esi
1087
        pop     ecx             ; pop from the stack saved value of esi
1092
; 7. Acquire the mutex for media object.
1088
; 7. Acquire the mutex for media object.
1093
        pop     edi             ; restore edi
1089
        pop     edi             ; restore edi
1094
        lea     ecx, [ebx+DISK.MediaLock]
1090
        lea     ecx, [ebx+DISK.MediaLock]
1095
        call    mutex_lock
1091
        call    mutex_lock
1096
; 8. Get the media object. If it is not NULL, reference it.
1092
; 8. Get the media object. If it is not NULL, reference it.
1097
        xor     edx, edx
1093
        xor     edx, edx
1098
        cmp     [ebx+DISK.MediaInserted], dl
1094
        cmp     [ebx+DISK.MediaInserted], dl
1099
        jz      @f
1095
        jz      @f
1100
        mov     edx, ebx
1096
        mov     edx, ebx
1101
        inc     [ebx+DISK.MediaRefCount]
1097
        inc     [ebx+DISK.MediaRefCount]
1102
@@:
1098
@@:
1103
; 9. Now we are sure that the media object, if it exists, is not going to die
1099
; 9. Now we are sure that the media object, if it exists, is not going to die
1104
; at least while we are working with it, so release the mutex for media object.
1100
; at least while we are working with it, so release the mutex for media object.
1105
        call    mutex_unlock
1101
        call    mutex_unlock
1106
        mov     ecx, ebx
1102
        mov     ecx, ebx
1107
        pop     ebx eax         ; restore ebx, pop return address
1103
        pop     ebx eax         ; restore ebx, pop return address
1108
; 10. Check whether the fs operation wants to enumerate partitions (go to 11)
1104
; 10. Check whether the fs operation wants to enumerate partitions (go to 11)
1109
; or work with some concrete partition (go to 12).
1105
; or work with some concrete partition (go to 12).
1110
        cmp     byte [esi], 0
1106
        cmp     byte [esi], 0
1111
        jnz     .haspartition
1107
        jnz     .haspartition
1112
; 11. The fs operation wants to enumerate partitions.
1108
; 11. The fs operation wants to enumerate partitions.
1113
; 11a. Only "list directory" operation is applicable to / path. Check
1109
; 11a. Only "list directory" operation is applicable to / path. Check
1114
; the operation code. If wrong, go to 13.
1110
; the operation code. If wrong, go to 13.
1115
        cmp     dword [ebx], 1
1111
        cmp     dword [ebx], 1
1116
        jnz     .access_denied
1112
        jnz     .access_denied
1117
; 11b. If the media is inserted, use 'fs_dyndisk_next' as an enumeration
1113
; 11b. If the media is inserted, use 'fs_dyndisk_next' as an enumeration
1118
; procedure. Otherwise, use 'fs_dyndisk_next_nomedia'.
1114
; procedure. Otherwise, use 'fs_dyndisk_next_nomedia'.
1119
        mov     esi, fs_dyndisk_next_nomedia
1115
        mov     esi, fs_dyndisk_next_nomedia
1120
        test    edx, edx
1116
        test    edx, edx
1121
        jz      @f
1117
        jz      @f
1122
        mov     esi, fs_dyndisk_next
1118
        mov     esi, fs_dyndisk_next
1123
@@:
1119
@@:
1124
; 11c. Let the procedure from fs_lfn.inc do the job.
1120
; 11c. Let the procedure from fs_lfn.inc do the job.
1125
        jmp     file_system_lfn.maindir_noesi
1121
        jmp     file_system_lfn.maindir_noesi
1126
.haspartition:
1122
.haspartition:
1127
; 12. The fs operation has specified some partition.
1123
; 12. The fs operation has specified some partition.
1128
; 12a. Store parameters for callback functions.
1124
; 12a. Store parameters for callback functions.
1129
        push    edx
1125
        push    edx
1130
        push    ecx
1126
        push    ecx
1131
; 12b. Store callback functions.
1127
; 12b. Store callback functions.
1132
        push    dyndisk_cleanup
1128
        push    dyndisk_cleanup
1133
        push    fs_dyndisk
1129
        push    fs_dyndisk
1134
        mov     edi, esp
1130
        mov     edi, esp
1135
; 12c. Let the procedure from fs_lfn.inc do the job.
1131
; 12c. Let the procedure from fs_lfn.inc do the job.
1136
        jmp     file_system_lfn.found2
1132
        jmp     file_system_lfn.found2
1137
.access_denied:
1133
.access_denied:
1138
; 13. Fail the operation with the appropriate code.
1134
; 13. Fail the operation with the appropriate code.
1139
        mov     dword [esp+32], ERROR_ACCESS_DENIED
1135
        mov     dword [esp+32], ERROR_ACCESS_DENIED
1140
.cleanup:
1136
.cleanup:
1141
; 14. Cleanup.
1137
; 14. Cleanup.
1142
        mov     esi, ecx        ; disk*dereference assume that esi points to DISK
1138
        mov     esi, ecx        ; disk*dereference assume that esi points to DISK
1143
.cleanup_esi:
1139
.cleanup_esi:
1144
        test    edx, edx        ; if there are no media, we didn't reference it
1140
        test    edx, edx        ; if there are no media, we didn't reference it
1145
        jz      @f
1141
        jz      @f
1146
        call    disk_media_dereference
1142
        call    disk_media_dereference
1147
@@:
1143
@@:
1148
        call    disk_dereference
1144
        call    disk_dereference
1149
; 15. Return.
1145
; 15. Return.
1150
        ret
1146
        ret
1151
 
1147
 
1152
; This is a callback for cleaning up things called from file_system_lfn.found2.
1148
; This is a callback for cleaning up things called from file_system_lfn.found2.
1153
dyndisk_cleanup:
1149
dyndisk_cleanup:
1154
        mov     esi, [edi+8]
1150
        mov     esi, [edi+8]
1155
        mov     edx, [edi+12]
1151
        mov     edx, [edi+12]
1156
        jmp     dyndisk_handler.cleanup_esi
1152
        jmp     dyndisk_handler.cleanup_esi
1157
 
1153
 
1158
; This is a callback for enumerating partitions called from
1154
; This is a callback for enumerating partitions called from
1159
; file_system_lfn.maindir in the case of inserted media.
1155
; file_system_lfn.maindir in the case of inserted media.
1160
; It just increments eax until DISK.NumPartitions reached and then
1156
; It just increments eax until DISK.NumPartitions reached and then
1161
; cleans up.
1157
; cleans up.
1162
fs_dyndisk_next:
1158
fs_dyndisk_next:
1163
        cmp     eax, [ecx+DISK.NumPartitions]
1159
        cmp     eax, [ecx+DISK.NumPartitions]
1164
        jae     .nomore
1160
        jae     .nomore
1165
        inc     eax
1161
        inc     eax
1166
        clc
1162
        clc
1167
        ret
1163
        ret
1168
.nomore:
1164
.nomore:
1169
        pusha
1165
        pusha
1170
        mov     esi, ecx
1166
        mov     esi, ecx
1171
        call    disk_media_dereference
1167
        call    disk_media_dereference
1172
        call    disk_dereference
1168
        call    disk_dereference
1173
        popa
1169
        popa
1174
        stc
1170
        stc
1175
        ret
1171
        ret
1176
 
1172
 
1177
; This is a callback for enumerating partitions called from
1173
; This is a callback for enumerating partitions called from
1178
; file_system_lfn.maindir in the case of missing media.
1174
; file_system_lfn.maindir in the case of missing media.
1179
; In this case we create one pseudo-partition.
1175
; In this case we create one pseudo-partition.
1180
fs_dyndisk_next_nomedia:
1176
fs_dyndisk_next_nomedia:
1181
        cmp     eax, 1
1177
        cmp     eax, 1
1182
        jae     .nomore
1178
        jae     .nomore
1183
        inc     eax
1179
        inc     eax
1184
        clc
1180
        clc
1185
        ret
1181
        ret
1186
.nomore:
1182
.nomore:
1187
        pusha
1183
        pusha
1188
        mov     esi, ecx
1184
        mov     esi, ecx
1189
        call    disk_dereference
1185
        call    disk_dereference
1190
        popa
1186
        popa
1191
        stc
1187
        stc
1192
        ret
1188
        ret
1193
 
1189
 
1194
; This is a callback for doing real work with selected partition.
1190
; This is a callback for doing real work with selected partition.
1195
; Currently this is just placeholder, since no file systems are supported.
1191
; Currently this is just placeholder, since no file systems are supported.
1196
; edi = esp -> {dd fs_dyndisk, dd dyndisk_cleanup, dd pointer to DISK, dd media object}
1192
; edi = esp -> {dd fs_dyndisk, dd dyndisk_cleanup, dd pointer to DISK, dd media object}
1197
; ecx = partition number, esi+ebp = ASCIIZ name
1193
; ecx = partition number, esi+ebp = ASCIIZ name
1198
fs_dyndisk:
1194
fs_dyndisk:
1199
        dec     ecx     ; convert to zero-based partition index
1195
        dec     ecx     ; convert to zero-based partition index
1200
        pop     edx edx edx eax ; edx = pointer to DISK, eax = NULL or edx
1196
        pop     edx edx edx eax ; edx = pointer to DISK, eax = NULL or edx
1201
        test    eax, eax
1197
        test    eax, eax
1202
        jz      .nomedia
1198
        jz      .nomedia
1203
.main:
1199
.main:
1204
        cmp     ecx, [edx+DISK.NumPartitions]
1200
        cmp     ecx, [edx+DISK.NumPartitions]
1205
        jae     .notfound
1201
        jae     .notfound
1206
        mov     eax, [edx+DISK.Partitions]
1202
        mov     eax, [edx+DISK.Partitions]
1207
        mov     eax, [eax+ecx*4]
1203
        mov     eax, [eax+ecx*4]
1208
        mov     edi, [eax+PARTITION.FSUserFunctions]
1204
        mov     edi, [eax+PARTITION.FSUserFunctions]
1209
        test    edi, edi
1205
        test    edi, edi
1210
        jz      .nofs
1206
        jz      .nofs
1211
        mov     ecx, [ebx]
1207
        mov     ecx, [ebx]
1212
        cmp     [edi], ecx
1208
        cmp     [edi], ecx
1213
        jbe     .unsupported
1209
        jbe     .unsupported
1214
        push    edx
1210
        push    edx
1215
        push    ebp
1211
        push    ebp
1216
        mov     ebp, eax
1212
        mov     ebp, eax
1217
        call    dword [edi+4+ecx*4]
1213
        call    dword [edi+4+ecx*4]
1218
        pop     ebp
1214
        pop     ebp
1219
        pop     edx
1215
        pop     edx
1220
        mov     dword [esp+32], eax
1216
        mov     dword [esp+32], eax
1221
        mov     dword [esp+20], ebx
1217
        mov     dword [esp+20], ebx
1222
.cleanup:
1218
.cleanup:
1223
        mov     esi, edx
1219
        mov     esi, edx
1224
        call    disk_media_dereference
1220
        call    disk_media_dereference
1225
        call    disk_dereference
1221
        call    disk_dereference
1226
        ret
1222
        ret
1227
.nofs:
1223
.nofs:
1228
        mov     dword [esp+32], ERROR_UNKNOWN_FS
1224
        mov     dword [esp+32], ERROR_UNKNOWN_FS
1229
        jmp     .cleanup
1225
        jmp     .cleanup
1230
.notfound:
1226
.notfound:
1231
        mov     dword [esp+32], ERROR_FILE_NOT_FOUND
1227
        mov     dword [esp+32], ERROR_FILE_NOT_FOUND
1232
        jmp     .cleanup
1228
        jmp     .cleanup
1233
.unsupported:
1229
.unsupported:
1234
        mov     dword [esp+32], ERROR_UNSUPPORTED_FS
1230
        mov     dword [esp+32], ERROR_UNSUPPORTED_FS
1235
        jmp     .cleanup
1231
        jmp     .cleanup
1236
.nomedia:
1232
.nomedia:
1237
        test    ecx, ecx
1233
        test    ecx, ecx
1238
        jnz     .notfound
1234
        jnz     .notfound
1239
        test    byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION
1235
        test    byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION
1240
        jz      .deverror
1236
        jz      .deverror
1241
; if the driver does not support insert notifications and we are the only fs
1237
; if the driver does not support insert notifications and we are the only fs
1242
; operation with this disk, issue the fake insert notification; if media is
1238
; operation with this disk, issue the fake insert notification; if media is
1243
; still not inserted, 'disk_media_changed' will detect this and do nothing
1239
; still not inserted, 'disk_media_changed' will detect this and do nothing
1244
        lea     ecx, [edx+DISK.MediaLock]
1240
        lea     ecx, [edx+DISK.MediaLock]
1245
        call    mutex_lock
1241
        call    mutex_lock
1246
        cmp     [edx+DISK.MediaRefCount], 1
1242
        cmp     [edx+DISK.MediaRefCount], 1
1247
        jnz     .noluck
1243
        jnz     .noluck
1248
        call    mutex_unlock
1244
        call    mutex_unlock
1249
        push    edx
1245
        push    edx
1250
        stdcall disk_media_changed, edx, 1
1246
        stdcall disk_media_changed, edx, 1
1251
        pop     edx
1247
        pop     edx
1252
        lea     ecx, [edx+DISK.MediaLock]
1248
        lea     ecx, [edx+DISK.MediaLock]
1253
        call    mutex_lock
1249
        call    mutex_lock
1254
        cmp     [edx+DISK.MediaInserted], 0
1250
        cmp     [edx+DISK.MediaInserted], 0
1255
        jz      .noluck
1251
        jz      .noluck
1256
        lock inc [edx+DISK.MediaRefCount]
1252
        lock inc [edx+DISK.MediaRefCount]
1257
        call    mutex_unlock
1253
        call    mutex_unlock
1258
        xor     ecx, ecx
1254
        xor     ecx, ecx
1259
        jmp     .main
1255
        jmp     .main
1260
.noluck:
1256
.noluck:
1261
        call    mutex_unlock
1257
        call    mutex_unlock
1262
.deverror:
1258
.deverror:
1263
        mov     dword [esp+32], ERROR_DEVICE
1259
        mov     dword [esp+32], ERROR_DEVICE
1264
        mov     esi, edx
1260
        mov     esi, edx
1265
        call    disk_dereference
1261
        call    disk_dereference
1266
        ret
1262
        ret
1267
 
1263
 
1268
; This function is called from file_system_lfn.
1264
; This function is called from file_system_lfn.
1269
; This handler is called when virtual root is enumerated
1265
; This handler is called when virtual root is enumerated
1270
; and must return all items which can be handled by this.
1266
; and must return all items which can be handled by this.
1271
; It is called several times, first time with eax=0
1267
; It is called several times, first time with eax=0
1272
; in: eax = 0 for first call, previously returned value for subsequent calls
1268
; in: eax = 0 for first call, previously returned value for subsequent calls
1273
; out: eax = 0 => no more items
1269
; out: eax = 0 => no more items
1274
;      eax != 0 => buffer pointed to by edi contains name of item
1270
;      eax != 0 => buffer pointed to by edi contains name of item
1275
dyndisk_enum_root:
1271
dyndisk_enum_root:
1276
        push    edx             ; save register used in file_system_lfn
1272
        push    edx             ; save register used in file_system_lfn
1277
        mov     ecx, disk_list_mutex    ; it will be useful
1273
        mov     ecx, disk_list_mutex    ; it will be useful
1278
; 1. If this is the first call, acquire the mutex and initialize.
1274
; 1. If this is the first call, acquire the mutex and initialize.
1279
        test    eax, eax
1275
        test    eax, eax
1280
        jnz     .notfirst
1276
        jnz     .notfirst
1281
        call    mutex_lock
1277
        call    mutex_lock
1282
        mov     eax, disk_list
1278
        mov     eax, disk_list
1283
.notfirst:
1279
.notfirst:
1284
; 2. Get next item.
1280
; 2. Get next item.
1285
        mov     eax, [eax+DISK.Next]
1281
        mov     eax, [eax+DISK.Next]
1286
; 3. If there are no more items, go to 6.
1282
; 3. If there are no more items, go to 6.
1287
        cmp     eax, disk_list
1283
        cmp     eax, disk_list
1288
        jz      .last
1284
        jz      .last
1289
; 4. Copy name from the DISK structure to edi.
1285
; 4. Copy name from the DISK structure to edi.
1290
        push    eax esi
1286
        push    eax esi
1291
        mov     esi, [eax+DISK.Name]
1287
        mov     esi, [eax+DISK.Name]
1292
@@:
1288
@@:
1293
        lodsb
1289
        lodsb
1294
        stosb
1290
        stosb
1295
        test    al, al
1291
        test    al, al
1296
        jnz     @b
1292
        jnz     @b
1297
        pop     esi eax
1293
        pop     esi eax
1298
; 5. Return with eax = item.
1294
; 5. Return with eax = item.
1299
        pop     edx             ; restore register used in file_system_lfn
1295
        pop     edx             ; restore register used in file_system_lfn
1300
        ret
1296
        ret
1301
.last:
1297
.last:
1302
; 6. Release the mutex and return with eax = 0.
1298
; 6. Release the mutex and return with eax = 0.
1303
        call    mutex_unlock
1299
        call    mutex_unlock
1304
        xor     eax, eax
1300
        xor     eax, eax
1305
        pop     edx             ; restore register used in file_system_lfn
1301
        pop     edx             ; restore register used in file_system_lfn
1306
        ret
1302
        ret