"bootloader" stub - works fine in QEMU, but not in BOCHS.

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Licho
Posts: 2
Joined: Sun Jun 05, 2016 11:48 am
Libera.chat IRC: licho

"bootloader" stub - works fine in QEMU, but not in BOCHS.

Post by Licho »

I wrote a simple code running as bootloader:

Code: Select all

; Framebuffer
%define FB 0xB8000
%define FB_W 80
%define FB_H 25
%define FB_END FB + (FB_W) * (FB_H) * 2

; Char color code
%define FB_COLOR 0x02

; Position of logo
%define LOGO_X ((FB_W / 2) - 16)
%define LOGO_Y ((FB_H / 2) - 4)
%define LOGO_POS (LOGO_X + (FB_W * LOGO_Y)) * 2

%define debug xchg bx, bx

[BITS 16]
[CPU 386]
org 0x7C00

; Set cursor position to (0,0)
mov dx, 0x3D4
mov al, 14
out dx, al

inc dx ;0x3D5
mov al, 0
out dx, al

dec dx ;0x3D4
mov al, 15
out dx, al

inc dx ;0x3D5
mov al, 0
out dx, al

debug
; Clear whole screen
clear:
    mov edx, FB
    .write:
    	mov [edx], WORD 0x20
        add edx, 2
        cmp edx, FB_END
        jnz .write

debug
; Draw logo
logo:
    ; Prepare registers for loading string
    mov edx, FB + LOGO_POS
    mov ebx, 1
    mov si, data.str

    ; Write next char
    .write:
    	; Read single char from string
        lodsb
        
        ; Jump on special chars
        cmp al, 0xA
        jz .new_line ; Make new line if char == 0xA (\n)
        cmp al, 0x0
        jz .end ; Exit loop on null byte
        
        debug
        ;Write char to framebuffer
        mov ah, FB_COLOR
        mov [edx], WORD ax
        add edx, 2
        jmp .write
    .new_line:
    	debug
    	mov edx, FB_W * 2
    	imul edx, ebx
    	add edx, FB + LOGO_POS
    	inc ebx
        jmp .write
    .end:

; Loop forever
end:
    jmp $

data:
    .str:
        db '    _/_/_/        _/_/',0xA
        db '   _/    _/    _/        _/_/_/',0xA
        db '  _/_/_/    _/_/_/_/  _/    _/',0xA
        db ' _/    _/    _/      _/    _/',0xA
        db '_/_/_/      _/        _/_/_/',0xA
        db '                         _/',0xA
        db '                        _/',0x0
    .fill: ;MBR partition table space
        times 510 - ( $ - $$ ) db 0
    .bootflag: ;Mark as bootable
        dw 0xAA55
Everything works fine under QEMU, but BOCHS enters forever loop on line 43 (mov [edx], WORD 0x20)

Code: Select all

(0) [0x00007c1a] 0000:7c1a (unk. ctxt): mov word ptr ds:[edx], 0x0020 ; 67c7022000
(0) [0x000fe9e6] f000:e9e6 (unk. ctxt): push ax                   ; 50
(0) [0x000fe9e7] f000:e9e7 (unk. ctxt): call .-20413 (0x000f9a2d) ; e843b0
(0) [0x000f9a2d] f000:9a2d (unk. ctxt): mov al, 0x20              ; b020
(0) [0x000f9a2f] f000:9a2f (unk. ctxt): out 0x20, al              ; e620
(0) [0x000f9a31] f000:9a31 (unk. ctxt): ret                       ; c3
(0) [0x000fe9ea] f000:e9ea (unk. ctxt): pop ax                    ; 58
(0) [0x000fe9eb] f000:e9eb (unk. ctxt): iret                      ; cf
(0) [0x00007c1a] 0000:7c1a (unk. ctxt): mov word ptr ds:[edx], 0x0020 ; 67c7022000
My BOCHS config:

Code: Select all

# You may now use double quotes around pathnames, in case
# your pathname includes spaces.

#=======================================================================
# CONFIG_INTERFACE
#
# The configuration interface is a series of menus or dialog boxes that
# allows you to change all the settings that control Bochs's behavior.
# Depending on the platform there are up to 3 choices of configuration
# interface: a text mode version called "textconfig" and two graphical versions
# called "win32config" and "wx".  The text mode version uses stdin/stdout and
# is always compiled in, unless Bochs is compiled for wx only. The choice
# "win32config" is only available on win32 and it is the default there.
# The choice "wx" is only available when you use "--with-wx" on the configure
# command.  If you do not write a config_interface line, Bochs will
# choose a default for you.
#
# NOTE: if you use the "wx" configuration interface, you must also use
# the "wx" display library.
#=======================================================================
config_interface: textconfig
#config_interface: win32config
#config_interface: wx

