OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 4:05 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 25 posts ]  Go to page Previous  1, 2
Author Message
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sat Mar 23, 2019 9:11 am 
Offline
Member
Member
User avatar

Joined: Sun Feb 20, 2011 2:01 pm
Posts: 110
hextakatt wrote:
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

The linker will be emitting a section before .text - running objdump probably will help track that down. Alternatively, building for 64 bit, it can use bigger pages - Creating a 64-bit kernel: -z max-page-size=0x1000 forces 4KB.

_________________
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: Sat Mar 23, 2019 1:10 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
bellezzasolo wrote:
hextakatt wrote:
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

The linker will be emitting a section before .text - running objdump probably will help track that down. Alternatively, building for 64 bit, it can use bigger pages - Creating a 64-bit kernel: -z max-page-size=0x1000 forces 4KB.

Tried using -z max-page-size=0x1000 and tried the other solutions that are in the "Possible Problems" section of Creating a 64-bit kernel, getting "error: invalid arch-dependent elf magic". again the elfs with their magic


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

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
You said you were getting "error: invalid arch-dependent elf magic" . The only way I know of to get that is if you modified your makefile (or linker script) to build a binary file from your kernel with an improper multiboot header (without proper support for the AOUT kludge) and got that error when booting with GRUB. Please post your recent changes that don't work to your git repo wipcode branch.


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sat Mar 23, 2019 5:06 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
Only changed the makefile, in order to use x86_64-elf-gcc instead of i686-elf-gcc.


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sat Mar 23, 2019 5:51 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
I can only gather then you might have a version of GRUB that may not understand 64-bit ELF executables. What does the command grub-mkconfig --version show for output? There is a way around this hassle though. I'm not sure it is captured in the Wiki articles or not (but it is the method I first used when I started my first 64-bit kernel when the 64-bit processors started becoming popular). You can use the MULTIBOOT AOUT KLUDGE (enabled by setting bit 16 in the multiboot flags) but it also requires a proper AOUT section right after the header that defines the start of the multiboot section, the beginning of the text section, the end of the data section, the end of the BSS section and the address of the entry point.

