Page 1 of 1

Entering Protected Mode on laptop

Posted: Sun Aug 09, 2015 12:25 pm
by drnono
Hi.
It took me a while to get into protected mode on VMware with a virtual floppy but eventually I got it working and can run C programs.
I can write my OS code to a usb stick and boot it - it works, but keeps resetting when I try to get into protected mode like I do on the virtual machine. I tried booting on two laptops but they will not go 32bits with the same (gdt) settings as the VM.

I can only think of two things that might be stopping it:
1. The bios doesn't like me using segment limits that are larger than the memory size?
2. I need to restore interrupts ?=> write IVT etc which I don't want to do yet.

My code runs and prints char to screen until the exact line where 'mov cr0,eax' ...
I have no debugger set up yet so I can't tell where the code messes up after this line.

Code: Select all

jmp load_GDT
GDTR:
dw (end_GDT - GDT) -1		;end_GDT - GDTR ??
dd GDT

GDT db 0,0, 0,0, 0,0, 0,0

code32 equ 0x8
db 0xff,0xff,0x00,0x00
db 0,0b10011010,0b11001111,0

data32 equ 0x10
db 0xff,0xff,0x00,0x00
db 0,0b10010010,0b11001111,0
end_GDT:

load_GDT:

xor eax,eax
mov eax,GDT
add eax,0x7c00
mov [GDTR+2],eax

cli			 ; disable interrupts
lgdt [GDTR]		 ; load table into cpu

mov eax,cr0	 ; control register
or eax,0x1		 ; set protection enable (PE)
mov cr0,eax
jmp 0x08:0x7e00   ; set 32bit registers <- jmp to next sector
			 ; jmp a:b means set cs:ip

Code: Select all

; SECTOR 2, 0X7E00

set_registers:

bits 32

mov ax,0x10
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax

mov byte [0xb8322],'y'
mov byte [0xb8323], 0x12

mov esp, 0x4000000
hlt
; C KERNEL PASTES HERE AFTER LINKING
; ...
; ...

Re: Entering Protected Mode on laptop

Posted: Sun Aug 09, 2015 2:04 pm
by Unsigned
drnono wrote:It took me a while to get into protected mode on VMware with a virtual floppy but eventually I got it working and can run C programs.
I can write my OS code to a usb stick and boot it - it works, but keeps resetting when I try to get into protected mode like I do on the virtual machine. I tried booting on two laptops but they will not go 32bits with the same (gdt) settings as the VM.
You should use Bochs, it gives you critical information when there's a triple fault. I couldn't even be osdeving without its errors and warnings.
drnono wrote:The bios doesn't like me using segment limits that are larger than the memory size?
The BIOS ignores anything related to protected mode.
drnono wrote:I need to restore interrupts ?=> write IVT etc which I don't want to do yet.
Restore what? What do you mean? And protected mode doesn't use the IVT, it uses the IDT, which you have to set up. But if the interrupts are disabled, you shouldn't get any problem yet. The only problem you could have here is when a NMI occurs, which may happen in real hardware and not in a VM, but i think you shouldn't have this problem at least for several minutes. Anyway, you could try disabling NMI and see if it works, see the CMOS wiki article for information about it.
drnono wrote:xor eax,eax
mov eax,GDT
add eax,0x7c00
mov [GDTR+2],eax
Are you sure the code is loaded at 0000:7c00? Depending on the BIOS and the boot sector, it could be loaded at 07c0:0000 or any other seg:off pair which resolves to the same address. This is what i do in my code to fix it (at the very beggining of the code):

Code: Select all

org 0
jmp 07c0h:initfix
initfix:
But if you prefer your base to be 0, you should use this:

Code: Select all

org 0x7c00
jmp 0:initfix
initfix:
drnono wrote:mov esp, 0x4000000
Why do you put such a big value in ESP? Have you got the memory map to know which parts of the memory are available? Have you enabled paging to make your address space contiguous so that your code/data is not referenced in non-existant memory? Have you enabled the A20 line?

Re: Entering Protected Mode on laptop

Posted: Mon Aug 10, 2015 12:01 pm
by drnono
Turns out I was trying to load the second sector of a floppy after 0x7c00 instead of a hard disk sector.

I can boot both laptops now. The older one will boot after I set the code segment with jmp 0x7c0:bootloader or jmp bootloader.
The newish laptop will only boot with jmp bootloader.

I looked at the assembled opcodes for both jumps. The CS jump points two bytes further in the file than the relative jump.

eb 2f ... jumps to offset 2f ?
ea 34 00 c0 07 ... jumps to offset 34 ?

Taking account of the three extra bytes in the CS jump code the BOOTLOADER label should three bytes further than 2f - but its at 34 not 32.

Can someone explain this?

Re: Entering Protected Mode on laptop

