Hi,

I tried having a go at creating my own boot disk that would write text to the screen. The code is here:

;----------------------------------------------------------------------
; Simple boot program that prints the letter 'H'
;  and then hangs
; Joel Gompert 2001
;
; Disclaimer: I am not responsible for any results of the use of the contents
;   of this file
;----------------------------------------------------------------------
	org 0x7c00	; This is where BIOS loads the bootloader


; Execution begins here
entry:
	jmp short begin ; jump over the DOS boot record data


; ----------------------------------------------------------------------
; data portion of the "DOS BOOT RECORD"
; ----------------------------------------------------------------------
brINT13Flag     DB      90H             ; 0002h - 0EH for INT13 AH=42 READ
brOEM           DB      'MSDOS5.0'      ; 0003h - OEM name & DOS version (8 chars)
brBPS           DW      512             ; 000Bh - Bytes/sector
brSPC           DB      1               ; 000Dh - Sectors/cluster
brResCount      DW      1               ; 000Eh - Reserved (boot) sectors
brFATs          DB      2               ; 0010h - FAT copies
brRootEntries   DW      0E0H		; 0011h - Root directory entries
brSectorCount   DW      2880		; 0013h - Sectors in volume, < 32MB
brMedia         DB      240		; 0015h - Media descriptor
brSPF           DW      9               ; 0016h - Sectors per FAT
brSPH           DW      18              ; 0018h - Sectors per track
brHPC           DW      2		; 001Ah - Number of Heads
brHidden        DD      0               ; 001Ch - Hidden sectors
brSectors       DD      0	        ; 0020h - Total number of sectors
		DB      0               ; 0024h - Physical drive no.
		DB      0               ; 0025h - Reserved (FAT32)
		DB      29H             ; 0026h - Extended boot record sig 
brSerialNum     DD      404418EAH       ; 0027h - Volume serial number (random)
brLabel         DB      'Joels disk '   ; 002Bh - Volume label  (11 chars)
brFSID          DB      'FAT12   '      ; 0036h - File System ID (8 chars)
;------------------------------------------------------------------------


; --------------------------------------------
;  Boot program code begins here
; --------------------------------------------
; boot code begins at 0x003E
begin:
  
  mov BYTE [0xB8000], 0x41
  mov BYTE [0xB8001], 0x07
  mov BYTE [0xB8002], 0x41
  mov BYTE [0xB8003], 0x07

hang:
jmp hang

;---------------------------------------------

size equ	$ - entry
%if size+2 > 512
  %error "code is too large for boot sector"
%endif
	times	(512 - size - 2) db 0

	db	0xAA, 0x55		;2  byte boot signature

It's modified from some code from a tutorial. The modified bit is the part after the begin: label. His tutorial said that the video memory started at 0xB8000 for colour displays and 0xB0000 for mono displays. I have tried both in there but neither of them seem to work. I should be getting two a's in the top left corner (I think) but I get nothing.

I know I'm doing something wrong (probably over simplifying it :P) but thats it :lol: Can anyone help me with this?

Thanks, Matt

Hi,

It doesn't work because you've not set up DS segement register, as of what you have in the code, its ambigous and while your at it, its best to leave other regularly used segment registers defined rather keeping them ambigous. In x86 assembly, when you don't specify which segment register like the instruction mov BYTE [0xB8000], 7 it assumes the offset is relative to DS segment, this means if DS=10h for an example the linear address pointed to is B8100h. Also however, for a boot sector you should keep in mind your in 16bit mode and that offset B8000h would need to contain more then 16bits. There are methods to go around this such as an operand size override prefix (opcode 66h). Or to simply write it in 16bit you would use a 0xB800h segment which would look something like:

; --------------------------------------------
;  Boot program code begins here
; --------------------------------------------
; boot code begins at 0x003E
begin:
 
  mov ax, 0xB800
  mov ds, ax     ; DS=B800h (notice a zero is missing from linear)
  xor ax, ax       ; AX=0  
  mov es, ax      ; ES=0 might as well set ES too
  mov ax, 80h
  mov ss, ax      ; SS=80h (bottom of the stack is 800h linear)
  mov ax, 800h
  mov sp, ax      ; SP=800h ( top of the stack is SS:800h == 1000h linear)
 
  mov BYTE [0x00], 0x41    ; sets 0x41 at linear B8000h
  mov BYTE [0x01], 0x07    ; sets 0x71 at linear B8001h
  mov BYTE [0x02], 0x41    ; ...and so on
  mov BYTE [0x03], 0x07
 
.....

hi
i'm beginner in assembly language and now , reading "
Jeff Duntemann" book for this purpose . ( off topic : this book is the best ! :mrgreen: )

@ RYU :
can you insert here comlete code for build simple boot disk here ? ( print "hello world" message for example! )
and how i can use & copy it in disk for use ?
at the end, where i can found about boot loaders Programming ?

thank's alot & have a fun ;)

Hi,

@ RYU :
can you insert here comlete code for build simple boot disk here ? ( print "hello world" message for example! )
and how i can use & copy it in disk for use ?
at the end, where i can found about boot loaders Programming ?

Typically for boot sectors its best if we use BIOS interrupts to print text to the screan because this will reduce the code size where we only have 512 bytes to do everything. However to elaberate with the problem in this thread I'll show an example from my own bootsector with a bit of midifications. Note that I use MASM which I know isn't widely used so you will have to make the adjustments with your assembler syntax and directives.

.386P
.MODEL TINY
OPTION M510
OPTION SCOPED
OPTION PROLOGUE :none
OPTION EPILOGUE :none
OPTION CASEMAP :none
OPTION OFFSET :SEGMENT
OPTION SEGMENT :USE16

assume cs:none, ss:none, ds:none, es:none, gs:none, fs:none

ORG 0

$BOOT SEGMENT USE16
;========================================
jmp short __CSIP
nop
; ================================================================= ;
;;;;;;;; Bios Parameters Block & Extended Block ;;;;;;;;;
; ================================================================= ;
OemString db "MYOS...." ; 0
BytesPerSector dw 512 ; 8
SectorsPerCluster db 1 ; 10
ReservedSectors dw 1 ; 11
TotalFATs db 2 ; 13
MaxRootEntries dw 224 ; 14
TotalSectorsSmall dw 2880 ; 16
MediaDescriptor db 240 ; 18
SectorsPerFAT dw 9 ; 19
SectorsPerTrack dw 18 ; 21
NumHeads dw 2 ; 23
HiddenSectors dd 0 ; 25
TotalSectorsLarge dd 0 ; 29
;;;;;;;; Extended Parameters ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DriveNumber db 0 ; 33
Flags db 0 ; 34
Signature db 41 ; 35
VolumeID dd 23232 ; 36
VolumeLabel db "BOOT SYS" ; 40
SystemID db "FAT12 " ; 51
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

szHelloWorld db "HelloWorld", 0

__CSIP:
cli ; disable interrupts
db 0EAh
dw offset start ; jump far 07C0:start
dw 000h ; this is to ensure CS=7C0h for calls that returns from
;absolute address which is relative to CS segment
start:
mov ax, 07C0h
mov ds, ax ; DS=07C0h
mov ax, B800h
mov es, ax ; ES=B800h prepare ES to write to video memory
mov ax, 80h
mov ss, ax ; SS=80h (bottom of the stack is 800h linear)
mov ax, 800h
mov sp, ax ; SP=800h ( top of the stack is SS:800h == 1000h linear)

mov si, offset szHelloWorld
xor di, di ; start at ES:[0] == B8000 linear
mov ax, 0700h ; 15:8 attribute 7:0 text character

PrintLoop:

mov al, [si] ; load a character
test al, al
jz short HALT ; if(ZF==1) indicates test is zero, we are finished.

mov es:[di], ax ; copy attribute and character to vmem
add di, 2 ; adjust offset in video memory by 2 (attribute+character)
inc si ; adjust our offset by 1
jmp short PrintLoop ;continue

HALT:
hlt
jmp short HALT

ORG 1FEh
$BOOTSIG dw 0AA55h ; last two bytes must contain this signature
END

Some things to note: The bootsector is made for FAT12 floppy bootsector, the BPB isn't necessary, but being in windows can make a lot of fusses without it. The far jump to __CSIP isnt necessary either, but if you do things later on such as installing interrupt routines and software interrupt to them, it ensures the routine has the correct return address and not to oblivion because the theres no standard that specifies the BIOS to set CS segment apon entering the bootsector or even all normal calls which the return address is abolute with CS segment. However the standard is the bootsector must be loaded at linear address 7C00h. The source also needs to be linked image relative, meaning it starts at offset 0. You may encounter other examples that use ORG 7C00h which means you would use zero based segments. Because of the ORG 7C00h in MASM creating images 7C00h + the code size I choose to base my code on a 7C00h segment (CS=ES=DS=7C0h) in this case ES was used to point to a video memory segment. Video memory usually will start at B8000h however this in now always the case, here I've assumed so, and detecting which mode the VGA is currently in is another issue. Hope this helps.

Hello, I have to write a bootloader using AMD64 assembler. I am a newbie in it. Do you think it will work if I just change the 16/32 bit registers to the coresponding ones of the AMD64 architecture? Are there any other changes to make? Thank you for the bootloader codes above.

Hello, I have to write a bootloader using AMD64 assembler. I am a newbie in it. Do you think it will work if I just change the 16/32 bit registers to the coresponding ones of the AMD64 architecture? Are there any other changes to make? Thank you for the bootloader codes above.

Sorry I am not familar with AMD64 processors. If they still follow 0x86 architecture the code pasted above should work because the processor should boot up in realmode (16bit), the 32bit processors do this and then instructed to go in 32bit protected mode. It is part of the 0x86 architecture to be backwards compatible.

Perhaps you should let us know when you find out.

This article has been dead for over six months. Start a new discussion instead.