#=======================================================================
# DISPLAY_LIBRARY
#
# The display library is the code that displays the Bochs VGA screen.  Bochs 
# has a selection of about 10 different display library implementations for 
# different platforms.  If you run configure with multiple --with-* options, 
# the display_library command lets you choose which one you want to run with.
# If you do not write a display_library line, Bochs will choose a default for
# you.
#
# The choices are: 
#   x              use X windows interface, cross platform
#   win32          use native win32 libraries
#   carbon         use Carbon library (for MacOS X)
#   macintosh      use MacOS pre-10
#   amigaos        use native AmigaOS libraries
#   sdl            use SDL 1.2.x library, cross platform
#   sdl2           use SDL 2.x library, cross platform
#   svga           use SVGALIB library for Linux, allows graphics without X11
#   term           text only, uses curses/ncurses library, cross platform
#   rfb            provides an interface to AT&T's VNC viewer, cross platform
#   vncsrv         use LibVNCServer for extended RFB(VNC) support
#   wx             use wxWidgets library, cross platform
#   nogui          no display at all
#
# NOTE: if you use the "wx" configuration interface, you must also use
# the "wx" display library.
#
# Specific options:
# Some display libraries now support specific options to control their
# behaviour. These options are supported by more than one display library:
#
# "gui_debug"   - use GTK debugger gui (sdl, sdl2, x) / Win32 debugger gui (sdl,
#                 sdl2, win32)
# "hideIPS"     - disable IPS output in status bar (rfb, sdl, sdl2, vncsrv,
#                 win32, wx, x)
# "nokeyrepeat" - turn off host keyboard repeat (sdl, sdl2, win32, x)
# "timeout"     - time (in seconds) to wait for client (rfb, vncsrv)
#
# See the examples below for other currently supported options.
#=======================================================================
#display_library: amigaos
#display_library: carbon
#display_library: macintosh
#display_library: nogui
#display_library: rfb
#display_library: sdl, options="fullscreen" # startup in fullscreen mode
display_library: sdl2 #, options="fullscreen" # startup in fullscreen mode
#display_library: term
#display_library: vncsrv
#display_library: win32
#display_library: wx
#display_library: x

#=======================================================================
# CPU:
# This defines cpu-related parameters inside Bochs:
#
#  MODEL:
#    Selects CPU configuration to emulate from pre-defined list of all
#    supported configurations. When this option is used and the value
#    is different from 'bx_generic', the parameters of the CPUID option
#    have no effect anymore.
#
#  CPU configurations that can be selected:
# -----------------------------------------------------------------
#  pentium                    Intel Pentium (P54C)
#  pentium_mmx                Intel Pentium MMX
#  amd_k6_2_chomper           AMD-K6(tm) 3D processor (Chomper)
#  p2_klamath                 Intel Pentium II (Klamath)
#  p3_katmai                  Intel Pentium III (Katmai)
#  p4_willamette              Intel(R) Pentium(R) 4 (Willamette)
#  core_duo_t2400_yonah       Intel(R) Core(TM) Duo CPU T2400 (Yonah)
#  atom_n270                  Intel(R) Atom(TM) CPU N270
#  p4_prescott_celeron_336    Intel(R) Celeron(R) 336 (Prescott)
#  athlon64_clawhammer        AMD Athlon(tm) 64 Processor 2800+ (Clawhammer)
#  athlon64_venice            AMD Athlon(tm) 64 Processor 3000+ (Venice)
#  turion64_tyler             AMD Turion(tm) 64 X2 Mobile TL-60 (Tyler)
#  phenom_8650_toliman        AMD Phenom X3 8650 (Toliman)
#  core2_penryn_t9600         Intel Mobile Core 2 Duo T9600 (Penryn)
#  corei5_lynnfield_750       Intel(R) Core(TM) i5   750 (Lynnfield)
#  corei5_arrandale_m520      Intel(R) Core(TM) i5 M 520 (Arrandale)
#  zambezi                    AMD FX(tm)-4100 Quad-Core Processor (Zambezi)
#  trinity_apu                AMD A8-5600K APU (Trinity)
#  corei7_sandy_bridge_2600k  Intel(R) Core(TM) i7-2600K (Sandy Bridge)
#  corei7_ivy_bridge_3770k    Intel(R) Core(TM) i7-3770K CPU (Ivy Bridge)
#  corei7_haswell_4770        Intel(R) Core(TM) i7-4770 CPU (Haswell)
#  broadwell_ult              Intel(R) Processor 5Y70 CPU (Broadwell)
#
#  COUNT:
#    Set the number of processors:cores per processor:threads per core when
#    Bochs is compiled for SMP emulation. Bochs currently supports up to
#    14 threads (legacy APIC) or 254 threads (xAPIC or higher) running
#    simultaniosly. If Bochs is compiled without SMP support, it won't accept
#    values different from 1.
#
#  QUANTUM:
#    Maximum amount of instructions allowed to execute by processor before
#    returning control to another cpu. This option exists only in Bochs 
#    binary compiled with SMP support.
#
#  RESET_ON_TRIPLE_FAULT:
#    Reset the CPU when triple fault occur (highly recommended) rather than
#    PANIC. Remember that if you trying to continue after triple fault the 
#    simulation will be completely bogus !
#
#  CPUID_LIMIT_WINNT:
#    Determine whether to limit maximum CPUID function to 2. This mode is
#    required to workaround WinNT installation and boot issues.
#
#  MSRS:
#    Define path to user CPU Model Specific Registers (MSRs) specification.
#    See example in msrs.def.
#
#  IGNORE_BAD_MSRS:
#    Ignore MSR references that Bochs does not understand; print a warning
#    message instead of generating #GP exception. This option is enabled
#    by default but will not be avaiable if configurable MSRs are enabled.
#
#  MWAIT_IS_NOP:
#    When this option is enabled MWAIT will not put the CPU into a sleep state.
#    This option exists only if Bochs compiled with --enable-monitor-mwait.
#
#  IPS:
#    Emulated Instructions Per Second. This is the number of IPS that bochs
#    is capable of running on your machine. You can recompile Bochs with
#    --enable-show-ips option enabled, to find your host's capability.
#    Measured IPS value will then be logged into your log file or shown
#    in the status bar (if supported by the gui).
#
#    IPS is used to calibrate many time-dependent events within the bochs 
#    simulation.  For example, changing IPS affects the frequency of VGA
#    updates, the duration of time before a key starts to autorepeat, and
#    the measurement of BogoMips and other benchmarks.
#
#  Examples:
#
#  Bochs Machine/Compiler                                 Mips
# ______________________________________________________________________
#  2.4.6 3.4Ghz Intel Core i7 2600 with Win7x64/g++ 4.5.2 85 to 95 Mips
#  2.3.7 3.2Ghz Intel Core 2 Q9770 with WinXP/g++ 3.4     50 to 55 Mips
#  2.3.7 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4       38 to 43 Mips
#  2.2.6 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4       21 to 25 Mips
#  2.2.6 2.1Ghz Athlon XP with Linux 2.6/g++ 3.4          12 to 15 Mips
#=======================================================================
cpu: model=pentium_mmx, count=1, ips=2000000, reset_on_triple_fault=1

