The file isn't loaded correctly because you both add 32 to ES and 512 to BX. You should remove the instruction that adds the sector size to BX.
It also turns out that the KERNEL.EXE has sections with VirtualSize less than SizeOfRawData. I didn't account for this in my code, so my Sectionloop code should be changed to:
Code: Select all
sectionloop:
mov ebp,[esi+ebx]
mov edi,[esi+ebx+4]
add edi,IMAGE_PMODE_BASE
mov ecx,[esi+ebx+8]
cmp ecx,ebp
jb vsize_ok
mov ecx,ebp
vsize_ok:
sub ebp,ecx
push esi
add esi,[esi+ebx+12]
rep movsb
pop esi
mov ecx,ebp
mov al,0
rep stosb
add ebx,40
dec edx
jnz sectionloop
Here are some other issues I could find:
In the boot sector
DL is stored to two variables before loading DS, overwriting the keyboard IRQ vector instead of the variable it should store to. It should only store the value after loading DS.
There is no need to have a CLI before loading the segment registers. When loading SS, interrupts are automatically disabled during the next instruction.
There is no need to load FS and GS, since you don't use them.
There's an unused string: "OK" and an unused function which prints it.
The boot sector jumps to 0x28:0x280. If you change it to 0:0x500, you don't need a far jump in the beginning of kernel.sys.
In KERNEL.SYS
There's still an unnecessary mov ax,0 where AX is already 0.
Puts16 is inlined twice where you could just have called it instead.
The functions that display "16 bits", "32 bits" and "64 bits" are very repetitive and could have been implemented with a loop, like this:
Code: Select all
Display16Bits:
mov si,str_16
mov di,324
jmp DisplayBits
Display16Bits:
mov si,str_32
mov di,484
jmp DisplayBits
Display16Bits:
mov si,str_64
mov di,644
DisplayBits:
call DisplayColoredString
mov si,str_bits
DisplayColoredString:
push es
mov es,0xb800
dcs_loop:
lodsb
test al,al
jz dcs_end
stosb
mov al,bl
stosb
jmp dcs_loop
dsc_end:
pop es
ret
str_16 db "16",0
str_32 db "32",0
str_64 db "64",0
str_bits db " bits",0
When pressing the Up key, there are unnecessary instructions when moving the maximum choice into the current choice.
After pressing Enter, after the second int 0x10, there are also instructions which don't do anything useful. The first value popped is always 0, since it's set by the push ax at the start, where AX is 0. Then, the current choice is loaded into both AL and AH and checked twice. The 0 that was popped is pushed again, and then popped and not used.
The MEMEM function stores the return address in a byte variable. It should be a dword.
After calling LoadFile, the number of clusters is stored as a ImageSize, which is also a byte variable and should be a dword.
In KERNEL.EXE
I forgot to mention that you should turn off Incremental Linking under Configuration Properties => Linker.
The functions strcmp, strlen, strcpy and memset have to be linked in statically, so go to Configuration Properties => C++ => Code Generation and set Runtime Library to just Multi-threaded (not DLL or Debug), or implement these four functions by yourself.