Posted: Mon Aug 10, 2015 12:38 pm
by Octocontrabass
drnono wrote:I can boot both laptops now. The older one will boot after I set the code segment with jmp 0x7c0:bootloader or jmp bootloader.
The newish laptop will only boot with jmp bootloader.
This is a bug in your code, not a problem with the computer. Are you initializing all of the registers before you use them? Perhaps you're accessing memory without setting DS first.
drnono wrote:I looked at the assembled opcodes for both jumps. The CS jump points two bytes further in the file than the relative jump. [...] Can someone explain this?
Short and Near jumps are encoded with relative addresses, not absolute addresses. The operand is added to the address of the byte following the instruction to get the address of the jump destination.

Re: Entering Protected Mode on laptop

Posted: Mon Aug 10, 2015 2:41 pm
by drnono
I double checked it. On the newer laptop it will not boot if it does jmp 0x7c0:bootloader but will if jmp bootloader.
This is a bug in your code, not a problem with the computer. Are you initializing all of the registers before you use them? Perhaps you're accessing memory without setting DS first.
I don't think it's the registers ...

This is the code I can boot with both laptops:

Code: Select all

org 0
jmp BOOTLOADER   ; avoid BIOS load problem at 0:0x7c00 or 0x7c0:0 ???

BPB:

... ...

BOOTLOADER:
mov ax,0x7c0    ; bootsector memory addr = here
mov ds,ax
mov ax,0x7bf
mov ss,ax
mov sp,0

mov al,'R'
mov ah,0xe
int 0x10

end_BOOTLOADER: jmp $
This only works on the older one:

Code: Select all

org 0
jmp 0x7c0:BOOTLOADER   ; avoid BIOS load problem at 0:0x7c00 or 0x7c0:0 ???

BPB:

... ...

BOOTLOADER:
mov ax,0x7c0    ; bootsector memory addr = here
mov ds,ax
mov ax,0x7bf
mov ss,ax
mov sp,0

mov al,'R'
mov ah,0xe
int 0x10

end_BOOTLOADER: jmp $
I attached a print of the jump opcodes. They don't seem to point at the same code ...

Re: Entering Protected Mode on laptop

Posted: Mon Aug 10, 2015 3:15 pm
by neon
They are both wrong. You should be doing:

Code: Select all

bits 16
org 0
   jmp short BOOTLOADER
   nop

BOOTLOADER:
   jmp 0x7c0:.fix_cs
.fix_cs:
; etc.
Never assume CS:IP and always insure a 2 byte short or 3 byte far jmp.

Re: Entering Protected Mode on laptop

Posted: Mon Aug 10, 2015 5:52 pm
by drnono
Hmm, I don't understand this - although I tried it and it works for both.

What do you mean by a 3 byte far jump or a 2 byte short jump?

I looked at the binary output: the short jump instruction, and the far jump have the same opcodes as they did before. And far as I can tell the far jump is 4 bytes.

Why does this work ? (since the jumps look the exact same as when not using two jumps and they just jump to the same instructions: b8 c0 07 ...)

Re: Entering Protected Mode on laptop

Posted: Mon Aug 10, 2015 5:59 pm
by kzinti
The OEM signature needs to be at offset 3. So that only gives you 3 bytes for a jump instruction.

If you don't use exactly 3 bytes, your BPB will end up at the wrong offset and that won't work.

Re: Entering Protected Mode on laptop

Posted: Mon Aug 10, 2015 6:17 pm
by neon
Hello,

The first two instructions (the jmp with nop) I provided translates to EBh disp8 90h, which is 3 bytes. Using a jmp without specifying far or near allows the assembler to decide for you which can break the code (as you have seen here.)

Your jmp seg:off assembles to jmpf ptr16:16/32. Compare that with "jmp rel8" which is what my example uses. The former translates to EA ptr16:ptr16 or 5 bytes. The latter translates to EB rel8 or 2 bytes.

Your jmp BOOTLOADER appears to have been assembled as jmp rel8 which would have made your bpb off by 1. In other words, your jmp BOOTLOADER was still a short jmp which is why they have the same opcode and displacement offset. You can test this theory yourself by doing this:

Code: Select all

jmp BOOTLOADER
nop
The generated code should be the same as mine. Keep in mind that I recommend keeping "short" to avoid potential breaking later.

Re: Entering Protected Mode on laptop

Posted: Mon Aug 10, 2015 6:47 pm
by drnono
Thanks - think I get it now. Is it possible to do a far jump with three bytes in nasm?

Re: Entering Protected Mode on laptop

Posted: Mon Aug 10, 2015 7:17 pm
by neon
Hello,

It should be noted that the only allowed forms are EBh rel8 90h or E9h rel16 as defined by the fat32 whitepaper. The former is a short jmp with a nop, the latter is a 16 bit relative jmp. The problem with using the latter is that optimizations could result in the assembler translating it differently.

jmp BOOTLOADER may be assembled as E9h rel16 (3 bytes) or EBh rel8 (2 bytes) depending on optimization settings and label distance. Easiest way to avoid these issues that I know of is to explicitly use the short form with a nop.

There is no 3 byte far jump since they require ptr16:ptr16/32. Best you can do is 3 byte relative jump (the E9h opcode) -- but we tend to use the short form (EBh opcode.)