#=======================================================================
# MEMORY
# Set the amount of physical memory you want to emulate.
#
# GUEST:
# Set amount of guest physical memory to emulate. The default is 32MB,
# the maximum amount limited only by physical address space limitations.
#
# HOST:
# Set amount of host memory you want to allocate for guest RAM emulation.
# It is possible to allocate less memory than you want to emulate in guest
# system. This will fake guest to see the non-existing memory. Once guest
# system touches new memory block it will be dynamically taken from the
# memory pool. You will be warned (by FATAL PANIC) in case guest already
# used all allocated host memory and wants more.
#
#=======================================================================
memory: guest=64, host=64

#=======================================================================
# ROMIMAGE:
# The ROM BIOS controls what the PC does when it first powers on.
# Normally, you can use a precompiled BIOS in the source or binary
# distribution called BIOS-bochs-latest. The default ROM BIOS is usually loaded
# starting at address 0xfffe0000, and it is exactly 128k long. The legacy
# version of the Bochs BIOS is usually loaded starting at address 0xffff0000,
# and it is exactly 64k long.
# You can use the environment variable $BXSHARE to specify the location
# of the BIOS.
# The usage of external large BIOS images (up to 512k) at memory top is
# now supported, but we still recommend to use the BIOS distributed with Bochs.
# The start address is optional, since it can be calculated from image size.
#=======================================================================
romimage: file=$BXSHARE/BIOS-bochs-latest 
#romimage: file=$BXSHARE/bios.bin-1.7.5 # http://www.seabios.org/SeaBIOS
#romimage: file=mybios.bin, address=0xfff80000 # 512k at memory top

#=======================================================================
# VGAROMIMAGE
# You now need to load a VGA ROM BIOS into C0000.
#=======================================================================
#vgaromimage: file=bios/VGABIOS-elpin-2.40
vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
#vgaromimage: file=bios/VGABIOS-lgpl-latest-cirrus

#=======================================================================
# VGA:
# This defines parameters related to the VGA display
#
#   EXTENSION
#     Here you can specify the display extension to be used. With the value
#     'none' you can use standard VGA with no extension. Other supported
#     values are 'vbe' for Bochs VBE and 'cirrus' for Cirrus SVGA support.
#
#   UPDATE_FREQ
#     This parameter specifies the number of display updates per second.
#     The VGA update timer now uses the realtime engine and the default
#     value is 5. This parameter can be changed at runtime.
#
#   REALTIME
#     If set to 1, the VGA timer is based on realtime, otherwise it is based
#     on the ips setting. If the host is slow (low ips, update_freq) and the
#     guest uses HLT appropriately, setting this to 0 and "clock: sync=none"
#     may improve the responsiveness of the guest GUI when the guest is
#     otherwise idle. The default value is 1.
#
# Examples:
#   vga: extension=cirrus, update_freq=10
#=======================================================================
#vga: extension=vbe, update_freq=5, realtime=1

#=======================================================================
# KEYBOARD:
# This defines parameters related to the emulated keyboard
#
#   TYPE:
#     Type of keyboard return by a "identify keyboard" command to the
#     keyboard controller. It must be one of "xt", "at" or "mf".
#     Defaults to "mf". It should be ok for almost everybody. A known
#     exception is french macs, that do have a "at"-like keyboard.
#
#   SERIAL_DELAY:
#     Approximate time in microseconds that it takes one character to
#     be transferred from the keyboard to controller over the serial path.
#
#   PASTE_DELAY:
#     Approximate time in microseconds between attempts to paste
#     characters to the keyboard controller. This leaves time for the
#     guest os to deal with the flow of characters.  The ideal setting
#     depends on how your operating system processes characters.  The
#     default of 100000 usec (.1 seconds) was chosen because it works 
#     consistently in Windows.
#     If your OS is losing characters during a paste, increase the paste
#     delay until it stops losing characters.
#
#   KEYMAP:
#     This enables a remap of a physical localized keyboard to a
#     virtualized us keyboard, as the PC architecture expects.
#
#   USER_SHORTCUT:
#     This defines the keyboard shortcut to be sent when you press the "user"
#     button in the headerbar. The shortcut string is a combination of maximum
#     3 key names (listed below) separated with a '-' character.
#     Valid key names:
#     "alt", "bksl", "bksp", "ctrl", "del", "down", "end", "enter", "esc",
#     "f1", ... "f12", "home", "ins", "left", "menu", "minus", "pgdwn", "pgup",
#     "plus", "power", "print", "right", "scrlck", "shift", "space", "tab", "up"
#     and "win".

# Examples:
#   keyboard: type=mf, serial_delay=200, paste_delay=100000
#   keyboard: keymap=gui/keymaps/x11-pc-de.map
#   keyboard: user_shortcut=ctrl-alt-del
#=======================================================================
#keyboard: type=mf, serial_delay=250

#=======================================================================
# MOUSE:
# This defines parameters for the emulated mouse type, the initial status
# of the mouse capture and the runtime method to toggle it.
#
#  TYPE:
#  With the mouse type option you can select the type of mouse to emulate.
#  The default value is 'ps2'. The other choices are 'imps2' (wheel mouse
#  on PS/2), 'serial', 'serial_wheel', 'serial_msys' (one com port requires
#  setting 'mode=mouse') and 'bus' (if present). To connect a mouse to an
#  USB port, see the 'usb_uhci', 'usb_ohci' or 'usb_xhci' options (requires
#  PCI and USB support).
#
#  ENABLED:
#  The Bochs gui creates mouse "events" unless the 'enabled' option is
#  set to 0. The hardware emulation itself is not disabled by this.
#  Unless you have a particular reason for enabling the mouse by default,
#  it is recommended that you leave it off. You can also toggle the mouse
#  usage at runtime (RFB, SDL, Win32, wxWidgets and X11 - see below).
#
#  TOGGLE:
#  The default method to toggle the mouse capture at runtime is to press the
#  CTRL key and the middle mouse button ('ctrl+mbutton'). This option allows
#  to change the method to 'ctrl+f10' (like DOSBox), 'ctrl+alt' (like QEMU)
#  or 'f12' (replaces win32 'legacyF12' option).
#
# Examples:
#   mouse: enabled=1
#   mouse: type=imps2, enabled=1
#   mouse: type=serial, enabled=1
#   mouse: enabled=0, toggle=ctrl+f10
#=======================================================================
mouse: enabled=0

#=======================================================================
# PCI:
# This option controls the presence of a PCI chipset in Bochs. Currently it only
# supports the i430FX and i440FX chipsets. You can also specify the devices
# connected to PCI slots. Up to 5 slots are available. For these combined PCI/ISA
# devices assigning to slot is mandatory if you want to emulate the PCI model:
# cirrus, ne2k and pcivga. These PCI-only devices are also supported, but they
# are auto-assigned if you don't use the slot configuration: e1000, es1370,
# pcidev, pcipnic, usb_ohci, usb_xhci and voodoo.
#
# Example:
#   pci: enabled=1, chipset=i440fx, slot1=pcivga, slot2=ne2k
#=======================================================================
pci: enabled=1, chipset=i440fx

#=======================================================================
# CLOCK:
# This defines the parameters of the clock inside Bochs:
#
#  SYNC:
#  This defines the method how to synchronize the Bochs internal time
#  with realtime. With the value 'none' the Bochs time relies on the IPS
#  value and no host time synchronization is used. The 'slowdown' method
#  sacrifices performance to preserve reproducibility while allowing host
#  time correlation. The 'realtime' method sacrifices reproducibility to
#  preserve performance and host-time correlation.
#  It is possible to enable both synchronization methods.
#
#  RTC_SYNC:
#  If this option is enabled together with the realtime synchronization,
#  the RTC runs at realtime speed. This feature is disabled by default.
#
#  TIME0:
#  Specifies the start (boot) time of the virtual machine. Use a time
#  value as returned by the time(2) system call or a string as returned
#  by the ctime(3) system call. If no time0 value is set or if time0
#  equal to 1 (special case) or if time0 equal 'local', the simulation
#  will be started at the current local host time. If time0 equal to 2
#  (special case) or if time0 equal 'utc', the simulation will be started
#  at the current utc time.
#
# Syntax:
#  clock: sync=[none|slowdown|realtime|both], time0=[timeValue|local|utc]
#
# Example:
#   clock: sync=none,     time0=local       # Now (localtime)
#   clock: sync=slowdown, time0=315529200   # Tue Jan  1 00:00:00 1980
#   clock: sync=none,     time0="Mon Jan  1 00:00:00 1990" # 631148400
#   clock: sync=realtime, time0=938581955   # Wed Sep 29 07:12:35 1999
#   clock: sync=realtime, time0="Sat Jan  1 00:00:00 2000" # 946681200
#   clock: sync=none,     time0=1           # Now (localtime)
#   clock: sync=none,     time0=utc         # Now (utc/gmt)
#
# Default value are sync=none, rtc_sync=0, time0=local
#=======================================================================
clock: sync=realtime, rtc_sync=1, time0=utc

#=======================================================================
# FLOPPYA:
# Point this to pathname of floppy image file or device
# This should be of a bootable floppy(image/device) if you're
# booting from 'a' (or 'floppy').
#
# You can set the initial status of the media to 'ejected' or 'inserted'.
#   floppya: 2_88=path, status=ejected    (2.88M 3.5"  media)
#   floppya: 1_44=path, status=inserted   (1.44M 3.5"  media)
#   floppya: 1_2=path, status=ejected     (1.2M  5.25" media)
#   floppya: 720k=path, status=inserted   (720K  3.5"  media)
#   floppya: 360k=path, status=inserted   (360K  5.25" media)
#   floppya: 320k=path, status=inserted   (320K  5.25" media)
#   floppya: 180k=path, status=inserted   (180K  5.25" media)
#   floppya: 160k=path, status=inserted   (160K  5.25" media)
#   floppya: image=path, status=inserted  (guess media type from image size)
#   floppya: 1_44=vvfat:path, status=inserted  (use directory as VFAT media)
#   floppya: type=1_44                    (1.44M 3.5" floppy drive, no media)
#
# The path should be the name of a disk image file.  On Unix, you can use a raw
# device name such as /dev/fd0 on Linux.  On win32 platforms, use drive letters
# such as a: or b: as the path.  The parameter 'image' works with image files
# only. In that case the size must match one of the supported types.
# The parameter 'type' can be used to enable the floppy drive without media
# and status specified. Usually the drive type is set up based on the media type.
# The optional parameter 'write_protected' can be used to control the media
# write protect switch. By default it is turned off.
#=======================================================================
#floppya: 1_44=/dev/fd0, status=inserted
#floppya: image=../1.44, status=inserted
#floppya: 1_44=/dev/fd0H1440, status=inserted
#floppya: 1_2=../1_2, status=inserted
#floppya: 1_44=a:, status=inserted
#floppya: 1_44=a.img, status=inserted, write_protected=1
#floppya: 1_44=/dev/rfd0a, status=inserted
floppya: image=boot.img, status=inserted, write_protected=1

