The builder for SHUTTLE2

make_shuttle2 is designed to be used at the command line with redirection of input and output from and to DEBUG.EXE like in the following way:

C:\TEMP> debug < make_shuttle2.npp > make_shuttle2_dbg.npp

So make_shuttle2 is a complex script that instructs DEBUG.EXE to build SHUTTLE2.BIN. I prepared the file "make_shuttle2.npp" for you in the DOWNLOAD AREA, but here I want to present how I organized the script and how it works. A first overview of make_shuttle2 follows here.

make_shuttle2_dbg.npp
-f 100 1000 3f - -n boot_sec.bin -l 200 - -n SHUTTEMP.BIN -l 400 - - -a 600 137B:0600 ;234567890123456789012345678901234567890123456789012345678901234567890123456789 137B:0600 ;-------10--------20--------30--------40--------50--------60--------70-------79 137B:0600 ;############################################################################## 137B:0600 ; make_shuttle2: 137B:0600 ; 137B:0600 ; Copyright (C) 2020 - Michele Musci 137B:0600 ; Distributed under the GNU Affero General Public License version 3. 137B:0600 ; See https://www.gnu.org/licenses/agpl-3.0.txt 137B:0600 ; 137B:0600 ; This is the code that manipulates SHUTTEMP (template of SHUTTLE2) to produce 137B:0600 ; the customized version of SHUTTLE2 that is going to boot on the target PC. 137B:0600 ; 137B:0600 ; 1. Load the 512 bytes image of the boot sector (boot_sec.bin) starting 137B:0600 ; at address 0x200. 137B:0600 ; 2. Load the 512 bytes SHUTTEMP.BIN starting at address 0x400. 137B:0600 ; 137B:0600 ; Build it with command: 137B:0600 ; debug < make_shuttle2.npp > make_shuttle2_dbg.npp 137B:0600 ;############################################################################## [...]

At the beginning of the script, you see that I prepared my working RAM area with the command f 100 1000 3f, then I loaded at 0x200 the original image of the first block from disk (boot_sec.bin file)1 and finally I loaded at 0x400 the SHUTTEMP.BIN template. At address 0x600, I wrote an assembly code that reads the BIOS Parameter Block from address 0x200 and manipulates the SHUTTEMP at address 0x400 with all the necessary data and code injections as described in the previous paragraph. I omit for the moment the very assembly code of make_shuttle2 because I want to explain the script first. You have to understand that the code written starting as address 0x600 is inactive in RAM until the very same script activates it.

