OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 8:00 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Trying to port OS (IDT) to long mode
PostPosted: Sat Mar 16, 2019 10:56 am 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
Hi again.
I decided that I should adapt my OS to work in long mode (64 bits), before it grows more and becomes more complicated (I don't want to regret it later). The bootloader works well, now I try to port the IDT (which in part is written in assembly, 50% C and 50% NASM) I'm just getting troubles in assembly (I'm not very good at assembly)
I already changed the IDT structure to the AMD64 one
Code:
idt.inc:320: error: instruction not supported in 64-bit mode
idt.inc:321: error: instruction not supported in 64-bit mode
idt.inc:336: error: instruction not supported in 64-bit mode
idt.inc:337: error: instruction not supported in 64-bit mode
idt.inc:475: error: instruction not supported in 64-bit mode
idt.inc:476: error: instruction not supported in 64-bit mode
idt.inc:494: error: instruction not supported in 64-bit mode
idt.inc:495: error: instruction not supported in 64-bit mode

idt.inc
Code:
global idt_load
extern fault_handler
extern idtp
extern kputs
extern k_readkb
extern getch
extern cmd_shell


; Loads the IDT defined in '_idtp' into the processor.
idt_load:
    lidt [idtp]
    ret

global isr0
global isr1
global isr2
global isr3
global isr4
global isr5
global isr6
global isr7
global isr8
global isr9
global isr10
global isr11
global isr12
global isr13
global isr14
global isr15
global isr16
global isr17
global isr18
global isr19
global isr20
global isr21
global isr22
global isr23
global isr24
global isr25
global isr26
global isr27
global isr28
global isr29
global isr30
global isr31
global isr128

%macro pushall 0
    push rax
    push rcx
    push rdx
    push rbx
    push rbp
    push rsi
    push rdi
%endmacro

%macro popall 0
    pop rax
    pop rcx
    pop rdx
    pop rbx
    pop rbp
    pop rsi
    pop rdi
%endmacro

isr0:
    cli
    push byte 0 
    push byte 0
    jmp isr_common_stub

isr1:
    cli
    push byte 0
    push byte 1
    jmp isr_common_stub
   
isr2:
    cli
    push byte 0
    push byte 2
    jmp isr_common_stub

isr3:
    cli
    push byte 0
    push byte 3
    jmp isr_common_stub

isr4:
    cli
    push byte 0
    push byte 4
    jmp isr_common_stub

isr5:
    cli
    push byte 0
    push byte 5
    jmp isr_common_stub

isr6:
    cli
    push byte 0
    push byte 6
    jmp isr_common_stub

isr7:
    cli
    push byte 0
    push byte 7
    jmp isr_common_stub

isr8:
    cli
    push byte 8       
    jmp isr_common_stub

isr9:
    cli
    push byte 0
    push byte 9
    jmp isr_common_stub

isr10:
    cli
    push byte 10
    jmp isr_common_stub

isr11:
    cli
    push byte 11
    jmp isr_common_stub

isr12:
    cli
    push byte 12
    jmp isr_common_stub

isr13:
    cli
    push byte 13
    jmp isr_common_stub

isr14:
    cli
    push byte 14
    jmp isr_common_stub

isr15:
    cli
    push byte 0
    push byte 15
    jmp isr_common_stub

isr16:
    cli
    push byte 0
    push byte 16
    jmp isr_common_stub

isr17:
    cli
    push byte 0
    push byte 18
    jmp isr_common_stub

isr18:
    cli
    push byte 0
    push byte 18
    jmp isr_common_stub

isr19:
    cli
    push byte 0
    push byte 19
    jmp isr_common_stub

isr20:
    cli
    push byte 0
    push byte 20
    jmp isr_common_stub

isr21:
    cli
    push byte 0
    push byte 21
    jmp isr_common_stub

isr22:
    cli
    push byte 0
    push byte 22
    jmp isr_common_stub

isr23:
    cli
    push byte 0
    push byte 23
    jmp isr_common_stub

isr24:
    cli
    push byte 0
    push byte 24
    jmp isr_common_stub

isr25:
    cli
    push byte 0
    push byte 25
    jmp isr_common_stub

isr26:
    cli
    push byte 0
    push byte 26
    jmp isr_common_stub

isr27:
    cli
    push byte 0
    push byte 26
    jmp isr_common_stub

isr28:
    cli
    push byte 0
    push byte 28
    jmp isr_common_stub

isr29:
    cli
    push byte 0
    push byte 29
    jmp isr_common_stub

isr30:
    cli
    push byte 0
    push byte 30
    jmp isr_common_stub

isr31:
    cli
    push byte 0
    push byte 31
    jmp isr_common_stub

; Int 80h
; Registers:
; eax = service, ecx
isr128:
    cli
    push byte 0
    push byte 80

    cmp rax, 1 ; Service 1 (terminate program)
    je .terminate_prg

    cmp rax, 3 ; Service 3 (read keyboard)
    je .read_srv

    cmp rax, 4 ; Service 4 (prints text)
    je .write_srv
    jmp .end
    .terminate_prg:
        ; We don't have processes yet, because we still in
        ; monotasking. Just return to the command shell
        call cmd_shell
        jmp isr_common_stub
        jmp .end
    .read_srv:
        xor rax, rax
        push rdx
        push rcx
        call k_readkb
        pop rdx
        pop rcx
        jmp isr_common_stub
        jmp .end
    .write_srv:
        xor rax, rax
        push rcx
        call kputs
        pop rcx
        jmp isr_common_stub
    .end:

isr_common_stub:
    pushall
    push ds
    push es
    push fs
    push gs
    mov ax, 0x10   
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov rax, rsp   
    push rax
    mov rax, fault_handler
    call rax       
    pop rax
    pop gs
    pop fs
    pop es
    pop ds
    popall
    add rsp, 8     
    iretq           


global irq0
global irq1
global irq2
global irq3
global irq4
global irq5
global irq6
global irq7
global irq8
global irq9
global irq10
global irq11
global irq12
global irq13
global irq14
global irq15

; 32: IRQ0
irq0:
    cli
    push byte 0
    push byte 32
    jmp irq_common_stub

; 33: IRQ1
irq1:
    cli
    push byte 0
    push byte 33
    jmp irq_common_stub

; 34: IRQ2
irq2:
    cli
    push byte 0
    push byte 34
    jmp irq_common_stub

; 35: IRQ3
irq3:
    cli
    push byte 0
    push byte 35
    jmp irq_common_stub

; 36: IRQ4
irq4:
    cli
    push byte 0
    push byte 36
    jmp irq_common_stub

; 37: IRQ5
irq5:
    cli
    push byte 0
    push byte 37
    jmp irq_common_stub

; 38: IRQ6
irq6:
    cli
    push byte 0
    push byte 38
    jmp irq_common_stub

; 39: IRQ7
irq7:
    cli
    push byte 0
    push byte 39
    jmp irq_common_stub

; 40: IRQ8
irq8:
    cli
    push byte 0
    push byte 40
    jmp irq_common_stub

; 41: IRQ9
irq9:
    cli
    push byte 0
    push byte 41
    jmp irq_common_stub

; 42: IRQ10
irq10:
    cli
    push byte 0
    push byte 42
    jmp irq_common_stub

; 43: IRQ11
irq11:
    cli
    push byte 0
    push byte 43
    jmp irq_common_stub

; 44: IRQ12
irq12:
    cli
    push byte 0
    push byte 44
    jmp irq_common_stub

; 45: IRQ13
irq13:
    cli
    push byte 0
    push byte 45
    jmp irq_common_stub

; 46: IRQ14
irq14:
    cli
    push byte 0
    push byte 46
    jmp irq_common_stub

; 47: IRQ15
irq15:
    cli
    push byte 0
    push byte 47
    jmp irq_common_stub

extern irq_handler
irq_common_stub:
    pushall
    push ds ; Can't push segment register directly in x64
    push es
    push fs
    push gs

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov rax, rsp

    push rax
    mov rax, irq_handler
    call rax
    pop rax

    pop gs
    pop fs
    pop es
    pop ds
    popall
    add rsp, 8
    iretq


The problem is that we can't push segment registers directly, we need to move it to an register, and then push it. But I'm using all the registers. And then I need to pop from stack the segment registers!
Porting this is more than just replacing "e" with "r".
Thank for you patience.


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sat Mar 16, 2019 11:37 am 
Offline
Member
Member
User avatar

Joined: Thu Oct 13, 2016 4:55 pm
Posts: 1584
Hi,

I don't know your source file entirely, but you have errors in pairs of lines with gaps. That suggests it's not the segment register push failing, but the "push byte" ones. You can't push a byte in 64 bit mode only 64 bit values.
Why do you need the segment registers anyway? In long mode there's no segmentation it uses a flat memory modell. The only purpose is to specify access and CPL in case of CS; base and limit is not used by the CPU at all.

You can set ES, DS to a user readable, writable but not executable segment and happily use that from kernel mode too. No need to change them, ever. You should not need to use FS/GS, but if you really do, see the SWAPGS instruction instead of pushing/poping selectors on the stack. Finally CS is pushed by the CPU on gate entry and popped by IRETQ, so no need to manually push/pop that either.

Cheers,
bzt


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sat Mar 16, 2019 1:08 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
Thanks for replying.
I'm getting "bootg.o: file not recognized: File format not recognized" error from the linker.
bootg.asm:
Code:
%include "gdt.inc"
%include "idt.inc"

global start
extern kernelmain
extern kputs
extern long_mode_start

bits 32

; This is the GRUB multiboot header
section .multiboot
align 4

mboot:
    MULTIBOOT_PAGE_ALIGN     equ 1 << 0
    MULTIBOOT_MEMORY_INFO    equ 1 << 1
    MULTIBOOT_VIDEO_MODE      equ 1 << 2
    MULTIBOOT_HEADER_MAGIC   equ 0x1BADB002
    MULTIBOOT_HEADER_FLAGS   equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
    MULTIBOOT_CHECKSUM       equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)

    dd MULTIBOOT_HEADER_MAGIC
    dd MULTIBOOT_HEADER_FLAGS
    dd MULTIBOOT_CHECKSUM

section .text

check_cpuid:
    pushfd
    pop eax
    mov ecx, eax

    ; Flip the ID bit
    xor eax, 1 << 21

    ; Copy EAX to FLAGS via the stack
    push eax
    popfd

    ; Copy FLAGS back to EAX (with the flipped bit if CPUID is supported)
    pushfd
    pop eax

    ; Restore FLAGS from the old version stored in ECX (i.e. flipping the
    ; ID bit back if it was ever flipped).
    push ecx
    popfd

    ; Compare EAX and ECX. If they are equal then that means the bit
    ; wasn't flipped, and CPUID isn't supported.
    cmp eax, ecx
    je .no_cpuid
    ret
    .no_cpuid:
        ;mov ecx, no_cpuid_str
        ;push ecx
        ;call kputs
        ;pop ecx
        cli
        hlt

check_long_mode:
    ; test if extended processor info in available
    mov eax, 0x80000000    ; implicit argument for cpuid
    cpuid                  ; get highest supported argument
    cmp eax, 0x80000001    ; it needs to be at least 0x80000001
    jb .no_long_mode       ; if it's less, the CPU is too old for long mode

    ; use extended info to test if long mode is available
    mov eax, 0x80000001    ; argument for extended processor info
    cpuid                  ; returns various feature bits in ecx and edx
    test edx, 1 << 29      ; test if the LM-bit is set in the D-register
    jz .no_long_mode       ; If it's not set, there is no long mode
    ret
.no_long_mode:
    ;mov ecx, no_long_str
    ;push ecx
    ;call kputs
    ;pop ecx
    cli
    hlt

set_up_page_tables:
    ; map first P4 entry to P3 table
    mov eax, p3_table
    or eax, 0b11 ; present + writable
    mov [p4_table], eax

    ; map first P3 entry to P2 table
    mov eax, p2_table
    or eax, 0b11 ; present + writable
    mov [p3_table], eax

    mov ecx, 0
   
    .map_p2_table:
        ; map ecx-th P2 entry to a huge page that starts at address 2MiB*ecx
        mov eax, 0x200000  ; 2MiB
        mul ecx            ; start address of ecx-th page
        or eax, 0b10000011 ; present + writable + huge
        mov [p2_table + ecx * 8], eax ; map ecx-th entry

        inc ecx            ; increase counter
        cmp ecx, 512       ; if counter == 512, the whole P2 table is mapped
        jne .map_p2_table  ; else map the next entry

        ret

enable_paging:
    ; load P4 to cr3 register (cpu uses this to access the P4 table)
    mov eax, p4_table
    mov cr3, eax

    ; enable PAE-flag in cr4 (Physical Address Extension)
    mov eax, cr4
    or eax, 1 << 5
    mov cr4, eax

    ; set the long mode bit in the EFER MSR (model specific register)
    mov ecx, 0xC0000080
    rdmsr
    or eax, 1 << 8
    wrmsr

    ; enable paging in the cr0 register
    mov eax, cr0
    or eax, 1 << 31
    mov cr0, eax
    ret

start:
    mov esp, _sys_stack_t
    ; Check for CPUID support
    call check_cpuid
    call check_long_mode
    call set_up_page_tables
    call enable_paging
    lgdt [gdt64.pointer]
    jmp gdt64.code:long_mode_start

section .data:
    ;no_cpuid_str: db "CPUID is not supported.", 0x0A, 0x0D, 0
    ;no_long_str: db "Long mode (x86-64) not supported", 0x0A, 0x0D, 0

section .bss
align 4096
p4_table:
    resb 4096
p3_table:
    resb 4096
p2_table:
    resb 4096
_sys_stack_b:
    resb 64
_sys_stack_t:


I don't know if it is useful, but here is the file bootg.o output:
Code:
bootg.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), with debug_info, not stripped