#=======================================================================
# FLOPPYB:
# See FLOPPYA above for syntax
#=======================================================================
#floppyb: 1_44=b:, status=inserted
#floppyb: 1_44=b.img, status=inserted

#=======================================================================
# ATA0, ATA1, ATA2, ATA3
# ATA controller for hard disks and cdroms
#
# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number
# 
# These options enables up to 4 ata channels. For each channel
# the two base io addresses and the irq must be specified.
# 
# ata0 and ata1 are enabled by default with the values shown below
#
# Examples:
#   ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
#   ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
#   ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
#   ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x360, irq=9
#=======================================================================
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9

#=======================================================================
# ATA[0-3]-MASTER, ATA[0-3]-SLAVE
#
# This defines the type and characteristics of all attached ata devices:
#   type=       type of attached device [disk|cdrom] 
#   mode=       only valid for disks [flat|concat|external|dll|sparse|vmware3]
#                                    [vmware4|undoable|growing|volatile|vpc]
#                                    [vbox|vvfat]
#   path=       path of the image / directory
#   cylinders=  only valid for disks
#   heads=      only valid for disks
#   spt=        only valid for disks
#   status=     only valid for cdroms [inserted|ejected]
#   biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos]
#   translation=type of translation of the bios, only for disks [none|lba|large|rechs|auto]
#   model=      string returned by identify device command
#   journal=    optional filename of the redolog for undoable, volatile and vvfat disks
#
# Point this at a hard disk image file, cdrom iso file, or physical cdrom
# device.  To create a hard disk image, try running bximage.  It will help you
# choose the size and then suggest a line that works with it.
#
# In UNIX it may be possible to use a raw device as a Bochs hard disk, 
# but WE DON'T RECOMMEND IT.  In Windows there is no easy way.
#
# In windows, the drive letter + colon notation should be used for cdroms.
# Depending on versions of windows and drivers, you may only be able to 
# access the "first" cdrom in the system.  On MacOSX, use path="drive"
# to access the physical drive.
#
# The path is mandatory for hard disks. Disk geometry autodetection works with
# images created by bximage if CHS is set to 0/0/0 (cylinders are calculated
# using  heads=16 and spt=63). For other hard disk images and modes the
# cylinders, heads, and spt are mandatory. In all cases the disk size reported
# from the image must be exactly C*H*S*512.
#
# Default values are:
#   mode=flat, biosdetect=auto, translation=auto, model="Generic 1234"
#
# The biosdetect option has currently no effect on the bios
#
# Examples:
#   ata0-master: type=disk, mode=flat, path=10M.sample, cylinders=306, heads=4, spt=17
#   ata0-slave:  type=disk, mode=flat, path=20M.sample, cylinders=615, heads=4, spt=17
#   ata1-master: type=disk, mode=flat, path=30M.sample, cylinders=615, heads=6, spt=17
#   ata1-slave:  type=disk, mode=flat, path=46M.sample, cylinders=940, heads=6, spt=17
#   ata2-master: type=disk, mode=flat, path=62M.sample, cylinders=940, heads=8, spt=17
#   ata2-slave:  type=disk, mode=flat, path=112M.sample, cylinders=900, heads=15, spt=17
#   ata3-master: type=disk, mode=flat, path=483M.sample, cylinders=1024, heads=15, spt=63
#   ata3-slave:  type=cdrom, path=iso.sample, status=inserted
#=======================================================================
#ata0-master: type=disk, mode=flat, path="boot.bin"
#ata0-master: type=disk, mode=flat, path="30M.sample", cylinders=615, heads=6, spt=17
#ata0-master: type=disk, mode=flat, path="c.img", cylinders=0 # autodetect
#ata0-slave: type=disk, mode=vvfat, path=/bochs/images/vvfat, journal=vvfat.redolog
#ata0-slave: type=cdrom, path=D:, status=inserted
#ata0-slave: type=cdrom, path=/dev/cdrom, status=inserted
#ata0-slave: type=cdrom, path="drive", status=inserted
#ata0-slave: type=cdrom, path=/dev/rcd0d, status=inserted 

#=======================================================================
# BOOT:
# This defines the boot sequence. Now you can specify up to 3 boot drives,
# which can be 'floppy', 'disk', 'cdrom' or 'network' (boot ROM).
# Legacy 'a' and 'c' are also supported.
# Examples:
#   boot: floppy
#   boot: cdrom, disk
#   boot: network, disk
#   boot: cdrom, floppy, disk
#=======================================================================
boot: floppy

#=======================================================================
# FLOPPY_BOOTSIG_CHECK: disabled=[0|1]
# Enables or disables the 0xaa55 signature check on boot floppies
# Defaults to disabled=0
# Examples:
#   floppy_bootsig_check: disabled=0
#   floppy_bootsig_check: disabled=1
#=======================================================================
floppy_bootsig_check: disabled=0

#=======================================================================
# LOG:
# Give the path of the log file you'd like Bochs debug and misc. verbiage
# to be written to. If you don't use this option or set the filename to
# '-' the output is written to the console. If you really don't want it,
# make it "/dev/null" (Unix) or "nul" (win32). :^(
#
# Examples:
#   log: ./bochs.out
#   log: /dev/tty
#=======================================================================
#log: /dev/null
log: -

#=======================================================================
# LOGPREFIX:
# This handles the format of the string prepended to each log line.
# You may use those special tokens :
#   %t : 11 decimal digits timer tick
#   %i : 8 hexadecimal digits of cpu current eip (ignored in SMP configuration)
#   %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror)
#   %d : 5 characters string of the device, between brackets
# 
# Default : %t%e%d
# Examples:
#   logprefix: %t-%e-@%i-%d
#   logprefix: %i%e%d
#=======================================================================
#logprefix: %t%e%d

#=======================================================================
# LOG CONTROLS
#
# Bochs has four severity levels for event logging.
#   panic: cannot proceed.  If you choose to continue after a panic, 
#          don't be surprised if you get strange behavior or crashes.
#   error: something went wrong, but it is probably safe to continue the
#          simulation.
#   info: interesting or useful messages.
#   debug: messages useful only when debugging the code.  This may
#          spit out thousands per second.
#
# For events of each level, you can choose to exit Bochs ('fatal'), 'report'
# or 'ignore'. On some guis you have the additional choice 'ask'. A gui dialog
# appears asks how to proceed.
#
# It is also possible to specify the 'action' to do for each Bochs facility
# separately (e.g. crash on panics from everything except the cdrom, and only
# report those). See the 'log function' module list in the user documentation.
#
# If you are experiencing many panics, it can be helpful to change
# the panic action to report instead of fatal.  However, be aware
# that anything executed after a panic is uncharted territory and can 
# cause bochs to become unstable.  The panic is a "graceful exit," so
# if you disable it you may get a spectacular disaster instead.
#=======================================================================
panic: action=ask
error: action=report
info: action=report
debug: action=ignore, pci=report # report BX_DEBUG from module 'pci'

#=======================================================================
# DEBUGGER_LOG:
# Give the path of the log file you'd like Bochs to log debugger output.
# If you really don't want it, make it /dev/null or '-'. :^(
#
# Examples:
#   debugger_log: ./debugger.out
#=======================================================================
#debugger_log: /dev/null
#debugger_log: debugger.out
debugger_log: -

#=======================================================================
# COM1, COM2, COM3, COM4:
# This defines a serial port (UART type 16550A). In the 'term' mode you can
# specify a device to use as com1. This can be a real serial line, or a pty.
# To use a pty (under X/Unix), create two windows (xterms, usually).  One of
# them will run bochs, and the other will act as com1. Find out the tty the com1
# window using the `tty' command, and use that as the `dev' parameter.
# Then do `sleep 1000000' in the com1 window to keep the shell from
# messing with things, and run bochs in the other window.  Serial I/O to
# com1 (port 0x3f8) will all go to the other window.
# In socket* and pipe* (win32 only) modes Bochs becomes either socket/named pipe
# client or server. In client mode it connects to an already running server (if
# connection fails Bochs treats com port as not connected). In server mode it
# opens socket/named pipe and waits until a client application connects to it
# before starting simulation. This mode is useful for remote debugging (e.g.
# with gdb's "target remote host:port" command or windbg's command line option
# -k com:pipe,port=\\.\pipe\pipename). Socket modes use simple TCP communication,
#  pipe modes use duplex byte mode pipes.
# Other serial modes are 'null' (no input/output), 'file' (output to a file
# specified as the 'dev' parameter), 'raw' (use the real serial port - under
# construction for win32), 'mouse' (standard serial mouse - requires
# mouse option setting 'type=serial', 'type=serial_wheel' or 'type=serial_msys').
#
# Examples:
#   com1: enabled=1, mode=null
#   com1: enabled=1, mode=mouse
#   com2: enabled=1, mode=file, dev=serial.out
#   com3: enabled=1, mode=raw, dev=com1
#   com3: enabled=1, mode=socket-client, dev=localhost:8888
#   com3: enabled=1, mode=socket-server, dev=localhost:8888
#   com4: enabled=1, mode=pipe-client, dev=\\.\pipe\mypipe
#   com4: enabled=1, mode=pipe-server, dev=\\.\pipe\mypipe
#=======================================================================
#com1: enabled=1, mode=term, dev=/dev/ttyp9


#=======================================================================
# PARPORT1, PARPORT2:
# This defines a parallel (printer) port. When turned on and an output file is
# defined the emulated printer port sends characters printed by the guest OS
# into the output file. On some platforms a device filename can be used to
# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on
# win32 platforms).
#
# Examples:
#   parport1: enabled=1, file="parport.out"
#   parport2: enabled=1, file="/dev/lp0"
#   parport1: enabled=0
#=======================================================================
#parport1: enabled=1, file="parport.out"

#=======================================================================
# MAGIC_BREAK:
# This enables the "magic breakpoint" feature when using the debugger.
# The useless cpu instruction XCHG BX, BX causes Bochs to enter the
# debugger mode. This might be useful for software development.
#
# Example:
#   magic_break: enabled=1
#=======================================================================
magic_break: enabled=1
What's wrong?
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: "bootloader" stub - works fine in QEMU, but not in BOCHS

Post by BenLunt »

You haven't set up a segment register yet, specifically the DS register.

Any memory access must use a segment register.

mov [edx], word 0x20

assumes the DS segment.

DS is *not* defined to be set from any boot.

Also, since you are in real mode, you can't access 0xB8000 using [edx] alone. You need to set up a segment:offset pair to point to that position.

mov ax,0xB800
mov es,ax
xor di,di
mov cx,(80*25)
mov ax,0720h
rep stosw

Also, as you notice in my code above, the screen is not filled with only characters. It is filled with attribute:character pairs. Setting the attribute to 0x00 as your code does, will make any character non-visible.

BTW, how does it work fine in QEMU? Your boot code starts in real mode. If it worked as expected, QEMU would be in error, and I don't think it is.

Ben
Licho
Posts: 2
Joined: Sun Jun 05, 2016 11:48 am
Libera.chat IRC: licho

Re: "bootloader" stub - works fine in QEMU, but not in BOCHS

Post by Licho »

Non-visible character isn't a bug, I just clear whole screen by putting spaces (color didn't matter at all). And yeah, it's working perfectly under QEMU in that form, and also on EeePC 900 which I use to test things like this on real machine). Anyway, thanks for help.

Image
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: "bootloader" stub - works fine in QEMU, but not in BOCHS

Post by BenLunt »

Well, that's interesting. Does QEMU start out in unreal mode?

