Page 1 of 1

Linking per-CPU variables to a special area?

Posted: Mon Mar 21, 2016 7:01 am
by mariuszp
My kernel is a flat binary with a multiboot header (mainly because it has a 32-bit glue followed by 64-bit code).

I am using the following linker script at the moment:

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(_start)
phys = 0xFFFF800000100000;

SECTIONS
{
	.text phys : AT(phys) {
		code = .;
		*(.bootstrap32)
		*(.text)
		*(.rodata)
		. = ALIGN(4096);
	}

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

	.bss (phys + (bss - code)) : AT(phys + (bss - code))
	{
		bss = .;
		*(.bss)
		. = ALIGN(4096);
		end = .;
	}
}
My idea of per-CPU variables would be to put them in a specific section called "data_per_cpu", and have that section linked such that it is at 0xFFFF828000000000 (that's PML4 entry 261). This way, each CPU would have its own copy of the PML4, each having this specific area of memory mapped to a different physical location, hence having per-CPU variables.

However, if I try to put this section inside the ".bss" above, like so:

Code: Select all

. = 0xFFFF828000000000;
_per_cpu_start = .;
*(.data_per_cpu)
_per_cpu_end = .;
The linker tries to fill the entire area from the end of BSS all the way up to 0xFFFF828000000000 with zeores; and that is a good few terabytes of data, so it obviously doesn't work.

Can I somehow force the linker not to put any zeroes or other data in that area, but instead simply relocate references to within the per_cpu_data section to match those addresses?

Re: Linking per-CPU variables to a special area?

Posted: Mon Mar 21, 2016 7:31 am
by Velko
Do not place it inside .bss then. Place it in dedicated section. What about (did not test, based on your linker script):

Code: Select all

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

   . = 0xFFFF828000000000;
   .per_cpu_bss ((phys + (_per_cpu_start - code)) : AT(phys + (_per_cpu_start - code)))
   {
      _per_cpu_start = .;
      *(.data_per_cpu)
      _per_cpu_end = .;
   }
}
Running kernel does not care what was linked to which section. Only VMA addresses matter. And if you use flat binary, bootloader does not know anything about sections either.

Re: Linking per-CPU variables to a special area?

Posted: Mon Mar 21, 2016 7:59 am
by mariuszp
I know that neither the kernel nor the bootloader care about what went into each section; the only reason to put per-cpu variables in a special section is so that the virtual addresses are in an area that can be mapped to a different physical location on each CPU.

Re: Linking per-CPU variables to a special area?

Posted: Mon Mar 21, 2016 8:51 am
by iansjack
Flat binaries just make life more difficult. I would highly recommend using Elf-format files.

Re: Linking per-CPU variables to a special area?

Posted: Fri Mar 25, 2016 10:43 am
by mariuszp
I have tried linking it using that script snippet, but it generates a 1.7 TB file.

However, the ".bss" section is never placed in the flat binary. Do I have to somehow tell the linker that ".data_per_cpu" is a BSS section, such that it does not try to actually put it in the binary?

Re: Linking per-CPU variables to a special area?

Posted: Fri Mar 25, 2016 10:55 am
by mariuszp
Ah, I got it. The trick was:

Code: Select all

	. = 0xFFFF828000000000;
	_per_cpu_start = .;
	.per_cpu_bss (phys + (_per_cpu_start - code)) (NOLOAD) : AT(phys + (_per_cpu_start - code))
	{
		*(.data_per_cpu)
   	}
   	_per_cpu_end = .;