├── FAT32-Bootsector.exe ├── Install.sh ├── LICENSE ├── NASM LICENSE ├── README.md ├── backup └── dummy_file ├── bin └── dummy_file ├── nasm.exe └── src ├── app_source.cpp └── bootloader.asm /FAT32-Bootsector.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TebexPL/FAT32-Bootsector/68e3b62ff7279cdeec1198f218438c9f4cb6031c/FAT32-Bootsector.exe -------------------------------------------------------------------------------- /Install.sh: -------------------------------------------------------------------------------- 1 | RED='\033[0;31m' 2 | NC='\033[0m' 3 | clear 4 | printf "${RED}" 5 | echo "This script needs NASM to compile source code, It will be installed right now" 6 | printf "${NC}" 7 | echo "(press anything to continue)" 8 | read -n 1 -s 9 | clear 10 | sudo apt-get install nasm -qq > /dev/null 11 | 12 | 13 | 14 | 15 | bool="1" 16 | 17 | clear 18 | printf "${RED}" 19 | echo "To exit press enter with no value, at any time" 20 | printf "${NC}" 21 | echo "(press anything to continue)" 22 | read -n 1 -s 23 | while [ "$bool" = "1" ]; do 24 | clear 25 | echo "Filename without extention: " 26 | echo "---------------------------" 27 | read 28 | if [ -z "$REPLY" ] ; then 29 | exit 30 | fi 31 | while (( "${#REPLY}" > "8" )) ; do 32 | echo "max 8 characters" 33 | read 34 | done 35 | _FILENAME=$REPLY 36 | filename=$REPLY 37 | while (( "${#_FILENAME}" < "8" )) ; do 38 | _FILENAME="$_FILENAME " 39 | done 40 | clear 41 | echo "Extention: " 42 | echo "----------" 43 | read 44 | if [ -z "$REPLY" ] ; then 45 | exit 46 | fi 47 | while (( "${#REPLY}" > "3" )) ; do 48 | echo "max 3 characters" 49 | read 50 | done 51 | filename+="." 52 | filename+=$REPLY 53 | _FILENAME="$_FILENAME""$REPLY" 54 | while (( "${#_FILENAME}" < "11" )) ; do 55 | _FILENAME="$_FILENAME " 56 | done 57 | 58 | _FILENAME=$(echo "$_FILENAME" | awk '{printf toupper($0)}') 59 | 60 | clear 61 | echo "Is that correct?(y/n)" 62 | echo "---------------------" 63 | echo "Filename: "$filename 64 | 65 | read 66 | if [ -z "$REPLY" ] ; then 67 | exit 68 | fi 69 | if [ "$REPLY" = "y" ] || [ "$REPLY" = "Y" ] ; then 70 | bool="0" 71 | else 72 | bool="1" 73 | fi 74 | 75 | done 76 | 77 | nasm -d _FILENAME=\'"$_FILENAME"\' -o bin/bootloader.bin -f bin src/bootloader.asm 78 | 79 | clear 80 | 81 | printf "${RED}" 82 | echo "CHECK TWICE WHAT YOU'RE DOING NOW, IF YOU CHOOSE WRONG DEVICE YOUR PC WON'T BOOT"; 83 | printf "${NC}" 84 | echo "(press anything to continue)" 85 | read -n 1 -s 86 | clear 87 | echo "Choose device you want to boot from:" 88 | echo "--------------------------------------------------------------------------------" 89 | devices=$(sudo ls /dev/disk/by-id/ | grep -v "part[0-9]$"); 90 | num=1 91 | for word in $devices 92 | do 93 | device[$num]=$word 94 | echo $num". "${device[$num]}; 95 | num=$((num+1)); 96 | done 97 | read 98 | while [ -z "$REPLY" ] || (( "$REPLY" < "1" )) || (( "$REPLY" >= "$num")) ; do 99 | if [ -z "$REPLY" ] ; then 100 | exit 101 | fi 102 | echo "Not a valid value!" 103 | read 104 | if [ -z "$REPLY" ] ; then 105 | exit 106 | fi 107 | done 108 | 109 | 110 | bootdev=${device[$REPLY]} 111 | clear 112 | echo "Choose partition you want to boot from:" 113 | echo "---------------------------------------" 114 | parts="$(sudo parted /dev/disk/by-id/${device[$REPLY]} print | grep "^ [0-9]")"; 115 | 116 | if [ $? -eq 0 ]; then 117 | info=$(sudo parted /dev/disk/by-id/${device[$REPLY]} print | grep "^Number"); 118 | info=${info%"Flags"} 119 | echo "$info" 120 | else 121 | clear 122 | echo "Bad data or device not available" 123 | exit 124 | fi 125 | 126 | num=1 127 | while read -r line; do 128 | 129 | part[$num]=$line 130 | curpart=${part[$num]%"boot"} 131 | echo " $curpart" 132 | num=$((num+1)); 133 | done <<< "$parts" 134 | read 135 | while [ -z "$REPLY" ] || (( "$REPLY" < "1" )) || (( "$REPLY" >= "$num")) || [ -z "$(echo ${part[$REPLY]} | grep "fat32")" ] ; do 136 | if [ -z "$REPLY" ] ; then 137 | exit 138 | fi 139 | echo "Not a valid value or partition isn't FAT32!" 140 | read 141 | 142 | done 143 | clear 144 | bootpart=$REPLY 145 | echo "Are you sure you want to install bootsector on this device?[y/n]" 146 | echo "----------------------------------------------------------------" 147 | echo "Device: "$bootdev 148 | echo 149 | echo "Partition: $info" 150 | echo " ${part[$REPLY]%"boot"}" 151 | read 152 | if [ "$REPLY" = "y" ] || [ "$REPLY" = "Y" ] ; then 153 | echo 154 | else 155 | exit 156 | fi 157 | sudo dd if=/dev/disk/by-id/$bootdev of=backup/backup_bootsector_MBR.bin count=1 status=none 158 | sudo chmod 777 backup/backup_bootsector_MBR.bin 159 | tmp=$(wc -c ./bin/bootloader.bin | awk '{printf $1}') 160 | if (("$tmp" > "446")) ; then 161 | clear 162 | printf "${RED}" 163 | echo "Critical Error - bootsector code exceeds 446 bytes"; 164 | echo "No changes were made to your device"; 165 | printf "${NC}" 166 | exit 167 | fi 168 | if [ -z "$(echo ${part[$bootpart]} | grep "boot" )" ] ; then 169 | sudo parted /dev/disk/by-id/$bootdev toggle $bootpart boot > /dev/null 170 | fi 171 | clear 172 | sudo dd if=./bin/bootloader.bin of=/dev/disk/by-id/$bootdev status=none 173 | echo "DONE!" 174 | printf "${RED}\n" 175 | printf "Now copy "${NC}$filename${RED}" to root directory of selected partition, and you're good to go" 176 | printf "${NC}\n" 177 | echo "(press anything to end)" 178 | read -n 1 -s 179 | clear 180 | 181 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 TebexPL 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NASM LICENSE: -------------------------------------------------------------------------------- 1 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2 | 3 | 4 | ©1996-2015 The NASM development team 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FAT32-Bootsector 2 | 3 | A simple and VERY compact bootsector, which lets you load your bootloader or kernel from a file. 4 | 5 | Build using attached script. 6 | 7 | Notice: Don't read this, read the source code. It is commented, so all the info is there 8 | 9 | ## What does this bootsector actually do? 10 | 11 | Here it is, step by step: 12 | 13 | 1. Check if BIOS supports extended Disk operation 14 | 2. Looks for first active FAT32 partition 15 | 3. Looks for your file on that partition(in root directory) 16 | 4. Loads it into memory 17 | 5. Executes it 18 | 19 | ## State of memory after my bootsector 20 | 21 | ### Your Code: 22 | Your code is loaded at 0x1000:0x0000(segment:offset), or 0x10000(linear). 23 | 24 | ### Registers 25 | Most of registers **are not "zeroed" and garbage is assigned to them** 26 | 27 | **Only those have valid values:** 28 | 29 | + CS:IP - 0x1000:0x0000 (assigned to loaded file) 30 | + DS - 0x1000 (also assigned to loaded file) 31 | + SS:SP - 0x0000:0xFFFF (stack in first segment) 32 | + DL - drive number(for bios interrupts) 33 | 34 | ### Useful data left in memory 35 | 36 | #### after jumping to loaded file there is still some useful data left in memory: 37 | **(all offsets are specified in source code)** 38 | 39 | + 0x7C00 - current disk(device number), FAT address, first data sector address and similar info. 40 | + 0x7E00 - BPB sector of that partition 41 | 42 | 43 | 44 | ## Limitations 45 | + It's all in real mode so maximum size of file shouldn't be bigger than a few hundred Kilobytes 46 | + File must be in root directory of selected partition 47 | + Filename - Bootsector searches for file with 8.3 filename 48 | 49 | ## Install methods 50 | 51 | To install use: 52 | 53 | + On ubuntu compatible systems use Install.sh script 54 | + On Windows use Fat32-bootsector.exe 55 | 56 | **Notice** Windows version does not use letters for partitions, but phisycal partitions(not logical), so: 57 | It may be more difficult to match partition-letter, but on the other hand it supports **multi partition usb drives** 58 | 59 | ## Errors? 60 | 61 | When error occurs bootsector draws error code on the screen. 62 | 63 | ### Here are codes and explanations of errors: 64 | 65 | 0 - extended BIOS functions not availble 66 | 67 | 1 - Bootable partition not found 68 | 69 | 2 - Bootable partition is not FAT32 70 | 71 | 3 - File not found 72 | 73 | 4 - Can't load sectors (BIOS interrupt error) 74 | -------------------------------------------------------------------------------- /backup/dummy_file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TebexPL/FAT32-Bootsector/68e3b62ff7279cdeec1198f218438c9f4cb6031c/backup/dummy_file -------------------------------------------------------------------------------- /bin/dummy_file: -------------------------------------------------------------------------------- 1 | This file only exists so I can commit this directory(it can't be empty) 2 | -------------------------------------------------------------------------------- /nasm.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TebexPL/FAT32-Bootsector/68e3b62ff7279cdeec1198f218438c9f4cb6031c/nasm.exe -------------------------------------------------------------------------------- /src/app_source.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | //Int to string conversion 18 | string intoStr(int n) 19 | { 20 | string tmp; 21 | if(n < 0) { 22 | tmp = "-"; 23 | n = -n; 24 | } 25 | if(n > 9) 26 | tmp += intoStr(n / 10); 27 | tmp += n % 10 + 48; 28 | return tmp; 29 | } 30 | 31 | 32 | //change number of bytes into string of characters(in GiB/MiB/KiB/B) 33 | string bytesToString(unsigned long long bytes){ 34 | if(bytes<1024) 35 | return intoStr(bytes)+"B"; 36 | else if(bytes<1048576) 37 | return intoStr(bytes/1024)+"KiB"; 38 | else if(bytes<1073741824) 39 | return intoStr(bytes/1024/1024)+"MiB"; 40 | else 41 | return intoStr(bytes/1024/1024/1024)+"GiB"; 42 | } 43 | 44 | //Check size of file 45 | std::ifstream::pos_type filesize(string filename) 46 | { 47 | std::ifstream in(filename.c_str(), std::ifstream::ate | std::ifstream::binary); 48 | return in.tellg(); 49 | } 50 | 51 | //check current Y coordinate of console cursor 52 | int wherey() 53 | { 54 | CONSOLE_SCREEN_BUFFER_INFO csbi; 55 | if (!GetConsoleScreenBufferInfo( 56 | GetStdHandle( STD_OUTPUT_HANDLE ), 57 | &csbi 58 | )) 59 | return -1; 60 | return csbi.dwCursorPosition.Y; 61 | } 62 | //change console cursor X coordinate to desired position 63 | void gotox(int x) 64 | { 65 | 66 | COORD c; 67 | c.X = x; 68 | c.Y = wherey(); 69 | SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE),c); 70 | 71 | } 72 | //Read raw bytes from selected device/path 73 | char* readBytes(const char *target, unsigned int offset = 0, unsigned int length = 512) 74 | { 75 | 76 | DWORD dwRead; 77 | HANDLE hTarget=CreateFile(target,GENERIC_READ,FILE_SHARE_VALID_FLAGS,0,OPEN_EXISTING,0,0); 78 | if(hTarget==INVALID_HANDLE_VALUE) 79 | { 80 | CloseHandle(hTarget); 81 | return NULL; 82 | } 83 | if(SetFilePointer(hTarget,offset,0,FILE_BEGIN) == INVALID_SET_FILE_POINTER) 84 | { 85 | CloseHandle(hTarget); 86 | return NULL; 87 | } 88 | char* buffer = new char[length]; 89 | ReadFile(hTarget,buffer,length,&dwRead,0); 90 | CloseHandle(hTarget); 91 | return buffer; 92 | } 93 | //write raw bytes from selected device/path 94 | bool writeBytes(const char *target, char*& buffer, unsigned int offset = 0, unsigned int length = 512) 95 | { 96 | 97 | DWORD dwWritten; 98 | HANDLE hTarget=CreateFile(target,GENERIC_WRITE,FILE_SHARE_VALID_FLAGS,0,OPEN_EXISTING,0,0); 99 | if(hTarget==INVALID_HANDLE_VALUE) 100 | { 101 | CloseHandle(hTarget); 102 | return true; 103 | } 104 | if(SetFilePointer(hTarget,offset,0,FILE_BEGIN) == INVALID_SET_FILE_POINTER) 105 | { 106 | CloseHandle(hTarget); 107 | return true; 108 | } 109 | WriteFile(hTarget,buffer,length,&dwWritten,0); 110 | CloseHandle(hTarget); 111 | return false; 112 | } 113 | 114 | 115 | int main() 116 | { 117 | //Checking administrator rights(It may not be the right way but it works) 118 | cout << "Checking privileges..."; 119 | char * testtable = readBytes("\\\\.\\PhysicalDrive0"); 120 | if(testtable == NULL) 121 | { 122 | system("cls"); 123 | cout << "Error! Need administrator rights...(right click->run as administrator)"; 124 | getch(); 125 | return 1; 126 | } 127 | delete[] testtable; 128 | //Declaring filename variables 129 | string filename, FILENAME, tmp; 130 | //result variable for regex 131 | smatch result; 132 | //WinAPI variables 133 | char drive_letter = 'A'; 134 | char drive_path[] = "\\\\.\\X:"; 135 | VOLUME_DISK_EXTENTS diskInfo; 136 | PARTITION_INFORMATION partitionInfo; 137 | DWORD bytesread = 0; 138 | bool another_letter = false; 139 | 140 | //outputting a small warning 141 | system("cls"); 142 | cout << "\ 143 | Disclaimer: Be aware what you're doing, in worst case your OS won't boot(of course only if you make it that way)\n\ 144 | \n\ 145 | (press anything to continue)"; 146 | getch(); 147 | 148 | //Obtaining 8.3 Filename 149 | do 150 | { 151 | //Obtaining raw filename with dot, and making sure it is valid(regex) 152 | system("cls"); 153 | while(true) 154 | { 155 | 156 | cout << "\ 157 | Enter the FAT32 filename(max 8 chars for name, and 3 for extension, with dot):\n\ 158 | ------------------------------------------------------------------------------\n"; 159 | cin.clear(); 160 | cin.sync(); 161 | cin >> filename; 162 | if(cin.good() && regex_match(filename, result, (regex)"([A-Za-z0-9\\s!#%&'@_`~\\$\\(\\)\\^\\{\\}\\-]{1,8})\\.([A-Za-z0-9\\s!#%&'@_`~\\$\\(\\)\\^\\{\\}\\-]{1,3})")) 163 | break; 164 | else{ 165 | system("cls"); 166 | cout << "Error, wrong filename. Try again:\n\n"; 167 | } 168 | 169 | } 170 | //Just making sure filename is correct 171 | system("cls"); 172 | cout << "\ 173 | Is that correct?(Enter-yes)\n\ 174 | ---------------------------\n" << filename; 175 | 176 | } 177 | while(getch() != 13); 178 | //Transforming to 8.3 format for directory entry 179 | tmp = result[1]; 180 | while(tmp.length() < 8) 181 | tmp += " "; 182 | FILENAME = tmp; 183 | tmp = result[2]; 184 | while(tmp.length() < 3) 185 | tmp += " "; 186 | FILENAME += tmp; 187 | transform(FILENAME.begin(), FILENAME.end(), FILENAME.begin(), ::toupper); 188 | //Reading physical drives list into a vector 189 | 190 | FILE* Drives = popen("wmic diskdrive get index,model,size,partitions", "r"); 191 | tmp.clear(); 192 | vector driveslist; 193 | while(!feof(Drives)){ 194 | tmp += (char)fgetc(Drives); 195 | if(tmp.substr(tmp.length()-1) == "\n"){ 196 | driveslist.push_back(tmp); 197 | tmp.clear(); 198 | } 199 | } 200 | pclose(Drives); 201 | //popping empty line from the end of vector 202 | driveslist.pop_back(); 203 | //sorting devices by index 204 | sort(driveslist.begin()+(unsigned int)1, driveslist.end()); 205 | //Outputting information 206 | system("cls"); 207 | cout << "\ 208 | Select device you want to install bootsector on:(Enter index value of device)\n\ 209 | -----------------------------------------------------------------------------\n"; 210 | cout << driveslist.at(0).substr(0,driveslist.at(0).find_first_of("\n")-1); 211 | //And outputting custom info 212 | gotox(60); 213 | cout << "Mounted volumes\n"; 214 | //Outputting data(information about Physical drives and letters belonging to them) 215 | for(unsigned int i=1;i> chosenDevice; 254 | } 255 | while(!cin.good() || chosenDevice >= driveslist.size()-1); 256 | //Print selection of partitions 257 | system("cls"); 258 | drive_letter = 'A'; 259 | bytesread = 0; 260 | cout << "\ 261 | Select partition you want to boot from(where file will be copied):\n\ 262 | (Enter index value of partition)\n\ 263 | ------------------------------------------------------------------\n"; 264 | cout << "Index Letter Start End Size File System"; 265 | 266 | unsigned int maxPart=0, minPart = 128; 267 | for(unsigned int i=0, j=0; j maxPart) 277 | maxPart = partitionInfo.PartitionNumber; 278 | if(partitionInfo.PartitionNumber-1 < minPart) 279 | minPart = partitionInfo.PartitionNumber-1; 280 | cout << endl; 281 | cout << partitionInfo.PartitionNumber-1; 282 | gotox(10); 283 | cout << drive_letter << ":"; 284 | gotox(20); 285 | cout << bytesToString((unsigned long long)partitionInfo.StartingOffset.QuadPart); 286 | gotox(30); 287 | cout << bytesToString((unsigned long long)partitionInfo.StartingOffset.QuadPart+(unsigned long long)partitionInfo.PartitionLength.QuadPart); 288 | gotox(40); 289 | cout << bytesToString((unsigned long long)partitionInfo.PartitionLength.QuadPart-(unsigned long long)partitionInfo.StartingOffset.QuadPart); 290 | gotox(50); 291 | if(partitionInfo.PartitionType == 0x0B || partitionInfo.PartitionType == 0x0C) 292 | cout << "Supported(FAT32)"; 293 | else 294 | cout << "Not Supported"; 295 | } 296 | } 297 | } 298 | //get info from user(index of chosen partition) 299 | unsigned int chosenPart; 300 | cout << endl; 301 | do{ 302 | cin.clear(); 303 | cin.sync(); 304 | cin >> chosenPart; 305 | } 306 | while(!cin.good() || chosenPart < minPart || chosenPart >= maxPart); 307 | //get letter of selected partition(just to print it later) 308 | drive_letter = 'A'; 309 | bytesread = 0; 310 | for(unsigned int i=0, j=0; j 446) 346 | { 347 | system("cls"); 348 | cout << "Critical Error(binary too big)"; 349 | getch(); 350 | return 1; 351 | } 352 | //Loading binary bootsector code over previously loaded bootsector code 353 | system("cls"); 354 | ifstream f32exe; 355 | f32exe.open("bin/bootloader.bin", ios::binary|ios::in); 356 | f32exe.seekg(f32exe.beg); 357 | f32exe.read(bootsector, 446); 358 | f32exe.close(); 359 | //Before writing to device, a quick check if filesystem is FAT32 360 | if((unsigned char)bootsector[0x1BE +chosenPart*0x10+0x04] != 0x0B && (unsigned char)bootsector[0x1BE +chosenPart*0x10+0x04] != 0x0C) 361 | { 362 | cout << "Error! Partition type not supported... \nMake sure you format this partition as FAT32"; 363 | getch(); 364 | return 1; 365 | } 366 | //If all is good, write new bootsector to the device 367 | if(writeBytes(tmp.c_str(), bootsector) == 0) 368 | cout << "Done! Now copy \"" << filename << "\" to \""<< drive_letter <<":\" partition"; 369 | else{ 370 | cout << "Writing to device finished with errors..."; 371 | getch(); 372 | return 1; 373 | } 374 | getch(); 375 | return 0; 376 | } 377 | -------------------------------------------------------------------------------- /src/bootloader.asm: -------------------------------------------------------------------------------- 1 | ;All of theese are defining offsets in memory to store data later, or to load data 2 | 3 | ;This defines offset to first/ 4 | ;MBR entry-0x10 5 | %define MBR 0x7DAE 6 | 7 | ;This defines address to a buffer for loading root directory clusters 8 | %define RootBuffer 0x0800 9 | ;Offset to this bootloader in memory 10 | %define BootOffset 0x7C00 11 | ;Loaded file Segment 12 | %define FileBuffer 0x1000 13 | 14 | ;Theese define memory locations, where useful data will be saved 15 | ;Also, this data is overwritten over already executed code. (for space saving) 16 | %define BPB_LBA 0x7C00 ; <--Dword - Points to LBA of first sector of loaded partition 17 | %define FAT_LBA 0x7C04 ; <--Dword - Points to LBA of first FAT sector 18 | %define DATA_LBA 0x7C08 ; <--Dword - Points to LBA of first DATA sector 19 | %define CLUSTER BPB+RootCluster ; <--Dword - Points to Temporary number of cluster to be loaded 20 | %define DEV 0x7C14 ; <--Byte - Points to Current storage device index (for bios interrupts) 21 | 22 | 23 | ;Memory address to FAT BPB which is loaded later 24 | %define BPB 0x7E00 25 | ;And some offsets in loaded BPB for calculating FAT values 26 | %define BytesPerSec 0x0B ; <--Word - Points to Bytes Per Sector 27 | %define SecPerCluster 0x0D ; <--Byte - Points to Sectors Per Cluster 28 | %define ResvdSecs 0x0E ; <--Word - Points to Reserved Sectors 29 | %define FatCount 0x10 ; <--Byte - Points to Number of FATs 30 | %define FatSize 0x24 ; <--Dword - Points to Size of one FAT 31 | %define RootCluster 0x2C ; <--Dword - Points to Root Cluster Number 32 | ;Error codes and their meanings 33 | %define ERR_NO_EXT 0x30 ; <-- Extended BIOS interrupts not supported 34 | %define ERR_NO_ACTIVE 0x31 ; <-- No active partition found 35 | %define ERR_NOT_FAT32 0x32 ; <-- Active partition is not FAT32 36 | %define ERR_NOT_FOUND 0x33 ; <-- File is not present in root directory 37 | %define ERR_HARDWARE 0x34 ; <-- Loading sector error(probably hardware error) 38 | 39 | ;Misc defines 40 | %define FAT32 0x0B 41 | %define FAT32LBA 0x0C 42 | %define HIDFAT32 0x1B 43 | %define HIDFAT32LBA 0x1C 44 | ;Setting segment registers, and Stack 45 | cli 46 | xor ax, ax 47 | mov ds, ax 48 | mov ss, ax 49 | mov es, ax 50 | or sp, 0xFFFF 51 | sti 52 | ;Checking if BIOS supports extended interrupts 53 | mov ah, 0x41 54 | mov bx, 0x55AA 55 | int 0x13 56 | mov al, ERR_NO_EXT ;if not - save error code and jump to error routine 57 | jc ErrorRoutine 58 | 59 | ;Find active partition 60 | mov bx, MBR 61 | findActivePart: 62 | add bl, 0x10 63 | cmp bl, 0xFE 64 | mov al, ERR_NO_ACTIVE;if no bootable partition was found - save error code and jump to error routine 65 | je ErrorRoutine 66 | cmp byte [bx], 0x80 67 | jne findActivePart; 68 | 69 | ;Check active partition type 70 | cmp byte[bx+0x04], FAT32 71 | je loadBPB 72 | cmp byte[bx+0x04], FAT32LBA 73 | je loadBPB 74 | cmp byte[bx+0x04], HIDFAT32 75 | je loadBPB 76 | cmp byte[bx+0x04], HIDFAT32LBA 77 | je loadBPB 78 | mov al, ERR_NOT_FAT32 79 | jmp ErrorRoutine 80 | 81 | 82 | loadBPB: 83 | ;When found active partition, load it's first sector to get FAT information 84 | mov ecx, dword [bx+0x08] 85 | mov dword [DAP.address+BootOffset], ecx 86 | mov byte [DEV], dl 87 | call dapLoad 88 | 89 | ;Then calculate and save that information: 90 | 91 | ;LBA of first FAT sector 92 | mov ecx, dword [DAP.address+BootOffset] 93 | mov dword [BPB_LBA], ecx 94 | add cx, word [BPB+ResvdSecs] 95 | mov dword [FAT_LBA], ecx 96 | 97 | ;LBA of first DATA sector 98 | xor eax, eax 99 | mov al, byte [BPB+FatCount] 100 | mul dword [BPB+FatSize] 101 | add ecx, eax 102 | xor eax, eax 103 | mov al, byte [BPB+SecPerCluster] 104 | sub ecx, eax 105 | sub ecx, eax 106 | mov dword[DATA_LBA], ecx 107 | 108 | 109 | 110 | ;search root directory for specified filename 111 | searchCluster: 112 | cmp dword [CLUSTER], 0x0FFFFFF8 113 | mov al, ERR_NOT_FOUND;if file wasn't found(searched whole root directory)-save error code 114 | jae ErrorRoutine ; and jump to error routine 115 | ;Load one cluster of root directory 116 | mov word [DAP.segment+BootOffset], RootBuffer 117 | call lnc 118 | ;Prepare registers for searching cluster 119 | mov dx, word [DAP.segment+BootOffset] 120 | shl dx, 0x04 121 | mov bx, RootBuffer*0x10-0x20 ; <-- Offset to Root Buffer-0x20 122 | ;Prepare registers for each filename comparison 123 | searchPrep: 124 | add bx, 0x0020 125 | cmp dx, bx ; <--- if whole cluster was checked - load another one 126 | je searchCluster 127 | ;Check if entry has attribute VOLUME_ID or DIRECTORY 128 | test byte[es:bx+0x0b], 0x18 129 | jnz searchPrep 130 | mov di, bx 131 | mov cx, 0x000B 132 | mov si, BootOffset+filename 133 | ;Compare single characters of filenames from root directory with our filename 134 | repe cmpsb 135 | jne searchPrep ;<--- if filenames don't match, try another filename 136 | 137 | ;if filename matches get this file's cluster number 138 | match: 139 | mov ax, word[es:bx+0x14] 140 | mov dx, word[es:bx+0x1A] 141 | mov word [CLUSTER], dx 142 | mov word [CLUSTER+2], ax 143 | mov word [DAP.segment+BootOffset], FileBuffer 144 | ;and load it 145 | loadfile: 146 | call lnc 147 | cmp dword [CLUSTER], 0x0FFFFFF8 148 | jb loadfile 149 | 150 | ;This is where function jumps when whole file is loaded 151 | fileLoaded: 152 | ;Set registers 153 | push FileBuffer 154 | pop ds 155 | ;And Jump to loaded Code 156 | mov dl, byte[DEV] 157 | jmp FileBuffer:0x0000 ; THE END 158 | 159 | 160 | ;Routines: 161 | 162 | 163 | ;lnc - Load Next Cluster 164 | ;loads cluster into memory, and saves next cluster's number 165 | lnc: 166 | ;this part saves next cluster's number 167 | push dword [CLUSTER] 168 | push word [DAP.segment+BootOffset] 169 | xor eax, eax 170 | mov al, 0x04 171 | mul dword[CLUSTER] 172 | xor ebx, ebx 173 | mov bx, word [BPB+BytesPerSec] 174 | div ebx 175 | add eax, dword[FAT_LBA] 176 | mov dword[DAP.address+BootOffset], eax 177 | mov word [DAP.segment+BootOffset], RootBuffer 178 | mov word [DAP.count+BootOffset], 0x0001 179 | xchg bx, dx 180 | call dapLoad 181 | mov eax, dword [bx+(RootBuffer*0x10)] 182 | and eax, 0x0FFFFFFF 183 | mov dword [CLUSTER], eax 184 | 185 | ;This part loads current cluster into memory 186 | pop word [DAP.segment+BootOffset] 187 | xor eax, eax 188 | mov al, byte[BPB+SecPerCluster] 189 | mov byte[DAP.count+BootOffset], al 190 | pop dword ebx 191 | mul ebx 192 | add eax, dword[DATA_LBA] 193 | mov dword[DAP.address+BootOffset], eax 194 | call dapLoad 195 | ;Also sets buffer for next cluster right after loaded one 196 | xor eax, eax 197 | mov al, byte[BPB+SecPerCluster] 198 | mul word [BPB+BytesPerSec] 199 | shr ax, 0x04 200 | add word [DAP.segment+BootOffset], ax 201 | ret 202 | 203 | ;Simple routine loading sectors according to DAP 204 | ;It also tries to call BIOS interrupt 5 times, if error occurs 205 | dapLoad: 206 | mov cx, 0x0005 207 | .repeat: 208 | mov ah, 0x42 209 | mov si, DAP+BootOffset 210 | mov dl, byte [DEV] 211 | int 0x13 212 | jnc .end 213 | loop .repeat 214 | mov al, ERR_HARDWARE 215 | jmp ErrorRoutine 216 | .end: 217 | ret 218 | 219 | 220 | ;Simple Error routine(only prints one character - error code) 221 | ErrorRoutine: 222 | mov ah, 0x0E 223 | int 0x10 224 | cli 225 | jmp $ 226 | 227 | 228 | filename: db _FILENAME; Filename in 8.3 format 229 | 230 | 231 | DAP: 232 | .size: db 0x10 233 | .null: db 0x00 234 | .count: dw 0x0001 235 | .offset: dw 0x0000 236 | .segment: dw BPB/0x10 237 | .address: dq 0x0000000000000000 238 | --------------------------------------------------------------------------------