bkerndev 16kb+ problem

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

bkerndev 16kb+ problem

Post by Martius »

hi there,
i've done this great tutorial: http://osdever.net/bkerndev/index.php?the_id=90
and i've built a nice and small kernel now, but i have a problem:
as soon as the kernel gets larger than 16 kb, grub does no longer want to boot it

after hours of searching i found that the multibootheader in start.asm caused the problem, because bit 0 is set in it:

Code: Select all

MULTIBOOT_PAGE_ALIGN   equ 1<<0 ; align loaded modules on page boundaries
that means the code modules must stay within the page (4kb) boundaries to let grub load it, but i want to build a kernel larger than those 16kb's actually.
how do i solve it? do i need to set up paging myself? or are there any other solutions?
AR

Re:bkerndev 16kb+ problem

Post by AR »

I doubt that is the cause of your problem. GRUB does not set up paging for you, page align is there to make it easier for you to setup paging.
Tora OS

Re:bkerndev 16kb+ problem

Post by Tora OS »

I used the same tutorial to start from and my kernel is 18 kb....

I dont think grub is the problem child here. Otherwise minilinux or whatever it is called woudnt boot. (i dont think...)
mystran

Re:bkerndev 16kb+ problem

Post by mystran »

The alignment bit is only to tell GRUB that each module should start from a 4kb boundary. That's all it does. Modules (and kernel) can be of any size, as long as they fit in memory.
Martius

Re:bkerndev 16kb+ problem

Post by Martius »

So you guys say I'm wrong :P

Maybe this can help a bit:
This is the kernel entry point. Everything works fine. I've tested the divide by Zero Exception. And the keyboard and timer in the C-code work great.
But as I told if I make the kernel larger than 16 kb (by printing very much gibberish to the screen with main.c) it doesn't work anymore.
Is that the problem? That I try to fill the 16k's with text and not with code?
Well here's the code anyway:

Code: Select all

; start.asm
[BITS 32]
global start
start:
    mov esp, _sys_stack     ; This points the stack to our new stack area
    jmp stublet

ALIGN 4
mboot:
    MULTIBOOT_PAGE_ALIGN   equ 1<<0 ; align loaded modules on page boundaries
    MULTIBOOT_MEMORY_INFO   equ 1<<1 ; provide memory map
    MULTIBOOT_AOUT_KLUDGE   equ 1<<16
    MULTIBOOT_HEADER_MAGIC   equ 0x1BADB002 ; 'magic number' lets bootloader find the header
    MULTIBOOT_HEADER_FLAGS   equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE ; this is the Multiboot 'flag' field
    MULTIBOOT_CHECKSUM   equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
    EXTERN code, bss, end

    dd MULTIBOOT_HEADER_MAGIC
    dd MULTIBOOT_HEADER_FLAGS
    dd MULTIBOOT_CHECKSUM
    
    ; AOUT kludge - must be physical addresses. Make a note of these:
    ; The linker script fills in the data for these ones!
    dd mboot
    dd code
    dd bss
    dd end
    dd start

stublet:
    extern _main
    call _main
    jmp $

; This will set up our new segment registers. We need to do
; a far jump order to set CS.
; This is declared in C as 'extern void gdt_flush();'
global _gdt_flush
extern _gp
_gdt_flush:
    lgdt [_gp]
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    jmp 0x08:flush2
flush2:
    ret

; Loads the IDT defined in '_idtp' into the processor.
; This is declared in C as 'extern void idt_load();'
global _idt_load
extern _idtp
_idt_load:
    lidt [_idtp]
    ret

global _isr0
;.... etc. (to _isr31)

;  0: Divide By Zero Exception
_isr0:
    cli
    push byte 0
    push byte 0
    jmp isr_common_stub
;.... etc.

extern _fault_handler

; This is our common ISR stub. It saves the processor state, sets
; up for kernel mode segments, calls the C-level fault handler,
; and finally restores the stack frame.
isr_common_stub:
    pusha
    push ds
    push es
    push fs
    push gs
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp
    push eax
    mov eax, _fault_handler
    call eax
    pop eax
    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret

global _irq0
;.... etc. (to _irq15)

; 32: IRQ0
_irq0:
    cli
    push byte 0
    push byte 32
    jmp irq_common_stub
;.... etc.

extern _irq_handler

irq_common_stub:
    pusha
    push ds
    push es
    push fs
    push gs

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp

    push eax
    mov eax, _irq_handler
    call eax
    pop eax

    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret

; Here is the definition of our BSS section. Right now, we'll use
; it just to store the stack. Remember that a stack actually grows
; downwards, so we declare the size of the data before declaring
; the identifier '_sys_stack'
SECTION .bss
    resb 8192               ; This reserves 8KBytes of memory here
_sys_stack:
and this is the linker script:

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x0100000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}
I've tried to change the 'phys' in the linkerscript and to align the sections with words like 8192.
But as soon as I change the ALIGN in .text to a greater value than 4096. Grub says: Error 13 invalid or unsupported executable format.

-Can I change something in the linkerscript to solve it. Like the 'phys'. Or should I change the stacksize in the kernel entry point.

-Can someone explain to me what the sections actually mean and what they're for.

-I use GRUB 0.94 and I use DJGPP 2.03

-@ Tora OS: Do you dev on Win32 or not? :P Maybe it's just m$ that causes the problem :P
Martius

Re:bkerndev 16kb+ problem

Post by Martius »

one thing I forgot to say is that I'm using Bochs 2.02
I don't think that has any effect on the process, because when I boot a floppy with my computer GRUB gives the same error
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:bkerndev 16kb+ problem

Post by Solar »

Yes I know I'm cherry-picking. ;)
Martius wrote: -Can someone explain to me what the sections actually mean and what they're for.
.text holds your executable code.

.data holds values you use to initialize local variables (like the MULTIBOOT_* ones in your start.asm).

.bss is not actually part of your binary, but a number that tells the loader how much reserved, zero-initialized space your binary is requesting. (Your stack, for example.)

First thing you should do is adding *(.rodata) to your .text section. .rodata holds what global constants are initialized to; even if you don't need it now you will need it later.

Sorry that I'm only answering the easiest part of your question, but I don't have the time to delve into code details ATM. But I don't think it has something to do with alignment, either.
Every good solution is obvious once you've found it.
AR

Re:bkerndev 16kb+ problem

Post by AR »

You're wrong there Solar, assembly does exactly what it's told the MULTIBOOT_* are part of .text as he hasn't explicitly put SECTION .data, without explicitly saying .data everything ends up in .text.

The only thing I've noticed so far is that you haven't externed all the linker variables used to make the multiboot header.

Try generating a link map for the kernel to see what values it fills in for the a.out kludge (ld .... -Map LinkMap.txt ....)

Edit: You also mentioned using strings? Add *(.rodata*) to the .text section of the linkscript
Martius

Re:bkerndev 16kb+ problem

Post by Martius »

I've added the *(.rodata*) right after *(.text) as grub-how.txt says. But it also says that that *(.rodata*) is an ELF read-only data section(s) and I use the a.out format. And when I make a linkmap it only says . = ALIGN (0x1000) at the *(.rodata*).
Even If I put many printf's in main.c.
The problem with using ELF is that ld doesn't understand the elf format from NASM.

First I'm going to add functionality to the kernel. And I hope that only pure text and not code is stressing GRUB.
AR

Re:bkerndev 16kb+ problem

Post by AR »

GRUB doesn't read the binary, once it has the multiboot header it simply interprets it and relocates the kernel accordingly, can you post the whole linkmap? (You do not need to ask NASM for ELFs, LD can understand other INPUT formats, ELF is only the OUTPUT)
Martius

Re:bkerndev 16kb+ problem

Post by Martius »

The linkmaps were too large for this messagebox
You can find them here:
http://home.wanadoo.nl/frank.silvis/LinkMaps.txt

Thanks for all the replies yet :D
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:bkerndev 16kb+ problem

Post by Solar »

AR wrote: You're wrong there Solar, assembly does exactly what it's told the MULTIBOOT_* are part of .text as he hasn't explicitly put SECTION .data, without explicitly saying .data everything ends up in .text.
Yes, but it's the next best thing to a variable initialization seeing as there isn't any C code to comment on. ;)
Every good solution is obvious once you've found it.
AR

Re:bkerndev 16kb+ problem

Post by AR »

I still can't see what exactly is wrong but I have noticed another misc problem, COMMON is not accounted for by your linkscript so is being created after the BSS, add *(COMMON) to the .bss section.
Martius

Re:bkerndev 16kb+ problem

Post by Martius »

I've done that now:

.bss : AT(phys + (bss - code))
{
bss = .;
*(.bss)
*(COMMON)
. = ALIGN(4096);
}
AR

Re:bkerndev 16kb+ problem

Post by AR »

What binary format are using in NASM? Did you try EXTERN-ing all the mutliboot header values?

I'm afraid I'm out of ideas, whatever it is doesn't seem very obvious.
Post Reply