I'd modify your makefile to be this:
Code:
ifeq ($(OS), Windows_NT)
        $(warning Compiling in Windows? Wow you're insane)
        $(warning If you are too lazy to install an GNU/Linux distro, use WSL!)
endif

CFLAGS = -g -c -std=gnu99 -ffreestanding -mno-red-zone -mno-sse -mno-sse2 -mno-sse3 -O3 -Wall -fomit-frame-pointer

# Compile and link everything
all:
        $(info Compiling GryphusOS... Please wait.)
        @nasm -f elf64 -Fdwarf -g bootg.asm -o bootg.o
        @nasm -f elf64 -Fdwarf -g bootg2.asm -o bootg2.o
        @nasm -f elf64 -Fdwarf -g api_test.asm -o api_test.o
        @x86_64-elf-gcc $(CFLAGS) -masm=intel kmain.c -o kmain.o
        @x86_64-elf-gcc $(CFLAGS) kernel/timer.c -o kernel/timer.o
        @x86_64-elf-gcc $(CFLAGS) kernel/terminal.c -o kernel/terminal.o
        @x86_64-elf-gcc $(CFLAGS) kernel/serial.c -o kernel/serial.o
        @x86_64-elf-gcc $(CFLAGS) kernel/pic.c -o kernel/pic.o
        @x86_64-elf-gcc $(CFLAGS) kernel/irq.c -o kernel/irq.o
        @x86_64-elf-gcc $(CFLAGS) kernel/isrs.c -o kernel/isrs.o
        @x86_64-elf-gcc $(CFLAGS) kernel/idt.c -o kernel/idt.o
        @x86_64-elf-gcc $(CFLAGS) kernel/keyboard.c -o kernel/keyboard.o
        @x86_64-elf-gcc $(CFLAGS) kernel/mouse.c -o kernel/mouse.o
        @x86_64-elf-gcc $(CFLAGS) kernel/panic.c -o kernel/panic.o
        @#x86_64-elf-gcc $(CFLAGS) -I../osproject kernel/paging.c -o kernel/paging.o
        @x86_64-elf-gcc $(CFLAGS) kernel/cpu.c -o kernel/cpu.o
        @x86_64-elf-gcc $(CFLAGS) kernel/cmos.c -o kernel/cmos.o
        @x86_64-elf-gcc $(CFLAGS) kernel/fpc.c -o kernel/fpc.o
        @x86_64-elf-gcc $(CFLAGS) kernel/rtc.c -o kernel/rtc.o
        @x86_64-elf-gcc -std=c99 -nostartfiles -nostdlib -Tlink.ld -lgcc -z max-page-size=4096 -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/irq.o kernel/isrs.o \
                kernel/keyboard.o kernel/mouse.o kernel/panic.o kernel/cpu.o kernel/cmos.o kernel/fpc.o kernel/rtc.o
        @x86_64-elf-objcopy -O binary os.elf os.bin
        @mkdir -p isodir/boot/grub
        @cp os.bin isodir/boot/os.bin
        @cp grub.cfg isodir/boot/grub/grub.cfg
        @grub-mkrescue -o os.iso isodir

clear:
        rm *.o *.elf



# Compile and link only the bootloader
bootloader:
        nasm -f elf64 -Fdwarf -g bootg.asm -o bootg.o
        #yasm -f elf32 bootg.asm -o bootg.o
        x86_64-elf-gcc -std=c99 -nostartfiles -nostdlib -Tlink.ld -lgcc -o os.elf \
                bootg.o api_test.o kmain.o kernel/timer.o kernel/terminal.o  kernel/pic.o kernel/serial.o kernel/idt.o kernel/irq.o kernel/isrs.o \
                kernel/keyboard.o kernel/mouse.o kernel/panic.o kernel/paginga.o kernel/paging.o kernel/cpu.o kernel/cmos.o kernel/fpc.o kernel/rtc.o

run:
        @qemu-system-x86_64 -cdrom os.iso
An important note is that I create os.elf and os.bin . The ELF file is a normal 64-bit elf executable. os.bin is the binary version of os.elf. You then modify grub.cfg to use the bin file:
Code:
set timeout=10

menuentry "Gryphus" {
        echo Gryphus is loading. Please wait.
        multiboot /boot/os.bin
}

submenu "About GryphusOS..."{
        echo Gryphus aims to be a modern and an monolithic kernel.
        echo Maybe later I have more info to put here :D
        echo "Gitlab repo: gitlab.com/hextakatt/gryphus/"
        read
}
You also have to modify the linker script to create symbols that point to the needed memory locations required by a mulitboot AOUT kludge. I have also added * to .rodata and .text since it is possible for there to be a number of sections that start with .text and .rodata:
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)
        {
        __text_start = .;
                *(.multiboot)
                *(.text*)
        __text_end = .;
        }

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

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

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

        /* The compiler may produce other sections, by default it will put them in
           a segment with the same name. Simply add stuff here as needed. */
    /* Remove unnecessary sections */
    /DISCARD/ : {
        *(.eh_frame);
        *(.comment);
    }

}
You then have to modify bootg.asm so that it enables the AOUT kludge and provides the required extra fields with information the multiboot loader (GRUB) needs to parse the binary:
Code:
; Gryphus GRUB bootstrapper, hextakatt 2019

%include "gdt.inc"

global start
extern kernelmain
extern kputs
extern long_mode_start
extern __text_start
extern __data_end
extern __bss_end

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_AOUT_KLUDGE      equ 1 << 16
    MULTIBOOT_HEADER_MAGIC   equ 0x1BADB002
    MULTIBOOT_HEADER_FLAGS   equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE
    MULTIBOOT_CHECKSUM       equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)

    dd MULTIBOOT_HEADER_MAGIC
    dd MULTIBOOT_HEADER_FLAGS
    dd MULTIBOOT_CHECKSUM

    dd mboot
    dd __text_start
    dd __data_end
    dd __bss_end
    dd start

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
    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

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:
If you haven't already done so you should consider making the other bugfixes I mentioned in bootg2.asm:
Code:
; Gryphus GRUB bootstrapper, hextakatt 2019

