diff options
Diffstat (limited to 'contrib/syslinux-4.02/gpxe/src/arch/i386/core')
19 files changed, 2124 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/aout_loader.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/aout_loader.c new file mode 100644 index 0000000..f85620e --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/aout_loader.c @@ -0,0 +1,144 @@ +/* a.out */ +struct exec { + unsigned long a_midmag; /* flags<<26 | mid<<16 | magic */ + unsigned long a_text; /* text segment size */ + unsigned long a_data; /* initialized data size */ + unsigned long a_bss; /* uninitialized data size */ + unsigned long a_syms; /* symbol table size */ + unsigned long a_entry; /* entry point */ + unsigned long a_trsize; /* text relocation size */ + unsigned long a_drsize; /* data relocation size */ +}; + +struct aout_state { + struct exec head; + unsigned long curaddr; + int segment; /* current segment number, -1 for none */ + unsigned long loc; /* start offset of current block */ + unsigned long skip; /* padding to be skipped to current segment */ + unsigned long toread; /* remaining data to be read in the segment */ +}; + +static struct aout_state astate; + +static sector_t aout_download(unsigned char *data, unsigned int len, int eof); +static inline os_download_t aout_probe(unsigned char *data, unsigned int len) +{ + unsigned long start, mid, end, istart, iend; + if (len < sizeof(astate.head)) { + return 0; + } + memcpy(&astate.head, data, sizeof(astate.head)); + if ((astate.head.a_midmag & 0xffff) != 0x010BL) { + return 0; + } + + printf("(a.out"); + aout_freebsd_probe(); + printf(")... "); + /* Check the aout image */ + start = astate.head.a_entry; + mid = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data; + end = ((mid + 4095) & ~4095) + astate.head.a_bss; + istart = 4096; + iend = istart + (mid - start); + if (!prep_segment(start, mid, end, istart, iend)) + return dead_download; + astate.segment = -1; + astate.loc = 0; + astate.skip = 0; + astate.toread = 0; + return aout_download; +} + +static sector_t aout_download(unsigned char *data, unsigned int len, int eof) +{ + unsigned int offset; /* working offset in the current data block */ + + offset = 0; + +#ifdef AOUT_LYNX_KDI + astate.segment++; + if (astate.segment == 0) { + astate.curaddr = 0x100000; + astate.head.a_entry = astate.curaddr + 0x20; + } + memcpy(phys_to_virt(astate.curaddr), data, len); + astate.curaddr += len; + return 0; +#endif + + do { + if (astate.segment != -1) { + if (astate.skip) { + if (astate.skip >= len - offset) { + astate.skip -= len - offset; + break; + } + offset += astate.skip; + astate.skip = 0; + } + + if (astate.toread) { + if (astate.toread >= len - offset) { + memcpy(phys_to_virt(astate.curaddr), data+offset, + len - offset); + astate.curaddr += len - offset; + astate.toread -= len - offset; + break; + } + memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread); + offset += astate.toread; + astate.toread = 0; + } + } + + /* Data left, but current segment finished - look for the next + * segment. This is quite simple for a.out files. */ + astate.segment++; + switch (astate.segment) { + case 0: + /* read text */ + astate.curaddr = astate.head.a_entry; + astate.skip = 4096; + astate.toread = astate.head.a_text; + break; + case 1: + /* read data */ + /* skip and curaddr may be wrong, but I couldn't find + * examples where this failed. There is no reasonable + * documentation for a.out available. */ + astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr; + astate.curaddr = (astate.curaddr + 4095) & ~4095; + astate.toread = astate.head.a_data; + break; + case 2: + /* initialize bss and start kernel */ + astate.curaddr = (astate.curaddr + 4095) & ~4095; + astate.skip = 0; + astate.toread = 0; + memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss); + goto aout_startkernel; + default: + break; + } + } while (offset < len); + + astate.loc += len; + + if (eof) { + unsigned long entry; + +aout_startkernel: + entry = astate.head.a_entry; + done(1); + + aout_freebsd_boot(); +#ifdef AOUT_LYNX_KDI + xstart32(entry); +#endif + printf("unexpected a.out variant\n"); + longjmp(restart_etherboot, -2); + } + return 0; +} diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/basemem_packet.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/basemem_packet.c new file mode 100644 index 0000000..d487cce --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/basemem_packet.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * @file + * + * Packet buffer in base memory. Used by various components which + * need to pass packets to and from external real-mode code. + * + */ + +#include <basemem_packet.h> + +#undef basemem_packet +char __bss16_array ( basemem_packet, [BASEMEM_PACKET_LEN] ); diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/cpu.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/cpu.c new file mode 100644 index 0000000..c24fa4e --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/cpu.c @@ -0,0 +1,73 @@ +#include <stdint.h> +#include <string.h> +#include <cpu.h> + +/** @file + * + * CPU identification + * + */ + +/** + * Test to see if CPU flag is changeable + * + * @v flag Flag to test + * @ret can_change Flag is changeable + */ +static inline int flag_is_changeable ( unsigned int flag ) { + uint32_t f1, f2; + + __asm__ ( "pushfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "movl %0,%1\n\t" + "xorl %2,%0\n\t" + "pushl %0\n\t" + "popfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "popfl\n\t" + : "=&r" ( f1 ), "=&r" ( f2 ) + : "ir" ( flag ) ); + + return ( ( ( f1 ^ f2 ) & flag ) != 0 ); +} + +/** + * Get CPU information + * + * @v cpu CPU information structure to fill in + */ +void get_cpuinfo ( struct cpuinfo_x86 *cpu ) { + unsigned int cpuid_level; + unsigned int cpuid_extlevel; + unsigned int discard_1, discard_2, discard_3; + + memset ( cpu, 0, sizeof ( *cpu ) ); + + /* Check for CPUID instruction */ + if ( ! flag_is_changeable ( X86_EFLAGS_ID ) ) { + DBG ( "CPUID not supported\n" ); + return; + } + + /* Get features, if present */ + cpuid ( 0x00000000, &cpuid_level, &discard_1, + &discard_2, &discard_3 ); + if ( cpuid_level >= 0x00000001 ) { + cpuid ( 0x00000001, &discard_1, &discard_2, + &discard_3, &cpu->features ); + } else { + DBG ( "CPUID cannot return capabilities\n" ); + } + + /* Get 64-bit features, if present */ + cpuid ( 0x80000000, &cpuid_extlevel, &discard_1, + &discard_2, &discard_3 ); + if ( ( cpuid_extlevel & 0xffff0000 ) == 0x80000000 ) { + if ( cpuid_extlevel >= 0x80000001 ) { + cpuid ( 0x80000001, &discard_1, &discard_2, + &discard_3, &cpu->amd_features ); + } + } +} diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/dumpregs.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/dumpregs.c new file mode 100644 index 0000000..82dc218 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/dumpregs.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <realmode.h> + +void __asmcall _dump_regs ( struct i386_all_regs *ix86 ) { + + __asm__ __volatile__ ( + TEXT16_CODE ( ".globl dump_regs\n\t" + "\ndump_regs:\n\t" + "pushl $_dump_regs\n\t" + "pushw %%cs\n\t" + "call prot_call\n\t" + "addr32 leal 4(%%esp), %%esp\n\t" + "ret\n\t" ) : : ); + + printf ( "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" + "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", + ix86->regs.eax, ix86->regs.ebx, ix86->regs.ecx, + ix86->regs.edx, ix86->regs.esi, ix86->regs.edi, + ix86->regs.ebp, ix86->regs.esp, + ix86->segs.cs, ix86->segs.ss, ix86->segs.ds, + ix86->segs.es, ix86->segs.fs, ix86->segs.gs ); +} diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/freebsd_loader.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/freebsd_loader.c new file mode 100644 index 0000000..464f6d9 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/freebsd_loader.c @@ -0,0 +1,377 @@ +/* bootinfo */ +#define BOOTINFO_VERSION 1 +#define NODEV (-1) /* non-existent device */ +#define PAGE_SHIFT 12 /* LOG2(PAGE_SIZE) */ +#define PAGE_SIZE (1<<PAGE_SHIFT) /* bytes/page */ +#define PAGE_MASK (PAGE_SIZE-1) +#define N_BIOS_GEOM 8 + +struct bootinfo { + unsigned int bi_version; + const unsigned char *bi_kernelname; + struct nfs_diskless *bi_nfs_diskless; + /* End of fields that are always present. */ +#define bi_endcommon bi_n_bios_used + unsigned int bi_n_bios_used; + unsigned long bi_bios_geom[N_BIOS_GEOM]; + unsigned int bi_size; + unsigned char bi_memsizes_valid; + unsigned char bi_pad[3]; + unsigned long bi_basemem; + unsigned long bi_extmem; + unsigned long bi_symtab; + unsigned long bi_esymtab; + /* Note that these are in the FreeBSD headers but were not here... */ + unsigned long bi_kernend; /* end of kernel space */ + unsigned long bi_envp; /* environment */ + unsigned long bi_modulep; /* preloaded modules */ +}; + +static struct bootinfo bsdinfo; + +#ifdef ELF_IMAGE +static Elf32_Shdr *shdr; /* To support the FreeBSD kludge! */ +static Address symtab_load; +static Address symstr_load; +static int symtabindex; +static int symstrindex; +#endif + +static enum { + Unknown, Tagged, Aout, Elf, Aout_FreeBSD, Elf_FreeBSD, +} image_type = Unknown; + +static unsigned int off; + + +#ifdef ELF_IMAGE +static void elf_freebsd_probe(void) +{ + image_type = Elf; + if ( (estate.e.elf32.e_entry & 0xf0000000) && + (estate.e.elf32.e_type == ET_EXEC)) + { + image_type = Elf_FreeBSD; + printf("/FreeBSD"); + off = -(estate.e.elf32.e_entry & 0xff000000); + estate.e.elf32.e_entry += off; + } + /* Make sure we have a null to start with... */ + shdr = 0; + + /* Clear the symbol index values... */ + symtabindex = -1; + symstrindex = -1; + + /* ...and the load addresses of the symbols */ + symtab_load = 0; + symstr_load = 0; +} + +static void elf_freebsd_fixup_segment(void) +{ + if (image_type == Elf_FreeBSD) { + estate.p.phdr32[estate.segment].p_paddr += off; + } +} + +static void elf_freebsd_find_segment_end(void) +{ + /* Count the bytes read even for the last block + * as we will need to know where the last block + * ends in order to load the symbols correctly. + * (plus it could be useful elsewhere...) + * Note that we need to count the actual size, + * not just the end of the disk image size. + */ + estate.curaddr += + (estate.p.phdr32[estate.segment].p_memsz - + estate.p.phdr32[estate.segment].p_filesz); +} + +static int elf_freebsd_debug_loader(unsigned int offset) +{ + /* No more segments to be loaded - time to start the + * nasty state machine to support the loading of + * FreeBSD debug symbols due to the fact that FreeBSD + * uses/exports the kernel's debug symbols in order + * to make much of the system work! Amazing (arg!) + * + * We depend on the fact that for the FreeBSD kernel, + * there is only one section of debug symbols and that + * the section is after all of the loaded sections in + * the file. This assumes a lot but is somewhat required + * to make this code not be too annoying. (Where do you + * load symbols when the code has not loaded yet?) + * Since this function is actually just a callback from + * the network data transfer code, we need to be able to + * work with the data as it comes in. There is no chance + * for doing a seek other than forwards. + * + * The process we use is to first load the section + * headers. Once they are loaded (shdr != 0) we then + * look for where the symbol table and symbol table + * strings are and setup some state that we found + * them and fall into processing the first one (which + * is the symbol table) and after that has been loaded, + * we try the symbol strings. Note that the order is + * actually required as the memory image depends on + * the symbol strings being loaded starting at the + * end of the symbol table. The kernel assumes this + * layout of the image. + * + * At any point, if we get to the end of the load file + * or the section requested is earlier in the file than + * the current file pointer, we just end up falling + * out of this and booting the kernel without this + * information. + */ + + /* Make sure that the next address is long aligned... */ + /* Assumes size of long is a power of 2... */ + estate.curaddr = (estate.curaddr + sizeof(long) - 1) & ~(sizeof(long) - 1); + + /* If we have not yet gotten the shdr loaded, try that */ + if (shdr == 0) + { + estate.toread = estate.e.elf32.e_shnum * estate.e.elf32.e_shentsize; + estate.skip = estate.e.elf32.e_shoff - (estate.loc + offset); + if (estate.toread) + { +#if ELF_DEBUG + printf("shdr *, size %lX, curaddr %lX\n", + estate.toread, estate.curaddr); +#endif + + /* Start reading at the curaddr and make that the shdr */ + shdr = (Elf32_Shdr *)phys_to_virt(estate.curaddr); + + /* Start to read... */ + return 1; + } + } + else + { + /* We have the shdr loaded, check if we have found + * the indexs where the symbols are supposed to be */ + if ((symtabindex == -1) && (symstrindex == -1)) + { + int i; + /* Make sure that the address is page aligned... */ + /* Symbols need to start in their own page(s)... */ + estate.curaddr = (estate.curaddr + 4095) & ~4095; + + /* Need to make new indexes... */ + for (i=0; i < estate.e.elf32.e_shnum; i++) + { + if (shdr[i].sh_type == SHT_SYMTAB) + { + int j; + for (j=0; j < estate.e.elf32.e_phnum; j++) + { + /* Check only for loaded sections */ + if ((estate.p.phdr32[j].p_type | 0x80) == (PT_LOAD | 0x80)) + { + /* Only the extra symbols */ + if ((shdr[i].sh_offset >= estate.p.phdr32[j].p_offset) && + ((shdr[i].sh_offset + shdr[i].sh_size) <= + (estate.p.phdr32[j].p_offset + estate.p.phdr32[j].p_filesz))) + { + shdr[i].sh_offset=0; + shdr[i].sh_size=0; + break; + } + } + } + if ((shdr[i].sh_offset != 0) && (shdr[i].sh_size != 0)) + { + symtabindex = i; + symstrindex = shdr[i].sh_link; + } + } + } + } + + /* Check if we have a symbol table index and have not loaded it */ + if ((symtab_load == 0) && (symtabindex >= 0)) + { + /* No symbol table yet? Load it first... */ + + /* This happens to work out in a strange way. + * If we are past the point in the file already, + * we will skip a *large* number of bytes which + * ends up bringing us to the end of the file and + * an old (default) boot. Less code and lets + * the state machine work in a cleaner way but this + * is a nasty side-effect trick... */ + estate.skip = shdr[symtabindex].sh_offset - (estate.loc + offset); + + /* And we need to read this many bytes... */ + estate.toread = shdr[symtabindex].sh_size; + + if (estate.toread) + { +#if ELF_DEBUG + printf("db sym, size %lX, curaddr %lX\n", + estate.toread, estate.curaddr); +#endif + /* Save where we are loading this... */ + symtab_load = estate.curaddr; + + *((long *)phys_to_virt(estate.curaddr)) = estate.toread; + estate.curaddr += sizeof(long); + + /* Start to read... */ + return 1; + } + } + else if ((symstr_load == 0) && (symstrindex >= 0)) + { + /* We have already loaded the symbol table, so + * now on to the symbol strings... */ + + + /* Same nasty trick as above... */ + estate.skip = shdr[symstrindex].sh_offset - (estate.loc + offset); + + /* And we need to read this many bytes... */ + estate.toread = shdr[symstrindex].sh_size; + + if (estate.toread) + { +#if ELF_DEBUG + printf("db str, size %lX, curaddr %lX\n", + estate.toread, estate.curaddr); +#endif + /* Save where we are loading this... */ + symstr_load = estate.curaddr; + + *((long *)phys_to_virt(estate.curaddr)) = estate.toread; + estate.curaddr += sizeof(long); + + /* Start to read... */ + return 1; + } + } + } + /* all done */ + return 0; +} + +static void elf_freebsd_boot(unsigned long entry) +{ + if (image_type != Elf_FreeBSD) + return; + + memset(&bsdinfo, 0, sizeof(bsdinfo)); + bsdinfo.bi_basemem = meminfo.basememsize; + bsdinfo.bi_extmem = meminfo.memsize; + bsdinfo.bi_memsizes_valid = 1; + bsdinfo.bi_version = BOOTINFO_VERSION; + bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF); + bsdinfo.bi_nfs_diskless = NULL; + bsdinfo.bi_size = sizeof(bsdinfo); +#define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */ + if(freebsd_kernel_env[0] != '\0'){ + freebsd_howto |= RB_BOOTINFO; + bsdinfo.bi_envp = (unsigned long)freebsd_kernel_env; + } + + /* Check if we have symbols loaded, and if so, + * made the meta_data needed to pass those to + * the kernel. */ + if ((symtab_load !=0) && (symstr_load != 0)) + { + unsigned long *t; + + bsdinfo.bi_symtab = symtab_load; + + /* End of symbols (long aligned...) */ + /* Assumes size of long is a power of 2... */ + bsdinfo.bi_esymtab = (symstr_load + + sizeof(long) + + *((long *)phys_to_virt(symstr_load)) + + sizeof(long) - 1) & ~(sizeof(long) - 1); + + /* Where we will build the meta data... */ + t = phys_to_virt(bsdinfo.bi_esymtab); + +#if ELF_DEBUG + printf("Metadata at %lX\n",t); +#endif + + /* Set up the pointer to the memory... */ + bsdinfo.bi_modulep = virt_to_phys(t); + + /* The metadata structure is an array of 32-bit + * words where we store some information about the + * system. This is critical, as FreeBSD now looks + * only for the metadata for the extended symbol + * information rather than in the bootinfo. + */ + /* First, do the kernel name and the kernel type */ + /* Note that this assumed x86 byte order... */ + + /* 'kernel\0\0' */ + *t++=MODINFO_NAME; *t++= 7; *t++=0x6E72656B; *t++=0x00006C65; + + /* 'elf kernel\0\0' */ + *t++=MODINFO_TYPE; *t++=11; *t++=0x20666C65; *t++=0x6E72656B; *t++ = 0x00006C65; + + /* Now the symbol start/end - note that they are + * here in local/physical address - the Kernel + * boot process will relocate the addresses. */ + *t++=MODINFOMD_SSYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_symtab; + *t++=MODINFOMD_ESYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_esymtab; + + *t++=MODINFO_END; *t++=0; /* end of metadata */ + + /* Since we have symbols we need to make + * sure that the kernel knows its own end + * of memory... It is not _end but after + * the symbols and the metadata... */ + bsdinfo.bi_kernend = virt_to_phys(t); + + /* Signal locore.s that we have a valid bootinfo + * structure that was completely filled in. */ + freebsd_howto |= 0x80000000; + } + + xstart32(entry, freebsd_howto, NODEV, 0, 0, 0, + virt_to_phys(&bsdinfo), 0, 0, 0); + longjmp(restart_etherboot, -2); +} +#endif + +#ifdef AOUT_IMAGE +static void aout_freebsd_probe(void) +{ + image_type = Aout; + if (((astate.head.a_midmag >> 16) & 0xffff) == 0) { + /* Some other a.out variants have a different + * value, and use other alignments (e.g. 1K), + * not the 4K used by FreeBSD. */ + image_type = Aout_FreeBSD; + printf("/FreeBSD"); + off = -(astate.head.a_entry & 0xff000000); + astate.head.a_entry += off; + } +} + +static void aout_freebsd_boot(void) +{ + if (image_type == Aout_FreeBSD) { + memset(&bsdinfo, 0, sizeof(bsdinfo)); + bsdinfo.bi_basemem = meminfo.basememsize; + bsdinfo.bi_extmem = meminfo.memsize; + bsdinfo.bi_memsizes_valid = 1; + bsdinfo.bi_version = BOOTINFO_VERSION; + bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF); + bsdinfo.bi_nfs_diskless = NULL; + bsdinfo.bi_size = sizeof(bsdinfo); + xstart32(astate.head.a_entry, freebsd_howto, NODEV, 0, 0, 0, + virt_to_phys(&bsdinfo), 0, 0, 0); + longjmp(restart_etherboot, -2); + } +} +#endif diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/gdbidt.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/gdbidt.S new file mode 100644 index 0000000..cd8b38a --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/gdbidt.S @@ -0,0 +1,215 @@ +/* + * Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub. + */ + +#include <librm.h> + +#define SIZEOF_I386_REGS 32 +#define SIZEOF_I386_FLAGS 4 + +/**************************************************************************** + * Interrupt Descriptor Table + **************************************************************************** + */ + .section ".data16", "aw", @progbits + .globl idtr +idtr: +idt_limit: + .word idt_length - 1 +idt_base: + .long 0 + +/* IDT entries have the following format: + * offset_lo, segment selector, flags, offset_hi + * + * Since it is not possible to specify relocations in arbitrary + * expressions like (int_overflow & 0xffff), we initialise the + * IDT with entries in an incorrect format. + * + * The entries are shuffled into the correct format in init_librm(). + */ +#define IDT_ENTRY_EMPTY(name) .word 0, 0, 0, 0 +#define IDT_ENTRY_PRESENT(name) \ + .long int_##name; \ + .word 0x8e00, VIRTUAL_CS + +.align 16 +idt: + IDT_ENTRY_PRESENT(divide_error) + IDT_ENTRY_PRESENT(debug_trap) + IDT_ENTRY_EMPTY(non_maskable_interrupt) + IDT_ENTRY_PRESENT(breakpoint) + IDT_ENTRY_PRESENT(overflow) + IDT_ENTRY_PRESENT(bound_range_exceeded) + IDT_ENTRY_PRESENT(invalid_opcode) + IDT_ENTRY_EMPTY(device_not_available) + IDT_ENTRY_PRESENT(double_fault) + IDT_ENTRY_EMPTY(coprocessor_segment_overrun) + IDT_ENTRY_PRESENT(invalid_tss) + IDT_ENTRY_PRESENT(segment_not_present) + IDT_ENTRY_PRESENT(stack_segment_fault) + IDT_ENTRY_PRESENT(general_protection) + IDT_ENTRY_PRESENT(page_fault) +idt_end: + .equ idt_length, idt_end - idt + +/* The IDT entries are fixed up (once) in init_librm() */ +idt_fixed: + .byte 0 + +/**************************************************************************** + * idt_init (real-mode near call, 16-bit real-mode near return address) + * + * Initialise the IDT, called from init_librm. + * + * Parameters: + * %eax : IDT base address + * + * Destroys %ax, %bx, and %di. + **************************************************************************** + */ + .section ".text16", "ax", @progbits + .code16 + .globl idt_init +idt_init: + movl %eax, idt_base + addl $idt, idt_base + + /* IDT entries are only fixed up once */ + movb idt_fixed, %al + orb %al, %al + jnz 2f + movb $1, idt_fixed + + /* Shuffle IDT entries into the correct format */ + movb $(idt_length / 8), %al + movw $idt, %bx + or %al, %al + jz 2f +1: + movw 2(%bx), %di + xchg %di, 6(%bx) + movw %di, 2(%bx) + addw $8, %bx + dec %al + jnz 1b +2: + ret + +/**************************************************************************** + * Interrupt handlers + **************************************************************************** + */ + .section ".text", "ax", @progbits + .code32 + +/* POSIX signal numbers for reporting traps to GDB */ +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGSEGV 11 +#define SIGSTKFLT 16 + +int_divide_error: + pushl $SIGFPE + jmp do_interrupt + +int_debug_trap: +int_breakpoint: + pushl $SIGTRAP + jmp do_interrupt + +int_overflow: +int_bound_range_exceeded: + pushl $SIGSTKFLT + jmp do_interrupt + +int_invalid_opcode: + pushl $SIGILL + jmp do_interrupt + +int_double_fault: + movl $SIGBUS, (%esp) + jmp do_interrupt + +int_invalid_tss: +int_segment_not_present: +int_stack_segment_fault: +int_general_protection: +int_page_fault: + movl $SIGSEGV, (%esp) + jmp do_interrupt + +/* When invoked, the stack contains: eflags, cs, eip, signo. */ +#define IH_OFFSET_GDB_REGS ( 0 ) +#define IH_OFFSET_GDB_EIP ( IH_OFFSET_GDB_REGS + SIZEOF_I386_REGS ) +#define IH_OFFSET_GDB_EFLAGS ( IH_OFFSET_GDB_EIP + 4 ) +#define IH_OFFSET_GDB_SEG_REGS ( IH_OFFSET_GDB_EFLAGS + SIZEOF_I386_FLAGS ) +#define IH_OFFSET_GDB_END ( IH_OFFSET_GDB_SEG_REGS + 6 * 4 ) +#define IH_OFFSET_SIGNO ( IH_OFFSET_GDB_END ) +#define IH_OFFSET_OLD_EIP ( IH_OFFSET_SIGNO + 4 ) +#define IH_OFFSET_OLD_CS ( IH_OFFSET_OLD_EIP + 4 ) +#define IH_OFFSET_OLD_EFLAGS ( IH_OFFSET_OLD_CS + 4 ) +#define IH_OFFSET_END ( IH_OFFSET_OLD_EFLAGS + 4 ) + +/* We also access the stack whilst still storing or restoring + * the register snapshot. Since ESP is in flux, we need + * special offsets. + */ +#define IH_OFFSET_FLUX_OLD_CS ( IH_OFFSET_OLD_CS - 44 ) +#define IH_OFFSET_FLUX_OLD_EFLAGS ( IH_OFFSET_OLD_EFLAGS - 40 ) +#define IH_OFFSET_FLUX_OLD_EIP ( IH_OFFSET_OLD_EIP - 36 ) +#define IH_OFFSET_FLUX_END ( IH_OFFSET_END - 20 ) +do_interrupt: + /* Store CPU state in GDB register snapshot */ + pushw $0 + pushw %gs + pushw $0 + pushw %fs + pushw $0 + pushw %es + pushw $0 + pushw %ds + pushw $0 + pushw %ss + pushw $0 + pushw IH_OFFSET_FLUX_OLD_CS + 2(%esp) + pushl IH_OFFSET_FLUX_OLD_EFLAGS(%esp) + pushl IH_OFFSET_FLUX_OLD_EIP(%esp) + pushl %edi + pushl %esi + pushl %ebp + leal IH_OFFSET_FLUX_END(%esp), %edi + pushl %edi /* old ESP */ + pushl %ebx + pushl %edx + pushl %ecx + pushl %eax + + /* Call GDB stub exception handler */ + pushl %esp + pushl (IH_OFFSET_SIGNO + 4)(%esp) + call gdbmach_handler + addl $8, %esp + + /* Restore CPU state from GDB register snapshot */ + popl %eax + popl %ecx + popl %edx + popl %ebx + addl $4, %esp /* Changing ESP currently not supported */ + popl %ebp + popl %esi + popl %edi + popl IH_OFFSET_FLUX_OLD_EIP(%esp) + popl IH_OFFSET_FLUX_OLD_EFLAGS(%esp) + popl IH_OFFSET_FLUX_OLD_CS(%esp) + popl %ss + popl %ds + popl %es + popl %fs + popl %gs + + addl $4, %esp /* drop signo */ + iret diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/gdbmach.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/gdbmach.c new file mode 100644 index 0000000..97827ec --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/gdbmach.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stddef.h> +#include <stdio.h> +#include <assert.h> +#include <gpxe/uaccess.h> +#include <gpxe/gdbstub.h> +#include <gdbmach.h> + +/** @file + * + * GDB architecture-specific bits for i386 + * + */ + +enum { + DR7_CLEAR = 0x00000400, /* disable hardware breakpoints */ + DR6_CLEAR = 0xffff0ff0, /* clear breakpoint status */ +}; + +/** Hardware breakpoint, fields stored in x86 bit pattern form */ +struct hwbp { + int type; /* type (1=write watchpoint, 3=access watchpoint) */ + unsigned long addr; /* linear address */ + size_t len; /* length (0=1-byte, 1=2-byte, 3=4-byte) */ + int enabled; +}; + +static struct hwbp hwbps [ 4 ]; +static gdbreg_t dr7 = DR7_CLEAR; + +static struct hwbp *gdbmach_find_hwbp ( int type, unsigned long addr, size_t len ) { + struct hwbp *available = NULL; + unsigned int i; + for ( i = 0; i < sizeof hwbps / sizeof hwbps [ 0 ]; i++ ) { + if ( hwbps [ i ].type == type && hwbps [ i ].addr == addr && hwbps [ i ].len == len ) { + return &hwbps [ i ]; + } + if ( !hwbps [ i ].enabled ) { + available = &hwbps [ i ]; + } + } + return available; +} + +static void gdbmach_commit_hwbp ( struct hwbp *bp ) { + unsigned int regnum = bp - hwbps; + + /* Set breakpoint address */ + assert ( regnum < ( sizeof hwbps / sizeof hwbps [ 0 ] ) ); + switch ( regnum ) { + case 0: + __asm__ __volatile__ ( "movl %0, %%dr0\n" : : "r" ( bp->addr ) ); + break; + case 1: + __asm__ __volatile__ ( "movl %0, %%dr1\n" : : "r" ( bp->addr ) ); + break; + case 2: + __asm__ __volatile__ ( "movl %0, %%dr2\n" : : "r" ( bp->addr ) ); + break; + case 3: + __asm__ __volatile__ ( "movl %0, %%dr3\n" : : "r" ( bp->addr ) ); + break; + } + + /* Set type */ + dr7 &= ~( 0x3 << ( 16 + 4 * regnum ) ); + dr7 |= bp->type << ( 16 + 4 * regnum ); + + /* Set length */ + dr7 &= ~( 0x3 << ( 18 + 4 * regnum ) ); + dr7 |= bp->len << ( 18 + 4 * regnum ); + + /* Set/clear local enable bit */ + dr7 &= ~( 0x3 << 2 * regnum ); + dr7 |= bp->enabled << 2 * regnum; +} + +int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable ) { + struct hwbp *bp; + + /* Check and convert breakpoint type to x86 type */ + switch ( type ) { + case GDBMACH_WATCH: + type = 0x1; + break; + case GDBMACH_AWATCH: + type = 0x3; + break; + default: + return 0; /* unsupported breakpoint type */ + } + + /* Only lengths 1, 2, and 4 are supported */ + if ( len != 2 && len != 4 ) { + len = 1; + } + len--; /* convert to x86 breakpoint length bit pattern */ + + /* Calculate linear address by adding segment base */ + addr += virt_offset; + + /* Set up the breakpoint */ + bp = gdbmach_find_hwbp ( type, addr, len ); + if ( !bp ) { + return 0; /* ran out of hardware breakpoints */ + } + bp->type = type; + bp->addr = addr; + bp->len = len; + bp->enabled = enable; + gdbmach_commit_hwbp ( bp ); + return 1; +} + +static void gdbmach_disable_hwbps ( void ) { + /* Store and clear hardware breakpoints */ + __asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( DR7_CLEAR ) ); +} + +static void gdbmach_enable_hwbps ( void ) { + /* Clear breakpoint status register */ + __asm__ __volatile__ ( "movl %0, %%dr6\n" : : "r" ( DR6_CLEAR ) ); + + /* Restore hardware breakpoints */ + __asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( dr7 ) ); +} + +__asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) { + gdbmach_disable_hwbps(); + gdbstub_handler ( signo, regs ); + gdbmach_enable_hwbps(); +} diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/nulltrap.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/nulltrap.c new file mode 100644 index 0000000..3046fbe --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/nulltrap.c @@ -0,0 +1,51 @@ +#include <stdint.h> +#include <stdio.h> + +__attribute__ (( noreturn, section ( ".text.null_trap" ) )) +void null_function_trap ( void ) { + void *stack; + + /* 128 bytes of NOPs; the idea of this is that if something + * dereferences a NULL pointer and overwrites us, we at least + * have some chance of still getting to execute the printf() + * statement. + */ + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + __asm__ __volatile__ ( "nop ; nop ; nop ; nop" ); + + __asm__ __volatile__ ( "movl %%esp, %0" : "=r" ( stack ) ); + printf ( "NULL method called from %p (stack %p)\n", + __builtin_return_address ( 0 ), stack ); + DBG_HD ( stack, 256 ); + while ( 1 ) {} +} diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/pic8259.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/pic8259.c new file mode 100644 index 0000000..1e2d23c --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/pic8259.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <gpxe/io.h> +#include <pic8259.h> + +/** @file + * + * Minimal support for the 8259 Programmable Interrupt Controller + * + */ + +/** + * Send non-specific EOI(s) + * + * @v irq IRQ number + * + * This seems to be inherently unsafe. + */ +static inline void send_nonspecific_eoi ( unsigned int irq ) { + DBG ( "Sending non-specific EOI for IRQ %d\n", irq ); + if ( irq >= IRQ_PIC_CUTOFF ) { + outb ( ICR_EOI_NON_SPECIFIC, PIC2_ICR ); + } + outb ( ICR_EOI_NON_SPECIFIC, PIC1_ICR ); +} + +/** + * Send specific EOI(s) + * + * @v irq IRQ number + */ +static inline void send_specific_eoi ( unsigned int irq ) { + DBG ( "Sending specific EOI for IRQ %d\n", irq ); + if ( irq >= IRQ_PIC_CUTOFF ) { + outb ( ( ICR_EOI_SPECIFIC | ICR_VALUE ( CHAINED_IRQ ) ), + ICR_REG ( CHAINED_IRQ ) ); + } + outb ( ( ICR_EOI_SPECIFIC | ICR_VALUE ( irq ) ), ICR_REG ( irq ) ); +} + +/** + * Send End-Of-Interrupt to the PIC + * + * @v irq IRQ number + */ +void send_eoi ( unsigned int irq ) { + send_specific_eoi ( irq ); +} diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/rdtsc_timer.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/rdtsc_timer.c new file mode 100644 index 0000000..7667917 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/rdtsc_timer.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * RDTSC timer + * + */ + +#include <assert.h> +#include <gpxe/timer.h> +#include <gpxe/timer2.h> + +/** + * Number of TSC ticks per microsecond + * + * This is calibrated on the first use of the timer. + */ +static unsigned long rdtsc_ticks_per_usec; + +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +static void rdtsc_udelay ( unsigned long usecs ) { + unsigned long start; + unsigned long elapsed; + + /* Sanity guard, since we may divide by this */ + if ( ! usecs ) + usecs = 1; + + start = currticks(); + if ( rdtsc_ticks_per_usec ) { + /* Already calibrated; busy-wait until done */ + do { + elapsed = ( currticks() - start ); + } while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) ); + } else { + /* Not yet calibrated; use timer2 and calibrate + * based on result. + */ + timer2_udelay ( usecs ); + elapsed = ( currticks() - start ); + rdtsc_ticks_per_usec = ( elapsed / usecs ); + DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs " + "(%ld MHz)\n", elapsed, usecs, + ( rdtsc_ticks_per_usec << TSC_SHIFT ) ); + } +} + +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +static unsigned long rdtsc_ticks_per_sec ( void ) { + + /* Calibrate timer, if not already done */ + if ( ! rdtsc_ticks_per_usec ) + udelay ( 1 ); + + /* Sanity check */ + assert ( rdtsc_ticks_per_usec != 0 ); + + return ( rdtsc_ticks_per_usec * 1000 * 1000 ); +} + +PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay ); +PROVIDE_TIMER_INLINE ( rdtsc, currticks ); +PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec ); diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/relocate.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/relocate.c new file mode 100644 index 0000000..44e764f --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/relocate.c @@ -0,0 +1,170 @@ +#include <gpxe/io.h> +#include <registers.h> +#include <gpxe/memmap.h> + +/* + * Originally by Eric Biederman + * + * Heavily modified by Michael Brown + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/* + * The linker passes in the symbol _max_align, which is the alignment + * that we must preserve, in bytes. + * + */ +extern char _max_align[]; +#define max_align ( ( unsigned int ) _max_align ) + +/* Linker symbols */ +extern char _textdata[]; +extern char _etextdata[]; + +/* within 1MB of 4GB is too close. + * MAX_ADDR is the maximum address we can easily do DMA to. + * + * Not sure where this constraint comes from, but kept it from Eric's + * old code - mcb30 + */ +#define MAX_ADDR (0xfff00000UL) + +/** + * Relocate Etherboot + * + * @v ix86 x86 register dump from prefix + * @ret ix86 x86 registers to return to prefix + * + * This finds a suitable location for Etherboot near the top of 32-bit + * address space, and returns the physical address of the new location + * to the prefix in %edi. + */ +__asmcall void relocate ( struct i386_all_regs *ix86 ) { + struct memory_map memmap; + unsigned long start, end, size, padded_size; + unsigned long new_start, new_end; + unsigned i; + + /* Get memory map and current location */ + get_memmap ( &memmap ); + start = virt_to_phys ( _textdata ); + end = virt_to_phys ( _etextdata ); + size = ( end - start ); + padded_size = ( size + max_align - 1 ); + + DBG ( "Relocate: currently at [%lx,%lx)\n" + "...need %lx bytes for %d-byte alignment\n", + start, end, padded_size, max_align ); + + /* Walk through the memory map and find the highest address + * below 4GB that etherboot will fit into. Ensure etherboot + * lies entirely within a range with A20=0. This means that + * even if something screws up the state of the A20 line, the + * etherboot code is still visible and we have a chance to + * diagnose the problem. + */ + new_end = end; + for ( i = 0 ; i < memmap.count ; i++ ) { + struct memory_region *region = &memmap.regions[i]; + unsigned long r_start, r_end; + + DBG ( "Considering [%llx,%llx)\n", region->start, region->end); + + /* Truncate block to MAX_ADDR. This will be less than + * 4GB, which means that we can get away with using + * just 32-bit arithmetic after this stage. + */ + if ( region->start > MAX_ADDR ) { + DBG ( "...starts after MAX_ADDR=%lx\n", MAX_ADDR ); + continue; + } + r_start = region->start; + if ( region->end > MAX_ADDR ) { + DBG ( "...end truncated to MAX_ADDR=%lx\n", MAX_ADDR ); + r_end = MAX_ADDR; + } else { + r_end = region->end; + } + + /* Shrink the range down to use only even megabytes + * (i.e. A20=0). + */ + if ( ( r_end - 1 ) & 0x100000 ) { + /* If last byte that might be used (r_end-1) + * is in an odd megabyte, round down r_end to + * the top of the next even megabyte. + * + * Make sure that we don't accidentally wrap + * r_end below 0. + */ + if ( r_end >= 1 ) { + r_end = ( r_end - 1 ) & ~0xfffff; + DBG ( "...end truncated to %lx " + "(avoid ending in odd megabyte)\n", + r_end ); + } + } else if ( ( r_end - size ) & 0x100000 ) { + /* If the last byte that might be used + * (r_end-1) is in an even megabyte, but the + * first byte that might be used (r_end-size) + * is an odd megabyte, round down to the top + * of the next even megabyte. + * + * Make sure that we don't accidentally wrap + * r_end below 0. + */ + if ( r_end >= 0x100000 ) { + r_end = ( r_end - 0x100000 ) & ~0xfffff; + DBG ( "...end truncated to %lx " + "(avoid starting in odd megabyte)\n", + r_end ); + } + } + + DBG ( "...usable portion is [%lx,%lx)\n", r_start, r_end ); + + /* If we have rounded down r_end below r_ start, skip + * this block. + */ + if ( r_end < r_start ) { + DBG ( "...truncated to negative size\n" ); + continue; + } + + /* Check that there is enough space to fit in Etherboot */ + if ( ( r_end - r_start ) < size ) { + DBG ( "...too small (need %lx bytes)\n", size ); + continue; + } + + /* If the start address of the Etherboot we would + * place in this block is higher than the end address + * of the current highest block, use this block. + * + * Note that this avoids overlaps with the current + * Etherboot, as well as choosing the highest of all + * viable blocks. + */ + if ( ( r_end - size ) > new_end ) { + new_end = r_end; + DBG ( "...new best block found.\n" ); + } + } + + /* Calculate new location of Etherboot, and align it to the + * required alignemnt. + */ + new_start = new_end - padded_size; + new_start += ( start - new_start ) & ( max_align - 1 ); + new_end = new_start + size; + + DBG ( "Relocating from [%lx,%lx) to [%lx,%lx)\n", + start, end, new_start, new_end ); + + /* Let prefix know what to copy */ + ix86->regs.esi = start; + ix86->regs.edi = new_start; + ix86->regs.ecx = size; +} diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/setjmp.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/setjmp.S new file mode 100644 index 0000000..0372714 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/setjmp.S @@ -0,0 +1,42 @@ +/* setjmp and longjmp. Use of these functions is deprecated. */ + +FILE_LICENCE ( GPL2_OR_LATER ) + + .text + .arch i386 + .code32 + +/************************************************************************** +SETJMP - Save stack context for non-local goto +**************************************************************************/ + .globl setjmp +setjmp: + movl 4(%esp),%ecx /* jmpbuf */ + movl 0(%esp),%edx /* return address */ + movl %edx,0(%ecx) + movl %ebx,4(%ecx) + movl %esp,8(%ecx) + movl %ebp,12(%ecx) + movl %esi,16(%ecx) + movl %edi,20(%ecx) + movl $0,%eax + ret + +/************************************************************************** +LONGJMP - Non-local jump to a saved stack context +**************************************************************************/ + .globl longjmp +longjmp: + movl 4(%esp),%edx /* jumpbuf */ + movl 8(%esp),%eax /* result */ + movl 0(%edx),%ecx + movl 4(%edx),%ebx + movl 8(%edx),%esp + movl 12(%edx),%ebp + movl 16(%edx),%esi + movl 20(%edx),%edi + cmpl $0,%eax + jne 1f + movl $1,%eax +1: movl %ecx,0(%esp) + ret diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/stack.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/stack.S new file mode 100644 index 0000000..737ec0e --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/stack.S @@ -0,0 +1,15 @@ +FILE_LICENCE ( GPL2_OR_LATER ) + + .arch i386 + +/**************************************************************************** + * Internal stack + **************************************************************************** + */ + .section ".stack", "aw", @nobits + .align 8 + .globl _stack +_stack: + .space 4096 + .globl _estack +_estack: diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/stack16.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/stack16.S new file mode 100644 index 0000000..523f028 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/stack16.S @@ -0,0 +1,15 @@ +FILE_LICENCE ( GPL2_OR_LATER ) + + .arch i386 + +/**************************************************************************** + * Internal stack + **************************************************************************** + */ + .section ".stack16", "aw", @nobits + .align 8 + .globl _stack16 +_stack16: + .space 4096 + .globl _estack16 +_estack16: diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/timer2.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/timer2.c new file mode 100644 index 0000000..6e76b2e --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/timer2.c @@ -0,0 +1,87 @@ +/* + * arch/i386/core/i386_timer.c + * + * Use the "System Timer 2" to implement the udelay callback in + * the BIOS timer driver. Also used to calibrate the clock rate + * in the RTDSC timer driver. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, or (at + * your option) any later version. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stddef.h> +#include <gpxe/timer2.h> +#include <gpxe/io.h> + +/* Timers tick over at this rate */ +#define TIMER2_TICKS_PER_SEC 1193180U + +/* Parallel Peripheral Controller Port B */ +#define PPC_PORTB 0x61 + +/* Meaning of the port bits */ +#define PPCB_T2OUT 0x20 /* Bit 5 */ +#define PPCB_SPKR 0x02 /* Bit 1 */ +#define PPCB_T2GATE 0x01 /* Bit 0 */ + +/* Ports for the 8254 timer chip */ +#define TIMER2_PORT 0x42 +#define TIMER_MODE_PORT 0x43 + +/* Meaning of the mode bits */ +#define TIMER0_SEL 0x00 +#define TIMER1_SEL 0x40 +#define TIMER2_SEL 0x80 +#define READBACK_SEL 0xC0 + +#define LATCH_COUNT 0x00 +#define LOBYTE_ACCESS 0x10 +#define HIBYTE_ACCESS 0x20 +#define WORD_ACCESS 0x30 + +#define MODE0 0x00 +#define MODE1 0x02 +#define MODE2 0x04 +#define MODE3 0x06 +#define MODE4 0x08 +#define MODE5 0x0A + +#define BINARY_COUNT 0x00 +#define BCD_COUNT 0x01 + +static void load_timer2 ( unsigned int ticks ) { + /* + * Now let's take care of PPC channel 2 + * + * Set the Gate high, program PPC channel 2 for mode 0, + * (interrupt on terminal count mode), binary count, + * load 5 * LATCH count, (LSB and MSB) to begin countdown. + * + * Note some implementations have a bug where the high bits byte + * of channel 2 is ignored. + */ + /* Set up the timer gate, turn off the speaker */ + /* Set the Gate high, disable speaker */ + outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); + /* binary, mode 0, LSB/MSB, Ch 2 */ + outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT); + /* LSB of ticks */ + outb(ticks & 0xFF, TIMER2_PORT); + /* MSB of ticks */ + outb(ticks >> 8, TIMER2_PORT); +} + +static int timer2_running ( void ) { + return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0); +} + +void timer2_udelay ( unsigned long usecs ) { + load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) ); + while (timer2_running()) { + /* Do nothing */ + } +} diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/video_subr.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/video_subr.c new file mode 100644 index 0000000..c821cd0 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/video_subr.c @@ -0,0 +1,104 @@ +/* + * + * modified from linuxbios code + * by Cai Qiang <rimy2000@hotmail.com> + * + */ + +#include "stddef.h" +#include "string.h" +#include <gpxe/io.h> +#include "console.h" +#include <gpxe/init.h> +#include "vga.h" + +struct console_driver vga_console; + +static char *vidmem; /* The video buffer */ +static int video_line, video_col; + +#define VIDBUFFER 0xB8000 + +static void memsetw(void *s, int c, unsigned int n) +{ + unsigned int i; + u16 *ss = (u16 *) s; + + for (i = 0; i < n; i++) { + ss[i] = ( u16 ) c; + } +} + +static void video_init(void) +{ + static int inited=0; + + vidmem = (char *)phys_to_virt(VIDBUFFER); + + if (!inited) { + video_line = 0; + video_col = 0; + + memsetw(vidmem, VGA_ATTR_CLR_WHT, 2*1024); // + + inited=1; + } +} + +static void video_scroll(void) +{ + int i; + + memcpy(vidmem, vidmem + COLS * 2, (LINES - 1) * COLS * 2); + for (i = (LINES - 1) * COLS * 2; i < LINES * COLS * 2; i += 2) + vidmem[i] = ' '; +} + +static void vga_putc(int byte) +{ + if (byte == '\n') { + video_line++; + video_col = 0; + + } else if (byte == '\r') { + video_col = 0; + + } else if (byte == '\b') { + video_col--; + + } else if (byte == '\t') { + video_col += 4; + + } else if (byte == '\a') { + //beep + //beep(500); + + } else { + vidmem[((video_col + (video_line *COLS)) * 2)] = byte; + vidmem[((video_col + (video_line *COLS)) * 2) +1] = VGA_ATTR_CLR_WHT; + video_col++; + } + if (video_col < 0) { + video_col = 0; + } + if (video_col >= COLS) { + video_line++; + video_col = 0; + } + if (video_line >= LINES) { + video_scroll(); + video_line--; + } + // move the cursor + write_crtc((video_col + (video_line *COLS)) >> 8, CRTC_CURSOR_HI); + write_crtc((video_col + (video_line *COLS)) & 0x0ff, CRTC_CURSOR_LO); +} + +struct console_driver vga_console __console_driver = { + .putchar = vga_putc, + .disabled = 1, +}; + +struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = { + .initialise = video_init, +}; diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/virtaddr.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/virtaddr.S new file mode 100644 index 0000000..aae1e1e --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/virtaddr.S @@ -0,0 +1,103 @@ +/* + * Functions to support the virtual addressing method of relocation + * that Etherboot uses. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +#include "librm.h" + + .arch i386 + .text + .code32 + +/**************************************************************************** + * _virt_to_phys (virtual addressing) + * + * Switch from virtual to flat physical addresses. %esp is adjusted + * to a physical value. Segment registers are set to flat physical + * selectors. All other registers are preserved. Flags are + * preserved. + * + * Parameters: none + * Returns: none + **************************************************************************** + */ + .globl _virt_to_phys +_virt_to_phys: + /* Preserve registers and flags */ + pushfl + pushl %eax + pushl %ebp + + /* Change return address to a physical address */ + movl virt_offset, %ebp + addl %ebp, 12(%esp) + + /* Switch to physical code segment */ + pushl $PHYSICAL_CS + leal 1f(%ebp), %eax + pushl %eax + lret +1: + /* Reload other segment registers and adjust %esp */ + movl $PHYSICAL_DS, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + addl %ebp, %esp + + /* Restore registers and flags, and return */ + popl %ebp + popl %eax + popfl + ret + +/**************************************************************************** + * _phys_to_virt (flat physical addressing) + * + * Switch from flat physical to virtual addresses. %esp is adjusted + * to a virtual value. Segment registers are set to virtual + * selectors. All other registers are preserved. Flags are + * preserved. + * + * Note that this depends on the GDT already being correctly set up + * (e.g. by a call to run_here()). + * + * Parameters: none + * Returns: none + **************************************************************************** + */ + .globl _phys_to_virt +_phys_to_virt: + /* Preserve registers and flags */ + pushfl + pushl %eax + pushl %ebp + + /* Switch to virtual code segment */ + ljmp $VIRTUAL_CS, $1f +1: + /* Reload data segment registers */ + movl $VIRTUAL_DS, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + + /* Reload stack segment and adjust %esp */ + movl virt_offset, %ebp + movl %eax, %ss + subl %ebp, %esp + + /* Change the return address to a virtual address */ + subl %ebp, 12(%esp) + + /* Restore registers and flags, and return */ + popl %ebp + popl %eax + popfl + ret diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/wince_loader.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/wince_loader.c new file mode 100644 index 0000000..f452b65 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/wince_loader.c @@ -0,0 +1,273 @@ +#define LOAD_DEBUG 0 + +static int get_x_header(unsigned char *data, unsigned long now); +static void jump_2ep(); +static unsigned char ce_signature[] = {'B', '0', '0', '0', 'F', 'F', '\n',}; +static char ** ep; + +#define BOOT_ARG_PTR_LOCATION 0x001FFFFC + +typedef struct _BOOT_ARGS{ + unsigned char ucVideoMode; + unsigned char ucComPort; + unsigned char ucBaudDivisor; + unsigned char ucPCIConfigType; + + unsigned long dwSig; + #define BOOTARG_SIG 0x544F4F42 + unsigned long dwLen; + + unsigned char ucLoaderFlags; + unsigned char ucEshellFlags; + unsigned char ucEdbgAdapterType; + unsigned char ucEdbgIRQ; + + unsigned long dwEdbgBaseAddr; + unsigned long dwEdbgDebugZone; + unsigned long dwDHCPLeaseTime; + unsigned long dwEdbgFlags; + + unsigned long dwEBootFlag; + unsigned long dwEBootAddr; + unsigned long dwLaunchAddr; + + unsigned long pvFlatFrameBuffer; + unsigned short vesaMode; + unsigned short cxDisplayScreen; + unsigned short cyDisplayScreen; + unsigned short cxPhysicalScreen; + unsigned short cyPhysicalScreen; + unsigned short cbScanLineLength; + unsigned short bppScreen; + + unsigned char RedMaskSize; + unsigned char REdMaskPosition; + unsigned char GreenMaskSize; + unsigned char GreenMaskPosition; + unsigned char BlueMaskSize; + unsigned char BlueMaskPosition; +} BOOT_ARGS; + +BOOT_ARGS BootArgs; + +static struct segment_info{ + unsigned long addr; // Section Address + unsigned long size; // Section Size + unsigned long checksum; // Section CheckSum +} X; + +#define PSIZE (1500) //Max Packet Size +#define DSIZE (PSIZE+12) +static unsigned long dbuffer_available =0; +static unsigned long not_loadin =0; +static unsigned long d_now =0; + +unsigned long entry; +static unsigned long ce_curaddr; + + +static sector_t ce_loader(unsigned char *data, unsigned int len, int eof); +static os_download_t wince_probe(unsigned char *data, unsigned int len) +{ + if (strncmp(ce_signature, data, sizeof(ce_signature)) != 0) { + return 0; + } + printf("(WINCE)"); + return ce_loader; +} + +static sector_t ce_loader(unsigned char *data, unsigned int len, int eof) +{ + static unsigned char dbuffer[DSIZE]; + int this_write = 0; + static int firsttime = 1; + + /* + * new packet in, we have to + * [1] copy data to dbuffer, + * + * update... + * [2] dbuffer_available + */ + memcpy( (dbuffer+dbuffer_available), data, len); //[1] + dbuffer_available += len; // [2] + len = 0; + + d_now = 0; + +#if 0 + printf("dbuffer_available =%ld \n", dbuffer_available); +#endif + + if (firsttime) + { + d_now = sizeof(ce_signature); + printf("String Physical Address = %lx \n", + *(unsigned long *)(dbuffer+d_now)); + + d_now += sizeof(unsigned long); + printf("Image Size = %ld [%lx]\n", + *(unsigned long *)(dbuffer+d_now), + *(unsigned long *)(dbuffer+d_now)); + + d_now += sizeof(unsigned long); + dbuffer_available -= d_now; + + d_now = (unsigned long)get_x_header(dbuffer, d_now); + firsttime = 0; + } + + if (not_loadin == 0) + { + d_now = get_x_header(dbuffer, d_now); + } + + while ( not_loadin > 0 ) + { + /* dbuffer do not have enough data to loading, copy all */ +#if LOAD_DEBUG + printf("[0] not_loadin = [%ld], dbuffer_available = [%ld] \n", + not_loadin, dbuffer_available); + printf("[0] d_now = [%ld] \n", d_now); +#endif + + if( dbuffer_available <= not_loadin) + { + this_write = dbuffer_available ; + memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write ); + ce_curaddr += this_write; + not_loadin -= this_write; + + /* reset index and available in the dbuffer */ + dbuffer_available = 0; + d_now = 0; +#if LOAD_DEBUG + printf("[1] not_loadin = [%ld], dbuffer_available = [%ld] \n", + not_loadin, dbuffer_available); + printf("[1] d_now = [%ld], this_write = [%d] \n", + d_now, this_write); +#endif + + // get the next packet... + return (0); + } + + /* dbuffer have more data then loading ... , copy partital.... */ + else + { + this_write = not_loadin; + memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write); + ce_curaddr += this_write; + not_loadin = 0; + + /* reset index and available in the dbuffer */ + dbuffer_available -= this_write; + d_now += this_write; +#if LOAD_DEBUG + printf("[2] not_loadin = [%ld], dbuffer_available = [%ld] \n", + not_loadin, dbuffer_available); + printf("[2] d_now = [%ld], this_write = [%d] \n\n", + d_now, this_write); +#endif + + /* dbuffer not empty, proceed processing... */ + + // don't have enough data to get_x_header.. + if ( dbuffer_available < (sizeof(unsigned long) * 3) ) + { +// printf("we don't have enough data remaining to call get_x. \n"); + memcpy( (dbuffer+0), (dbuffer+d_now), dbuffer_available); + return (0); + } + else + { +#if LOAD_DEBUG + printf("with remaining data to call get_x \n"); + printf("dbuffer available = %ld , d_now = %ld\n", + dbuffer_available, d_now); +#endif + d_now = get_x_header(dbuffer, d_now); + } + } + } + return (0); +} + +static int get_x_header(unsigned char *dbuffer, unsigned long now) +{ + X.addr = *(unsigned long *)(dbuffer + now); + X.size = *(unsigned long *)(dbuffer + now + sizeof(unsigned long)); + X.checksum = *(unsigned long *)(dbuffer + now + sizeof(unsigned long)*2); + + if (X.addr == 0) + { + entry = X.size; + done(1); + printf("Entry Point Address = [%lx] \n", entry); + jump_2ep(); + } + + if (!prep_segment(X.addr, X.addr + X.size, X.addr + X.size, 0, 0)) { + longjmp(restart_etherboot, -2); + } + + ce_curaddr = X.addr; + now += sizeof(unsigned long)*3; + + /* re-calculate dbuffer available... */ + dbuffer_available -= sizeof(unsigned long)*3; + + /* reset index of this section */ + not_loadin = X.size; + +#if 1 + printf("\n"); + printf("\t Section Address = [%lx] \n", X.addr); + printf("\t Size = %d [%lx]\n", X.size, X.size); + printf("\t Checksum = %ld [%lx]\n", X.checksum, X.checksum); +#endif +#if LOAD_DEBUG + printf("____________________________________________\n"); + printf("\t dbuffer_now = %ld \n", now); + printf("\t dbuffer available = %ld \n", dbuffer_available); + printf("\t not_loadin = %ld \n", not_loadin); +#endif + + return now; +} + +static void jump_2ep() +{ + BootArgs.ucVideoMode = 1; + BootArgs.ucComPort = 1; + BootArgs.ucBaudDivisor = 1; + BootArgs.ucPCIConfigType = 1; // do not fill with 0 + + BootArgs.dwSig = BOOTARG_SIG; + BootArgs.dwLen = sizeof(BootArgs); + + if(BootArgs.ucVideoMode == 0) + { + BootArgs.cxDisplayScreen = 640; + BootArgs.cyDisplayScreen = 480; + BootArgs.cxPhysicalScreen = 640; + BootArgs.cyPhysicalScreen = 480; + BootArgs.bppScreen = 16; + BootArgs.cbScanLineLength = 1024; + BootArgs.pvFlatFrameBuffer = 0x800a0000; // ollie say 0x98000000 + } + else if(BootArgs.ucVideoMode != 0xFF) + { + BootArgs.cxDisplayScreen = 0; + BootArgs.cyDisplayScreen = 0; + BootArgs.cxPhysicalScreen = 0; + BootArgs.cyPhysicalScreen = 0; + BootArgs.bppScreen = 0; + BootArgs.cbScanLineLength = 0; + BootArgs.pvFlatFrameBuffer = 0; + } + + ep = phys_to_virt(BOOT_ARG_PTR_LOCATION); + *ep= virt_to_phys(&BootArgs); + xstart32(entry); +} diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/core/x86_io.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/x86_io.c new file mode 100644 index 0000000..d2c363b --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/core/x86_io.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <gpxe/io.h> +#include <gpxe/x86_io.h> + +/** @file + * + * gPXE I/O API for x86 + * + */ + +/** + * Read 64-bit qword from memory-mapped device + * + * @v io_addr I/O address + * @ret data Value read + * + * This routine uses MMX instructions. + */ +static uint64_t x86_readq ( volatile uint64_t *io_addr ) { + uint64_t data; + __asm__ __volatile__ ( "pushl %%edx\n\t" + "pushl %%eax\n\t" + "movq (%1), %%mm0\n\t" + "movq %%mm0, (%%esp)\n\t" + "popl %%eax\n\t" + "popl %%edx\n\t" + "emms\n\t" + : "=A" ( data ) : "r" ( io_addr ) ); + return data; +} + +/** + * Write 64-bit qword to memory-mapped device + * + * @v data Value to write + * @v io_addr I/O address + * + * This routine uses MMX instructions. + */ +static void x86_writeq ( uint64_t data, volatile uint64_t *io_addr ) { + __asm__ __volatile__ ( "pushl %%edx\n\t" + "pushl %%eax\n\t" + "movq (%%esp), %%mm0\n\t" + "movq %%mm0, (%1)\n\t" + "popl %%eax\n\t" + "popl %%edx\n\t" + "emms\n\t" + : : "A" ( data ), "r" ( io_addr ) ); +} + +PROVIDE_IOAPI_INLINE ( x86, phys_to_bus ); +PROVIDE_IOAPI_INLINE ( x86, bus_to_phys ); +PROVIDE_IOAPI_INLINE ( x86, ioremap ); +PROVIDE_IOAPI_INLINE ( x86, iounmap ); +PROVIDE_IOAPI_INLINE ( x86, io_to_bus ); +PROVIDE_IOAPI_INLINE ( x86, readb ); +PROVIDE_IOAPI_INLINE ( x86, readw ); +PROVIDE_IOAPI_INLINE ( x86, readl ); +PROVIDE_IOAPI ( x86, readq, x86_readq ); +PROVIDE_IOAPI_INLINE ( x86, writeb ); +PROVIDE_IOAPI_INLINE ( x86, writew ); +PROVIDE_IOAPI_INLINE ( x86, writel ); +PROVIDE_IOAPI ( x86, writeq, x86_writeq ); +PROVIDE_IOAPI_INLINE ( x86, inb ); +PROVIDE_IOAPI_INLINE ( x86, inw ); +PROVIDE_IOAPI_INLINE ( x86, inl ); +PROVIDE_IOAPI_INLINE ( x86, outb ); +PROVIDE_IOAPI_INLINE ( x86, outw ); +PROVIDE_IOAPI_INLINE ( x86, outl ); +PROVIDE_IOAPI_INLINE ( x86, insb ); +PROVIDE_IOAPI_INLINE ( x86, insw ); +PROVIDE_IOAPI_INLINE ( x86, insl ); +PROVIDE_IOAPI_INLINE ( x86, outsb ); +PROVIDE_IOAPI_INLINE ( x86, outsw ); +PROVIDE_IOAPI_INLINE ( x86, outsl ); +PROVIDE_IOAPI_INLINE ( x86, iodelay ); +PROVIDE_IOAPI_INLINE ( x86, mb ); |