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

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

Redone LVM sector validation [v1.1.1-testing]

AL.0 is 1 when a valid signature is found..
AH.0 is 1 when the CRC was OK.
ZF is 0 when LVM sector is valid.

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.3 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 dx
115 call LVM_GetSectorCRC
116 cmp ax, word ptr [si+LocLVM_CRC]
117 jne LVMCSCRC_BadCRC
118 cmp dx, word ptr [si+LocLVM_CRC+2]
119 jne LVMCSCRC_BadCRC
120 stc
121 ret
122 LVMCSCRC_BadCRC:
123 clc
124 ret
125LVM_CheckSectorCRC EndP
126
127; Checks if a sector is a valid LVM-sector
128; Sector is considered valid LVM-sector if both signature and CRC are correct.
129; In: DS:SI - Sector that needs to get checked...
130; Out: AL = 1 -> LVM Signature found
131; AH = 1 -> CRC OK
132; ZF = 0 -> Signature found and CRC OK, ZF = 1 -> Invalid LVM sector
133; Note: AL thus indicates a valid signature and AH a valid CRC
134; Destroyed: None
135LVM_ValidateSector Proc Near
136 xor ax, ax ; Start with all zero bits
137 call LVM_CheckSectorSignature ; CF=1 -> Signature OK
138 rcl al, 1 ; Store CF in AL
139 call LVM_CheckSectorCRC ; CF=1 -> Checksum OK
140 rcl ah, 1 ; Store CF in AH
141 test al, ah ; ZF=0 if both AL and AH are 1
142 ret
143LVM_ValidateSector EndP
144
145; Updates Sector with valid LVM CRC
146; This one doesn't check, if it's really an LVM sector, so check before!
147; In: DS:SI - Sector that needs to get checked...
148; Out: None, CRC updated
149; Destroyed: None
150LVM_UpdateSectorCRC Proc Near Uses ax dx
151 call LVM_GetSectorCRC
152 mov word ptr [si+LocLVM_CRC], ax
153 mov word ptr [si+LocLVM_CRC+2], dx
154 ret
155LVM_UpdateSectorCRC EndP
156
157; Searches for a partition in LVM Information Sector and sets SI to point to
158; the LVM-entry. It will also set CARRY then.
159; In: DX:AX - LBA starting sector of partition to be searched
160; DS:SI - Valid (previously checked) LVM-Information-Sector
161; Out: Carry set, if partition found
162; DS:SI - points to LVM information entry
163; Destroyed: None
164LVM_SearchForPartition Proc Near Uses cx
165 cmp byte ptr [si+LocLVM_SignatureStart], LocLVM_SignatureByte0
166 jne LVMSFP_NotFound ; Quick Check, if LVM sector there
167 add si, LocLVM_StartOfEntries
168 mov cl, LocLVM_MaxEntries
169 LVMSFP_Loop:
170 cmp ax, [si+LocLVM_PartitionStart]
171 jne LVMSFP_NextEntry
172 cmp dx, [si+LocLVM_PartitionStart+2]
173 je LVMSFP_FoundIt
174 LVMSFP_NextEntry:
175 add si, LocLVM_LenOfEntry
176 dec cl
177 jnz LVMSFP_Loop
178 LVMSFP_NotFound:
179 clc
180 ret
181 LVMSFP_FoundIt:
182 stc
183 ret
184LVM_SearchForPartition EndP
185
186
187; Gets a drive-letter from the LVM-info of a partition. (if it exists)
188; In: BX:CX - LBA starting sector of partition to be searched
189; DL = Physical Disk in BIOS notation. (80h+)
190; Out: CY=1 if LVM-info found, 0 if no LVM-info.
191; AL - drive-letter from LVM-info or zero if no drive-letter
192; assigned or no LVM-info.
193LVM_GetDriveLetter Proc Near Uses bx cx dx si di ds es
194 ; For primary partitions this information is stored in the last
195 ; sector of track0; for all four partition entries in case they
196 ; they are all primary ones.
197 ;
198 ; LVM DLAT info for logical partitions is stored in the sector
199 ; preceding the start of the partition.
200 ;
201 ; Because the LVM info of a logical partition is the easiest to find,
202 ; we do that first. The LVM info for primary partitions is located
203 ; dependent on the geometry in use, so we use a special locater
204 ; call for that. Also, since the LVM info for primaries contains
205 ; info on all 4 entries, we need the partition index to obtain the
206 ; correct drive-letter.
207 ;
208
209 ; See if this is a primary partition
210 ; CY will be set if it is and AL will contain the 0-based
211 ; index in the P-table.
212 ; If it's a logical partition, CY will be clear and AL
213 ; will be set to 0ffh indicating an invalid index.
214 call PART_IsPrimaryPartition
215 mov al,0
216 rcl al,1 ; CY if primary
217 mov dh,al ; Save PRI or LOG
218
219 ; Save PRI/LOG indicator for later use
220 push dx
221
222 ; Load *possible* LVM sector
223 ; This load is only valid if the partition is logical, in which case
224 ; the LVM sector is below the start of the partition.
225 ; If primary, the LVM sector is at a location that
226 ; DriveIO_LoadMasterLVMSector will find out.
227
228 ; Push LBA address
229 push bx
230 push cx
231
232 ; Adjust for logical LVM-sector
233 sub cx,1
234 sbb bx,0
235
236 ; Load the LVM sector
237 push si
238 push di
239 mov si,offset [LVMSector]
240 mov di,ds
241 call DriveIO_LoadSectorLBA ; Change this to normal IO-routine !!!!!!
242 pop di
243 pop si
244
245 ; Restore LBA address
246 pop cx
247 pop bx
248
249 ; Restore PRI/LOG partition indicator in DH
250 pop dx
251
252 ; Test PRI or not
253 test dh,dh
254 ; It's not a PRI so we can use the previously loaded LVM sector
255 jz LVM_GetDriveLetter_is_not_pri
256
257 ;
258 ; It's a PRI so we use the special locator function.
259 ; This locator takes care of extended OS/2 geometry should that be used
260 ;
261 call DriveIO_LoadMasterLVMSector
262
263 LVM_GetDriveLetter_is_not_pri:
264
265
266 ;
267 ; At this stage the LVM-info sector has been loaded at [LVMSector].
268 ; From here we look for an LVM entry for the partition.
269 ; If one is found, based on it's LBA-start, it's driveletter is used
270 ; in case byte 25h in the BPB is zero.
271 ;
272
273
274 ; Search for the partition in the LVM info.
275 ; If found, CY is set and SI points to LVM entry.
276 push si
277 mov ax,cx
278 mov dx,bx
279 mov si,offset [LVMSector]
280 call LVM_SearchForPartition
281 mov bx,si ; BX now points to LVM entry
282 mov dx,0
283 pop si
284
285 mov al,0 ; Setup null driveletter
286 ; Oops, no valid LVM record was used so we have a null driveletter.
287 jnc LVM_GetDriveLetter_null_lvm_dl
288
289 ;
290 ; At this point BX points to the LVM-entry related to the
291 ; partition, whether it was a logical or a primary one.
292 ;
293 mov al,[bx+LocLVM_VolumeLetter]
294 ; Test for zero dtive-letter.
295 test al,al
296 ; Preset CY in case drive-letter is zero.
297 clc
298 jz LVM_GetDriveLetter_null_lvm_dl
299
300 ; We have a non-zero drive-letter, so set CY.
301 stc
302
303 LVM_GetDriveLetter_null_lvm_dl:
304 ret
305LVM_GetDriveLetter EndP
306
307
308
309; Sets a drive-letter in the LVM-info of a partition. (if it exists)
310; In: BX:CX - LBA starting sector of partition to be searched
311; DL = Physical Disk in BIOS notation. (80h+)
312; AL = DriveLetter to set (can be zero to hide partition from LVM)
313; Out: CY=1 if LVM-info found, 0 if no LVM-info.
314LVM_SetDriveLetter Proc Near Uses bx cx dx si di ds es
315 local disk:byte
316 local drive_letter:byte
317 local pri_ind:byte
318 local lvm_log_high:word
319 local lvm_log_low:word
320 ; For primary partitions this information is stored in the last
321 ; sector of track0; for all four partition entries in case they
322 ; they are all primary ones.
323 ;
324 ; LVM DLAT info for logical partitions is stored in the sector
325 ; preceding the start of the partition.
326 ;
327 ; Because the LVM info of a logical partition is the easiest to find,
328 ; we do that first. The LVM info for primary partitions is located
329 ; dependent on the geometry in use, so we use a special locater
330 ; call for that. Also, since the LVM info for primaries contains
331 ; info on all 4 entries, we need the partition index to obtain the
332 ; correct drive-letter.
333 ;
334
335 mov [disk], dl
336
337 ; Store the drive-letter for later use
338 mov [drive_letter], al
339
340
341 ; See if this is a primary partition
342 ; CY will be set if it is and AL will contain the 0-based
343 ; index in the P-table.
344 ; If it's a logical partition, CY will be clear and AL
345 ; will be set to 0ffh indicating an invalid index.
346 call PART_IsPrimaryPartition
347 mov al,0
348 rcl al,1 ; CY if primary
349 mov dh,al ; Save PRI or LOG
350 mov [pri_ind],al
351
352 ; Save PRI/LOG indicator for later use
353 push dx
354
355 ; Load *possible* LVM sector
356 ; This load is only valid if the partition is logical, in which case
357 ; the LVM sector is below the start of the partition.
358 ; If primary, the LVM sector is at a location that
359 ; DriveIO_LoadMasterLVMSector will find out.
360
361 ; Push LBA address
362 push bx
363 push cx
364
365 ; Adjust for logical LVM-sector
366 sub cx,1
367 sbb bx,0
368
369 ; Store LBA address of LVM-sector
370 mov [lvm_log_low],cx
371 mov [lvm_log_high],bx
372
373 ; Load the LVM sector
374 push si
375 push di
376 mov si,offset [LVMSector]
377 mov di,ds
378 call DriveIO_LoadSectorLBA ; Change this to normal IO-routine !!!!!!
379 pop di
380 pop si
381
382 ; Restore LBA address
383 pop cx
384 pop bx
385
386 ; Restore PRI/LOG partition indicator in DH
387 pop dx
388
389 ; Test PRI or not
390 test dh,dh
391 ; It's not a PRI so we can use the previously loaded LVM sector
392 jz LVM_SetDriveLetter_is_not_pri
393
394 ;
395 ; It's a PRI so we use the special locator function.
396 ; This locator takes care of extended OS/2 geometry should that be used
397 ;
398 call DriveIO_LoadMasterLVMSector
399 jnc LVM_SetDriveLetter_null_lvm_dl
400
401 mov ax, word ptr [MasterLVMLBA] ; ARRAY VAN MAKEN !
402 mov [lvm_log_low], ax
403 mov [lvm_log_high], 0
404
405 LVM_SetDriveLetter_is_not_pri:
406
407 ;
408 ; At this stage the LVM-info sector has been loaded at [LVMSector].
409 ; From here we look for an LVM entry for the partition.
410 ; If one is found, based on it's LBA-start, it's driveletter is used
411 ; in case byte 25h in the BPB is zero.
412 ;
413
414 ; Search for the partition in the LVM info.
415 ; If found, CY is set and SI points to LVM entry.
416 push si
417 mov ax,cx
418 mov dx,bx
419 mov si,offset [LVMSector]
420 call LVM_SearchForPartition
421 mov bx,si ; BX now points to LVM entry
422 pop si
423
424 mov al,0 ; Setup null driveletter
425 ; Oops, no valid LVM record was used so we have a null driveletter.
426 jnc LVM_SetDriveLetter_null_lvm_dl
427
428 ;
429 ; At this point BX points to the LVM-entry related to the
430 ; partition, whether it was a logical or a primary one.
431 ;
432 mov al, [drive_letter]
433 mov [bx+LocLVM_VolumeLetter],al
434
435 mov si, offset [LVMSector]
436 call LVM_UpdateSectorCRC
437
438 mov dl, [disk]
439 mov bx, [lvm_log_high]
440 mov ax, [lvm_log_low]
441
442 call DriveIO_SaveSector
443
444 LVM_SetDriveLetter_null_lvm_dl:
445 ret
446LVM_SetDriveLetter EndP
447
448
449
450; Removes a given drive-letter from the whole LVM information sector
451; In: CH - drive-letter (ascii)
452; DS:SI - LVM-Information-Sector
453; Out: LVM-Information-Sector updated (including LVM CRC)
454; Destroyed: None
455LVM_RemoveVolLetterFromSector Proc Near Uses cx
456 cmp bptr [si+LocLVM_SignatureStart], LocLVM_SignatureByte0
457 jne LVMRVLFS_Done ; Quick Check, if LVM sector there
458 push si
459 add si, LocLVM_StartOfEntries
460 mov cl, LocLVM_MaxEntries
461 LVMRVLFS_Loop:
462 cmp ch, [si+LocLVM_VolumeLetter]
463 jne LVMRVLFS_NextEntry
464 ; Reset drive-letter, if matched
465 mov bptr [si+LocLVM_VolumeLetter], 0 ; ASSIGN NEXT FREE HERE... (DOET DUBBEL ALS ZELFDE DL ALS SYS)
466 LVMRVLFS_NextEntry:
467 add si, LocLVM_LenOfEntry
468 dec cl
469 jnz LVMRVLFS_Loop
470 pop si
471 call LVM_UpdateSectorCRC
472 LVMRVLFS_Done:
473 ret
474LVM_RemoveVolLetterFromSector EndP
475
476; Reassigns LVM volume driveletter
477; Will remove the drive-letter from any volume that got it currently
478; and finally change the drive-letter of the given partition
479; In: AL - drive-letter
480; DS:SI - points to partition, that needs that driveletter
481; Out: None
482; Destroyed: AX
483
484LVM_DoLetterReassignment Proc Near Uses bx cx dx si di
485
486 IFDEF AUX_DEBUG
487 pusha
488 mov si, offset [dlra]
489 call AuxIO_Print
490 call AuxIO_Teletype
491 call AuxIO_TeletypeNL
492 popa
493 ENDIF
494
495 mov di, si ; Save SI in DI (Partition-pointer)
496 mov ch, al ; and AL in CH (drive-letter)
497 xor bx, bx
498 mov cl, CFG_Partitions
499 or cl, cl
500 jz LVMDLR_SkipRemove
501
502 LVMDLR_RemoveLoop:
503 cmp bptr [PartitionVolumeLetters+bx], ch
504 jne LVMDLR_NextPartition
505 ; One volume that has our wanted drive-letter, so remove it!
506 mov dl, bl
507 call PART_GetPartitionPointer ; DL - partition -> SI
508 ; Now set CurPartition_Location for the DriveIO-functions to work
509 mov ax, wptr [si+LocIPT_AbsolutePartTable]
510 mov wptr [CurPartition_Location+0], ax
511 mov ax, wptr [si+LocIPT_AbsolutePartTable+2]
512 mov wptr [CurPartition_Location+2], ax
513 mov ax, wptr [si+LocIPT_LocationPartTable+1]
514 mov wptr [CurPartition_Location+6], ax
515 mov ah, bptr [si+LocIPT_LocationPartTable+0]
516 mov al, [si+LocIPT_Drive]
517 mov wptr [CurPartition_Location+4], ax
518 call DriveIO_LoadLVMSector ; SI points now to LVM-Sector
519 call LVM_RemoveVolLetterFromSector
520
521 call DriveIO_SaveLVMSector ; Save sector
522
523 LVMDLR_NextPartition:
524 inc bx
525 dec cl
526 jnz LVMDLR_RemoveLoop
527
528 LVMDLR_SkipRemove:
529 ; Set CurPartition_Location information of destination partition
530 mov ax, wptr [di+LocIPT_AbsolutePartTable]
531 mov wptr [CurPartition_Location+0], ax
532 mov ax, wptr [di+LocIPT_AbsolutePartTable+2]
533 mov wptr [CurPartition_Location+2], ax
534 mov ah, bptr [di+LocIPT_LocationPartTable+0]
535 mov al, [di+LocIPT_Drive]
536 mov wptr [CurPartition_Location+4], ax
537 mov ax, wptr [di+LocIPT_LocationPartTable+1]
538 mov wptr [CurPartition_Location+6], ax
539 call DriveIO_LoadLVMSector ; SI points now to LVM-Sector
540 mov ax, wptr [di+LocIPT_AbsoluteBegin]
541 mov dx, wptr [di+LocIPT_AbsoluteBegin+2]
542 mov di, si ; Save SI in DI
543 call LVM_SearchForPartition
544 jnc LVMDLR_DestPartNotFound
545 ; Set new volume letter
546 mov bptr [si+LocLVM_VolumeLetter], ch
547 mov si, di ; SI - LVM Sector again
548 call LVM_UpdateSectorCRC ; Update LVM-CRC now
549
550 call DriveIO_SaveLVMSector ; Save sector
551
552 LVMDLR_DestPartNotFound:
553 ; This here is done for safety, because we misuse CurPartition_Location
554 xor ax, ax
555 mov di, offset CurPartition_Location
556 mov cx, 4
557 rep stosw ; NUL out CurPartition_Location
558 ret
559LVM_DoLetterReassignment EndP
560
561
562; This walks the IPT and for each partition it obtains the LVM drive-letter
563; if available. This drive-letter is then marked as in-use in the Map.
564; The FreeDriveletterMap is used by the drive-letter reassignment function
565; to assign a new drive to a data-partition when a system-partition is booted
566; with the same drive-letter. The original drive-letter for the data-partition
567; is saved so it can be restored later when a system is booted that does not
568; use the drive-letter. Note that there can be multiple system-partitions
569; using the same drive-letter and data-partitions can become system-partition
570; by making them bootable. (and vice versa)
571LVM_ComposeFreeDriveletterMap Proc
572
573; get nr of partitions in IPT
574; for each partition get LVM drive-letter and reset bit in map.
575
576LVM_ComposeFreeDriveletterMap EndP
577
Note: See TracBrowser for help on using the repository browser.