make_shuttle2_dbg.npp
[...] -a 100 137B:0100 call 060c 137B:0103 jmp 100 137B:0105 -rip IP 0100 :100 - -p AX=C700 BX=0000 CX=0004 DX=0000 SP=FFEE BP=0020 SI=08B5 DI=0129 DS=137B ES=137B SS=137B CS=137B IP=0103 NV UP EI PL ZR NA PE NC 137B:0103 EBFB JMP 0100 - -d 100 137B:0100 E8 09 05 EB FB 3F 3F 3F-3F 3F 3F 3F 3F 3F 3F 3F .....??????????? 137B:0110 53 48 55 54 54 4C 45 32-20 20 20 20 20 20 20 20 SHUTTLE2 137B:0120 49 53 20 52 45 41 44 59-21 3F 3F 3F 3F 3F 3F 3F IS READY!??????? 137B:0130 3F 3F 3F 3F 3F 3F 3F 3F-3F 3F 3F 3F 3F 3F 3F 3F ???????????????? 137B:0140 3F 3F 3F 3F 3F 3F 3F 3F-3F 3F 3F 3F 3F 3F 3F 3F ???????????????? 137B:0150 3F 3F 3F 3F 3F 3F 3F 3F-3F 3F 3F 3F 3F 3F 3F 3F ???????????????? 137B:0160 3F 3F 3F 3F 3F 3F 3F 3F-3F 3F 3F 3F 3F 3F 3F 3F ???????????????? 137B:0170 3F 3F 3F 3F 3F 3F 3F 3F-3F 3F 3F 3F 3F 3F 3F 3F ???????????????? - -d 400 5ff 137B:0400 EB 78 90 4D 53 44 4F 53-35 2E 30 00 02 04 08 00 .x.MSDOS5.0..... 137B:0410 02 00 02 00 00 F8 C8 00-3F 00 FF 00 00 58 E7 10 ........?....X.. 137B:0420 00 20 03 00 80 00 29 F0-20 F8 04 4E 4F 20 4E 41 . ....). ..NO NA 137B:0430 4D 45 20 20 20 20 46 41-54 31 36 20 20 20 B4 0E ME FAT16 .. 137B:0440 BB 07 00 CD 10 AC 3C 00-75 F4 C3 04 30 3C 39 76 ......<.u...0<9v 137B:0450 02 04 07 C3 B1 04 D3 E8-D2 E8 E8 EE FF 88 44 01 ..............D. 137B:0460 88 E0 E8 E6 FF 88 44 00-E8 DA FF BE DB 7B E8 D4 ......D......{.. 137B:0470 FF 31 C0 CD 16 EA 00 00-FF FF FA 31 DB 8E DB 8E .1.........1.... 137B:0480 C3 8E D3 BC 00 78 FC BE-00 7C BF 00 7A B9 FF 00 .....x...|..z... 137B:0490 F3 A5 89 1E FE 7B FB EA-9C 7A 00 00 F8 BE F0 7B .....{...z.....{ 137B:04A0 B2 80 B4 42 CD 13 BE B6-7B 72 A9 8B 16 11 7A BB ...B....{r....z. 137B:04B0 00 05 B9 0C 00 89 DF BE-95 7B F3 A6 E3 0B 83 C3 .........{...... 137B:04C0 20 4A 75 EE BE 95 7B EB-9F 8B 45 0E 8B 2E EA 7B Ju...{...E....{ 137B:04D0 8B 3E E8 7B 50 2D 02 00-B9 04 00 F7 E1 01 F8 11 .>.{P-.......... 137B:04E0 EA 89 16 EA 7B A3 E8 7B-F8 BE E0 7B B2 80 B4 42 ....{..{...{...B 137B:04F0 CD 13 73 06 BE C2 7B E9-5A FF B8 80 00 01 06 E6 ..s...{.Z....... 137B:0500 7B 58 BB 02 00 B9 00 70-F7 E3 F7 F1 50 52 3A 06 {X.....p....PR:. 137B:0510 DD 7B 74 3A 8A 26 F2 7B-F6 E4 89 C3 B9 02 00 E3 .{t:.&.{........ 137B:0520 27 49 A1 16 7A F7 E1 01-D8 83 D2 00 05 08 58 81 'I..z.........X. 137B:0530 D2 E7 10 A3 F8 7B 89 16-FA 7B F8 BE F0 7B B2 80 .....{...{...{.. 137B:0540 B4 42 CD 13 73 08 EB D7-BE CE 7B E9 06 FF 5B 58 .B..s.....{...[X 137B:0550 A2 DD 7B 8B 87 00 05 3D-FF FF 74 19 3D 02 00 72 ..{....=..t.=..r 137B:0560 21 3D 94 C7 77 1C FF 0E-DE 7B 74 03 E9 65 FF BE !=..w....{t..e.. 137B:0570 AB 7B E9 F3 FE B9 09 00-BF 00 7C BE 50 7B F3 A7 .{........|.P{.. 137B:0580 E3 09 BE 91 7B 8C 5C 0F-E9 DD FE E9 82 00 3F 3F ....{.\.......?? 137B:0590 3F 42 61 64 20 53 4F 46-54 57 41 52 45 42 49 47 ?Bad SOFTWAREBIG 137B:05A0 20 6E 6F 74 20 66 6F 75-6E 64 00 46 69 6C 65 20 not found.File 137B:05B0 74 6F 6F 20 62 69 67 00-68 3A 20 42 61 64 20 52 too big.h: Bad R 137B:05C0 4F 4F 54 00 68 3A 20 42-61 64 20 44 41 54 41 00 OOT.h: Bad DATA. 137B:05D0 68 3A 20 42 61 64 20 46-41 54 00 2E 00 FF 30 01 h: Bad FAT....0. 137B:05E0 10 00 04 00 00 00 C0 07-B8 59 E7 10 00 00 00 00 .........Y...... 137B:05F0 10 00 38 00 00 05 00 00-98 59 E7 10 00 00 55 AA ..8......Y....U. - - - -rbx BX 0000 :0 -rcx CX 0004 :0200 -r AX=C700 BX=0000 CX=0200 DX=0000 SP=FFEE BP=0020 SI=08B5 DI=0129 DS=137B ES=137B SS=137B CS=137B IP=0103 NV UP EI PL ZR NA PE NC 137B:0103 EBFB JMP 0100 - -n SHUTTLE2.BIN -w 400 Writing 00200 bytes -q

After the omitted code of make_shuttle2, I continued with the script and I coded at 0x100 the CALL instruction at 0x06C0 (entry point of MAIN) which I used, together with the command p, to activate the code which builds SHUTTLE2 in RAM. Remember that the command p executes all instructions incurred from a CALL to the next RET instruction. For this reason, I had to code somewhere outside the MAIN procedure a CALL instruction to the entry point of the MAIN and the same must terminate with a RET instruction. Finally, I pointed the instruction pointer (IP) to the CALL instruction that activates the MAIN and I used the p command to make the script run the code automatically.

make_shuttle2 writes one message in RAM starting at address 0x110 in such a way that I could have them in the "make_shuttle2_dbg.npp" protocol file created with redirection of outputs2. Finally, I put, with the dump instruction d 400 5ff, the SHUTTLE2 as it appears in RAM and I wrote it to disk into the file SHUTTLE2.BIN.

Now it is time to have a closer look at the assembly software3 omitted before, however, I don't show all of it here in the post, since you can download the complete file from the DOWNLOAD AREA.

>make_shuttle2_dbg.npp
[...] -a 600 137B:0600 ;234567890123456789012345678901234567890123456789012345678901234567890123456789 137B:0600 ;-------10--------20--------30--------40--------50--------60--------70-------79 137B:0600 ;############################################################################## 137B:0600 ; make_shuttle2: 137B:0600 ; 137B:0600 ; Copyright (C) 2020 - Michele Musci 137B:0600 ; Distributed under the GNU Affero General Public License version 3. 137B:0600 ; See https://www.gnu.org/licenses/agpl-3.0.txt 137B:0600 ; 137B:0600 ; This is the code that manipulates SHUTTEMP (template of SHUTTLE2) to produce 137B:0600 ; the customized version of SHUTTLE2 that is going to boot on the target PC. 137B:0600 ; 137B:0600 ; 1. Load the 512 bytes image of the boot sector (boot_sec.bin) starting 137B:0600 ; at address 0x200. 137B:0600 ; 2. Load the 512 bytes SHUTTEMP.BIN starting at address 0x400. 137B:0600 ; 137B:0600 ; Build it with command: 137B:0600 ; debug < make_shuttle2.npp > make_shuttle2_dbg.npp 137B:0600 ;############################################################################## 137B:0600 ; 137B:0600 ;############################################################################## 137B:0600 ; 137B:0600 ; SET_END_MSG: END OF PROCEDURE 137B:0600 ; 137B:0600 ;############################################################################## 137B:0600 ; 137B:0600 ; set_end_msg: <--- 137B:0600 ; 137B:0600 mov di, 110 ; DI -> RAM area where to put the end message. 137B:0603 jmp 0606 ; JUMP msg_entry: ---> 137B:0605 ; 137B:0605 ; 137B:0605 ; one_char_on_RAM: <--- 137B:0605 ; 137B:0605 stosb ; ES:[DI] = AL 137B:0606 ; DI = DI + 1 137B:0606 ; 137B:0606 ; 137B:0606 ; msg_entry: <--- 137B:0606 ; 137B:0606 lodsb ; AL = DS:[SI] 137B:0607 ; SI = SI + 1 137B:0607 cmp al, 00 ; flags = AL - 0x 00 137B:0609 ; Unsigned comparison: 137B:0609 jne 0605 ; JumpNotEqual one_char_on_RAM: ---> 137B:060B ; 137B:060B ;------------------------------------------------------------------------------ 137B:060B ; END OF PROCEDURE 137B:060B ;------------------------------------------------------------------------------ 137B:060B ret [...]

I began the software with the termination procedure. I similarly used this termination procedure as I used show_string, but this procedure writes bytes in memory rather than on screen. Another important difference is that I activated this procedure with a JUMP and not with a CALL: this procedure is the common exit point of make_shuttle2 that jumps here as soon as a problem is found or at the very end when SHUTTLE2 is ready. In any case, I placed in register SI the address of the first Byte of string that I wanted to copy to 0x110.

make_shuttle2 continues with a lot of plausibility checks across the BIOS Parameter Block based on the information available in the Microsoft's specification.

make_shuttle2_dbg.npp
[...] 137B:060C ;############################################################################## 137B:060C ; 137B:060C ; START MAIN procedure 137B:060C ; 137B:060C ;############################################################################## 137B:060C ; 137B:060C ; start: <--- 137B:060C ; 137B:060C ;############################################################################## 137B:060C ; 137B:060C ; CHECKS 137B:060C ; 137B:060C ;############################################################################## 137B:060C ;------------------------------------------------------------------------------ 137B:060C ; BPB_BytsPerSec -> [BPB + 0x0b] (2 Bytes) 137B:060C ; Number of Bytes per block. Legal values are: 137B:060C ; 0x0200 -> 512 bytes, 137B:060C ; 0x0400 -> 1024 bytes, 137B:060C ; 0x0800 -> 2048 bytes, 137B:060C ; 0x1000 -> 4096 bytes. 137B:060C ;------------------------------------------------------------------------------ 137B:060C mov ax, [200 + 0b] ; AX = BPB_BytsPerSec 137B:060F cmp ax, 0200 ; flags = AX - 0x 0200 137B:0612 ; Unsigned comparison: 137B:0612 je 063f ; JumpEqual isOK_A: ---> 137B:0614 ; 137B:0614 cmp ax, 0400 ; flags = AX - 0x 0400 137B:0617 ; Unsigned comparison: 137B:0617 je 063f ; JumpEqual isOK_A: ---> 137B:0619 ; 137B:0619 cmp ax, 0800 ; flags = AX - 0x 0800 137B:061C ; Unsigned comparison: 137B:061C je 063f ; JumpEqual isOK_A: ---> 137B:061E ; 137B:061E ; 137B:061E cmp ax, 1000 ; flags = AX - 0x 1000 137B:0621 ; Unsigned comparison: 137B:0621 je 063f ; JumpEqual isOK_A: ---> 137B:0623 ; 137B:0623 ; 137B:0623 ;----------------------------- 137B:0623 ; Error... 137B:0623 ;----------------------------- 137B:0623 mov si, 0628 ; SI -> "BPB_BytsPerSec is bad!" 137B:0626 jmp 0600 ; JUMP set_end_msg: ---> 137B:0628 ; 137B:0628 DB 'BPB_BytsPerSec is bad!' 00 137B:063F ; 137B:063F ; 137B:063F ; 137B:063F ; isOK_A: <--- 137B:063F ; 137B:063F ;------------------------------------------------------------------------------ 137B:063F ; BPB_SecPerClus -> [BPB + 0x0d] (1 Bytes) 137B:063F ; Number of blocks per cluster of file. Legal values are: 137B:063F ; 0x01 (1), 0x02 (2), 0x04 (4), 0x08 (8), 137B:063F ; 0x10 (16), 0x20 (32), 0x40 (64), 0x80 (128). 137B:063F ; IMPORTANT!!! 137B:063F ; BPB_SecPerClus * BPB_BytsPerSec <= 0x8000 (32Kbyte). 137B:063F ;------------------------------------------------------------------------------ 137B:063F xor bx, bx ; BH = 0x00 137B:0641 mov bl, [200 + 0d] ; BX = BPB_SecPerClus. 137B:0645 ; Remember that AX = BPB_BytsPerSec and we will 137B:0645 ; perform a MUL with BX that implies 137B:0645 ; the use of AX. 137B:0645 ; 137B:0645 mov dx, 01 ; DX = 0x01. Initial value that gets multiplied 137B:0648 ; at each step 137B:0648 mov cx, 8 ; We have 8 steps. 137B:064B ; 137B:064B ; next_chk: <--- 137B:064B ; 137B:064B cmp bx, dx ; flags = BX - DX 137B:064D ; Unsigned comparison: 137B:064D je 066f ; JumpEqual isOK_B: ---> 137B:064F ; 137B:064F shl dx, 1 ; DX = DX * 2 137B:0651 loop 064B ; dec CX LOOP next_chk: ---> 137B:0653 ; JNZ 137B:0653 ;----------------------------- 137B:0653 ; Error... 137B:0653 ;----------------------------- 137B:0653 mov si, 0658 ; SI -> "BPB_SecPerClus is bad!" 137B:0656 jmp 0600 ; JUMP set_end_msg: ---> 137B:0658 ; 137B:0658 DB 'BPB_SecPerClus is bad!' 00 137B:066F ; 137B:066F ; 137B:066F ; 137B:066F ; isOK_B: <--- 137B:066F ; [...]

As you can see, at every check either the software stops with an error message, or it continues towards the next check. Stopping the software with an error message is done always with the preparation of the string that is pointed by register SI and then the jump goes at the termination part of the procedure.

After almost all the checks, I could move on with the calculation of the parameters and the injection in SHUTTEMP. During the calculation of the parameters I still had to perform some additional few checks, however, the vast majority of them was already done at the beginning.

Now that I look back and I sum together the pages of this diary for the first Space Shuttle and SHUTTLE2, I get myself astonished about the huge amount of know-how and experience one may need just to write 512 bytes of data plus code. I had already a great deal of respect and admiration for the people who wrote and maintains GRUB, but since I tried to do myself these toy bootloader and I got aware of all the things you have to take care of to make it work, my respect and admiration for the people of GRUB has grown.

Final consideration

If you ask anybody if Assembly is a programming or a scripting language, everybody will answer that Assembly is a programming language and so do I. But wait a moment. All the software done until now with DEBUG.EXE is programmed in assembly and runs later on in deep dark space (my metaphor for real mode bare bone x86), all of them except this one. MAKESHUT is indeed a script to use DEBUG.EXE in an automatized way that takes two binary files (the SHUTTEMP.BIN and the boot_sec.bin) to produce a third binary file: the SHUTTLE2.BIN. MAKESHUT doesn’t run in the deep dark space, but quite comfortable inside Windows. I just used redirection of inputs and output to feed DEBUG.EXE with commands in an automatized way. Then Assembly can be used as a scripting language too!…. or not ?.... well let me just say… almost.



  1. I created the image of the boot sector from Ubuntu with the use of the command dd if=/dev/sdax of=/home/mik/Desktop/boot_sec.bin bs=512 count=1 (where "x" is the number of the partition "TEST") as I did already in the post "Story of a deep space exploration". [click back]
  2. I use a specific name convention with the files when I assembly in DEBUG.EXE as described in the post "Change of gear". [click back]
  3. it is not just code but software because it contains code and data. [click back]

<PREV.  -  ALL  -  NEXT>

Comments