title: Custom bootloader booted via USB drive produces incorrect output on some computers
body: <p>I am fairly new to assembly, but I'm trying to dive into the world of low level computing. I'm trying to learn how to write assembly code that would run as bootloader code; so independent of any other OS like Linux or Windows. After reading <a href="http://mikeos.sourceforge.net/write-your-own-os.html#pcprimer" rel="noreferrer">this page</a> and a few other lists of x86 instruction sets, I came up with some assembly code that is supposed to print 10 A's on the screen and then 1 B.</p>
  
  <pre><code>      BITS 16
  start: 
      mov ax, 07C0h       ; Set up 4K stack space after this bootloader
      add ax, 288     ; (4096 + 512) / 16 bytes per paragraph
      mov ss, ax
      mov sp, 4096
  
      mov ax, 07C0h       ; Set data segment to where we're loaded
      mov ds, ax
  
      mov cl, 10          ; Use this register as our loop counter
      mov ah, 0Eh         ; This register holds our BIOS instruction
  
  .repeat:
      mov al, 41h         ; Put ASCII 'A' into this register
      int 10h             ; Execute our BIOS print instruction
      cmp cl, 0           ; Find out if we've reached the end of our loop
      dec cl              ; Decrement our loop counter
      jnz .repeat         ; Jump back to the beginning of our loop
      jmp .done           ; Finish the program when our loop is done
  
  .done:
      mov al, 42h         ; Put ASCII 'B' into this register
      int 10h             ; Execute BIOS print instruction
      ret
  
  
  times 510-($-$$) db 0   ; Pad remainder of boot sector with 0s
  dw 0xAA55
  </code></pre>
  
  <p>So the output should look like this:</p>
  
  <pre><code>AAAAAAAAAAB
  </code></pre>
  
  <p>I assembled the code using the nasm assembler running on the Windows 10 Ubuntu Bash program. After it produced the .bin file, I opened it using a hex editor. I used the same hex editor to copy the contents of that .bin file into the first 512 bytes of a flash drive. Once I had written my program to the flash drive, I disconnected it and plugged it into a computer with an Intel Core i3-7100. On bootup, I selected my USB flash drive as the boot device, only to get the following output:</p>
  
  <pre><code>A
  </code></pre>
  
  <p>After changing various things in the program, I finally got frustrated and tried the program on another computer. The other computer was a laptop with an i5-2520m. I followed the same process as I mentioned before. Sure enough, it gave me the expected output:</p>
  
  <pre><code>AAAAAAAAAAB
  </code></pre>
  
  <p>I immediately tried it on my original computer with the i3, but it still didn't work. </p>
  
  <p>So my question is: Why does my program work with one x86 processor but not the other? They both support the x86 instruction set. What gives?</p>
  
  <hr>
  
  <p><strong>Solution:</strong><br>
  Ok, I've been able to track down the real solution with some help. If you read Michael Petch's answer below, you'll find a solution that will fix my problem, and another problem of a BIOS looking for a BPB.</p>
  
  <p>Here was the problem with my code: I was writing the program to the first bytes of my flash drive. Those bytes were loaded into memory, but some BIOS interrupts were using those bytes for itself. So my program was being overwritten by the BIOS. To prevent this, you can add a BPB description as shown below. If your BIOS works the same way mine does, it will simply overwrite the BPB in memory, but not your program. Alternatively, you can add the following code to the top of your program:</p>
  
  <pre><code>jmp start
  resb 0x50
  
  start: 
  ;enter code here
  </code></pre>
  
  <p>This code (courtesy of Ross Ridge) will push your program to memory location 0x50 (offset from 0x7c00) to prevent it from being overwritten by the BIOS during execution.</p>
  
  <p>Also keep in mind that whenever you call any subroutine, the values of the registers you were using could be overwritten. Make sure you either use <code>push</code>, <code>pop</code> or save your values to memory before calling a subroutine. Look at Martin Rosenau's answer below to read more about that.</p>
  
  <p>Thank you to all who replied to my question. I now have a better understanding of how this low-level stuff works.</p>