Just in case, link.ld:
Code:
/* The bootloader will look at this image and start execution at the symbol
   designated as the entry point. */
ENTRY(start)

/* Tell where the various sections of the object files will be put in the final
   kernel image. */
SECTIONS
{
   /* Begin putting sections at 1 MiB, a conventional place for kernels to be
      loaded at by the bootloader. */
   . = 1M;

   /* First put the multiboot header, as it is required to be put very early
      early in the image or the bootloader won't recognize the file format.
      Next we'll put the .text section. */
   .text BLOCK(4K) : ALIGN(4K)
   {
      *(.multiboot)
      *(.text)
   }

   /* Read-only data. */
   .rodata BLOCK(4K) : ALIGN(4K)
   {
      *(.rodata)
   }

   /* Read-write data (initialized) */
   .data BLOCK(4K) : ALIGN(4K)
   {
      *(.data)
   }

   /* Read-write data (uninitialized) and stack */
   .bss BLOCK(4K) : ALIGN(4K)
   {
      *(COMMON)
      *(.bss)
      __endkernel = .;
   }
}

Ok, so I tried to use elf32 instead of elf64 in nasm flags, added an bits 64 in the start of idt.inc and gdt.inc. No more linker problems, but triple faults now. As spected.


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sun Mar 17, 2019 7:05 am 
Offline
Member
Member
User avatar

