1

I'm trying to learn x86 assembly. I'm trying to make a toy OS. I tried printing out a character that was inputted but it failed. Is there something wrong in the input? Or in the output? I have set AH to 0x0E and used int 0x10 but it still doesn't work. Why doesn't it work?

Note: I'm very new to assembly, so if I got something wrong in the text or in the code, please don't say how dumb I am.

char:
    db 0
mov ah, 0
int 0x16

mov ah, 0x0e
mov al, [char]
int 0x10

jmp $

times 510-($-$$) db 0
dw 0xaa55
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
Lutpoint
  • 3
  • 1
  • 4
    The machine starts executing your program from the beginning. What do you think happens when it executes `db 0`? Do not put data into the path of execution. Also, writing boot loaders is not a good way to start with assembly programming. There are too many things to get wrong and too many weird restrictions. Consider writing COM-type DOS programs instead if you are hellbent on learning 16 bit x86 assembly. – fuz Aug 05 '21 at 14:36
  • You may find http://www.independent-software.com/operating-system-development.html useful for your bootsector development. – Alexander van Oostenrijk Aug 14 '21 at 15:39

2 Answers2

4
char:
    db 0
mov ah, 0

In assembly, you need to store the data out of the way of the executing code. In this bootloader, execution started at the top where you placed a data item. The CPU will try to interpret it as an instruction but it will fail (most of the time).

I tried printing out a character that was inputted

Once you receive the character as input, you still need to actually store it in the memory labeled char. If you don't, then the instruction mov al, [char] won't have anything useful to fetch!

Please note that in a bootloader, you are responsible to setup the segment registers. Your code depends on a correct DS segment register. Because you didn't use an ORG directive, the correct value for DS will be 0x07C0.

And the BIOS.Teletype function 0x0E has additional parameters in BH and BL. Don't ignore these.

mov ax, 0x07C0
mov ds, ax

mov ah, 0       ; BIOS.GetKeyboardKey
int 0x16        ; -> AL charactercode, AH scancode
mov [char], al

mov bx, 0x0007  ; BH is DisplayPage (0), BL is GraphicsColor (White)
mov ah, 0x0E    ; BIOS.Teletype
mov al, [char]
int 0x10

jmp $

char:   db 0

times 510-($-$$) db 0
dw 0xAA55
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
0

its awesome that you are getting started with assembly, and it can be quite overwhelming, but anyway, I have prepared a super simple "Hello, World!" Boot loader that should help make more sense to you :p

boot.asm:

org    0x7C00                 ; BIOS loads our program at this address
bits   16                     ; We're working at 16-bit mode here

_start:
  cli                         ; Disable all interrupts
  mov  si, msg                ; SI now points to our message
  mov  ah, 0x0E               ; Indicate to the BIOS we're going to print chars
.loop lodsb                   ; Loads SI into AL and increments SI [next char]
  or   al, al                 ; Checks if the end of the string
  jz   halt                   ; jump to halt if the end
  int  0x10                   ; Otherwise, call interrupt for printing characters
  jmp  .loop                  ; Next iteration of the loop

halt:  hlt                    ; CPU command to halt the execution
msg:   db "Hello, World!", 0  ; Our message that we want to print

;; Magic numbers
times 510-($-$$) db 0         ; Aligning 512 bytes to take up initial boot sector
dw 0xAA55                     ; Magic multiboot number

I hope this helps you understand a bit more about assembly, and I hope it makes you want to learn more. :p

  • [`test al,al` is a better choice than `or al,al`](https://stackoverflow.com/a/33724806/224132) - don't promote that obsolete inefficient idiom. Also, you can put `hlt` in a loop instead of disabling interrupts so ctrl+alt+del would still work on real hardware. (Because the keyboard interrupt handler can still run.) – Peter Cordes Aug 14 '21 at 01:30
  • I was just trying to make a nice, simple and helpful example, that could help him get on his feet. This is exactly why I don't like stack overflow, because there is always going to be people that aren't necessarily to help, but just to dispute arguments. @PeterCordes – Owen Boreham Aug 14 '21 at 02:42
  • I'm trying to help *you* improve your example. You can [edit] your answer, and comments are for suggesting improvements. Sorry about the phrasing of my first sentence, though; the tone was harsher than it needed to be. Stamping out the use of `or al,al` is a bit of a personal mission of mine I guess, and I don't have anything against people who unfortunately picked it up from other example apparently dating back to 8080 like I explained in my answer that I linked. – Peter Cordes Aug 14 '21 at 03:38
  • It's a pretty good answer overall, just a couple minor tweaks would make it worthy of an upvote, IMO. (Although there are several examples like this on other SO Q&As.) – Peter Cordes Aug 14 '21 at 03:42
  • Also, "multiboot" is a separate thing. 0xAA55 is the BIOS MBR magic number, not multiboot. [Multiboot](https://en.wikipedia.org/wiki/Multiboot_specification) is a standard format for kernel images that can be recognized and loaded *by* a bootloader such as GRUB, not for the BIOS to recognize a bootloader. – Peter Cordes Aug 14 '21 at 03:43
  • 1
    Also, you never set `ds` = 0 to match your ORG setting; some BIOSes don't start the bootloader with DS base = 0, so it's a good idea to always set it manually before using absolute addresses. Your example will work fine on some machines, I assume including qemu or BOCHS, but could fail on some real-world machines so it's maybe not useful to "simplify" by leaving out things like that. See Michael Petch's [general tips for bootloader development](https://stackoverflow.com/a/32705076/224132). – Peter Cordes Aug 14 '21 at 03:45