4

Edit: So I got things working by not using Bochs from apt but compile from source. Does anyone know how they are different?

I am trying to make a bootloader that simply displays the string "hello, world" on the screen. I created a raw disk image from my assembly code, and simulated the same image with both QEMU and Bochs. QEMU successfully printed the string, while Bochs only shows a black screen (I didn't forget to type 'c' to continue the simulation on Bochs). What am I doing wrong here?

Here's my assembly code (boot.asm):

org 0x7c00  

Start:
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x7c00

    mov ax, 0600h
    mov bx, 0700h
    mov cx, 0
    mov dx, 0184fh
    int 10h

    mov ax, 0200h
    mov bx, 0000h
    mov dx, 0000h
    int 10h

    mov ax, 1301h
    mov bx, 000fh
    mov dx, 0000h
    mov cx, 12
    push    ax
    mov ax, ds
    mov es, ax
    pop ax
    mov bp, Message
    int 10h

    xor ah, ah
    xor dl, dl
    int 13h

    jmp $

Message:    db  "hello, world"
    times   510 - ($ - $$)  db  0
    dw  0xaa55

Here's how I made the disk image:

$ nasm boot.asm
$ dd if=/dev/zero of=boot.img bs=512 count=2880
$ dd if=boot of=boot.img conv=notrunc

I ran QEMU with the command qemu-system-x86_64 -drive format=raw,file=boot.img, and Bochs with the following configuration:

# configuration file generated by Bochs
plugin_ctrl: unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, gameport=true, iodebug=true
config_interface: textconfig
display_library: x
memory: host=32, guest=32
romimage: file="/usr/share/bochs/BIOS-bochs-latest", address=0x00000000, options=none
vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
boot: floppy
floppy_bootsig_check: disabled=0
floppya: type=1_44, 1_44="boot.img", status=inserted, write_protected=0
# no floppyb
ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=none
ata0-slave: type=none
ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata1-master: type=none
ata1-slave: type=none
ata2: enabled=false
ata3: enabled=false
optromimage1: file=none
optromimage2: file=none
optromimage3: file=none
optromimage4: file=none
optramimage1: file=none
optramimage2: file=none
optramimage3: file=none
optramimage4: file=none
pci: enabled=1, chipset=i440fx
vga: extension=vbe, update_freq=5, realtime=1
cpu: count=1:1:1, ips=4000000, quantum=16, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
cpuid: level=6, stepping=3, model=3, family=6, vendor_string="GenuineIntel", brand_string="              Intel(R) Pentium(R) 4 CPU        "
cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true
cpuid: movbe=false, adx=false, aes=false, sha=false, xsave=false, xsaveopt=false, avx_f16c=false
cpuid: avx_fma=false, bmi=0, xop=false, fma4=false, tbm=false, x86_64=true, 1g_pages=false
cpuid: pcid=false, fsgsbase=false, smep=false, smap=false, mwait=true, vmx=1, svm=false
print_timestamps: enabled=0
debugger_log: -
magic_break: enabled=0
port_e9_hack: enabled=0
private_colormap: enabled=0
clock: sync=none, time0=local, rtc_sync=0
# no cmosimage
log: -
logprefix: %t%e%d
debug: action=ignore
info: action=report
error: action=report
panic: action=ask
keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
mouse: type=ps2, enabled=false, toggle=ctrl+mbutton
sound: waveoutdrv=dummy, waveout=none, waveindrv=dummy, wavein=none, midioutdrv=dummy, midiout=none
speaker: enabled=true, mode=sound
parport1: enabled=true, file=none
parport2: enabled=false
com1: enabled=true, mode=null
com2: enabled=false
com3: enabled=false
com4: enabled=false
  • You're assuming that your code will start with CS=0 so you get DS=0 to match your ORG 0x7C00. But that's not guaranteed; you should `xor ax,ax` instead. (And single-step it in Bochs's built-in debugger and see.) Bochs's debugger is one of the main reasons to use it for bare metal development of code that doesn't only use protected mode. – Peter Cordes Nov 22 '21 at 09:46
  • @PeterCordes Sadly this is not working. I checked registers and it looks like Bochs does initialise with CS=0 on my environment. Still, thank you for the advice! – Stultus Verus Nov 22 '21 at 09:59
  • Do you see anything else while single-stepping through? Like differences from when you single-step in qemu (via gdb-remote)? – Peter Cordes Nov 22 '21 at 10:24
  • @PeterCordes In Bochs I did "pb *0x7c00" and "c" but it loops between f000:fff0~e05b and does not pause at all. It turns out that my bootloader is never executed in Bochs. What might be the cause? – Stultus Verus Nov 22 '21 at 11:16
  • 1
    What's your bochs version? Works fine here with 2.6.8. – Jester Nov 22 '21 at 12:33
  • @Jester I'm using 2.6.11 from Ubuntu's repository... Did you use the bochsrc file I provided and it works fine? – Stultus Verus Nov 22 '21 at 12:41
  • With some minor tweaks to make it compatible with my version, yes. – Jester Nov 22 '21 at 12:48
  • Just a suggestion, but I'd put the stack somewhere else besides `0000:7c00`. In the unlikely event of stack underflow, the boot code would get corrupted. There's also the (unlikely) risk of stack overflow corrupting the BDA and the IVT. – sj95126 Nov 22 '21 at 16:50
  • 2
    @sj95126: Stack underflow is a severe logic error. And unless you want to dedicate a full 64 KiB segment to the stack you cannot avoid it. (Even so you would overwrite the earlier stack in the event of an underflow.) – ecm Nov 22 '21 at 19:06

0 Answers0