Do you have any other code run before yours, say GRUB or something else?

I am interested in how this is, because without some outside help, your code shouldn't work at all (no offense intended).

Please explain in a little more detail. I would be interested in finding out why it works on QEMU and not Bochs.
Is it a Bochs error, or does QEMU set and use unreal mode before it passes control to your boot code?

Without any more information, I would assume what is happening is that QEMU uses unreal mode in the POST and doesn't reset DS back to a 16-bit segment register before passing control to your boot code. This would be the only thing that would make it work.

Or am I completely missing something here.

Ben
mikegonta
Member
Member
Posts: 229
Joined: Thu May 19, 2011 5:13 am
Contact:

Little Big Mode was "bootloader" stub - works fine in QEMU

Post by mikegonta »

BenLunt wrote:Well, that's interesting. Does QEMU start out in unreal mode?
There's nothing unreal about it. Memory access is still within 1MB.
BenLunt wrote:Do you have any other code run before yours, say GRUB or something else?
I am interested in how this is, because without some outside help, your code shouldn't work at all (no offense intended).
Nothing else is required. It actually does work, even on a real (386 or better) PC.
BenLunt wrote:Or am I completely missing something here.
Apparently when using 32 bit instructions in real mode on a modern PC the 24 bit address calculation (segment register * 16 + offset)
utilizes 24 bits of the offset register.
This is an interesting discovery.
By using 32 bit instructions and setting the segment registers to zero the entire 1MB flat address space is accessible in real mode.
Mike Gonta
look and see - many look but few see

https://mikegonta.com
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: "bootloader" stub - works fine in QEMU, but not in BOCHS

Post by Combuster »

Nothing else is required. It actually does work, even on a real (386 or better) PC.
I've been actively testing this ages ago. My Celeron-433 certainly does not boot into a state where the segment limit > 64k, and I wouldn't trust any other machine for it. QEMU is just cheating here (as it usually does)

The 64k segment limit also has nothing to do with 1MB, that's the A20 gate's fault.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: Little Big Mode was "bootloader" stub - works fine in QE

Post by alexfru »

mikegonta wrote: Apparently when using 32 bit instructions in real mode on a modern PC the 24 bit address calculation (segment register * 16 + offset)
utilizes 24 bits of the offset register.
This is an interesting discovery.
That shouldn't work / isn't guaranteed to. The segment limit should be set to 65535 and should be observed in real mode. I think, it may be the BIOS to blame for leaving large segment limits.
mikegonta
Member
Member
Posts: 229
Joined: Thu May 19, 2011 5:13 am
Contact:

Re: Little Big Mode was "bootloader" stub - works fine in QE

Post by mikegonta »

alexfru wrote:
mikegonta wrote:Apparently when using 32 bit instructions in real mode on a modern PC the 24 bit address calculation (segment register * 16 + offset)
utilizes 24 bits of the offset register.
This is an interesting discovery.
That shouldn't work / isn't guaranteed to.
A lot of things shouldn't work but simply do.
alexfru wrote:The segment limit should be set to 65535 and should be observed in real mode. I think, it may be the BIOS to blame for leaving
large segment limits.
The segment is zero - the resulting combined address is within the real mode addressing limits.
Mike Gonta
look and see - many look but few see

https://mikegonta.com
mikegonta
Member
Member
Posts: 229
Joined: Thu May 19, 2011 5:13 am
Contact:

Little Big Mode

Post by mikegonta »

Combuster wrote:
Nothing else is required. It actually does work, even on a real (386 or better) PC.
I've been actively testing this ages ago. My Celeron-433 certainly does not boot into a state where the segment limit > 64k, and I wouldn't
trust any other machine for it. QEMU is just cheating here (as it usually does)The 64k segment limit also has nothing to do with 1MB, that's
the A20 gate's fault.
Even this works:

Code: Select all

org 0x7C00
  push 0xA000
  pop ds
  mov edx, 0x18000+25*80 ; center of screen
  mov WORD [edx], 0x0258 ; green "X"
  jmp $
times 510 - ( $ - $$ ) db 0
  dw 0xAA55
Can you try the OP's code (or even this) on your 433 and report back?
Mike Gonta
look and see - many look but few see

https://mikegonta.com
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: Little Big Mode was "bootloader" stub - works fine in QE

Post by alexfru »

mikegonta wrote:The segment is zero - the resulting combined address is within the real mode addressing limits.
Observe that FB is defined as 0xB8000. Then there's this code:

Code: Select all

    mov edx, FB
    .write:
       mov [edx], WORD 0x20
While edx is less than 1MB, the offset within segment 0 (0xB8000) is greater than the expected realmode segment limit (0xFFFF) and the move instruction should trigger a #GP. Unless, of course, the segment limit is sufficiently large.
mikegonta
Member
Member
Posts: 229
Joined: Thu May 19, 2011 5:13 am
Contact:

Re: Little Big Mode was "bootloader" stub - works fine in QE

Post by mikegonta »

alexfru wrote:
mikegonta wrote:The segment is zero - the resulting combined address is within the real mode addressing limits.
Observe that FB is defined as 0xB8000. Then there's this code:

Code: Select all

    mov edx, FB
    .write:
       mov [edx], WORD 0x20
While edx is less than 1MB, the offset within segment 0 (0xB8000) is greater than the expected realmode segment limit (0xFFFF)
and the move instruction should trigger a #GP. Unless, of course, the segment limit is sufficiently large.
This (the effect of unreal mode) must be it. My apologies to Ben Lunt.
Oh well, another good reason to say goodbye to real mode code.
Last edited by mikegonta on Tue Jun 07, 2016 2:53 am, edited 1 time in total.
Mike Gonta
look and see - many look but few see

https://mikegonta.com
mikegonta
Member
Member
Posts: 229
Joined: Thu May 19, 2011 5:13 am
Contact:

