Permalink
Browse files

Fixes to get x64 booting via UEFI.

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 3feb1c49b4db633674b8d81184f615c0c812d88b
View
@@ -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"
@@ -187,7 +187,8 @@ function build() {
"includes": includes,
"config": pcatConfig,
"text_address": "0x100000",
"binplace": "bin"
"binplace": "bin",
"prefix": "pcat"
};
entries += staticApplication(pcatApp);
@@ -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)
View
@@ -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.
@@ -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.
@@ -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.
View
@@ -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.
View
@@ -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.
View
@@ -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;
}
}
//
View
@@ -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)
@@ -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.*)
@@ -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)))
@@ -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 = .;
@@ -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);
}
Oops, something went wrong.

0 comments on commit 3feb1c4

Please sign in to comment.