general protection fault when running os on iso - nasm
I have the following bootloader code which seems to run perfectly fine on a hard disk:
[bits 16]
[org 0x7c00]
bootld_start:
KERNEL_OFFSET equ 0x2000
xor ax, ax ; Explicitly set ES = DS = 0
mov ds, ax
mov es, ax
mov bx, 0x8C00 ; Set SS:SP to 0x8C00:0x0000 . The stack will exist
; between 0x8C00:0x0000 and 0x8C00:0xFFFF
mov ss, bx
mov sp, ax
mov [BOOT_DRIVE], dl
mov bx, boot_msg
call print_string
mov dl, [BOOT_DRIVE]
call disk_load
jmp pm_setup
jmp $
BOOT_DRIVE:
db 0
disk_load:
mov si, dap
mov ah, 0x42
int 0x13
;cmp al, 4
;jne disk_error_132
ret
dap:
db 0x10 ; Size of DAP
db 0
; You can only read 46 sectors into memory between 0x2000 and
; 0x7C00. Don't read anymore or we overwrite the bootloader we are
; executing from. (0x7c00-0x2000)/512 = 46
dw 46 ; Number of sectors to read
dw KERNEL_OFFSET ; Offset
dw 0 ; Segment
dd 1
dd 0
disk_error_132:
mov bx, disk_error_132_msg
call print_string
jmp $
disk_error_132_msg:
db 'Error! Error! Something is VERY wrong! (0x132)', 0
gdt_start:
gdt_null:
dd 0x0
dd 0x0
gdt_code:
dw 0xffff
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
boot_msg:
db 'OS is booting files... ', 0
done_msg:
db 'Done! ', 0
%include "boot/print_string.asm"
pm_setup:
mov bx, done_msg
call print_string
mov ax, 0
mov ss, ax
mov sp, 0xFFFC
mov ax, 0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
cli
lgdt[gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:b32
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
print32:
pusha
mov edx, VIDEO_MEMORY
.loop:
mov al, [ebx]
mov ah, WHITE_ON_BLACK
cmp al, 0
je .done
mov [edx], ax
add ebx, 1
add edx, 2
jmp .loop
.done:
popa
ret
b32:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Place stack below EBDA in lower memory
mov ebp, 0x9c000
mov esp, ebp
mov ebx, pmode_msg
call print32
call KERNEL_OFFSET
jmp $
pmode_msg:
db 'Protected mode enabled!', 0
kernel:
mov ebx, pmode_msg
call print32
jmp $
pmode_tst:
db 'Testing...'
times 510-($-$$) db 0
db 0x55
db 0xAA
The problem is that when I convert it to an ISO with these commands:
mkdir iso
mkdir iso/boot
cp image.flp iso/boot/boot
xorriso -as mkisofs -R -J -c boot/bootcat \
-b boot/boot -no-emul-boot -boot-load-size 4 \
-o image.iso iso
...it fails with a triple fault. When I run it with qemu-system-i386 -boot d -cdrom os-image.iso -m 512 -d int -no-reboot -no-shutdown, it outputs (excluding useless SMM exceptions):
check_exception old: 0xffffffff new 0xd
0: v=0d e=0000 i=0 cpl=0 IP=0008:0000000000006616
pc=0000000000006616
SP=0010:000000000009bff8 env->regs[R_EAX]=0000000000000000
EAX=00000000 EBX=00007d72 ECX=00000000 EDX=000000e0
ESI=00007cb0 EDI=00000010 EBP=0009c000 ESP=0009bff8
EIP=00006616 EFL=00000083 [--S---C] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 00007c73 00000018
IDT= 00000000 000003ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=000000e0 CCD=000001b3 CCO=ADDB
EFER=0000000000000000
check_exception old: 0xd new 0xd
1: v=08 e=0000 i=0 cpl=0 IP=0008:0000000000006616 pc=0000000000006616 SP=0010:000000000009bff8 env- >regs[R_EAX]=0000000000000000
EAX=00000000 EBX=00007d72 ECX=00000000 EDX=000000e0
ESI=00007cb0 EDI=00000010 EBP=0009c000 ESP=0009bff8
EIP=00006616 EFL=00000083 [--S---C] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 00007c73 00000018
IDT= 00000000 000003ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=000000e0 CCD=000001b3 CCO=ADDB
EFER=0000000000000000
check_exception old: 0x8 new 0xd
Which means that I got a 0x0d (general protection fault), then a 0x08 (double fault), then it triple faulted. Why is this happening?
EDIT: I have changed the command to:
xorriso -as mkisofs -R -J -c boot/bootcat -b boot/boot.flp -o nmos.iso nmos.flp
But I am now getting the following error:
xorriso : FAILURE : Cannot find in ISO image: -boot_image ... bin_path='/boot/boot.flp'
xorriso : NOTE : -return_with SORRY 32 triggered by problem severity FAILURE
Does anyone know what this means?
EDIT 2:
I have changed the code to read using ah=0x02 like this:
mov bx, KERNEL_OFFSET
mov ah, 0x02
mov al, 46
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
mov dl, [BOOT_DRIVE]
int 0x13
But it is still triple-faulting. Why?
I am the developer of xorriso. If image.flp is a floppy disk image
with MBR, possibly a partition table, and a filesystem, then the hint
of Michael goes to the right direction. El Torito specifies emulations
which lets the boot image file appear to the BIOS as floppy or hard disk.
The options -no-emul-boot -boot-load-size 4 causes BIOS to load the
first 2048 bytes of file image.flp and to execute them as x86 program.
Obviously a floppy image is not suitable as plain program.
According to mkisofs traditions floppy emulation is the default with
option -b. So you would just have to remove the option -no-emul-boot
from your xorriso command line in order to get the El Torito boot image
as floppy. (-boot-load-size 4 is then obsolete, too.)
The floppy image must have either 2400, or 2880, or 5760 sectors of 512
bytes, or else it will be rejected by xorriso.
Images of other sizes may be emulated as hard disks where the first
(and only) partition entry in the MBR partition table tells the size of
the disk. xorriso -as mkisofs option -hard-disk-boot chooses this emulation.
The primary cause of all the triple faults in your question really come down to the fact that your kernel isn't being loaded properly into the memory at 0x0000:0x2000. When you transfer control to this location with a JMP you end up running what happens to be in the memory region and the CPU executes until it hits an instruction that causes a fault.
Bootable CDs are strange beasts that have a number of different modes, and there are many BIOSes that boot such CDs but they too may have their own quirks. When you use -no-emul-boot with XORRISO you are requesting the disk neither be treated as a floppy nor hard disk. You could remove -no-emul-boot -boot-load-size 4 that should generate an ISO that gets treated as a floppy. The problem with that is many real BIOSes, Emulators (BOCHs and QEMU) and Virtual machines do not support Int 13h/AH=42h extended disk reads when the CD is booted using floppy emulation. You may be forced to use regular disk read via Int 13h/AH=02h.
You should be able to use extended disk reads via Int 13h/AH=42h if you use -no-emul-boot -boot-load-size 4 but it will require some changes to your bootloader. When using -no-emul-boot -boot-load-size 4 CDROMs sector sizes are 2048 bytes, not 512. This will require a bit of modification to your bootloader and kernel. The -boot-load-size 4 writes information to the ISO that informs the BIOS to read 4 512-byte chunks from the beginning of the disk image inside the ISO. The 0xaa55 boot signature is no longer needed.
If you use -no-emul-boot there is one other snag that needs to be dealt with. On the CD-ROM LBA 0 isn't where the disk image gets placed in the final ISO. The question is, how can you get the LBA where the disk image is in the ISO? You can have XORRISO write this information into a special section of the bootloader you create, and you enable this feature with -boot-info-table.
Creating the special section at the beginning of the bootloader is relatively easy. In the El Torito Specification Supplement they mention this:
EL TORITO BOOT INFORMATION TABLE
...
The format of this table is as follows; all integers are in sec-
tion 7.3.1 ("little endian") format.
Offset Name Size Meaning
8 bi_pvd 4 bytes LBA of primary volume descriptor
12 bi_file 4 bytes LBA of boot file
16 bi_length 4 bytes Boot file length in bytes
20 bi_csum 4 bytes 32-bit checksum
24 bi_reserved 40 bytes Reserved
The 32-bit checksum is the sum of all the 32-bit words in the
boot file starting at byte offset 64. All linear block addresses
(LBAs) are given in CD sectors (normally 2048 bytes).
This is talking about the 56 bytes at offset 8 of the virtual disk we create holding our bootloader. If we modify the top of your bootloader code to look like this we effectively create a blank boot information table:
start:
jmp bootld_start
times 8-($-$$) db 0 ; Pad out first 8 bytes
; Boot info table
bi_pvd dd 0
bi_file dd 0
bi_kength dd 0
bi_csum dd 0
bi_reserved times 40 db 0 ; 40 bytes reserved
When using XORRISO with -boot-info-table this table will be filled in once the ISO is generated. bi_file is the important piece of information we will need since it is the LBA where our disk image is placed inside the ISO. We can use this to fill in the Disk Access Packet used by extended disk reads to read from the proper location of the ISO.
To make the DAP a little more readable and to account for 2048 byte sectors I've amended it to look like:
dap:
dap_size: db 0x10 ; Size of DAP
dap_zero db 0
; You can only read 11 2048 byte sectors into memory between 0x2000 and
; 0x7C00. Don't read anymore or we overwrite the bootloader we are
; executing from. (0x7c00-0x2000)/2048 = 11 (rounded down)
dap_numsec: dw 11 ; Number of sectors to read
dap_offset: dw KERNEL_OFFSET ; Offset
dap_segment: dw 0 ; Segment
dap_lba_low: dd 0
dap_lba_high:dd 0
One issue is that the LBA placed into the Boot Information table is from the start of the disk image (sector with our bootloader). We need to increment that LBA by 1 and place it into the DAP so we are using the LBA where our kernel starts. Using 32-bit instruction we can just read the 32-bit value from the Boot Information Table, add 1 and save it to the DAP. If using strictly 16-bit instructions add one to a 32-bit value is more complex. Since we are going into 386 protected mode we can assume instruction with 32-bit operands are supported in real mode. The code to update the DAP with the LBA of the kernel could look like:
mov ebx, [bi_file] ; Get LBA of our disk image in ISO
inc ebx ; Add sector to get LBA for start of kernel
mov [dap_lba_low], ebx ; Update DAP with LBA of kernel in the ISO
The only other issue is that the bootloader sector needs to be padded out to 2048 (the size of a CD-ROM sector) rather than 512 and we can remove the boot signature. Change:
times 510-($-$$) db 0
db 0x55
db 0xAA
To:
times 2048-($-$$) db 0
The modified bootloader code could look like:
[bits 16]
[org 0x7c00]
KERNEL_OFFSET equ 0x2000
start:
jmp bootld_start
times 8-($-$$) db 0 ; Pad out first 8 bytes
; Boot info table
bi_pvd dd 0
bi_file dd 0
bi_kength dd 0
bi_csum dd 0
bi_reserved times 40 db 0 ; 40 bytes reserved
bootld_start:
xor ax, ax ; Explicitly set ES = DS = 0
mov ds, ax
mov es, ax
mov bx, 0x8C00 ; Set SS:SP to 0x8C00:0x0000 . The stack will exist
; between 0x8C00:0x0000 and 0x8C00:0xFFFF
mov ss, bx
mov sp, ax
mov ebx, [bi_file] ; Get LBA of our disk image in ISO
inc ebx ; Add sector to get LBA for start of kernel
mov [dap_lba_low], ebx ; Update DAP with LBA of kernel in the ISO
mov [BOOT_DRIVE], dl
mov bx, boot_msg
call print_string
mov dl, [BOOT_DRIVE]
call disk_load
jmp pm_setup
jmp $
BOOT_DRIVE:
db 0
disk_load:
mov si, dap
mov ah, 0x42
int 0x13
;cmp al, 4
;jne disk_error_132
ret
dap:
dap_size: db 0x10 ; Size of DAP
dap_zero db 0
; You can only read 11 2048 byte sectors into memory between 0x2000 and
; 0x7C00. Don't read anymore or we overwrite the bootloader we are
; executing from. (0x7c00-0x2000)/2048 = 11 (rounded down)
dap_numsec: dw 11 ; Number of sectors to read
dap_offset: dw KERNEL_OFFSET ; Offset
dap_segment: dw 0 ; Segment
dap_lba_low: dd 0
dap_lba_high:dd 0
disk_error_132:
mov bx, disk_error_132_msg
call print_string
jmp $
disk_error_132_msg:
db 'Error! Error! Something is VERY wrong! (0x132)', 0
gdt_start:
gdt_null:
dd 0x0
dd 0x0
gdt_code:
dw 0xffff
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
boot_msg:
db 'OS is booting files... ', 0
done_msg:
db 'Done! ', 0
%include "boot/print_string.asm"
pm_setup:
mov bx, done_msg
call print_string
mov ax, 0
mov ss, ax
mov sp, 0xFFFC
mov ax, 0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
cli
lgdt[gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:b32
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
print32:
pusha
mov edx, VIDEO_MEMORY
.loop:
mov al, [ebx]
mov ah, WHITE_ON_BLACK
cmp al, 0
je .done
mov [edx], ax
add ebx, 1
add edx, 2
jmp .loop
.done:
popa
ret
b32:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Place stack below EBDA in lower memory
mov ebp, 0x9c000
mov esp, ebp
mov ebx, pmode_msg
call print32
call KERNEL_OFFSET
jmp $
pmode_msg:
db 'Protected mode enabled!', 0
kernel:
mov ebx, pmode_msg
call print32
jmp $
pmode_tst:
db 'Testing...'
times 2048-($-$$) db 0
You can then modify your original XORRISO command to be:
xorriso -as mkisofs -R -J -c boot/bootcat \
-b boot/boot -no-emul-boot -boot-load-size 4 \
-boot-info-table -o image.iso iso
Related
NASM ASSEMBLY - Print "Hello World"
I've created a string and turned it into an array. Looping through each index and moving to the al register so it can print out to the vga. The problem is, it prints the size of the string with no problem, but the characters in gibberish. Can you please help me figure out what the problem is in the code. It will be highly appreciated. org 0 bits 16 section .text global _start _start: mov si, msg loop: inc si mov ah, 0x0e mov al, [si] or al, al jz end mov bh, 0x00 int 0x10 jmp loop end: jmp .done .done: jmp $ msg db 'Hello, world!',0xa len equ $ - msg TIMES 510 - ($ - $$) db 0 DW 0xAA55 bootloader code ORG 0x7c00 BITS 16 boot: mov ah, 0x02 mov al, 0x01 mov ch, 0x00 mov cl, 0x02 mov dh, 0x00 mov dl, 0x00 mov bx, 0x1000 mov es, bx int 0x13 jmp 0x1000:0x00 times 510 - ($ - $$) db 0 dw 0xAA55
The bootloader Before tackling the kernel code, let's look at the bootloader that brings the kernel in memory. You have written a very minimalistic version of a bootloader, one that omits much of the usual stuff like setting up segment registers, but thanks to its reduced nature that's not really a problem. What could be a problem is that you wrote mov dl, 0x00, hardcoding a zero to select the first floppy as your bootdisk. No problem if this is indeed the case, but it would be much better to just use whatever value the BIOS preloaded the DL register with. That's the ID for the disk that holds your bootloader and kernel. What is a problem is that you load the kernel to the segmented address 0x1000:0x1000 and then later jump to the segmented address 0x1000:0x0000 which is 4096 bytes short of the kernel. You got lucky that the kernel code did run in the end, thanks to the memory between these two addresses most probably being filled with zero-bytes that (two by two) translate into the instruction add [bx+si], al. Because you omitted setting up the DS segment register, we don't know what unlucky byte got overwritten so many times. Let's hope it was not an important byte... mov bx, 0x1000 mov es, bx xor bx, bx <== You forgot to write this instruction! int 0x13 jmp 0x1000:0x0000 What is a problem is that you ignore the possibility of encountering troubles when loading a sector from the disk. At the very least you should inspect the carry flag that the BIOS.ReadSector function 02h reports and if the flag is set you could abort cleanly. A more sophisticated approach would also retry a limited number of times, say 3 times. ORG 0x7C00 BITS 16 ; IN (dl) mov dh, 0x00 ; DL is bootdrive mov cx, 0x0002 mov bx, 0x1000 mov es, bx xor bx, bx mov ax, 0x0201 ; BIOS.ReadSector int 0x13 ; -> AH CF jc ERR jmp 0x1000:0x0000 ERR: cli hlt jmp ERR times 510 - ($ - $$) db 0 dw 0xAA55 The kernel After the jmp 0x1000:0x0000 instruction has brought you to the first instruction of your kernel, the CS code segment register holds the value 0x1000. None of the other segment registers did change, and since you did not setup any of them in the bootloader, we still don't know what any of them contain. However in order to retrieve the bytes from the message at msg with the mov al, [si] instruction, we need a correct value for the DS data segment register. In accordance with the ORG 0 directive, the correct value is the one we already have in CS. Just two 1-byte instructions are needed: push cs pop ds. There's more to be said about the kernel code: The printing loop uses a pre-increment on the pointer in the SI register. Because of this the first character of the string will not get displayed. You could compensate for this via mov si, msg - 1. The printing loop processes a zero-terminating string. You don't need to prepare that len equate. What you do need is an explicit zero byte that terminates the string. You should not rely on that large number of zero bytes thattimes produced. In some future version of the code there might be no zero byte at all! You (think you) have included a newline (0xa) in the string. For the BIOS.Teletype function 0Eh, this is merely a linefeed that moves down on the screen. To obtain a newline, you need to include both carriage return (13) and linefeed (10). There's no reason for your kernel code to have the bootsector signature bytes at offset 510. Depending on how you get this code to the disk, it might be necessary to pad the code up to (a multiple of) 512, so keep times 512 - ($ - $$) db 0. The kernel: ORG 0 BITS 16 section .text global _start _start: push cs pop ds mov si, msg mov bx, 0x0007 ; DisplayPage=0, GraphicsColor=7 (White) jmp BeginLoop PrintLoop: mov ah, 0x0E ; BIOS.Teletype int 0x10 BeginLoop: mov al, [si] inc si test al, al jnz PrintLoop cli hlt jmp $-2 msg db 'Hello, world!', 13, 10, 0 TIMES 512 - ($ - $$) db 0
Error while creating a bootable floppy that contains a bootloader and a kernel
I'm trying to create a bootable floppy drive for my boot.bin and kernel.bin files. My boot.asm code is: bits 16 section .text start: JMP MAIN WAIT_FOR_KEY: MOV AH, 00H INT 16H RET CLEAR: MOV AH, 0H ;CHANGING THE VIDEO MODE TO CLEAR THE SCREEN MOV AL, 03H ;VIDEO MODE COD INT 10H RET LOG_TO_HTS: PUSH BX PUSH AX MOV BX, AX MOV DX, 0 DIV WORD[ALL_SECTORS] ADD DL, 01H MOV CL, DL MOV AX, BX MOV DX, 0 DIV WORD [ALL_SECTORS] MOV DX, 0 DIV WORD[FACES] MOV DH, DL MOV CH, AL POP AX POP BX MOV DL, BYTE [BOOT_DEVICE] RET ECHO: ;-=-=-=PRINTING FUNCTION =-=-=-; LODSB ;MOV ONE CHAR FROM SI TO AL AND DELETE IT FROM SI CMP AL, 0 ;CHECK IF THE VALUE IN AL=0, IF ITS ZERO THEN WE JE DONE ;WE ARE DONE PRINTING, AND JUMP BACK TO THE MAIN FUNCTION CMP AL, 59 JE NEWLINE MOV AH, 0EH ;THE FUNCTION CODE FOR PRINTING (TELETYPE PRINTING) INT 10H ;BIOS CALL JMP ECHO ;IF WE ARRIVED TO THIS LINE THATS MEAN WE ARE NOT DONE WITH ;PRINTING THE WHOLE STREING SO JUMP BACK AND COMPLETE THE PROCESS DONE: ;LABEL CONTAINS ONE INSTRUCTION TO JUMP BACK TO THE LINE RET ;WHERE WE CALLED THE ECHO FUNCTION NEWLINE: PUSHA MOV AH, 0EH MOV AL, 13 INT 10H MOV AL, 10 INT 10H POPA RET RESET_DRIVE: ;RESET FLOPPY DRIVE FUNCTION MOV AX, 0 ;THE FUNCTION CODE TO RESET DRIVE MOV DL, BYTE [BOOT_DEVICE] ;DRIVE ID TO RESET INT 13H RET MAIN: ;THE MAIN FUNCTION LABEL ;TO BEGIN LOADING EXTERNAL FILE LIKE KERNEL SOME THINGS MUST BE DONE LIKE : ;1- SETTING UP THE STACK ;2- SETTING UP THE SEGMENTS ;3- SPECIFY THE BOOT DRIVE ;SETTING UP THE STACK CLI ;CLEAR INTERRUPTS TO SET THE SEGMENT XOR AX, AX ;SET THE BOTTOM OF THE STACK MOV SS, AX MOV SP, 0XFFFF ;SET THE TOP OF THE STACK STI ;RESTORE THE INTERRUPTS ;SETTING UP THE SEGMENTS MOV AX, 07C0H MOV DS, AX MOV ES, AX ;AFTER SETTING UP SEGMENTS AND STACK, YOU ARE FREE TO CODE WHAT EVER YOU WANT ;THE CPU WILL RECOGNISE YOUR CODE AS A BOOTLOADER CALL CLEAR ;MOV SI, WELCOME_MSG ;CALL ECHO MOV [BOOT_DEVICE], DL ;SAVE THE DRIVE ID TO USE IT LATER ;WE WILL USE IN 13H TO LOAD ROOT DIR. THAT WE NEED TO LOAD THE FIRST SECTOR OF THE KERNEL ;THEN WE WILL LOAD FAT TO LOAD THE WHOLE KERNEL SINCE THE FILE LOAD PROCESS CONSISTS OF 3 STEPS ;1- LOAD THE FISRT SECTOR OF THE FILE ;2- LOAD THE WHOLE FILE AND COPY IT INTO RAM ;3- EXCUTE THE FILE ;THE ROOT DIR. AND FAT ARE LOCATED IN SOMEWHERE ON THE FLOPPY DRIVE AS FOLLOWS ;1- SETTING UP AND LOADING THE ROOT DIR. MOV AH, 02H ;THE FUNCTION CODE FOR LOADING ROOT DIR. MOV AL, 14 ;THE SIZE OF THE ROOT DIR. THE ROOT DIR. = 14 AND WE WANT TO LOAD IT ALL SO AL=14 MOV BX, TEMP ;THE TEMP STORAGE FOR THE DATA WILL BE READED OR LOADED MOV CH, 0 ;TRACK WE WANT TO LOAD, ITS TRACK 0 BEACUSE THE ROOT DIR. LOCATED THERE (CYLINDER) MOV CL, 2 ;SECTOR WE WANT TO LOAD, ITS SECTOR 2 BEACUSE THE ROOT DIR. LOCATED THERE MOV DH, 1 ;HEAD WE WANT TO LOAD, ITS HEAD 1 BEACUSE THE ROOT DIR. LOCATED THERE PUSHA ;TO BE ABLE TO RETRY TO LOAD ROOT DIR. IF INT 13H FAILED LOAD_RD: INT 13H JNC LOAD_RD_DONE ;IF WE ARRIVE HERE, THATS MEAN THAT THE ROOT DIR. LOADED SUCCESSFULLY CALL RESET_DRIVE ;RESET FLOPPY FUNCTION CALL JMP LOAD_RD ;RETRY IF INT 13H FAILED LOAD_RD_DONE: POPA ;NOW WE WILL SEARCH IN THE ROOT DIR. TABLE IF IT CONTAINS THE DESIRED FILE NAME WHICH IS KERNEL.BIN ;WE WILL USE CMPSB INSTRUCTION THAT COMPARES THE VALUE OF DS:SI AND ES:DI ;ES AND DS ARE ALREADY SET ;THE SEARCH WILL BE LIMITED TO SEARCH AMONG 11 BYTES BECAUSE THE FILE NAME IS 11 BYTES MOV DI, TEMP ;THE RESULT WE GOT (THE ENTRY) MOV CX, 224 ;THE MAX. POSSIBLE FILE NUMBER THAT WE COULD HAVE IS 224 SO WE LIMIT THE SEARCH TO IT (THE VALUE THAT WILL BE DECREASED WHILE LOOPING) FIND_KERNEL: PUSH CX ;PUSH CX AND DI BECAUSE THEY HELD IMPORTANT DATA THAT WE DONT WANT TO LOSE POP DX MOV SI, FILE_NAME ;THE VALUE THAT WE WILL COMPARE THE RESULT OF ROOT DIR. TO FIND MOV CX, 11 ;TO REPEATE THE SEARCH PROCESS 11 TIMES(THE FILE NAME LENGTH) REP CMPSB ;COPMARES SI WITH DI JE FOUND_KERNEL ;IF WO GO TO THE NEXT LINE, THAT MEANS THAT THE KERNEL IS NOT FOUNDED YET ;AND SINCE DI IS POINTS TO THE FIRST ENTRY, WE NEED TO MOVE TO THE NEXT ONE BY ADDING 32 ADD AX, 32 MOV DI, TEMP ADD DI, AX PUSH DX POP CX LOOP FIND_KERNEL ;IF WE ARE HERE, THEN THE KERNEL IS NOT EXISTS ;MOV SI, FAILED_TO_LOAD_KERNEL ;CALL ECHO CLI INT 18H ;CRASH AND HALT THE PROCESSOR FOUND_KERNEL: ;IF WE FOUND THE KERNEL WE WILL BE HERE ;NOW WE HAVE THE ENTRY POINT FOR THE KERNEL SAVED IN DL REGISTER ;WE GOT THE KERNEL FROM THE FIRST 11 BYTES SO WE NEED TO ADD 15 TO GET TO THE 26 BYTES ;THE FIRST SECTOR IS LOCATED AT 26 AND 27 SO WE MUST ADD 15 TO LOAD THE KERNEL IN THE FIRST SECTOR MOV AX, WORD [DI+15] ;WORD ADDED TO COPY BOTH 26 AND 27 BYTES TO AX, THE WORD IS 2 BYTES MOV [ENTERY_POINT], AX ;2- SETTING UP AND LOADING THE FAT MOV AX, 1 MOV BX, TEMP ;THE TEMP STORAGE FOR THE DATA WILL BE READED OR LOADED CALL LOG_TO_HTS MOV AH, 2 ;THE FUNCTION CODE FOR LOADING ROOT DIR. MOV AL, 9 ;THE SIZE OF THE ROOT DIR. THE ROOT DIR. = 14 AND WE WANT TO LOAD IT ALL SO AL=14 PUSHA ;TO BE ABLE TO RETRY TO LOAD ROOT DIR. IF INT 13H FAILED LOAD_FAT: INT 13H JNC LOAD_FAT_DONE ;IF WE ARRIVE HERE, THATS MEAN THAT THE FAT LOADED SUCCESSFULLY CALL RESET_DRIVE ;RESET FLOPPY FUNCTION CALL JMP LOAD_FAT ;RETRY IF INT 13H FAILED LOAD_FAT_DONE: ;IF LOADING FAT DONE SUCCESSFULLY, WE WILL BE HERE MOV AH, 2 MOV AL, 1 PUSH AX LOAD_SECTOR: ;ROOT DIR. GIVES US A DATA SECTOR AND WE WANT A LOGICAL SECTOR, WE WILL DO IT HERE MOV AX, WORD [ENTERY_POINT] ADD AX, 31 ;31 ADDED TO DONE THE CONVERTION CALL LOG_TO_HTS ;COVERTS THE LOGICAL SECTORS INTO HEAD TRACK SECTORS MOV AX, 2000H MOV ES, AX MOV BX, WORD[OFFSET_] POP AX PUSH AX INT 13H JNC GET_NEXT CALL RESET_DRIVE JMP LOAD_SECTOR GET_NEXT: MOV AX, [ENTERY_POINT] MOV DX, 0 MOV BX, 6 MUL BX MOV BX, 4 DIV BX MOV SI, TEMP ADD SI, AX MOV AX, WORD[SI] OR DX, DX JZ EVEN ODD: SHR AX, 4 JMP SHORT COMP_SECTOR EVEN: AND AX, 0FFFH COMP_SECTOR: MOV WORD [ENTERY_POINT], AX CMP AX, 0FF8H JAE END ADD WORD[OFFSET_], 512 JMP LOAD_SECTOR END: ;MOV SI, KERNEL_LOADED_MSG CALL ECHO CALL WAIT_FOR_KEY POP AX MOV DL, BYTE[BOOT_DEVICE] JMP 2000H:0000H OFFSET_ DW 0 ALL_SECTORS DW 18 FACES DW 2 ENTERY_POINT DW 0 ;FAILED_TO_LOAD_KERNEL DB "Error, Cannot Load The Kernel. Booting Process Aborted;",0 BOOT_DEVICE DB 0 FILE_NAME DB "KERNEL BIN" ;WELCOME_MSG DB "Litesoft bootloader Copyright (C) 2012-2016 By Mohamed El Sayed;",0 ;KERNEL_LOADED_MSG DB "Kernel Loaded, Press Any Key To Continue...",0 TIMES 510 - ($-$$) DB 0 ;LOOK FOR EVERY SINGLE EMPTY BIT AND FILL IT WITH ZERO ;TILL THE BOOTLOADER SIZE BE 512 BYTE DW 0xAA55 ;THE BOOT SIGNETUARE, ALWAYS THE SAME TEMP: ;HERE IN BYTE 513 WE HAVE SOME MEMORY THAT WILL NOT BE EXECUTED ;AND WE CAN USE IT AS A TEMP MEMORY The method i planed to use is creating a floppy image using dd and write my bootloader to the first sector then mount it and copy my kernel to it. The commands i used 1- mkdosfs -C floppy.flp 1440 , This command creates a floppy image 2- dd status=noxfer conv=notrunc if=boot.bin of=floppy.flp ,This command burns the bootloader to the first sector Those commands working very will and the floppy image with my bootloader at the first sector created successfully The problem comes when i try to mount the floppy image to copy the kernel to it using the following commands rm -rf tmp-loop mkdir tmp-loop && mount -o loop -t vfat floppy.flp tmp-loop && cp kernel.bin tmp-loop/ Every time i try to mount the floppy image i get this error mount: wrong fs type, bad option, bad superblock on /dev/loop0, missing codepage or helper program, or other error In some cases useful info is found in syslog - try dmesg | tail or so. What is the solution for this error? I'm using Ubuntu 16.04.
You lack a proper BIOS Parameter Block(BPB) at the beginning of your bootloader. This structure contains information used/updated by some BIOSes; can be used by the bootloader to read a FAT file system on unpartitioned media like a floppy; must be present for software like mount to determine what type of media a virtual floppy image represents. In the case of FAT12 on unpartitioned media (like a floppy) file system information is present in the Master Boot Record's BPB. A common layout is the DOS 3.4 EBPB and it could look something like: start: JMP MAIN TIMES 3-($-$$) DB 0x90 ; Support 2 or 3 byte encoded JMPs before BPB. ; Dos 3.4 EBPB 1.44MB floppy OEMname: db "mkfs.fat" ; mkfs.fat is what OEMname mkdosfs uses bytesPerSector: dw 512 sectPerCluster: db 1 reservedSectors: dw 1 numFAT: db 2 numRootDirEntries: dw 224 numSectors: dw 2880 mediaType: db 0xf0 numFATsectors: dw 9 sectorsPerTrack: dw 18 numHeads: dw 2 numHiddenSectors: dd 0 numSectorsHuge: dd 0 driveNum: db 0 reserved: db 0 signature: db 0x29 volumeID: dd 0x2d7e5a1a volumeLabel: db "NO NAME " fileSysType: db "FAT12 " Based on the DOS 3.4 EBPB above and your boot.asm code, this BPB represents one similar to a 1.44MB floppy disk boot sector produced with mkdosfs -C floppy.flp 1440: bits 16 section .text start: JMP MAIN TIMES 3-($-$$) DB 0x90 ; Support 2 or 3 byte encoded JMPs before BPB. ; Dos 3.4 EBPB 1.44MB floppy OEMname: db "mkfs.fat" ; mkfs.fat is what OEMname mkdosfs uses bytesPerSector: dw 512 sectPerCluster: db 1 reservedSectors: dw 1 numFAT: db 2 numRootDirEntries: dw 224 numSectors: dw 2880 mediaType: db 0xf0 numFATsectors: dw 9 sectorsPerTrack: dw 18 numHeads: dw 2 numHiddenSectors: dd 0 numSectorsHuge: dd 0 driveNum: db 0 reserved: db 0 signature: db 0x29 volumeID: dd 0x2d7e5a1a volumeLabel: db "NO NAME " fileSysType: db "FAT12 " WAIT_FOR_KEY: MOV AH, 00H INT 16H RET CLEAR: MOV AH, 0H ;CHANGING THE VIDEO MODE TO CLEAR THE SCREEN MOV AL, 03H ;VIDEO MODE COD INT 10H RET LOG_TO_HTS: PUSH BX PUSH AX MOV BX, AX MOV DX, 0 DIV WORD[ALL_SECTORS] ADD DL, 01H MOV CL, DL MOV AX, BX MOV DX, 0 DIV WORD [ALL_SECTORS] MOV DX, 0 DIV WORD[FACES] MOV DH, DL MOV CH, AL POP AX POP BX MOV DL, BYTE [BOOT_DEVICE] RET ECHO: ;-=-=-=PRINTING FUNCTION =-=-=-; LODSB ;MOV ONE CHAR FROM SI TO AL AND DELETE IT FROM SI CMP AL, 0 ;CHECK IF THE VALUE IN AL=0, IF ITS ZERO THEN WE JE DONE ;WE ARE DONE PRINTING, AND JUMP BACK TO THE MAIN FUNCTION CMP AL, 59 JE NEWLINE MOV AH, 0EH ;THE FUNCTION CODE FOR PRINTING (TELETYPE PRINTING) INT 10H ;BIOS CALL JMP ECHO ;IF WE ARRIVED TO THIS LINE THATS MEAN WE ARE NOT DONE WITH ;PRINTING THE WHOLE STREING SO JUMP BACK AND COMPLETE THE PROCESS DONE: ;LABEL CONTAINS ONE INSTRUCTION TO JUMP BACK TO THE LINE RET ;WHERE WE CALLED THE ECHO FUNCTION NEWLINE: PUSHA MOV AH, 0EH MOV AL, 13 INT 10H MOV AL, 10 INT 10H POPA RET RESET_DRIVE: ;RESET FLOPPY DRIVE FUNCTION MOV AX, 0 ;THE FUNCTION CODE TO RESET DRIVE MOV DL, BYTE [BOOT_DEVICE] ;DRIVE ID TO RESET INT 13H RET MAIN: ;THE MAIN FUNCTION LABEL ;TO BEGIN LOADING EXTERNAL FILE LIKE KERNEL SOME THINGS MUST BE DONE LIKE : ;1- SETTING UP THE STACK ;2- SETTING UP THE SEGMENTS ;3- SPECIFY THE BOOT DRIVE ;SETTING UP THE STACK CLI ;CLEAR INTERRUPTS TO SET THE SEGMENT XOR AX, AX ;SET THE BOTTOM OF THE STACK MOV SS, AX MOV SP, 0XFFFF ;SET THE TOP OF THE STACK STI ;RESTORE THE INTERRUPTS ;SETTING UP THE SEGMENTS MOV AX, 07C0H MOV DS, AX MOV ES, AX ;AFTER SETTING UP SEGMENTS AND STACK, YOU ARE FREE TO CODE WHAT EVER YOU WANT ;THE CPU WILL RECOGNISE YOUR CODE AS A BOOTLOADER CALL CLEAR ;MOV SI, WELCOME_MSG ;CALL ECHO MOV [BOOT_DEVICE], DL ;SAVE THE DRIVE ID TO USE IT LATER ;WE WILL USE IN 13H TO LOAD ROOT DIR. THAT WE NEED TO LOAD THE FIRST SECTOR OF THE KERNEL ;THEN WE WILL LOAD FAT TO LOAD THE WHOLE KERNEL SINCE THE FILE LOAD PROCESS CONSISTS OF 3 STEPS ;1- LOAD THE FISRT SECTOR OF THE FILE ;2- LOAD THE WHOLE FILE AND COPY IT INTO RAM ;3- EXCUTE THE FILE ;THE ROOT DIR. AND FAT ARE LOCATED IN SOMEWHERE ON THE FLOPPY DRIVE AS FOLLOWS ;1- SETTING UP AND LOADING THE ROOT DIR. MOV AH, 02H ;THE FUNCTION CODE FOR LOADING ROOT DIR. MOV AL, 14 ;THE SIZE OF THE ROOT DIR. THE ROOT DIR. = 14 AND WE WANT TO LOAD IT ALL SO AL=14 MOV BX, TEMP ;THE TEMP STORAGE FOR THE DATA WILL BE READED OR LOADED MOV CH, 0 ;TRACK WE WANT TO LOAD, ITS TRACK 0 BEACUSE THE ROOT DIR. LOCATED THERE (CYLINDER) MOV CL, 2 ;SECTOR WE WANT TO LOAD, ITS SECTOR 2 BEACUSE THE ROOT DIR. LOCATED THERE MOV DH, 1 ;HEAD WE WANT TO LOAD, ITS HEAD 1 BEACUSE THE ROOT DIR. LOCATED THERE PUSHA ;TO BE ABLE TO RETRY TO LOAD ROOT DIR. IF INT 13H FAILED LOAD_RD: INT 13H JNC LOAD_RD_DONE ;IF WE ARRIVE HERE, THATS MEAN THAT THE ROOT DIR. LOADED SUCCESSFULLY CALL RESET_DRIVE ;RESET FLOPPY FUNCTION CALL JMP LOAD_RD ;RETRY IF INT 13H FAILED LOAD_RD_DONE: POPA ;NOW WE WILL SEARCH IN THE ROOT DIR. TABLE IF IT CONTAINS THE DESIRED FILE NAME WHICH IS KERNEL.BIN ;WE WILL USE CMPSB INSTRUCTION THAT COMPARES THE VALUE OF DS:SI AND ES:DI ;ES AND DS ARE ALREADY SET ;THE SEARCH WILL BE LIMITED TO SEARCH AMONG 11 BYTES BECAUSE THE FILE NAME IS 11 BYTES MOV DI, TEMP ;THE RESULT WE GOT (THE ENTRY) MOV CX, 224 ;THE MAX. POSSIBLE FILE NUMBER THAT WE COULD HAVE IS 224 SO WE LIMIT THE SEARCH TO IT (THE VALUE THAT WILL BE DECREASED WHILE LOOPING) FIND_KERNEL: PUSH CX ;PUSH CX AND DI BECAUSE THEY HELD IMPORTANT DATA THAT WE DONT WANT TO LOSE POP DX MOV SI, FILE_NAME ;THE VALUE THAT WE WILL COMPARE THE RESULT OF ROOT DIR. TO FIND MOV CX, 11 ;TO REPEATE THE SEARCH PROCESS 11 TIMES(THE FILE NAME LENGTH) REP CMPSB ;COPMARES SI WITH DI JE FOUND_KERNEL ;IF WO GO TO THE NEXT LINE, THAT MEANS THAT THE KERNEL IS NOT FOUNDED YET ;AND SINCE DI IS POINTS TO THE FIRST ENTRY, WE NEED TO MOVE TO THE NEXT ONE BY ADDING 32 ADD AX, 32 MOV DI, TEMP ADD DI, AX PUSH DX POP CX LOOP FIND_KERNEL ;IF WE ARE HERE, THEN THE KERNEL IS NOT EXISTS ;MOV SI, FAILED_TO_LOAD_KERNEL ;CALL ECHO CLI INT 18H ;CRASH AND HALT THE PROCESSOR FOUND_KERNEL: ;IF WE FOUND THE KERNEL WE WILL BE HERE ;NOW WE HAVE THE ENTRY POINT FOR THE KERNEL SAVED IN DL REGISTER ;WE GOT THE KERNEL FROM THE FIRST 11 BYTES SO WE NEED TO ADD 15 TO GET TO THE 26 BYTES ;THE FIRST SECTOR IS LOCATED AT 26 AND 27 SO WE MUST ADD 15 TO LOAD THE KERNEL IN THE FIRST SECTOR MOV AX, WORD [DI+15] ;WORD ADDED TO COPY BOTH 26 AND 27 BYTES TO AX, THE WORD IS 2 BYTES MOV [ENTERY_POINT], AX ;2- SETTING UP AND LOADING THE FAT MOV AX, 1 MOV BX, TEMP ;THE TEMP STORAGE FOR THE DATA WILL BE READED OR LOADED CALL LOG_TO_HTS MOV AH, 2 ;THE FUNCTION CODE FOR LOADING ROOT DIR. MOV AL, 9 ;THE SIZE OF THE ROOT DIR. THE ROOT DIR. = 14 AND WE WANT TO LOAD IT ALL SO AL=14 PUSHA ;TO BE ABLE TO RETRY TO LOAD ROOT DIR. IF INT 13H FAILED LOAD_FAT: INT 13H JNC LOAD_FAT_DONE ;IF WE ARRIVE HERE, THATS MEAN THAT THE FAT LOADED SUCCESSFULLY CALL RESET_DRIVE ;RESET FLOPPY FUNCTION CALL JMP LOAD_FAT ;RETRY IF INT 13H FAILED LOAD_FAT_DONE: ;IF LOADING FAT DONE SUCCESSFULLY, WE WILL BE HERE MOV AH, 2 MOV AL, 1 PUSH AX LOAD_SECTOR: ;ROOT DIR. GIVES US A DATA SECTOR AND WE WANT A LOGICAL SECTOR, WE WILL DO IT HERE MOV AX, WORD [ENTERY_POINT] ADD AX, 31 ;31 ADDED TO DONE THE CONVERTION CALL LOG_TO_HTS ;COVERTS THE LOGICAL SECTORS INTO HEAD TRACK SECTORS MOV AX, 2000H MOV ES, AX MOV BX, WORD[OFFSET_] POP AX PUSH AX INT 13H JNC GET_NEXT CALL RESET_DRIVE JMP LOAD_SECTOR GET_NEXT: MOV AX, [ENTERY_POINT] MOV DX, 0 MOV BX, 6 MUL BX MOV BX, 4 DIV BX MOV SI, TEMP ADD SI, AX MOV AX, WORD[SI] OR DX, DX JZ EVEN ODD: SHR AX, 4 JMP SHORT COMP_SECTOR EVEN: AND AX, 0FFFH COMP_SECTOR: MOV WORD [ENTERY_POINT], AX CMP AX, 0FF8H JAE END ADD WORD[OFFSET_], 512 JMP LOAD_SECTOR END: ;MOV SI, KERNEL_LOADED_MSG CALL ECHO CALL WAIT_FOR_KEY POP AX MOV DL, BYTE[BOOT_DEVICE] JMP 2000H:0000H OFFSET_ DW 0 ALL_SECTORS DW 18 FACES DW 2 ENTERY_POINT DW 0 ;FAILED_TO_LOAD_KERNEL DB "Error, Cannot Load The Kernel. Booting Process Aborted;",0 BOOT_DEVICE DB 0 FILE_NAME DB "KERNEL BIN" ;WELCOME_MSG DB "Litesoft bootloader Copyright (C) 2012-2016 By Mohamed El Sayed;",0 ;KERNEL_LOADED_MSG DB "Kernel Loaded, Press Any Key To Continue...",0 TIMES 510 - ($-$$) DB 0 ;LOOK FOR EVERY SINGLE EMPTY BIT AND FILL IT WITH ZERO ;TILL THE BOOTLOADER SIZE BE 512 BYTE DW 0xAA55 ;THE BOOT SIGNETUARE, ALWAYS THE SAME TEMP: ;HERE IN BYTE 513 WE HAVE SOME MEMORY THAT WILL NOT BE EXECUTED ;AND WE CAN USE IT AS A TEMP MEMORY If you generate boot.bin from this code and place it in a floppy image and use the command to display file type information: file floppy.flp It should produce something like this if it worked: floppy.flp: , code offset 0x99+3, OEM-ID "mkfs.fat", root entries 224, sectors 2880 (volumes <=32 MB) , sectors/FAT 9, sectors/track 18, serial number 0x2d7e5a1a, unlabeled, FAT (12 bit), followed by FAT If you get similar output it should be mountable with the mount command. As you may have noticed the data within an EBPB/BPB can be used to navigate over a FAT12 file system.
How to use ORG addresses > 0xFFFF?
I am trying to write a simply bootloader in assembler. The bootloader copies sector 2 from a floppy to address 0x5000 (segment 0x500, offset 0x0), jumps to the segment and prints a message. However, when I change the segment address to 0x1000, the message does not get printed anymore. I suspect the org 0x10000 instruction has a problem, which might be related to segmentation. I tried org 0x1000:0 too, but the message won't be printed. Here is my bootloader code, which gets written to the first sector of the floppy: [BITS 16] org 0x7C00 start: mov ah, 0x02 ; Read sectors from drive mov al, 1 ; Read 1 sector mov ch, 0 ; Cylinder 0 mov cl, 2 ; Sector 2 mov dh, 0 ; Head 0 mov bx, sect2dest; mov es, bx mov bx, 0x0 int 0x13 jmp sect2dest:0; data: sect2dest equ 0x500 The magic identifier in the end is written by a custom linking script, so don't worry about that. Here is my sector two, which should print a message: [BITS 16] org 0x5000 sect2: mov ah, 0x13 mov al, 1 mov bl, 0x17 mov cx, msg_len mov dh, 0 mov dl, 0 mov bh, 0 mov bp, 0 mov es, bp mov bp, msg int 0x10 jmp $ msg db 13,10,"Hello, World!" msg_len equ $ - msg As mentioned above, when I try writing sector 2 to any address larger than 0xFFFF, the message doesn't get printed.
Consider that bp is 16 bit, so if you use an ORG of 10000h any offset won't fit in it. I was expecting the assembler to raise a warning but a quick test shown otherwise. Remember also that generally is best to avoid challenging the BIOS, thought I don't know how it is actually handled, I would avoid to print a string that strides two segments. Since you are putting zero in es, make sure that the ORG is at most 10000h-[msg_len], so that the whole string is reachable within es.
Raising BRK in assembly on i386 Linux
I found and studied x86 memory access segmentation fault and it won't work in my code. The difference perhaps being that I don't use separate .text and .data segments but keep all in a single segment by creating a custom ELF header. Does that explain why the SYS_BRK call fails? The program then continues by making the memory pages read/write/execute etc. I tried to find the minimum code sample that illustrated the issue. In kdbg the sample does work, but not when started from the command line, hence the message printing. cpu 386 bits 32 ; System calls used %assign SYS_EXIT 1 %assign SYS_WRITE 4 %assign SYS_BRK 45 %assign SYS_MPROTECT 125 ; flags for SYS_MPROTECT %assign PROT_READ 1 %assign PROT_WRITE 2 %assign PROT_EXEC 4 %assign STDOUT 1 memstart: org 0x08048000 ehdr: ; Elf32_Ehdr (see https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) db 0x7F, "ELF" ; e_ident[EI_MAG0..EI_MAG03] db 1 ; e_ident[EI_CLASS] db 1 ; e_ident[EI_DATA] db 1 ; e_ident[EI_VERSION] db 0 ; e_ident[EI_OSABI] db 0 ; e_ident[EI_ABIVERSION] times 7 db 0 ; e_ident[EI_PAD] dw 2 ; e_type dw 3 ; e_machine dd 1 ; e_version dd start ; e_entry dd phdr - $$ ; e_phoff dd 0 ; e_shoff dd 0 ; e_flags dw ehdrsize ; e_ehsize dw phdrsize ; e_phentsize dw 1 ; e_phnum dw 0 ; e_shentsize dw 0 ; e_shnum dw 0 ; e_shstrndx ehdrsize equ $ - ehdr phdr: ; Elf32_Phdr dd 1 ; p_type dd 0 ; p_offset dd $$ ; p_vaddr dd $$ ; p_paddr dd filesize ; p_filesz dd filesize ; p_memsz dd 5 ; p_flags dd 0x1000 ; p_align phdrsize equ $ - phdr memsize: dd 16*4096 ; = 16 * 4K pages memtop: dd 0 start: ;int 3 xor ebx, ebx ; find the amount of allocated memory mov eax, SYS_BRK int 0x80 ; eax contains current memtop sub eax, memstart ; got enough memory? test eax, [memsize] ja memgood mov eax, memstart ; raise memory limit to memstart + memsize add eax, [memsize] mov ebx, eax mov ecx, eax ; save requested memory size in ecx mov eax, SYS_BRK int 0x80 cmp eax, ecx jne brk_error ; raising memory limit failed memgood: mov edx, (PROT_READ | PROT_WRITE | PROT_EXEC) mov ecx, [memsize] ; make memory read/write/execute mov ebx, memstart mov eax, SYS_MPROTECT int 0x80 test eax, eax js bailout jmp launch ; lets start the party brk_error: mov edx, brkelen mov ecx, brke mov ebx, STDOUT mov eax, SYS_WRITE int 0x80 jmp bailout brke: db 'SYS_BRK failed, bye', 10 brkelen equ $ - brke bailout: mov eax, SYS_EXIT xor ebx, ebx int 0x80 launch: mov edx, succlen mov ecx, succ mov ebx, STDOUT mov eax, SYS_WRITE int 0x80 jmp bailout succ: db 'Success with mem config, bye', 10 succlen equ $ - succ filesize equ $ - $$
You should use cmp here instead of test: sub eax, memstart ; got enough memory? test eax, [memsize] ja memgood The memory area described by SYS_BRK start a random offset of 0 to 0x02000000 after the executable unless address space layout randomisation is disabled, which I suspect your debugger does. You can use mmap to allocate memory at a specified address (don't set MAP_FIXED unless you want overwrite existing mappings) . However this whole exercise with brk and mprotect seems rather pointless as apart from the stack upon program start memory is allocated exactly as the ELF header specified, instead you can: phdr: ; Elf32_Phdr dd 1 ; p_type dd 0 ; p_offset dd $$ ; p_vaddr dd $$ ; p_paddr dd filesize ; p_filesz dd 16*4096 ; p_memsz dd 7 ; p_flags dd 0x1000 ; p_align phdrsize equ $ - phdr
the difference of machine code between mov eax, 0 and mov ax, 0
I use nasm to study assembly. Below is the source code: [BITS 32] mov ebx, 0 mov bx, 0 mov bl, 0 then I use 'ndisasm -b 32 test.bin' to get output as following: 00000000 BB00000000 mov ebx,0x0 00000005 66BB0000 mov bx,0x0 00000009 B300 mov bl,0x0 My question is the difference of BB00000000 and 66BB0000, I know the opcode of MOV is B, but what is the 66 before B?
0x66 is operand-size override prefix which means that if the default operand size is 32-bit (as your case is), it becomes 16-bit a the opcode works on 16-bit size registers (bx in your case)