Do-it-yourself MBR for a flash drive or how to make three from one device

    My respect to the reader!
    The topic could have turned out to be simply disastrously huge, so let's get right to the point. Ahead of you is a story about how you can make one USB flash drive simultaneously bootable for both the Windows OS family and * nix, and also make it live-usb. I apologize in advance for the jargon, not a supporter, but so shorter.

    annotation


    Somehow I had to install a bunch of different operating systems on the same machine many times in a row, both from fellow gentlemen from Microsoft and our favorite * nixes. At the same time, the installers of the newly installed OSs periodically rubbed the boot loaders of the previously installed ones, so they had to be manually restored by booting from live-usb. But the worst thing is that with all this, there was only one flash drive at hand (and another 15 computers were true, but there was little sense from them, since it was impossible to disassemble them for warranty reasons in the hope of an extra hard drive). The flash drive, fortunately, was a large volume. It was then that the idea arose of making two, and preferably three (although 4 possible) different devices from one flash drive.

    Bit of theory


    How to make several from one flash drive for the purpose of subsequent installation on it simultaneously of several OS installers and another live OS? The answer is obvious - make several partitions on a flash drive!

    Rummaging through the Internet the depths of the subconscious, I remembered from the institute's course that the partition information is stored in the first sector of the flash drive’s drive, called the Master Boot Table ( MBR ), or rather, in a separate part of it called the partitions. This part is located at offset 0x01BE and consists of 4 fields of 16 bytes each, each of which is an entry about a separate section. At the same time, in principle, it is possible to have a larger number of partitions on one device, but this is more complicated and four flash drives are enough for us.

    Tools

    In a flush OS, there is an unpleasant limitation on the number of flash drive partitions. It must not exceed 1 . More precisely, partitions can be any number, but the OS will see only the first of the entries in partitions. Actually, this determined the choice of means for formatting a flash drive. We will work with Linux fdisk!

    The loader itself will be written in FASM , as it is most convenient for programming code that runs outside the OS in my opinion.

    You can work with a flash drive as a block device using the terrible destroy data ( dd ), but since such a mishmash of OSes comes out here, we will use a more friendly window DMDE .

    Short lyrical digression
    In fact, the peculiarity of the work of the Windows OS family with flash drives allows using the technology I offer is absolutely painless with respect to the further use of the flash drive as an ordinary data storage device. Having cut off a couple at the end of 16 GB that I had available, I became the owner of a 14-gig flash drive that worked from the Windows point of view as before (that is, the other sections were not visible), but at the same time when trying to boot from it from BIOS allows you to install the OS from two gigabyte partitions created at the end.

    Tooth Flash Crusher

    Let's start with the simplest, mark up the file system on our flash drive. In particular, I used a Transcend JetFlash 16 GB flash drive (it was received as a gift, but as I know, a gift horse ... Although I have no complaints about it for 1.5 years). As I already said, we will use Linux fdisk (the old Ubuntu 9 virtual machine was at hand).

    So, we mount the USB flash drive (since we are sitting under X, we just stick it into the port). We get the device / dev / sdb.

    We start fdisk, setting it on a new device:
    root @ kubuntu: / # fdisk / dev / sdb

    We have the exhaust:
    The number of cylinders for this disk is set to 1953.
    There is nothing wrong with that, but this is larger than 1024,
    and could in certain setups cause problems with:
    1) software that runs at boot time (eg, old versions of LILO)
    2) booting and partitioning software from other OSs
       (eg, DOS FDISK, OS / 2 FDISK)
    Command (m for help): m
    Command action
       a toggle a bootable flag
       b edit bsd disklabel
       c toggle the dos compatibility flag
       d delete a partition
       l list known partition types
       m print this menu
       n add a new partition
       o create a new empty DOS partition table
       p print the partition table
       q quit without saving changes
       s create a new empty Sun disklabel
       t change a partition's system id
       u change display / entry units
       v verify the partition table
       w write table to disk and exit
       x extra functionality (experts only)

    We believe that the disk is clean and does not contain any partitions. Otherwise, using the d command, we correct this drawback (without forgetting to copy the necessary data in advance).

    The task is simple - create three sections. We will create sections (primary) so that all information about them is stored in partitions MBR. We use the n command.
    The first section is the largest (14 GB), as Windows will later see it, and we will use it as a regular flash drive:
    Command (m for help): n
    Command action
       e extended
       p primary partition (1-4)
    p
    Partition number (1-4): 1
    First cylinder (1-15320, default 1): 1
    Last cylinder or + size or + sizeM or + sizeK (1-15320, default 15320): + 14336M

    Second and third in gigabytes:
    Command (m for help): n
    Command action
       e extended
       p primary partition (1-4)
    p
    Partition number (1-4): 2
    First cylinder (13674-15320, default 13674):
    Using default value 13674
    Last cylinder or + size or + sizeM or + sizeK (13674-15320, default 15320): + 1024M
    Command (m for help): n
    Command action
       e extended
       p primary partition (1-4)
    p
    Partition number (1-4): 3
    First cylinder (14652-15320, default 14652):
    Using default value 14652
    Last cylinder or + size or + sizeM or + sizeK (14652-15320, default 15320):
    Using default value 15320

    Check the results by printing the generated partition table with the p command:
    Command (m for help): p
    Disk / dev / sdb: 16.0 GB, 16064184320 bytes
    64 heads, 32 sectors / track, 15320 cylinders
    Units = cylinders of 2048 * 512 = 1048576 bytes
    Disk identifier: 0x0dee0000
       Device Boot Start End Blocks Id System
    / dev / sdb1 1 13673 14001136 83 Linux
    / dev / sdb2 13674 14651 1001472 83 Linux
    / dev / sdb3 14652 15320 685056 83 Linux

    As you can see, we have three sections: 14 GB, 1 GB and residuals (slightly less than gigabytes). It remains to save the received changes with the w command:
    Command (m for help): w
    The partition table has been altered!
    Calling ioctl () to re-read partition table.
    Syncing disks.
    root @ kubuntu: / #

    We disconnect the USB flash drive from the virtual machine and immediately



    see the pop-up window of the following type: It can be seen that the USB flash drive has become perceived as a much smaller device. Well, formatting! We get the first section, ready for use. But what to do with the other two? The first, not the fact that the smartest (but the main thing is working!) That came to mind was to deceive the old Windows and swap the entries in the partition table.

    So, we will use the DMDE program, open the USB flash drive as a block device and delve into the bytes of the boot sector.



    We chose the right size device.



    They opened it and the first thing we see is a partition table, divided by fields. Not happy, climb to raw bytes. Press F2 and see the contents of the MBR. Remember that partitions are stored with 446 bytes.



    The record about the first section is highlighted in red. Next, make a knight's move! We save all three records somewhere in a notebook, and in the place of the first record we write the second (crtl + e, write, ctrl + w save). Close DMDE, drag the flash drive and ... bingo! We see the following window:



    Windows this time saw a second section in gigantic size. We rub our hands and format.

    As it’s not difficult to guess, then it’s worth putting the third one in the place of the first, and copying the first one in the place of the second. Format again and return the received record to the third position (do not forget that the record is 16 bytes, and when formatting, the byte of the file system identifier changes). At the last step, we return the first record from the notebook to the place. As a result, if you mount such a USB flash drive to Ubuntu, we get three different partitions, and in the case of Windows - only one - the first.

    In a manner similar to the method of formatting partitions, various operating systems are easily installed on a USB flash drive. I installed the following on my own:
    • Section 1 (14 GB) - Windows 7 installer (+ is also used as a regular flash drive)
    • Section 2 (1 GB) - live-usb Windows (bartPE)
    • Section 3 - live-usb Linux (backtrack)
    And where is the code?

    What's next? We have a beautiful flash drive with three OSes and ... a huge minus! In order for the computer to start loading from the USB flash drive after loading the BIOS, one of its sections must be active (the value of the first byte in the partitions entry is 0x01). Easy, you say, take advantage of the same favorite DMDE. Perhaps, but here we are faced with another problem - what if we often change our minds about which section of the flash drive to boot from? Do not edit the partition table manually from DMDE each time. Of course not, we are automating this process!

    Some more theory

    What does an MBR consist of? MBR is a bootloader + partition table entry. After the BIOS firmware checks the computer ( POST ), it copies the first sector of the disk from which it is supposed to load the operating system into memory at 0x7C00 (the processor works in real address mode) and transfers control there. Next, the MBR bootloader code (everything up to the 446th byte) checks the readiness of the disk, checks the entries in the partition table (there should be only one active!) And selects the active partition with subsequent transfer of control to the bootloader.

    What will we do

    To get rid of the limit on the number of simultaneous active partitions on the disk, we will replace the bootloader code from MBR with our own, which will check the entries, find those marked active and wait for the user to press a key with a number corresponding to the number of the partition from which to boot.

    As I said, we will write the code in FASM (and debugging was done in Bochs ). The following is a listing without special explanation, otherwise the topic will never end. I would just like to note that it so happened that this is my first assembler program, so do not judge strictly. What the code does has been described above.
    ;регистр dl cодержит номер загрузочного диска!
    use16
    ;======== Копируем самого себя по адресу 0000:0600h ===================
        mov ax, 7C0h
        mov ds, ax
        xor si, si
        mov ax, 60h
        mov es, ax
        xor di, di
        mov cx, 0FFh ;в cx лежит число повторений функции копирования слов
        ;[DS:SI] => [ES:DI]; SI += 2; DI += 2;
        rep movsw
        ;Передаем управление на новое расположение кода
        jmp 0000:0618h
    ;======== Приветствуем пользователя ===================================
    	  mov ax, hello_msg_1
    	  call print
    	  mov ax, hello_msg_2
    	  call print
    ;======== Проверяем таблицу разделов ===================================
    	  mov si, [part_adr]
    	  mov bh, 80h
    	  mov cl, -1
    partitions_chek:
    	  cmp cl, 3			   ;если уже было проверено 4 записи, выходим из цикла и переходим к обработке записей
    	  je partition_select
    	  add si, 10h
    	  inc cl
    	  mov bl, [es:si]
    	  cmp bl, bh
    	  jne partitions_chek		   ;запись не является загрузочной
    	  call partitions_process	   ;запись загрузочная!
    					   ;[es:si] содержит адрес записи в таблице разделов
    					   ;cl - номер раздела
    	  jmp partitions_chek
    ;======== Подпрограмма вывода инофрмации об активном разделе =============================
    partitions_process:
    	  mov ax, boot_part_msg
    	  call print
    	  mov di, part_num
    	  add [ds:di], cl
    	  mov ax, part_num
    	  call print
    	  sub [ds:di], cl
    	  mov di, boot_flags
    	  mov ch, 0
    	  add di, cx
    	  mov byte[ds:di], 1
    	  ret;
    ;=======================================================================
    partition_select:
    	  ;Обрабатываем пользовательский ввод
    	  mov ax, select_part_msg
    	  call print
    choise:   mov di, boot_flags
    	  mov si, [part_adr]
    	  mov ah, 0
    	  int 16h
    p0:	  cmp al, 48
    	  jne p1
    	  add si, 10h
    	  jmp disk
    p1:	  cmp al, 49
    	  jne p2
    	  add si, 20h
    	  jmp disk
    p2:	  cmp al, 50
    	  jne p3
    	  add si, 30h
    	  jmp disk
    p3:	  add si, 40h
    	  cmp al, 51
    	  je disk
    wrong_choise:
    	  mov ax, wrong_input_msg
    	  call print
    	  jmp choise
    disk:	  mov ah, 0
    	  sub al, 48		      ; сначала проверка, выбрал ли пользователь действительно загрузочный раздел
    	  add di, ax
    	  cmp byte [ds:di], 0
    	  je wrong_choise
    				      ; по [es:si] содержится запись таблицы разделов
    				      ; о выбранном загрузочном диске
    	  mov ah, 41h		      ; проверка поддержки диском расширенного режима (> 8 GB)
    				      ; dl содержит номер диска
    	  mov bx, 55AAh
    	  int 13h
    	  jc  ext_not_present_error
    	  shr  cx, 1
    	  jnb  ext_not_present_error
    	  cmp  bx, 0AA55h
    	  je   read_boot_sect
    ext_not_present_error:
    	  mov ax, ext_not_pres_msg
    	  call print
    	  int 18h
    read_boot_sect:
    	  mov ah, 42h
    	  mov di, DAP_structure
    	  add di, 8
    	  add si, 8
    	  mov ebx, [ds:si]
    	  mov [ds:di], ebx
    	  mov si, DAP_structure
    	  int 13h
    	  jc  ext_not_present_error
    	  jmp 0000:7C00h
    ;======== Подпрограмма вывода сообщений ================================
    print:
    	  push si
    	  push bx
    	  mov bx, ax
    	  xor si, si
    	  mov ah, 0Eh
    p:	  mov al, [bx + si]
    	  cmp al, 0Ah
    	  int 10h
    	  je end_print
    	  inc si
    	  jmp p
    end_print:
    	  pop bx
    	  pop si
    	  ret
    ;=======================================================================
    hello_msg_1	 db '************************', 0Dh, 0Ah
    hello_msg_2	 db '*WELL`s LOADER (c) 2011*', 0Dh, 0Ah
    boot_part_msg	 db 'Find bootable partitions:', 0Dh, 0Ah
    select_part_msg  db 'Select part to boot from (press 0 ... 3)', 0Dh, 0Ah
    wrong_input_msg  db 'Wrong choise. Try again', 0Dh, 0Ah
    ext_not_pres_msg db 'a disk read error occured', 0Dh, 0Ah
    part_num	 db '0', 0Dh, 0Ah
    part_adr	 dw 1AEh
    boot_flags	 db 4 dup (0)
    DAP_structure	 db 10h, 0, 1, 0, 0, 7Ch, 0, 0, 8 dup (0)

    As you can see, the bootloader program is a clean binary without any entry points, sections, or other complexity. The processor operating mode is real (16-bit).
    To use this bootloader, you need to upload it to the USB flash drive in the first sector (using DMDE, for example), while maintaining the partition table intact. The compiled binary file size is 442 bytes.

    Prospects


    If such a solution becomes popular, then the functionality of the bootloader can be easily expanded, for example, by adding information about sections to the screen during the selection process. For the convenience of uploading a bootloader to a USB flash drive and choosing which of the sections will be active, you can write a small tool. In general, your wishes and suggestions are accepted in the comments.

    You can download the source code and the bootloader binary from here .

    Also popular now: