I code a simple program which loads the sector (sector num.2) to the RAM
but prints nothing.
first, I tried this code for bootsector:
org 0x7c00
mov ax, 0x1000 ; ES:BX = 1000:0000
mov es, ax
mov bx, 0x00
LoadSectortoMemory:
mov al, 0x01 ; Load 1 sectors
mov ah, 0x02 ; Load disk data to ES:BX
mov cl, 0x02 ; Sector = 2
mov ch, 0x00 ; Cylinder = 0
mov dl, 0x00 ; Drive = 0
mov dh, 0x00 ; Head = 0
int 13h ; Read
jc LoadSectortoMemory ; ERROR => Try again
jmp 0x1000:0x0000
times 510-($-$$) db 0
dw 0xaa55
the kernel which takes the username and password from user then terminate the program:
mov si,Username
call Write
call Read
call Next_Line
call Pass
call Read
call Next_Line
call Kernel_Exit
Write:
mov al,[si]
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
inc si
mov dl,[si]
cmp dl,0x00
jne Write
ret
Read:
mov ah,0x00
int 0x16
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
cmp al,0x0d
jne Read
ret
Pass:
mov si,Password
call Write
ret
Next_Line:
mov al,0x0a
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
ret
Kernel_Exit:
mov si,Done
call Write
mov ah,0x4c
int 0x21
Username db 'Username: ',0
Password db 'Password: ',0
Done db 'Done',0
times 510-($-$$) db 0
and didn't work
after searching I tried this code (just registers added at the end:/):
bits 16
org 0x7c00
mov ax, 0x1000 ; ES:BX = 1000:0000
mov es, ax
mov bx, 0x00
LoadSectortoMemory:
mov al, 0x01 ; Load 1 sectors
mov ah, 0x02 ; Load disk data to ES:BX
mov cl, 0x02 ; Sector = 2
mov ch, 0x00 ; Cylinder = 0
mov dl, 0x00 ; Drive = 0
mov dh, 0x00 ; Head = 0
int 0x13 ; Read!
jc LoadSectortoMemory ; ERROR => Try again
mov ax, 0x1000
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x1000:0x0
times 510-($-$$) db 0
dw 0xaa55
again didn't work
command lines which I use:
nasm -fbin BootSector.asm -o Bootsector.bin
nasm -fbin Kernel.asm -o Kernel.bin
cat BootSector.bin Kernel.bin > Code.bin
qemu-system-x86_64 Code.bin
is it a problem with qemu?
can anyone help me with my problem?
thanks in advance
There are several problems with your code. First, the most important one:
LoadSectortoMemory:
mov al, 0x01 ; Load 1 sectors
mov ah, 0x02 ; Load disk data to ES:BX
mov cl, 0x02 ; Sector = 2
mov ch, 0x00 ; Cylinder = 0
mov dl, 0x00 ; Drive = 0
mov dh, 0x00 ; Head = 0
int 0x13 ; Read!
jc LoadSectortoMemory ; ERROR => Try again
This only works if you're being booted from drive unit zero. By default, qemu appears to set up your image as drive unit 80h (hda = first harddisk). You're assuming that you are loaded from unit 0 (fda = first diskette). Therefore, you need to either use the parameters -fda code.bin
to tell qemu to use your file as a diskette image, and/or drop the line modifying dl
to use the unit-to-load-from as initialised by the ROM-BIOS before it transfers control to your loader.
You already modified your loader to set the segment registers. Especially ds
needs to be set to 1000h because your kernel uses that segment register (implicitly) to access its messages. (Your kernel.asm has no org
line so NASM uses its default of org 0
here.) Instead of setting ds
in the boot loader, you could also add the following to the start of kernel.asm:
push cs
pop ds
This sets ds
to the value of cs
. In Real 86 Mode, this is valid to get a data segment reference with the same base address as the code segment (but with Read/Write permissions).
Besides setting ss
you should also set sp
. You should set sp
in the immediately following instruction to the one that sets ss
. Example:
mov ax, 1000h
cli
mov ss, ax
xor sp, sp
sti
This sets up sp
to equal zero. Because of underflow, the first used stack slot will be at ss:0FFFEh
(the top of the full 64 KiB segment).
In Kernel_Exit
you're using interrupt 21h service 4Ch. This service is not available to you in this environment. You should use something else, such as this:
xor ax, ax
int 16h ; wait for key pressed
int 19h ; reboot
Or this:
sti
halt:
hlt ; wait for external interrupt, keep CPU usage low
jmp halt ; jump infinitely to stop program flow
In Next_Line
you have this:
Next_Line:
mov al,0x0a
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
ret
This only happens to work because each time you use Next_Line
you previously used Read
which ends when it displayed a terminating 13 (CR = Carriage Return). Next_Line
, to be more general, should display first a 13 (CR) and then a 10 (LF = Line Feed). That is, you should do this:
Next_Line:
mov al, 13
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
mov al, 10
int 10h
ret
You're using the line times 510-($-$$) db 0
at the end of kernel.asm. You should use times 512 - ($ - $$) db 0
instead, to fill the entire sector, not just up to 510 bytes.