Re: Little Big Mode

Post by mikegonta »

mikegonta wrote:
alexfru wrote:
mikegonta wrote:The segment is zero - the resulting combined address is within the real mode addressing limits.
Observe that FB is defined as 0xB8000. Then there's this code:

Code: Select all

    mov edx, FB
    .write:
       mov [edx], WORD 0x20
While edx is less than 1MB, the offset within segment 0 (0xB8000) is greater than the expected realmode segment limit (0xFFFF)
and the move instruction should trigger a #GP. Unless, of course, the segment limit is sufficiently large.
This (the effect of unreal mode) must be it. My apologies to Ben Lunt.
OK, this time I wasn't right and everyone else wasn't wrong. (Well, at least I didn't say that I was wrong and everyone else was right).
Last edited by mikegonta on Tue Jun 07, 2016 2:52 am, edited 3 times in total.
Mike Gonta
look and see - many look but few see

https://mikegonta.com
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: "bootloader" stub - works fine in QEMU, but not in BOCHS

Post by BenLunt »

This was my assumption/conclusion. Modern, and even not so modern BIOSes may use unreal mode to "initialize" the machine, then pass control to the boot sector. There is no reason to switch the segment register's limit back to 64k since a boot sector code should assume a 64k limit.

I believe this is an error on QEMU's part, a cheat as one has put it, while Bochs handles this correctly.

To the OP, I would suggest you do not assume that your code works on all machines, and code your boot sector as if you only had 64k limits. However, it takes very little code to switch to unreal mode, so you might want to do that too, though this assumes you have a 32-bit machine.

Another suggestion/question. Why do you use IO to set the cursor position? Why not use the safer, more reliable BIOS calls?

Thanks,
Ben
mikegonta
Member
Member
Posts: 229
Joined: Thu May 19, 2011 5:13 am
Contact:

Re: "bootloader" stub - works fine in QEMU, but not in BOCHS

Post by mikegonta »

Licho wrote:I wrote a simple code running as bootloader:
What's wrong?
On the other hand the (slightly modified) code works just fine in PM32.

Code: Select all

; Framebuffer
%define FB 0xB8000
%define FB_W 80
%define FB_H 25
%define FB_END FB + (FB_W) * (FB_H) * 2

; Char color code
%define FB_COLOR 0x02

; Position of logo
%define LOGO_X ((FB_W / 2) - 16)
%define LOGO_Y ((FB_H / 2) - 4)
%define LOGO_POS (LOGO_X + (FB_W * LOGO_Y)) * 2

%define debug xchg bx, bx

%define PM_CODE_SELECTOR 8
%define PM_DATA_SELECTOR 0x10

org 0x7C00
  cli
  lgdt [cs:gdt_ptr] ; load Global Descriptor Table
  mov eax, cr0
  or al, 1 ; set PE bit
  mov cr0, eax
  jmp PM_CODE_SELECTOR:pm
use32
pm:
  mov eax, PM_DATA_SELECTOR
  mov ds, ax
  mov es, ax
  
; Set cursor position to (0,0)
mov edx, 0x3D4
mov al, 14
out dx, al

inc edx ;0x3D5
mov al, 0
out dx, al

dec edx ;0x3D4
mov al, 15
out dx, al

inc edx ;0x3D5
mov al, 0
out dx, al

debug
; Clear whole screen
clear:
    mov edx, FB
    .write:
       mov [edx], WORD 0x20
        add edx, 2
        cmp edx, FB_END
        jnz .write

debug
; Draw logo
logo:
    ; Prepare registers for loading string
    mov edx, FB + LOGO_POS
    mov ebx, 1
    mov esi, data.str

    ; Write next char
    .write:
       ; Read single char from string
        lodsb
       
        ; Jump on special chars
        cmp al, 0xA
        jz .new_line ; Make new line if char == 0xA (\n)
        cmp al, 0x0
        jz .end ; Exit loop on null byte
       
        debug
        ;Write char to framebuffer
        mov ah, FB_COLOR
        mov [edx], WORD ax
        add edx, 2
        jmp .write
    .new_line:
       debug
       mov edx, FB_W * 2
       imul edx, ebx
       add edx, FB + LOGO_POS
       inc ebx
        jmp .write
    .end:

; Loop forever
end:
    jmp $

data:
    .str:
        db '    _/_/_/        _/_/',0xA
        db '   _/    _/    _/        _/_/_/',0xA
        db '  _/_/_/    _/_/_/_/  _/    _/',0xA
        db ' _/    _/    _/      _/    _/',0xA
        db '_/_/_/      _/        _/_/_/',0xA
        db '                         _/',0xA
        db '                        _/',0x0

align 8
gdt_ptr:
  dw 23 ; Global Descriptor Table size - 1
  dd gdt_ptr
  dw 0
  dw 0xFFFF, 0, 0x9A00, 0xCF ; maximum pm code selector
  dw 0xFFFF, 0, 0x9200, 0xCF ; maximum pm data selector

    .fill: ;MBR partition table space
        times 510 - ( $ - $$ ) db 0
    .bootflag: ;Mark as bootable
        dw 0xAA55
Mike Gonta
look and see - many look but few see

https://mikegonta.com
Kevin
Member
Member
Posts: 1071
Joined: Sun Feb 01, 2009 6:11 am
Location: Germany
Contact:

Re: "bootloader" stub - works fine in QEMU, but not in BOCHS

Post by Kevin »

BenLunt wrote:I believe this is an error on QEMU's part, a cheat as one has put it, while Bochs handles this correctly.
Yes, QEMU generally doesn't check segment limits (presumably for performance reasons) when using emulation (TCG). With KVM, you should get the right exceptions, though.
Developer of tyndur - community OS of Lowlevel (German)
Post Reply