Joined: Thu Oct 13, 2016 4:55 pm
Posts: 1584
hextakatt wrote:
Ok, so I tried to use elf32 instead of elf64 in nasm flags, added an bits 64 in the start of idt.inc and gdt.inc. No more linker problems, but triple faults now. As spected.
You can't just mix those, you must know precisely in which mode the CPU is at a given time during boot, otherwise a fault is guaranteed.

You need a pure 64 bit toolchain, generating elf64 with long mode instructions in the text sections. There's only one exception to this, the startup code, so you should only use "bits 32" in your multiboot code (you should have no "bits" directive anywhere else):
Code:
   ; multiboot header with start32 as entry point
bits 32
start32:
   ; multiboot stub
   ; enable paging, switch to longmode
   jmp gdt64.code:start64     ; this jump is important as it loads CS and enables long mode

bits 64
start64:
   ; set up long mode environment (stack, segments, lidt etc.)
   ; jump to 64 bit C code
This source, the C code (and everything) must be compiled as elf64, and you should not include idt.inc (as your boot up code mixes modes, but your idt must be purely 64 bit). You should define the idt descriptor (lidt's argument) as extern to access it and that's all. There should be absolutely no code in gdt.inc, only data, therefore "bits 64" should not matter there anyway, but if you have a "loadgdt()" function there then it must be compiled for the default 64 bit (so no "bits 64" needed in that case either).

With the triple faults, use bochs debugger to figure out where that happened, but I'm sure this time it's the invalid mixing of CPU modes.

Just a sidenote, not related to your issue, but your pushall does not store all registers. In long mode you also have GPRs r8 - r15.

Cheers,
bzt


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sun Mar 17, 2019 10:47 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
On top of the things BZT said, you are also pushing and popping in the same order. You need to pop in reverse order of what you pushed. The popall macro is backwards:

Code:
%macro pushall 0
    push rax
    push rcx
    push rdx
    push rbx
    push rbp
    push rsi
    push rdi
%endmacro

%macro popall 0
    pop rax
    pop rcx
    pop rdx
    pop rbx
    pop rbp
    pop rsi
    pop rdi
%endmacro


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Mon Mar 18, 2019 9:40 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
Can you make your non-functioning 64-bit code as it currently is available in a branch in your git repository?


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Wed Mar 20, 2019 7:24 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
I already commited. Here's the repo
Sorry for late answer, I was busy.


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Thu Mar 21, 2019 10:17 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
Your wipcode branch seems to be lacking files including(but not limited to) bootg.asm.


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Thu Mar 21, 2019 9:47 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
MichaelPetch wrote:
Your wipcode branch seems to be lacking files including(but not limited to) bootg.asm.

The missing files are now in the repo. Sorry #-o


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Fri Mar 22, 2019 4:26 pm 
Offline
Member
Member
User avatar

Joined: Sun Feb 20, 2011 2:01 pm
Posts: 110
Also, re the. triple faults, having a bochs trace would be helpful - you can see what exception was fired, and the register state at the time, not to mention the address.

_________________
Whoever said you can't do OS development on Windows?
https://github.com/ChaiSoft/ChaiOS


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Fri Mar 22, 2019 7:10 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
bellezzasolo wrote:
Also, re the. triple faults, having a bochs trace would be helpful - you can see what exception was fired, and the register state at the time, not to mention the address.

I was also thinking about using the Bochs debugger, but since I started using GRUB and an iso file instead of img (floppy) I just can't get my OS to boot into Bochs. Bochs refuses the ISO file. But please, I don't want to introduce another problem, I have a ton of they. I will try to debug using GDB.
EDIT: guess what gdb refuses to debug... #-o


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Fri Mar 22, 2019 8:18 pm 
Offline
Member
Member

Joined: Tue Apr 03, 2018 2:44 pm
Posts: 36
hextakatt wrote:
bellezzasolo wrote:
Also, re the. triple faults, having a bochs trace would be helpful - you can see what exception was fired, and the register state at the time, not to mention the address.

I was also thinking about using the Bochs debugger, but since I started using GRUB and an iso file instead of img (floppy) I just can't get my OS to boot into Bochs. Bochs refuses the ISO file. But please, I don't want to introduce another problem, I have a ton of they.


Getting Bochs to work would be very beneficial and save you a lot of time down the road. If you post your bochsrc we can help you sort that out, and that would help get this sorted out.

_________________
Image is my operating system.

"...not because [it is] easy, but because [it is] hard; because that goal will serve to organize and measure the best of [my] energies and skills..."


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Fri Mar 22, 2019 10:16 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
When I try to build your project there is a linker error. `bootg.o: file not recognized: File format not recognized` . It occurs because you build bootg.o with `@nasm -f elf64 -Fdwarf -g bootg.asm -o bootg.o` (you assemble to a 64-bit ELF object) and then later you use an i686 cross compiler to build an executable with
Code:
@i686-elf-gcc -std=c99 -nostartfiles -nostdlib -Tlink.ld -lgcc -o os.elf \
        bootg.o bootg2.o api_test.o kmain.o kernel/timer.o kernel/terminal.o  kernel/pic.o kernel/serial.o kernel/idt.o kernel$
        kernel/keyboard.o kernel/mouse.o kernel/panic.o kernel/cpu.o kernel/cmos.o kernel/fpc.o kernel/rtc.o
My question is this. Is this suppose to be a 64-bit kernel? If so, why aren't you using a 64-bit cross compiler like x86_64-elf-gcc ? You can't build 64-bit code with i686-elf-gcc.


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sat Mar 23, 2019 6:27 am 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
MichaelPetch wrote:
When I try to build your project there is a linker error. `bootg.o: file not recognized: File format not recognized` . It occurs because you build bootg.o with `@nasm -f elf64 -Fdwarf -g bootg.asm -o bootg.o` (you assemble to a 64-bit ELF object) and then later you use an i686 cross compiler to build an executable with
Code:
@i686-elf-gcc -std=c99 -nostartfiles -nostdlib -Tlink.ld -lgcc -o os.elf \
        bootg.o bootg2.o api_test.o kmain.o kernel/timer.o kernel/terminal.o  kernel/pic.o kernel/serial.o kernel/idt.o kernel$
        kernel/keyboard.o kernel/mouse.o kernel/panic.o kernel/cpu.o kernel/cmos.o kernel/fpc.o kernel/rtc.o
My question is this. Is this suppose to be a 64-bit kernel? If so, why aren't you using a 64-bit cross compiler like x86_64-elf-gcc ? You can't build 64-bit code with i686-elf-gcc.

I fixed the dumbest error, now I'm using x86_64-elf-gcc. But I'm getting error:no multiboot header found. I don't touched nothing.
The multiboot header is aligned to the first 4 kb, as we can see in the linker file:
Code:
.text BLOCK(4K) : ALIGN(4K)
{
   *(.multiboot)
   *(.text)
}

Code:
section .multiboot
align 4

mboot:
    MULTIBOOT_PAGE_ALIGN     equ 1 << 0
    MULTIBOOT_MEMORY_INFO    equ 1 << 1
    MULTIBOOT_VIDEO_MODE      equ 1 << 2
    MULTIBOOT_HEADER_MAGIC   equ 0x1BADB002
    MULTIBOOT_HEADER_FLAGS   equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
    MULTIBOOT_CHECKSUM       equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)

    dd MULTIBOOT_HEADER_MAGIC
    dd MULTIBOOT_HEADER_FLAGS
    dd MULTIBOOT_CHECKSUM


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sat Mar 23, 2019 9:09 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
The default page size is 2MiB with x86_64-elf-gcc so the bootloader ends up outside the first 8KiB. This is discussed on the Wiki. To fix this when linking to your executable you need to add -z max-page-size=4096. One other significant problem is that you are going to have problems with SIMD instructions (SSE, SSE2, SSE3 etc) when in your kernel. You are going to want to add the compiler options -mno-sse -mno-sse2 -mno-sse3 along with -mno-red-zone .

