;------------------------------------------------------------------------------ ;Rev Date Name Decription ;------------------------------------------------------------------------------ ;R04 25-03-2023 BAO ; !FIXIT ;R03 23-01-2000 DNS OPTIMIZE NEW BOOTING PROCEDURE ;R02 08-01-2000 DNS NEW BOOTING PROCEDURE ;R01 25-05-1998 DNS Console printing ;R00 09-11-1998 DNS Color printing start message ; Install CGA palette ; +------------------------------+ ; + System Bootstrap + ; + Initial revision 09 Nov 1998 + ; +------------------------------+ MODULE DSS_Boot_Loader ; BIOS 3.06 загружает один сектор загрузчика и передаёт ему управление. ; 0 - оригинальный вариант запуска DSS, 1 - вариант Саймана DEFINE ORIGINAL_DSS 0 ; 1 - будет грузить версию Саймана и основную. 0 - только основную. DEFINE UNIVERSAL_BOOT 1 ;------------------------------------------------------------------------------ ORG_ADDRESS EQU #8000 MAX_SECTORS_PER_PAGE EQU #20 ;максимальное кол-во секторов в странице ;!TODO а если сектор больше 512? LOAD_SECTORS EQU SECTORS_OF_LOADER.AFTER_BPB LOADER_IN_BPB: .MAX_SIZE EQU _sBOOT_SECTOR.PARTITION_TABLE - _sBOOT_SECTOR_PARAMS_FAT32 ;------------------------------------------------------------------------------ DISP ORG_ADDRESS OUTPUT 'build/DSSloader.bin' ;ADRIVE EQU #00 ;CDRIVE EQU #02 DRIVE: _mSYSID DI ; ;!TEST 26/03/2024 LD SP,#C000 ; ; LD (DRIVE),A ;[ ] 17.12.2023 загрузка с активного раздела, а не с первого XOR A LD (DRIVE+1),A ; LD C,BIOS.DRV_VERSION RST ToBIOS_18 ; LD HL,FAIL PUSH HL ; LD HL,MESSAGES.INCORR RET C ; goto FAIL LD A,(DRIVE) BIT 7,A JR Z,GOOD_DRIVE EX DE,HL LD DE,2*256 + 21 ;!HARDCODE если версия ниже 2.21, то ошибка SBC HL,DE LD HL,MESSAGES.INCORR RET C ; goto FAIL ; GOOD_DRIVE: LD DE,#8200 ;!HARDCODE LD HL,0 LD IX,2 LD BC,LOAD_SECTORS*256 + BIOS.DRV_READ ; дозагрузка секторов загрузчика LD A,(DRIVE) RST ToBIOS_18 JP NC,CONTINUE JR FAIL.NULL //////////////////////////////////////////////////////////////////////// FAIL: CALL MESSAGE .NULL: LD HL,MESSAGES.FAILURE CALL MESSAGE JR $ ; MESSAGE: ;R01 Start XOR A OUT (SYS_PORT.ON),A .loop: LD A,(HL) ;R01 INC HL OR A RET Z CALL PRINTX JR .loop ; PRINTX: CP "\r" ; JR Z,.CR_ CP "\n" ; JR Z,.LF_ LD BC,1*256 + BIOS.LP_PRINT_SYM RST ToBIOS_18 RET ; .CR_: LD C,BIOS.LP_GET_PLACE RST ToBIOS_18 LD E,0 LD C,BIOS.LP_SET_PLACE RST ToBIOS_18 RET ; .LF_: LD C,BIOS.LP_GET_PLACE RST ToBIOS_18 LD A,#1F CP D JR NZ,.LF2 PUSH DE PUSH HL LD DE,#0020 LD BC,1*256 + BIOS.LP_SCROLL_UD RST ToBIOS_18 ; LD DE,#1F00 LD C,BIOS.LP_SET_PLACE RST ToBIOS_18 ; LD A," " LD BC,#50 + BIOS.LP_PRINT_SYM RST ToBIOS_18 POP HL POP DE DEC D .LF2: INC D LD C,BIOS.LP_SET_PLACE RST ToBIOS_18 RET ;R01 ;R01 End MESSAGES:; 0 10 20 30 40 50 60 70 80 .INCORR: DB "\r\nOld BIOS version.\r\n",0 .ERRPART: DB "\r\nUnknown partition table.",0 .FAILURE: DB "\r\nFatal error! Press RESET to restart.\r\n",0 .ERRIBPB: DB "\r\nInvalid BOOT sector.",0 .NO_SYS: DB "\r\nCan't open SYSTEM.DOS...",0 .NOSHELL: DB "\r\nCan't open SYSTEM.EXE...",0 .STARTDO: DB "\r\nStarting DSS... \r\n\n",0 ; SHELL_NAME: DB '\SYSTEM.EXE /P',0 ROOT: DB 'X:\',0 CORE_NAME: DB "SYSTEM DOS" .Size EQU $-CORE_NAME //////////////////////////////////////////////////////////////////////// ASSERT $<#8200, "Error!!! BIOS LOADING ONLY FIRST #200 BYTES" //////////////////////////////////////////////////////////////////////// CONTINUE: LD HL,0 LD (PARTITION_START_L),HL LD (PARTITION_START_H),HL ; LD BC,1*256 + BIOS.GetMem RST ToBIOS_18 ;GET PAGE FOR DOS LD (LOAD_CORE.BANKDOS),A OUT (SLOT0),A ; CALL GET_BPB ;READ BPB LD HL,MESSAGES.ERRIBPB RET C ; goto FAIL CALL GETROOT ; LD HL,MESSAGES.NO_SYS RET C ; goto FAIL ; [ ] загрузка system.dos больше #4000 байтов LD HL,(FSIZE1) LD A,H OR L JR NZ,.set_size LD DE,(FSIZE0) LD HL,#4000 SBC HL,DE JR NC,.set_no_size .set_size: LD A,#FF .set_no_size: LD (LOAD_CORE.BIG_CORE),A OR A PUSH AF ; загрузка EXX LD HL,(FCLUSTER_H) EXX LD HL,(FCLUSTR_L) LD DE,#C000 ; -bug: счётчик для .SMALL_CLUSTER, баг отрепортил Vasil Ivanov ; LD A,MAX_SECTORS_PER_PAGE ; LD (LOAD_CORE.BIG_CORE),A ; CALL LOAD_CORE ; [ ] загрузка system.dos больше #4000 байтов EX AF,AF' POP AF JR Z,.no_big_core EX AF,AF' JR C,.no_big_core ; IN A,(SLOT1) LD (LOAD_CORE.BANKDOS),A LD A,SUBLOAD_SIZE + 1 LD (LOAD_CORE.max_sectors),A LD (LOAD_CORE.BIG_CORE),A ; теперь это счётчик оставшихся секторов ; LD A,(BOOT_BUFFER + BOOT_SECTOR.SectorsPerCluster) CP MAX_SECTORS_PER_PAGE + 1 ; кол-во загружаемых секторов JP NC,INC_SECTOR_NUM CALL READ_FROM_FAT ; next cluster in chain EX DE,HL EXX EX DE,HL EXX LD DE,#C000 CALL NC,LOAD_CORE .no_big_core: ; RUN_CORE: DI ; LD A,(READ_FAT_TABLE.FAT_PAGE) LD C,BIOS.FreeMem RST ToBIOS_18 ; XOR A OUT (SYS_PORT.OFF),A ; LD A,#10 LD BC,#7FFD OUT (C),A ; LD A,1 LD B,#1F ;1FFD OUT (C),A ; ;DOS LOADED ;[ ] 17.12.2023 загрузка с активного раздела, а не с первого LD A,(DRIVE+1) ; номер раздела LD L,A ; LD A,(DRIVE) ; номер устройства LD C,Dss.Version RST ToDSS JP C,FAIL.NULL ; LD HL,MESSAGES.STARTDO CALL MESSAGE ; XOR A OUT (SYS_PORT.OFF),A ; LD A,(DRIVE) LD BC,Dss.BootDSK.Set RST ToDSS ; LD BC,Dss.BootDSK.Get RST ToDSS ; ADD A,"A" ; LD HL,ROOT LD (HL),A LD C,Dss.ChDir RST ToDSS ; LD HL,SHELL_NAME LD BC,Dss.Exec RST ToDSS .NoShell: JP NC,FAIL.NULL LD HL,MESSAGES.NOSHELL CP DSS_Error.sys.UNEXPECTED_APP_TRMN JP NZ,FAIL JP FAIL.NULL ; INC_SECTOR_NUM: PUSH DE CALL CLUSTER_TO_SECTOR CALL GET_ABSOLUTE_SECTOR LD DE,MAX_SECTORS_PER_PAGE ; количество прочитанных секторов ADD IX,DE JR NC,.no_inc INC HL .no_inc: ; POP DE LD BC,RUN_CORE PUSH BC PUSH HL ; для баланса PUSH HL ; для баланса JP LOAD_CORE.subload ; ; PART_TB: LD HL,(BOOT_BUFFER + BOOT_SECTOR.MBR_SIGNATURE) LD DE,#AA55 ; CF = 0 SBC HL,DE SCF RET NZ ; PUSH BC LD IX,BOOT_BUFFER + BOOT_SECTOR.PARTITION_TABLE LD B, +(_sMBR_PARTITION_TABLE / _sMBR_PARTITION_RECORD) ; ;LD HL,YEPDOS ; .part_loop: LD A,(IX + _sMBR_PARTITION_RECORD.FS_ID) ; ЕСЛИ добавится поддержка ещё нескольких типов ФС, то поменять 1fs на 2fs ; 1 CP PartitionSysTypes.FAT16_LBA JR Z,YEPDOS CP PartitionSysTypes.FAT16 JR Z,YEPDOS CP PartitionSysTypes.FAT16_32Mb JR Z,YEPDOS CP PartitionSysTypes.FAT12 JR Z,YEPDOS CP PartitionSysTypes.FAT32 JR Z,YEPDOS CP PartitionSysTypes.FAT32_LBA JR Z,YEPDOS ; ; 2fs ; EXX ; LD HL,SUPPORTED_PARTITIONS ; LD BC,SUPPORTED_PARTITIONS.Size ; CPIR ; EXX ; RET Z ;JR Z,YEPDOS ; .next: LD DE,_sMBR_PARTITION_RECORD ADD IX,DE DJNZ .part_loop ; LD HL,MESSAGES.ERRPART JP FAIL ; 2fs ; SUPPORTED_PARTITIONS: ; ;.Empty DB #00 ; .FAT12 DB #01 ; .FAT16_32Mb DB #04 ; ;.Extended DB #05 ; .FAT16 DB #06 ; ;.HPFS_NTFS DB #07 ; .FAT32 DB #0B ; .FAT32_LBA DB #0C ; .FAT16_LBA DB #0E ; ;.Win_Ext_LBA DB #0F ; ;.Linux_swap DB #82 ; ;.Linux DB #83 ; ;.Linux_extended DB #85 ; .Size EQU $-SUPPORTED_PARTITIONS ; ; YEPDOS: ;[ ] 17.12.2023 загрузка с активного раздела, а не с первого LD A,#80 CP (IX + _sMBR_PARTITION_RECORD.isActive) JR NZ,PART_TB.next LD A,4 ;!HARDCODE счетчик записей партиций в MBR SUB B PUSH AF ; номер загрузочного раздела ; LD L,(IX + _sMBR_PARTITION_RECORD.Start_LBA + 0) LD H,(IX + _sMBR_PARTITION_RECORD.Start_LBA + 1) PUSH HL LD (PARTITION_START_L),HL LD L,(IX + _sMBR_PARTITION_RECORD.Start_LBA + 2) LD H,(IX + _sMBR_PARTITION_RECORD.Start_LBA + 3) POP IX LD (PARTITION_START_H),HL LD A,(DRIVE) LD DE,BOOT_BUFFER LD BC,1*256 + BIOS.DRV_READ RST ToBIOS_18 ;[ ] 17.12.2023 загрузка с активного раздела, а не с первого POP AF POP BC LD L,A ; номер загрузочного раздела LD A,C ; RET ; ; GET_BPB: XOR A LD HL,FatBuffer LD B,_sysFatBuffer .loop_clear: LD (HL),A INC HL DJNZ .loop_clear LD H,A LD L,A ; LD (FatBuffer.FAT1_SEC_H),HL ; high word first sector FAT #1 ; LD (FatBuffer.RootDirFirstSector_H),HL ; LD (FatBuffer.SectorsPerFAT_H),A ; PUSH HL POP IX LD DE,BOOT_BUFFER LD BC,1*256 + BIOS.DRV_READ LD A,(DRIVE) RST ToBIOS_18 RET C ; перекидывание части загрузчика из 0 сектора LD HL,BOOT_BUFFER + (_sBOOT_SECTOR.PARTITION_TABLE - ZERO_SECTOR_OF_BPB.Size) LD DE,ZERO_SECTOR_OF_BPB LD BC,ZERO_SECTOR_OF_BPB.Size LDIR ; ; -bug: пересечение буферов FAT и SYSTEM.DOS, баг отрепортил Vasil Ivanov LD BC,1*256 + BIOS.GetMem RST ToBIOS_18 ;GET PAGE FOR DOS LD (READ_FAT_TABLE.FAT_PAGE),A ; ; LD A,(DRIVE) LD B,A AND #F0 LD C,A CP #80 JR NZ,.NX1 CALL PART_TB ;HDD RET C ;[ ] 17.12.2023 загрузка с активного раздела, а не с первого LD (DRIVE+1),HL ; .NX1: ;CP #00 AND A JR NZ,.NX2 ; ; SET_PRM if FDD PUSH BC LD A,B LD C,BIOS.DRV_GET_PAR RST ToBIOS_18 LD A,(BOOT_BUFFER + BOOT_SECTOR.SectorsPerTrack) LD L,A POP AF LD C,BIOS.DRV_SET_PAR RST ToBIOS_18 ; .NX2: LD HL,(BOOT_BUFFER + BOOT_SECTOR.MBR_SIGNATURE) LD DE,#AA55 ;AND A SBC HL,DE SCF RET NZ ; LD A,(BOOT_BUFFER + BOOT_SECTOR.DRIVE_TYPE) CP #F0 RET C ; ;LD HL,(BOOT_BUFFER + BOOT_SECTOR.BytesPerSector) LD A,(BOOT_BUFFER + BOOT_SECTOR.SectorsPerCluster) LD (FatBuffer.SectorsPerCluster),A ; calc. first sector FAT LD HL,(BOOT_BUFFER + BOOT_SECTOR.RESERVED_SECTORS) LD (FatBuffer.FAT1_SEC_L),HL ; low word first sector FAT #1 ; XOR A LD B,A LD C,A EXX LD H,A LD L,A LD D,A LD E,A EXX ; ;LD BC,0 LD DE,(BOOT_BUFFER + BOOT_SECTOR.SectorsPerFAT16) LD A,E OR D JR NZ,.skip_high ; EXX LD DE,(BOOT_BUFFER + BOOT_SECTOR.SectorsPerFAT32 + 2) LD A,E EXX ;LD BC,(BOOT_BUFFER + BOOT_SECTOR.SectorsPerFAT32 + 2) ;LD A,C LD (FatBuffer.SectorsPerFAT_H),A LD DE,(BOOT_BUFFER + BOOT_SECTOR.SectorsPerFAT32) ; .skip_high: LD (FatBuffer.SectorsPerFAT_L),DE LD A,(BOOT_BUFFER + BOOT_SECTOR.Number_of_FATs) ; amount FATs CP 1 JR Z,.one_FAT DEC A ADD HL,DE EXX ADC HL,DE EXX ;JR NC,.no_inc_BC ;INC BC .no_inc_BC: ; .one_FAT: ; .loop1: ADD HL,DE EXX ADC HL,DE EXX ;JR NC,.loop1_1 ;INC BC .loop1_1: DEC A JR NZ,.loop1 ; LD (FatBuffer.RootDirFirstSector_L),HL ; first sector DIR EXX ; можно сразу тут загнать старший байт, потому-что дла FAT32 следующий расчёт - это прибавление нуля. LD (FatBuffer.FirstDataSector_H),HL EXX ;LD (FatBuffer.FirstDataSector_H),BC LD BC,(BOOT_BUFFER + BOOT_SECTOR.BytesPerSector) LD A,B AND A ; RL C RLA RL C RLA RL C RLA ; LD C,A LD B,0 ; BC - File handels in sectors ; EX DE,HL LD HL,(BOOT_BUFFER + BOOT_SECTOR.FilesInRootDIR) ; 0 for fat32 LD A,H OR L JR Z,.skip_loop2 ; DEC HL XOR A .loop2: INC A RET C SBC HL,BC JR NC,.loop2 ; .skip_loop2: EX DE,HL LD C,A ; A - sectors in DIR LD B,0 LD (FatBuffer.DirSizeInSectors),A ADD HL,BC ; Start DATA area LD (FatBuffer.FirstDataSector_L),HL ; B = 0 ; LD HL,(BOOT_BUFFER + BOOT_SECTOR.BytesPerSector) LD A,(FatBuffer.SectorsPerCluster) ;!TODO FATcacheSize ; calc. cluster size XOR 1 JR Z,.loop3.end RRA .loop3: ADD HL,HL RRA JP NC,.loop3 .loop3.end: ; LD (FatBuffer.BytesPerCluster),HL ; проверка на размер кластера больше 32 кб - не поддерживается ; !TODO ; ..... ; //////////////////////////////////////////////////////////////////////// ; LD HL,(BOOT_BUFFER + BOOT_SECTOR.SectorsPerDrive) LD BC,0 LD A,H OR L JP NZ,.HDDSMAL ; LD HL,(BOOT_BUFFER + BOOT_SECTOR.BPB_BIG_TOTAL_SECTORS_L) LD BC,(BOOT_BUFFER + BOOT_SECTOR.BPB_BIG_TOTAL_SECTORS_H) .HDDSMAL: ; PUSH BC ; Total Sectors high PUSH HL ; Total Sectors low XOR A ;LD H,A ;LD L,A ;LD (FatBuffer.CacheBlock),HL ; A = 0 ; LD DE,(FatBuffer.SectorsPerFAT_H) ; LD D,A ; LD HL,(FatBuffer.SectorsPerFAT_L) ; ; DE:HL = SectorsPerFAT ; ; ; LD A,(BOOT_BUFFER + BOOT_SECTOR.Number_of_FATs) ; DEC A ; LD B,A ; JR Z,.loop_mul_end ; A = 0 LD HL,(FatBuffer.SectorsPerFAT_H) LD H,A LD D,H LD E,L ;EX DE,HL EXX LD HL,(FatBuffer.SectorsPerFAT_L) LD D,H LD E,L ; HL':HL = SectorsPerFAT ; DE':DE = SectorsPerFAT LD A,(BOOT_BUFFER + BOOT_SECTOR.Number_of_FATs) DEC A LD B,A ; CALL NZ,ALL_SECTORS_PER_FATs EXX PUSH HL EXX POP DE ; DE:HL - sectors per FATs ; .Number_of_FATs * .SectorsPerFAT ; .loop_mul: ADD HL,HL ; EX DE,HL ; ADC HL,HL ; EX DE,HL ; DJNZ .loop_mul .loop_mul_end: ; .DirSizeInSectors + .Number_of_FATs * .SectorsPerFAT LD B,0 LD A,(FatBuffer.DirSizeInSectors) LD C,A ADD HL,BC JR NC,.no_inc_DE INC DE .no_inc_DE: ; .RESERVED_SECTORS + .DirSizeInSectors + .Number_of_FATs * .SectorsPerFAT LD BC,(BOOT_BUFFER + BOOT_SECTOR.RESERVED_SECTORS) ADD HL,BC JR NC,.no_inc_de INC DE .no_inc_de: ; Total_Sectors - (.RESERVED_SECTORS + .DirSizeInSectors + .Number_of_FATs * .SectorsPerFAT) AND A LD B,D LD C,E POP DE ; Total Sectors low EX DE,HL SBC HL,DE EX (SP),HL ; Total Sectors high SBC HL,BC POP DE ; Total Sectors low ; HL:DE = DataSec ; LD A,(FatBuffer.SectorsPerCluster) ; HL:DE / A => DE:BC, H=0, L - остаток ;CALL DIV_by_Shifts LD C,A DEC A JR Z,.DIV_exit ; AND E LD B,A ; остаток LD A,C RRCA ; .DIV_loop: SRL H RR L RR D RR E RRCA JP NC,.DIV_loop LD A,B .DIV_exit: LD B,D LD C,E EX DE,HL LD H,0 LD L,A ; ; выясняем разрядность FAT LD A,D OR E JR NZ,.its_FAT32 ; DE=0 ; LD (FatBuffer.RootDirStartCluster_L),DE ; LD (FatBuffer.RootDirStartCluster_H),DE LD HL,4084 SBC HL,BC LD A,FAT_TYPE.x12 JR NC,.SET_VARS ; LD HL,65524 SBC HL,BC LD A,FAT_TYPE.x16 JR NC,.SET_VARS ; .its_FAT32: LD A,(BOOT_BUFFER + BOOT_SECTOR.MainFATnumber) CP #80 JR C,.mirrored_FATs ;если все копии FAT используются ; используется только одна копия FAT LD HL,(FatBuffer.FAT1_SEC_H) LD DE,(FatBuffer.SectorsPerFAT_H) LD D,0 EXX LD HL,(FatBuffer.FAT1_SEC_L) LD DE,(FatBuffer.SectorsPerFAT_L) AND #0F ; JR Z,.first_FAT_active ; LD B,A ; ; ; .fat_calc_loop: ADD HL,DE ; EXX ; ADC HL,DE ; EXX ; DJNZ .fat_calc_loop ; LD B,A CALL NZ,ALL_SECTORS_PER_FATs ; .first_FAT_active: LD (FatBuffer.FAT1_SEC_L),HL EXX LD (FatBuffer.FAT1_SEC_H),HL .mirrored_FATs: ; LD HL,(BOOT_BUFFER + BOOT_SECTOR.RootDirStartCluster) LD DE,(BOOT_BUFFER + BOOT_SECTOR.RootDirStartCluster+2) LD (FatBuffer.RootDirStartCluster_L),HL LD (FatBuffer.RootDirStartCluster_H),DE CALL CLUSTER_TO_SECTOR.no_prepare LD (FatBuffer.RootDirFirstSector_L),IX LD (FatBuffer.RootDirFirstSector_H),HL LD A,FAT_TYPE.x32 ; .SET_VARS: LD (FatBuffer.FAT_TYPE),A LD DE,0 CALL READ_FAT_TABLE AND A RET ; ; HL:HL' - first FAT sector ; DE:DE' - sectors per one FAT ; A - number of FATs (counts from 0) ALL_SECTORS_PER_FATs: ADD HL,DE EXX ADC HL,DE EXX DJNZ ALL_SECTORS_PER_FATs RET ;NSECTOR: ; in: HL':HL - CLUSTER ; out: HL:IX - SECTOR CLUSTER_TO_SECTOR: EXX PUSH HL EXX POP DE ; DE:HL - cluster ; .no_prepare: PUSH BC LD BC,-2 ADD HL,BC JR C,.no_dec_de DEC DE .no_dec_de: ; cluster = cluster - 2 ; LD A,(FatBuffer.SectorsPerCluster) XOR 1 JR Z,.skip ; RRA .loop: ADD HL,HL RL E RL D ; RRA JR NC,.loop ; .skip: EX DE,HL PUSH DE POP IX LD DE,(FatBuffer.FirstDataSector_L) ADD IX,DE LD DE,(FatBuffer.FirstDataSector_H) ADC HL,DE ; POP BC RET ; ; поиск system.dos GETROOT: LD HL,(FatBuffer.RootDirStartCluster_L) PUSH HL LD HL,(FatBuffer.RootDirStartCluster_H) PUSH HL LD A,(FatBuffer.FAT_TYPE) CP FAT_TYPE.x32 LD A,(FatBuffer.DirSizeInSectors) JR NZ,.load_and_search ; LD A,(FatBuffer.SectorsPerCluster);!FIXIT прочтёт только первый кластер каталога на FAT32 .load_and_search: LD HL,(FatBuffer.RootDirFirstSector_H) LD IX,(FatBuffer.RootDirFirstSector_L) ;LD BC,(PARTITION_START_L) ;LD DE,(PARTITION_START_H) ; [x] 28/04/2024. Bug with incorrect reading root dir. Reported by Roman "Romychs" Boykov. ;ADD IX,BC ;ADC HL,DE ; .NEXT_CLUSTER: CALL GET_ABSOLUTE_SECTOR CALL .NEXT_SECTOR ; POP HL EXX POP HL RET C RET NZ CALL READ_FROM_FAT RET C EX DE,HL PUSH HL EXX EX DE,HL PUSH HL EXX ; in: HL':HL - CLUSTER ; out: HL:IX - SECTOR CALL CLUSTER_TO_SECTOR LD A,(FatBuffer.SectorsPerCluster) JR .NEXT_CLUSTER ; ; .NEXT_SECTOR: PUSH AF ; [x] 28/04/2024. Bug with incorrect reading root dir. Reported by Roman "Romychs" Boykov. ;ADD IX,BC ;ADC HL,DE ; PUSH IX PUSH HL LD BC,1*256 + BIOS.DRV_READ LD DE,DIR_BUFFER LD A,(DRIVE) RST ToBIOS_18 CALL SEARCH POP HL POP IX POP BC RET C RET NZ LD A,B ; next sector LD BC,1 ; [x] 28/04/2024. Bug with incorrect reading root dir. Reported by Roman "Romychs" Boykov. ADD IX,BC JR NC,.no_inc_HL INC HL .no_inc_HL: ; DEC A JR NZ,.NEXT_SECTOR RET ; ; ; ; ; вход: HL:IX - относительный сектор ; выход: HL:IX - абсолютный сектор GET_ABSOLUTE_SECTOR: LD DE,(PARTITION_START_L) ADD IX,DE LD DE,(PARTITION_START_H) ADC HL,DE RET ; SEARCH: LD C,17 ;HANDELS PER SECTOR 512/32 + 1 LD IX, DIR_BUFFER - FAT_DIRECTORY_RECORD .SKIPNAM: LD DE,FAT_DIRECTORY_RECORD .SKIPNAM_DE: ADD IX,DE DEC C RET Z ; LD A,(IX+FAT_DIRECTORY_RECORD.NAME) OR A SCF RET Z ; CP #E5 JR Z,.SKIPNAM_DE ; LD A,(IX+FAT_DIRECTORY_RECORD.ATTRIBUT) AND FAT_ATTR.DIRECTORY JR NZ,.SKIPNAM_DE ; LD DE,CORE_NAME PUSH IX POP HL LD B,CORE_NAME.Size ; .loop: LD A,(DE) CP (HL) JR NZ,.SKIPNAM INC HL INC DE DJNZ .loop ; PUSH IX POP HL LD DE,HANDBUF LD BC,FAT_DIRECTORY_RECORD LDIR ; ZF = 1, CF = 0, A != 0 AND A ; на выходе ZF = CF = 0 RET ; HL - CLUSTER ; DE - ADDRESS ; !TODO сделать тут определение размера SYSTEM.DOS ; [ ] и возможность загрузить больше 1 страницы LOAD_CORE: LD (READMEM),DE .loop: PUSH HL EXX PUSH HL EXX ; CALL CLUSTER_TO_SECTOR ; ;LD A,(FatBuffer.FAT_TYPE) ; CP FAT_TYPE.x32 ; JR NZ,.skip_it ; ;LD DE,(PARTITION_START_L) ;ADD IX,DE ;LD DE,(PARTITION_START_H) ;ADC HL,DE CALL GET_ABSOLUTE_SECTOR ;.skip_it: ; LD DE,(READMEM) LD A,(BOOT_BUFFER + BOOT_SECTOR.SectorsPerCluster) .max_sectors+1: CP MAX_SECTORS_PER_PAGE JR C,.SMALL_CLUSTER ; .subload: LD A,(.max_sectors) LD B,A LD C,BIOS.DRV_READ_LONG LD A,(LOAD_CORE.BANKDOS) EX AF,AF' LD A,(DRIVE) RST ToBIOS_18 EXX POP HL EXX POP HL RET ; .SMALL_CLUSTER: LD B,A LD C,BIOS.DRV_READ_LONG .BANKDOS+1: LD A,0 EX AF,AF' LD A,(DRIVE) RST ToBIOS_18 ; LD HL,(READMEM) LD DE,(FatBuffer.BytesPerCluster) ADD HL,DE LD (READMEM),HL EXX POP HL EXX POP HL CCF RET NC ; [ ] загрузка system.dos больше #4000 байтов .BIG_CORE+1: LD A,0 DEC A LD (.BIG_CORE),A RET Z ; CALL READ_FROM_FAT ;CALL R_F_FAT RET C EXX EX DE,HL EXX EX DE,HL JP .loop ; ; ; HL:DE / A => DE:BC, H=0, L - остаток ; DIV_by_Shifts: ; LD C,A ; DEC A ; JR Z,.DIV_exit ; ; ; AND E ; LD B,A ; остаток ; LD A,C ; RRCA ; ; ; .DIV_loop: SRL H ; RR L ; RR D ; RR E ; RRCA ; JP NC,.DIV_loop ; LD A,B ; .DIV_exit: LD B,D ; LD C,E ; EX DE,HL ; LD H,0 ; LD L,A ; RET //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// DISPLAY "SECTORS 1..3 DATA ENDS:\t",/H,$,". Size: ",/D,$-ORG_ADDRESS," b. Free: ",/D,512*3-($-ORG_ADDRESS)," b." ZERO_SECTOR_OF_BPB: .physical EQU $$$ //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// ;FAT_BLOCK * Sectors_in_Block = SECTOR_OF_FAT ; in: HL - Cache block ; out: C:HL - logical number ; B = 0 GET_SECTOR_OF_FAT: LD A,(FatBuffer.FAT_TYPE) LD B,FAT_CACHE.Degree_32 ;!FIXIT сделать через переменную XOR FAT_TYPE.x32 JR Z,.next LD B,FAT_CACHE.Degree ;!FIXIT сделать через переменную XOR A .next: LD C,A ; .loop: ADD HL,HL ;x2 ADC A,C DJNZ .loop ; LD C,A RET ; ;вход: HL - номер кластера ;выход: HL - адрес нужной ячейки в странице FATPAGE ; CF - чётный/нечётный адрес кластера GET_FAT12_CELL: LD D,H LD E,L SRL H RR L ; сдвиг вправо через CF PUSH AF ; сохр. флаг ADD HL,DE ; CLUSTER * 1.5 ; IF FAT_CACHE.Size_12 < #1800 ;!FIXIT оптимизировать LD A,H LD B,H ; AND #1F ;AND FAT_CACHE.Size_Mask_16 ; LD H,A LD A,B ; RLCA RLCA RLCA ;DUP FAT_CACHE.Degree_16 ; RRCA ;EDUP AND #07 ;AND FAT_CACHE.Part_Mask_16 ; ; [ ] поменялся вход в процедуру READ_FAT_TABLE. Раньше номер блока в рег. A передавался LD DE,(FatBuffer.CacheBlock) ; BC - BLOCK FAT IN CASH CP E LD E,A ; CALL NZ,READ_FAT_TABLE ; прочитать в кеш 16 секторов FAT-а ENDIF ; LD DE,FATPAGE.cache ADD HL,DE POP AF RET ; ;вход: HL - номер кластера ;выход: HL - адрес нужной ячейки в странице FATPAGE GET_FAT16_CELL: LD A,H LD B,H AND FAT_CACHE.Size_Mask_16 LD H,A LD A,B ; A=A/16 ; A - BLOCK FAT (1 BLOCK = 8192 BYTES) DUP FAT_CACHE.Degree_16 RRCA EDUP ;AND #0F AND FAT_CACHE.Part_Mask_16 ; ADD HL,HL ; HL - FAT OFFSET (FROM CASH) LD DE,(FatBuffer.CacheBlock) ; BC - BLOCK FAT IN CASH CP E LD E,A ; CALL NZ,READ_FAT_TABLE ; A != C - READ NEW BLOCK FAT LD DE,FATPAGE.cache ; начало кеша FAT-а ADD HL,DE ; на ячейку FAT RET ; ; ;RE_FAT: ;RX01 ; Прочитать в кеш ХХ секторов FAT-а ; DE - NEW FAT BLOCK READ_FAT_TABLE: PUSH HL ; EX DE,HL LD (FatBuffer.CacheBlock),HL ; CALL GET_SECTOR_OF_FAT ; ; BC:HL - номер лог.сектора LD DE,(FatBuffer.FAT1_SEC_L) ADD HL,DE ; ; EX DE,HL ; LD XH,D ; LD XL,E PUSH HL POP IX ; LD HL,(FatBuffer.FAT1_SEC_H) .no_inc: ADC HL,BC ; HL:IX - SECTOR FAT FOR READING ; ;LD DE,(PARTITION_START_L) ;ADD IX,DE ;LD DE,(PARTITION_START_H) ;ADC HL,DE CALL GET_ABSOLUTE_SECTOR ; LD DE,FAT_SECTORS_BUFFER ; IN A,(SLOT3) PUSH AF .FAT_PAGE+1: LD A,0 OUT (SLOT3),A ; LD A,(FatBuffer.FAT_TYPE) XOR FAT_TYPE.x32 LD BC,FAT_CACHE.Sectors_16*256 + BIOS.DRV_READ JR NZ,.next LD B,FAT_CACHE.Sectors_32 .next: LD A,(DRIVE) RST ToBIOS_18 ; POP AF OUT (SLOT3),A POP HL RET ;вход: HL':HL - номер кластера ;выход: HL - адрес нужной ячейки в странице FATPAGE GET_FAT32_CELL: ; двигаем влево HL':H LD A,H EXX LD C,A LD A,H AND FAT_CACHE.Size_Mask_32 ; #0F LD H,A LD A,C ; LD B,FAT_CACHE.Degree ; 4 сдвига .loop_block: RLCA ; << H RL L ; << L' RL H ; << H' DJNZ .loop_block EXX ; В итоге тут в HL' номер блока FAT ; ; HL - FAT32 OFFSET (FROM CASH) LD A,H AND FAT_CACHE.Size_Mask_32 ; #0F LD H,A ADD HL,HL ADD HL,HL PUSH HL AND A ; EXX EX DE,HL LD HL,(FatBuffer.CacheBlock) ; BC - BLOCK FAT IN CASH SBC HL,DE CALL NZ,READ_FAT_TABLE ; A != C - READ NEW BLOCK FAT POP HL LD DE,FATPAGE.cache ; начало кеша FAT-а ADD HL,DE ; на ячейку FAT RET ; ;------------------------------------------------------------------------------------------------ ; Прочитать из кеша FAT-а номер след. кластера ; вход: hl - номер кластера (младшее слово) ; hl' - номер кластера (старшее слово. только для FAT32) ; выход: hl - номер кластера (младшее слово) ; hl' - номер кластера (старшее слово) ; de - номер след. кластера (младшее слово) ; de' - номер след. кластера (старшее слово) ; если DE':DE = 0, то кластер HL':HL свободен ; CF - конец цепочки ;------------------------------------------------------------------------------------------------ READ_FROM_FAT: PUSH HL ; IN A,(SLOT3) PUSH AF LD A,(READ_FAT_TABLE.FAT_PAGE) OUT (SLOT3),A ; LD A,(FatBuffer.FAT_TYPE) CP FAT_TYPE.x16 JR C,.FAT12 JR NZ,.FAT32 ; fat16, просто читать след. номер .FAT16: CALL GET_FAT16_CELL LD E,(HL) ; прочитать номер кластера INC HL LD D,(HL) ; LD HL,SERVICE_SECTORS.FAT16 .exit: POP AF OUT (SLOT3),A ; обнуляем CF и устанавливаем код ошибки = DssErr.sys.NO_ERROR XOR A ; проверка на служ. кластеры SBC HL,DE POP HL EXX LD H,A LD L,A LD D,A LD E,A EXX RET ; ; .FAT12: CALL GET_FAT12_CELL LD E,(HL) INC HL LD D,(HL) LD HL,SERVICE_SECTORS.FAT12 JR NC,.Correct_2 .Correct_1: LD A,E AND #F0 DUP 4 ; вправо на 4 битa RR D RRA EDUP LD E,A JR .exit ; .Correct_2: LD A,D AND #0F LD D,A JR .exit ; .FAT32: EXX PUSH HL EXX ; CALL GET_FAT32_CELL ; прочитать младшее слово номера кластера LD E,(HL) INC HL LD D,(HL) INC HL ; прочитать старшее слово номера кластера LD A,(HL) INC HL EX AF,AF' LD A,(HL) EXX AND #0F LD D,A EX AF,AF' LD E,A EXX ; обнуляем CF и устанавливаем код ошибки = DssErr.sys.NO_ERROR XOR A ; проверка на служ. кластеры младшего слова кластера LD HL,SERVICE_SECTORS.FAT32.Low SBC HL,DE ; проверка на служ. кластеры старшего слова кластера EXX LD HL,SERVICE_SECTORS.FAT32.High SBC HL,DE POP HL EXX POP BC LD A,B OUT (SLOT3),A POP HL LD A,0 RET ; ; ; //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// ASSERT ($-ZERO_SECTOR_OF_BPB) <= LOADER_IN_BPB.MAX_SIZE, "---< CRITICAL ERROR! Loader is too big >----" DISPLAY "SECTORS 0 DATA ENDS:\t\t",/H,$,". Size: ",/D,$-ZERO_SECTOR_OF_BPB," b. Free: ",/D,LOADER_IN_BPB.MAX_SIZE-($-ZERO_SECTOR_OF_BPB)," b." ZERO_SECTOR_OF_BPB_END: ZERO_SECTOR_OF_BPB.Size EQU ZERO_SECTOR_OF_BPB_END - ZERO_SECTOR_OF_BPB //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// ; ; //////////////////////////////////////////////////////////////////////// ; Area for boot sector [512Bytes] ;BOOT _sBOOT_SECTOR_PARAMS = $ BOOT_BUFFER EQU $ DIR_BUFFER EQU BOOT_BUFFER+512 ; ;FAT_SECTORS_BUFFER EQU DIR_BUFFER+512 ;VALUE EQU 3*512+FAT_SECTORS_BUFFER FAT_SECTORS_BUFFER EQU #C000 VALUE EQU DIR_BUFFER+512 FatBuffer _sysFatBuffer = VALUE HANDBUF EQU VALUE + _sysFatBuffer FCLUSTER_H EQU HANDBUF + FAT_DIRECTORY_RECORD.FIRST_CLUSTER_H FCLUSTR_L EQU HANDBUF + FAT_DIRECTORY_RECORD.FIRST_CLUSTER_L FSIZE0 EQU HANDBUF + FAT_DIRECTORY_RECORD.F_SIZE FSIZE1 EQU HANDBUF + FAT_DIRECTORY_RECORD.F_SIZE + 2 PARTITION_START_H EQU FSIZE1+2 PARTITION_START_L EQU PARTITION_START_H+2 READMEM EQU PARTITION_START_L+2 ;BIG_CORE EQU READMEM+2 ;FAT_PAGE EQU READMEM+2 DISPLAY "BOOT_BUFFER ",/H,BOOT_BUFFER DISPLAY "DIR_BUFFER ",/H,DIR_BUFFER DISPLAY "FatBuffer ",/H,FatBuffer ENT ENDMODULE OUTEND ;[]-----------------------------------------------------------[]