Skip to content

Commit

Permalink
Fixes to get x64 booting via UEFI.
Browse files Browse the repository at this point in the history
Most of the work was in fixing up elfconv and the x64 linker script to get
things just lined up so. Overall this conversion thing is pretty fragile,
but given that there's not a lot more that really needs to go into the boot
manager it seems fine for now. Perhaps a better solution would be to see
if binutils could be configured with an additional target to create these
types of files directly.

There were also a couple changes to the assembly, where the @GOTPCREL
register needs to be dereferenced to get the value of the variable.

Finally, I had to add a prefix to the boot manager PCAT build, and stop
reusing bootman.o and bootim.o. This is because in PCAT builds, those are
compiled in 32-bit mode, whereas in the EFI boot manager those are 64-bit
object files.

I wasn't able to fully test the mingen build, because I hit the
strict-aliasing IPv6 compiler errors. I'll fix those sometime soon.

The system now boots, albeit a bit slowly due apparently to hammering the
disk, via x64 UEFI on VMWare.
  • Loading branch information
evangreen committed Sep 2, 2017
1 parent 8f19bff commit 3feb1c4
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 159 deletions.
7 changes: 4 additions & 3 deletions boot/bootman/build.ck
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ function build() {

pcatSources = [
"pcat/x86/entry.S",
":bootman.o",
":bootim.o",
"bootman.c",
"bootim.c",
"pcat/bootxfr.c",
"pcat/main.c",
"pcat/paging.c"
Expand Down Expand Up @@ -187,7 +187,8 @@ function build() {
"includes": includes,
"config": pcatConfig,
"text_address": "0x100000",
"binplace": "bin"
"binplace": "bin",
"prefix": "pcat"
};

entries += staticApplication(pcatApp);
Expand Down
1 change: 1 addition & 0 deletions boot/bootman/efi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ endif

ifeq ($(ARCH), x64)
LINKER_SCRIPT = $(SRCROOT)/os/uefi/include/link_x64.x
LDFLAGS += -Wl,-zmax-page-size=1
endif

ifeq ($(ARCH), armv7)
Expand Down
98 changes: 63 additions & 35 deletions boot/lib/efi/x64/efia.S
Original file line number Diff line number Diff line change
Expand Up @@ -95,23 +95,30 @@ Return Value:
FUNCTION(BopEfiSaveInitialState)
xorl %eax, %eax # Zero rax.
movw %cs, %ax # Get CS.
movl %eax, BoFirmwareCs@GOTPCREL(%rip) # Save CS.
movq BoFirmwareCs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save CS.
movw %ds, %ax # Get DS.
movl %eax, BoFirmwareDs@GOTPCREL(%rip) # Save DS.
movq BoFirmwareDs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save DS.
movw %es, %ax # Get ES.
movl %eax, BoFirmwareEs@GOTPCREL(%rip) # Save ES.
movq BoFirmwareEs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save ES.
movw %fs, %ax # Get FS.
movl %eax, BoFirmwareFs@GOTPCREL(%rip) # Save FS.
movq BoFirmwareFs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save FS.
movw %gs, %ax # Get GS.
movl %eax, BoFirmwareGs@GOTPCREL(%rip) # Save GS.
movq BoFirmwareGs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save GS.
movw %ss, %ax # Get SS.
movl %eax, BoFirmwareSs@GOTPCREL(%rip) # Save SS.
movq BoFirmwareSs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save SS.
pushfq # Push rflags.
popq %rax # Pop RAX.
movq %rax, BoFirmwareRflags@GOTPCREL(%rip) # Save eflags.
leaq BoFirmwareIdt@GOTPCREL(%rip), %rax # Get the IDT save address.
movq BoFirmwareRflags@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save RFLAGS.
movq BoFirmwareIdt@GOTPCREL(%rip), %rax # Get the IDT save address.
sidt (%rax) # Save the IDT.
leaq BoFirmwareGdt@GOTPCREL(%rip), %rax # Get the GDT save address.
movq BoFirmwareGdt@GOTPCREL(%rip), %rax # Get the GDT save address.
sgdt (%rax) # Save the GDT.
cli # Disable interrupts.
retq # Return.
Expand Down Expand Up @@ -152,52 +159,66 @@ FUNCTION(BopEfiRestoreFirmwareContext)

xorl %eax, %eax # Zero eax.
movw %cs, %ax # Get CS.
movl %eax, BoLoaderCs@GOTPCREL(%rip) # Save CS.
movq BoLoaderCs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save CS.
movw %ds, %ax # Get DS.
movl %eax, BoLoaderDs@GOTPCREL(%rip) # Save DS.
movq BoLoaderDs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save DS.
movw %es, %ax # Get ES.
movl %eax, BoLoaderEs@GOTPCREL(%rip) # Save ES.
movq BoLoaderEs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save ES.
movw %fs, %ax # Get FS.
movl %eax, BoLoaderFs@GOTPCREL(%rip) # Save FS.
movq BoLoaderFs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save FS.
movw %gs, %ax # Get GS.
movl %eax, BoLoaderGs@GOTPCREL(%rip) # Save GS.
movq BoLoaderGs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save GS.
movw %ss, %ax # Get SS.
movl %eax, BoLoaderSs@GOTPCREL(%rip) # Save SS.
movq BoLoaderSs@GOTPCREL(%rip), %rcx # Get address of global.
movl %eax, (%rcx) # Save SS.
pushfq # Push rflags.
popq %rax # Pop RAX.
movq %rax, BoLoaderRflags@GOTPCREL(%rip) # Save rflags.
leaq BoLoaderIdt@GOTPCREL(%rip), %rax # Get the IDT save address.
movq BoLoaderRflags@GOTPCREL(%rip), %rcx # Get address of global.
movq %rax, (%rcx) # Save RFLAGS.
movq BoLoaderIdt@GOTPCREL(%rip), %rax # Get the IDT save address.
sidt (%rax) # Save the IDT.
leaq BoLoaderGdt@GOTPCREL(%rip), %rax # Get the GDT save address.
movq BoLoaderGdt@GOTPCREL(%rip), %rax # Get the GDT save address.
sgdt (%rax) # Save the GDT.
cli # Disable interrupts.

//
// Restore the firmware context.
//

movl BoFirmwareDs@GOTPCREL(%rip), %ecx # Get DS.
movl BoFirmwareCs@GOTPCREL(%rip), %eax # Get CS.
movq BoFirmwareDs@GOTPCREL(%rip), %rcx # Get DS address.
movl (%rcx), %ecx # Dereference to get value.
movq BoFirmwareCs@GOTPCREL(%rip), %rax # Get CS address.
movl (%rax), %eax # Dereference to get value.
pushq %rax # Push CS.
movq BopEfiRestoreFirmwareContextJump@GOTPCREL(%rip), %rax
pushq %rax # Push eax.
leaq BoFirmwareGdt@GOTPCREL(%rip), %rax # Get the GDT.
movq BoFirmwareGdt@GOTPCREL(%rip), %rax # Get the GDT.
lgdt (%rax) # Load the GDT. Do a jump.
retfq # "Return" immediately below.

BopEfiRestoreFirmwareContextJump:
movw %cx, %ds # Load DS.
movl BoFirmwareEs@GOTPCREL(%rip), %eax # Get ES.
movq BoFirmwareEs@GOTPCREL(%rip), %rax # Get ES address.
movl (%rax), %eax # Dereference to get value.
movw %ax, %es # Set ES.
movl BoFirmwareFs@GOTPCREL(%rip), %eax # Get FS.
movq BoFirmwareFs@GOTPCREL(%rip), %rax # Get FS address.
movl (%rax), %eax # Dereference to get value.
movw %ax, %fs # Set FS.
movl BoFirmwareGs@GOTPCREL(%rip), %eax # Get GS.
movq BoFirmwareGs@GOTPCREL(%rip), %rax # Get GS address.
movl (%rax), %eax # Dereference to get value.
movw %ax, %gs # Set GS.
movl BoFirmwareSs@GOTPCREL(%rip), %eax # Get SS.
movq BoFirmwareSs@GOTPCREL(%rip), %rax # Get SS address.
movl (%rax), %eax # Dereference to get value.
movw %ax, %ss # Set SS.
leaq BoFirmwareIdt@GOTPCREL(%rip), %rax # Get the IDT.
movq BoFirmwareIdt@GOTPCREL(%rip), %rax # Get the IDT.
lidt (%rax) # Restore the IDT.
movq BoFirmwareRflags@GOTPCREL(%rip), %rax # Get Rflags.
movq (%rax), %rax # Dereference to get value.
pushq %rax # Push the flags.
popfq # Pop flags, enable interrupts.
retq # Return.
Expand Down Expand Up @@ -230,28 +251,35 @@ Return Value:

FUNCTION(BopEfiRestoreApplicationContext)
cli # Disable interrupts.
movl BoLoaderDs@GOTPCREL(%rip), %ecx # Get DS.
movl BoLoaderCs@GOTPCREL(%rip), %eax # Get CS.
movq BoLoaderDs@GOTPCREL(%rip), %rcx # Get DS.
movl (%rcx), %ecx # Dereference to get value.
movq BoLoaderCs@GOTPCREL(%rip), %rax # Get CS.
movl (%rax), %eax # Dereference to get value.
pushq %rax # Push CS.
movq BopEfiRestoreApplicationContextJump@GOTPCREL(%rip), %rax
pushq %rax # Push eax.
leaq BoLoaderGdt@GOTPCREL(%rip), %rax # Get the GDT.
movq BoLoaderGdt@GOTPCREL(%rip), %rax # Get the GDT.
lgdt (%rax) # Load the GDT.
retfq # "Return" immediately below.

BopEfiRestoreApplicationContextJump:
movw %cx, %ds # Load DS.
movl BoLoaderEs@GOTPCREL(%rip), %eax # Get ES.
movq BoLoaderEs@GOTPCREL(%rip), %rax # Get ES address.
movl (%rax), %eax # Dereference to get value.
movw %ax, %es # Set ES.
movl BoLoaderFs@GOTPCREL(%rip), %eax # Get FS.
movq BoLoaderFs@GOTPCREL(%rip), %rax # Get FS address.
movl (%rax), %eax # Dereference to get value.
movw %ax, %fs # Set FS.
movl BoLoaderGs@GOTPCREL(%rip), %eax # Get GS.
movq BoLoaderGs@GOTPCREL(%rip), %rax # Get GS address.
movl (%rax), %eax # Dereference to get value.
movw %ax, %gs # Set GS.
movl BoLoaderSs@GOTPCREL(%rip), %eax # Get SS.
movq BoLoaderSs@GOTPCREL(%rip), %rax # Get SS address.
movl (%rax), %eax # Dereference to get value.
movw %ax, %ss # Set SS.
leaq BoLoaderIdt@GOTPCREL(%rip), %rax # Get the IDT.
movq BoLoaderIdt@GOTPCREL(%rip), %rax # Get the IDT.
lidt (%rax) # Restore the IDT. No debugging.
movq BoLoaderRflags@GOTPCREL(%rip), %rax # Get Rflags.
movq BoLoaderRflags@GOTPCREL(%rip), %rax # Get Rflags address.
movq (%rax), %rax # Dereference to get value.
pushq %rax # Push the flags.
popfq # Pop flags. Enable interrupts.
retq # Return.
Expand Down
17 changes: 17 additions & 0 deletions boot/loader/x64/kernxfr.S
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,23 @@ Return Value:

FUNCTION(BoEnablePaging)

//
// Enable NX mode. This may not have been done earlier on EFI machines.
//

movl $X86_MSR_EFER, %ecx # Get EFER as MSR register.
rdmsr # Read it.
orl $EFER_NO_EXECUTE_ENABLE, %eax # OR in the bit.
wrmsr # Write it.

//
// Also set the necessary bits in CR4 in case EFI firmware didn't do it.
//

movq %cr4, %rax # Read CR4.
orq $CR4_OR_MASK, %rax # OR in the PAE bit and others.
movq %rax, %cr4 # Set CR4.

//
// Set up CR3. Paging may already be on, in which case this switches to the
// kernel page tables immediately.
Expand Down
7 changes: 7 additions & 0 deletions docs/vhd.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Convert an image to VHDX:
qemu-img convert source.img -O vhdx -o subformat=dynamic dest.vhdx

Convert an image to VHD:
qemu-img convert source.img -O vpc -o subformat=dyanmic dest.vhdx

The subformat parameter can by dynamic or fixed.
14 changes: 9 additions & 5 deletions kernel/mm/x64/mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -3122,18 +3122,22 @@ Return Value:
ASSERT(X86_PTE_ENTRY(*Pte) == Physical);

*Pte |= X86_PTE_PRESENT | X86_PTE_WRITABLE | X86_PTE_USER_MODE;
if (AddressSpace != NULL) {

ASSERT(AddressSpace->ActivePageTables <
AddressSpace->AllocatedPageTables);
ASSERT(AddressSpace->ActivePageTables <
AddressSpace->AllocatedPageTables);

AddressSpace->ActivePageTables += 1;
AddressSpace->ActivePageTables += 1;
}

} else {
*Pte = Physical | X86_PTE_PRESENT | X86_PTE_WRITABLE |
X86_PTE_USER_MODE;

AddressSpace->AllocatedPageTables += 1;
AddressSpace->ActivePageTables += 1;
if (AddressSpace != NULL) {
AddressSpace->AllocatedPageTables += 1;
AddressSpace->ActivePageTables += 1;
}
}

//
Expand Down
34 changes: 17 additions & 17 deletions uefi/include/link_x64.x
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,7 @@ SEARCH_DIR("=//x86_64-pc-minoca/lib"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400)); . = SEGMENT_START("text-segment", 0x400) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x420)); . = SEGMENT_START("text-segment", 0x420); /* + SIZEOF_HEADERS;*/
.rela.dyn :
{
*(.rela.init)
Expand All @@ -40,13 +31,6 @@ SECTIONS
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.bnd : { *(.plt.bnd) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
Expand All @@ -57,6 +41,13 @@ SECTIONS
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
}
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.bnd : { *(.plt.bnd) }
.fini :
{
KEEP (*(SORT_NONE(.fini)))
Expand Down Expand Up @@ -144,8 +135,17 @@ SECTIONS
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
*(.interp)
*(.note.gnu.build-id)
}
.data1 : { *(.data1) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
Expand Down
2 changes: 1 addition & 1 deletion uefi/tools/elfconv/elfc32.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ Return Value:
case SHT_NOBITS:
if ((Context->Flags & ELFCONV_OPTION_VERBOSE) != 0) {
Difference = Destination - (VOID *)(Context->CoffFile);
printf("Zeroing COFF offset %lx, size %x",
printf("Zeroing COFF offset %lx, size %x\n",
(long)Difference,
ElfSection->sh_size);
}
Expand Down
Loading

0 comments on commit 3feb1c4

Please sign in to comment.