The x86-64 System V ABI passes the first two parameters through RDI and RSI (In that order). You don't push EAX and EBX onto the stack when calling kernelmain. You also clobber EAX when setting the segment registers. You need to ensure the upper 32-bits of RSP are set to zero. Your long_mode_start should probably look like:
Code:
long_mode_start:
    ; All segment registers to zero
    mov cx, 0
    mov ss, cx
    mov ds, cx
    mov es, cx
    mov fs, cx
    mov gs, cx
    mov esp,esp                  ; Move ESP to itself will clear the upper 32 bits of RSP

    call idt_load
    ; Pass GRUB registers. RDI=1st parameter of kernelmain, RSI=2nd parameter
    mov edi, ebx
    mov esi, eax

    ; Calls kernel entry point
    call kernelmain
    ; Jumps to the end routine, thats halts the system
    jmp end
In your `start` routine you clobber EAX and EBX that are passed by GRUB when you call your functions to do initializing. You are going to have to temporarily save them. You can do something like: start:
Code:
    mov esp, _sys_stack_t
    push eax
    push ebx
    ; Check for CPUID support
    call check_cpuid
    call check_long_mode
    call set_up_page_tables
    call enable_paging
    pop ebx
    pop eax
    lgdt [gdt64.pointer]
    jmp gdt64.code:long_mode_start
This should get you as far as entering kernelmain. At this point you really need to start using a debugger.

Note: In 64-bit code if the destination of an instruction is a 32-bit register then the CPU automatically sets the upper 32-bits of the corresponding 64-bit register to zero.


Last edited by MichaelPetch on Sat Mar 23, 2019 9:15 am, edited 3 times in total.

Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 60 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group