source: trunk/bootcode/special/lvm.asm@ 102

Last change on this file since 102 was 102, checked in by Ben Rietbroek, 8 years ago

Optimized reading a sector from disk using INT13X [v1.1.1-testing]

At this level it is more clear to talk about 'reading' and 'writing'
sectors, where 'disk read' and 'disk write' errors can occur.

CAUTION:
This is a testbuild !
AirBoot uses the BIOS to access disks and a small coding error can trash
partition tables or other vital disk structures. You are advised to make
backups of TRACK0 and EBRs before using this testbuild. More info at:
https://rousseaux.github.io/netlabs.air-boot/pdf/AirBoot-v1.1.0-manual.pdf

File size: 21.4 KB
Line 
1; AiR-BOOT (c) Copyright 1998-2008 M. Kiewitz
2;
3; This file is part of AiR-BOOT
4;
5; AiR-BOOT is free software: you can redistribute it and/or modify it under
6; the terms of the GNU General Public License as published by the Free
7; Software Foundation, either version 3 of the License, or (at your option)
8; any later version.
9;
10; AiR-BOOT is distributed in the hope that it will be useful, but WITHOUT ANY
11; WARRANTY: without even the implied warranty of MERCHANTABILITY or FITNESS
12; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13; details.
14;
15; You should have received a copy of the GNU General Public License along with
16; AiR-BOOT. If not, see <http://www.gnu.org/licenses/>.
17;
18;---------------------------------------------------------------------------
19; AiR-BOOT / LVM
20;---------------------------------------------------------------------------
21
22IFDEF MODULE_NAMES
23DB 'LVM',0
24ENDIF
25
26LVM_InitCRCTable Proc Near
27 ; Initializes our LVM-CRC-Table
28 xor cl, cl
29 mov di, offset [LVM_CRCTable]
30 LVM_ICRCT_Loop:
31 ;movzx ax, cl
32 mov al,cl
33 mov ah,0
34 xor dx, dx ; DX:AX - CRC-Value
35 mov ch, 8
36 LVM_ICRCT_Loop2:
37 shr dx, 1
38 rcr ax, 1 ; Shift value 1 to the right
39 jnc LVM_ICRCT_NoXOR
40 xor dx, 0EDB8h
41 xor ax, 8320h
42 LVM_ICRCT_NoXOR:
43 dec ch
44 jnz LVM_ICRCT_Loop2
45 mov wptr [di+0], ax
46 mov wptr [di+2], dx
47 add di, 4
48 add cl, 1
49 jnc LVM_ICRCT_Loop
50 ret
51LVM_InitCRCTable EndP
52
53; Calculates an LVM-Sector CRC of a given sector
54; In: DS:SI - Points to Sector...
55; Out: DX:AX - LVM CRC
56; Destroyed: None
57LVM_GetSectorCRC Proc Near Uses bx cx
58 push word ptr [si+LocLVM_CRC+00]
59 push word ptr [si+LocLVM_CRC+02]
60 push si
61 mov word ptr [si+LocLVM_CRC], 0
62 mov word ptr [si+LocLVM_CRC+2], 0
63 mov ax, -1
64 mov dx, -1
65 mov cx, 512
66 LVM_GSCRC_Loop:
67 xor bh, bh
68 mov bl, al ; Save last byte to BL
69 mov al, ah
70 mov ah, dl
71 mov dl, dh
72 xor dh, dh ; SHR DX:AX, 8
73 xor bl, [si]
74 inc si ; XOR last byte with [data]
75 shl bx, 1
76 shl bx, 1
77 xor ax, word ptr [LVM_CRCTable+bx+0]
78 xor dx, word ptr [LVM_CRCTable+bx+2] ; XOR with CRC-Table
79 loop LVM_GSCRC_Loop
80 pop si
81 pop word ptr [si+LocLVM_CRC+2]
82 pop word ptr [si+LocLVM_CRC]
83 ret
84LVM_GetSectorCRC EndP
85
86; Checks ds:[SI], if a valid LVM Signature is found (sets carry in that case)
87; This does not check for valid LVM CRC (which also needs to be done)
88; In: DS:SI - Sector that needs to get checked...
89; Out: Carry set, if valid LVM signature found
90; Destroyed: None
91LVM_CheckSectorSignature Proc Near
92 test byte ptr [CFG_IgnoreLVM], 1 ; We are supposed to ignore LVM, so
93 jnz LVMCSS_InvalidSignature ; any sector is bad!
94 cmp word ptr [si+LocLVM_SignatureStart], 5202h
95 jne LVMCSS_InvalidSignature
96 cmp word ptr [si+LocLVM_SignatureStart+2], 'BM'
97 jne LVMCSS_InvalidSignature
98 cmp word ptr [si+LocLVM_SignatureStart+4], 'MP'
99 jne LVMCSS_InvalidSignature
100 cmp word ptr [si+LocLVM_SignatureStart+6], 'DF'
101 jne LVMCSS_InvalidSignature
102 stc
103 ret
104 LVMCSS_InvalidSignature:
105 clc
106 ret
107LVM_CheckSectorSignature EndP
108
109; Checks Sector for a valid LVM CRC is encountered
110; First one should check for a valid signature and call this later.
111; In: DS:SI - Sector that needs to get checked...
112; Out: Carry set, if LVM CRC valid
113; Destroyed: None
114LVM_CheckSectorCRC Proc Near Uses ax bx dx
115 mov bx, si
116 call IsSectorZero ; Zero sector implies bad CRC
117 jz LVMCSCRC_BadCRC
118 call LVM_GetSectorCRC ; Only use after CRC table is valid
119 cmp ax, word ptr [si+LocLVM_CRC]
120 jne LVMCSCRC_BadCRC
121 cmp dx, word ptr [si+LocLVM_CRC+2]
122 jne LVMCSCRC_BadCRC
123 stc ; Indicate CRC is OK
124 ret
125 LVMCSCRC_BadCRC:
126 clc ; Indicate BAD CRC
127 ret
128LVM_CheckSectorCRC EndP
129
130; Checks if a sector is a valid LVM-sector
131; Sector is considered valid LVM-sector if both signature and CRC are correct.
132; In: DS:SI - Sector that needs to get checked...
133; Out: AL = 1 -> LVM Signature found
134; AH = 1 -> CRC OK
135; ZF = 0 -> Signature found and CRC OK, ZF = 1 -> Invalid LVM sector
136; Note: AL thus indicates a valid signature and AH a valid CRC
137; Destroyed: None
138LVM_ValidateSector Proc Near
139 xor ax, ax ; Start with all zero bits
140 call LVM_CheckSectorSignature ; CF=1 -> Signature OK
141 rcl al, 1 ; Store CF in AL
142 call LVM_CheckSectorCRC ; CF=1 -> Checksum OK
143 rcl ah, 1 ; Store CF in AH
144 test al, ah ; ZF=0 if both AL and AH are 1
145 ret
146LVM_ValidateSector EndP
147
148; Updates Sector with valid LVM CRC
149; This one doesn't check, if it's really an LVM sector, so check before!
150; In: DS:SI - Sector that needs to get checked...
151; Out: None, CRC updated
152; Destroyed: None
153LVM_UpdateSectorCRC Proc Near Uses ax dx
154 call LVM_GetSectorCRC
155 mov word ptr [si+LocLVM_CRC], ax
156 mov word ptr [si+LocLVM_CRC+2], dx
157 ret
158LVM_UpdateSectorCRC EndP
159
160; Searches for a partition in LVM Information Sector and sets SI to point to
161; the LVM-entry. It will also set CARRY then.
162; In: DX:AX - LBA starting sector of partition to be searched
163; DS:SI - Valid (previously checked) LVM-Information-Sector
164; Out: Carry set, if partition found
165; DS:SI - points to LVM information entry
166; Destroyed: None
167LVM_SearchForPartition Proc Near Uses cx
168 cmp byte ptr [si+LocLVM_SignatureStart], LocLVM_SignatureByte0
169 jne LVMSFP_NotFound ; Quick Check, if LVM sector there
170 add si, LocLVM_StartOfEntries
171 mov cl, LocLVM_MaxEntries
172 LVMSFP_Loop:
173 cmp ax, [si+LocLVM_PartitionStart]
174 jne LVMSFP_NextEntry
175 cmp dx, [si+LocLVM_PartitionStart+2]
176 je LVMSFP_FoundIt
177 LVMSFP_NextEntry:
178 add si, LocLVM_LenOfEntry
179 dec cl
180 jnz LVMSFP_Loop
181 LVMSFP_NotFound:
182 clc
183 ret
184 LVMSFP_FoundIt:
185 stc
186 ret
187LVM_SearchForPartition EndP
188
189
190; Gets a drive-letter from the LVM-info of a partition. (if it exists)
191; In: BX:CX - LBA starting sector of partition to be searched
192; DL = Physical Disk in BIOS notation. (80h+)
193; Out: CY=1 if LVM-info found, 0 if no LVM-info.
194; AL - drive-letter from LVM-info or zero if no drive-letter
195; assigned or no LVM-info.
196LVM_GetDriveLetter Proc Near Uses bx cx dx si di ds es
197 ; For primary partitions this information is stored in the last
198 ; sector of track0; for all four partition entries in case they
199 ; they are all primary ones.
200 ;
201 ; LVM DLAT info for logical partitions is stored in the sector
202 ; preceding the start of the partition.
203 ;
204 ; Because the LVM info of a logical partition is the easiest to find,
205 ; we do that first. The LVM info for primary partitions is located
206 ; dependent on the geometry in use, so we use a special locater
207 ; call for that. Also, since the LVM info for primaries contains
208 ; info on all 4 entries, we need the partition index to obtain the
209 ; correct drive-letter.
210 ;
211
212 ; See if this is a primary partition
213 ; CY will be set if it is and AL will contain the 0-based
214 ; index in the P-table.
215 ; If it's a logical partition, CY will be clear and AL
216 ; will be set to 0ffh indicating an invalid index.
217 call PART_IsPrimaryPartition
218 mov al,0
219 rcl al,1 ; CY if primary
220 mov dh,al ; Save PRI or LOG
221
222 ; Save PRI/LOG indicator for later use
223 push dx
224
225 ; Load *possible* LVM sector
226 ; This load is only valid if the partition is logical, in which case
227 ; the LVM sector is below the start of the partition.
228 ; If primary, the LVM sector is at a location that
229 ; DriveIO_LoadMasterLVMSector will find out.
230
231 ; Push LBA address
232 push bx
233 push cx
234
235 ; Adjust for logical LVM-sector
236 sub cx,1
237 sbb bx,0
238
239 ; Load the LVM sector
240 push si
241 push di
242 mov si,offset [LVMSector]
243 mov di,ds
244 call DriveIO_ReadSectorLBA
245 pop di
246 pop si
247
248 ; Restore LBA address
249 pop cx
250 pop bx
251
252 ; Restore PRI/LOG partition indicator in DH
253 pop dx
254
255 ; Test PRI or not
256 test dh,dh
257 ; It's not a PRI so we can use the previously loaded LVM sector
258 jz LVM_GetDriveLetter_is_not_pri
259
260 ;
261 ; It's a PRI so we use the special locator function.
262 ; This locator takes care of extended OS/2 geometry should that be used
263 ;
264 call DriveIO_LoadMasterLVMSector
265
266 LVM_GetDriveLetter_is_not_pri:
267
268
269 ;
270 ; At this stage the LVM-info sector has been loaded at [LVMSector].
271 ; From here we look for an LVM entry for the partition.
272 ; If one is found, based on it's LBA-start, it's driveletter is used
273 ; in case byte 25h in the BPB is zero.
274 ;
275
276
277 ; Search for the partition in the LVM info.
278 ; If found, CY is set and SI points to LVM entry.
279 push si
280 mov ax,cx
281 mov dx,bx
282 mov si,offset [LVMSector]
283 call LVM_SearchForPartition
284 mov bx,si ; BX now points to LVM entry
285 mov dx,0
286 pop si
287
288 mov al,0 ; Setup null driveletter
289 ; Oops, no valid LVM record was used so we have a null driveletter.
290 jnc LVM_GetDriveLetter_null_lvm_dl
291
292 ;
293 ; At this point BX points to the LVM-entry related to the
294 ; partition, whether it was a logical or a primary one.
295 ;
296 mov al,[bx+LocLVM_VolumeLetter]
297 ; Test for zero dtive-letter.
298 test al,al
299 ; Preset CY in case drive-letter is zero.
300 clc
301 jz LVM_GetDriveLetter_null_lvm_dl
302
303 ; We have a non-zero drive-letter, so set CY.
304 stc
305
306 LVM_GetDriveLetter_null_lvm_dl:
307 ret
308LVM_GetDriveLetter EndP
309
310
311
312; Sets a drive-letter in the LVM-info of a partition. (if it exists)
313; In: BX:CX - LBA starting sector of partition to be searched
314; DL = Physical Disk in BIOS notation. (80h+)
315; AL = DriveLetter to set (can be zero to hide partition from LVM)
316; Out: CY=1 if LVM-info found, 0 if no LVM-info.
317LVM_SetDriveLetter Proc Near Uses bx cx dx si di ds es
318 local disk:byte
319 local drive_letter:byte
320 local pri_ind:byte
321 local lvm_log_high:word
322 local lvm_log_low:word
323 ; For primary partitions this information is stored in the last
324 ; sector of track0; for all four partition entries in case they
325 ; they are all primary ones.
326 ;
327 ; LVM DLAT info for logical partitions is stored in the sector
328 ; preceding the start of the partition.
329 ;
330 ; Because the LVM info of a logical partition is the easiest to find,
331 ; we do that first. The LVM info for primary partitions is located
332 ; dependent on the geometry in use, so we use a special locater
333 ; call for that. Also, since the LVM info for primaries contains
334 ; info on all 4 entries, we need the partition index to obtain the
335 ; correct drive-letter.
336 ;
337
338 mov [disk], dl
339
340 ; Store the drive-letter for later use
341 mov [drive_letter], al
342
343
344 ; See if this is a primary partition
345 ; CY will be set if it is and AL will contain the 0-based
346 ; index in the P-table.
347 ; If it's a logical partition, CY will be clear and AL
348 ; will be set to 0ffh indicating an invalid index.
349 call PART_IsPrimaryPartition
350 mov al,0
351 rcl al,1 ; CY if primary
352 mov dh,al ; Save PRI or LOG
353 mov [pri_ind],al
354
355 ; Save PRI/LOG indicator for later use
356 push dx
357
358 ; Load *possible* LVM sector
359 ; This load is only valid if the partition is logical, in which case
360 ; the LVM sector is below the start of the partition.
361 ; If primary, the LVM sector is at a location that
362 ; DriveIO_LoadMasterLVMSector will find out.
363
364 ; Push LBA address
365 push bx
366 push cx
367
368 ; Adjust for logical LVM-sector
369 sub cx,1
370 sbb bx,0
371
372 ; Store LBA address of LVM-sector
373 mov [lvm_log_low],cx
374 mov [lvm_log_high],bx
375
376 ; Load the LVM sector
377 push si
378 push di
379 mov si,offset [LVMSector]
380 mov di,ds
381 call DriveIO_ReadSectorLBA
382 pop di
383 pop si
384
385 ; Restore LBA address
386 pop cx
387 pop bx
388
389 ; Restore PRI/LOG partition indicator in DH
390 pop dx
391
392 ; Test PRI or not
393 test dh,dh
394 ; It's not a PRI so we can use the previously loaded LVM sector
395 jz LVM_SetDriveLetter_is_not_pri
396
397 ;
398 ; It's a PRI so we use the special locator function.
399 ; This locator takes care of extended OS/2 geometry should that be used
400 ;
401 call DriveIO_LoadMasterLVMSector
402 jnc LVM_SetDriveLetter_null_lvm_dl
403
404 mov ax, word ptr [MasterLVMLBA] ; ARRAY VAN MAKEN !
405 mov [lvm_log_low], ax
406 mov [lvm_log_high], 0
407
408 LVM_SetDriveLetter_is_not_pri:
409
410 ;
411 ; At this stage the LVM-info sector has been loaded at [LVMSector].
412 ; From here we look for an LVM entry for the partition.
413 ; If one is found, based on it's LBA-start, it's driveletter is used
414 ; in case byte 25h in the BPB is zero.
415 ;
416
417 ; Search for the partition in the LVM info.
418 ; If found, CY is set and SI points to LVM entry.
419 push si
420 mov ax,cx
421 mov dx,bx
422 mov si,offset [LVMSector]
423 call LVM_SearchForPartition
424 mov bx,si ; BX now points to LVM entry
425 pop si
426
427 mov al,0 ; Setup null driveletter
428 ; Oops, no valid LVM record was used so we have a null driveletter.
429 jnc LVM_SetDriveLetter_null_lvm_dl
430
431 ;
432 ; At this point BX points to the LVM-entry related to the
433 ; partition, whether it was a logical or a primary one.
434 ;
435 mov al, [drive_letter]
436 mov [bx+LocLVM_VolumeLetter],al
437
438 mov si, offset [LVMSector]
439 call LVM_UpdateSectorCRC
440
441 mov dl, [disk]
442 mov bx, [lvm_log_high]
443 mov ax, [lvm_log_low]
444
445 call DriveIO_SaveSector
446
447 LVM_SetDriveLetter_null_lvm_dl:
448 ret
449LVM_SetDriveLetter EndP
450
451
452
453; Removes a given drive-letter from the whole LVM information sector
454; In: CH - drive-letter (ascii)
455; DS:SI - LVM-Information-Sector
456; Out: LVM-Information-Sector updated (including LVM CRC)
457; Destroyed: None
458LVM_RemoveVolLetterFromSector Proc Near Uses cx
459 cmp bptr [si+LocLVM_SignatureStart], LocLVM_SignatureByte0
460 jne LVMRVLFS_Done ; Quick Check, if LVM sector there
461 push si
462 add si, LocLVM_StartOfEntries
463 mov cl, LocLVM_MaxEntries
464 LVMRVLFS_Loop:
465 cmp ch, [si+LocLVM_VolumeLetter]
466 jne LVMRVLFS_NextEntry
467 ; Reset drive-letter, if matched
468 mov bptr [si+LocLVM_VolumeLetter], 0 ; ASSIGN NEXT FREE HERE... (DOET DUBBEL ALS ZELFDE DL ALS SYS)
469 LVMRVLFS_NextEntry:
470 add si, LocLVM_LenOfEntry
471 dec cl
472 jnz LVMRVLFS_Loop
473 pop si
474 call LVM_UpdateSectorCRC
475 LVMRVLFS_Done:
476 ret
477LVM_RemoveVolLetterFromSector EndP
478
479; Reassigns LVM volume driveletter
480; Will remove the drive-letter from any volume that got it currently
481; and finally change the drive-letter of the given partition
482; In: AL - drive-letter
483; DS:SI - points to partition, that needs that driveletter
484; Out: None
485; Destroyed: AX
486
487LVM_DoLetterReassignment Proc Near Uses bx cx dx si di
488
489 IFDEF AUX_DEBUG
490 pusha
491 mov si, offset [dlra]
492 call AuxIO_Print
493 call AuxIO_Teletype
494 call AuxIO_TeletypeNL
495 popa
496 ENDIF
497
498 mov di, si ; Save SI in DI (Partition-pointer)
499 mov ch, al ; and AL in CH (drive-letter)
500 xor bx, bx
501 mov cl, CFG_Partitions
502 or cl, cl
503 jz LVMDLR_SkipRemove
504
505 LVMDLR_RemoveLoop:
506 cmp bptr [PartitionVolumeLetters+bx], ch
507 jne LVMDLR_NextPartition
508 ; One volume that has our wanted drive-letter, so remove it!
509 mov dl, bl
510 call PART_GetPartitionPointer ; DL - partition -> SI
511 ; Now set CurPartition_Location for the DriveIO-functions to work
512 mov ax, wptr [si+LocIPT_AbsolutePartTable]
513 mov wptr [CurPartition_Location+0], ax
514 mov ax, wptr [si+LocIPT_AbsolutePartTable+2]
515 mov wptr [CurPartition_Location+2], ax
516 mov ax, wptr [si+LocIPT_LocationPartTable+1]
517 mov wptr [CurPartition_Location+6], ax
518 mov ah, bptr [si+LocIPT_LocationPartTable+0]
519 mov al, [si+LocIPT_Drive]
520 mov wptr [CurPartition_Location+4], ax
521 call DriveIO_LoadLVMSector ; SI points now to LVM-Sector
522 call LVM_RemoveVolLetterFromSector
523
524 call DriveIO_SaveLVMSector ; Save sector
525
526 LVMDLR_NextPartition:
527 inc bx
528 dec cl
529 jnz LVMDLR_RemoveLoop
530
531 LVMDLR_SkipRemove:
532 ; Set CurPartition_Location information of destination partition
533 mov ax, wptr [di+LocIPT_AbsolutePartTable]
534 mov wptr [CurPartition_Location+0], ax
535 mov ax, wptr [di+LocIPT_AbsolutePartTable+2]
536 mov wptr [CurPartition_Location+2], ax
537 mov ah, bptr [di+LocIPT_LocationPartTable+0]
538 mov al, [di+LocIPT_Drive]
539 mov wptr [CurPartition_Location+4], ax
540 mov ax, wptr [di+LocIPT_LocationPartTable+1]
541 mov wptr [CurPartition_Location+6], ax
542 call DriveIO_LoadLVMSector ; SI points now to LVM-Sector
543 mov ax, wptr [di+LocIPT_AbsoluteBegin]
544 mov dx, wptr [di+LocIPT_AbsoluteBegin+2]
545 mov di, si ; Save SI in DI
546 call LVM_SearchForPartition
547 jnc LVMDLR_DestPartNotFound
548 ; Set new volume letter
549 mov bptr [si+LocLVM_VolumeLetter], ch
550 mov si, di ; SI - LVM Sector again
551 call LVM_UpdateSectorCRC ; Update LVM-CRC now
552
553 call DriveIO_SaveLVMSector ; Save sector
554
555 LVMDLR_DestPartNotFound:
556 ; This here is done for safety, because we misuse CurPartition_Location
557 xor ax, ax
558 mov di, offset CurPartition_Location
559 mov cx, 4
560 rep stosw ; NUL out CurPartition_Location
561 ret
562LVM_DoLetterReassignment EndP
563
564
565; This walks the IPT and for each partition it obtains the LVM drive-letter
566; if available. This drive-letter is then marked as in-use in the Map.
567; The FreeDriveletterMap is used by the drive-letter reassignment function
568; to assign a new drive to a data-partition when a system-partition is booted
569; with the same drive-letter. The original drive-letter for the data-partition
570; is saved so it can be restored later when a system is booted that does not
571; use the drive-letter. Note that there can be multiple system-partitions
572; using the same drive-letter and data-partitions can become system-partition
573; by making them bootable. (and vice versa)
574LVM_ComposeFreeDriveletterMap Proc
575
576; get nr of partitions in IPT
577; for each partition get LVM drive-letter and reset bit in map.
578
579LVM_ComposeFreeDriveletterMap EndP
580
Note: See TracBrowser for help on using the repository browser.