├── include ├── smbios.h ├── stdlib.h ├── stdio.h ├── linuxboot.h ├── segment.h ├── memaccess.h ├── assembly.h ├── bswap.h ├── const.h ├── string.h ├── e820.h ├── ioport.h ├── bios.h ├── pci.h ├── multiboot.h ├── fw_cfg.h ├── mpspec_def.h ├── processor-flags.h └── start_info.h ├── benchmark.h ├── malloc.c ├── flat.lds ├── cstart.S ├── meson.build ├── README ├── code32seg.c ├── code16.c ├── entry.S ├── string.c ├── main.c ├── tables.c ├── linuxboot.c ├── hwsetup.c ├── pci.c ├── printf.c ├── mptable.c ├── smbios.c ├── fw_cfg.c └── LICENSE /include/smbios.h: -------------------------------------------------------------------------------- 1 | void extract_smbios(void); 2 | -------------------------------------------------------------------------------- /include/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef BIOS_STDLIB_H 2 | #define BIOS_STDLIB_H 1 3 | 4 | extern long atol(const char *ptr); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /include/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef BIOS_STDIO_H 2 | #define BIOS_STDIO_H 1 3 | 4 | #include 5 | 6 | extern int puts(const char *s); 7 | extern int printf(const char *fmt, ...); 8 | extern int snprintf(char *buf, int size, const char *fmt, ...); 9 | extern int vsnprintf(char *buf, int size, const char *fmt, va_list va); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /benchmark.h: -------------------------------------------------------------------------------- 1 | #ifndef BENCHMARK_H 2 | #define BENCHMARK_H 3 | 4 | /* IO ports for different exit points */ 5 | #define LINUX_EXIT_PORT 0xf4 6 | #define FW_EXIT_PORT 0xf5 7 | 8 | /* Exit point values */ 9 | #define FW_START 1 10 | #define LINUX_START_FWCFG 2 11 | #define LINUX_START_BOOT 3 12 | #define LINUX_START_PVHBOOT 4 13 | 14 | #endif /* BENCHMARK_H */ 15 | -------------------------------------------------------------------------------- /include/linuxboot.h: -------------------------------------------------------------------------------- 1 | #ifndef BIOS_LINUXBOOT_H 2 | #define BIOS_LINUXBOOT_H 1 3 | 4 | #include 5 | 6 | struct linuxboot_args { 7 | /* Output */ 8 | void *setup_addr, *cmdline_addr, *kernel_addr, *initrd_addr; 9 | uint32_t setup_size, kernel_size; 10 | 11 | /* Input */ 12 | uint32_t cmdline_size, vmlinuz_size, initrd_size; 13 | }; 14 | 15 | bool parse_bzimage(struct linuxboot_args *args); 16 | void boot_bzimage(struct linuxboot_args *args); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /include/segment.h: -------------------------------------------------------------------------------- 1 | #ifndef BIOS_SEGMENT_H 2 | #define BIOS_SEGMENT_H 3 | 4 | static inline uint32_t segment_to_flat(uint16_t selector, uint16_t offset) 5 | { 6 | return ((uint32_t)selector << 4) + (uint32_t) offset; 7 | } 8 | 9 | static inline uint16_t flat_to_seg16(uint32_t address) 10 | { 11 | return (address >> 4) & 0xf000; 12 | } 13 | 14 | static inline uint16_t flat_to_off16(uint32_t address) 15 | { 16 | return address & 65535; 17 | } 18 | 19 | #endif /* KVM_SEGMENT_H */ 20 | -------------------------------------------------------------------------------- /malloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "string.h" 3 | #include "bios.h" 4 | 5 | static uint8_t *fseg_base = &edata; 6 | static uint8_t *malloc_top = &stext; 7 | 8 | void *malloc_align(int n, int align) 9 | { 10 | malloc_top = (uint8_t *) ((uintptr_t)(malloc_top - n) & -align); 11 | return malloc_top; 12 | } 13 | 14 | void *malloc_fseg_align(int n, int align) 15 | { 16 | void *p; 17 | fseg_base = (uint8_t *) (((uintptr_t)fseg_base + align - 1) & -align); 18 | p = fseg_base; 19 | fseg_base += n; 20 | return p; 21 | } 22 | -------------------------------------------------------------------------------- /flat.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(i386) 2 | 3 | SECTIONS 4 | { 5 | . = 1024K - 64K; 6 | stext = .; 7 | .text : { *(.text.startup) *(.text) *(.text.*) } 8 | . = ALIGN(16); 9 | .data : { *(.data) } 10 | . = ALIGN(16); 11 | .rodata : { *(.rodata) } 12 | . = ALIGN(16); 13 | .bss : { *(.bss) } 14 | . = ALIGN(16); 15 | edata = .; 16 | . = 1024K - 128; 17 | sinit = .; 18 | .init : { 19 | *(.init); 20 | . = 128 - 16; 21 | *(.resetvector); 22 | . = 128; 23 | } 24 | einit = .; 25 | } 26 | 27 | ENTRY(main) 28 | 29 | -------------------------------------------------------------------------------- /include/memaccess.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMACCESS_H_ 2 | #define MEMACCESS_H_ 3 | 4 | #include "string.h" 5 | 6 | static inline uint16_t lduw_p(void *p) 7 | { 8 | uint16_t val; 9 | memcpy(&val, p, 2); 10 | return val; 11 | } 12 | 13 | static inline uint32_t ldl_p(void *p) 14 | { 15 | uint32_t val; 16 | memcpy(&val, p, 4); 17 | return val; 18 | } 19 | 20 | static inline void stw_p(void *p, uint16_t val) 21 | { 22 | memcpy(p, &val, 2); 23 | } 24 | 25 | static inline void stl_p(void *p, uint32_t val) 26 | { 27 | memcpy(p, &val, 4); 28 | } 29 | 30 | #endif /* MEMACCESS_H_ */ 31 | -------------------------------------------------------------------------------- /include/assembly.h: -------------------------------------------------------------------------------- 1 | #ifndef ASSEMBLY_H_ 2 | #define ASSEMBLY_H_ 3 | 4 | #define __ASSEMBLY__ 5 | 6 | #define __ALIGN .p2align 4, 0x90 7 | #define ENTRY(name) \ 8 | __ALIGN; \ 9 | .globl name; \ 10 | name: 11 | 12 | #define GLOBAL(name) \ 13 | .globl name; \ 14 | name: 15 | 16 | #define ENTRY_END(name) GLOBAL(name##_end) 17 | #define END(name) GLOBAL(name##_end) 18 | 19 | /* 20 | * gas produces size override prefix with which 21 | * we are unhappy, lets make it hardcoded for 22 | * 16 bit mode 23 | */ 24 | #define IRET .byte 0xcf 25 | 26 | #endif /* ASSEMBLY_H_ */ 27 | -------------------------------------------------------------------------------- /include/bswap.h: -------------------------------------------------------------------------------- 1 | #ifndef BSWAP_H 2 | #define BSWAP_H 1 3 | 4 | static inline uint16_t bswap16(uint16_t x) 5 | { 6 | return __builtin_bswap16(x); 7 | } 8 | 9 | static inline uint32_t bswap32(uint32_t x) 10 | { 11 | return __builtin_bswap32(x); 12 | } 13 | 14 | static inline uint64_t bswap64(uint64_t x) 15 | { 16 | return __builtin_bswap64(x); 17 | } 18 | 19 | static inline uint32_t ldl_le_p(const void *p) 20 | { 21 | uint32_t val; 22 | memcpy(&val, p, 4); 23 | return val; 24 | } 25 | 26 | static inline uint32_t ldl_be_p(const void *p) 27 | { 28 | uint32_t val; 29 | memcpy(&val, p, 4); 30 | return bswap32(val); 31 | } 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/const.h: -------------------------------------------------------------------------------- 1 | /* const.h: Macros for dealing with constants. */ 2 | 3 | #ifndef BIOS_CONST_H 4 | #define BIOS_CONST_H 5 | 6 | /* Some constant macros are used in both assembler and 7 | * C code. Therefore we cannot annotate them always with 8 | * 'UL' and other type specifiers unilaterally. We 9 | * use the following macros to deal with this. 10 | * 11 | * Similarly, _AT() will cast an expression with a type in C, but 12 | * leave it unchanged in asm. 13 | */ 14 | 15 | #ifdef __ASSEMBLY__ 16 | #define _AC(X,Y) X 17 | #define _AT(T,X) X 18 | #else 19 | #define __AC(X,Y) (X##Y) 20 | #define _AC(X,Y) __AC(X,Y) 21 | #define _AT(T,X) ((T)(X)) 22 | #endif 23 | 24 | #define BITUL(x) (_AC(1,UL) << (x)) 25 | #define BITULL(x) (_AC(1,ULL) << (x)) 26 | 27 | #endif /* BIOS_CONST_H */ 28 | -------------------------------------------------------------------------------- /cstart.S: -------------------------------------------------------------------------------- 1 | .code16gcc 2 | #include "assembly.h" 3 | .section .init 4 | ENTRY(pm_entry) 5 | xor %ax, %ax 6 | mov %ax, %ds 7 | mov %ax, %es 8 | mov %ax, %fs 9 | mov %ax, %gs 10 | mov %ax, %ss 11 | mov $0x7c00, %sp 12 | 13 | mov %cr0, %eax 14 | and $~((1 << 30) | (1 << 29)), %eax # clear CD and NW 15 | or $1, %al 16 | mov %eax, %cr0 17 | lgdtl %cs:0xff80 + gdt32_descr - pm_entry 18 | ljmpl $8, $0xffffff80 + 2f - pm_entry 19 | 2: 20 | .code32 21 | mov $16, %ax 22 | mov %ax, %ds 23 | mov %ax, %es 24 | mov %ax, %fs 25 | mov %ax, %gs 26 | mov %ax, %ss 27 | ljmp $8, $0xffff0000 28 | 29 | gdt32: 30 | .quad 0 31 | .quad 0x00cf9b000000ffff // flat 32-bit code segment 32 | .quad 0x00cf93000000ffff // flat 32-bit data segment 33 | .quad 0x000f9b0f0000ffff // 64K 16-bit code segment at 0xF0000 34 | .quad 0x000f93000000ffff // 64K 16-bit data segment at 0x0 35 | gdt32_end: 36 | 37 | gdt32_descr: 38 | .word gdt32_end - gdt32 - 1 39 | .long 0xffffff80 + gdt32 - pm_entry 40 | ENTRY_END(pm_entry) 41 | 42 | .code16gcc 43 | .section .resetvector 44 | jmp pm_entry 45 | 46 | -------------------------------------------------------------------------------- /include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef BIOS_STRING_H 2 | #define BIOS_STRING_H 3 | 4 | #include 5 | #include 6 | 7 | unsigned long strlen(const char *buf); 8 | char *strcat(char *dest, const char *src); 9 | char *strcpy(char *dest, const char *src); 10 | int strcmp(const char *a, const char *b); 11 | char *strchr(const char *s, int c); 12 | char *strstr(const char *s1, const char *s2); 13 | int memcmp(const void *s1, const void *s2, size_t n); 14 | void *memmove(void *dest, const void *src, size_t n); 15 | void *memchr(const void *s, int c, size_t n); 16 | uint8_t csum8(uint8_t *buf, uint32_t len); 17 | 18 | static inline void *memset(void *s, int c, size_t n) 19 | { 20 | return __builtin_memset(s, c, n); 21 | } 22 | 23 | static inline void *memcpy(void *dest, const void *src, size_t n) 24 | { 25 | return __builtin_memcpy(dest, src, n); 26 | } 27 | 28 | void *malloc_align(int n, int align); 29 | void *malloc_fseg_align(int n, int align); 30 | 31 | static inline void *malloc(int n) 32 | { 33 | return malloc_align(n, 16); 34 | } 35 | 36 | static inline void *malloc_fseg(int n) 37 | { 38 | return malloc_fseg_align(n, 16); 39 | } 40 | #endif 41 | -------------------------------------------------------------------------------- /include/e820.h: -------------------------------------------------------------------------------- 1 | #ifndef BIOS_E820_H 2 | #define BIOS_E820_H 3 | 4 | #define SMAP 0x534d4150 /* ASCII "SMAP" */ 5 | 6 | #define E820_RAM 1 7 | #define E820_RESERVED 2 8 | #define E820_ACPI 3 9 | #define E820_NVS 4 10 | #define E820_UNUSABLE 5 11 | 12 | 13 | /* 14 | * reserved RAM used by kernel itself 15 | * if CONFIG_INTEL_TXT is enabled, memory of this type will be 16 | * included in the S3 integrity calculation and so should not include 17 | * any memory that BIOS might alter over the S3 transition 18 | */ 19 | #define E820_RESERVED_KERN 128 20 | 21 | struct e820entry { 22 | uint64_t addr; /* start of memory segment */ 23 | uint64_t size; /* size of memory segment */ 24 | uint32_t type; /* type of memory segment */ 25 | } __attribute__((packed)); 26 | 27 | struct e820map { 28 | uint32_t nr_map; 29 | struct e820entry map[]; 30 | }; 31 | 32 | extern struct e820map *e820; 33 | 34 | #define ISA_START_ADDRESS 0xa0000 35 | #define ISA_END_ADDRESS 0x100000 36 | 37 | #define BIOS_BEGIN 0x000a0000 38 | #define BIOS_END 0x00100000 39 | 40 | #define BIOS_ROM_BASE 0xffe00000 41 | #define BIOS_ROM_END 0xffffffff 42 | 43 | 44 | #endif /* BIOS_E820_H */ 45 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('qboot', 'c', meson_version: '>=0.49.0') 2 | 3 | cc = meson.get_compiler('c') 4 | objcopy = find_program('objcopy') 5 | 6 | c_args = [ 7 | '-m32', 8 | '-march=i386', 9 | '-mregparm=3', 10 | '-fno-stack-protector', 11 | '-fno-delete-null-pointer-checks', 12 | '-ffreestanding', 13 | '-mstringop-strategy=rep_byte', 14 | '-minline-all-stringops', 15 | '-fno-pic', 16 | ] 17 | 18 | link_args = ['-nostdlib', '-m32'] 19 | link_args += cc.get_supported_link_arguments('-Wl,--build-id=none') 20 | link_args += '-Wl,-T' + meson.current_source_dir() / 'flat.lds' 21 | link_args += cc.get_supported_link_arguments(['-no-pie']) 22 | 23 | elf = executable( 24 | 'bios.bin.elf', 25 | files( 26 | 'code16.c', 27 | 'code32seg.c', 28 | 'cstart.S', 29 | 'entry.S', 30 | 'fw_cfg.c', 31 | 'hwsetup.c', 32 | 'linuxboot.c', 33 | 'main.c', 34 | 'malloc.c', 35 | 'mptable.c', 36 | 'pci.c', 37 | 'printf.c', 38 | 'string.c', 39 | 'smbios.c', 40 | 'tables.c', 41 | ), 42 | c_args: c_args, 43 | include_directories: include_directories('include'), 44 | link_args: link_args, 45 | ) 46 | 47 | bin = custom_target( 48 | 'bios.bin', 49 | output: 'bios.bin', 50 | input: elf, 51 | command: [objcopy, '-O', 'binary', '@INPUT@', '@OUTPUT@'], 52 | build_by_default: true, 53 | ) 54 | -------------------------------------------------------------------------------- /include/ioport.h: -------------------------------------------------------------------------------- 1 | #ifndef BIOS_IOPORT_H 2 | #define BIOS_IOPORT_H 1 3 | 4 | static inline void outsb(unsigned short port, void *buf, int len) 5 | { 6 | asm volatile("rep outsb %%ds:(%0), %3" : "=S" (buf), "=c" (len) : "m"(buf), "Nd"(port), "0" (buf), "1" (len)); 7 | } 8 | 9 | static inline void insb(void *buf, unsigned short port, int len) 10 | { 11 | asm volatile("rep insb %3, %%es:(%0)" : "=D" (buf), "=c" (len), "=m"(buf) : "Nd"(port), "0" (buf), "1" (len)); 12 | } 13 | 14 | static inline unsigned char inb(unsigned short port) 15 | { 16 | unsigned char val; 17 | asm volatile("inb %1, %0" : "=a"(val) : "Nd"(port)); 18 | return val; 19 | } 20 | 21 | static inline unsigned short inw(unsigned short port) 22 | { 23 | unsigned short val; 24 | asm volatile("inw %1, %0" : "=a"(val) : "Nd"(port)); 25 | return val; 26 | } 27 | 28 | static inline unsigned inl(unsigned short port) 29 | { 30 | unsigned val; 31 | asm volatile("inl %1, %0" : "=a"(val) : "Nd"(port)); 32 | return val; 33 | } 34 | 35 | static inline void outb(unsigned short port, unsigned char val) 36 | { 37 | asm volatile("outb %0, %1" : : "a"(val), "Nd"(port)); 38 | } 39 | 40 | static inline void outw(unsigned short port, unsigned short val) 41 | { 42 | asm volatile("outw %0, %1" : : "a"(val), "Nd"(port)); 43 | } 44 | 45 | static inline void outl(unsigned short port, unsigned val) 46 | { 47 | asm volatile("outl %0, %1" : : "a"(val), "Nd"(port)); 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | A simple x86 firmware that can boot Linux. 2 | 3 | Most of QEMU's startup time is spent: 4 | 5 | * in the dynamic linker. This can be reduced by 150 ms simply by 6 | compiling a stripped down QEMU: 7 | 8 | ./configure --disable-libssh2 --disable-tcmalloc --disable-glusterfs \ 9 | --disable-seccomp --disable-{bzip2,snappy,lzo} --disable-usb-redir \ 10 | --disable-libusb --disable-smartcard-nss --disable-libnfs \ 11 | --disable-libiscsi --disable-rbd --disable-spice --disable-attr \ 12 | --disable-cap-ng --disable-linux-aio --disable-brlapi \ 13 | --disable-vnc-{jpeg,tls,sasl,png,ws} --disable-rdma --disable-bluez \ 14 | --disable-fdt --disable-curl --disable-curses --disable-sdl \ 15 | --disable-gtk --disable-tpm --disable-vte --disable-vnc \ 16 | --disable-xen --disable-opengl --target-list=x86_64-softmmu 17 | 18 | * in the BIOS. qboot saves another 150 ms. 19 | 20 | * until QEMU 2.7+, in fw_cfg. qboot uses the DMA interface which is pretty 21 | much instantaneous. 22 | 23 | Compile qboot 24 | ============= 25 | 26 | Clone the source: 27 | 28 | $ git clone https://github.com/bonzini/qboot.git 29 | 30 | Compile the qboot firmware (you may need to install the relevant build 31 | time dependancies): 32 | 33 | $ meson build && ninja -C build 34 | 35 | The result will be a 64K file named bios.bin under the build/ directory. 36 | 37 | Usage 38 | ===== 39 | 40 | $ qemu-kvm -bios bios.bin \ 41 | -kernel /boot/vmlinuz-4.0.3-300.fc22.x86_64 \ 42 | -serial mon:stdio -append 'console=ttyS0,115200,8n1' 43 | 44 | TODO 45 | ==== 46 | 47 | * Add the possibility to configure out PIC and PCI bridge initialization 48 | -------------------------------------------------------------------------------- /code32seg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bios.h" 3 | #include "pci.h" 4 | #include "processor-flags.h" 5 | 6 | #define PCI_FUNC_NOT_SUPPORTED 0x81 7 | #define PCI_BAD_VENDOR_ID 0x83 8 | #define PCI_DEVICE_NOT_FOUND 0x86 9 | #define PCI_BUFFER_TOO_SMALL 0x89 10 | 11 | /* 12 | * The PCIBIOS handler must be position independent. To read a flat pointer, 13 | * we use the instruction pointer to retrieve the address corresponding to 14 | * physical address 0 (i.e., what Linux calls PAGE_OFFSET). 15 | */ 16 | 17 | static inline void *from_flat_ptr(void *p) 18 | { 19 | return p + pic_base(); 20 | } 21 | 22 | #define FLAT_VAR(x) (*(typeof(&(x))) from_flat_ptr(&(x))) 23 | 24 | #pragma GCC optimize("no-jump-tables") 25 | 26 | bioscall void pcibios_handler(struct bios32regs *args) 27 | { 28 | switch (args->eax) { 29 | /* discovery */ 30 | case 0xb101: 31 | args->eax = 0x01; 32 | args->ebx = 0x210; 33 | args->ecx = FLAT_VAR(max_bus); 34 | args->edx = 0x20494350; 35 | goto success; 36 | 37 | /* config space access */ 38 | case 0xb108: 39 | args->ecx = pci_config_readb(args->ebx, args->edi); 40 | goto success; 41 | case 0xb109: 42 | args->ecx = pci_config_readw(args->ebx, args->edi); 43 | goto success; 44 | case 0xb10a: 45 | args->ecx = pci_config_readl(args->ebx, args->edi); 46 | goto success; 47 | case 0xb10b: 48 | pci_config_writeb(args->ebx, args->edi, args->ecx); 49 | goto success; 50 | case 0xb10c: 51 | pci_config_writew(args->ebx, args->edi, args->ecx); 52 | goto success; 53 | case 0xb10d: 54 | pci_config_writel(args->ebx, args->edi, args->ecx); 55 | goto success; 56 | 57 | /* find device id, find class code */ 58 | case 0xb102: 59 | case 0xb103: 60 | args->eax &= ~0xff00; 61 | args->eax |= PCI_DEVICE_NOT_FOUND << 8; 62 | break; 63 | 64 | default: 65 | args->eax &= ~0xff00; 66 | args->eax |= PCI_FUNC_NOT_SUPPORTED << 8; 67 | break; 68 | } 69 | args->eflags |= X86_EFLAGS_CF; 70 | return; 71 | 72 | success: 73 | /* On entry, CF=0 */ 74 | args->eax &= ~0xff00; /* clear ah */ 75 | } 76 | -------------------------------------------------------------------------------- /include/bios.h: -------------------------------------------------------------------------------- 1 | #ifndef BIOS_H_ 2 | #define BIOS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * When interfacing with assembler code we need to be sure how 10 | * arguments are passed in real mode. 11 | */ 12 | #define bioscall __attribute__((regparm(3))) 13 | 14 | #ifndef __ASSEMBLER__ 15 | 16 | struct biosregs { 17 | uint32_t eax; 18 | uint32_t ebx; 19 | uint32_t ecx; 20 | uint32_t edx; 21 | uint32_t esp; 22 | uint32_t ebp; 23 | uint32_t esi; 24 | uint32_t edi; 25 | uint32_t ds; 26 | uint32_t es; 27 | uint32_t fs; 28 | uint16_t ip; 29 | uint16_t cs; 30 | uint16_t eflags; 31 | } __attribute__((packed)); 32 | 33 | /* 34 | * BIOS32 is called via a far call, so eflags is pushed by our 35 | * entry point and lies below CS:EIP. We do not include CS:EIP 36 | * at all in this struct. 37 | */ 38 | struct bios32regs { 39 | uint32_t eax; 40 | uint32_t ebx; 41 | uint32_t ecx; 42 | uint32_t edx; 43 | uint32_t esp; 44 | uint32_t ebp; 45 | uint32_t esi; 46 | uint32_t edi; 47 | uint32_t ds; 48 | uint32_t es; 49 | uint32_t fs; 50 | uint32_t eflags; 51 | } __attribute__((packed)); 52 | 53 | extern bioscall void int10_handler(struct biosregs *regs); 54 | extern bioscall void int15_handler(struct biosregs *regs); 55 | extern bioscall void e820_query_map(struct biosregs *regs); 56 | extern bioscall void pcibios_handler(struct bios32regs *regs); 57 | 58 | extern void bios_intfake(void); 59 | extern void bios_irq(void); 60 | extern void bios_int10(void); 61 | extern void bios_int15(void); 62 | extern void bios32_entry(void); 63 | 64 | extern uint32_t pic_base(void); 65 | 66 | extern void setup_pci(void); 67 | extern bool setup_hw(void); 68 | extern bool setup_mmconfig(void); 69 | extern void setup_mptable(void); 70 | extern void extract_acpi(void); 71 | extern void boot_from_fwcfg(void); 72 | 73 | extern uint8_t max_bus; 74 | extern uint16_t e820_seg; 75 | extern uint32_t lowmem; 76 | 77 | extern uint8_t stext; 78 | extern uint8_t edata; 79 | extern uint8_t sinit; 80 | extern uint8_t einit; 81 | 82 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) 83 | 84 | static inline void __attribute__((noreturn)) panic(void) 85 | { 86 | asm volatile("cli; hlt"); 87 | for(;;); 88 | } 89 | 90 | #endif 91 | 92 | #endif /* BIOS_H_ */ 93 | -------------------------------------------------------------------------------- /include/pci.h: -------------------------------------------------------------------------------- 1 | #ifndef BIOS_PCI_H 2 | #define BIOS_PCI_H 3 | 4 | #include "ioport.h" 5 | 6 | static inline void pci_config_writel(uint16_t bdf, uint32_t addr, uint32_t val) 7 | { 8 | outl(0xcf8, 0x80000000 | (bdf << 8) | (addr & 0xfc)); 9 | outl(0xcfc, val); 10 | } 11 | 12 | static inline void pci_config_writew(uint16_t bdf, uint32_t addr, uint16_t val) 13 | { 14 | outl(0xcf8, 0x80000000 | (bdf << 8) | (addr & 0xfc)); 15 | outw(0xcfc | (addr & 2), val); 16 | } 17 | 18 | static inline void pci_config_writeb(uint16_t bdf, uint32_t addr, uint8_t val) 19 | { 20 | outl(0xcf8, 0x80000000 | (bdf << 8) | (addr & 0xfc)); 21 | outb(0xcfc | (addr & 3), val); 22 | } 23 | 24 | static inline uint32_t pci_config_readl(uint16_t bdf, uint32_t addr) 25 | { 26 | outl(0xcf8, 0x80000000 | (bdf << 8) | (addr & 0xfc)); 27 | return inl(0xcfc); 28 | } 29 | 30 | static inline uint16_t pci_config_readw(uint16_t bdf, uint32_t addr) 31 | { 32 | outl(0xcf8, 0x80000000 | (bdf << 8) | (addr & 0xfc)); 33 | return inw(0xcfc | (addr & 2)); 34 | } 35 | 36 | static inline uint8_t pci_config_readb(uint16_t bdf, uint32_t addr) 37 | { 38 | outl(0xcf8, 0x80000000 | (bdf << 8) | (addr & 0xfc)); 39 | return inb(0xcfc | (addr & 3)); 40 | } 41 | 42 | #define PCI_VENDOR_ID 0x00 43 | #define PCI_DEVICE_ID 0x02 44 | #define PCI_COMMAND 0x04 45 | #define PCI_CLASS_DEVICE 0x0a 46 | #define PCI_HEADER_TYPE 0x0e 47 | #define PCI_PRIMARY_BUS 0x18 48 | #define PCI_SECONDARY_BUS 0x19 49 | #define PCI_SUBORDINATE_BUS 0x1a 50 | #define PCI_INTERRUPT_LINE 0x3c 51 | #define PCI_INTERRUPT_PIN 0x3d 52 | #define PCI_BRIDGE_CONTROL 0x3e 53 | 54 | /* PCI_COMMAND */ 55 | #define PCI_COMMAND_DIS_INTX 0x400 56 | 57 | /* PCI_CLASS_DEVICE */ 58 | #define PCI_CLASS_STORAGE_IDE 0x0101 59 | #define PCI_CLASS_BRIDGE_PCI 0x0604 60 | 61 | /* PCI_HEADER_TYPE */ 62 | #define PCI_HEADER_TYPE_BRIDGE 1 63 | #define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 64 | 65 | /* PCI_BRIDGE_CONTROL */ 66 | #define PCI_BRIDGE_CTL_SERR 0x02 67 | 68 | /* PCI_VENDOR_ID / PCI_DEVICE_ID */ 69 | #define PCI_VENDOR_ID_INTEL 0x8086 70 | #define PCI_DEVICE_ID_INTEL_82441 0x1237 71 | #define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 72 | #define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 73 | #define PCI_DEVICE_ID_INTEL_82371AB 0x7111 74 | 75 | #define PCIE_MMCONFIG_BASE 0xb0000000 76 | #define PCIE_MMCONFIG_SIZE (256 * 1024 * 1024) 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /include/multiboot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Kevin Wolf 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef MULTIBOOT_H 24 | #define MULTIBOOT_H 25 | 26 | #include 27 | 28 | struct mb_info { 29 | uint32_t flags; 30 | uint32_t mem_lower; 31 | uint32_t mem_upper; 32 | uint32_t boot_device; 33 | uint32_t cmdline; 34 | uint32_t mods_count; 35 | uint32_t mods_addr; 36 | char syms[16]; 37 | uint32_t mmap_length; 38 | uint32_t mmap_addr; 39 | uint32_t drives_length; 40 | uint32_t drives_addr; 41 | uint32_t config_table; 42 | uint32_t boot_loader_name; 43 | uint32_t apm_table; 44 | uint32_t vbe_control_info; 45 | uint32_t vbe_mode_info; 46 | uint16_t vbe_mode; 47 | uint16_t vbe_interface_seg; 48 | uint16_t vbe_interface_off; 49 | uint16_t vbe_interface_len; 50 | } __attribute__((packed)); 51 | 52 | struct mb_module { 53 | uint32_t mod_start; 54 | uint32_t mod_end; 55 | uint32_t string; 56 | uint32_t reserved; 57 | } __attribute__((packed)); 58 | 59 | struct mb_mmap_entry { 60 | uint32_t size; 61 | uint64_t base_addr; 62 | uint64_t length; 63 | uint32_t type; 64 | } __attribute__((packed)); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /code16.c: -------------------------------------------------------------------------------- 1 | asm(".code16gcc"); 2 | #include 3 | #include "bios.h" 4 | #include "segment.h" 5 | #include "ioport.h" 6 | #include "processor-flags.h" 7 | #include "e820.h" 8 | 9 | static inline void set_fs(uint16_t seg) 10 | { 11 | asm volatile("movw %0,%%fs" : : "rm" (seg)); 12 | } 13 | 14 | static inline uint8_t rdfs8(unsigned long addr) 15 | { 16 | uint8_t v; 17 | 18 | asm volatile("addr32 movb %%fs:%1,%0" : "=q" (v) : "m" (*(uint8_t *)addr)); 19 | 20 | return v; 21 | } 22 | 23 | static inline uint32_t rdfs32(unsigned long addr) 24 | { 25 | uint32_t v; 26 | 27 | asm volatile("addr32 movl %%fs:%1,%0" : "=r" (v) : "m" (*(uint32_t *)addr)); 28 | 29 | return v; 30 | } 31 | 32 | static inline uint16_t rdcs16(void *p) 33 | { 34 | uint32_t addr = ((uintptr_t) p) & 65535; 35 | uint16_t v; 36 | 37 | asm volatile("addr32 movw %%cs:%1,%0" : "=r" (v) : "m" (*(uint32_t *)addr)); 38 | 39 | return v; 40 | } 41 | 42 | uint16_t e820_seg; 43 | 44 | bioscall void e820_query_map(struct biosregs *regs) 45 | { 46 | uint32_t map_size; 47 | uint32_t ndx; 48 | 49 | set_fs(rdcs16(&e820_seg)); 50 | 51 | ndx = regs->ebx; 52 | 53 | map_size = rdfs32(offsetof(struct e820map, nr_map)); 54 | 55 | if (ndx < map_size) { 56 | uint32_t start; 57 | unsigned int i; 58 | uint8_t *p; 59 | 60 | start = offsetof(struct e820map, map[ndx]); 61 | 62 | p = (void *) regs->edi; 63 | 64 | for (i = 0; i < sizeof(struct e820entry); i++) 65 | *p++ = rdfs8(start + i); 66 | } 67 | 68 | regs->eax = SMAP; 69 | regs->ecx = sizeof(struct e820entry); 70 | regs->ebx = ++ndx; 71 | 72 | if (ndx >= map_size) 73 | regs->ebx = 0; /* end of map */ 74 | } 75 | 76 | bioscall void int15_handler(struct biosregs *regs) 77 | { 78 | switch (regs->eax) { 79 | case 0xe820: 80 | e820_query_map(regs); 81 | break; 82 | default: 83 | /* Set CF to indicate failure. */ 84 | regs->eflags |= X86_EFLAGS_CF; 85 | break; 86 | } 87 | } 88 | /* 89 | * It's probably much more useful to make this print to the serial 90 | * line rather than print to a non-displayed VGA memory 91 | */ 92 | static inline void int10_putchar(struct biosregs *args) 93 | { 94 | uint8_t al = args->eax & 0xFF; 95 | 96 | outb(0x3f8, al); 97 | } 98 | 99 | #define VBE_STATUS_OK 0x004F 100 | #define VBE_STATUS_FAIL 0x014F 101 | 102 | static void int10_vesa(struct biosregs *args) 103 | { 104 | args->eax = VBE_STATUS_FAIL; 105 | } 106 | 107 | bioscall void int10_handler(struct biosregs *args) 108 | { 109 | uint8_t ah; 110 | 111 | ah = (args->eax & 0xff00) >> 8; 112 | 113 | switch (ah) { 114 | case 0x0e: 115 | int10_putchar(args); 116 | break; 117 | case 0x4f: 118 | int10_vesa(args); 119 | break; 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /entry.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Our pretty trivial BIOS emulation 3 | */ 4 | 5 | #include "assembly.h" 6 | #include "processor-flags.h" 7 | 8 | .org 0 9 | .code16gcc 10 | 11 | /* 12 | * handy BIOS macros 13 | */ 14 | 15 | /* If you change these macros, remember to update 'struct biosregs' */ 16 | .macro SAVE_BIOSREGS 17 | pushl %fs 18 | pushl %es 19 | pushl %ds 20 | pushl %edi 21 | pushl %esi 22 | pushl %ebp 23 | pushl %esp 24 | pushl %edx 25 | pushl %ecx 26 | pushl %ebx 27 | pushl %eax 28 | .endm 29 | 30 | .macro RESTORE_BIOSREGS 31 | popl %eax 32 | popl %ebx 33 | popl %ecx 34 | popl %edx 35 | popl %esp 36 | popl %ebp 37 | popl %esi 38 | popl %edi 39 | popl %ds 40 | popl %es 41 | popl %fs 42 | .endm 43 | 44 | ENTRY(bios_irq) 45 | pushw %ax 46 | mov $0x20, %al 47 | out %al, $0x20 48 | popw %ax 49 | IRET 50 | ENTRY_END(bios_irq) 51 | 52 | /* 53 | * fake interrupt handler, nothing can be faster ever 54 | */ 55 | ENTRY(bios_intfake) 56 | /* 57 | * Set CF to indicate failure. We don't want callers to think that the 58 | * interrupt handler succeeded and then treat the return values in 59 | * registers as valid data. 60 | */ 61 | orb $X86_EFLAGS_CF, 0x4(%esp) 62 | 63 | IRET 64 | ENTRY_END(bios_intfake) 65 | 66 | /* 67 | * int 10 - video - service 68 | */ 69 | ENTRY(bios_int10) 70 | andb $~X86_EFLAGS_CF, 0x4(%esp) 71 | SAVE_BIOSREGS 72 | 73 | movl %esp, %eax 74 | /* this is way easier than doing it in assembly */ 75 | /* just push all the regs and jump to a C handler */ 76 | call int10_handler 77 | 78 | RESTORE_BIOSREGS 79 | 80 | IRET 81 | ENTRY_END(bios_int10) 82 | 83 | ENTRY(bios_int15) 84 | andb $~X86_EFLAGS_CF, 0x4(%esp) 85 | SAVE_BIOSREGS 86 | 87 | movl %esp, %eax 88 | call int15_handler 89 | 90 | RESTORE_BIOSREGS 91 | 92 | IRET 93 | ENTRY_END(bios_int15) 94 | 95 | .code32 96 | ENTRY(pcibios_entry) 97 | clc 98 | pushfl 99 | SAVE_BIOSREGS 100 | 101 | movl %esp, %eax 102 | call pcibios_handler 103 | 104 | RESTORE_BIOSREGS 105 | popfl 106 | lretl 107 | ENTRY_END(pcibios_entry) 108 | 109 | ENTRY(bios32_entry) 110 | pushfl 111 | testl %ebx, %ebx /* BIOS32 service directory? */ 112 | jnz 2f 113 | cmp $0x49435024, %eax /* "$PCI"? */ 114 | movb $0x80, %al /* service not present */ 115 | jne 1f 116 | xorl %ebx, %ebx /* fill in base/length/entry */ 117 | movl $(1 << 20), %ecx 118 | movl $pcibios_entry, %edx 119 | movb $0x00, %al /* service present */ 120 | 1: 121 | popfl 122 | lretl 123 | 2: 124 | movb $0x81, %al /* unimplemented function */ 125 | popfl 126 | lretl 127 | ENTRY_END(bios32_entry) 128 | 129 | ENTRY(pic_base) 130 | call 1f 131 | 2: 132 | ret 133 | 1: 134 | popl %eax 135 | pushl %eax 136 | subl $2b, %eax 137 | ret /* return to 2b */ 138 | ENTRY_END(pic_base) 139 | -------------------------------------------------------------------------------- /string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | unsigned long strlen(const char *buf) 4 | { 5 | unsigned long len = 0; 6 | 7 | while (*buf++) 8 | ++len; 9 | return len; 10 | } 11 | 12 | char *strcat(char *dest, const char *src) 13 | { 14 | char *p = dest; 15 | 16 | while (*p) 17 | ++p; 18 | while ((*p++ = *src++) != 0) 19 | ; 20 | return dest; 21 | } 22 | 23 | char *strcpy(char *dest, const char *src) 24 | { 25 | *dest = 0; 26 | return strcat(dest, src); 27 | } 28 | 29 | int strcmp(const char *a, const char *b) 30 | { 31 | while (*a == *b) { 32 | if (*a == '\0') { 33 | break; 34 | } 35 | ++a, ++b; 36 | } 37 | return *a - *b; 38 | } 39 | 40 | char *strchr(const char *s, int c) 41 | { 42 | while (*s != (char)c) 43 | if (*s++ == '\0') 44 | return NULL; 45 | return (char *)s; 46 | } 47 | 48 | char *strstr(const char *s1, const char *s2) 49 | { 50 | size_t l1, l2; 51 | 52 | l2 = strlen(s2); 53 | if (!l2) 54 | return (char *)s1; 55 | l1 = strlen(s1); 56 | while (l1 >= l2) { 57 | l1--; 58 | if (!memcmp(s1, s2, l2)) 59 | return (char *)s1; 60 | s1++; 61 | } 62 | return NULL; 63 | } 64 | 65 | int memcmp(const void *s1, const void *s2, size_t n) 66 | { 67 | const unsigned char *a = s1, *b = s2; 68 | int ret = 0; 69 | 70 | while (n--) { 71 | ret = *a - *b; 72 | if (ret) 73 | break; 74 | ++a, ++b; 75 | } 76 | return ret; 77 | } 78 | 79 | void *memmove(void *dest, const void *src, size_t n) 80 | { 81 | const unsigned char *s = src; 82 | unsigned char *d = dest; 83 | 84 | if (d <= s) { 85 | while (n--) 86 | *d++ = *s++; 87 | } else { 88 | d += n, s += n; 89 | while (n--) 90 | *--d = *--s; 91 | } 92 | return dest; 93 | } 94 | 95 | void *memchr(const void *s, int c, size_t n) 96 | { 97 | const unsigned char *str = s, chr = (unsigned char)c; 98 | 99 | while (n--) 100 | if (*str++ == chr) 101 | return (void *)(str - 1); 102 | return NULL; 103 | } 104 | 105 | long atol(const char *ptr) 106 | { 107 | long acc = 0; 108 | const char *s = ptr; 109 | int neg, c; 110 | 111 | while (*s == ' ' || *s == '\t') 112 | s++; 113 | if (*s == '-'){ 114 | neg = 1; 115 | s++; 116 | } else { 117 | neg = 0; 118 | if (*s == '+') 119 | s++; 120 | } 121 | 122 | while (*s) { 123 | if (*s < '0' || *s > '9') 124 | break; 125 | c = *s - '0'; 126 | acc = acc * 10 + c; 127 | s++; 128 | } 129 | 130 | if (neg) 131 | acc = -acc; 132 | 133 | return acc; 134 | } 135 | 136 | uint8_t csum8(uint8_t *buf, uint32_t len) 137 | { 138 | uint32_t s = 0; 139 | while (len-- > 0) 140 | s += *buf++; 141 | return s; 142 | } 143 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bios.h" 3 | #include "stdio.h" 4 | #include "e820.h" 5 | #include "string.h" 6 | #include "segment.h" 7 | #include "fw_cfg.h" 8 | #include "pci.h" 9 | #include "benchmark.h" 10 | #include "smbios.h" 11 | 12 | static void set_realmode_int(int vec, void *p) 13 | { 14 | uint16_t *realmode_idt = (uint16_t *) 0; 15 | realmode_idt[vec * 2] = flat_to_off16((uintptr_t) p); 16 | realmode_idt[vec * 2 + 1] = flat_to_seg16((uintptr_t) p); 17 | } 18 | 19 | static void setup_idt(void) 20 | { 21 | int i; 22 | for (i = 0; i < 0x100; i++) 23 | set_realmode_int(i, bios_intfake); 24 | for (i = 8; i < 16; i++) 25 | set_realmode_int(i, bios_irq); 26 | for (i = 0x70; i < 0x78; i++) 27 | set_realmode_int(i, bios_irq); 28 | set_realmode_int(0x10, bios_int10); 29 | set_realmode_int(0x15, bios_int15); 30 | } 31 | 32 | /* Top of memory below 4GB. */ 33 | uint32_t lowmem; 34 | struct e820map *e820; 35 | static bool have_mmconfig; 36 | 37 | static void extract_e820(void) 38 | { 39 | int id = fw_cfg_file_id("etc/e820"); 40 | uint32_t size; 41 | int nr_map; 42 | int i; 43 | 44 | if (id == -1) 45 | panic(); 46 | 47 | size = fw_cfg_file_size(id); 48 | nr_map = size / sizeof(e820->map[0]) + 5; 49 | 50 | e820 = malloc(offsetof(struct e820map, map[nr_map])); 51 | e820->nr_map = nr_map; 52 | e820->map[0] = (struct e820entry) 53 | { .addr = 0, .size = 639 * 1024, .type = E820_RAM }; /* low RAM */ 54 | e820->map[1] = (struct e820entry) 55 | { .addr = 639 * 1024, .size = 1024, .type = E820_RESERVED }; /* EBDA */ 56 | e820->map[2] = (struct e820entry) 57 | { .addr = 0xd0000, .size = 128 * 1024, .type = E820_NVS }; /* ACPI tables */ 58 | e820->map[3] = (struct e820entry) 59 | { .addr = 0xf0000, .size = 64 * 1024, .type = E820_RESERVED }; /* firmware */ 60 | 61 | i = 4; 62 | if (have_mmconfig) 63 | e820->map[i++] = (struct e820entry) 64 | { .addr = PCIE_MMCONFIG_BASE, .size = PCIE_MMCONFIG_SIZE, .type = E820_RESERVED }; 65 | else 66 | nr_map--; 67 | 68 | fw_cfg_read_file(id, &e820->map[i], size); 69 | for (; i < e820->nr_map; i++) 70 | if (e820->map[i].addr == 0) { 71 | lowmem = e820->map[i].size; 72 | e820->map[i].addr = 1024 * 1024; 73 | e820->map[i].size -= 1024 * 1024; 74 | break; 75 | } 76 | 77 | e820_seg = ((uintptr_t) e820) >> 4; 78 | } 79 | 80 | int __attribute__ ((section (".text.startup"))) main(void) 81 | { 82 | bool have_pci; 83 | #ifdef BENCHMARK_HACK 84 | outb(FW_EXIT_PORT, FW_START); 85 | #endif 86 | have_pci = setup_hw(); 87 | 88 | // Only the 16-bit trampoline for vmlinuz and the 16-bit interrupt 89 | // handlers need to run from the F-segment, but keep things simple 90 | // and jump there. From this point we can modify global variables. 91 | asm("ljmp $0x8, $1f; 1:"); 92 | 93 | have_mmconfig = setup_mmconfig(); 94 | if (have_pci) { 95 | setup_pci(); 96 | } 97 | setup_idt(); 98 | fw_cfg_setup(); 99 | extract_acpi(); 100 | extract_e820(); 101 | setup_mptable(); 102 | extract_smbios(); 103 | boot_from_fwcfg(); 104 | panic(); 105 | } 106 | -------------------------------------------------------------------------------- /tables.c: -------------------------------------------------------------------------------- 1 | #include "bios.h" 2 | #include "stdio.h" 3 | #include "fw_cfg.h" 4 | #include "string.h" 5 | #include "start_info.h" 6 | 7 | extern struct hvm_start_info start_info; 8 | 9 | struct loader_cmd { 10 | uint32_t cmd; 11 | union { 12 | #define CMD_QUIT 0 13 | #define CMD_ALLOC 1 14 | struct { 15 | char file[56]; 16 | uint32_t align; 17 | uint8_t zone; 18 | } alloc; 19 | #define CMD_PTR 2 20 | struct { 21 | char dest[56]; 22 | char src[56]; 23 | uint32_t offset; 24 | uint8_t size; 25 | } ptr; 26 | #define CMD_CHECKSUM 3 27 | struct { 28 | char file[56]; 29 | uint32_t offset; 30 | uint32_t start; 31 | uint32_t len; 32 | } checksum; 33 | uint8_t pad[124]; 34 | }; 35 | } __attribute__((__packed__)); 36 | 37 | enum { 38 | ALLOC_HIGH = 1, 39 | ALLOC_FSEG = 2 40 | }; 41 | 42 | static uint8_t *file_address[20]; 43 | 44 | static inline void *id_to_addr(int fw_cfg_id) 45 | { 46 | return file_address[fw_cfg_id]; 47 | } 48 | 49 | static inline void set_file_addr(int fw_cfg_id, void *p) 50 | { 51 | file_address[fw_cfg_id] = p; 52 | } 53 | 54 | static void do_alloc(char *file, uint32_t align, uint8_t zone) 55 | { 56 | int id = fw_cfg_file_id(file); 57 | int n = fw_cfg_file_size(id); 58 | char *p; 59 | 60 | if (id == -1) 61 | panic(); 62 | 63 | if (align < 16) 64 | align = 16; 65 | 66 | if (zone == ALLOC_FSEG) 67 | p = malloc_fseg_align(n, align); 68 | else 69 | p = malloc_align(n, align); 70 | 71 | set_file_addr(id, p); 72 | fw_cfg_read_file(id, p, n); 73 | 74 | /* For PVH boot, save the PA where the RSDP is stored */ 75 | if (zone == ALLOC_FSEG) { 76 | if (!memcmp(p, "RSD PTR ", 8)) { 77 | start_info.rsdp_paddr = (uintptr_t)id_to_addr(id); 78 | } 79 | } 80 | } 81 | 82 | static void do_ptr(char *dest, char *src, uint32_t offset, uint8_t size) 83 | { 84 | char *p, *q; 85 | int id; 86 | union { 87 | long long ll; 88 | char b[8]; 89 | } data; 90 | 91 | id = fw_cfg_file_id(src); 92 | p = id_to_addr(id); 93 | if (!p) 94 | panic(); 95 | 96 | id = fw_cfg_file_id(dest); 97 | q = id_to_addr(id); 98 | if (!q) 99 | panic(); 100 | 101 | q += offset; 102 | 103 | /* Assumes little endian */ 104 | data.ll = 0; 105 | memcpy(&data.b, q, size); 106 | data.ll += (uintptr_t) p; 107 | memcpy(q, &data.b, size); 108 | } 109 | 110 | static void do_checksum(char *file, uint32_t offset, uint32_t start, uint32_t len) 111 | { 112 | uint8_t *p; 113 | int id; 114 | int n; 115 | 116 | id = fw_cfg_file_id(file); 117 | p = id_to_addr(id); 118 | if (!p) 119 | panic(); 120 | 121 | n = fw_cfg_file_size(id); 122 | if (offset >= n || n < start || len > n - start) 123 | panic(); 124 | 125 | p[offset] -= csum8(&p[start], len); 126 | } 127 | 128 | void extract_acpi(void) 129 | { 130 | int id = fw_cfg_file_id("etc/table-loader"); 131 | int n = fw_cfg_file_size(id); 132 | struct loader_cmd script[n / sizeof(struct loader_cmd)]; 133 | int i; 134 | 135 | if (!n) 136 | return; 137 | 138 | fw_cfg_read_file(id, script, n); 139 | 140 | for (i = 0; i < ARRAY_SIZE(script); i++) { 141 | struct loader_cmd *s = &script[i]; 142 | switch(script[i].cmd) { 143 | case CMD_ALLOC: 144 | do_alloc(s->alloc.file, s->alloc.align, s->alloc.zone); 145 | break; 146 | case CMD_PTR: 147 | do_ptr(s->ptr.dest, s->ptr.src, s->ptr.offset, s->ptr.size); 148 | break; 149 | case CMD_CHECKSUM: 150 | do_checksum(s->checksum.file, s->checksum.offset, 151 | s->checksum.start, s->checksum.len); 152 | break; 153 | case CMD_QUIT: 154 | return; 155 | default: 156 | panic(); 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /linuxboot.c: -------------------------------------------------------------------------------- 1 | #include "bios.h" 2 | #include "linuxboot.h" 3 | #include "memaccess.h" 4 | #include "ioport.h" 5 | #include "start_info.h" 6 | #include "string.h" 7 | #include "stdio.h" 8 | #include "benchmark.h" 9 | 10 | struct hvm_start_info start_info = {0}; 11 | 12 | bool parse_bzimage(struct linuxboot_args *args) 13 | { 14 | uint8_t *header = args->setup_addr; 15 | 16 | uint32_t real_addr, cmdline_addr, prot_addr, initrd_addr; 17 | uint32_t setup_size; 18 | uint32_t initrd_max; 19 | uint16_t protocol; 20 | 21 | if (ldl_p(header+0x202) == 0x53726448) 22 | protocol = lduw_p(header+0x206); 23 | else { 24 | /* assume multiboot. TODO: scan for header */ 25 | return false; 26 | // protocol = 0; 27 | } 28 | 29 | if (protocol < 0x200 || !(header[0x211] & 0x01)) { 30 | /* Low kernel */ 31 | real_addr = 0x90000; 32 | cmdline_addr = (0x9a000 - args->cmdline_size) & ~15; 33 | prot_addr = 0x10000; 34 | } else if (protocol < 0x202) { 35 | /* High but ancient kernel */ 36 | real_addr = 0x90000; 37 | cmdline_addr = (0x9a000 - args->cmdline_size) & ~15; 38 | prot_addr = 0x100000; 39 | } else { 40 | /* High and recent kernel */ 41 | real_addr = 0x10000; 42 | cmdline_addr = 0x20000; 43 | prot_addr = 0x100000; 44 | } 45 | 46 | if (protocol >= 0x203) 47 | initrd_max = ldl_p(header+0x22c); 48 | else 49 | initrd_max = 0x37ffffff; 50 | if (initrd_max > lowmem - 1) 51 | initrd_max = lowmem - 1; 52 | 53 | if (protocol >= 0x202) 54 | stl_p(header+0x228, cmdline_addr); 55 | else { 56 | stw_p(header+0x20, 0xA33F); 57 | stw_p(header+0x22, cmdline_addr-real_addr); 58 | } 59 | 60 | /* High nybble = B reserved for QEMU; low nybble is revision number. 61 | * If this code is substantially changed, you may want to consider 62 | * incrementing the revision. */ 63 | if (protocol >= 0x200) 64 | header[0x210] = 0xB0; 65 | 66 | /* heap */ 67 | if (protocol >= 0x201) { 68 | header[0x211] |= 0x80; /* CAN_USE_HEAP */ 69 | stw_p(header+0x224, cmdline_addr-real_addr-0x200); 70 | } 71 | 72 | if (args->initrd_size) 73 | initrd_addr = (initrd_max - args->initrd_size) & ~4095; 74 | else 75 | initrd_addr = 0; 76 | stl_p(header+0x218, initrd_addr); 77 | stl_p(header+0x21c, args->initrd_size); 78 | 79 | /* load kernel and setup */ 80 | setup_size = header[0x1f1]; 81 | if (setup_size == 0) 82 | setup_size = 4; 83 | 84 | args->setup_size = (setup_size+1)*512; 85 | args->kernel_size = args->vmlinuz_size - setup_size; 86 | args->initrd_addr = (void *)initrd_addr; 87 | args->kernel_addr = (void *)prot_addr; 88 | args->cmdline_addr = (void *)cmdline_addr; 89 | return true; 90 | } 91 | 92 | void boot_bzimage(struct linuxboot_args *args) 93 | { 94 | #ifdef BENCHMARK_HACK 95 | /* Exit just before getting to vmlinuz, so that it is easy 96 | * to time/profile the firmware. 97 | */ 98 | outb(LINUX_EXIT_PORT, LINUX_START_BOOT); 99 | #endif 100 | asm volatile( 101 | "ljmp $0x18, $pm16_boot_linux - 0xf0000" 102 | : : 103 | "b" (((uintptr_t) args->setup_addr) >> 4), 104 | "d" (args->cmdline_addr - args->setup_addr - 16)); 105 | panic(); 106 | } 107 | 108 | /* BX = address of data block 109 | * DX = cmdline_addr-setup_addr-16 110 | */ 111 | asm("pm16_boot_linux:" 112 | ".code16;" 113 | "mov $0x20, %ax; mov %ax, %ds; mov %ax, %es;" 114 | "mov %ax, %fs; mov %ax, %gs; mov %ax, %ss;" 115 | "xor %eax, %eax; mov %eax, %cr0;" 116 | "ljmpl $0xf000, $(1f - 0xf0000); 1:" 117 | "mov %bx, %ds; mov %bx, %es;" 118 | "mov %bx, %fs; mov %bx, %gs; mov %bx, %ss;" 119 | "mov %dx, %sp;" 120 | "add $0x20, %bx; pushw %bx;" // push CS 121 | "pushw %ax;" // push IP 122 | "xor %ebx, %ebx;" 123 | "xor %ecx, %ecx;" 124 | "xor %edx, %edx;" 125 | "xor %edi, %edi;" 126 | "xor %ebp, %ebp;" 127 | "lret;" 128 | ".code32"); 129 | -------------------------------------------------------------------------------- /include/fw_cfg.h: -------------------------------------------------------------------------------- 1 | #ifndef BIOS_FW_CFG_H 2 | #define BIOS_FW_CFG_H 1 3 | 4 | // List of QEMU fw_cfg entries. DO NOT ADD MORE. (All new content 5 | // should be passed via the fw_cfg "file" interface.) 6 | #define FW_CFG_SIGNATURE 0x00 7 | #define FW_CFG_ID 0x01 8 | #define FW_CFG_UUID 0x02 9 | #define FW_CFG_RAM_SIZE 0x03 10 | #define FW_CFG_NOGRAPHIC 0x04 11 | #define FW_CFG_NB_CPUS 0x05 12 | #define FW_CFG_MACHINE_ID 0x06 13 | #define FW_CFG_KERNEL_ADDR 0x07 14 | #define FW_CFG_KERNEL_SIZE 0x08 15 | #define FW_CFG_KERNEL_CMDLINE 0x09 16 | #define FW_CFG_INITRD_ADDR 0x0a 17 | #define FW_CFG_INITRD_SIZE 0x0b 18 | #define FW_CFG_BOOT_DEVICE 0x0c 19 | #define FW_CFG_NUMA 0x0d 20 | #define FW_CFG_BOOT_MENU 0x0e 21 | #define FW_CFG_MAX_CPUS 0x0f 22 | #define FW_CFG_KERNEL_ENTRY 0x10 23 | #define FW_CFG_KERNEL_DATA 0x11 24 | #define FW_CFG_INITRD_DATA 0x12 25 | #define FW_CFG_CMDLINE_ADDR 0x13 26 | #define FW_CFG_CMDLINE_SIZE 0x14 27 | #define FW_CFG_CMDLINE_DATA 0x15 28 | #define FW_CFG_SETUP_ADDR 0x16 29 | #define FW_CFG_SETUP_SIZE 0x17 30 | #define FW_CFG_SETUP_DATA 0x18 31 | #define FW_CFG_FILE_DIR 0x19 32 | #define FW_CFG_FILE_FIRST 0x20 33 | #define FW_CFG_ARCH_LOCAL 0x8000 34 | #define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0) 35 | #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1) 36 | #define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2) 37 | #define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3) 38 | 39 | #define FW_CFG_VERSION 0x01 40 | #define FW_CFG_VERSION_DMA 0x02 41 | 42 | #define FW_CFG_DMA_CTL_ERROR 0x01 43 | #define FW_CFG_DMA_CTL_READ 0x02 44 | #define FW_CFG_DMA_CTL_SKIP 0x04 45 | #define FW_CFG_DMA_CTL_SELECT 0x08 46 | 47 | #define FW_CFG_CTL 0x510 48 | #define FW_CFG_DATA 0x511 49 | #define FW_CFG_DMA_ADDR_HIGH 0x514 50 | #define FW_CFG_DMA_ADDR_LOW 0x518 51 | 52 | #include "ioport.h" 53 | 54 | static inline void fw_cfg_select(uint16_t f) 55 | { 56 | outw(FW_CFG_CTL, f); 57 | } 58 | 59 | static inline uint32_t fw_cfg_readb(void) 60 | { 61 | return inb(FW_CFG_DATA); 62 | } 63 | 64 | static inline uint32_t fw_cfg_readw_be(void) 65 | { 66 | uint32_t val; 67 | 68 | val = inb(FW_CFG_DATA); 69 | val = (val << 8) | inb(FW_CFG_DATA); 70 | return val; 71 | } 72 | 73 | static inline uint32_t fw_cfg_readw_le(void) 74 | { 75 | uint32_t val; 76 | 77 | val = inb(FW_CFG_DATA); 78 | val = (inb(FW_CFG_DATA) << 8) | val; 79 | return val; 80 | } 81 | 82 | static inline uint32_t fw_cfg_readl_be(void) 83 | { 84 | uint32_t val; 85 | 86 | val = inb(FW_CFG_DATA); 87 | val = (val << 8) | inb(FW_CFG_DATA); 88 | val = (val << 8) | inb(FW_CFG_DATA); 89 | val = (val << 8) | inb(FW_CFG_DATA); 90 | return val; 91 | } 92 | 93 | static inline uint32_t fw_cfg_readl_le(void) 94 | { 95 | uint32_t val; 96 | 97 | val = inb(FW_CFG_DATA); 98 | val = (inb(FW_CFG_DATA) << 8) | val; 99 | val = (inb(FW_CFG_DATA) << 16) | val; 100 | val = (inb(FW_CFG_DATA) << 24) | val; 101 | return val; 102 | } 103 | 104 | static inline void fw_cfg_skip(int len) 105 | { 106 | while (len--) 107 | inb(FW_CFG_DATA); 108 | } 109 | 110 | void fw_cfg_setup(void); 111 | int fw_cfg_file_id(char *name); 112 | uint32_t fw_cfg_file_size(int id); 113 | void fw_cfg_file_select(int id); 114 | 115 | void fw_cfg_read(void *buf, int len); 116 | void fw_cfg_read_entry(int e, void *buf, int len); 117 | void fw_cfg_dma(int control, void *buf, int len); 118 | void fw_cfg_read_file(int e, void *buf, int len); 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /hwsetup.c: -------------------------------------------------------------------------------- 1 | #include "bios.h" 2 | #include "ioport.h" 3 | #include "pci.h" 4 | #include "string.h" 5 | 6 | // NOTE: this runs from ROM at 0xFFFF0000, so it is not possible to use any 7 | // static data. 8 | 9 | #define PIIX_ISA_PIRQA_ROUT 0x60 10 | #define PIIX_PMBASE 0x40 11 | #define PIIX_PMREGMISC 0x80 12 | #define PIIX_SMBHSTBASE 0x90 13 | #define PIIX_SMBHSTCFG 0xd2 14 | 15 | static void setup_piix(void) 16 | { 17 | const int bdf = (1 << 3); 18 | pci_config_writeb(bdf, PIIX_ISA_PIRQA_ROUT, 10); 19 | pci_config_writeb(bdf, PIIX_ISA_PIRQA_ROUT+1, 10); 20 | pci_config_writeb(bdf, PIIX_ISA_PIRQA_ROUT+2, 11); 21 | pci_config_writeb(bdf, PIIX_ISA_PIRQA_ROUT+3, 11); 22 | } 23 | 24 | static void setup_piix_pm(void) 25 | { 26 | const int bdf = (1 << 3) | 3; 27 | 28 | pci_config_writel(bdf, PIIX_PMBASE, 0x601); 29 | pci_config_writeb(bdf, PIIX_PMREGMISC, 0x01); 30 | pci_config_writel(bdf, PIIX_SMBHSTBASE, 0x701); 31 | pci_config_writeb(bdf, PIIX_SMBHSTCFG, 0x09); 32 | } 33 | 34 | #define ICH9_LPC_PIRQA_ROUT 0x60 35 | #define ICH9_LPC_PIRQE_ROUT 0x68 36 | #define ICH9_LPC_PMBASE 0x40 37 | #define ICH9_LPC_ACPI_CTRL 0x44 38 | 39 | static void setup_ich9(void) 40 | { 41 | const int bdf = 0x1f << 3; 42 | pci_config_writeb(bdf, ICH9_LPC_PIRQA_ROUT, 10); 43 | pci_config_writeb(bdf, ICH9_LPC_PIRQA_ROUT+1, 10); 44 | pci_config_writeb(bdf, ICH9_LPC_PIRQA_ROUT+2, 11); 45 | pci_config_writeb(bdf, ICH9_LPC_PIRQA_ROUT+3, 11); 46 | pci_config_writeb(bdf, ICH9_LPC_PIRQE_ROUT, 10); 47 | pci_config_writeb(bdf, ICH9_LPC_PIRQE_ROUT+1, 10); 48 | pci_config_writeb(bdf, ICH9_LPC_PIRQE_ROUT+2, 11); 49 | pci_config_writeb(bdf, ICH9_LPC_PIRQE_ROUT+3, 11); 50 | } 51 | 52 | static void setup_ich9_pm(void) 53 | { 54 | const int bdf = 0x1f << 3; 55 | pci_config_writel(bdf, ICH9_LPC_PMBASE, 0x601); 56 | pci_config_writeb(bdf, ICH9_LPC_ACPI_CTRL, 0x80); 57 | } 58 | 59 | #define I440FX_PAM0 0x59 60 | #define Q35_HOST_BRIDGE_PAM0 0x90 61 | 62 | static void setup_pic(void) 63 | { 64 | /* Send ICW1 (select OCW1 + will send ICW4) */ 65 | outb(0x20, 0x11); 66 | outb(0xa0, 0x11); 67 | /* Send ICW2 (base irqs: 0x08-0x0f for irq0-7, 0x70-0x77 for irq8-15) */ 68 | outb(0x21, 8); 69 | outb(0xa1, 0x70); 70 | /* Send ICW3 (cascaded pic ids) */ 71 | outb(0x21, 0x04); 72 | outb(0xa1, 0x02); 73 | /* Send ICW4 (enable 8086 mode) */ 74 | outb(0x21, 0x01); 75 | outb(0xa1, 0x01); 76 | /* Mask all irqs (except cascaded PIC2 irq) */ 77 | outb(0x21, ~(1 << 2)); 78 | outb(0xa1, ~0); 79 | 80 | /* Set ELCR to IRQs 10 and 11 */ 81 | outb(0x4d0, 0); 82 | outb(0x4d1, 0x0c); 83 | } 84 | 85 | void setup_pam(int bdf, int pambase) 86 | { 87 | int i; 88 | for (i=0; i<6; i++) { 89 | int pam = pambase + 1 + i; 90 | pci_config_writeb(bdf, pam, 0x33); 91 | } 92 | 93 | // Make ram from 0xf0000-0x100000 read-write 94 | pci_config_writeb(bdf, pambase, 0x30); 95 | } 96 | 97 | bool setup_hw(void) 98 | { 99 | const int bdf = 0; 100 | const uint8_t *bios_start = (void *)((uintptr_t)&stext + 0xfff00000); 101 | const uint8_t *init_start = (void *)((uintptr_t)&sinit + 0xfff00000); 102 | static volatile uint8_t rom_check; 103 | int rom_check_value; 104 | int pambase; 105 | 106 | uint32_t id = pci_config_readl(bdf, 0); 107 | if (id == (PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_82441 << 16))) { 108 | setup_piix(); 109 | setup_piix_pm(); 110 | pambase = I440FX_PAM0; 111 | } else if (id == (PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_Q35_MCH << 16))) { 112 | setup_ich9(); 113 | setup_ich9_pm(); 114 | pambase = Q35_HOST_BRIDGE_PAM0; 115 | } else { 116 | return false; 117 | } 118 | 119 | // Make ram from 0xc0000-0xf0000 read-write 120 | rom_check_value = rom_check; 121 | rom_check = rom_check_value + 1; 122 | if (rom_check == rom_check_value) 123 | setup_pam(bdf, pambase); 124 | 125 | // Shadow BIOS; we're still running from 0xffff0000 126 | memcpy(&stext, bios_start, &edata - &stext); 127 | memcpy(&sinit, init_start, &einit - &sinit); 128 | 129 | setup_pic(); 130 | 131 | return true; 132 | } 133 | 134 | #define Q35_HOST_BRIDGE_PCIEXBAREN 1 135 | #define Q35_HOST_BRIDGE_PCIEXBAR 0x60 136 | 137 | static void setup_q35_mmconfig(void) 138 | { 139 | const int bdf = 0; 140 | uint64_t addr = PCIE_MMCONFIG_BASE; 141 | uint32_t upper = addr >> 32; 142 | uint32_t lower = (addr & 0xffffffff) | Q35_HOST_BRIDGE_PCIEXBAREN; 143 | 144 | pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, 0); 145 | pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR + 4, upper); 146 | pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, lower); 147 | } 148 | 149 | bool setup_mmconfig(void) 150 | { 151 | const int bdf = 0; 152 | uint32_t id = pci_config_readl(bdf, 0); 153 | 154 | if (id == (PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_Q35_MCH << 16))) { 155 | setup_q35_mmconfig(); 156 | return true; 157 | } 158 | 159 | return false; 160 | } 161 | -------------------------------------------------------------------------------- /pci.c: -------------------------------------------------------------------------------- 1 | #include "bios.h" 2 | #include "ioport.h" 3 | #include "pci.h" 4 | #include "string.h" 5 | 6 | static uint16_t addend; 7 | static uint8_t bus, bridge_head; 8 | static bool use_i440fx_routing; 9 | static int bridge_count; 10 | uint8_t max_bus; 11 | 12 | static void do_setup_pci_bus(void); 13 | 14 | static void pci_foreach(void(*fn)(uint32_t bdf, uint32_t id, uint8_t type)) 15 | { 16 | int d, f; 17 | for (d = 0; d < 32; d++) { 18 | for (f = 0; f < 8; f++) { 19 | uint32_t bdf = (bus * 256) + (d * 8) + f; 20 | uint32_t id = pci_config_readl(bdf, PCI_VENDOR_ID); 21 | uint16_t vendor; 22 | uint8_t type; 23 | 24 | /* 0x0000 or 0xFFFF? Skip. */ 25 | vendor = id & 0xFFFF; 26 | if ((uint16_t)(vendor + 1) <= 1) { 27 | if (f == 0) 28 | break; 29 | else 30 | continue; 31 | } 32 | 33 | type = pci_config_readb(bdf, PCI_HEADER_TYPE); 34 | fn(bdf, id, type); 35 | 36 | if (f == 0 && !(type & PCI_HEADER_TYPE_MULTI_FUNCTION)) 37 | break; 38 | } 39 | } 40 | } 41 | 42 | static void do_setup_pci_irq(uint32_t bdf, int pin) 43 | { 44 | int dev = (bdf >> 3) & 0x1f; 45 | int lnk, irq; 46 | 47 | irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE); 48 | if (irq != 0) 49 | return; 50 | 51 | lnk = addend + pin; 52 | if (use_i440fx_routing) 53 | lnk += dev - 1; 54 | else { 55 | /* Q35 devices 25-31 all use LNKA. Devices 0-24 have 56 | * a slightly different mapping. 57 | */ 58 | if (dev <= 24) 59 | lnk += dev; 60 | } 61 | lnk &= 3; 62 | 63 | irq = lnk & 2 ? 11 : 10; 64 | pci_config_writeb(bdf, PCI_INTERRUPT_LINE, irq); 65 | } 66 | 67 | static void do_setup_pci(uint32_t bdf, uint32_t id, uint8_t type) 68 | { 69 | uint16_t class; 70 | uint8_t pin; 71 | 72 | pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN); 73 | if (pin != 0) 74 | do_setup_pci_irq(bdf, pin); 75 | 76 | if (type & PCI_HEADER_TYPE_BRIDGE) { 77 | uint32_t ctl; 78 | 79 | ctl = pci_config_readw(bdf, PCI_BRIDGE_CONTROL); 80 | pci_config_writew(bdf, PCI_BRIDGE_CONTROL, 81 | ctl | PCI_BRIDGE_CTL_SERR); 82 | } 83 | 84 | class = pci_config_readw(bdf, PCI_CLASS_DEVICE); 85 | switch (class) { 86 | case PCI_CLASS_STORAGE_IDE: 87 | pci_config_writel(bdf, 0x10, 0x1f0); 88 | pci_config_writel(bdf, 0x14, 0x3f4); 89 | pci_config_writel(bdf, 0x18, 0x170); 90 | pci_config_writel(bdf, 0x1c, 0x374); 91 | if (id == (PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_82371SB_1 << 16)) 92 | || id == (PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_82371AB << 16))) { 93 | /* Enable IDE0 and IDE1. */ 94 | pci_config_writew(bdf, 0x40, 0x8000); 95 | pci_config_writew(bdf, 0x42, 0x8000); 96 | } 97 | break; 98 | 99 | case PCI_CLASS_BRIDGE_PCI: 100 | pci_config_writeb(bdf, PCI_PRIMARY_BUS, bus); 101 | /* prevent accidental access to unintended devices */ 102 | pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 0); 103 | /* 104 | * Insert at the head of a linked list of bridges. 105 | * do_setup_pci_bus will use it later to initialize secondary 106 | * buses with a recursive call. 107 | */ 108 | pci_config_writeb(bdf, PCI_SECONDARY_BUS, bridge_head); 109 | bridge_head = (uint8_t)(bdf & 0xFF); 110 | bridge_count++; 111 | break; 112 | } 113 | } 114 | 115 | static void do_setup_pci_bus(void) 116 | { 117 | uint8_t save_bus, next_head; 118 | int i; 119 | 120 | bridge_head = 0xFF; 121 | bridge_count = 0; 122 | 123 | /* Discover all PCI devices and block bridges */ 124 | pci_foreach(do_setup_pci); 125 | 126 | next_head = bridge_head; 127 | save_bus = bus; 128 | 129 | /* Configure bridges on this bus and recursively setup new busses */ 130 | for (i = bridge_count; i > 0; i--) { 131 | uint32_t bdf = (save_bus * 256) + next_head; 132 | 133 | next_head = pci_config_readb(bdf, PCI_SECONDARY_BUS); 134 | 135 | bus = ++max_bus; 136 | pci_config_writeb(bdf, PCI_SECONDARY_BUS, bus); 137 | pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 255); 138 | 139 | /* Add PCI bridge device id for the recursive call. */ 140 | addend += (bdf >> 3) & 0x1f; 141 | do_setup_pci_bus(); 142 | addend -= (bdf >> 3) & 0x1f; 143 | 144 | pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, max_bus); 145 | } 146 | } 147 | 148 | void setup_bios32(void) 149 | { 150 | char *bios32 = malloc_fseg_align(16, 16); 151 | void *bios32_entry_ = &bios32_entry; 152 | int i; 153 | 154 | memcpy(bios32, "_32_", 4); 155 | memcpy(bios32 + 4, &bios32_entry_, 4); 156 | bios32[8] = 0; 157 | bios32[9] = 1; 158 | memset(bios32 + 10, 0, 6); 159 | for (i = 0; i <= 9; i++) 160 | bios32[10] -= bios32[i]; 161 | } 162 | 163 | void setup_pci(void) 164 | { 165 | const int bdf = 0; 166 | 167 | uint32_t id = pci_config_readl(bdf, 0); 168 | if (id == (PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_82441 << 16))) 169 | use_i440fx_routing = true; 170 | else if (id == (PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_Q35_MCH << 16))) 171 | use_i440fx_routing = false; 172 | else 173 | panic(); 174 | 175 | do_setup_pci_bus(); 176 | setup_bios32(); 177 | } 178 | -------------------------------------------------------------------------------- /include/mpspec_def.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _ASM_X86_MPSPEC_DEF_H 3 | #define _ASM_X86_MPSPEC_DEF_H 4 | 5 | /* 6 | * Structure definitions for SMP machines following the 7 | * Intel Multiprocessing Specification 1.1 and 1.4. 8 | */ 9 | 10 | /* 11 | * This tag identifies where the SMP configuration 12 | * information is. 13 | */ 14 | 15 | #define SMP_MAGIC_IDENT (('_'<<24) | ('P'<<16) | ('M'<<8) | '_') 16 | 17 | #ifdef CONFIG_X86_32 18 | # define MAX_MPC_ENTRY 1024 19 | #endif 20 | 21 | /* Intel MP Floating Pointer Structure */ 22 | struct mpf_intel { 23 | char signature[4]; /* "_MP_" */ 24 | unsigned int physptr; /* Configuration table address */ 25 | unsigned char length; /* Our length (paragraphs) */ 26 | unsigned char specification; /* Specification version */ 27 | unsigned char checksum; /* Checksum (makes sum 0) */ 28 | unsigned char feature1; /* Standard or configuration ? */ 29 | unsigned char feature2; /* Bit7 set for IMCR|PIC */ 30 | unsigned char feature3; /* Unused (0) */ 31 | unsigned char feature4; /* Unused (0) */ 32 | unsigned char feature5; /* Unused (0) */ 33 | }; 34 | 35 | #define MPC_SIGNATURE "PCMP" 36 | 37 | struct mpc_table { 38 | char signature[4]; 39 | unsigned short length; /* Size of table */ 40 | char spec; /* 0x01 */ 41 | char checksum; 42 | char oem[8]; 43 | char productid[12]; 44 | unsigned int oemptr; /* 0 if not present */ 45 | unsigned short oemsize; /* 0 if not present */ 46 | unsigned short oemcount; 47 | unsigned int lapic; /* APIC address */ 48 | unsigned int reserved; 49 | }; 50 | 51 | /* Followed by entries */ 52 | 53 | #define MP_PROCESSOR 0 54 | #define MP_BUS 1 55 | #define MP_IOAPIC 2 56 | #define MP_INTSRC 3 57 | #define MP_LINTSRC 4 58 | /* Used by IBM NUMA-Q to describe node locality */ 59 | #define MP_TRANSLATION 192 60 | 61 | #define CPU_ENABLED 1 /* Processor is available */ 62 | #define CPU_BOOTPROCESSOR 2 /* Processor is the boot CPU */ 63 | 64 | #define CPU_STEPPING_MASK 0x000F 65 | #define CPU_MODEL_MASK 0x00F0 66 | #define CPU_FAMILY_MASK 0x0F00 67 | 68 | struct mpc_cpu { 69 | unsigned char type; 70 | unsigned char apicid; /* Local APIC number */ 71 | unsigned char apicver; /* Its versions */ 72 | unsigned char cpuflag; 73 | unsigned int cpufeature; 74 | unsigned int featureflag; /* CPUID feature value */ 75 | unsigned int reserved[2]; 76 | }; 77 | 78 | struct mpc_bus { 79 | unsigned char type; 80 | unsigned char busid; 81 | unsigned char bustype[6]; 82 | }; 83 | 84 | /* List of Bus Type string values, Intel MP Spec. */ 85 | #define BUSTYPE_EISA "EISA" 86 | #define BUSTYPE_ISA "ISA" 87 | #define BUSTYPE_INTERN "INTERN" /* Internal BUS */ 88 | #define BUSTYPE_MCA "MCA" /* Obsolete */ 89 | #define BUSTYPE_VL "VL" /* Local bus */ 90 | #define BUSTYPE_PCI "PCI" 91 | #define BUSTYPE_PCMCIA "PCMCIA" 92 | #define BUSTYPE_CBUS "CBUS" 93 | #define BUSTYPE_CBUSII "CBUSII" 94 | #define BUSTYPE_FUTURE "FUTURE" 95 | #define BUSTYPE_MBI "MBI" 96 | #define BUSTYPE_MBII "MBII" 97 | #define BUSTYPE_MPI "MPI" 98 | #define BUSTYPE_MPSA "MPSA" 99 | #define BUSTYPE_NUBUS "NUBUS" 100 | #define BUSTYPE_TC "TC" 101 | #define BUSTYPE_VME "VME" 102 | #define BUSTYPE_XPRESS "XPRESS" 103 | 104 | #define MPC_APIC_USABLE 0x01 105 | 106 | struct mpc_ioapic { 107 | unsigned char type; 108 | unsigned char apicid; 109 | unsigned char apicver; 110 | unsigned char flags; 111 | unsigned int apicaddr; 112 | }; 113 | 114 | struct mpc_intsrc { 115 | unsigned char type; 116 | unsigned char irqtype; 117 | unsigned short irqflag; 118 | unsigned char srcbus; 119 | unsigned char srcbusirq; 120 | unsigned char dstapic; 121 | unsigned char dstirq; 122 | }; 123 | 124 | enum mp_irq_source_types { 125 | mp_INT = 0, 126 | mp_NMI = 1, 127 | mp_SMI = 2, 128 | mp_ExtINT = 3 129 | }; 130 | 131 | #define MP_IRQPOL_DEFAULT 0x0 132 | #define MP_IRQPOL_ACTIVE_HIGH 0x1 133 | #define MP_IRQPOL_RESERVED 0x2 134 | #define MP_IRQPOL_ACTIVE_LOW 0x3 135 | #define MP_IRQPOL_MASK 0x3 136 | 137 | #define MP_IRQTRIG_DEFAULT 0x0 138 | #define MP_IRQTRIG_EDGE 0x4 139 | #define MP_IRQTRIG_RESERVED 0x8 140 | #define MP_IRQTRIG_LEVEL 0xc 141 | #define MP_IRQTRIG_MASK 0xc 142 | 143 | #define MP_APIC_ALL 0xFF 144 | 145 | struct mpc_lintsrc { 146 | unsigned char type; 147 | unsigned char irqtype; 148 | unsigned short irqflag; 149 | unsigned char srcbusid; 150 | unsigned char srcbusirq; 151 | unsigned char destapic; 152 | unsigned char destapiclint; 153 | }; 154 | 155 | #define MPC_OEM_SIGNATURE "_OEM" 156 | 157 | struct mpc_oemtable { 158 | char signature[4]; 159 | unsigned short length; /* Size of table */ 160 | char rev; /* 0x01 */ 161 | char checksum; 162 | char mpc[8]; 163 | }; 164 | 165 | /* 166 | * Default configurations 167 | * 168 | * 1 2 CPU ISA 82489DX 169 | * 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining 170 | * 3 2 CPU EISA 82489DX 171 | * 4 2 CPU MCA 82489DX 172 | * 5 2 CPU ISA+PCI 173 | * 6 2 CPU EISA+PCI 174 | * 7 2 CPU MCA+PCI 175 | */ 176 | 177 | enum mp_bustype { 178 | MP_BUS_ISA = 1, 179 | MP_BUS_EISA, 180 | MP_BUS_PCI, 181 | }; 182 | #endif /* _ASM_X86_MPSPEC_DEF_H */ 183 | -------------------------------------------------------------------------------- /printf.c: -------------------------------------------------------------------------------- 1 | #include "bios.h" 2 | #include "stdio.h" 3 | #include "string.h" 4 | #include "stdlib.h" 5 | #include "ioport.h" 6 | 7 | typedef struct pstream { 8 | char *buffer; 9 | int remain; 10 | int added; 11 | } pstream_t; 12 | 13 | typedef struct strprops { 14 | char pad; 15 | int npad; 16 | } strprops_t; 17 | 18 | static void addchar(pstream_t *p, char c) 19 | { 20 | if (p->remain) { 21 | *p->buffer++ = c; 22 | --p->remain; 23 | } 24 | ++p->added; 25 | } 26 | 27 | int puts(const char *c) 28 | { 29 | int n = 0; 30 | while (c[n]) 31 | outb(0x3f8, c[n++]); 32 | return n; 33 | } 34 | 35 | void print_str(pstream_t *p, const char *s, strprops_t props) 36 | { 37 | const char *s_orig = s; 38 | int npad = props.npad; 39 | 40 | if (npad > 0) { 41 | npad -= strlen(s_orig); 42 | while (npad > 0) { 43 | addchar(p, props.pad); 44 | --npad; 45 | } 46 | } 47 | 48 | while (*s) 49 | addchar(p, *s++); 50 | 51 | if (npad < 0) { 52 | props.pad = ' '; /* ignore '0' flag with '-' flag */ 53 | npad += strlen(s_orig); 54 | while (npad < 0) { 55 | addchar(p, props.pad); 56 | ++npad; 57 | } 58 | } 59 | } 60 | 61 | static char digits[16] = "0123456789abcdef"; 62 | 63 | void print_int(pstream_t *ps, long n, int base, strprops_t props) 64 | { 65 | char buf[sizeof(long) * 3 + 2], *p = buf; 66 | int s = 0, i; 67 | 68 | if (n < 0) { 69 | n = -n; 70 | s = 1; 71 | } 72 | 73 | while (n) { 74 | *p++ = digits[n % base]; 75 | n /= base; 76 | } 77 | 78 | if (s) 79 | *p++ = '-'; 80 | 81 | if (p == buf) 82 | *p++ = '0'; 83 | 84 | for (i = 0; i < (p - buf) / 2; ++i) { 85 | char tmp; 86 | 87 | tmp = buf[i]; 88 | buf[i] = p[-1-i]; 89 | p[-1-i] = tmp; 90 | } 91 | 92 | *p = 0; 93 | 94 | print_str(ps, buf, props); 95 | } 96 | 97 | void print_unsigned(pstream_t *ps, unsigned long n, int base, 98 | strprops_t props) 99 | { 100 | char buf[sizeof(long) * 3 + 1], *p = buf; 101 | int i; 102 | 103 | while (n) { 104 | *p++ = digits[n % base]; 105 | n /= base; 106 | } 107 | 108 | if (p == buf) 109 | *p++ = '0'; 110 | 111 | for (i = 0; i < (p - buf) / 2; ++i) { 112 | char tmp; 113 | 114 | tmp = buf[i]; 115 | buf[i] = p[-1-i]; 116 | p[-1-i] = tmp; 117 | } 118 | 119 | *p = 0; 120 | 121 | print_str(ps, buf, props); 122 | } 123 | 124 | static int fmtnum(const char **fmt) 125 | { 126 | const char *f = *fmt; 127 | int len = 0, num; 128 | 129 | if (*f == '-') 130 | ++f, ++len; 131 | 132 | while (*f >= '0' && *f <= '9') 133 | ++f, ++len; 134 | 135 | num = atol(*fmt); 136 | *fmt += len; 137 | return num; 138 | } 139 | 140 | int vsnprintf(char *buf, int size, const char *fmt, va_list va) 141 | { 142 | pstream_t s; 143 | 144 | s.buffer = buf; 145 | s.remain = size - 1; 146 | s.added = 0; 147 | while (*fmt) { 148 | char f = *fmt++; 149 | int nlong = 0; 150 | strprops_t props; 151 | memset(&props, 0, sizeof(props)); 152 | props.pad = ' '; 153 | 154 | if (f != '%') { 155 | addchar(&s, f); 156 | continue; 157 | } 158 | morefmt: 159 | f = *fmt++; 160 | if (f == '%') { 161 | addchar(&s, '%'); 162 | continue; 163 | } 164 | if (f == 'c') { 165 | addchar(&s, va_arg(va, int)); 166 | continue; 167 | } 168 | if (f == '\0') { 169 | --fmt; 170 | continue; 171 | } 172 | if (f == '0') { 173 | props.pad = '0'; 174 | ++fmt; 175 | /* fall through */ 176 | } 177 | if ((f >= '1' && f <= '9') || f == '-') { 178 | --fmt; 179 | props.npad = fmtnum(&fmt); 180 | goto morefmt; 181 | } 182 | if (f == 'l') { 183 | ++nlong; 184 | goto morefmt; 185 | } 186 | if (f == 'd') { 187 | switch (nlong) { 188 | case 0: 189 | print_int(&s, va_arg(va, int), 10, props); 190 | break; 191 | case 1: 192 | print_int(&s, va_arg(va, long), 10, props); 193 | break; 194 | default: 195 | panic(); 196 | break; 197 | } 198 | continue; 199 | } 200 | if (f == 'x') { 201 | switch (nlong) { 202 | case 0: 203 | print_unsigned(&s, va_arg(va, unsigned), 16, props); 204 | break; 205 | case 1: 206 | print_unsigned(&s, va_arg(va, unsigned long), 16, props); 207 | break; 208 | default: 209 | panic(); 210 | break; 211 | } 212 | continue; 213 | } 214 | if (f == 'p') { 215 | print_str(&s, "0x", props); 216 | print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props); 217 | continue; 218 | } 219 | if (f == 's') { 220 | print_str(&s, va_arg(va, const char *), props); 221 | continue; 222 | } 223 | addchar(&s, f); 224 | } 225 | *s.buffer = 0; 226 | ++s.added; 227 | return s.added; 228 | } 229 | 230 | 231 | int snprintf(char *buf, int size, const char *fmt, ...) 232 | { 233 | va_list va; 234 | int r; 235 | 236 | va_start(va, fmt); 237 | r = vsnprintf(buf, size, fmt, va); 238 | va_end(va); 239 | return r; 240 | } 241 | 242 | int printf(const char *fmt, ...) 243 | { 244 | va_list va; 245 | char buf[2000]; 246 | int r; 247 | 248 | va_start(va, fmt); 249 | r = vsnprintf(buf, sizeof buf, fmt, va); 250 | va_end(va); 251 | puts(buf); 252 | return r; 253 | } 254 | -------------------------------------------------------------------------------- /mptable.c: -------------------------------------------------------------------------------- 1 | #include "include/string.h" 2 | #include "bios.h" 3 | #include "fw_cfg.h" 4 | #include "include/mpspec_def.h" 5 | 6 | #define MPTABLE_START 0x9fc00 7 | #define APIC_VERSION 0x14 8 | #define MPC_SPEC 0x4 9 | 10 | #define MP_IRQDIR_DEFAULT 0 11 | #define MP_IRQDIR_HIGH 1 12 | #define MP_IRQDIR_LOW 3 13 | 14 | static const char MPC_OEM[] = "QBOOT "; 15 | static const char MPC_PRODUCT_ID[] = "000000000000"; 16 | static const char BUS_TYPE_ISA[] = "ISA "; 17 | 18 | #define IO_APIC_DEFAULT_PHYS_BASE 0xfec00000 19 | #define APIC_DEFAULT_PHYS_BASE 0xfee00000 20 | #define APIC_VERSION 0x14 21 | 22 | static int mptable_checksum(char *buf, int size) 23 | { 24 | int i; 25 | int sum = 0; 26 | 27 | for (i = 0; i < size; i++) { 28 | sum += buf[i]; 29 | } 30 | 31 | return sum; 32 | } 33 | 34 | static void mptable_get_cpuid(int *signature, int *features) 35 | { 36 | int ebx, ecx; 37 | 38 | asm("cpuid" 39 | : "=a" (*signature), "=b" (ebx), "=c" (ecx), "=d" (*features) 40 | : "0" (1)); 41 | } 42 | 43 | void setup_mptable(void) 44 | { 45 | struct mpf_intel *mpf; 46 | struct mpc_table *table; 47 | struct mpc_cpu *cpu; 48 | struct mpc_bus *bus; 49 | struct mpc_ioapic *ioapic; 50 | struct mpc_intsrc *intsrc; 51 | struct mpc_lintsrc *lintsrc; 52 | const char mpc_signature[] = MPC_SIGNATURE; 53 | const char smp_magic_ident[] = "_MP_"; 54 | int cpuid_stepping, cpuid_features; 55 | int irq0_override = 0; 56 | int checksum = 0; 57 | int offset = 0; 58 | int num_cpus; 59 | int ssize; 60 | int i; 61 | 62 | ssize = sizeof(struct mpf_intel); 63 | 64 | mpf = (struct mpf_intel *) MPTABLE_START; 65 | memset(mpf, 0, ssize); 66 | memcpy(mpf->signature, smp_magic_ident, sizeof(smp_magic_ident) - 1); 67 | mpf->length = 1; 68 | mpf->specification = 4; 69 | mpf->physptr = MPTABLE_START + ssize; 70 | mpf->checksum -= mptable_checksum((char *) mpf, ssize); 71 | 72 | offset += ssize; 73 | ssize = sizeof(struct mpc_table); 74 | 75 | table = (struct mpc_table *) (MPTABLE_START + offset); 76 | memset(table, 0, ssize); 77 | memcpy(table->signature, mpc_signature, sizeof(mpc_signature) - 1); 78 | table->spec = MPC_SPEC; 79 | memcpy(table->oem, MPC_OEM, sizeof(MPC_OEM) - 1); 80 | memcpy(table->productid, MPC_PRODUCT_ID, sizeof(MPC_PRODUCT_ID) - 1); 81 | table->lapic = APIC_DEFAULT_PHYS_BASE; 82 | 83 | offset += ssize; 84 | ssize = sizeof(struct mpc_cpu); 85 | 86 | fw_cfg_select(FW_CFG_NB_CPUS); 87 | num_cpus = fw_cfg_readl_le(); 88 | mptable_get_cpuid(&cpuid_stepping, &cpuid_features); 89 | 90 | for (i = 0; i < num_cpus; i++) { 91 | cpu = (struct mpc_cpu *) (MPTABLE_START + offset); 92 | memset(cpu, 0, ssize); 93 | cpu->type = MP_PROCESSOR; 94 | cpu->apicid = i; 95 | cpu->apicver = APIC_VERSION; 96 | cpu->cpuflag = CPU_ENABLED; 97 | if (i == 0) { 98 | cpu->cpuflag |= CPU_BOOTPROCESSOR; 99 | } 100 | cpu->cpufeature = cpuid_stepping; 101 | cpu->featureflag = cpuid_features; 102 | checksum += mptable_checksum((char *) cpu, ssize); 103 | offset += ssize; 104 | } 105 | 106 | ssize = sizeof(struct mpc_bus); 107 | 108 | bus = (struct mpc_bus *) (MPTABLE_START + offset); 109 | memset(bus, 0, ssize); 110 | bus->type = MP_BUS; 111 | bus->busid = 0; 112 | memcpy(bus->bustype, BUS_TYPE_ISA, sizeof(BUS_TYPE_ISA) - 1); 113 | checksum += mptable_checksum((char *) bus, ssize); 114 | 115 | offset += ssize; 116 | ssize = sizeof(struct mpc_ioapic); 117 | 118 | ioapic = (struct mpc_ioapic *) (MPTABLE_START + offset); 119 | memset(ioapic, 0, ssize); 120 | ioapic->type = MP_IOAPIC; 121 | ioapic->apicid = num_cpus + 1; 122 | ioapic->apicver = APIC_VERSION; 123 | ioapic->flags = MPC_APIC_USABLE; 124 | ioapic->apicaddr = IO_APIC_DEFAULT_PHYS_BASE; 125 | checksum += mptable_checksum((char *) ioapic, ssize); 126 | 127 | offset += ssize; 128 | ssize = sizeof(struct mpc_intsrc); 129 | 130 | fw_cfg_select(FW_CFG_IRQ0_OVERRIDE); 131 | irq0_override = fw_cfg_readl_le(); 132 | 133 | for (i = 0; i < 16; i++) { 134 | intsrc = (struct mpc_intsrc *) (MPTABLE_START + offset); 135 | memset(intsrc, 0, ssize); 136 | intsrc->type = MP_INTSRC; 137 | intsrc->irqtype = mp_INT; 138 | intsrc->irqflag = MP_IRQDIR_DEFAULT; 139 | intsrc->srcbus = 0; 140 | intsrc->srcbusirq = i; 141 | intsrc->dstapic = num_cpus + 1; 142 | intsrc->dstirq = i; 143 | if (irq0_override) { 144 | if (i == 0) { 145 | intsrc->dstirq = 2; 146 | } else if (i == 2) { 147 | // Don't update offset nor checksum 148 | continue; 149 | } 150 | } 151 | checksum += mptable_checksum((char *) intsrc, ssize); 152 | offset += ssize; 153 | } 154 | 155 | ssize = sizeof(struct mpc_lintsrc); 156 | 157 | lintsrc = (struct mpc_lintsrc *) (MPTABLE_START + offset); 158 | memset(lintsrc, 0, ssize); 159 | lintsrc->type = MP_LINTSRC; 160 | lintsrc->irqtype = mp_ExtINT; 161 | lintsrc->irqflag = MP_IRQDIR_DEFAULT; 162 | lintsrc->srcbusid = 0; 163 | lintsrc->srcbusirq = 0; 164 | lintsrc->destapic = 0; 165 | lintsrc->destapiclint = 0; 166 | checksum += mptable_checksum((char *) lintsrc, ssize); 167 | 168 | offset += ssize; 169 | 170 | lintsrc = (struct mpc_lintsrc *) (MPTABLE_START + offset); 171 | lintsrc->type = MP_LINTSRC; 172 | lintsrc->irqtype = mp_NMI; 173 | lintsrc->irqflag = MP_IRQDIR_DEFAULT; 174 | lintsrc->srcbusid = 0; 175 | lintsrc->srcbusirq = 0; 176 | lintsrc->destapic = 0xFF; 177 | lintsrc->destapiclint = 1; 178 | checksum += mptable_checksum((char *) lintsrc, ssize); 179 | 180 | offset += ssize; 181 | ssize = sizeof(struct mpc_table); 182 | 183 | table->length = offset - sizeof(struct mpf_intel); 184 | checksum += mptable_checksum((char *) table, ssize); 185 | table->checksum -= checksum; 186 | } 187 | -------------------------------------------------------------------------------- /smbios.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "smbios.h" 3 | #include "string.h" 4 | #include "fw_cfg.h" 5 | 6 | #define VERSION "0.1" 7 | #define BIOS_NAME "qboot" 8 | #define BIOS_DATE "11/11/2019" 9 | 10 | struct smbios_entry_point { 11 | uint32_t signature; 12 | uint8_t checksum; 13 | uint8_t length; 14 | uint8_t smbios_major_version; 15 | uint8_t smbios_minor_version; 16 | uint16_t max_structure_size; 17 | uint8_t entry_point_revision; 18 | uint8_t formatted_area[5]; 19 | char intermediate_anchor_string[5]; 20 | uint8_t intermediate_checksum; 21 | uint16_t structure_table_length; 22 | uint32_t structure_table_address; 23 | uint16_t number_of_structures; 24 | uint8_t smbios_bcd_revision; 25 | } __attribute__((packed)); 26 | 27 | struct smbios_structure_header { 28 | uint8_t type; 29 | uint8_t length; 30 | uint16_t handle; 31 | } __attribute__((packed)); 32 | 33 | struct smbios_type_0 { 34 | struct smbios_structure_header header; 35 | uint8_t vendor_str; 36 | uint8_t bios_version_str; 37 | uint16_t bios_starting_address_segment; 38 | uint8_t bios_release_date_str; 39 | uint8_t bios_rom_size; 40 | uint8_t bios_characteristics[8]; 41 | uint8_t bios_characteristics_extension_bytes[2]; 42 | uint8_t system_bios_major_release; 43 | uint8_t system_bios_minor_release; 44 | uint8_t embedded_controller_major_release; 45 | uint8_t embedded_controller_minor_release; 46 | } __attribute__((packed)); 47 | 48 | #define set_str_field_or_skip(type, field, value) \ 49 | do { \ 50 | int size = (value != NULL) ? strlen(value) + 1 : 0; \ 51 | if (size > 1) { \ 52 | memcpy(end, value, size); \ 53 | end += size; \ 54 | p->field = ++str_index; \ 55 | } else { \ 56 | p->field = 0; \ 57 | } \ 58 | } while (0) 59 | 60 | static void smbios_new_type_0(void *start, const char *vendor, 61 | const char *version, const char *date) 62 | { 63 | struct smbios_type_0 *p = (struct smbios_type_0 *)start; 64 | char *end = (char *)start + sizeof(struct smbios_type_0); 65 | int str_index = 0; 66 | 67 | p->header.type = 0; 68 | p->header.length = sizeof(struct smbios_type_0); 69 | p->header.handle = 0; 70 | 71 | set_str_field_or_skip(0, vendor_str, vendor); 72 | set_str_field_or_skip(0, bios_version_str, version); 73 | p->bios_starting_address_segment = 0xe800; 74 | set_str_field_or_skip(0, bios_release_date_str, date); 75 | 76 | p->bios_rom_size = 0; /* FIXME */ 77 | 78 | /* BIOS characteristics not supported */ 79 | memset(p->bios_characteristics, 0, 8); 80 | p->bios_characteristics[0] = 0x08; 81 | 82 | /* Enable targeted content distribution (needed for SVVP) */ 83 | p->bios_characteristics_extension_bytes[0] = 0; 84 | p->bios_characteristics_extension_bytes[1] = 4; 85 | 86 | p->system_bios_major_release = 0; 87 | p->system_bios_minor_release = 0; 88 | p->embedded_controller_major_release = 0xFF; 89 | p->embedded_controller_minor_release = 0xFF; 90 | 91 | *end = 0; 92 | end++; 93 | if (!str_index) { 94 | *end = 0; 95 | end++; 96 | } 97 | } 98 | 99 | static struct smbios_structure_header *smbios_next(struct smbios_entry_point *ep, 100 | struct smbios_structure_header *hdr) 101 | { 102 | if (!ep) 103 | return NULL; 104 | void *start = (void *)ep->structure_table_address; 105 | void *end = start + ep->structure_table_length; 106 | void *ptr; 107 | 108 | if (hdr == NULL) 109 | ptr = start; 110 | else { 111 | ptr = hdr; 112 | if (ptr + sizeof(*hdr) > end) 113 | return NULL; 114 | ptr += hdr->length + 2; 115 | while (ptr < end && 116 | (*(uint8_t*)(ptr-1) != '\0' || *(uint8_t*)(ptr-2) != '\0')) 117 | ptr++; 118 | } 119 | hdr = ptr; 120 | if (ptr >= end || ptr + sizeof(*hdr) >= end || ptr + hdr->length >= end) 121 | return NULL; 122 | return hdr; 123 | } 124 | 125 | void extract_smbios(void) 126 | { 127 | int id; 128 | struct smbios_entry_point *ep; 129 | uint8_t *qtables; 130 | uint16_t qtables_length; 131 | struct smbios_structure_header *table_header = NULL; 132 | int need_t0 = 1; 133 | uint16_t t0_len = sizeof(struct smbios_type_0) + strlen(BIOS_NAME) + 134 | strlen(VERSION) + strlen(BIOS_DATE) + 4; 135 | 136 | id = fw_cfg_file_id("etc/smbios/smbios-anchor"); 137 | if (id == -1 || (sizeof(*ep) != fw_cfg_file_size(id))) 138 | return ; 139 | /* malloc_fseg is 16-byte alignment default */ 140 | if (!(ep = malloc_fseg(sizeof(*ep)))) 141 | return; 142 | fw_cfg_read_file(id, ep, sizeof(*ep)); 143 | 144 | qtables_length = ep->structure_table_length; 145 | id = fw_cfg_file_id("etc/smbios/smbios-tables"); 146 | if (id == -1 || qtables_length != fw_cfg_file_size(id)) 147 | return ; 148 | if (!(qtables = malloc_fseg(qtables_length + t0_len))) 149 | return ; 150 | qtables += t0_len; 151 | fw_cfg_read_file(id, qtables, qtables_length); 152 | 153 | ep->structure_table_address = (uint32_t) qtables; 154 | ep->structure_table_length = qtables_length; 155 | 156 | while ((table_header = smbios_next(ep, table_header))) { 157 | if (table_header->type == 0) { 158 | need_t0 = 0; 159 | break; 160 | } 161 | } 162 | 163 | if (need_t0) { 164 | smbios_new_type_0(qtables - t0_len, BIOS_NAME, VERSION, BIOS_DATE); 165 | ep->number_of_structures++; 166 | ep->structure_table_address -= t0_len; 167 | ep->structure_table_length += t0_len; 168 | if (t0_len > ep->max_structure_size) 169 | ep->max_structure_size = t0_len; 170 | } 171 | 172 | ep->checksum -= csum8((void *) ep, 0x10); 173 | ep->intermediate_checksum -= csum8((void *) ep + 0x10, ep->length - 0x10); 174 | } 175 | -------------------------------------------------------------------------------- /include/processor-flags.h: -------------------------------------------------------------------------------- 1 | #ifndef BIOS_X86_PROCESSOR_FLAGS_H 2 | #define BIOS_X86_PROCESSOR_FLAGS_H 3 | /* Various flags defined: can be included from assembler. */ 4 | 5 | #include "const.h" 6 | 7 | /* 8 | * EFLAGS bits 9 | */ 10 | #define X86_EFLAGS_CF_BIT 0 /* Carry Flag */ 11 | #define X86_EFLAGS_CF BITUL(X86_EFLAGS_CF_BIT) 12 | #define X86_EFLAGS_FIXED_BIT 1 /* Bit 1 - always on */ 13 | #define X86_EFLAGS_FIXED BITUL(X86_EFLAGS_FIXED_BIT) 14 | #define X86_EFLAGS_PF_BIT 2 /* Parity Flag */ 15 | #define X86_EFLAGS_PF BITUL(X86_EFLAGS_PF_BIT) 16 | #define X86_EFLAGS_AF_BIT 4 /* Auxiliary carry Flag */ 17 | #define X86_EFLAGS_AF BITUL(X86_EFLAGS_AF_BIT) 18 | #define X86_EFLAGS_ZF_BIT 6 /* Zero Flag */ 19 | #define X86_EFLAGS_ZF BITUL(X86_EFLAGS_ZF_BIT) 20 | #define X86_EFLAGS_SF_BIT 7 /* Sign Flag */ 21 | #define X86_EFLAGS_SF BITUL(X86_EFLAGS_SF_BIT) 22 | #define X86_EFLAGS_TF_BIT 8 /* Trap Flag */ 23 | #define X86_EFLAGS_TF BITUL(X86_EFLAGS_TF_BIT) 24 | #define X86_EFLAGS_IF_BIT 9 /* Interrupt Flag */ 25 | #define X86_EFLAGS_IF BITUL(X86_EFLAGS_IF_BIT) 26 | #define X86_EFLAGS_DF_BIT 10 /* Direction Flag */ 27 | #define X86_EFLAGS_DF BITUL(X86_EFLAGS_DF_BIT) 28 | #define X86_EFLAGS_OF_BIT 11 /* Overflow Flag */ 29 | #define X86_EFLAGS_OF BITUL(X86_EFLAGS_OF_BIT) 30 | #define X86_EFLAGS_IOPL_BIT 12 /* I/O Privilege Level (2 bits) */ 31 | #define X86_EFLAGS_IOPL (_AC(3,UL) << X86_EFLAGS_IOPL_BIT) 32 | #define X86_EFLAGS_NT_BIT 14 /* Nested Task */ 33 | #define X86_EFLAGS_NT BITUL(X86_EFLAGS_NT_BIT) 34 | #define X86_EFLAGS_RF_BIT 16 /* Resume Flag */ 35 | #define X86_EFLAGS_RF BITUL(X86_EFLAGS_RF_BIT) 36 | #define X86_EFLAGS_VM_BIT 17 /* Virtual Mode */ 37 | #define X86_EFLAGS_VM BITUL(X86_EFLAGS_VM_BIT) 38 | #define X86_EFLAGS_AC_BIT 18 /* Alignment Check/Access Control */ 39 | #define X86_EFLAGS_AC BITUL(X86_EFLAGS_AC_BIT) 40 | #define X86_EFLAGS_AC_BIT 18 /* Alignment Check/Access Control */ 41 | #define X86_EFLAGS_AC BITUL(X86_EFLAGS_AC_BIT) 42 | #define X86_EFLAGS_VIF_BIT 19 /* Virtual Interrupt Flag */ 43 | #define X86_EFLAGS_VIF BITUL(X86_EFLAGS_VIF_BIT) 44 | #define X86_EFLAGS_VIP_BIT 20 /* Virtual Interrupt Pending */ 45 | #define X86_EFLAGS_VIP BITUL(X86_EFLAGS_VIP_BIT) 46 | #define X86_EFLAGS_ID_BIT 21 /* CPUID detection */ 47 | #define X86_EFLAGS_ID BITUL(X86_EFLAGS_ID_BIT) 48 | 49 | /* 50 | * Basic CPU control in CR0 51 | */ 52 | #define X86_CR0_PE_BIT 0 /* Protection Enable */ 53 | #define X86_CR0_PE BITUL(X86_CR0_PE_BIT) 54 | #define X86_CR0_MP_BIT 1 /* Monitor Coprocessor */ 55 | #define X86_CR0_MP BITUL(X86_CR0_MP_BIT) 56 | #define X86_CR0_EM_BIT 2 /* Emulation */ 57 | #define X86_CR0_EM BITUL(X86_CR0_EM_BIT) 58 | #define X86_CR0_TS_BIT 3 /* Task Switched */ 59 | #define X86_CR0_TS BITUL(X86_CR0_TS_BIT) 60 | #define X86_CR0_ET_BIT 4 /* Extension Type */ 61 | #define X86_CR0_ET BITUL(X86_CR0_ET_BIT) 62 | #define X86_CR0_NE_BIT 5 /* Numeric Error */ 63 | #define X86_CR0_NE BITUL(X86_CR0_NE_BIT) 64 | #define X86_CR0_WP_BIT 16 /* Write Protect */ 65 | #define X86_CR0_WP BITUL(X86_CR0_WP_BIT) 66 | #define X86_CR0_AM_BIT 18 /* Alignment Mask */ 67 | #define X86_CR0_AM BITUL(X86_CR0_AM_BIT) 68 | #define X86_CR0_NW_BIT 29 /* Not Write-through */ 69 | #define X86_CR0_NW BITUL(X86_CR0_NW_BIT) 70 | #define X86_CR0_CD_BIT 30 /* Cache Disable */ 71 | #define X86_CR0_CD BITUL(X86_CR0_CD_BIT) 72 | #define X86_CR0_PG_BIT 31 /* Paging */ 73 | #define X86_CR0_PG BITUL(X86_CR0_PG_BIT) 74 | 75 | /* 76 | * Paging options in CR3 77 | */ 78 | #define X86_CR3_PWT_BIT 3 /* Page Write Through */ 79 | #define X86_CR3_PWT BITUL(X86_CR3_PWT_BIT) 80 | #define X86_CR3_PCD_BIT 4 /* Page Cache Disable */ 81 | #define X86_CR3_PCD BITUL(X86_CR3_PCD_BIT) 82 | #define X86_CR3_PCID_MASK _AC(0x00000fff,UL) /* PCID Mask */ 83 | 84 | /* 85 | * Intel CPU features in CR4 86 | */ 87 | #define X86_CR4_VME_BIT 0 /* enable vm86 extensions */ 88 | #define X86_CR4_VME BITUL(X86_CR4_VME_BIT) 89 | #define X86_CR4_PVI_BIT 1 /* virtual interrupts flag enable */ 90 | #define X86_CR4_PVI BITUL(X86_CR4_PVI_BIT) 91 | #define X86_CR4_TSD_BIT 2 /* disable time stamp at ipl 3 */ 92 | #define X86_CR4_TSD BITUL(X86_CR4_TSD_BIT) 93 | #define X86_CR4_DE_BIT 3 /* enable debugging extensions */ 94 | #define X86_CR4_DE BITUL(X86_CR4_DE_BIT) 95 | #define X86_CR4_PSE_BIT 4 /* enable page size extensions */ 96 | #define X86_CR4_PSE BITUL(X86_CR4_PSE_BIT) 97 | #define X86_CR4_PAE_BIT 5 /* enable physical address extensions */ 98 | #define X86_CR4_PAE BITUL(X86_CR4_PAE_BIT) 99 | #define X86_CR4_MCE_BIT 6 /* Machine check enable */ 100 | #define X86_CR4_MCE BITUL(X86_CR4_MCE_BIT) 101 | #define X86_CR4_PGE_BIT 7 /* enable global pages */ 102 | #define X86_CR4_PGE BITUL(X86_CR4_PGE_BIT) 103 | #define X86_CR4_PCE_BIT 8 /* enable performance counters at ipl 3 */ 104 | #define X86_CR4_PCE BITUL(X86_CR4_PCE_BIT) 105 | #define X86_CR4_OSFXSR_BIT 9 /* enable fast FPU save and restore */ 106 | #define X86_CR4_OSFXSR BITUL(X86_CR4_OSFXSR_BIT) 107 | #define X86_CR4_OSXMMEXCPT_BIT 10 /* enable unmasked SSE exceptions */ 108 | #define X86_CR4_OSXMMEXCPT BITUL(X86_CR4_OSXMMEXCPT_BIT) 109 | #define X86_CR4_VMXE_BIT 13 /* enable VMX virtualization */ 110 | #define X86_CR4_VMXE BITUL(X86_CR4_VMXE_BIT) 111 | #define X86_CR4_SMXE_BIT 14 /* enable safer mode (TXT) */ 112 | #define X86_CR4_SMXE BITUL(X86_CR4_SMXE_BIT) 113 | #define X86_CR4_FSGSBASE_BIT 16 /* enable RDWRFSGS support */ 114 | #define X86_CR4_FSGSBASE BITUL(X86_CR4_FSGSBASE_BIT) 115 | #define X86_CR4_PCIDE_BIT 17 /* enable PCID support */ 116 | #define X86_CR4_PCIDE BITUL(X86_CR4_PCIDE_BIT) 117 | #define X86_CR4_OSXSAVE_BIT 18 /* enable xsave and xrestore */ 118 | #define X86_CR4_OSXSAVE BITUL(X86_CR4_OSXSAVE_BIT) 119 | #define X86_CR4_SMEP_BIT 20 /* enable SMEP support */ 120 | #define X86_CR4_SMEP BITUL(X86_CR4_SMEP_BIT) 121 | #define X86_CR4_SMAP_BIT 21 /* enable SMAP support */ 122 | #define X86_CR4_SMAP BITUL(X86_CR4_SMAP_BIT) 123 | 124 | /* 125 | * x86-64 Task Priority Register, CR8 126 | */ 127 | #define X86_CR8_TPR _AC(0x0000000f,UL) /* task priority register */ 128 | 129 | /* 130 | * AMD and Transmeta use MSRs for configuration; see 131 | */ 132 | 133 | /* 134 | * NSC/Cyrix CPU configuration register indexes 135 | */ 136 | #define CX86_PCR0 0x20 137 | #define CX86_GCR 0xb8 138 | #define CX86_CCR0 0xc0 139 | #define CX86_CCR1 0xc1 140 | #define CX86_CCR2 0xc2 141 | #define CX86_CCR3 0xc3 142 | #define CX86_CCR4 0xe8 143 | #define CX86_CCR5 0xe9 144 | #define CX86_CCR6 0xea 145 | #define CX86_CCR7 0xeb 146 | #define CX86_PCR1 0xf0 147 | #define CX86_DIR0 0xfe 148 | #define CX86_DIR1 0xff 149 | #define CX86_ARR_BASE 0xc4 150 | #define CX86_RCR_BASE 0xdc 151 | 152 | 153 | #endif /* BIOS_X86_PROCESSOR_FLAGS_H */ 154 | -------------------------------------------------------------------------------- /include/start_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Permission is hereby granted, free of charge, to any person obtaining a copy 3 | * of this software and associated documentation files (the "Software"), to 4 | * deal in the Software without restriction, including without limitation the 5 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 6 | * sell copies of the Software, and to permit persons to whom the Software is 7 | * furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in 10 | * all copies or substantial portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 | * DEALINGS IN THE SOFTWARE. 19 | * 20 | * Copyright (c) 2016, Citrix Systems, Inc. 21 | */ 22 | 23 | #ifndef __XEN_PUBLIC_ARCH_X86_HVM_START_INFO_H__ 24 | #define __XEN_PUBLIC_ARCH_X86_HVM_START_INFO_H__ 25 | 26 | /* 27 | * Start of day structure passed to PVH guests and to HVM guests in %ebx. 28 | * 29 | * NOTE: nothing will be loaded at physical address 0, so a 0 value in any 30 | * of the address fields should be treated as not present. 31 | * 32 | * 0 +----------------+ 33 | * | magic | Contains the magic value XEN_HVM_START_MAGIC_VALUE 34 | * | | ("xEn3" with the 0x80 bit of the "E" set). 35 | * 4 +----------------+ 36 | * | version | Version of this structure. Current version is 1. New 37 | * | | versions are guaranteed to be backwards-compatible. 38 | * 8 +----------------+ 39 | * | flags | SIF_xxx flags. 40 | * 12 +----------------+ 41 | * | nr_modules | Number of modules passed to the kernel. 42 | * 16 +----------------+ 43 | * | modlist_paddr | Physical address of an array of modules 44 | * | | (layout of the structure below). 45 | * 24 +----------------+ 46 | * | cmdline_paddr | Physical address of the command line, 47 | * | | a zero-terminated ASCII string. 48 | * 32 +----------------+ 49 | * | rsdp_paddr | Physical address of the RSDP ACPI data structure. 50 | * 40 +----------------+ 51 | * | memmap_paddr | Physical address of the (optional) memory map. Only 52 | * | | present in version 1 and newer of the structure. 53 | * 48 +----------------+ 54 | * | memmap_entries | Number of entries in the memory map table. Only 55 | * | | present in version 1 and newer of the structure. 56 | * | | Zero if there is no memory map being provided. 57 | * 52 +----------------+ 58 | * | reserved | Version 1 and newer only. 59 | * 56 +----------------+ 60 | * 61 | * The layout of each entry in the module structure is the following: 62 | * 63 | * 0 +----------------+ 64 | * | paddr | Physical address of the module. 65 | * 8 +----------------+ 66 | * | size | Size of the module in bytes. 67 | * 16 +----------------+ 68 | * | cmdline_paddr | Physical address of the command line, 69 | * | | a zero-terminated ASCII string. 70 | * 24 +----------------+ 71 | * | reserved | 72 | * 32 +----------------+ 73 | * 74 | * The layout of each entry in the memory map table is as follows: 75 | * 76 | * 0 +----------------+ 77 | * | addr | Base address 78 | * 8 +----------------+ 79 | * | size | Size of mapping in bytes 80 | * 16 +----------------+ 81 | * | type | Type of mapping as defined between the hypervisor 82 | * | | and guest it's starting. E820_TYPE_xxx, for example. 83 | * 20 +----------------| 84 | * | reserved | 85 | * 24 +----------------+ 86 | * 87 | * The address and sizes are always a 64bit little endian unsigned integer. 88 | * 89 | * NB: Xen on x86 will always try to place all the data below the 4GiB 90 | * boundary. 91 | * 92 | * Version numbers of the hvm_start_info structure have evolved like this: 93 | * 94 | * Version 0: 95 | * 96 | * Version 1: Added the memmap_paddr/memmap_entries fields (plus 4 bytes of 97 | * padding) to the end of the hvm_start_info struct. These new 98 | * fields can be used to pass a memory map to the guest. The 99 | * memory map is optional and so guests that understand version 1 100 | * of the structure must check that memmap_entries is non-zero 101 | * before trying to read the memory map. 102 | */ 103 | #define XEN_HVM_START_MAGIC_VALUE 0x336ec578 104 | 105 | /* 106 | * C representation of the x86/HVM start info layout. 107 | * 108 | * The canonical definition of this layout is above, this is just a way to 109 | * represent the layout described there using C types. 110 | */ 111 | struct hvm_start_info { 112 | uint32_t magic; /* Contains the magic value 0x336ec578 */ 113 | /* ("xEn3" with the 0x80 bit of the "E" set).*/ 114 | uint32_t version; /* Version of this structure. */ 115 | uint32_t flags; /* SIF_xxx flags. */ 116 | uint32_t nr_modules; /* Number of modules passed to the kernel. */ 117 | uint64_t modlist_paddr; /* Physical address of an array of */ 118 | /* hvm_modlist_entry. */ 119 | uint64_t cmdline_paddr; /* Physical address of the command line. */ 120 | uint64_t rsdp_paddr; /* Physical address of the RSDP ACPI data */ 121 | /* structure. */ 122 | uint64_t memmap_paddr; /* Physical address of an array of */ 123 | /* hvm_memmap_table_entry. Only present in */ 124 | /* version 1 and newer of the structure */ 125 | uint32_t memmap_entries; /* Number of entries in the memmap table. */ 126 | /* Only present in version 1 and newer of */ 127 | /* the structure. Value will be zero if */ 128 | /* there is no memory map being provided. */ 129 | uint32_t reserved; 130 | }; 131 | 132 | struct hvm_modlist_entry { 133 | uint64_t paddr; /* Physical address of the module. */ 134 | uint64_t size; /* Size of the module in bytes. */ 135 | uint64_t cmdline_paddr; /* Physical address of the command line. */ 136 | uint64_t reserved; 137 | }; 138 | 139 | struct hvm_memmap_table_entry { 140 | uint64_t addr; /* Base address of the memory region */ 141 | uint64_t size; /* Size of the memory region in bytes */ 142 | uint32_t type; /* Mapping type */ 143 | uint32_t reserved; 144 | }; 145 | 146 | #endif /* __XEN_PUBLIC_ARCH_X86_HVM_START_INFO_H__ */ 147 | -------------------------------------------------------------------------------- /fw_cfg.c: -------------------------------------------------------------------------------- 1 | #include "bios.h" 2 | #include "e820.h" 3 | #include "stdio.h" 4 | #include "ioport.h" 5 | #include "string.h" 6 | #include "fw_cfg.h" 7 | #include "bswap.h" 8 | #include "linuxboot.h" 9 | #include "memaccess.h" 10 | #include "multiboot.h" 11 | #include "benchmark.h" 12 | #include "start_info.h" 13 | 14 | extern struct hvm_start_info start_info; 15 | 16 | struct fw_cfg_file { 17 | uint32_t size; 18 | uint16_t select; 19 | uint16_t unused; 20 | char name[56]; 21 | }; 22 | 23 | static int version; 24 | static int filecnt; 25 | static struct fw_cfg_file *files; 26 | 27 | void fw_cfg_setup(void) 28 | { 29 | int i, n; 30 | 31 | fw_cfg_select(FW_CFG_ID); 32 | version = fw_cfg_readl_le(); 33 | 34 | fw_cfg_select(FW_CFG_FILE_DIR); 35 | n = fw_cfg_readl_be(); 36 | filecnt = n; 37 | files = malloc_fseg(sizeof(files[0]) * n); 38 | 39 | fw_cfg_read(files, sizeof(files[0]) * n); 40 | for (i = 0; i < n; i++) { 41 | struct fw_cfg_file *f = &files[i]; 42 | f->size = bswap32(f->size); 43 | f->select = bswap16(f->select); 44 | } 45 | } 46 | 47 | int filenamecmp(const char *a, const struct fw_cfg_file *f) 48 | { 49 | int n = sizeof(f->name); 50 | const char *b = f->name; 51 | while (*a == *b) { 52 | if (*a == '\0') { 53 | break; 54 | } 55 | if (--n == 0) { 56 | return *a; 57 | } 58 | ++a, ++b; 59 | } 60 | return *a - *b; 61 | } 62 | 63 | int fw_cfg_file_id(char *name) 64 | { 65 | int i; 66 | 67 | for (i = 0; i < filecnt; i++) 68 | if (!filenamecmp(name, &files[i])) 69 | return i; 70 | 71 | return -1; 72 | } 73 | 74 | uint32_t fw_cfg_file_size(int id) 75 | { 76 | if (id == -1) 77 | return 0; 78 | return files[id].size; 79 | } 80 | 81 | void fw_cfg_file_select(int id) 82 | { 83 | fw_cfg_select(files[id].select); 84 | } 85 | 86 | void fw_cfg_read_file(int id, void *buf, int len) 87 | { 88 | fw_cfg_read_entry(files[id].select, buf, len); 89 | } 90 | 91 | struct fw_cfg_dma_descriptor { 92 | uint32_t control; 93 | uint32_t length; 94 | uint64_t address; 95 | } __attribute__((packed)); 96 | 97 | void fw_cfg_dma(int control, void *buf, int len) 98 | { 99 | volatile struct fw_cfg_dma_descriptor dma; 100 | uint32_t dma_desc_addr; 101 | 102 | dma.control = bswap32(control); 103 | dma.length = bswap32(len); 104 | dma.address = bswap64((uintptr_t)buf); 105 | 106 | dma_desc_addr = (uint32_t)&dma; 107 | outl(FW_CFG_DMA_ADDR_LOW, bswap32(dma_desc_addr)); 108 | while (bswap32(dma.control) & ~FW_CFG_DMA_CTL_ERROR) { 109 | asm(""); 110 | } 111 | } 112 | 113 | void fw_cfg_read(void *buf, int len) 114 | { 115 | if (version & FW_CFG_VERSION_DMA) { 116 | fw_cfg_dma(FW_CFG_DMA_CTL_READ, buf, len); 117 | } else { 118 | insb(buf, FW_CFG_DATA, len); 119 | } 120 | } 121 | 122 | void 123 | fw_cfg_read_entry(int e, void *buf, int len) 124 | { 125 | if (version & FW_CFG_VERSION_DMA) { 126 | int control; 127 | control = (e << 16); 128 | control |= FW_CFG_DMA_CTL_SELECT; 129 | control |= FW_CFG_DMA_CTL_READ; 130 | fw_cfg_dma(control, buf, len); 131 | } else { 132 | fw_cfg_select(e); 133 | insb(buf, FW_CFG_DATA, len); 134 | } 135 | } 136 | 137 | /* Multiboot trampoline. QEMU does the ELF parsing. */ 138 | 139 | static void boot_multiboot_from_fw_cfg(void) 140 | { 141 | void *kernel_addr, *kernel_entry; 142 | struct mb_info *mb; 143 | struct mb_mmap_entry *mbmem; 144 | int i; 145 | uint32_t sz; 146 | 147 | fw_cfg_select(FW_CFG_KERNEL_SIZE); 148 | sz = fw_cfg_readl_le(); 149 | if (!sz) 150 | panic(); 151 | 152 | fw_cfg_select(FW_CFG_KERNEL_ADDR); 153 | kernel_addr = (void *) fw_cfg_readl_le(); 154 | fw_cfg_read_entry(FW_CFG_KERNEL_DATA, kernel_addr, sz); 155 | 156 | fw_cfg_select(FW_CFG_INITRD_SIZE); 157 | sz = fw_cfg_readl_le(); 158 | if (!sz) 159 | panic(); 160 | 161 | fw_cfg_select(FW_CFG_INITRD_ADDR); 162 | mb = (struct mb_info *) fw_cfg_readl_le(); 163 | fw_cfg_read_entry(FW_CFG_INITRD_DATA, mb, sz); 164 | 165 | mb->mem_lower = 639; 166 | mb->mem_upper = (lowmem - 1048576) >> 10; 167 | 168 | mb->mmap_length = 0; 169 | for (i = 0; i < e820->nr_map; i++) { 170 | mbmem = (struct mb_mmap_entry *) (mb->mmap_addr + mb->mmap_length); 171 | mbmem->size = sizeof(e820->map[i]); 172 | mbmem->base_addr = e820->map[i].addr; 173 | mbmem->length = e820->map[i].size; 174 | mbmem->type = e820->map[i].type; 175 | mb->mmap_length += sizeof(*mbmem); 176 | } 177 | 178 | #ifdef BENCHMARK_HACK 179 | /* Exit just before getting to vmlinuz, so that it is easy 180 | * to time/profile the firmware. 181 | */ 182 | outb(LINUX_EXIT_PORT, LINUX_START_FWCFG); 183 | #endif 184 | 185 | fw_cfg_select(FW_CFG_KERNEL_ENTRY); 186 | kernel_entry = (void *) fw_cfg_readl_le(); 187 | asm volatile("jmp *%2" : : "a" (0x2badb002), "b"(mb), "c"(kernel_entry)); 188 | panic(); 189 | } 190 | 191 | static void pvh_e820_setup() 192 | { 193 | struct hvm_memmap_table_entry *pvh_e820p; 194 | int i, pvh_e820_sz; 195 | 196 | pvh_e820_sz = sizeof(struct hvm_memmap_table_entry) * e820->nr_map; 197 | 198 | pvh_e820p = malloc(pvh_e820_sz); 199 | memset(pvh_e820p, 0, pvh_e820_sz); 200 | 201 | for (i = 0; i < e820->nr_map; i++) { 202 | pvh_e820p[i].addr = e820->map[i].addr; 203 | pvh_e820p[i].size = e820->map[i].size; 204 | pvh_e820p[i].type = e820->map[i].type; 205 | } 206 | start_info.memmap_paddr = (uintptr_t)pvh_e820p; 207 | start_info.memmap_entries = e820->nr_map; 208 | } 209 | 210 | static void boot_pvh_from_fw_cfg(void) 211 | { 212 | void *kernel_entry; 213 | uint32_t sz; 214 | struct linuxboot_args args; 215 | struct hvm_modlist_entry ramdisk_mod; 216 | 217 | start_info.magic = XEN_HVM_START_MAGIC_VALUE; 218 | start_info.version = 1; 219 | start_info.flags = 0; 220 | start_info.nr_modules = 0; 221 | start_info.reserved = 0; 222 | 223 | fw_cfg_select(FW_CFG_CMDLINE_SIZE); 224 | args.cmdline_size = fw_cfg_readl_le(); 225 | args.cmdline_addr = malloc(args.cmdline_size); 226 | fw_cfg_read_entry(FW_CFG_CMDLINE_DATA, args.cmdline_addr, 227 | args.cmdline_size); 228 | start_info.cmdline_paddr = (uintptr_t)args.cmdline_addr; 229 | 230 | fw_cfg_select(FW_CFG_INITRD_SIZE); 231 | args.initrd_size = fw_cfg_readl_le(); 232 | if (args.initrd_size) { 233 | fw_cfg_select(FW_CFG_INITRD_ADDR); 234 | args.initrd_addr = (void *)fw_cfg_readl_le(); 235 | 236 | fw_cfg_read_entry(FW_CFG_INITRD_DATA, args.initrd_addr, 237 | args.initrd_size); 238 | 239 | ramdisk_mod.paddr = (uintptr_t)args.initrd_addr; 240 | ramdisk_mod.size = (uintptr_t)args.initrd_size; 241 | 242 | /* The first module is always ramdisk. */ 243 | start_info.modlist_paddr = (uintptr_t)&ramdisk_mod; 244 | start_info.nr_modules = 1; 245 | } 246 | 247 | pvh_e820_setup(); 248 | 249 | fw_cfg_select(FW_CFG_KERNEL_SIZE); 250 | sz = fw_cfg_readl_le(); 251 | if (!sz) 252 | panic(); 253 | 254 | fw_cfg_select(FW_CFG_KERNEL_ENTRY); 255 | kernel_entry = (void *) fw_cfg_readl_le(); 256 | 257 | #ifdef BENCHMARK_HACK 258 | /* Exit just before jumping to vmlinux, so that it is easy 259 | * to time/profile the firmware. 260 | */ 261 | outb(LINUX_EXIT_PORT, LINUX_START_PVHBOOT); 262 | #endif 263 | asm volatile("jmp *%2" : : "a" (0x2badb002), 264 | "b"(&start_info), "c"(kernel_entry)); 265 | panic(); 266 | } 267 | 268 | void boot_from_fwcfg(void) 269 | { 270 | struct linuxboot_args args; 271 | uint32_t kernel_size; 272 | enum { HEADER_PEEK_SIZE = 8192 }; 273 | 274 | fw_cfg_select(FW_CFG_CMDLINE_SIZE); 275 | args.cmdline_size = fw_cfg_readl_le(); 276 | fw_cfg_select(FW_CFG_INITRD_SIZE); 277 | args.initrd_size = fw_cfg_readl_le(); 278 | 279 | /* QEMU has already split the real mode and protected mode 280 | * parts. Recombine them in args.vmlinuz_size. 281 | */ 282 | fw_cfg_select(FW_CFG_KERNEL_SIZE); 283 | kernel_size = fw_cfg_readl_le(); 284 | fw_cfg_select(FW_CFG_SETUP_SIZE); 285 | args.vmlinuz_size = kernel_size + fw_cfg_readl_le(); 286 | fw_cfg_select(FW_CFG_SETUP_ADDR); 287 | args.setup_addr = (void *)fw_cfg_readl_le(); 288 | 289 | if (!args.vmlinuz_size) 290 | return; 291 | 292 | fw_cfg_select(FW_CFG_SETUP_DATA); 293 | fw_cfg_read(args.setup_addr, HEADER_PEEK_SIZE); 294 | 295 | if (!parse_bzimage(&args)) { 296 | uint8_t *header = args.setup_addr; 297 | 298 | if (ldl_p(header) == 0x464c457f) /* ELF magic */ 299 | boot_pvh_from_fw_cfg(); 300 | boot_multiboot_from_fw_cfg(); 301 | } 302 | 303 | /* SETUP_DATA already selected */ 304 | if (args.setup_size > HEADER_PEEK_SIZE) 305 | fw_cfg_read(args.setup_addr + HEADER_PEEK_SIZE, 306 | args.setup_size - HEADER_PEEK_SIZE); 307 | 308 | fw_cfg_select(FW_CFG_KERNEL_DATA); 309 | fw_cfg_read_entry(FW_CFG_KERNEL_DATA, args.kernel_addr, kernel_size); 310 | 311 | fw_cfg_read_entry(FW_CFG_CMDLINE_DATA, args.cmdline_addr, args.cmdline_size); 312 | 313 | if (args.initrd_size) { 314 | fw_cfg_read_entry(FW_CFG_INITRD_DATA, args.initrd_addr, args.initrd_size); 315 | } 316 | 317 | boot_bzimage(&args); 318 | } 319 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | --------------------------------------------------------------------------------