From 2773606466643c3b301fa818f334e1218012b183 Mon Sep 17 00:00:00 2001 From: Taku Shimosawa Date: Mon, 7 Nov 2011 00:48:22 +0900 Subject: [PATCH] Kernel runs in the higher address space --- kboot/Makefile | 27 ++++++++ kboot/data.S | 9 +++ kboot/kernel.lds.S | 34 ++++++++++ kboot/main.c | 132 +++++++++++++++++++++++++++++++++++++ kernel/Makefile.build | 2 +- kernel/ap.c | 2 - kernel/configs/config.knf | 1 + kernel/knf.lds | 2 +- kernel/mee.lds | 2 +- kernel/scripts/mkimage.knf | 10 +++ kernel/scripts/mkimage.mee | 9 ++- 11 files changed, 224 insertions(+), 6 deletions(-) create mode 100644 kboot/Makefile create mode 100644 kboot/data.S create mode 100644 kboot/kernel.lds.S create mode 100644 kboot/main.c create mode 100644 kernel/scripts/mkimage.knf diff --git a/kboot/Makefile b/kboot/Makefile new file mode 100644 index 00000000..312ffb7e --- /dev/null +++ b/kboot/Makefile @@ -0,0 +1,27 @@ +DEST=$(O)/kboot +OBJS=$(DEST)/main.o $(DEST)/data.o +CFLAGS=-mno-sse -mno-mmx -mno-sse2 -mno-3dnow + +$(if $(O),,$(error Specify the target directory)) + +$(DEST)/kboot.elf: $(DEST) $(DEST)/kernel.lds $(OBJS) + @$(LD) $(LDFLAGS) -o $@ -T $(DEST)/kernel.lds -nostdlib $(OBJS) + +$(DEST)/%.o: %.c + @$(CC) $(CFLAGS) -c -o $@ -O3 $< + +$(DEST)/data.o: data.S + @$(CC) -c -o $@ -O3 -DKIMAGE='"$(KIMAGE)"' $^ + +$(DEST)/kernel.lds: kernel.lds.S + $(if $(LOAD_PA),,$(error Specify the loading physical address)) + @$(CC) -E -P -DLOAD_PA=$(LOAD_PA) -o $@ $< + +$(DEST): + @mkdir -p $(DEST) + +clean: + @$(RM) $(DEST)/* + +.PHONY: clean + diff --git a/kboot/data.S b/kboot/data.S new file mode 100644 index 00000000..855094e0 --- /dev/null +++ b/kboot/data.S @@ -0,0 +1,9 @@ +#ifndef KIMAGE +#error "No kernel image is specified" +#endif + +.data +.globl data_start +data_start: +.incbin KIMAGE + diff --git a/kboot/kernel.lds.S b/kboot/kernel.lds.S new file mode 100644 index 00000000..8b14fc57 --- /dev/null +++ b/kboot/kernel.lds.S @@ -0,0 +1,34 @@ +ENTRY(main) +PHDRS +{ + text PT_LOAD FLAGS(5); + data PT_LOAD FLAGS(7); +} +SECTIONS +{ + . = LOAD_PA; + _head = .; + + .text : { + *(.text); + } : text + + . = ALIGN(4096); + .data : { + *(.data) + *(.data.*) + } :data + .rodata : { + *(.rodata .rodata.*) + } :data + .bss : { + *(.bss .bss.*) + } + . = ALIGN(4096); + data_end = .; + + /DISCARD/ : { + *(.eh_frame) + *(.note.gnu.build-id) + } +} diff --git a/kboot/main.c b/kboot/main.c new file mode 100644 index 00000000..399c9c72 --- /dev/null +++ b/kboot/main.c @@ -0,0 +1,132 @@ +#include + +extern char data_start[], data_end[]; + +#define LARGE_PAGE_SIZE (1UL << 21) +#define LARGE_PAGE_MASK (~((unsigned long)LARGE_PAGE_SIZE - 1)) + +#define MAP_ST_START 0xffff800000000000UL +#define MAP_KERNEL_START 0xffffffff80000000UL + +#define PTL4_SHIFT 39 +#define PTL3_SHIFT 30 +#define PTL2_SHIFT 21 + +unsigned long page_tables[3][512] __attribute__((aligned(4096))); + +static void *memcpy(void *dest, void *src, unsigned long len) +{ + char *d = dest, *s = src; + + for ( ; len ; len--) { + *(d++) = *(s++); + } + + return d; +} +static void *memset(void *dest, int v, unsigned long len) +{ + char *d = dest; + + for ( ; len ; len--) { + *(d++) = (char)v; + } + + return d; +} + +void memzerol(unsigned long *p, unsigned long size) +{ + unsigned long i; + + size /= sizeof(unsigned long); + + for (i = 0; i < size; i++) { + p[i] = 0; + } +} + +static unsigned long load_programs(unsigned char *image, Elf64_Phdr *hdrs, + int nhdr, unsigned long offset) +{ + int i; + unsigned long end = MAP_KERNEL_START; + + for (i = 0; i < nhdr; i++) { + if (hdrs[i].p_type == PT_LOAD) { + memcpy((void *)(hdrs[i].p_vaddr - offset), + image + hdrs[i].p_offset, + hdrs[i].p_filesz); + if (hdrs[i].p_filesz < hdrs[i].p_memsz) { + memset((void *)(hdrs[i].p_vaddr + + hdrs[i].p_filesz - offset), 0, + hdrs[i].p_memsz - hdrs[i].p_filesz); + } + if (end < hdrs[i].p_vaddr + hdrs[i].p_memsz) { + end = hdrs[i].p_vaddr + hdrs[i].p_memsz; + } + } + } + + return end; +} + +/* + * Return value: If success, the entry point address. Otherwise, 0. + */ +unsigned long load_elf(unsigned char *image, unsigned long offset) +{ + Elf64_Ehdr *hdr = (Elf64_Ehdr *)image; + + if (hdr->e_ident[0] != 0x7f || hdr->e_ident[1] != 'E' + || hdr->e_ident[2] != 'L' || hdr->e_ident[3] != 'F') { + return 0; + } + /* TODO: We may overlap. So copying should be more sophisticated */ + if (!hdr->e_phoff || hdr->e_phentsize != sizeof(Elf64_Phdr)) { + return 0; + } + return load_programs(image, + (Elf64_Phdr *)(image + hdr->e_phoff), hdr->e_phnum, + offset); +} + +void main(unsigned long param) +{ + /* Assume phys == virt */ + unsigned long load_address, end, *org_cr3; + unsigned long i, n; + Elf64_Ehdr *hdr; + void (*entry)(unsigned long param, unsigned long load_address); + + load_address = (unsigned long)data_end; + load_address = (load_address + LARGE_PAGE_SIZE - 1) & LARGE_PAGE_MASK; + + asm volatile("movq %%cr3, %0" : "=r"(org_cr3)); + + memzerol((unsigned long *)page_tables, sizeof(page_tables)); + + page_tables[0][0] = org_cr3[0]; + page_tables[0][(MAP_ST_START >> PTL4_SHIFT) & 511] = org_cr3[0]; + page_tables[0][(MAP_KERNEL_START >> PTL4_SHIFT) & 511] = + ((unsigned long)page_tables[1]) | 3; + page_tables[1][(MAP_KERNEL_START >> PTL3_SHIFT) & 511] = + ((unsigned long)page_tables[2]) | 3; + + end = load_elf(data_start, MAP_KERNEL_START - load_address); + + /* map 4MB more in case */ + n = (end - MAP_KERNEL_START + (1 << PTL2_SHIFT) - 1) >> PTL2_SHIFT; + n += 2; + + for (i = 0; i < n; i++) { + page_tables[2][i] = (load_address + (i << PTL2_SHIFT)) | 0x83; + } + + hdr = (Elf64_Ehdr *)data_start; + + asm volatile("movq %0, %%cr3" : : "r"(page_tables) : "memory"); + + entry = (void *)hdr->e_entry; + entry(param, load_address); +} diff --git a/kernel/Makefile.build b/kernel/Makefile.build index 1d318aec..da438fc4 100644 --- a/kernel/Makefile.build +++ b/kernel/Makefile.build @@ -12,7 +12,7 @@ AALOBJ = aal/aal.o SUBCMD_OPTS = TARGET=$(TARGET) O=$(CURDIR)/aal CC=$(CC) LD=$(LD) ld_kern_cmd_base = $(LD) $(LDFLAGS) -o $@.elf $^ -mkimage_cmd_base = [ -f $(SRC)/scripts/mkimage.$(TARGET) ] && sh $(SRC)/scripts/mkimage.$(TARGET) '$@.elf' '$@' '$(SRC)' || cp $@.elf $@ +mkimage_cmd_base = [ -f $(SRC)/scripts/mkimage.$(TARGET) ] && CC=$(CC) LD=$(LD) LDFLAGS="$(LDFLAGS_MKIMAGE)" sh $(SRC)/scripts/mkimage.$(TARGET) '$@.elf' '$@' '$(SRC)' || cp $@.elf $@ ld_kern_cmd = $(call echo_cmd,LDKERN,$@)$(ld_kern_cmd_base) mkimage_cmd = $(call echo_cmd,MKIMAGE,$@)$(mkimage_cmd_base) diff --git a/kernel/ap.c b/kernel/ap.c index 761c8153..edce3a92 100644 --- a/kernel/ap.c +++ b/kernel/ap.c @@ -9,8 +9,6 @@ static volatile int ap_stop = 1; void ap_idle(void) { - int id = aal_mc_get_hardware_processor_id(); - while (1) { cpu_halt(); } diff --git a/kernel/configs/config.knf b/kernel/configs/config.knf index eda458bc..22a25c52 100644 --- a/kernel/configs/config.knf +++ b/kernel/configs/config.knf @@ -3,3 +3,4 @@ LD = /home/shimosawa/cross.knf/bin/x86_64-l1om-linux-ld CFLAGS += -mno-sse -mno-mmx -mno-sse2 -mno-3dnow LDFLAGS += -m elf_l1om -T $(SRC)/knf.lds +LDFLAGS_MKIMAGE = -m elf_l1om diff --git a/kernel/knf.lds b/kernel/knf.lds index 48a6be6c..c8edd0fe 100644 --- a/kernel/knf.lds +++ b/kernel/knf.lds @@ -5,7 +5,7 @@ PHDRS } SECTIONS { - . = 0x401000; + . = 0xffffffff80001000; _head = .; .text : { diff --git a/kernel/mee.lds b/kernel/mee.lds index 69c3ad2a..c8edd0fe 100644 --- a/kernel/mee.lds +++ b/kernel/mee.lds @@ -5,7 +5,7 @@ PHDRS } SECTIONS { - . = 0x40001000; + . = 0xffffffff80001000; _head = .; .text : { diff --git a/kernel/scripts/mkimage.knf b/kernel/scripts/mkimage.knf new file mode 100644 index 00000000..155e0a3f --- /dev/null +++ b/kernel/scripts/mkimage.knf @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +O=`pwd` + +make -C $3/../kboot O=$O clean +make -C $3/../kboot O=$O KIMAGE="$O/$1" LOAD_PA=0x401000 CC=${CC} LD=${LD} LDFLAGS="${LDFLAGS}" + +cp kboot/kboot.elf $2 diff --git a/kernel/scripts/mkimage.mee b/kernel/scripts/mkimage.mee index 1d9f234e..d503c8ef 100644 --- a/kernel/scripts/mkimage.mee +++ b/kernel/scripts/mkimage.mee @@ -1,3 +1,10 @@ #!/bin/sh -cat $3/../elfboot/elfboot $1 > $2 +set -e + +O=`pwd` + +make -C $3/../kboot O=$O clean +make -C $3/../kboot O=$O KIMAGE="$O/$1" LOAD_PA=0x3a001000 + +cat $3/../elfboot/elfboot kboot/kboot.elf > $2