Page 1 of 1

need help with 'hello world' kernel

Posted: Mon Jun 11, 2007 9:32 am
by 13postures
Hi,

I'm trying to boot this 'hello world' kernel as a native elf64 image using Grub2.

It consists of 3 files: boot.S, kernel.c and multiboot.h. The file 'kernel.c' is taken from the sample kernel provided from the Multiboot Specification (http://www.gnu.org/software/grub/manual ... le-OS-code).

boot.S:

Code: Select all

#include "multiboot.h"
.globl _start

_start:
	jmp	multiboot_entry

	/* Multiboot header.  */
	.align	4
	.long	MULTIBOOT_HEADER_MAGIC
	.long	MULTIBOOT_HEADER_FLAGS
	.long	-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)

multiboot_entry:
	/* set up stack */
	movq	$(stack + STACK_SIZE), %rsp
	call cmain

	.comm	stack, STACK_SIZE
multiboot.h:

Code: Select all

/* The magic number for the Multiboot header.*/
#define MULTIBOOT_HEADER_MAGIC		0x1BADB002
/* The flags for the Multiboot header.  */
# define MULTIBOOT_HEADER_FLAGS		0x00000000
#define STACK_SIZE			0x8000
kernel.c:

Code: Select all

#include "multiboot.h"

/* Some screen stuff.  */
/* The number of columns.  */
#define COLUMNS			80
/* The number of lines.  */
#define LINES			24
/* The attribute of an character.  */
#define ATTRIBUTE		7
/* The video memory address.  */
#define VIDEO			0xB8000

/* Variables.  */
/* Save the X position.  */
static int xpos;
/* Save the Y position.  */
static int ypos;
/* Point to the video memory.  */
static volatile unsigned char *video;

/* Forward declarations.  */
void cmain ();
static void cls (void);
static void itoa (char *buf, int base, int d);
static void putchar (int c);
void printf (const char *format, ...);

/* Check if MAGIC is valid and print the Multiboot information structure
   pointed by ADDR.  */
void
cmain ()
{
  cls();
  printf ("HELLO WORLD\n");
}    

/* Clear the screen and initialize VIDEO, XPOS and YPOS.  */
static void
cls (void)
{
  int i;

  video = (unsigned char *) VIDEO;
  
  for (i = 0; i < COLUMNS * LINES * 2; i++)
    *(video + i) = 0;

  xpos = 0;
  ypos = 0;
}

/* Convert the integer D to a string and save the string in BUF. If
   BASE is equal to 'd', interpret that D is decimal, and if BASE is
   equal to 'x', interpret that D is hexadecimal.  */
static void
itoa (char *buf, int base, int d)
{
  char *p = buf;
  char *p1, *p2;
  unsigned long ud = d;
  int divisor = 10;
  
  /* If %d is specified and D is minus, put `-' in the head.  */
  if (base == 'd' && d < 0)
    {
      *p++ = '-';
      buf++;
      ud = -d;
    }
  else if (base == 'x')
    divisor = 16;

  /* Divide UD by DIVISOR until UD == 0.  */
  do
    {
      int remainder = ud % divisor;
      
      *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10;
    }
  while (ud /= divisor);

  /* Terminate BUF.  */
  *p = 0;
  
  /* Reverse BUF.  */
  p1 = buf;
  p2 = p - 1;
  while (p1 < p2)
    {
      char tmp = *p1;
      *p1 = *p2;
      *p2 = tmp;
      p1++;
      p2--;
    }
}

/* Put the character C on the screen.  */
static void
putchar (int c)
{
  if (c == '\n' || c == '\r')
    {
    newline:
      xpos = 0;
      ypos++;
      if (ypos >= LINES)
	ypos = 0;
      return;
    }

  *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF;
  *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE;

  xpos++;
  if (xpos >= COLUMNS)
    goto newline;
}

/* Format a string and print it on the screen, just like the libc
   function printf.  */
void
printf (const char *format, ...)
{
  char **arg = (char **) &format;
  int c;
  char buf[20];

  arg++;
  
  while ((c = *format++) != 0)
    {
      if (c != '%')
	putchar (c);
      else
	{
	  char *p;
	  
	  c = *format++;
	  switch (c)
	    {
	    case 'd':
	    case 'u':
	    case 'x':
	      itoa (buf, c, *((int *) arg++));
	      p = buf;
	      goto string;
	      break;

	    case 's':
	      p = *arg++;
	      if (! p)
		p = "(null)";

	    string:
	      while (*p)
		putchar (*p++);
	      break;

	    default:
	      putchar (*((int *) arg++));
	      break;
	    }
	}
    }
}
When i build and boot this simple kernel, Grub2 reports 'error: could not read segment'.

Any thoughts/advices/solutions?

Posted: Mon Jun 11, 2007 10:46 am
by jnc100
I have no experience with grub2, but the I wonder whether it only supports elf64 images that contain the new Multiboot header. Specifically, the header must now be aligned on a 64-bit boundary (still within the first 8kiB) and the magic number is now 0xe85250d6.

Other than that, I'm not sure. Are you sure your particular version of grub2 supports elf64? What commands/linker script are you using?

Regards,
John.

Posted: Mon Jun 11, 2007 12:27 pm
by Franchie
jnc100 wrote:I have no experience with grub2, but the I wonder whether it only supports elf64 images that contain the new Multiboot header. Specifically, the header must now be aligned on a 64-bit boundary (still within the first 8kiB) and the magic number is now 0xe85250d6.
They have probably updated their 'mbchk' tool, and running it may give a good indication of what (if anything) is wrong with the multiboot header.
However, it does not appear to be a multiboot header problem, since I recollect that it specifically complains about the absence of one (rather than this rather obscure error).

So, is this a problem with the image, or the actual loading from disk?
Sorry I can't really help more here...
Franchie.

Posted: Mon Jun 11, 2007 12:42 pm
by jnc100
Its amazing what google produces...

Firstly http://www.mail-archive.com/grub-devel@ ... 02917.html says that despite the new draft, grub2 still actually looks for 0x1badb002

Secondly http://www.mail-archive.com/grub-devel@ ... 02691.html contains a patch dated 18 Apr 2007 against grub2 which specifically fixes the problem you're having, assuming your kernel is actually a valid elf64 multiboot-compliant kernel. It has been applied to the grub2 cvs but maybe you have an earlier release?

Regards,
John.

Posted: Mon Jun 11, 2007 1:31 pm
by 13postures
jnc100 wrote:Its amazing what google produces...

Firstly http://www.mail-archive.com/grub-devel@ ... 02917.html says that despite the new draft, grub2 still actually looks for 0x1badb002
That's right. A simple "grep 'e85250d6' * -r" produces absolutely nothing. Not to mention that grub2 expects the header to be 4-byte aligned EVEN when loading elf64. Take a look at this from grub2/loader/i386/pc/multiboot.c (inside function grub_rescue_cmd_multiboot):

Code: Select all

  /* Look for the multiboot header in the buffer.  The header should
     be at least 12 bytes and aligned on a 4-byte boundary.  */
  for (header = (struct grub_multiboot_header *) buffer; 
       ((char *) header <= buffer + len - 12) || (header = 0);
       header = (struct grub_multiboot_header *) ((char *) header + 4))
    {
      if (header->magic == GRUB_MB_MAGIC 
	  && !(header->magic + header->flags + header->checksum))
	break;
    }
jnc100 wrote:Secondly http://www.mail-archive.com/grub-devel@ ... 02691.html contains a patch dated 18 Apr 2007 against grub2 which specifically fixes the problem you're having, assuming your kernel is actually a valid elf64 multiboot-compliant kernel. It has been applied to the grub2 cvs but maybe you have an earlier release?
I wasn't aware of that patch. I doesn't matter though, because i have downloaded and installed a cvs version of grub2 so it is fixed. I double checked the source code to be sure.

Lately i'm wondering if grub2 can set up long mode or i have to do it manually. I have browsed the source and have found nothing that could mean setting up the long mode. However, i'm not a grub2 expert, so i might be mistaken.

The thing i know for sure is the cause of the error message.

grub2/loader/i386/pc/multiboot.c (inside function grub_multiboot_load_elf64, line 210):

Code: Select all

	  if (grub_file_read (file, (void *) ((grub_uint32_t) phdr->p_paddr),
			      phdr->p_filesz)
              != (grub_ssize_t) phdr->p_filesz)
	    return grub_error (GRUB_ERR_BAD_OS,
			       "couldn't read segment from file");

Posted: Mon Jun 11, 2007 2:43 pm
by jnc100
The current grub2 cvs does not, according to grep, contain the phrase 'cr3' therefore I assume it doesn't enable paging which is a prerequisite of long mode. There was another discussion on this topic where an alternative view was put, however.

Regards,
John.

Posted: Tue Jun 12, 2007 3:25 am
by 13postures
Yes, i have followed that discussion. However, quok doesn't seem to give any feedback on the matter.