global long_mode_start
extern kernelmain
bits 64
%include "idt.inc"
section .text
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

        call idt_load
        ; Push GRUB registers
    mov edi, ebx
    mov esi, eax

        ; Calls kernel entry point
        call kernelmain
        ; Jumps to the end routine, thats halts the system
        jmp end

; Suspends the processor, disable interrupts and halt CPU
end:
        ; Clear interrupts and halt the processor
    cli
    hlt


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sat Mar 23, 2019 5:59 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
Separate from the changes in the last post I made, I'm concerned you only have a 64 byte stack. Maybe you change it somewhere but a 64 byte stack isn't going to be sufficient in your kernel. Maybe I missed where you change from the bootstrap stack to a more permanent and larger one.

You have problems in your IDT structures (both idt_ptr and idt_entry). They should look like:
Code:
/* Defines an IDT entry */
struct idt_entry {
    uint16_t base_1;
    uint16_t sel;
    uint8_t zero;
    uint8_t flags;
    uint16_t base_2;
    uint32_t base_3;
    uint32_t zero2;
} __attribute__((packed));

struct idt_ptr {
    uint16_t limit;
    uint64_t base;
} __attribute__((packed));
Your versions are incorrectly laid out and will cause a crash on the first interrupt.

I didn't try figuring out your code but you have a line in cpu.c that is:
Code:
__get_cpuid(0, r->eax, &vendor[0], &vendor[8], &vendor[4]);
r->eax is not a pointer. Maybe you meant &r->eax although I'm unsure why you don't populate the vendor array with EAX like the other 3 parameters.

VERY IMPORTANT cannot stress this enough. You should be looking at every warning your compiler is outputting. I see a number of issues that could cause your software to fail. Don't ignore the warnings, they could be telling you something very important.


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

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
Thanks, now it boots, but it gets into an infinite int 0(division by zero exception), then finally gets into an triple fault.
At least it boots now, seems that I'm going in the right way.


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sat Mar 23, 2019 8:02 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
Yes I saw the div by zeroes when trying to get your kernel to a point of booting and executing kernelmain. BZT and I gave some hints on some of the problems in your IRQ handlers already, although I haven't investigated your failures besides trying to fix your IDT entry and IDT pointer structure. I felt that should be enough for you to feel like you are making progress but not take away from you trying to use a debugger to try and determine problems for yourself.


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

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
MichaelPetch wrote:
Yes I saw the div by zeroes when trying to get your kernel to a point of booting and executing kernelmain. BZT and I gave some hints on some of the problems in your IRQ handlers already, although I haven't investigated your failures besides trying to fix your IDT entry and IDT pointer structure. I felt that should be enough for you to feel like you are making progress but not take away from you trying to use a debugger to try and determine problems for yourself.

Doing some tests, I get that error when I enable interrupts. I'm gonna to check my interrupt handlers


Top
 Profile  
 
 Post subject: Re: Trying to port OS (IDT) to long mode
PostPosted: Sat Mar 23, 2019 11:01 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
Remember when calling C function in 64-bit code the first 6 parameters are passed in registers and not the stack. You may wish to review your interrupt code in idt.inc where you push parameters on the stack to call things like irq_handler. In kernel.h be aware that registers are now 64-bits wide (uint64_t) not 32-bits. You need to review and fix __system_stack. In __system_stack you have ESP in that structure but don't push it (it should be removed).You should rename all the fields with 64-bit register names. You should also be pushing r8,r9,r10,r11,r12,r13,r14,r15 in pushall and pop them all off in popall. Your __system_stack also has to match all the things you pushed before your interrupt handler is called. Be aware you have to pop in the reverse order you push. At the end of the interrupt handlers you need to add 16 to RSP (add rsp, 16) before the iretq instruction (rather than add rsp, 8 ) because each item (interrupt number and the error code) is 8 bytes wide (not 4).


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Amazonbot [bot], Bing [Bot] and 62 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