Multiboot with C instead of ASM.

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
whowhatwhere
Member
Member
Posts: 199
Joined: Sat Jun 28, 2008 6:44 pm

Multiboot with C instead of ASM.

Post by whowhatwhere »

Code: Select all

/* multiboot header structure  
   definition goes here 
   (modified for 64 bit) */

#define MB_MAGIC 0x1BADB002
#define MB_FLAGS 0x00000003 /* elf */
#define MB_CHECKSUM (-(MB_MAGIC + MB_FLAGS))

int kmain(void);

static multiboot_header_t 
mbheader __attribute__ ((packed))
         __attribute__ ((section(".mbheader") = 
{
    MB_MAGIC,
    MB_FLAGS,
    MB_CHECKSUM, 
...
    (unsigned long)&kmain,
...
};

int kmain(void) {
    for(;;)
    return 0;
}
...you get the picture. The reason for me doing this in this way is that I use GRUB2 and an Athlon64, so I don't need to bootstrap from 32 bit to 64 bit. As well, this allows some easier code cleanup (in my opinion, ASM is rarely "clean").
I can use a linker script to place ".mbheader" /near/ the beginning of the file, but not exactly there. For some reason, it is being offset. Could I possibly get some help in coming up with a linker script that does what I need?

Code: Select all

OUTPUT_FORMAT("elf64-x86-64")
OUTPUT_ARCH("i386:x86-64")
ENTRY(kmain)

SECTIONS 
{

}
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Multiboot with C instead of ASM.

Post by Solar »

Nice one. Though, when comparing this with Bare bones, I have two questions:

1) Is "__attribute__ ((packed)) __attribute__ ((section(".mbheader")))" really cleaner than 32 lines of commented ASM?

2) Where is your stack?
Every good solution is obvious once you've found it.
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Re: Multiboot with C instead of ASM.

Post by jal »

syntropy wrote:I can use a linker script to place ".mbheader" /near/ the beginning of the file, but not exactly there. For some reason, it is being offset.
Near is good enough, as the multiboot specs state that it must be somewhere within the first 8KB, 4 byte aligned.


JAL
whowhatwhere
Member
Member
Posts: 199
Joined: Sat Jun 28, 2008 6:44 pm

Re: Multiboot with C instead of ASM.

Post by whowhatwhere »

Solar wrote:Nice one. Though, when comparing this with Bare bones, I have two questions:

1) Is "__attribute__ ((packed)) __attribute__ ((section(".mbheader")))" really cleaner than 32 lines of commented ASM?

2) Where is your stack?
1) Probably not, which is why I've combined them to "__attribute__ ((packed,section(".mbheader"))". I just wanted to flesh things out for the sake of details.

2) I haven't got my entire source up there because there really is no point in including it. It's just a bit of 'dummy' code to show the entry point. [strike]My question was not about creating the stack nor anything else (GDT, IDT, etc.), but simply getting to a working C kmain() function.[/strike] I plan to use inline assembly for the other things on the way.

EDIT: I believe it is possible to create naked pre-init function that sets up a stack pointer using static (naked) functions, which the compiler does not add entry or exit routines, and I can use volatile inline assembly to push the appropriate registers and create a stack and valid stack pointer.

EDIT 2: I've managed to compile a test.

Code: Select all

#define MB_MAGIC 0x1BADB002 /* magic */
#define MB_FLAGS 0x00000003 /* elf */
#define MB_CKSUM (-(MB_MAGIC + MB_FLAGS))

#define SECTION(x) __attribute__ ((section(x)))
#define ALIGN(x)     __attribute__ ((aligned(x)))
#define NAKED        __attribute__ ((naked))
#define PACKED      __attribute__ ((packed))

typedef unsigned int __u32;
typedef struct mboot_s 
{
  __u32 magic;
  __u32 flags;
  __u32 checksum;
  __u32 header_addr;
  __u32 load_addr;
  __u32 load_end_addr;
  __u32 bss_end_addr;
  __u32 entry_addr;
  __u32 vid_modetype; /* full compliance */
  __u32 vid_width;
  __u32 vid_height;
  __u32 vid_depth;
} mboot_t;

mboot_t mbheader /*PACKED ALIGN(4) SECTION(".mbheader")*/ = {
    MB_MAGIC,   MB_FLAGS,   MB_CKSUM,
    0x00000000, 0x00000000, 0x00000000,
    0x00000000, 0x00000000, 0x00000000,
    0x00000000, 0x00000000, 0x00000000
};

unsigned int kmain(void)
{
    return 0;
}
If I compiled the kernel with '-Ttext=0x100000 -m32' (32 bit), mbchk reports the multiboot header is at byte 4128. If I compile it as 64 bit (just '-Ttext=0x100000'), mbchk reports that no header was found. Upon manual diagnosis of the binary, in 64 bit mode, the file offset is 0x2000 or 8192 (iirc) and therefore above the 8K mark. How can I compile this to 64 bit without breaking the 8K barrier or the ELF binary structure?


EDIT3: Fixed everything up using a linker script that places .mbheader at 0x200. Mbchk says it's perfect. =)
Post Reply