diff options
author | Eric Biederman <ebiederm@xmission.com> | 2003-04-22 19:02:15 +0000 |
---|---|---|
committer | Eric Biederman <ebiederm@xmission.com> | 2003-04-22 19:02:15 +0000 |
commit | 8ca8d7665d671e10d72b8fcb4d69121d75f7906e (patch) | |
tree | daad2699b4e6b6014bce5a76e82dd9c974801777 /src | |
parent | b138ac83b53da9abf3dc9a87a1cd4b3d3a8150bd (diff) | |
download | coreboot-8ca8d7665d671e10d72b8fcb4d69121d75f7906e.tar.xz |
- Initial checkin of the freebios2 tree
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@784 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src')
106 files changed, 12043 insertions, 0 deletions
diff --git a/src/arch/i386/boot/boot.c b/src/arch/i386/boot/boot.c new file mode 100644 index 0000000000..84c71da800 --- /dev/null +++ b/src/arch/i386/boot/boot.c @@ -0,0 +1,182 @@ +#include <console/console.h> +#include <ip_checksum.h> +#include <boot/elf.h> +#include <boot/elf_boot.h> +#include <string.h> + + +#ifndef CMD_LINE +#define CMD_LINE "" +#endif + + + +#define UPSZ(X) ((sizeof(X) + 3) &~3) + +static struct { + Elf_Bhdr hdr; + Elf_Nhdr ft_hdr; + unsigned char ft_desc[UPSZ(FIRMWARE_TYPE)]; + Elf_Nhdr bl_hdr; + unsigned char bl_desc[UPSZ(BOOTLOADER)]; + Elf_Nhdr blv_hdr; + unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)]; + Elf_Nhdr cmd_hdr; + unsigned char cmd_desc[UPSZ(CMD_LINE)]; +} elf_boot_notes = { + .hdr = { + .b_signature = 0x0E1FB007, + .b_size = sizeof(elf_boot_notes), + .b_checksum = 0, + .b_records = 4, + }, + .ft_hdr = { + .n_namesz = 0, + .n_descsz = sizeof(FIRMWARE_TYPE), + .n_type = EBN_FIRMWARE_TYPE, + }, + .ft_desc = FIRMWARE_TYPE, + .bl_hdr = { + .n_namesz = 0, + .n_descsz = sizeof(BOOTLOADER), + .n_type = EBN_BOOTLOADER_NAME, + }, + .bl_desc = BOOTLOADER, + .blv_hdr = { + .n_namesz = 0, + .n_descsz = sizeof(BOOTLOADER_VERSION), + .n_type = EBN_BOOTLOADER_VERSION, + }, + .blv_desc = BOOTLOADER_VERSION, + .cmd_hdr = { + .n_namesz = 0, + .n_descsz = sizeof(CMD_LINE), + .n_type = EBN_COMMAND_LINE, + }, + .cmd_desc = CMD_LINE, +}; + + +int elf_check_arch(Elf_ehdr *ehdr) +{ + return ( + ((ehdr->e_machine == EM_386) || (ehdr->e_machine == EM_486)) && + (ehdr->e_ident[EI_CLASS] == ELFCLASS32) && + (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + ); + +} + +void jmp_to_elf_entry(void *entry, unsigned long buffer) +{ + extern unsigned char _ram_seg, _eram_seg; + unsigned long lb_start, lb_size; + unsigned long adjust, adjusted_boot_notes; + unsigned long type; + + elf_boot_notes.hdr.b_checksum = + compute_ip_checksum(&elf_boot_notes, sizeof(elf_boot_notes)); + + type = 0x0E1FB007; + lb_start = (unsigned long)&_ram_seg; + lb_size = (unsigned long)(&_eram_seg - &_ram_seg); + adjust = buffer + lb_size - lb_start; + + adjusted_boot_notes = (unsigned long)&elf_boot_notes; + adjusted_boot_notes += adjust; + + printk_spew("entry = 0x%08lx\n", (unsigned long)entry); + printk_spew("lb_start = 0x%08lx\n", lb_start); + printk_spew("lb_size = 0x%08lx\n", lb_size); + printk_spew("adjust = 0x%08lx\n", adjust); + printk_spew("buffer = 0x%08lx\n", buffer); + printk_spew(" elf_boot_notes = 0x%08lx\n", (unsigned long)&elf_boot_notes); + printk_spew("adjusted_boot_notes = 0x%08lx\n", adjusted_boot_notes); + + /* Jump to kernel */ + __asm__ __volatile__( + " cld \n\t" + /* Save the callee save registers... */ + " pushl %%esi\n\t" + " pushl %%edi\n\t" + " pushl %%ebx\n\t" + /* Save the parameters I was passed */ + " pushl $0\n\t" /* 20 adjust */ + " pushl %0\n\t" /* 16 lb_start */ + " pushl %1\n\t" /* 12 buffer */ + " pushl %2\n\t" /* 8 lb_size */ + " pushl %3\n\t" /* 4 entry */ + " pushl %4\n\t" /* 0 elf_boot_notes */ + /* Compute the adjustment */ + " xorl %%eax, %%eax\n\t" + " subl 16(%%esp), %%eax\n\t" + " addl 12(%%esp), %%eax\n\t" + " addl 8(%%esp), %%eax\n\t" + " movl %%eax, 20(%%esp)\n\t" + /* Place a copy of linuxBIOS in it's new location */ + /* Move ``longs'' the linuxBIOS size is 4 byte aligned */ + " movl 12(%%esp), %%edi\n\t" + " addl 8(%%esp), %%edi\n\t" + " movl 16(%%esp), %%esi\n\t" + " movl 8(%%esp), %%ecx\n\n" + " shrl $2, %%ecx\n\t" + " rep movsl\n\t" + + /* Adjust the stack pointer to point into the new linuxBIOS image */ + " addl 20(%%esp), %%esp\n\t" + /* Adjust the instruction pointer to point into the new linuxBIOS image */ + " movl $1f, %%eax\n\t" + " addl 20(%%esp), %%eax\n\t" + " jmp *%%eax\n\t" + "1: \n\t" + + /* Copy the linuxBIOS bounce buffer over linuxBIOS */ + /* Move ``longs'' the linuxBIOS size is 4 byte aligned */ + " movl 16(%%esp), %%edi\n\t" + " movl 12(%%esp), %%esi\n\t" + " movl 8(%%esp), %%ecx\n\t" + " shrl $2, %%ecx\n\t" + " rep movsl\n\t" + + /* Now jump to the loaded image */ + " movl $0x0E1FB007, %%eax\n\t" + " movl 0(%%esp), %%ebx\n\t" + " call *4(%%esp)\n\t" + + /* The loaded image returned? */ + " cli \n\t" + " cld \n\t" + + /* Copy the saved copy of linuxBIOS where linuxBIOS runs */ + /* Move ``longs'' the linuxBIOS size is 4 byte aligned */ + " movl 16(%%esp), %%edi\n\t" + " movl 12(%%esp), %%esi\n\t" + " addl 8(%%esp), %%esi\n\t" + " movl 8(%%esp), %%ecx\n\t" + " shrl $2, %%ecx\n\t" + " rep movsl\n\t" + + /* Adjust the stack pointer to point into the old linuxBIOS image */ + " subl 20(%%esp), %%esp\n\t" + + /* Adjust the instruction pointer to point into the old linuxBIOS image */ + " movl $1f, %%eax\n\t" + " subl 20(%%esp), %%eax\n\t" + " jmp *%%eax\n\t" + "1: \n\t" + + /* Drop the parameters I was passed */ + " addl $24, %%esp\n\t" + + /* Restore the callee save registers */ + " popl %%ebx\n\t" + " popl %%edi\n\t" + " popl %%esi\n\t" + + :: + "g" (lb_start), "g" (buffer), "g" (lb_size), + "g" (entry), "g"(adjusted_boot_notes) + ); +} + + diff --git a/src/arch/i386/boot/linuxbios_table.c b/src/arch/i386/boot/linuxbios_table.c new file mode 100644 index 0000000000..1925f2ddb5 --- /dev/null +++ b/src/arch/i386/boot/linuxbios_table.c @@ -0,0 +1,281 @@ +#include <console/console.h> +#include <mem.h> +#include <ip_checksum.h> +#include <boot/linuxbios_tables.h> +#include "linuxbios_table.h" +#include <string.h> +#include <version.h> + + +struct lb_header *lb_table_init(unsigned long addr) +{ + struct lb_header *header; + + /* 16 byte align the address */ + addr += 15; + addr &= ~15; + + header = (void *)addr; + header->signature[0] = 'L'; + header->signature[1] = 'B'; + header->signature[2] = 'I'; + header->signature[3] = 'O'; + header->header_bytes = sizeof(*header); + header->header_checksum = 0; + header->table_bytes = 0; + header->table_checksum = 0; + header->table_entries = 0; + return header; +} + +struct lb_record *lb_first_record(struct lb_header *header) +{ + struct lb_record *rec; + rec = (void *)(((char *)header) + sizeof(*header)); + return rec; +} + +struct lb_record *lb_last_record(struct lb_header *header) +{ + struct lb_record *rec; + rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes); + return rec; +} + +struct lb_record *lb_next_record(struct lb_record *rec) +{ + rec = (void *)(((char *)rec) + rec->size); + return rec; +} + +struct lb_record *lb_new_record(struct lb_header *header) +{ + struct lb_record *rec; + rec = lb_last_record(header); + if (header->table_entries) { + header->table_bytes += rec->size; + } + rec = lb_last_record(header); + header->table_entries++; + rec->tag = LB_TAG_UNUSED; + rec->size = sizeof(*rec); + return rec; +} + + +struct lb_memory *lb_memory(struct lb_header *header) +{ + struct lb_record *rec; + struct lb_memory *mem; + rec = lb_new_record(header); + mem = (struct lb_memory *)rec; + mem->tag = LB_TAG_MEMORY; + mem->size = sizeof(*mem); + return mem; +} + +struct lb_mainboard *lb_mainboard(struct lb_header *header) +{ + struct lb_record *rec; + struct lb_mainboard *mainboard; + rec = lb_new_record(header); + mainboard = (struct lb_mainboard *)rec; + mainboard->tag = LB_TAG_MAINBOARD; + + mainboard->size = (sizeof(*mainboard) + + strlen(mainboard_vendor) + 1 + + strlen(mainboard_part_number) + 1 + + 3) & ~3; + + mainboard->vendor_idx = 0; + mainboard->part_number_idx = strlen(mainboard_vendor) + 1; + + memcpy(mainboard->strings + mainboard->vendor_idx, + mainboard_vendor, strlen(mainboard_vendor) + 1); + memcpy(mainboard->strings + mainboard->part_number_idx, + mainboard_part_number, strlen(mainboard_part_number) + 1); + + return mainboard; +} + +void lb_strings(struct lb_header *header) +{ + static const struct { + uint32_t tag; + const uint8_t *string; + } strings[] = { + { LB_TAG_VERSION, linuxbios_version, }, + { LB_TAG_EXTRA_VERSION, linuxbios_extra_version, }, + { LB_TAG_BUILD, linuxbios_build, }, + { LB_TAG_COMPILE_TIME, linuxbios_compile_time, }, + { LB_TAG_COMPILE_BY, linuxbios_compile_by, }, + { LB_TAG_COMPILE_HOST, linuxbios_compile_host, }, + { LB_TAG_COMPILE_DOMAIN, linuxbios_compile_domain, }, + { LB_TAG_COMPILER, linuxbios_compiler, }, + { LB_TAG_LINKER, linuxbios_linker, }, + { LB_TAG_ASSEMBLER, linuxbios_assembler, }, + }; + int i; + for(i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) { + struct lb_string *rec; + size_t len; + rec = (struct lb_string *)lb_new_record(header); + len = strlen(strings[i].string); + rec->tag = strings[i].tag; + rec->size = (sizeof(*rec) + len + 1 + 3) & ~3; + memcpy(rec->string, strings[i].string, len+1); + } + +} + +/* Some version of gcc have problems with 64 bit types so + * take an unsigned long instead of a uint64_t for now. + */ +void lb_memory_range(struct lb_memory *mem, + uint32_t type, unsigned long start, unsigned long size) +{ + int entries; + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + mem->map[entries].start = start; + mem->map[entries].size = size; + mem->map[entries].type = type; + mem->size += sizeof(mem->map[0]); +} + +static void lb_memory_rangek(struct lb_memory *mem, + uint32_t type, unsigned long startk, unsigned long endk) +{ + int entries; + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + mem->map[entries].start = startk; + mem->map[entries].start <<= 10; + mem->map[entries].size = endk - startk; + mem->map[entries].size <<= 10; + mem->map[entries].type = type; + mem->size += sizeof(mem->map[0]); +} + +static void lb_reserve_table_memory(struct lb_header *head) +{ + struct lb_record *last_rec; + struct lb_memory *mem; + uint64_t start; + uint64_t end; + int i, entries; + + last_rec = lb_last_record(head); + mem = get_lb_mem(); + start = (unsigned long)head; + end = (unsigned long)last_rec; + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + /* Resize the right two memory areas so this table is in + * a reserved area of memory. Everything has been carefully + * setup so that is all we need to do. + */ + for(i = 0; i < entries; i++ ) { + uint64_t map_start = mem->map[i].start; + uint64_t map_end = map_start + mem->map[i].size; + /* Does this area need to be expanded? */ + if (map_end == start) { + mem->map[i].size = end - map_start; + } + /* Does this area need to be contracted? */ + else if (map_start == start) { + mem->map[i].start = end; + mem->map[i].size = map_end - end; + } + } +} + + +unsigned long lb_table_fini(struct lb_header *head) +{ + struct lb_record *rec, *first_rec; + rec = lb_last_record(head); + if (head->table_entries) { + head->table_bytes += rec->size; + } + lb_reserve_table_memory(head); + first_rec = lb_first_record(head); + head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes); + head->header_checksum = 0; + head->header_checksum = compute_ip_checksum(head, sizeof(*head)); + printk_debug("Wrote linuxbios table at: %p - %p checksum %lx\n", + head, rec, head->table_checksum); + return (unsigned long)rec; +} + + +/* Routines to extract part so the linuxBIOS table or + * information from the linuxBIOS table after we have written it. + * Currently get_lb_mem relies on a global we can change the + * implementaiton. + */ +static struct lb_memory *mem_ranges = 0; +struct lb_memory *get_lb_mem(void) +{ + return mem_ranges; +} + +unsigned long write_linuxbios_table( + unsigned long *processor_map, + struct mem_range *ram, + unsigned long low_table_start, unsigned long low_table_end, + unsigned long rom_table_startk, unsigned long rom_table_endk) +{ + unsigned long table_size; + struct mem_range *ramp; + struct lb_header *head; + struct lb_memory *mem; + struct lb_record *rec_dest, *rec_src; + + head = lb_table_init(low_table_end); + low_table_end = (unsigned long)head; +#if HAVE_OPTION_TABLE == 1 + /* Write the option config table... */ + rec_dest = lb_new_record(head); + rec_src = (struct lb_record *)&option_table; + memcpy(rec_dest, rec_src, rec_src->size); +#endif + mem = lb_memory(head); + mem_ranges = mem; + /* I assume there is always ram at address 0 */ + /* Reserve our tables in low memory */ + table_size = (low_table_end - low_table_start); + lb_memory_range(mem, LB_MEM_TABLE, 0, table_size); + lb_memory_range(mem, LB_MEM_RAM, table_size, (ram[0].sizek << 10) - table_size); + /* Reserving pci memory mapped space will keep the kernel from booting seeing + * any pci resources. + */ + for(ramp = &ram[1]; ramp->sizek; ramp++) { + unsigned long startk, endk; + startk = ramp->basek; + endk = startk + ramp->sizek; + if ((startk < rom_table_startk) && (endk > rom_table_startk)) { + lb_memory_rangek(mem, LB_MEM_RAM, startk, rom_table_startk); + startk = rom_table_startk; + } + if ((startk == rom_table_startk) && (endk > startk)) { + unsigned long tend; + tend = rom_table_endk; + if (tend > endk) { + tend = endk; + } + lb_memory_rangek(mem, LB_MEM_TABLE, rom_table_startk, tend); + startk = tend; + } + if (endk > startk) { + lb_memory_rangek(mem, LB_MEM_RAM, startk, endk); + } + } + + /* Record our motheboard */ + lb_mainboard(head); + /* Record our various random string information */ + lb_strings(head); + + low_table_end = lb_table_fini(head); + + /* Remember where my valid memory ranges are */ + return low_table_end; +} diff --git a/src/arch/i386/boot/linuxbios_table.h b/src/arch/i386/boot/linuxbios_table.h new file mode 100644 index 0000000000..42c0a07dac --- /dev/null +++ b/src/arch/i386/boot/linuxbios_table.h @@ -0,0 +1,33 @@ +#ifndef LINUXBIOS_TABLE_H +#define LINUXBIOS_TABLE_H + +#include <boot/linuxbios_tables.h> + +struct mem_range; + +/* This file holds function prototypes for building the linuxbios table. */ +unsigned long write_linuxbios_table( + unsigned long *processor_map, + struct mem_range *ram, + unsigned long low_table_start, unsigned long low_table_end, + unsigned long rom_table_start, unsigned long rom_table_end); + +struct lb_header *lb_table_init(unsigned long addr); +struct lb_record *lb_first_record(struct lb_header *header); +struct lb_record *lb_last_record(struct lb_header *header); +struct lb_record *lb_next_record(struct lb_record *rec); +struct lb_record *lb_new_record(struct lb_header *header); +struct lb_memory *lb_memory(struct lb_header *header); +void lb_memory_range(struct lb_memory *mem, + uint32_t type, unsigned long startk, unsigned long sizek); +struct lb_mainboard *lb_mainboard(struct lb_header *header); +unsigned long lb_table_fini(struct lb_header *header); + +/* Routines to extract part so the linuxBIOS table or information + * from the linuxBIOS table. + */ +struct lb_memory *get_lb_mem(void); + +extern struct cmos_option_table option_table; + +#endif /* LINUXBIOS_TABLE_H */ diff --git a/src/arch/i386/boot/pirq_routing.c b/src/arch/i386/boot/pirq_routing.c new file mode 100644 index 0000000000..a7325c42ac --- /dev/null +++ b/src/arch/i386/boot/pirq_routing.c @@ -0,0 +1,93 @@ +#include <console/console.h> +#include <arch/pirq_routing.h> +#include <string.h> + +#ifdef DEBUG +void check_pirq_routing_table(void) +{ + const u8 *addr; + const struct irq_routing_table *rt; + int i; + u8 sum; + + printk_info("Checking IRQ routing tables...\n"); + +#ifdef(IRQ_SLOT_COUNT) + if (sizeof(intel_irq_routing_table) != intel_irq_routing_table.size) { + printk_warning("Inconsistent IRQ routing table size\n"); + } +#endif + + rt = &intel_irq_routing_table; + addr = (u8 *)rt; + + sum = 0; + for (i = 0; i < rt->size; i++) + sum += addr[i]; + + printk_debug("%s:%6d:%s() - irq_routing_table located at: 0x%p\n", + __FILE__, __LINE__, __FUNCTION__, addr); + + sum = (unsigned char)(rt->checksum-sum); + + if (sum != rt->checksum) { + printk_warning("%s:%6d:%s() - " + "checksum is: 0x%02x but should be: 0x%02x\n", + __FILE__, __LINE__, __FUNCTION__, rt->checksum, sum); + } + + if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION || + rt->size % 16 || rt->size < sizeof(struct irq_routing_table)) { + printk_warning("%s:%6d:%s() - " + "Interrupt Routing Table not valid\n", + __FILE__, __LINE__, __FUNCTION__); + return; + } + + sum = 0; + for (i=0; i<rt->size; i++) + sum += addr[i]; + + if (sum) { + printk_warning("%s:%6d:%s() - " + "checksum error in irq routing table\n", + __FILE__, __LINE__, __FUNCTION__); + } + + printk_info("done.\n"); +} + +int verify_copy_pirq_routing_table(unsigned long addr) +{ + int i; + u8 *rt_orig, *rt_curr; + + rt_curr = (u8*)addr; + rt_orig = (u8*)&intel_irq_routing_table; + printk_info("Verifing priq routing tables copy at 0x%x...", addr); + for (i = 0; i < intel_irq_routing_table.size; i++) { + if (*(rt_curr + i) != *(rt_orig + i)) { + printk_info("failed\n"); + return -1; + } + } + printk_info("succeed\n"); + return 0; +} +#else +#define verify_copy_pirq_routing_table(addr) +#endif + +unsigned long copy_pirq_routing_table(unsigned long addr) +{ + /* Align the table to be 16 byte aligned. */ + addr += 15; + addr &= ~15; + + /* This table must be betweeen 0xf0000 & 0x100000 */ + printk_info("Copying IRQ routing tables to 0x%x...", addr); + memcpy((void *)addr, &intel_irq_routing_table, intel_irq_routing_table.size); + printk_info("done.\n"); + verify_copy_pirq_routing_table(addr); + return addr + intel_irq_routing_table.size; +} diff --git a/src/arch/i386/boot/tables.c b/src/arch/i386/boot/tables.c new file mode 100644 index 0000000000..07579fefe2 --- /dev/null +++ b/src/arch/i386/boot/tables.c @@ -0,0 +1,69 @@ +#include <console/console.h> +#include <mem.h> +#include <cpu/cpu.h> +#include <boot/tables.h> +#include <boot/linuxbios_tables.h> +#include <arch/pirq_routing.h> +#include <arch/smp/mpspec.h> +#include "linuxbios_table.h" + +#if CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS && (CONFIG_MAX_PHYSICAL_CPUS < CONFIG_MAX_CPUS) +static void remove_logical_cpus(unsigned long *processor_map) +{ + /* To turn off hyperthreading just remove the logical + * cpus from the processor map. + */ + int disable_logical_cpus = !CONFIG_LOGICAL_CPUS; + if (get_option(&disable_logical_cpus,"hyper_threading")) { + disable_logical_cpus = !CONFIG_LOGICAL_CPUS; + } + if (disable_logical_cpus) { + /* disable logical cpus */ + int cnt; + for(cnt=MAX_PHYSICAL_CPUS;cnt<MAX_CPUS;cnt++) + processor_map[cnt]=0; + printk_debug("logical cpus disabled\n"); + } +} +#else + +#define remove_logical_cpus(processor_map) do {} while(0) + +#endif /* CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS */ + +struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_map) +{ + unsigned long low_table_start, low_table_end; + unsigned long rom_table_start, rom_table_end; + + rom_table_start = 0xf0000; + rom_table_end = 0xf0000; + /* Start low addr at 16 bytes instead of 0 because of a buglet + * in the generic linux unzip code, as it tests for the a20 line. + */ + low_table_start = 0; + low_table_end = 16; + + post_code(0x9a); + check_pirq_routing_table(); + /* This table must be betweeen 0xf0000 & 0x100000 */ + rom_table_end = copy_pirq_routing_table(rom_table_end); + rom_table_end = (rom_table_end + 1023) & ~1023; + + /* copy the smp block to address 0 */ + post_code(0x96); + /* The smp table must be in 0-1K, 639K-640K, or 960K-1M */ + remove_logical_cpus(processor_map); + low_table_end = write_smp_table(low_table_end, processor_map); + + /* Don't write anything in the traditional x86 BIOS data segment */ + if (low_table_end < 0x500) { + low_table_end = 0x500; + } + /* The linuxbios table must be in 0-4K or 960K-1M */ + write_linuxbios_table(processor_map, mem, + low_table_start, low_table_end, + rom_table_start >> 10, rom_table_end >> 10); + + return get_lb_mem(); +} diff --git a/src/arch/i386/include/arch/asm.h b/src/arch/i386/include/arch/asm.h new file mode 100644 index 0000000000..ea63e2d4eb --- /dev/null +++ b/src/arch/i386/include/arch/asm.h @@ -0,0 +1,30 @@ +#ifndef ASM_H +#define ASM_H + +#define ASSEMBLER + +/* + * Bootstrap code for the STPC Consumer + * Copyright (c) 1999 by Net Insight AB. All Rights Reserved. + * + * $Id$ + * + */ + +#define I386_ALIGN_TEXT 0 +#define I386_ALIGN_DATA 0 + +/* + * XXX + */ +#ifdef __ELF__ +#define EXT(x) x +#else +#define EXT(x) _ ## x +#endif + +#define STATIC(x) .align I386_ALIGN_TEXT; EXT(x): +#define GLOBAL(x) .globl EXT(x); STATIC(x) +#define ENTRY(x) .text; GLOBAL(x) + +#endif /* ASM_H */ diff --git a/src/arch/i386/include/arch/boot/boot.h b/src/arch/i386/include/arch/boot/boot.h new file mode 100644 index 0000000000..3ff51c3082 --- /dev/null +++ b/src/arch/i386/include/arch/boot/boot.h @@ -0,0 +1,8 @@ +#ifndef ASM_I386_BOOT_H +#define ASM_I386_BOOT_H + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_386 + +#endif /* ASM_I386_BOOT_H */ diff --git a/src/arch/i386/include/arch/intel.h b/src/arch/i386/include/arch/intel.h new file mode 100644 index 0000000000..df6604e08e --- /dev/null +++ b/src/arch/i386/include/arch/intel.h @@ -0,0 +1,369 @@ +/* +This software and ancillary information (herein called SOFTWARE ) +called LinuxBIOS is made available under the terms described +here. The SOFTWARE has been approved for release with associated +LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has +been authored by an employee or employees of the University of +California, operator of the Los Alamos National Laboratory under +Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The +U.S. Government has rights to use, reproduce, and distribute this +SOFTWARE. The public may copy, distribute, prepare derivative works +and publicly display this SOFTWARE without charge, provided that this +Notice and any statement of authorship are reproduced on all copies. +Neither the Government nor the University makes any warranty, express +or implied, or assumes any liability or responsibility for the use of +this SOFTWARE. If SOFTWARE is modified to produce derivative works, +such modified SOFTWARE should be clearly marked, so as not to confuse +it with the version available from LANL. + */ +/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL + * rminnich@lanl.gov + */ + + +#ifndef ROM_INTEL_H +#define ROM_INTEL_H + +/* + * Bootstrap code for the Intel + * + * $Id$ + * + */ + +/* + * Config registers. + */ +/* yeah, yeah, I know these are macros, which is bad. Don't forget: + * we have almost no assembly, so I am not worrying just yet about this. + * we'll fix it someday if we care. My guess is we won't. + */ + +/* well we want functions. But first we want to see it work at all. */ +#undef FUNCTIONS +#ifndef FUNCTIONS + + +#define RET_LABEL(label) \ + jmp label##_done + +#define CALL_LABEL(label) \ + jmp label ;\ +label##_done: + +#define CALLSP(func) \ + lea 0f, %esp ; \ + jmp func ; \ +0: + +#define RETSP \ + jmp *%esp + + +#define DELAY(x) mov x, %ecx ;\ + 1: loop 1b ;\ + + + /* + * Macro: PCI_WRITE_CONFIG_BYTE + * Arguments: %eax address to write to (includes bus, device, function, &offset) + * %dl byte to write + * + * Results: none + * + * Trashed: %eax, %edx + * Effects: writes a single byte to pci config space + * + * Notes: This routine is optimized for minimal register usage. + * And the tricks it does cannot scale beyond writing a single byte. + * + * What it does is almost simple. + * It preserves %eax (baring special bits) until it is written + * out to the appropriate port. And hides the data byte + * in the high half of edx. + * + * In %edx[3] it stores the byte to write. + * In %edx[2] it stores the lower three bits of the address. + */ + + +#define PCI_WRITE_CONFIG_BYTE \ + shll $8, %edx ; \ + movb %al, %dl ; \ + andb $0x3, %dl ; \ + shll $16, %edx ; \ + \ + orl $0x80000000, %eax ; \ + andl $0xfffffffc, %eax ; \ + movw $0xcf8, %dx ; \ + outl %eax, %dx ; \ + \ + shrl $16, %edx ; \ + movb %dh, %al ; \ + movb $0, %dh ; \ + addl $0xcfc, %edx ; \ + outb %al, %dx + + + /* + * Macro: PCI_WRITE_CONFIG_WORD + * Arguments: %eax address to write to (includes bus, device, function, &offset) + * %ecx word to write + * + * Results: none + * + * Trashed: %eax, %edx + * Preserved: %ecx + * Effects: writes a single byte to pci config space + * + * Notes: This routine is optimized for minimal register usage. + * + * What it does is almost simple. + * It preserves %eax (baring special bits) until it is written + * out to the appropriate port. And hides the least significant + * bits of the address in the high half of edx. + * + * In %edx[2] it stores the lower three bits of the address. + */ + + +#define PCI_WRITE_CONFIG_WORD \ + movb %al, %dl ; \ + andl $0x3, %edx ; \ + shll $16, %edx ; \ + \ + orl $0x80000000, %eax ; \ + andl $0xfffffffc, %eax ; \ + movw $0xcf8, %dx ; \ + outl %eax, %dx ; \ + \ + shrl $16, %edx ; \ + movl %ecx, %eax ; \ + addl $0xcfc, %edx ; \ + outw %ax, %dx + + + + /* + * Macro: PCI_WRITE_CONFIG_DWORD + * Arguments: %eax address to write to (includes bus, device, function, &offset) + * %ecx dword to write + * + * Results: none + * + * Trashed: %eax, %edx + * Preserved: %ecx + * Effects: writes a single byte to pci config space + * + * Notes: This routine is optimized for minimal register usage. + * + * What it does is almost simple. + * It preserves %eax (baring special bits) until it is written + * out to the appropriate port. And hides the least significant + * bits of the address in the high half of edx. + * + * In %edx[2] it stores the lower three bits of the address. + */ + + +#define PCI_WRITE_CONFIG_DWORD \ + movb %al, %dl ; \ + andl $0x3, %edx ; \ + shll $16, %edx ; \ + \ + orl $0x80000000, %eax ; \ + andl $0xfffffffc, %eax ; \ + movw $0xcf8, %dx ; \ + outl %eax, %dx ; \ + \ + shrl $16, %edx ; \ + movl %ecx, %eax ; \ + addl $0xcfc, %edx ; \ + outl %eax, %dx + + + + + /* + * Macro: PCI_READ_CONFIG_BYTE + * Arguments: %eax address to read from (includes bus, device, function, &offset) + * + * Results: %al Byte read + * + * Trashed: %eax, %edx + * Effects: reads a single byte from pci config space + * + * Notes: This routine is optimized for minimal register usage. + * + * What it does is almost simple. + * It preserves %eax (baring special bits) until it is written + * out to the appropriate port. And hides the least significant + * bits of the address in the high half of edx. + * + * In %edx[2] it stores the lower three bits of the address. + */ + + +#define PCI_READ_CONFIG_BYTE \ + movb %al, %dl ; \ + andl $0x3, %edx ; \ + shll $16, %edx ; \ + \ + orl $0x80000000, %eax ; \ + andl $0xfffffffc, %eax ; \ + movw $0xcf8, %dx ; \ + outl %eax, %dx ; \ + \ + shrl $16, %edx ; \ + addl $0xcfc, %edx ; \ + inb %dx, %al + + + + /* + * Macro: PCI_READ_CONFIG_WORD + * Arguments: %eax address to read from (includes bus, device, function, &offset) + * + * Results: %ax word read + * + * Trashed: %eax, %edx + * Effects: reads a 2 bytes from pci config space + * + * Notes: This routine is optimized for minimal register usage. + * + * What it does is almost simple. + * It preserves %eax (baring special bits) until it is written + * out to the appropriate port. And hides the least significant + * bits of the address in the high half of edx. + * + * In %edx[2] it stores the lower three bits of the address. + */ + + +#define PCI_READ_CONFIG_WORD \ + movb %al, %dl ; \ + andl $0x3, %edx ; \ + shll $16, %edx ; \ + \ + orl $0x80000000, %eax ; \ + andl $0xfffffffc, %eax ; \ + movw $0xcf8, %dx ; \ + outl %eax, %dx ; \ + \ + shrl $16, %edx ; \ + addl $0xcfc, %edx ; \ + inw %dx, %ax + + + + /* + * Macro: PCI_READ_CONFIG_DWORD + * Arguments: %eax address to read from (includes bus, device, function, &offset) + * + * Results: %eax + * + * Trashed: %edx + * Effects: reads 4 bytes from pci config space + * + * Notes: This routine is optimized for minimal register usage. + * + * What it does is almost simple. + * It preserves %eax (baring special bits) until it is written + * out to the appropriate port. And hides the least significant + * bits of the address in the high half of edx. + * + * In %edx[2] it stores the lower three bits of the address. + */ + + +#define PCI_READ_CONFIG_DWORD \ + movb %al, %dl ; \ + andl $0x3, %edx ; \ + shll $16, %edx ; \ + \ + orl $0x80000000, %eax ; \ + andl $0xfffffffc, %eax ; \ + movw $0xcf8, %dx ; \ + outl %eax, %dx ; \ + \ + shrl $16, %edx ; \ + addl $0xcfc, %edx ; \ + inl %dx, %eax + + + + +#define CS_READ(which) \ + mov $0x80000000,%eax ; \ + mov which,%ax ; \ + and $0xfc,%al /* clear bits 1-0 */ ; \ + mov $0xcf8,%dx /* port 0xcf8 ?*/ ; \ + outl %eax,%dx /* open up CS config */ ; \ + add $0x4,%dl /* 0xcfc data port 0 */ ; \ + mov which,%al ; \ + and $0x3,%al /* only bits 1-0 */ ; \ + add %al,%dl ; \ + inb %dx,%al /* read */ ; \ + + +#define CS_WRITE(which, data) \ + mov $0x80000000,%eax /* 32bit word with bit 31 set */ ; \ + mov which,%ax /* put the reg# in the low part */ ; \ + and $0xfc,%al /* dword align the reg# */ ; \ + mov $0xcf8,%dx /* enable port */ ; \ + outl %eax,%dx ; \ + add $0x4,%dl /* 1st data port */ ; \ + mov which,%ax /* register# */ ; \ + and $0x3,%ax ; \ + add %al,%dl ; \ + mov data, %al ; \ + outb %al,%dx /* write to reg */ + +#define REGBIS(which, bis) \ + CS_READ(which) ;\ + movb bis, %cl ;\ + orb %al, %cl ;\ + CS_WRITE(which, %cl) + +#define REGBIC(which, bic) \ + CS_READ(which) ;\ + movb bic, %cl ;\ + notb %cl ;\ + andb %al, %cl ;\ + CS_WRITE(which, %cl) + + +/* macro to BIC and BIS a reg. calls read a reg, + * does a BIC and then a BIS on it. + * to clear no bits, make BIC 0. + * to set no bits, make BIS 0 + */ +#define REGBICBIS(which, bic, bis) \ + CS_READ(which) ;\ + movb bic, %cl ;\ + notb %cl ;\ + andb %cl, %al ;\ + movb bis, %cl ;\ + orb %al, %cl ;\ + CS_WRITE(which, %cl) + +#else +NO FUNCTIONS YET! +#endif + + + +/* originally this macro was from STPC BIOS */ +#define intel_chip_post_macro(value) \ + movb $value, %al ; \ + outb %al, $0x80 + +#define INTEL_PDATA_MAGIC 0xdeadbeef + +/* SLOW_DOWN_IO is a delay we can use that is roughly cpu neutral, + * and can be used before memory or timer chips come up. + * Since this hits the isa bus it's roughly + */ +#define SLOW_DOWN_IO inb $0x80, %al + +#endif /* ROM_INTEL_H */ diff --git a/src/arch/i386/include/arch/io.h b/src/arch/i386/include/arch/io.h new file mode 100644 index 0000000000..bcba9a932c --- /dev/null +++ b/src/arch/i386/include/arch/io.h @@ -0,0 +1,76 @@ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +/* + * This file contains the definitions for the x86 IO instructions + * inb/inw/inl/outb/outw/outl and the "string versions" of the same + * (insb/insw/insl/outsb/outsw/outsl). + * + * This file is not meant to be obfuscating: it's just complicated + * to (a) handle it all in a way that makes gcc able to optimize it + * as well as possible and (b) trying to avoid writing the same thing + * over and over again with slight variations and possibly making a + * mistake somewhere. + */ + + /* + * Bit simplified and optimized by Jan Hubicka + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999. + */ + +/* + * Talk about misusing macros.. + */ +#define __OUT1(s,x) \ +extern inline void out##s(unsigned x value, unsigned short port) { + +#define __OUT2(s,s1,s2) \ +__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" + +#define __OUT(s,s1,x) \ +__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } + +#define __IN1(s) \ +extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v; + +#define __IN2(s,s1,s2) \ +__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" + +#define __IN(s,s1,i...) \ +__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } + +#define __INS(s) \ +extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("cld ; rep ; ins" #s \ +: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + +#define __OUTS(s) \ +extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("cld ; rep ; outs" #s \ +: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + +#define RETURN_TYPE unsigned char +__IN(b,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned short +__IN(w,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned int +__IN(l,"") +#undef RETURN_TYPE + +__OUT(b,"b",char) +__OUT(w,"w",short) +__OUT(l,,int) + +__INS(b) +__INS(w) +__INS(l) + +__OUTS(b) +__OUTS(w) +__OUTS(l) + + +#endif + diff --git a/src/arch/i386/include/arch/pciconf.h b/src/arch/i386/include/arch/pciconf.h new file mode 100644 index 0000000000..8695ee2294 --- /dev/null +++ b/src/arch/i386/include/arch/pciconf.h @@ -0,0 +1,9 @@ +#ifndef PCI_CONF_REG_INDEX + +// These are defined in the PCI spec, and hence are theoretically +// inclusive of ANYTHING that uses a PCI bus. +#define PCI_CONF_REG_INDEX 0xcf8 +#define PCI_CONF_REG_DATA 0xcfc +#define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where)) + +#endif diff --git a/src/arch/i386/include/arch/pirq_routing.h b/src/arch/i386/include/arch/pirq_routing.h new file mode 100644 index 0000000000..215c4e58c8 --- /dev/null +++ b/src/arch/i386/include/arch/pirq_routing.h @@ -0,0 +1,54 @@ +#ifndef ARCH_PIRQ_ROUTING_H +#define ARCH_PIRQ_ROUTING_H + +#include <stdint.h> + +#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) +#define PIRQ_VERSION 0x0100 + +struct irq_info { + uint8_t bus, devfn; /* Bus, device and function */ + struct { + uint8_t link; /* IRQ line ID, chipset dependent, 0=not routed */ + uint16_t bitmap; /* Available IRQs */ + } __attribute__((packed)) irq[4]; + uint8_t slot; /* Slot number, 0=onboard */ + uint8_t rfu; +} __attribute__((packed)); + +#if defined(IRQ_SLOT_COUNT) +#define IRQ_SLOTS_COUNT IRQ_SLOT_COUNT +#elif (__GNUC__ < 3) +#define IRQ_SLOTS_COUNT 1 +#else +#define IRQ_SLOTS_COUNT +#endif + +struct irq_routing_table { + uint32_t signature; /* PIRQ_SIGNATURE should be here */ + uint16_t version; /* PIRQ_VERSION */ + uint16_t size; /* Table size in bytes */ + uint8_t rtr_bus, rtr_devfn; /* Where the interrupt router lies */ + uint16_t exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ + uint16_t rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ + uint32_t miniport_data; /* Crap */ + uint8_t rfu[11]; + uint8_t checksum; /* Modulo 256 checksum must give zero */ + struct irq_info slots[IRQ_SLOTS_COUNT]; +} __attribute__((packed)); + +extern const struct irq_routing_table intel_irq_routing_table; + +#if defined(DEBUG) && defined(HAVE_PIRQ_TABLE) +void check_pirq_routing_table(void); +#else +#define check_pirq_routing_table() do {} while(0) +#endif + +#if defined(HAVE_PIRQ_TABLE) +unsigned long copy_pirq_routing_table(unsigned long start); +#else +#define copy_pirq_routing_table(start) (start) +#endif + +#endif /* ARCH_PIRQ_ROUTING_H */ diff --git a/src/arch/i386/include/arch/rom_segs.h b/src/arch/i386/include/arch/rom_segs.h new file mode 100644 index 0000000000..b51a805948 --- /dev/null +++ b/src/arch/i386/include/arch/rom_segs.h @@ -0,0 +1,10 @@ +#ifndef ROM_SEGS_H +#define ROM_SEGS_H + +#define ROM_CODE_SEG 0x08 +#define ROM_DATA_SEG 0x10 + +#define CACHE_RAM_CODE_SEG 0x18 +#define CACHE_RAM_DATA_SEG 0x20 + +#endif /* ROM_SEGS_H */ diff --git a/src/arch/i386/include/arch/romcc_io.h b/src/arch/i386/include/arch/romcc_io.h new file mode 100644 index 0000000000..02cc272884 --- /dev/null +++ b/src/arch/i386/include/arch/romcc_io.h @@ -0,0 +1,84 @@ +static void outb(unsigned char value, unsigned short port) +{ + __builtin_outb(value, port); +} + +static void outw(unsigned short value, unsigned short port) +{ + __builtin_outw(value, port); +} + +static void outl(unsigned int value, unsigned short port) +{ + __builtin_outl(value, port); +} + + +static unsigned char inb(unsigned short port) +{ + return __builtin_inb(port); +} + + +static unsigned char inw(unsigned short port) +{ + return __builtin_inw(port); +} + +static unsigned char inl(unsigned short port) +{ + return __builtin_inl(port); +} + +static void hlt(void) +{ + __builtin_hlt(); +} + +static unsigned int config_cmd(unsigned char bus, unsigned devfn, unsigned where) +{ + return 0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3); +} + +static unsigned char pcibios_read_config_byte( + unsigned char bus, unsigned devfn, unsigned where) +{ + outl(config_cmd(bus, devfn, where), 0xCF8); + return inb(0xCFC + (where & 3)); +} + +static unsigned short pcibios_read_config_word( + unsigned char bus, unsigned devfn, unsigned where) +{ + outl(config_cmd(bus, devfn, where), 0xCF8); + return inw(0xCFC + (where & 2)); +} + +static unsigned int pcibios_read_config_dword( + unsigned char bus, unsigned devfn, unsigned where) +{ + outl(config_cmd(bus, devfn, where), 0xCF8); + return inl(0xCFC); +} + + +static void pcibios_write_config_byte( + unsigned char bus, unsigned devfn, unsigned where, unsigned char value) +{ + outl(config_cmd(bus, devfn, where), 0xCF8); + outb(value, 0xCFC + (where & 3)); +} + +static void pcibios_write_config_word( + unsigned char bus, unsigned devfn, unsigned where, unsigned short value) +{ + outl(config_cmd(bus, devfn, where), 0xCF8); + outw(value, 0xCFC + (where & 2)); +} + +static void pcibios_write_config_dword( + unsigned char bus, unsigned devfn, unsigned where, unsigned int value) +{ + outl(config_cmd(bus, devfn, where), 0xCF8); + outl(value, 0xCFC); +} diff --git a/src/arch/i386/include/arch/smp/mpspec.h b/src/arch/i386/include/arch/smp/mpspec.h new file mode 100644 index 0000000000..305276e482 --- /dev/null +++ b/src/arch/i386/include/arch/smp/mpspec.h @@ -0,0 +1,282 @@ +#ifndef __ASM_MPSPEC_H +#define __ASM_MPSPEC_H + +#ifdef HAVE_MP_TABLE + +/* + * Structure definitions for SMP machines following the + * Intel Multiprocessing Specification 1.1 and 1.4. + */ + +/* + * This tag identifies where the SMP configuration + * information is. + */ + +#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_') + +/* + * a maximum of 16 APICs with the current APIC ID architecture. + */ +#define MAX_APICS 16 + + +#define SMP_FLOATING_TABLE_LEN sizeof(struct intel_mp_floating) + +struct intel_mp_floating +{ + char mpf_signature[4]; /* "_MP_" */ + unsigned long mpf_physptr; /* Configuration table address */ + unsigned char mpf_length; /* Our length (paragraphs) */ + unsigned char mpf_specification;/* Specification version */ + unsigned char mpf_checksum; /* Checksum (makes sum 0) */ + unsigned char mpf_feature1; /* Standard or configuration ? */ + unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */ + unsigned char mpf_feature3; /* Unused (0) */ + unsigned char mpf_feature4; /* Unused (0) */ + unsigned char mpf_feature5; /* Unused (0) */ +}; + +struct mp_config_table +{ + char mpc_signature[4]; +#define MPC_SIGNATURE "PCMP" + unsigned short mpc_length; /* Size of table */ + char mpc_spec; /* 0x01 */ + char mpc_checksum; + char mpc_oem[8]; + char mpc_productid[12]; + unsigned long mpc_oemptr; /* 0 if not present */ + unsigned short mpc_oemsize; /* 0 if not present */ + unsigned short mpc_entry_count; + unsigned long mpc_lapic; /* APIC address */ + unsigned short mpe_length; /* Extended Table size */ + unsigned char mpe_checksum; /* Extended Table checksum */ + unsigned char reserved; +}; + +/* Followed by entries */ + +#define MP_PROCESSOR 0 +#define MP_BUS 1 +#define MP_IOAPIC 2 +#define MP_INTSRC 3 +#define MP_LINTSRC 4 + +struct mpc_config_processor +{ + unsigned char mpc_type; + unsigned char mpc_apicid; /* Local APIC number */ + unsigned char mpc_apicver; /* Its versions */ + unsigned char mpc_cpuflag; +#define MPC_CPU_ENABLED 1 /* Processor is available */ +#define MPC_CPU_BOOTPROCESSOR 2 /* Processor is the BP */ + unsigned long mpc_cpufeature; +#define MPC_CPU_STEPPING_MASK 0x0F +#define MPC_CPU_MODEL_MASK 0xF0 +#define MPC_CPU_FAMILY_MASK 0xF00 + unsigned long mpc_featureflag; /* CPUID feature value */ + unsigned long mpc_reserved[2]; +}; + +struct mpc_config_bus +{ + unsigned char mpc_type; + unsigned char mpc_busid; + unsigned char mpc_bustype[6] __attribute((packed)); +}; + +#define BUSTYPE_EISA "EISA" +#define BUSTYPE_ISA "ISA" +#define BUSTYPE_INTERN "INTERN" /* Internal BUS */ +#define BUSTYPE_MCA "MCA" +#define BUSTYPE_VL "VL" /* Local bus */ +#define BUSTYPE_PCI "PCI" +#define BUSTYPE_PCMCIA "PCMCIA" + +struct mpc_config_ioapic +{ + unsigned char mpc_type; + unsigned char mpc_apicid; + unsigned char mpc_apicver; + unsigned char mpc_flags; +#define MPC_APIC_USABLE 0x01 + unsigned long mpc_apicaddr; +}; + +struct mpc_config_intsrc +{ + unsigned char mpc_type; + unsigned char mpc_irqtype; + unsigned short mpc_irqflag; + unsigned char mpc_srcbus; + unsigned char mpc_srcbusirq; + unsigned char mpc_dstapic; + unsigned char mpc_dstirq; +}; + +enum mp_irq_source_types { + mp_INT = 0, + mp_NMI = 1, + mp_SMI = 2, + mp_ExtINT = 3 +}; + +#define MP_IRQ_POLARITY_DEFAULT 0x0 +#define MP_IRQ_POLARITY_HIGH 0x1 +#define MP_IRQ_POLARITY_LOW 0x3 +#define MP_IRQ_POLARITY_MASK 0x3 +#define MP_IRQ_TRIGGER_DEFAULT 0x0 +#define MP_IRQ_TRIGGER_EDGE 0x4 +#define MP_IRQ_TRIGGER_LEVEL 0xc +#define MP_IRQ_TRIGGER_MASK 0xc + + +struct mpc_config_lintsrc +{ + unsigned char mpc_type; + unsigned char mpc_irqtype; + unsigned short mpc_irqflag; + unsigned char mpc_srcbusid; + unsigned char mpc_srcbusirq; + unsigned char mpc_destapic; +#define MP_APIC_ALL 0xFF + unsigned char mpc_destapiclint; +}; + +/* + * Default configurations + * + * 1 2 CPU ISA 82489DX + * 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining + * 3 2 CPU EISA 82489DX + * 4 2 CPU MCA 82489DX + * 5 2 CPU ISA+PCI + * 6 2 CPU EISA+PCI + * 7 2 CPU MCA+PCI + */ + +#define MAX_IRQ_SOURCES 128 +#define MAX_MP_BUSSES 32 +enum mp_bustype { + MP_BUS_ISA, + MP_BUS_EISA, + MP_BUS_PCI, + MP_BUS_MCA +}; + +/* Followed by entries */ + +#define MPE_SYSTEM_ADDRESS_SPACE 0x80 +#define MPE_BUS_HIERARCHY 0x81 +#define MPE_COMPATIBILITY_ADDRESS_SPACE 0x82 + +struct mp_exten_config { + unsigned char mpe_type; + unsigned char mpe_length; +}; + +typedef struct mp_exten_config *mpe_t; + +struct mp_exten_system_address_space { + unsigned char mpe_type; + unsigned char mpe_length; + unsigned char mpe_busid; + unsigned char mpe_address_type; +#define ADDRESS_TYPE_IO 0 +#define ADDRESS_TYPE_MEM 1 +#define ADDRESS_TYPE_PREFETCH 2 + unsigned int mpe_address_base_low; + unsigned int mpe_address_base_high; + unsigned int mpe_address_length_low; + unsigned int mpe_address_length_high; +}; + +struct mp_exten_bus_hierarchy { + unsigned char mpe_type; + unsigned char mpe_length; + unsigned char mpe_busid; + unsigned char mpe_bus_info; +#define BUS_SUBTRACTIVE_DECODE 1 + unsigned char mpe_parent_busid; + unsigned char reserved[3]; +}; + +struct mp_exten_compatibility_address_space { + unsigned char mpe_type; + unsigned char mpe_length; + unsigned char mpe_busid; + unsigned char mpe_address_modifier; +#define ADDRESS_RANGE_SUBTRACT 1 +#define ADDRESS_RANGE_ADD 0 + unsigned int mpe_range_list; +#define RANGE_LIST_IO_ISA 0 + /* X100 - X3FF + * X500 - X7FF + * X900 - XBFF + * XD00 - XFFF + */ +#define RANGE_LIST_IO_VGA 1 + /* X3B0 - X3BB + * X3C0 - X3DF + * X7B0 - X7BB + * X7C0 - X7DF + * XBB0 - XBBB + * XBC0 - XBDF + * XFB0 - XFBB + * XFC0 - XCDF + */ +}; + +/* Default local apic addr */ +#define LAPIC_ADDR 0xFEE00000 + +void *smp_next_mpc_entry(struct mp_config_table *mc); +void *smp_next_mpe_entry(struct mp_config_table *mc); + +void smp_write_processor(struct mp_config_table *mc, + unsigned char apicid, unsigned char apicver, + unsigned char cpuflag, unsigned int cpufeature, + unsigned int featureflag); +void smp_write_processors(struct mp_config_table *mc, + unsigned long *processor_map); +void smp_write_bus(struct mp_config_table *mc, + unsigned char id, unsigned char *bustype); +void smp_write_ioapic(struct mp_config_table *mc, + unsigned char id, unsigned char ver, + unsigned long apicaddr); +void smp_write_intsrc(struct mp_config_table *mc, + unsigned char irqtype, unsigned short irqflag, + unsigned char srcbus, unsigned char srcbusirq, + unsigned char dstapic, unsigned char dstirq); +void smp_write_lintsrc(struct mp_config_table *mc, + unsigned char irqtype, unsigned short irqflag, + unsigned char srcbusid, unsigned char srcbusirq, + unsigned char destapic, unsigned char destapiclint); +void smp_write_address_space(struct mp_config_table *mc, + unsigned char busid, unsigned char address_type, + unsigned int address_base_low, unsigned int address_base_high, + unsigned int address_length_low, unsigned int address_length_high); +void smp_write_bus_hierarchy(struct mp_config_table *mc, + unsigned char busid, unsigned char bus_info, + unsigned char parent_busid); +void smp_write_compatibility_address_space(struct mp_config_table *mc, + unsigned char busid, unsigned char address_modifier, + unsigned int range_list); +unsigned char smp_compute_checksum(void *v, int len); +void *smp_write_floating_table(unsigned long addr); +unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map); + +/* A table (per mainboard) listing the initial apicid of each cpu. */ +extern unsigned long initial_apicid[MAX_CPUS]; + +#else /* HAVE_MP_TABLE */ +static inline +unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map) +{ + return addr; +} +#endif /* HAVE_MP_TABLE */ + +#endif + diff --git a/src/arch/i386/include/bitops.h b/src/arch/i386/include/bitops.h new file mode 100644 index 0000000000..fae2045b9a --- /dev/null +++ b/src/arch/i386/include/bitops.h @@ -0,0 +1,20 @@ +#ifndef I386_BITOPS_H +#define I386_BITOPS_H + +/** + * log2 - Find the truncated log base 2 of x + */ + +static inline unsigned long log2(unsigned long x) +{ + unsigned long r = 0; + __asm__( + "bsrl %1, %0\n\t" + "jnz 1f\n\t" + "movl $-1, %0\n\t" + "1:\n\t" + : "=r" (r) : "r" (x)); + return r; + +} +#endif /* I386_BITOPS_H */ diff --git a/src/arch/i386/include/stddef.h b/src/arch/i386/include/stddef.h new file mode 100644 index 0000000000..4bf6b0a867 --- /dev/null +++ b/src/arch/i386/include/stddef.h @@ -0,0 +1,15 @@ +#ifndef I386_STDDEF_H +#define I386_STDDEF_H + +typedef long ptrdiff_t; +typedef unsigned long size_t; +typedef long ssize_t; + +typedef int wchar_t; +typedef unsigned int wint_t; + +#define NULL 0 + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#endif /* I386_STDDEF_H */ diff --git a/src/arch/i386/include/stdint.h b/src/arch/i386/include/stdint.h new file mode 100644 index 0000000000..58d7519cde --- /dev/null +++ b/src/arch/i386/include/stdint.h @@ -0,0 +1,52 @@ +#ifndef I386_STDINT_H +#define I386_STDINT_H + +/* Exact integral types */ +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef signed int int32_t; + +typedef unsigned long long uint64_t; +typedef signed long long int64_t; + +/* Small types */ +typedef unsigned char uint_least8_t; +typedef signed char int_least8_t; + +typedef unsigned short uint_least16_t; +typedef signed short int_least16_t; + +typedef unsigned int uint_least32_t; +typedef signed int int_least32_t; + +typedef unsigned long long uint_least64_t; +typedef signed long long int_least64_t; + +/* Fast Types */ +typedef unsigned char uint_fast8_t; +typedef signed char int_fast8_t; + +typedef unsigned int uint_fast16_t; +typedef signed int int_fast16_t; + +typedef unsigned int uint_fast32_t; +typedef signed int int_fast32_t; + +typedef unsigned long long uint_fast64_t; +typedef signed long long int_fast64_t; + +/* Types for `void *' pointers. */ +typedef int intptr_t; +typedef unsigned int uintptr_t; + +/* Largest integral types */ +typedef long long int intmax_t; +typedef unsigned long long uintmax_t; + + +#endif /* I386_STDINT_H */ diff --git a/src/arch/i386/lib/c_start.S b/src/arch/i386/lib/c_start.S new file mode 100644 index 0000000000..f5ca3388f8 --- /dev/null +++ b/src/arch/i386/lib/c_start.S @@ -0,0 +1,135 @@ +#include <arch/asm.h> +#include <arch/intel.h> +#ifdef SMP +#include <cpu/p6/apic.h> +#endif + .section ".text" + .code32 + .globl _start +_start: + cli + lgdt %cs:gdtaddr + ljmp $0x10, $1f +1: movl $0x18, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %ss + movl %eax, %fs + movl %eax, %gs + + intel_chip_post_macro(0x13) /* post 12 */ + + /** clear stack */ + leal EXT(_stack), %edi + movl $EXT(_estack), %ecx + subl %edi, %ecx + xorl %eax, %eax + rep + stosb + + /** clear bss */ + leal EXT(_bss), %edi + movl $EXT(_ebss), %ecx + subl %edi, %ecx + jz .Lnobss + xorl %eax, %eax + rep + stosb +.Lnobss: + + /* set new stack */ + movl $_estack, %esp +#ifdef SMP + /* Get the cpu id */ + movl $APIC_DEFAULT_BASE, %edi + movl APIC_ID(%edi), %eax + shrl $24, %eax + + /* Get the cpu index (MAX_CPUS on error) */ + movl $-4, %ebx +1: addl $4, %ebx + cmpl $(MAX_CPUS << 2), %ebx + je 2 + cmpl %eax, EXT(initial_apicid)(%ebx) + jne 1b +2: shrl $2, %ebx + + /* Now compute the appropriate stack */ + movl %ebx, %eax + movl $STACK_SIZE, %ebx + mull %ebx + subl %eax, %esp +#endif + + /* push the boot_complete flag */ + pushl %ebp + + /* Save the stack location */ + movl %esp, %ebp + + /* + * Now we are finished. Memory is up, data is copied and + * bss is cleared. Now we call the main routine and + * let it do the rest. + */ + intel_chip_post_macro(0xfe) /* post fe */ + + /* Resort the stack location */ + movl %ebp, %esp + + /* The boot_complete flag has already been pushed */ + call EXT(hardwaremain) + /*NOTREACHED*/ +.Lhlt: + intel_chip_post_macro(0xee) /* post fe */ + hlt + jmp .Lhlt + + + .globl gdt, gdt_end, gdt_limit + +gdt_limit = gdt_end - gdt - 1 /* compute the table limit */ +gdtaddr: + .word gdt_limit + .long gdt /* we know the offset */ + +gdt: +// selgdt 0 + .word 0x0000, 0x0000 /* dummy */ + .byte 0x00, 0x00, 0x00, 0x00 + +// selgdt 8 + .word 0x0000, 0x0000 /* dummy */ + .byte 0x00, 0x00, 0x00, 0x00 + +// selgdt 0x10 +/* flat code segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xcf, 0x00 + +//selgdt 0x18 +/* flat data segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x93, 0xcf, 0x00 + +//selgdt 0x20 + .word 0x0000, 0x0000 /* dummy */ + .byte 0x00, 0x00, 0x00, 0x00 + +#if defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1) + // from monty: + /* 0x00009a00,0000ffffULL, 20h: 16-bit 64k code at 0x00000000 */ + /* 0x00009200,0000ffffULL 28h: 16-bit 64k data at 0x00000000 */ +// selgdt 0x28 +/*16-bit 64k code at 0x00000000 */ + .word 0xffff, 0x0000 + .byte 0, 0x9a, 0, 0 + +// selgdt 0x30 +/*16-bit 64k data at 0x00000000 */ + .word 0xffff, 0x0000 + .byte 0, 0x92, 0, 0 +#endif // defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1) +gdt_end: + +.code32 diff --git a/src/arch/i386/lib/console.c b/src/arch/i386/lib/console.c new file mode 100644 index 0000000000..8c8eccdd2a --- /dev/null +++ b/src/arch/i386/lib/console.c @@ -0,0 +1,119 @@ +#include <console/loglevel.h> + +static void __console_tx_byte(unsigned char byte) +{ + uart_tx_byte(byte); +} + +static void __console_tx_nibble(unsigned nibble) +{ + unsigned char digit; + digit = nibble + '0'; + if (digit > '9') { + digit += 39; + } + __console_tx_byte(digit); +} + +static void __console_tx_char(int loglevel, unsigned char byte) +{ + if (ASM_CONSOLE_LOGLEVEL > loglevel) { + uart_tx_byte(byte); + } +} + +static void __console_tx_hex8(int loglevel, unsigned char byte) +{ + if (ASM_CONSOLE_LOGLEVEL > loglevel) { + __console_tx_nibble(byte >> 4U); + __console_tx_nibble(byte & 0x0fU); + } +} + +static void __console_tx_hex32(int loglevel, unsigned int value) +{ + if (ASM_CONSOLE_LOGLEVEL > loglevel) { + __console_tx_nibble((value >> 28U) & 0x0fU); + __console_tx_nibble((value >> 24U) & 0x0fU); + __console_tx_nibble((value >> 20U) & 0x0fU); + __console_tx_nibble((value >> 16U) & 0x0fU); + __console_tx_nibble((value >> 12U) & 0x0fU); + __console_tx_nibble((value >> 8U) & 0x0fU); + __console_tx_nibble((value >> 4U) & 0x0fU); + __console_tx_nibble(value & 0x0fU); + } +} + +static void __console_tx_string(int loglevel, const char *str) +{ + if (ASM_CONSOLE_LOGLEVEL > loglevel) { + unsigned char ch; + while((ch = *str++) != '\0') { + __console_tx_byte(ch); + } + } +} + +static void print_emerg_char(unsigned char byte) { __console_tx_char(BIOS_EMERG, byte); } +static void print_emerg_hex8(unsigned char value){ __console_tx_hex8(BIOS_EMERG, value); } +static void print_emerg_hex32(unsigned int value) { __console_tx_hex32(BIOS_EMERG, value); } +static void print_emerg(const char *str) { __console_tx_string(BIOS_EMERG, str); } + +static void print_alert_char(unsigned char byte) { __console_tx_char(BIOS_ALERT, byte); } +static void print_alert_hex8(unsigned char value) { __console_tx_hex8(BIOS_ALERT, value); } +static void print_alert_hex32(unsigned int value) { __console_tx_hex32(BIOS_ALERT, value); } +static void print_alert(const char *str) { __console_tx_string(BIOS_ALERT, str); } + +static void print_crit_char(unsigned char byte) { __console_tx_char(BIOS_CRIT, byte); } +static void print_crit_hex8(unsigned char value) { __console_tx_hex8(BIOS_CRIT, value); } +static void print_crit_hex32(unsigned int value) { __console_tx_hex32(BIOS_CRIT, value); } +static void print_crit(const char *str) { __console_tx_string(BIOS_CRIT, str); } + +static void print_err_char(unsigned char byte) { __console_tx_char(BIOS_ERR, byte); } +static void print_err_hex8(unsigned char value) { __console_tx_hex8(BIOS_ERR, value); } +static void print_err_hex32(unsigned int value) { __console_tx_hex32(BIOS_ERR, value); } +static void print_err(const char *str) { __console_tx_string(BIOS_ERR, str); } + +static void print_warning_char(unsigned char byte) { __console_tx_char(BIOS_WARNING, byte); } +static void print_warning_hex8(unsigned char value) { __console_tx_hex8(BIOS_WARNING, value); } +static void print_warning_hex32(unsigned int value) { __console_tx_hex32(BIOS_WARNING, value); } +static void print_warning(const char *str) { __console_tx_string(BIOS_WARNING, str); } + +static void print_notice_char(unsigned char byte) { __console_tx_char(BIOS_NOTICE, byte); } +static void print_notice_hex8(unsigned char value) { __console_tx_hex8(BIOS_NOTICE, value); } +static void print_notice_hex32(unsigned int value) { __console_tx_hex32(BIOS_NOTICE, value); } +static void print_notice(const char *str) { __console_tx_string(BIOS_NOTICE, str); } + +static void print_info_char(unsigned char byte) { __console_tx_char(BIOS_INFO, byte); } +static void print_info_hex8(unsigned char value) { __console_tx_hex8(BIOS_INFO, value); } +static void print_info_hex32(unsigned int value) { __console_tx_hex32(BIOS_INFO, value); } +static void print_info(const char *str) { __console_tx_string(BIOS_INFO, str); } + +static void print_debug_char(unsigned char byte) { __console_tx_char(BIOS_DEBUG, byte); } +static void print_debug_hex8(unsigned char value) { __console_tx_hex8(BIOS_DEBUG, value); } +static void print_debug_hex32(unsigned int value) { __console_tx_hex32(BIOS_DEBUG, value); } +static void print_debug(const char *str) { __console_tx_string(BIOS_DEBUG, str); } + +static void print_spew_char(unsigned char byte) { __console_tx_char(BIOS_SPEW, byte); } +static void print_spew_hex8(unsigned char value) { __console_tx_hex8(BIOS_SPEW, value); } +static void print_spew_hex32(unsigned int value) { __console_tx_hex32(BIOS_SPEW, value); } +static void print_spew(const char *str) { __console_tx_string(BIOS_SPEW, str); } + +#define __STR(X) #X +#define STR(X) __STR(X) + +#ifndef LINUXBIOS_EXTRA_VERSION +#define LINUXBIOS_EXTRA_VERSION +#endif + +static void console_init(void) +{ + static const char console_test[] = + "\r\n\r\nLinuxBIOS-" + STR(LINUXBIOS_VERSION) + STR(LINUXBIOS_EXTRA_VERSION) + " " + STR(LINUXBIOS_BUILD) + " starting...\r\n"; + print_info(console_test); +} diff --git a/src/arch/i386/lib/console.inc b/src/arch/i386/lib/console.inc new file mode 100644 index 0000000000..3d6b01b3a2 --- /dev/null +++ b/src/arch/i386/lib/console.inc @@ -0,0 +1,527 @@ +#include <console/loglevel.h> + +jmp console0 + +#define __STR(X) #X +#define STR(X) __STR(X) + +#ifndef LINUXBIOS_EXTRA_VERSION +#define LINUXBIOS_EXTRA_VERSION +#endif + +console_test: + .ascii "\r\n\r\nLinuxBIOS-" + .ascii STR(LINUXBIOS_VERSION) + .ascii STR(LINUXBIOS_EXTRA_VERSION) + .ascii " " + .ascii STR(LINUXBIOS_BUILD) + .asciz " starting...\r\n" + +#undef STR + /* uses: ax, dx */ +#if CONFIG_CONSOLE_SERIAL8250 +#define __CONSOLE_INLINE_TX_AL TTYS0_TX_AL +#else +#define __CONSOLE_INLINE_TX_AL +#endif + + /* uses: esp, ax, dx */ +#define __CONSOLE_TX_CHAR(byte) \ + mov byte, %al ; \ + CALLSP(console_tx_al) + + /* uses: ax, dx */ +#define __CONSOLE_INLINE_TX_CHAR(byte) \ + mov byte, %al ; \ + __CONSOLE_INLINE_TX_AL + + /* uses: esp, ax, edx */ +#define __CONSOLE_TX_HEX8(byte) \ + mov byte, %al ; \ + CALLSP(console_tx_hex8) + + /* uses: byte, ax, dx */ +#define __CONSOLE_INLINE_TX_HEX8(byte) \ + movb byte, %dl ; \ + shll $16, %edx ; \ + shr $4, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + __CONSOLE_INLINE_TX_AL ; \ + shrl $16, %edx ; \ + movb %dl, %al ; \ + and $0x0f, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + __CONSOLE_INLINE_TX_AL + + /* uses: esp, eax, ebx, dx */ +#define __CONSOLE_TX_HEX32(lword) \ + mov lword, %eax ; \ + CALLSP(console_tx_hex32) + + /* uses: eax, lword, dx */ +#define __CONSOLE_INLINE_TX_HEX32(lword) \ + mov lword, %eax ; \ + shr $28, %eax ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + __CONSOLE_INLINE_TX_AL ; \ + ; \ + mov lword, %eax ; \ + shr $24, %eax ; \ + and $0x0f, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + __CONSOLE_INLINE_TX_AL ; \ + ; \ + mov lword, %eax ; \ + shr $20, %eax ; \ + and $0x0f, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + __CONSOLE_INLINE_TX_AL ; \ + ; \ + mov lword, %eax ; \ + shr $16, %eax ; \ + and $0x0f, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + __CONSOLE_INLINE_TX_AL ; \ + ; \ + mov lword, %eax ; \ + shr $12, %eax ; \ + and $0x0f, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + __CONSOLE_INLINE_TX_AL ; \ + ; \ + mov lword, %eax ; \ + shr $8, %eax ; \ + and $0x0f, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + __CONSOLE_INLINE_TX_AL ; \ + ; \ + mov lword, %eax ; \ + shr $4, %eax ; \ + and $0x0f, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + __CONSOLE_INLINE_TX_AL ; \ + ; \ + mov lword, %eax ; \ + and $0x0f, %al ; \ + add $'0', %al ; \ + cmp $'9', %al ; \ + jle 9f ; \ + add $39, %al ; \ +9: ; \ + __CONSOLE_INLINE_TX_AL + + + /* uses: esp, ebx, ax, dx */ +#define __CONSOLE_TX_STRING(string) \ + mov string, %ebx ; \ + CALLSP(console_tx_string) + + /* uses: ebx, ax, dx */ +#define __CONSOLE_INLINE_TX_STRING(string) \ + movl string, %ebx ; \ +10: movb (%ebx), %al ; \ + incl %ebx ; \ + testb %al, %al ; \ + jz 11f ; \ + __CONSOLE_INLINE_TX_AL ; \ + jmp 10b ; \ +11: + + +#define CONSOLE_EMERG_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte) +#define CONSOLE_EMERG_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte) +#define CONSOLE_EMERG_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte) +#define CONSOLE_EMERG_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte) +#define CONSOLE_EMERG_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword) +#define CONSOLE_EMERG_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword) +#define CONSOLE_EMERG_TX_STRING(string) __CONSOLE_TX_STRING(string) +#define CONSOLE_EMERG_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string) + +#define CONSOLE_ALERT_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte) +#define CONSOLE_ALERT_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte) +#define CONSOLE_ALERT_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte) +#define CONSOLE_ALERT_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte) +#define CONSOLE_ALERT_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword) +#define CONSOLE_ALERT_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword) +#define CONSOLE_ALERT_TX_STRING(string) __CONSOLE_TX_STRING(string) +#define CONSOLE_ALERT_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string) + +#define CONSOLE_CRIT_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte) +#define CONSOLE_CRIT_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte) +#define CONSOLE_CRIT_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte) +#define CONSOLE_CRIT_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte) +#define CONSOLE_CRIT_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword) +#define CONSOLE_CRIT_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword) +#define CONSOLE_CRIT_TX_STRING(string) __CONSOLE_TX_STRING(string) +#define CONSOLE_CRIT_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string) + +#define CONSOLE_ERR_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte) +#define CONSOLE_ERR_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte) +#define CONSOLE_ERR_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte) +#define CONSOLE_ERR_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte) +#define CONSOLE_ERR_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword) +#define CONSOLE_ERR_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword) +#define CONSOLE_ERR_TX_STRING(string) __CONSOLE_TX_STRING(string) +#define CONSOLE_ERR_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string) + +#define CONSOLE_WARNING_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte) +#define CONSOLE_WARNING_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte) +#define CONSOLE_WARNING_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte) +#define CONSOLE_WARNING_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte) +#define CONSOLE_WARNING_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword) +#define CONSOLE_WARNING_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword) +#define CONSOLE_WARNING_TX_STRING(string) __CONSOLE_TX_STRING(string) +#define CONSOLE_WARNING_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string) + +#define CONSOLE_NOTICE_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte) +#define CONSOLE_NOTICE_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte) +#define CONSOLE_NOTICE_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte) +#define CONSOLE_NOTICE_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte) +#define CONSOLE_NOTICE_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword) +#define CONSOLE_NOTICE_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword) +#define CONSOLE_NOTICE_TX_STRING(string) __CONSOLE_TX_STRING(string) +#define CONSOLE_NOTICE_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string) + +#define CONSOLE_INFO_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte) +#define CONSOLE_INFO_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte) +#define CONSOLE_INFO_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte) +#define CONSOLE_INFO_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte) +#define CONSOLE_INFO_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword) +#define CONSOLE_INFO_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword) +#define CONSOLE_INFO_TX_STRING(string) __CONSOLE_TX_STRING(string) +#define CONSOLE_INFO_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string) + +#define CONSOLE_DEBUG_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte) +#define CONSOLE_DEBUG_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte) +#define CONSOLE_DEBUG_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte) +#define CONSOLE_DEBUG_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte) +#define CONSOLE_DEBUG_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword) +#define CONSOLE_DEBUG_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword) +#define CONSOLE_DEBUG_TX_STRING(string) __CONSOLE_TX_STRING(string) +#define CONSOLE_DEBUG_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string) + +#define CONSOLE_SPEW_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte) +#define CONSOLE_SPEW_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte) +#define CONSOLE_SPEW_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte) +#define CONSOLE_SPEW_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte) +#define CONSOLE_SPEW_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword) +#define CONSOLE_SPEW_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword) +#define CONSOLE_SPEW_TX_STRING(string) __CONSOLE_TX_STRING(string) +#define CONSOLE_SPEW_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string) + +#if ASM_CONSOLE_LOGLEVEL <= BIOS_EMERG +#undef CONSOLE_EMERG_TX_CHAR +#undef CONSOLE_EMERG_INLINE_TX_CHAR +#undef CONSOLE_EMERG_TX_HEX8 +#undef CONSOLE_EMERG_INLINE_TX_HEX8 +#undef CONSOLE_EMERG_TX_HEX32 +#undef CONSOLE_EMERG_INLINE_TX_HEX32 +#undef CONSOLE_EMERG_TX_STRING +#undef CONSOLE_EMERG_INLINE_TX_STRING +#define CONSOLE_EMERG_TX_CHAR(byte) +#define CONSOLE_EMERG_INLINE_TX_CHAR(byte) +#define CONSOLE_EMERG_TX_HEX8(byte) +#define CONSOLE_EMERG_INLINE_TX_HEX8(byte) +#define CONSOLE_EMERG_TX_HEX32(lword) +#define CONSOLE_EMERG_INLINE_TX_HEX32(lword) +#define CONSOLE_EMERG_TX_STRING(string) +#define CONSOLE_EMERG_INLINE_TX_STRING(string) +#endif + + +#if ASM_CONSOLE_LOGLEVEL <= BIOS_ALERT +#undef CONSOLE_ALERT_TX_CHAR +#undef CONSOLE_ALERT_INLINE_TX_CHAR +#undef CONSOLE_ALERT_TX_HEX8 +#undef CONSOLE_ALERT_INLINE_TX_HEX8 +#undef CONSOLE_ALERT_TX_HEX32 +#undef CONSOLE_ALERT_INLINE_TX_HEX32 +#undef CONSOLE_ALERT_TX_STRING +#undef CONSOLE_ALERT_INLINE_TX_STRING +#define CONSOLE_ALERT_TX_CHAR(byte) +#define CONSOLE_ALERT_INLINE_TX_CHAR(byte) +#define CONSOLE_ALERT_TX_HEX8(byte) +#define CONSOLE_ALERT_INLINE_TX_HEX8(byte) +#define CONSOLE_ALERT_TX_HEX32(lword) +#define CONSOLE_ALERT_INLINE_TX_HEX32(lword) +#define CONSOLE_ALERT_TX_STRING(string) +#define CONSOLE_ALERT_INLINE_TX_STRING(string) +#endif + +#if ASM_CONSOLE_LOGLEVEL <= BIOS_CRIT +#undef CONSOLE_CRIT_TX_CHAR +#undef CONSOLE_CRIT_INLINE_TX_CHAR +#undef CONSOLE_CRIT_TX_HEX8 +#undef CONSOLE_CRIT_INLINE_TX_HEX8 +#undef CONSOLE_CRIT_TX_HEX32 +#undef CONSOLE_CRIT_INLINE_TX_HEX32 +#undef CONSOLE_CRIT_TX_STRING +#undef CONSOLE_CRIT_INLINE_TX_STRING +#define CONSOLE_CRIT_TX_CHAR(byte) +#define CONSOLE_CRIT_INLINE_TX_CHAR(byte) +#define CONSOLE_CRIT_TX_HEX8(byte) +#define CONSOLE_CRIT_INLINE_TX_HEX8(byte) +#define CONSOLE_CRIT_TX_HEX32(lword) +#define CONSOLE_CRIT_INLINE_TX_HEX32(lword) +#define CONSOLE_CRIT_TX_STRING(string) +#define CONSOLE_CRIT_INLINE_TX_STRING(string) +#endif + +#if ASM_CONSOLE_LOGLEVEL <= BIOS_ERR +#undef CONSOLE_ERR_TX_CHAR +#undef CONSOLE_ERR_INLINE_TX_CHAR +#undef CONSOLE_ERR_TX_HEX8 +#undef CONSOLE_ERR_INLINE_TX_HEX8 +#undef CONSOLE_ERR_TX_HEX32 +#undef CONSOLE_ERR_INLINE_TX_HEX32 +#undef CONSOLE_ERR_TX_STRING +#undef CONSOLE_ERR_INLINE_TX_STRING +#define CONSOLE_ERR_TX_CHAR(byte) +#define CONSOLE_ERR_INLINE_TX_CHAR(byte) +#define CONSOLE_ERR_TX_HEX8(byte) +#define CONSOLE_ERR_INLINE_TX_HEX8(byte) +#define CONSOLE_ERR_TX_HEX32(lword) +#define CONSOLE_ERR_INLINE_TX_HEX32(lword) +#define CONSOLE_ERR_TX_STRING(string) +#define CONSOLE_ERR_INLINE_TX_STRING(string) +#endif + +#if ASM_CONSOLE_LOGLEVEL <= BIOS_WARNING +#undef CONSOLE_WARNING_TX_CHAR +#undef CONSOLE_WARNING_INLINE_TX_CHAR +#undef CONSOLE_WARNING_TX_HEX8 +#undef CONSOLE_WARNING_INLINE_TX_HEX8 +#undef CONSOLE_WARNING_TX_HEX32 +#undef CONSOLE_WARNING_INLINE_TX_HEX32 +#undef CONSOLE_WARNING_TX_STRING +#undef CONSOLE_WARNING_INLINE_TX_STRING +#define CONSOLE_WARNING_TX_CHAR(byte) +#define CONSOLE_WARNING_INLINE_TX_CHAR(byte) +#define CONSOLE_WARNING_TX_HEX8(byte) +#define CONSOLE_WARNING_INLINE_TX_HEX8(byte) +#define CONSOLE_WARNING_TX_HEX32(lword) +#define CONSOLE_WARNING_INLINE_TX_HEX32(lword) +#define CONSOLE_WARNING_TX_STRING(string) +#define CONSOLE_WARNING_INLINE_TX_STRING(string) +#endif + +#if ASM_CONSOLE_LOGLEVEL <= BIOS_NOTICE +#undef CONSOLE_NOTICE_TX_CHAR +#undef CONSOLE_NOTICE_INLINE_TX_CHAR +#undef CONSOLE_NOTICE_TX_HEX8 +#undef CONSOLE_NOTICE_INLINE_TX_HEX8 +#undef CONSOLE_NOTICE_TX_HEX32 +#undef CONSOLE_NOTICE_INLINE_TX_HEX32 +#undef CONSOLE_NOTICE_TX_STRING +#undef CONSOLE_NOTICE_INLINE_TX_STRING +#define CONSOLE_NOTICE_TX_CHAR(byte) +#define CONSOLE_NOTICE_INLINE_TX_CHAR(byte) +#define CONSOLE_NOTICE_TX_HEX8(byte) +#define CONSOLE_NOTICE_INLINE_TX_HEX8(byte) +#define CONSOLE_NOTICE_TX_HEX32(lword) +#define CONSOLE_NOTICE_INLINE_TX_HEX32(lword) +#define CONSOLE_NOTICE_TX_STRING(string) +#define CONSOLE_NOTICE_INLINE_TX_STRING(string) +#endif + +#if ASM_CONSOLE_LOGLEVEL <= BIOS_INFO +#undef CONSOLE_INFO_TX_CHAR +#undef CONSOLE_INFO_INLINE_TX_CHAR +#undef CONSOLE_INFO_TX_HEX8 +#undef CONSOLE_INFO_INLINE_TX_HEX8 +#undef CONSOLE_INFO_TX_HEX32 +#undef CONSOLE_INFO_INLINE_TX_HEX32 +#undef CONSOLE_INFO_TX_STRING +#undef CONSOLE_INFO_INLINE_TX_STRING +#define CONSOLE_INFO_TX_CHAR(byte) +#define CONSOLE_INFO_INLINE_TX_CHAR(byte) +#define CONSOLE_INFO_TX_HEX8(byte) +#define CONSOLE_INFO_INLINE_TX_HEX8(byte) +#define CONSOLE_INFO_TX_HEX32(lword) +#define CONSOLE_INFO_INLINE_TX_HEX32(lword) +#define CONSOLE_INFO_TX_STRING(string) +#define CONSOLE_INFO_INLINE_TX_STRING(string) +#endif + +#if ASM_CONSOLE_LOGLEVEL <= BIOS_DEBUG +#undef CONSOLE_DEBUG_TX_CHAR +#undef CONSOLE_DEBUG_INLINE_TX_CHAR +#undef CONSOLE_DEBUG_TX_HEX8 +#undef CONSOLE_DEBUG_INLINE_TX_HEX8 +#undef CONSOLE_DEBUG_TX_HEX32 +#undef CONSOLE_DEBUG_INLINE_TX_HEX32 +#undef CONSOLE_DEBUG_TX_STRING +#undef CONSOLE_DEBUG_INLINE_TX_STRING +#define CONSOLE_DEBUG_TX_CHAR(byte) +#define CONSOLE_DEBUG_INLINE_TX_CHAR(byte) +#define CONSOLE_DEBUG_TX_HEX8(byte) +#define CONSOLE_DEBUG_INLINE_TX_HEX8(byte) +#define CONSOLE_DEBUG_TX_HEX32(lword) +#define CONSOLE_DEBUG_INLINE_TX_HEX32(lword) +#define CONSOLE_DEBUG_TX_STRING(string) +#define CONSOLE_DEBUG_INLINE_TX_STRING(string) +#endif + +#if ASM_CONSOLE_LOGLEVEL <= BIOS_SPEW +#undef CONSOLE_SPEW_TX_CHAR +#undef CONSOLE_SPEW_INLINE_TX_CHAR +#undef CONSOLE_SPEW_TX_HEX8 +#undef CONSOLE_SPEW_INLINE_TX_HEX8 +#undef CONSOLE_SPEW_TX_HEX32 +#undef CONSOLE_SPEW_INLINE_TX_HEX32 +#undef CONSOLE_SPEW_TX_STRING +#undef CONSOLE_SPEW_INLINE_TX_STRING +#define CONSOLE_SPEW_TX_CHAR(byte) +#define CONSOLE_SPEW_INLINE_TX_CHAR(byte) +#define CONSOLE_SPEW_TX_HEX8(byte) +#define CONSOLE_SPEW_INLINE_TX_HEX8(byte) +#define CONSOLE_SPEW_TX_HEX32(lword) +#define CONSOLE_SPEW_INLINE_TX_HEX32(lword) +#define CONSOLE_SPEW_TX_STRING(string) +#define CONSOLE_SPEW_INLINE_TX_STRING(string) +#endif + + + /* uses: esp, ax, dx */ +console_tx_al: + __CONSOLE_INLINE_TX_AL + RETSP + + /* uses: esp, ax, edx */ +console_tx_hex8: + __CONSOLE_INLINE_TX_HEX8(%al) + RETSP + + + /* uses: esp, ebx, eax, dx */ +console_tx_hex32: + mov %eax, %ebx + shr $28, %eax + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + __CONSOLE_INLINE_TX_AL + + mov %ebx, %eax + shr $24, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + __CONSOLE_INLINE_TX_AL + + mov %ebx, %eax + shr $20, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + __CONSOLE_INLINE_TX_AL + + mov %ebx, %eax + shr $16, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + __CONSOLE_INLINE_TX_AL + + mov %ebx, %eax + shr $12, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + __CONSOLE_INLINE_TX_AL + + mov %ebx, %eax + shr $8, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + __CONSOLE_INLINE_TX_AL + + mov %ebx, %eax + shr $4, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + __CONSOLE_INLINE_TX_AL + + mov %ebx, %eax + and $0x0f, %al + add $'0', %al + cmp $'9', %al + jle 9f + add $39, %al +9: + __CONSOLE_INLINE_TX_AL + RETSP + + /* Uses esp, ebx, ax, dx */ + +console_tx_string: + mov (%ebx), %al + inc %ebx + cmp $0, %al + jne 9f + RETSP +9: + __CONSOLE_INLINE_TX_AL + jmp console_tx_string + +console0: + CONSOLE_INFO_TX_STRING($console_test) + diff --git a/src/arch/i386/lib/cpu.c b/src/arch/i386/lib/cpu.c new file mode 100644 index 0000000000..3e27e7acdc --- /dev/null +++ b/src/arch/i386/lib/cpu.c @@ -0,0 +1,139 @@ +#include <console/console.h> +#include <cpu/cpu.h> +#include <mem.h> +#include <arch/io.h> +#include <string.h> +#include <cpu/cpufixup.h> +#include <smp/start_stop.h> +#include <cpu/cpufixup.h> +#include <cpu/p6/mtrr.h> +#include <cpu/p6/msr.h> +#include <cpu/p6/apic.h> +#include <cpu/p5/cpuid.h> +#if 0 +#include <cpu/l2_cache.h> +#endif + +#if CONFIG_SMP || CONFIG_IOAPIC +#define APIC 1 +#endif + +static void cache_on(struct mem_range *mem) +{ + post_code(0x60); + printk_info("Enabling cache..."); + + + /* we need an #ifdef i586 here at some point ... */ + __asm__ __volatile__("mov %cr0, %eax\n\t" + "and $0x9fffffff,%eax\n\t" + "mov %eax, %cr0\n\t"); + /* turns out cache isn't really on until you set MTRR registers on + * 686 and later. + * NOTHING FANCY. Linux does a much better job anyway. + * so absolute minimum needed to get it going. + */ + /* OK, linux it turns out does nothing. We have to do it ... */ +#if defined(i686) + // totalram here is in linux sizing, i.e. units of KB. + // set_mtrr is responsible for getting it into the right units! + setup_mtrrs(mem); +#endif + + post_code(0x6A); + printk_info("done.\n"); +} + +static void interrupts_on() +{ + /* this is so interrupts work. This is very limited scope -- + * linux will do better later, we hope ... + */ + /* this is the first way we learned to do it. It fails on real SMP + * stuff. So we have to do things differently ... + * see the Intel mp1.4 spec, page A-3 + */ + +#if defined(APIC) + /* Only Pentium Pro and later have those MSR stuff */ + unsigned long low, high; + + printk_info("Setting up local apic..."); + + /* Enable the local apic */ + rdmsr(APIC_BASE_MSR, low, high); + low |= APIC_BASE_MSR_ENABLE; + low &= ~APIC_BASE_MSR_ADDR_MASK; + low |= APIC_DEFAULT_BASE; + wrmsr(APIC_BASE_MSR, low, high); + + + /* Put the local apic in virtual wire mode */ + apic_write_around(APIC_SPIV, + (apic_read_around(APIC_SPIV) & ~(APIC_VECTOR_MASK)) + | APIC_SPIV_ENABLE); + apic_write_around(APIC_LVT0, + (apic_read_around(APIC_LVT0) & + ~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER | + APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY | + APIC_SEND_PENDING |APIC_LVT_RESERVED_1 | + APIC_DELIVERY_MODE_MASK)) + | (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING | + APIC_DELIVERY_MODE_EXTINT) + ); + apic_write_around(APIC_LVT1, + (apic_read_around(APIC_LVT1) & + ~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER | + APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY | + APIC_SEND_PENDING |APIC_LVT_RESERVED_1 | + APIC_DELIVERY_MODE_MASK)) + | (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING | + APIC_DELIVERY_MODE_NMI) + ); +#else /* APIC */ +#ifdef i686 + /* Only Pentium Pro and later have those MSR stuff */ + unsigned long low, high; + + printk_info("Disabling local apic..."); + + rdmsr(APIC_BASE_MSR, low, high); + low &= ~APIC_BASE_MSR_ENABLE; + wrmsr(APIC_BASE_MSR, low, high); +#endif /* i686 */ +#endif /* APIC */ + printk_info("done.\n"); + post_code(0x9b); +} + +unsigned long cpu_initialize(struct mem_range *mem) +{ + /* Because we busy wait at the printk spinlock. + * It is important to keep the number of printed messages + * from secondary cpus to a minimum, when debugging is + * disabled. + */ + unsigned long processor_id = this_processors_id(); + printk_notice("Initializing CPU #%d\n", processor_id); + + /* some cpus need a fixup done. This is the hook for doing that. */ + cpufixup(mem); + + /* Turn on caching if we haven't already */ + cache_on(mem); + + display_cpuid(); + mtrr_check(); + +#if 0 + /* now that everything is really up, enable the l2 cache if desired. + * The enable can wait until this point, because linuxbios and it's + * data areas are tiny, easily fitting into the L1 cache. + */ + configure_l2_cache(); +#endif + interrupts_on(); + printk_info("CPU #%d Initialized\n", processor_id); + return processor_id; +} + diff --git a/src/arch/i386/lib/cpu_reset.inc b/src/arch/i386/lib/cpu_reset.inc new file mode 100644 index 0000000000..c7c05e2198 --- /dev/null +++ b/src/arch/i386/lib/cpu_reset.inc @@ -0,0 +1,9 @@ +jmp cpu_reset_out + +__cpu_reset: + movl $0xffffffff, %ebp + jmp __main + +cpu_reset_out: + + diff --git a/src/arch/i386/lib/failover.lds b/src/arch/i386/lib/failover.lds new file mode 100644 index 0000000000..c9cf7298f8 --- /dev/null +++ b/src/arch/i386/lib/failover.lds @@ -0,0 +1 @@ + __normal_image = (ZKERNEL_START & 0xfffffff0) - 8; diff --git a/src/arch/i386/lib/id.inc b/src/arch/i386/lib/id.inc new file mode 100644 index 0000000000..f28e23a2e8 --- /dev/null +++ b/src/arch/i386/lib/id.inc @@ -0,0 +1,21 @@ + .section ".id", "a", @progbits + +#define __STR(X) #X +#define STR(X) __STR(X) + + .globl __id_start +__id_start: +vendor: + .asciz STR(MAINBOARD_VENDOR) +part: + .asciz STR(MAINBOARD_PART_NUMBER) +.long __id_end + 0x10 - vendor /* Reverse offset to the vendor id */ +.long __id_end + 0x10 - part /* Reverse offset to the part number */ +.long PAYLOAD_SIZE + ROM_IMAGE_SIZE /* Size of this romimage */ + .globl __id_end + +#undef __STR +#undef STR + +__id_end: +.previous diff --git a/src/arch/i386/lib/id.lds b/src/arch/i386/lib/id.lds new file mode 100644 index 0000000000..ccdf7008f7 --- /dev/null +++ b/src/arch/i386/lib/id.lds @@ -0,0 +1,6 @@ +SECTIONS { + . = (_ROMBASE + ROM_IMAGE_SIZE - 0x10) - (__id_end - __id_start); + .id (.): { + *(.id) + } +} diff --git a/src/arch/i386/lib/noop_failover.inc b/src/arch/i386/lib/noop_failover.inc new file mode 100644 index 0000000000..70c10b0d3e --- /dev/null +++ b/src/arch/i386/lib/noop_failover.inc @@ -0,0 +1,9 @@ +/* Step 1: Test for cpu reset + * That is, did I just boot or is this a later boot since power on. + * The result of this test in %al + * %al == 1 -- We are rebooting + * %al == 0 -- This is the initial boot + * + */ + testb %al, %al + jnz __cpu_reset diff --git a/src/arch/i386/lib/pci_ops.c b/src/arch/i386/lib/pci_ops.c new file mode 100644 index 0000000000..80921bf9da --- /dev/null +++ b/src/arch/i386/lib/pci_ops.c @@ -0,0 +1,281 @@ +#include <console/console.h> +#include <arch/io.h> +#include <arch/pciconf.h> +#include <pci.h> +#include <pci_ids.h> +#include <pci_ops.h> + +static const struct pci_ops *conf; +struct pci_ops { + int (*read_byte) (uint8_t bus, int devfn, int where, uint8_t * val); + int (*read_word) (uint8_t bus, int devfn, int where, uint16_t * val); + int (*read_dword) (uint8_t bus, int devfn, int where, uint32_t * val); + int (*write_byte) (uint8_t bus, int devfn, int where, uint8_t val); + int (*write_word) (uint8_t bus, int devfn, int where, uint16_t val); + int (*write_dword) (uint8_t bus, int devfn, int where, uint32_t val); +}; + +/* + * Direct access to PCI hardware... + */ + + +/* + * Functions for accessing PCI configuration space with type 1 accesses + */ + +#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3)) + +static int pci_conf1_read_config_byte(unsigned char bus, int devfn, int where, uint8_t * value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + *value = inb(0xCFC + (where & 3)); + return 0; +} + +static int pci_conf1_read_config_word(unsigned char bus, int devfn, int where, uint16_t * value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + *value = inw(0xCFC + (where & 2)); + return 0; +} + +static int pci_conf1_read_config_dword(unsigned char bus, int devfn, int where, uint32_t * value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + *value = inl(0xCFC); + return 0; +} + +static int pci_conf1_write_config_byte(unsigned char bus, int devfn, int where, uint8_t value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outb(value, 0xCFC + (where & 3)); + return 0; +} + +static int pci_conf1_write_config_word(unsigned char bus, int devfn, int where, uint16_t value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outw(value, 0xCFC + (where & 2)); + return 0; +} + +static int pci_conf1_write_config_dword(unsigned char bus, int devfn, int where, uint32_t value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outl(value, 0xCFC); + return 0; +} + +#undef CONFIG_CMD + +static const struct pci_ops pci_direct_conf1 = +{ + pci_conf1_read_config_byte, + pci_conf1_read_config_word, + pci_conf1_read_config_dword, + pci_conf1_write_config_byte, + pci_conf1_write_config_word, + pci_conf1_write_config_dword +}; + +/* + * Functions for accessing PCI configuration space with type 2 accesses + */ + +#define IOADDR(devfn, where) ((0xC000 | ((devfn & 0x78) << 5)) + where) +#define FUNC(devfn) (((devfn & 7) << 1) | 0xf0) +#define SET(bus,devfn) if (devfn & 0x80) return -1;outb(FUNC(devfn), 0xCF8); outb(bus, 0xCFA); + +static int pci_conf2_read_config_byte(unsigned char bus, int devfn, int where, uint8_t * value) +{ + SET(bus, devfn); + *value = inb(IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +static int pci_conf2_read_config_word(unsigned char bus, int devfn, int where, uint16_t * value) +{ + SET(bus, devfn); + *value = inw(IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +static int pci_conf2_read_config_dword(unsigned char bus, int devfn, int where, uint32_t * value) +{ + SET(bus, devfn); + *value = inl(IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +static int pci_conf2_write_config_byte(unsigned char bus, int devfn, int where, uint8_t value) +{ + SET(bus, devfn); + outb(value, IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +static int pci_conf2_write_config_word(unsigned char bus, int devfn, int where, uint16_t value) +{ + SET(bus, devfn); + outw(value, IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +static int pci_conf2_write_config_dword(unsigned char bus, int devfn, int where, uint32_t value) +{ + SET(bus, devfn); + outl(value, IOADDR(devfn, where)); + outb(0, 0xCF8); + return 0; +} + +#undef SET +#undef IOADDR +#undef FUNC + +static const struct pci_ops pci_direct_conf2 = +{ + pci_conf2_read_config_byte, + pci_conf2_read_config_word, + pci_conf2_read_config_dword, + pci_conf2_write_config_byte, + pci_conf2_write_config_word, + pci_conf2_write_config_dword +}; + +/* + * Before we decide to use direct hardware access mechanisms, we try to do some + * trivial checks to ensure it at least _seems_ to be working -- we just test + * whether bus 00 contains a host bridge (this is similar to checking + * techniques used in XFree86, but ours should be more reliable since we + * attempt to make use of direct access hints provided by the PCI BIOS). + * + * This should be close to trivial, but it isn't, because there are buggy + * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. + */ +static int pci_sanity_check(const struct pci_ops *o) +{ + uint16_t x; + uint8_t bus; + int devfn; +#define PCI_CLASS_BRIDGE_HOST 0x0600 +#define PCI_CLASS_DISPLAY_VGA 0x0300 +#define PCI_VENDOR_ID_COMPAQ 0x0e11 +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_VENDOR_ID_MOTOROLA 0x1057 + + for (bus = 0, devfn = 0; devfn < 0x100; devfn++) + if ((!o->read_word(bus, devfn, PCI_CLASS_DEVICE, &x) && + (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) || + (!o->read_word(bus, devfn, PCI_VENDOR_ID, &x) && + (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ || x == PCI_VENDOR_ID_MOTOROLA))) + return 1; + printk_err("PCI: Sanity check failed\n"); + return 0; +} + +static const struct pci_ops *pci_check_direct(void) +{ + unsigned int tmp; + + /* + * Check if configuration type 1 works. + */ + { + outb(0x01, 0xCFB); + tmp = inl(0xCF8); + outl(0x80000000, 0xCF8); + if (inl(0xCF8) == 0x80000000 && + pci_sanity_check(&pci_direct_conf1)) { + outl(tmp, 0xCF8); + printk_debug("PCI: Using configuration type 1\n"); + return &pci_direct_conf1; + } + outl(tmp, 0xCF8); + } + + /* + * Check if configuration type 2 works. + */ + { + outb(0x00, 0xCFB); + outb(0x00, 0xCF8); + outb(0x00, 0xCFA); + if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 && + pci_sanity_check(&pci_direct_conf2)) { + printk_debug("PCI: Using configuration type 2\n"); + return &pci_direct_conf2; + } + } + + printk_debug("pci_check_direct failed\n"); + + return 0; +} + +int pci_read_config_byte(struct device *dev, uint8_t where, uint8_t * val) +{ + int res; + res = conf->read_byte(dev->bus->secondary, dev->devfn, where, val); + printk_spew("Read config byte bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n", + dev->bus->secondary, dev->devfn, where, *val, res); + return res; + + +} + +int pci_read_config_word(struct device *dev, uint8_t where, uint16_t * val) +{ + int res; + res = conf->read_word(dev->bus->secondary, dev->devfn, where, val); + printk_spew( "Read config word bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n", + dev->bus->secondary, dev->devfn, where, *val, res); + return res; +} + +int pci_read_config_dword(struct device *dev, uint8_t where, uint32_t * val) +{ + int res; + res = conf->read_dword(dev->bus->secondary, dev->devfn, where, val); + printk_spew( "Read config dword bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n", + dev->bus->secondary, dev->devfn, where, *val, res); + return res; +} + +int pci_write_config_byte(struct device *dev, uint8_t where, uint8_t val) +{ + printk_spew( "Write config byte bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", + dev->bus->secondary, dev->devfn, where, val); + return conf->write_byte(dev->bus->secondary, dev->devfn, where, val); +} + +int pci_write_config_word(struct device *dev, uint8_t where, uint16_t val) +{ + printk_spew( "Write config word bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", + dev->bus->secondary, dev->devfn, where, val); + return conf->write_word(dev->bus->secondary, dev->devfn, where, val); +} + +int pci_write_config_dword(struct device *dev, uint8_t where, uint32_t val) +{ + printk_spew( "Write config dword bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n", + dev->bus->secondary, dev->devfn, where, val); + return conf->write_dword(dev->bus->secondary, dev->devfn, where, val); +} + +/** Set the method to be used for PCI, type I or type II + */ +void pci_set_method(void) +{ + conf = &pci_direct_conf1; + conf = pci_check_direct(); +} + + diff --git a/src/arch/i386/smp/mpspec.c b/src/arch/i386/smp/mpspec.c new file mode 100644 index 0000000000..3bb5fa1985 --- /dev/null +++ b/src/arch/i386/smp/mpspec.c @@ -0,0 +1,245 @@ +#include <console/console.h> +#include <cpu/cpu.h> +#include <smp/start_stop.h> +#include <arch/smp/mpspec.h> +#include <string.h> +#include <cpu/p5/cpuid.h> +#include <cpu/p6/apic.h> + +unsigned char smp_compute_checksum(void *v, int len) +{ + unsigned char *bytes; + unsigned char checksum; + int i; + bytes = v; + checksum = 0; + for(i = 0; i < len; i++) { + checksum -= bytes[i]; + } + return checksum; +} + +void *smp_write_floating_table(unsigned long addr) +{ + struct intel_mp_floating *mf; + void *v; + + /* 16 byte align the table address */ + addr += 15; + addr &= ~15; + v = (void *)addr; + + mf = v; + mf->mpf_signature[0] = '_'; + mf->mpf_signature[1] = 'M'; + mf->mpf_signature[2] = 'P'; + mf->mpf_signature[3] = '_'; + mf->mpf_physptr = (unsigned long)(((char *)v) + SMP_FLOATING_TABLE_LEN); + mf->mpf_length = 1; + mf->mpf_specification = 4; + mf->mpf_checksum = 0; + mf->mpf_feature1 = 0; + mf->mpf_feature2 = 0; + mf->mpf_feature3 = 0; + mf->mpf_feature4 = 0; + mf->mpf_feature5 = 0; + mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16); + return v; +} + +void *smp_next_mpc_entry(struct mp_config_table *mc) +{ + void *v; + v = (void *)(((char *)mc) + mc->mpc_length); + return v; +} +static void smp_add_mpc_entry(struct mp_config_table *mc, unsigned length) +{ + mc->mpc_length += length; + mc->mpc_entry_count++; +} + +void *smp_next_mpe_entry(struct mp_config_table *mc) +{ + void *v; + v = (void *)(((char *)mc) + mc->mpc_length + mc->mpe_length); + return v; +} +static void smp_add_mpe_entry(struct mp_config_table *mc, mpe_t mpe) +{ + mc->mpe_length += mpe->mpe_length; +} + +void smp_write_processor(struct mp_config_table *mc, + unsigned char apicid, unsigned char apicver, + unsigned char cpuflag, unsigned int cpufeature, + unsigned int featureflag) +{ + struct mpc_config_processor *mpc; + mpc = smp_next_mpc_entry(mc); + memset(mpc, '\0', sizeof(*mpc)); + mpc->mpc_type = MP_PROCESSOR; + mpc->mpc_apicid = apicid; + mpc->mpc_apicver = apicver; + mpc->mpc_cpuflag = cpuflag; + mpc->mpc_cpufeature = cpufeature; + mpc->mpc_featureflag = featureflag; + smp_add_mpc_entry(mc, sizeof(*mpc)); +} + +/* If we assume a symmetric processor configuration we can + * get all of the information we need to write the processor + * entry from the bootstrap processor. + * Plus I don't think linux really even cares. + * Having the proper apicid's in the table so the non-bootstrap + * processors can be woken up should be enough. + */ +void smp_write_processors(struct mp_config_table *mc, + unsigned long *processor_map) +{ + int i; + int processor_id; + unsigned apic_version; + unsigned cpu_features; + unsigned cpu_feature_flags; + int eax, ebx, ecx, edx; + processor_id = this_processors_id(); + apic_version = apic_read(APIC_LVR) & 0xff; + cpuid(1, &eax, &ebx, &ecx, &edx); + cpu_features = eax; + cpu_feature_flags = edx; + for(i = 0; i < MAX_CPUS; i++) { + unsigned long cpu_apicid = initial_apicid[i]; + unsigned long cpu_flag; + if(initial_apicid[i]==-1) + continue; + cpu_flag = MPC_CPU_ENABLED + if (processor_map[i] & CPU_BOOTPROCESSOR) { + cpu_flag |= MPC_CPU_BOOTPROCESSOR; + } + smp_write_processor(mc, cpu_apicid, apic_version, + cpu_flag, cpu_features, cpu_feature_flags + ); + + } +} + +void smp_write_bus(struct mp_config_table *mc, + unsigned char id, unsigned char *bustype) +{ + struct mpc_config_bus *mpc; + mpc = smp_next_mpc_entry(mc); + memset(mpc, '\0', sizeof(*mpc)); + mpc->mpc_type = MP_BUS; + mpc->mpc_busid = id; + memcpy(mpc->mpc_bustype, bustype, sizeof(mpc->mpc_bustype)); + smp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void smp_write_ioapic(struct mp_config_table *mc, + unsigned char id, unsigned char ver, + unsigned long apicaddr) +{ + struct mpc_config_ioapic *mpc; + mpc = smp_next_mpc_entry(mc); + memset(mpc, '\0', sizeof(*mpc)); + mpc->mpc_type = MP_IOAPIC; + mpc->mpc_apicid = id; + mpc->mpc_apicver = ver; + mpc->mpc_flags = MPC_APIC_USABLE; + mpc->mpc_apicaddr = apicaddr; + smp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void smp_write_intsrc(struct mp_config_table *mc, + unsigned char irqtype, unsigned short irqflag, + unsigned char srcbus, unsigned char srcbusirq, + unsigned char dstapic, unsigned char dstirq) +{ + struct mpc_config_intsrc *mpc; + mpc = smp_next_mpc_entry(mc); + memset(mpc, '\0', sizeof(*mpc)); + mpc->mpc_type = MP_INTSRC; + mpc->mpc_irqtype = irqtype; + mpc->mpc_irqflag = irqflag; + mpc->mpc_srcbus = srcbus; + mpc->mpc_srcbusirq = srcbusirq; + mpc->mpc_dstapic = dstapic; + mpc->mpc_dstirq = dstirq; + smp_add_mpc_entry(mc, sizeof(*mpc)); +#if CONFIG_DEBUG_MPTABLE == 1 + printk_info("add intsrc srcbus 0x%x srcbusirq 0x%x, dstapic 0x%x, dstirq 0x%x\n", + srcbus, srcbusirq, dstapic, dstirq); + hexdump(__FUNCTION__, mpc, sizeof(*mpc)); +#endif +} + + +void smp_write_lintsrc(struct mp_config_table *mc, + unsigned char irqtype, unsigned short irqflag, + unsigned char srcbusid, unsigned char srcbusirq, + unsigned char destapic, unsigned char destapiclint) +{ + struct mpc_config_lintsrc *mpc; + mpc = smp_next_mpc_entry(mc); + memset(mpc, '\0', sizeof(*mpc)); + mpc->mpc_type = MP_LINTSRC; + mpc->mpc_irqtype = irqtype; + mpc->mpc_irqflag = irqflag; + mpc->mpc_srcbusid = srcbusid; + mpc->mpc_srcbusirq = srcbusirq; + mpc->mpc_destapic = destapic; + mpc->mpc_destapiclint = destapiclint; + smp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void smp_write_address_space(struct mp_config_table *mc, + unsigned char busid, unsigned char address_type, + unsigned int address_base_low, unsigned int address_base_high, + unsigned int address_length_low, unsigned int address_length_high) +{ + struct mp_exten_system_address_space *mpe; + mpe = smp_next_mpe_entry(mc); + memset(mpe, '\0', sizeof(*mpe)); + mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_address_type = address_type; + mpe->mpe_address_base_low = address_base_low; + mpe->mpe_address_base_high = address_base_high; + mpe->mpe_address_length_low = address_length_low; + mpe->mpe_address_length_high = address_length_high; + smp_add_mpe_entry(mc, (mpe_t)mpe); +} + + +void smp_write_bus_hierarchy(struct mp_config_table *mc, + unsigned char busid, unsigned char bus_info, + unsigned char parent_busid) +{ + struct mp_exten_bus_hierarchy *mpe; + mpe = smp_next_mpe_entry(mc); + memset(mpe, '\0', sizeof(*mpe)); + mpe->mpe_type = MPE_BUS_HIERARCHY; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_bus_info = bus_info; + mpe->mpe_parent_busid = parent_busid; + smp_add_mpe_entry(mc, (mpe_t)mpe); +} + +void smp_write_compatibility_address_space(struct mp_config_table *mc, + unsigned char busid, unsigned char address_modifier, + unsigned int range_list) +{ + struct mp_exten_compatibility_address_space *mpe; + mpe = smp_next_mpe_entry(mc); + memset(mpe, '\0', sizeof(*mpe)); + mpe->mpe_type = MPE_COMPATIBILITY_ADDRESS_SPACE; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_address_modifier = address_modifier; + mpe->mpe_range_list = range_list; + smp_add_mpe_entry(mc, (mpe_t)mpe); +} + diff --git a/src/boot/elfboot.c b/src/boot/elfboot.c new file mode 100644 index 0000000000..da0e909ced --- /dev/null +++ b/src/boot/elfboot.c @@ -0,0 +1,663 @@ +#include <console/console.h> +#include <part/fallback_boot.h> +#include <boot/elf.h> +#include <boot/elf_boot.h> +#include <boot/linuxbios_tables.h> +#include <ip_checksum.h> +#include <stream/read_bytes.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +/* Maximum physical address we can use for the linuxBIOS bounce buffer. + */ +#ifndef MAX_ADDR +#define MAX_ADDR -1UL +#endif + +extern unsigned char _ram_seg; +extern unsigned char _eram_seg; + +struct segment { + struct segment *next; + struct segment *prev; + struct segment *phdr_next; + struct segment *phdr_prev; + unsigned long s_addr; + unsigned long s_memsz; + unsigned long s_offset; + unsigned long s_filesz; +}; + +struct verify_callback { + struct verify_callback *next; + int (*callback)(struct verify_callback *vcb, + Elf_ehdr *ehdr, Elf_phdr *phdr, struct segment *head); + unsigned long desc_offset; + unsigned long desc_addr; +}; + +struct ip_checksum_vcb { + struct verify_callback data; + unsigned short ip_checksum; +}; + +int verify_ip_checksum( + struct verify_callback *vcb, + Elf_ehdr *ehdr, Elf_phdr *phdr, struct segment *head) +{ + struct ip_checksum_vcb *cb; + struct segment *ptr; + unsigned long bytes; + unsigned long checksum; + unsigned char buff[2], *n_desc; + cb = (struct ip_checksum_vcb *)vcb; + /* zero the checksum so it's value won't + * get in the way of verifying the checksum. + */ + n_desc = 0; + if (vcb->desc_addr) { + n_desc = (unsigned char *)(vcb->desc_addr); + memcpy(buff, n_desc, 2); + memset(n_desc, 0, 2); + } + bytes = 0; + checksum = compute_ip_checksum(ehdr, sizeof(*ehdr)); + bytes += sizeof(*ehdr); + checksum = add_ip_checksums(bytes, checksum, + compute_ip_checksum(phdr, ehdr->e_phnum*sizeof(*phdr))); + bytes += ehdr->e_phnum*sizeof(*phdr); + for(ptr = head->phdr_next; ptr != head; ptr = ptr->phdr_next) { + checksum = add_ip_checksums(bytes, checksum, + compute_ip_checksum((void *)ptr->s_addr, ptr->s_memsz)); + bytes += ptr->s_memsz; + } + if (n_desc != 0) { + memcpy(n_desc, buff, 2); + } + if (checksum != cb->ip_checksum) { + printk_err("Image checksum: %04x != computed checksum: %04x\n", + cb->ip_checksum, checksum); + } + return checksum == cb->ip_checksum; +} + +/* The problem: + * Static executables all want to share the same addresses + * in memory because only a few addresses are reliably present on + * a machine, and implementing general relocation is hard. + * + * The solution: + * - Allocate a buffer twice the size of the linuxBIOS image. + * - Anything that would overwrite linuxBIOS copy into the lower half of + * the buffer. + * - After loading an ELF image copy linuxBIOS to the upper half of the + * buffer. + * - Then jump to the loaded image. + * + * Benefits: + * - Nearly arbitrary standalone executables can be loaded. + * - LinuxBIOS is preserved, so it can be returned to. + * - The implementation is still relatively simple, + * and much simpler then the general case implemented in kexec. + * + */ + +static unsigned long get_bounce_buffer(struct lb_memory *mem) +{ + unsigned long lb_size; + unsigned long mem_entries; + unsigned long buffer; + int i; + lb_size = (unsigned long)(&_eram_seg - &_ram_seg); + /* Double linuxBIOS size so I have somewhere to place a copy to return to */ + lb_size = lb_size + lb_size; + mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + buffer = 0; + for(i = 0; i < mem_entries; i++) { + unsigned long mstart, mend; + unsigned long msize; + unsigned long tbuffer; + if (mem->map[i].type != LB_MEM_RAM) + continue; + if (mem->map[i].start > MAX_ADDR) + continue; + if (mem->map[i].size < lb_size) + continue; + mstart = mem->map[i].start; + msize = MAX_ADDR - mstart +1; + if (msize > mem->map[i].size) + msize = mem->map[i].size; + mend = mstart + msize; + tbuffer = mend - lb_size; + if (tbuffer < buffer) + continue; + buffer = tbuffer; + } + return buffer; +} + + +static struct verify_callback *process_elf_notes( + unsigned char *header, + unsigned long offset, unsigned long length) +{ + struct verify_callback *cb_chain; + unsigned char *note, *end; + char *program, *version; + + cb_chain = 0; + note = header + offset; + end = note + length; + program = version = 0; + while(note < end) { + Elf_Nhdr *hdr; + unsigned char *n_name, *n_desc, *next; + hdr = (Elf_Nhdr *)note; + n_name = note + sizeof(*hdr); + n_desc = n_name + ((hdr->n_namesz + 3) & ~3); + next = n_desc + ((hdr->n_descsz + 3) & ~3); + if (next > end) { + break; + } + if ((hdr->n_namesz == sizeof(ELF_NOTE_BOOT)) && + (memcmp(n_name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT)) == 0)) { + switch(hdr->n_type) { + case EIN_PROGRAM_NAME: + if (n_desc[hdr->n_descsz -1] == 0) { + program = n_desc; + } + break; + case EIN_PROGRAM_VERSION: + if (n_desc[hdr->n_descsz -1] == 0) { + version = n_desc; + } + break; + case EIN_PROGRAM_CHECKSUM: + { + struct ip_checksum_vcb *cb; + cb = malloc(sizeof(*cb)); + cb->ip_checksum = *((uint16_t *)n_desc); + cb->data.callback = verify_ip_checksum; + cb->data.next = cb_chain; + cb->data.desc_offset = n_desc - header; + cb_chain = &cb->data; + break; + } + } + } + printk_spew("n_type: %08x n_name(%d): %-*.*s n_desc(%d): %-*.*s\n", + hdr->n_type, + hdr->n_namesz, hdr->n_namesz, hdr->n_namesz, n_name, + hdr->n_descsz,hdr->n_descsz, hdr->n_descsz, n_desc); + note = next; + } + if (program && version) { + printk_info("Loading %s version: %s\n", + program, version); + } + return cb_chain; +} + +static int valid_area(struct lb_memory *mem, unsigned long buffer, + unsigned long start, unsigned long len) +{ + /* Check through all of the memory segments and ensure + * the segment that was passed in is completely contained + * in RAM. + */ + int i; + unsigned long end = start + len; + unsigned long mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + + /* See if I conflict with the bounce buffer */ + if (end >= buffer) { + return 0; + } + + /* Walk through the table of valid memory ranges and see if I + * have a match. + */ + for(i = 0; i < mem_entries; i++) { + uint64_t mstart, mend; + uint32_t mtype; + mtype = mem->map[i].type; + mstart = mem->map[i].start; + mend = mstart + mem->map[i].size; + if ((mtype == LB_MEM_RAM) && (start < mend) && (end > mstart)) { + break; + } + } + if (i == mem_entries) { + printk_err("No matching ram area found for range:\n"); + printk_err(" [0x%016lx, 0x%016lx)\n", start, end); + printk_err("Ram areas\n"); + for(i = 0; i < mem_entries; i++) { + uint64_t mstart, mend; + uint32_t mtype; + mtype = mem->map[i].type; + mstart = mem->map[i].start; + mend = mstart + mem->map[i].size; + printk_err(" [0x%016lx, 0x%016lx) %s\n", + (unsigned long)mstart, + (unsigned long)mend, + (mtype == LB_MEM_RAM)?"RAM":"Reserved"); + + } + return 0; + } + return 1; +} + +static void relocate_segment(unsigned long buffer, struct segment *seg) +{ + /* Modify all segments that want to load onto linuxBIOS + * to load onto the bounce buffer instead. + */ + unsigned long lb_start = (unsigned long)&_ram_seg; + unsigned long lb_end = (unsigned long)&_eram_seg; + unsigned long start, middle, end; + + printk_spew("lb: [0x%016lx, 0x%016lx)\n", + lb_start, lb_end); + + start = seg->s_addr; + middle = start + seg->s_filesz; + end = start + seg->s_memsz; + /* I don't conflict with linuxBIOS so get out of here */ + if ((end <= lb_start) || (start >= lb_end)) + return; + + printk_spew("segment: [0x%016lx, 0x%016lx, 0x%016lx)\n", + start, middle, end); + + /* Slice off a piece at the beginning + * that doesn't conflict with linuxBIOS. + */ + if (start < lb_start) { + struct segment *new; + unsigned long len = lb_start - start; + new = malloc(sizeof(*new)); + *new = *seg; + new->s_memsz = len; + seg->s_memsz -= len; + seg->s_addr += len; + seg->s_offset += len; + if (seg->s_filesz > len) { + new->s_filesz = len; + seg->s_filesz -= len; + } else { + seg->s_filesz = 0; + } + + /* Order by stream offset */ + new->next = seg; + new->prev = seg->prev; + seg->prev->next = new; + seg->prev = new; + /* Order by original program header order */ + new->phdr_next = seg; + new->phdr_prev = seg->phdr_prev; + seg->phdr_prev->phdr_next = new; + seg->phdr_prev = new; + + /* compute the new value of start */ + start = seg->s_addr; + + printk_spew(" early: [0x%016lx, 0x%016lx, 0x%016lx)\n", + new->s_addr, + new->s_addr + new->s_filesz, + new->s_addr + new->s_memsz); + } + + /* Slice off a piece at the end + * that doesn't conflict with linuxBIOS + */ + if (end > lb_end) { + unsigned long len = lb_end - start; + struct segment *new; + new = malloc(sizeof(*new)); + *new = *seg; + seg->s_memsz = len; + new->s_memsz -= len; + new->s_addr += len; + new->s_offset += len; + if (seg->s_filesz > len) { + seg->s_filesz = len; + new->s_filesz -= len; + } else { + new->s_filesz = 0; + } + /* Order by stream offset */ + new->next = seg->next; + new->prev = seg; + seg->next->prev = new; + seg->next = new; + /* Order by original program header order */ + new->phdr_next = seg->phdr_next; + new->phdr_prev = seg; + seg->phdr_next->phdr_prev = new; + seg->phdr_next = new; + + /* compute the new value of end */ + end = start + len; + + printk_spew(" late: [0x%016lx, 0x%016lx, 0x%016lx)\n", + new->s_addr, + new->s_addr + new->s_filesz, + new->s_addr + new->s_memsz); + + } + /* Now retarget this segment onto the bounce buffer */ + seg->s_addr = buffer + (seg->s_addr - lb_start); + + printk_spew(" bounce: [0x%016lx, 0x%016lx, 0x%016lx)\n", + seg->s_addr, + seg->s_addr + seg->s_filesz, + seg->s_addr + seg->s_memsz); +} + + +static int build_elf_segment_list( + struct segment *head, + unsigned long bounce_buffer, struct lb_memory *mem, + Elf_phdr *phdr, int headers) +{ + struct segment *ptr; + int i; + memset(head, 0, sizeof(*head)); + head->next = head->prev = head; + for(i = 0; i < headers; i++) { + struct segment *new; + /* Ignore data that I don't need to handle */ + if (phdr[i].p_type != PT_LOAD) { + printk_debug("Dropping non PT_LOAD segment\n"); + continue; + } + if (phdr[i].p_memsz == 0) { + printk_debug("Dropping empty segment\n"); + continue; + } + new = malloc(sizeof(*new)); + new->s_addr = phdr[i].p_paddr; + new->s_memsz = phdr[i].p_memsz; + new->s_offset = phdr[i].p_offset; + new->s_filesz = phdr[i].p_filesz; + printk_debug("New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n", + new->s_addr, new->s_memsz, new->s_offset, new->s_filesz); + /* Clean up the values */ + if (new->s_filesz > new->s_memsz) { + new->s_filesz = new->s_memsz; + } + printk_debug("(cleaned up) New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n", + new->s_addr, new->s_memsz, new->s_offset, new->s_filesz); + for(ptr = head->next; ptr != head; ptr = ptr->next) { + if (new->s_offset < ptr->s_offset) + break; + } + /* Order by stream offset */ + new->next = ptr; + new->prev = ptr->prev; + ptr->prev->next = new; + ptr->prev = new; + /* Order by original program header order */ + new->phdr_next = head; + new->phdr_prev = head->phdr_prev; + head->phdr_prev->phdr_next = new; + head->phdr_prev = new; + + /* Verify the memory addresses in the segment are valid */ + if (!valid_area(mem, bounce_buffer, new->s_addr, new->s_memsz)) + goto out; + + /* Modify the segment to load onto the bounce_buffer if necessary. + */ + relocate_segment(bounce_buffer, new); + } + return 1; + out: + return 0; +} + +static int load_elf_segments( + struct segment *head, unsigned char *header, unsigned long header_size) +{ + unsigned long offset; + struct segment *ptr; + + offset = 0; + for(ptr = head->next; ptr != head; ptr = ptr->next) { + unsigned long start_offset; + unsigned long skip_bytes, read_bytes; + unsigned char *dest, *middle, *end; + byte_offset_t result; + printk_debug("Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n", + ptr->s_addr, ptr->s_memsz, ptr->s_filesz); + + /* Compute the boundaries of the segment */ + dest = (unsigned char *)(ptr->s_addr); + end = dest + ptr->s_memsz; + middle = dest + ptr->s_filesz; + start_offset = ptr->s_offset; + + printk_spew("[ 0x%016lx, %016lx, 0x%016lx) <- %016lx\n", + (unsigned long)dest, + (unsigned long)middle, + (unsigned long)end, + (unsigned long)start_offset); + + /* Skip intial buffer unused bytes */ + if (offset < header_size) { + if (start_offset < header_size) { + offset = start_offset; + } else { + offset = header_size; + } + } + + /* Skip the unused bytes */ + skip_bytes = start_offset - offset; + if (skip_bytes && + ((result = stream_skip(skip_bytes)) != skip_bytes)) { + printk_err("ERROR: Skip of %ld bytes skiped %ld bytes\n", + skip_bytes, result); + goto out; + } + offset = start_offset; + + /* Copy data from the initial buffer */ + if (offset < header_size) { + size_t len; + if ((ptr->s_filesz + start_offset) > header_size) { + len = header_size - start_offset; + } + else { + len = ptr->s_filesz; + } + memcpy(dest, &header[start_offset], len); + dest += len; + } + + /* Read the segment into memory */ + read_bytes = middle - dest; + if (read_bytes && + ((result = stream_read(dest, read_bytes)) != read_bytes)) { + printk_err("ERROR: Read of %ld bytes read %ld bytes...\n", + read_bytes, result); + goto out; + } + offset += ptr->s_filesz; + + /* Zero the extra bytes between middle & end */ + if (middle < end) { + printk_debug("Clearing Segment: addr: 0x%016lx memsz: 0x%016lx\n", + (unsigned long)middle, end - middle); + + /* Zero the extra bytes */ + memset(middle, 0, end - middle); + } + } + return 1; + out: + return 0; +} + +static int verify_loaded_image( + struct verify_callback *vcb, + Elf_ehdr *ehdr, Elf_phdr *phdr, + struct segment *head + ) +{ + struct segment *ptr; + int ok; + ok = 1; + for(; ok && vcb ; vcb = vcb->next) { + /* Find where the note is loaded */ + /* The whole note must be loaded intact + * so an address of 0 for the descriptor is impossible + */ + vcb->desc_addr = 0; + for(ptr = head->next; ptr != head; ptr = ptr->next) { + unsigned long desc_addr; + desc_addr = ptr->s_addr + vcb->desc_offset - ptr->s_offset; + if ((desc_addr >= ptr->s_addr) && + (desc_addr < (ptr->s_addr + ptr->s_filesz))) { + vcb->desc_addr = desc_addr; + } + } + ok = vcb->callback(vcb, ehdr, phdr, head); + } + return ok; +} + +int elfload(struct lb_memory *mem, + unsigned char *header, unsigned long header_size) +{ + Elf_ehdr *ehdr; + Elf_phdr *phdr; + void *entry; + struct segment head; + struct verify_callback *cb_chain; + unsigned long bounce_buffer; + + /* Find a bounce buffer so I can load to linuxBIOS's current location */ + bounce_buffer = get_bounce_buffer(mem); + if (!bounce_buffer) { + printk_err("Could not find a bounce buffer...\n"); + goto out; + } + + ehdr = (Elf_ehdr *)header; + entry = (void *)(ehdr->e_entry); + phdr = (Elf_phdr *)(&header[ehdr->e_phoff]); + + /* Digest elf note information... */ + cb_chain = 0; + if ((phdr[0].p_type == PT_NOTE) && + ((phdr[0].p_offset + phdr[0].p_filesz) < header_size)) { + cb_chain = process_elf_notes(header, + phdr[0].p_offset, phdr[0].p_filesz); + } + + /* Preprocess the elf segments */ + if (!build_elf_segment_list(&head, + bounce_buffer, mem, phdr, ehdr->e_phnum)) + goto out; + + /* Load the segments */ + if (!load_elf_segments(&head, header, header_size)) + goto out; + + printk_spew("Loaded segments\n"); + /* Verify the loaded image */ + if (!verify_loaded_image(cb_chain, ehdr, phdr, &head)) + goto out; + + printk_spew("verified segments\n"); + /* Shutdown the stream device */ + stream_fini(); + + printk_spew("closed down stream\n"); + /* Reset to booting from this image as late as possible */ + boot_successful(); + + printk_debug("Jumping to boot code at 0x%x\n", entry); + post_code(0xfe); + + /* Jump to kernel */ + jmp_to_elf_entry(entry, bounce_buffer); + return 1; + + out: + return 0; +} + +int elfboot(struct lb_memory *mem) +{ + Elf_ehdr *ehdr; + static unsigned char header[ELF_HEAD_SIZE]; + int header_offset; + int i, result; + + result = 0; + printk_info("\n"); + printk_info("Welcome to %s, the open sourced starter.\n", BOOTLOADER); + printk_info("January 2002, Eric Biederman.\n"); + printk_info("Version %s\n", BOOTLOADER_VERSION); + printk_info("\n"); + post_code(0xf8); + + if (stream_init() < 0) { + printk_err("Could not initialize driver...\n"); + goto out; + } + + /* Read in the initial ELF_HEAD_SIZE bytes */ + if (stream_read(header, ELF_HEAD_SIZE) != ELF_HEAD_SIZE) { + printk_err("Read failed...\n"); + goto out; + } + /* Scan for an elf header */ + header_offset = -1; + for(i = 0; i < ELF_HEAD_SIZE - (sizeof(Elf_ehdr) + sizeof(Elf_phdr)); i+=16) { + ehdr = (Elf_ehdr *)(&header[i]); + if (memcmp(ehdr->e_ident, ELFMAG, 4) != 0) { + printk_spew("NO header at %d\n", i); + continue; + } + printk_debug("Found ELF candiate at offset %d\n", i); + /* Sanity check the elf header */ + if ((ehdr->e_type == ET_EXEC) && + elf_check_arch(ehdr) && + (ehdr->e_ident[EI_VERSION] == EV_CURRENT) && + (ehdr->e_version == EV_CURRENT) && + (ehdr->e_ehsize == sizeof(Elf_ehdr)) && + (ehdr->e_phentsize = sizeof(Elf_phdr)) && + (ehdr->e_phoff < (ELF_HEAD_SIZE - i)) && + ((ehdr->e_phoff + (ehdr->e_phentsize * ehdr->e_phnum)) <= + (ELF_HEAD_SIZE - i))) { + header_offset = i; + break; + } + ehdr = 0; + } + printk_spew("header_offset is %d\n", header_offset); + if (header_offset == -1) { + goto out; + } + + printk_spew("Try to load at offset 0x%x\n", header_offset); + result = elfload(mem, + header + header_offset , ELF_HEAD_SIZE - header_offset); + out: + if (!result) { + /* Shutdown the stream device */ + stream_fini(); + + printk_err("Cannot Load ELF Image\n"); + + post_code(0xff); + } + return 0; + +} diff --git a/src/boot/hardwaremain.c b/src/boot/hardwaremain.c new file mode 100644 index 0000000000..3507f88f0a --- /dev/null +++ b/src/boot/hardwaremain.c @@ -0,0 +1,216 @@ +/* +This software and ancillary information (herein called SOFTWARE ) +called LinuxBIOS is made available under the terms described +here. The SOFTWARE has been approved for release with associated +LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has +been authored by an employee or employees of the University of +California, operator of the Los Alamos National Laboratory under +Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The +U.S. Government has rights to use, reproduce, and distribute this +SOFTWARE. The public may copy, distribute, prepare derivative works +and publicly display this SOFTWARE without charge, provided that this +Notice and any statement of authorship are reproduced on all copies. +Neither the Government nor the University makes any warranty, express +or implied, or assumes any liability or responsibility for the use of +this SOFTWARE. If SOFTWARE is modified to produce derivative works, +such modified SOFTWARE should be clearly marked, so as not to confuse +it with the version available from LANL. + */ +/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL + * rminnich@lanl.gov + */ + + +/* + * C Bootstrap code for the LinuxBIOS + */ + + +#include <console/console.h> +#include <cpu/cpu.h> +#include <mem.h> +#include <version.h> +#include <smp/start_stop.h> +#include <boot/tables.h> +#include <part/sizeram.h> +#include <device.h> +#include <pci.h> +#if 0 +#include <part/mainboard.h> +#endif +#if 0 +#include <part/hard_reset.h> +#endif +#include <smp/atomic.h> +#include <boot/elf.h> + + +#ifndef CONFIG_MAX_PHYSICAL_CPUS +#define CONFIG_MAX_PHYSICAL_CPUS CONFIG_MAX_CPUS +#endif + +/* The processor map. + * Now that SMP is in linuxbios, and Linux counts on us + * giving accurate information about processors, we need a map + * of what processors are out there. This could be a bit mask, + * but we will be optimistic and hope we someday run on + * REALLY BIG SMPs. Also we may need more than one bit of + * info per processor at some point. I hope we don't need + * anything more complex than an int. + */ +static unsigned long processor_map[MAX_CPUS]; + +static struct mem_range *get_ramsize(void) +{ + struct mem_range *mem = 0; + if (!mem) { + mem = sizeram(); + } + if (!mem) { + printk_err("No memory size information!\n"); + for(;;); + } + return mem; +} + + +#if SMP == 1 +/* Number of cpus that are currently running in linuxbios */ +static atomic_t active_cpus = ATOMIC_INIT(1); + +void secondary_cpu_init(void) +{ + struct mem_range *mem; + unsigned long id; + int index; + + atomic_inc(&active_cpus); + printk_debug(__FUNCTION__ "\n"); + mem = get_ramsize(); + id = cpu_initialize(mem); + index = processor_index(id); + printk_debug(__FUNCTION__ " %d/%u\n", index, id); + processor_map[index] = CPU_ENABLED; + atomic_dec(&active_cpus); + stop_cpu(id); +} + +static void wait_for_other_cpus(void) +{ + int old_active_count, active_count; + int i; + old_active_count = 1; + + active_count = atomic_read(&active_cpus); + while(active_count > 1) { + if (active_count != old_active_count) { + printk_info("Waiting for %d CPUS to stop\n", active_count); + old_active_count = active_count; + } + active_count = atomic_read(&active_cpus); + } + for(i = 0; i < MAX_CPUS; i++) { + if (!(processor_map[i] & CPU_ENABLED)) { + printk_err("CPU %d/%u did not initialize!\n", + i, initial_apicid[i]); + processor_map[i] = 0; + mainboard_cpu_fixup(i); + } + } + printk_debug("All AP CPUs stopped\n"); +} + +#else /* SMP */ +#define wait_for_other_cpus() do {} while(0) +#endif /* SMP */ + +void hardwaremain(int boot_complete) +{ + /* Processor ID of the BOOT cpu (i.e. the one running this code) */ + unsigned long boot_cpu; + int boot_index; + + /* the order here is a bit tricky. We don't want to do much of + * anything that uses config registers until after PciAllocateResources + * since that function also figures out what kind of config strategy + * to use (type 1 or type 2). + * so we turn on cache, then worry about PCI setup, then do other + * things, so that the other work can use the PciRead* and PciWrite* + * functions. + */ + struct mem_range *mem, *tmem; + struct lb_memory *lb_mem; + unsigned long totalmem; + + post_code(0x80); + /* displayinit MUST PRECEDE ALL PRINTK! */ + console_init(); + + post_code(0x39); + printk_notice("LinuxBIOS-%s%s %s %s...\n", + linuxbios_version, linuxbios_extra_version, linuxbios_build, + (boot_complete)?"rebooting":"booting"); + + post_code(0x40); + +#if 0 + /* If we have already booted attempt a hard reboot */ + if (boot_complete) { + hard_reset(); + } +#endif +#if 1 + + // pick how to scan the bus. This is first so we can get at memory size. + printk_info("Finding PCI configuration type.\n"); + pci_set_method(); + post_code(0x5f); +#if 0 + enumerate_static_devices(); +#endif + dev_enumerate(); + post_code(0x66); + // Now do the real bus + // we round the total ram up a lot for thing like the SISFB, which + // shares high memory with the CPU. + dev_configure(); + post_code(0x88); + + dev_enable(); + dev_initialize(); + post_code(0x89); +#endif + + mem = get_ramsize(); + post_code(0x70); + totalmem = 0; + for(tmem = mem; tmem->sizek; tmem++) { + totalmem += tmem->sizek; + } + printk_info("totalram: %ldM\n", + (totalmem + 512) >> 10); /* Round to the nearest meg */ + + /* Fully initialize the cpu before configuring the bus */ + boot_cpu = cpu_initialize(mem); + boot_index = processor_index(boot_cpu); + printk_spew("BOOT CPU is %d\n", boot_cpu); + processor_map[boot_index] = CPU_BOOTPROCESSOR|CPU_ENABLED; + + /* Now start the other cpus initializing + * The sooner they start the sooner they stop. + */ + post_code(0x75); + startup_other_cpus(processor_map); + post_code(0x77); + + /* make certain we are the only cpu running in linuxBIOS */ + wait_for_other_cpus(); + + /* Now that we have collected all of our information + * write our configuration tables. + */ + lb_mem = write_tables(mem, processor_map); + + elfboot(lb_mem); +} + diff --git a/src/config/LinuxBIOSDoc.config b/src/config/LinuxBIOSDoc.config new file mode 100755 index 0000000000..557b952ee5 --- /dev/null +++ b/src/config/LinuxBIOSDoc.config @@ -0,0 +1,691 @@ +# Doxyfile 1.2.1 + +# This file describes the settings to be used by doxygen for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "LinuxBIOS" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, +# Spanish, Russian, Croatian, Polish, and Portuguese. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a class diagram (in Html and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. + +CLASS_DIAGRAMS = YES + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen +# will only generate file names in lower case letters. If set to +# YES upper case letters are also allowed. This is useful if you have +# classes or files whose names only differ in case and if your file system +# supports case sensitive file names. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the Javadoc-style will +# behave just like the Qt-style comments. + +JAVADOC_AUTOBRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The ENABLE_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +# INPUT = ../src + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +# FILE_PATTERNS = *.c *.h *.S + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = YES + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using a WORD or other. +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Warning: This feature +# is still experimental and very incomplete. + +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other +# documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented header file showing +# the documented files that directly or indirectly include this file + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/src/config/doxyscript.base b/src/config/doxyscript.base new file mode 100755 index 0000000000..557b952ee5 --- /dev/null +++ b/src/config/doxyscript.base @@ -0,0 +1,691 @@ +# Doxyfile 1.2.1 + +# This file describes the settings to be used by doxygen for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "LinuxBIOS" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, +# Spanish, Russian, Croatian, Polish, and Portuguese. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a class diagram (in Html and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. + +CLASS_DIAGRAMS = YES + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen +# will only generate file names in lower case letters. If set to +# YES upper case letters are also allowed. This is useful if you have +# classes or files whose names only differ in case and if your file system +# supports case sensitive file names. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the Javadoc-style will +# behave just like the Qt-style comments. + +JAVADOC_AUTOBRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The ENABLE_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +# INPUT = ../src + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +# FILE_PATTERNS = *.c *.h *.S + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = YES + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using a WORD or other. +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Warning: This feature +# is still experimental and very incomplete. + +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other +# documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented header file showing +# the documented files that directly or indirectly include this file + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/src/config/linuxbios_c.ld b/src/config/linuxbios_c.ld new file mode 100644 index 0000000000..187a99a638 --- /dev/null +++ b/src/config/linuxbios_c.ld @@ -0,0 +1,112 @@ +/* + * Memory map: + * + * _RAMBASE + * : data segment + * : bss segment + * : heap + * : stack + */ +/* + * Bootstrap code for the STPC Consumer + * Copyright (c) 1999 by Net Insight AB. All Rights Reserved. + * + * $Id$ + * + */ + +/* + * Written by Johan Rydberg, based on work by Daniel Kahlin. + * Rewritten by Eric Biederman + */ +/* + * We use ELF as output format. So that we can + * debug the code in some form. + */ +INCLUDE ldoptions + +ENTRY(_start) + +SECTIONS +{ + . = _RAMBASE; + /* + * First we place the code and read only data (typically const declared). + * This get placed in rom. + */ + .text : { + _text = .; + *(.text); + *(.text.*); + . = ALIGN(16); + _etext = .; + } + .rodata : { + _rodata = .; + . = ALIGN(4); + console_drivers = .; + *(.rodata.console_drivers) + econsole_drivers = . ; + . = ALIGN(4); + pci_drivers = . ; + *(.rodata.pci_drivers) + epci_drivers = . ; + *(.rodata) + *(.rodata.*) + /* + * kevinh/Ispiri - Added an align, because the objcopy tool + * incorrectly converts sections that are not long word aligned. + * This breaksthe linuxbios.strip target. + */ + . = ALIGN(4); + + _erodata = .; + } + /* + * After the code we place initialized data (typically initialized + * global variables). This gets copied into ram by startup code. + * __data_start and __data_end shows where in ram this should be placed, + * whereas __data_loadstart and __data_loadend shows where in rom to + * copy from. + */ + .data : { + _data = .; + *(.data) + _edata = .; + } + /* + * bss does not contain data, it is just a space that should be zero + * initialized on startup. (typically uninitialized global variables) + * crt0.S fills between _bss and _ebss with zeroes. + */ + _bss = .; + .bss . : { + *(.bss) + *(.sbss) + *(COMMON) + } + _ebss = .; + _end = .; + _stack = .; + .stack . : { + /* Reserve a stack for each possible cpu, +1 extra */ + . = ((MAX_CPUS * STACK_SIZE) + STACK_SIZE) ; + } + _estack = .; + _heap = .; + .heap . : { + /* Reserve 256K for the heap */ + . = HEAP_SIZE ; + . = ALIGN(4); + } + _eheap = .; + /* The ram segment + * This is all address of the memory resident copy of linuxBIOS. + */ + _ram_seg = _text; + _eram_seg = _eheap; + /DISCARD/ : { + *(.comment) + *(.note) + } +} diff --git a/src/console/console.c b/src/console/console.c new file mode 100644 index 0000000000..458fbb8fff --- /dev/null +++ b/src/console/console.c @@ -0,0 +1,75 @@ +/* + * Bootstrap code for the INTEL + * $Id$ + * + */ + +#include <arch/io.h> +#include <console/console.h> +#include <string.h> +#include <pc80/mc146818rtc.h> + + +static int initialized; + +/* initialize the console */ +void console_init(void) +{ + struct console_driver *driver; + if(get_option(&console_loglevel, "debug_level")) + console_loglevel=DEFAULT_CONSOLE_LOGLEVEL; + + for(driver = console_drivers; driver < econsole_drivers; driver++) { + if (!driver->init) + continue; + driver->init(); + } + initialized = 1; +} + +static void __console_tx_byte(unsigned char byte) +{ + struct console_driver *driver; + for(driver = console_drivers; driver < econsole_drivers; driver++) { + driver->tx_byte(byte); + } +} + +void console_tx_flush(void) +{ + struct console_driver *driver; + for(driver = console_drivers; driver < econsole_drivers; driver++) { + if (!driver->tx_flush) + continue; + driver->tx_flush(); + } +} + +void console_tx_byte(unsigned char byte) +{ + if (!initialized) + return; + if (byte == '\n') + __console_tx_byte('\r'); + __console_tx_byte(byte); +} + +/* + * Write POST information + */ +void post_code(uint8_t value) +{ +#ifdef CONFIG_SERIAL_POST + printk_info("POST: 0x%02x\n", value); +#elsif !define(NO_POST) + outb(value, 0x80); +#endif +} + +/* Report a fatal error */ +void die(char *msg) +{ + printk_emerg("%s", msg); + post_code(0xff); + while (1); /* Halt */ +} diff --git a/src/console/logbuf_console.c b/src/console/logbuf_console.c new file mode 100644 index 0000000000..e605ae5c23 --- /dev/null +++ b/src/console/logbuf_console.c @@ -0,0 +1,19 @@ +#include <console/console.h> + +#define LOGBUF_SIZE 1024 + +// KEEP THIS GLOBAL. +// I need the address so I can watch it with the ARIUM hardware. RGM. +char logbuf[LOGBUF_SIZE]; +int logbuf_offset = 0; + +static void logbuf_tx_byte(unsigned char byte) +{ + logbuf[logbuf_offset] = byte; + logbuf_offset = (logbuf_offset +1) % LOGBUF_SIZE; +} + +static struct console_driver __console = { + .init = 0, + .tx_byte = logbuf_tx_byte, +};} diff --git a/src/console/printk.c b/src/console/printk.c new file mode 100644 index 0000000000..67b0d4e19b --- /dev/null +++ b/src/console/printk.c @@ -0,0 +1,56 @@ +/* + * blantantly copied from linux/kernel/printk.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + */ + +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +//typedef void * va_list; + +#include <stdarg.h> +#include <smp/spinlock.h> +#include <console/console.h> + +/* printk's without a loglevel use this.. */ +#define DEFAULT_MESSAGE_LOGLEVEL 4 /* BIOS_WARNING */ + +/* We show everything that is MORE important than this.. */ +#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ + +/* Keep together for sysctl support */ + +int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; +int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL; +int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL; +int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; + +void display(char*); +extern int vtxprintf(void (*)(unsigned char), const char *, va_list); + +spinlock_t console_lock = SPIN_LOCK_UNLOCKED; + +int do_printk(int msg_level, const char *fmt, ...) +{ + va_list args; + int i; + + if (msg_level >= console_loglevel) { + return 0; + } + + spin_lock(&console_lock); + + va_start(args, fmt); + i = vtxprintf(console_tx_byte, fmt, args); + va_end(args); + + console_tx_flush(); + + spin_unlock(&console_lock); + + return i; +} diff --git a/src/console/uart8250_console.c b/src/console/uart8250_console.c new file mode 100644 index 0000000000..6eeeb6aa55 --- /dev/null +++ b/src/console/uart8250_console.c @@ -0,0 +1,49 @@ +#include <console/console.h> +#include <uart8250.h> +#include <pc80/mc146818rtc.h> + +/* Base Address */ +#ifndef TTYS0_BASE +#define TTYS0_BASE 0x3f8 +#endif + +#ifndef TTYS0_BAUD +#define TTYS0_BAUD 115200 +#endif + +#if ((115200%TTYS0_BAUD) != 0) +#error Bad ttys0 baud rate +#endif + +#define TTYS0_DIV (115200/TTYS0_BAUD) + +/* Line Control Settings */ +#ifndef TTYS0_LCS +/* Set 8bit, 1 stop bit, no parity */ +#define TTYS0_LCS 0x3 +#endif + +#define UART_LCS TTYS0_LCS + +void ttyS0_init(void) +{ + static unsigned char div[8]={1,2,3,6,12,24,48,96}; + int b_index=0; + unsigned int divisor=TTYS0_DIV; + + if(get_option(&b_index,"baud_rate")==0) { + divisor=div[b_index]; + } + uart8250_init(TTYS0_BASE, divisor, TTYS0_LCS); +} + +void ttyS0_tx_byte(unsigned char data) +{ + uart8250_tx_byte(TTYS0_BASE, data); +} + +static struct console_driver uart8250_console __console = { + .init = ttyS0_init, + .tx_byte = ttyS0_tx_byte, +}; + diff --git a/src/console/vga_console.c b/src/console/vga_console.c new file mode 100644 index 0000000000..ffd6699529 --- /dev/null +++ b/src/console/vga_console.c @@ -0,0 +1,100 @@ +/* + * + * modified from original freebios code + * by Steve M. Gehlbach <steve@kesa.com> + * + */ + +#include <arch/io.h> +#include <string.h> +#include <pc80/vga.h> +#include <console/console.h> + +void beep(int ms); + +static char *vidmem; /* The video buffer, should be replaced by symbol in ldscript.ld */ +int vga_line, vga_col; + +#define VIDBUFFER 0xB8000; + +static void memsetw(void *s, int c, unsigned int n) +{ + int i; + u16 *ss = (u16 *) s; + + for (i = 0; i < n; i++) { + ss[i] = ( u16 ) c; + } +} + +static void vga_init(void) +{ + + // these are globals + vga_line = 0; + vga_col = 0; + vidmem = (unsigned char *) VIDBUFFER; + + // mainboard or chip specific init routines + // also loads font + vga_hardware_fixup(); + + // set attributes, char for entire screen + // font should be previously loaded in + // device specific code (vga_hardware_fixup) + memsetw(vidmem, VGA_ATTR_CLR_WHT, 2*1024); // +} + +static void vga_scroll(void) +{ + int i; + + memcpy(vidmem, vidmem + COLS * 2, (LINES - 1) * COLS * 2); + for (i = (LINES - 1) * COLS * 2; i < LINES * COLS * 2; i += 2) + vidmem[i] = ' '; +} + +static void vga_tx_byte(unsigned char byte) +{ + if (byte == '\n') { + vga_line++; + vga_col = 0; + + } else if (byte == '\r') { + vga_col = 0; + + } else if (byte == '\b') { + vga_col--; + + } else if (byte == '\t') { + vga_col += 4; + + } else if (byte == '\a') { + //beep + beep(500); + + } else { + vidmem[((vga_col + (vga_line *COLS)) * 2)] = byte; + vidmem[((vga_col + (vga_line *COLS)) * 2) +1] = VGA_ATTR_CLR_WHT; + vga_col++; + } + if (vga_col < 0) { + vga_col = 0; + } + if (vga_col >= COLS) { + vga_line++; + vga_col = 0; + } + if (vga_line >= LINES) { + vga_scroll(); + vga_line--; + } + // move the cursor + write_crtc((vga_col + (vga_line *COLS)) >> 8, CRTC_CURSOR_HI); + write_crtc((vga_col + (vga_line *COLS)) & 0x0ff, CRTC_CURSOR_LO); +} + +struct console_driver { + .init = vga_init, + .tx_byte = vga_tx_byte, +}; diff --git a/src/console/vsprintf.c b/src/console/vsprintf.c new file mode 100644 index 0000000000..b1310c62d1 --- /dev/null +++ b/src/console/vsprintf.c @@ -0,0 +1,352 @@ +/* + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +#include <stdarg.h> +#include <string.h> + +/* haha, don't need ctype.c */ +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#define is_digit isdigit +#define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) +#define islower(c) ((c) >= 'a' && (c) <= 'z') +#define toupper(c) __toupper(c) + +static inline unsigned char __toupper(unsigned char c) +{ + if (islower(c)) + c -= 'a'-'A'; + return c; +} + + +unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) +{ + unsigned long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) + ? toupper(*cp) : *cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +long simple_strtol(const char *cp,char **endp,unsigned int base) +{ + if(*cp=='-') + return -simple_strtoul(cp+1,endp,base); + return simple_strtoul(cp,endp,base); +} + + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static int number(void (*tx_byte)(unsigned char byte), long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + int count = 0; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + tx_byte(' '), count++; + if (sign) + tx_byte(sign), count++; + if (type & SPECIAL) { + if (base==8) + tx_byte('0'), count++; + else if (base==16) { + tx_byte('0'), count++; + tx_byte(digits[33]), count++; + } + } + if (!(type & LEFT)) + while (size-- > 0) + tx_byte(c), count++; + while (i < precision--) + tx_byte('0'), count++; + while (i-- > 0) + tx_byte(tmp[i]), count++; + while (size-- > 0) + tx_byte(' '), count++; + return count; +} + + +int vtxprintf(void (*tx_byte)(unsigned char byte), const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + int count; + + for (count=0; *fmt ; ++fmt) { + if (*fmt != '%') { + tx_byte(*fmt), count++; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + tx_byte(' '), count++; + tx_byte((unsigned char) va_arg(args, int)), count++; + while (--field_width > 0) + tx_byte(' '), count++; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = "<NULL>"; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + tx_byte(' '), count++; + for (i = 0; i < len; ++i) + tx_byte(*s++), count++; + while (len < field_width--) + tx_byte(' '), count++; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + count += number(tx_byte, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = count; + } else { + int * ip = va_arg(args, int *); + *ip = count; + } + continue; + + case '%': + tx_byte('%'), count++; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + tx_byte('%'), count++; + if (*fmt) + tx_byte(*fmt), count++; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + count += number(tx_byte, num, base, field_width, precision, flags); + } + return count; +} + +/* FIXME this global makes vsprintf non-reentrant + */ +static char *str_buf; +static void str_tx_byte(unsigned char byte) +{ + *str_buf = byte; + str_buf++; +} + +int vsprintf(char * buf, const char *fmt, va_list args) +{ + int i; + str_buf = buf; + i = vtxprintf(str_tx_byte, fmt, args); + /* maeder/Ispiri -- The null termination was missing a deference */ + /* and was just zeroing out the pointer instead */ + *str_buf = '\0'; + return i; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} diff --git a/src/cpu/i386/entry16.inc b/src/cpu/i386/entry16.inc new file mode 100644 index 0000000000..c357504735 --- /dev/null +++ b/src/cpu/i386/entry16.inc @@ -0,0 +1,112 @@ +/* +This software and ancillary information (herein called SOFTWARE ) +called LinuxBIOS is made available under the terms described +here. The SOFTWARE has been approved for release with associated +LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has +been authored by an employee or employees of the University of +California, operator of the Los Alamos National Laboratory under +Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The +U.S. Government has rights to use, reproduce, and distribute this +SOFTWARE. The public may copy, distribute, prepare derivative works +and publicly display this SOFTWARE without charge, provided that this +Notice and any statement of authorship are reproduced on all copies. +Neither the Government nor the University makes any warranty, express +or implied, or assumes any liability or responsibility for the use of +this SOFTWARE. If SOFTWARE is modified to produce derivative works, +such modified SOFTWARE should be clearly marked, so as not to confuse +it with the version available from LANL. + */ +/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL + * rminnich@lanl.gov + */ + + +/** Start code to put an i386 or later processor into 32-bit + * protected mode. + */ + +/* .section ".rom.text" */ +#include <arch/rom_segs.h> +.code16 +.globl EXT(_start) +.type EXT(_start), @function + +EXT(_start): + cli + +/* thanks to kmliu@sis.tw.com for this TBL fix ... */ +/**/ +/* IMMEDIATELY invalidate the translation lookaside buffer before executing*/ +/* any further code. Even though paging is disabled we could still get*/ +/*false address translations due to the TLB if we didn't invalidate it.*/ +/**/ + xorl %eax, %eax + movl %eax, %cr3 /* Invalidate TLB*/ + + /* invalidate the cache */ + invd + + /* Note: gas handles memory addresses in 16 bit code very poorly. + * In particular it doesn't appear to have a directive allowing you + * associate a section or even an absolute offset with a segment register. + * + * This means that anything except cs:ip relative offsets are + * a real pain in 16 bit mode. And explains why it is almost + * imposible to get gas to do lgdt correctly. + * + * One way to work around this is to have the linker do the + * math instead of the assembler. This solves the very + * pratical problem of being able to write code that can + * be relocated. + * + * An lgdt call before we have memory enabled cannot be + * position independent, as we cannot execute a call + * instruction to get our current instruction pointer. + * So while this code is relocateable it isn't arbitrarily + * relocatable. + * + * The criteria for relocation have been relaxed to their + * utmost, so that we can use the same code for both + * our initial entry point and startup of the second cpu. + * The code assumes when executing at _start that: + * (((cs & 0xfff) == 0) and (ip == _start & 0xffff)) + * or + * ((cs == anything) and (ip == 0)). + * + * The restrictions in reset16.inc mean that _start initially + * must be loaded at or above 0xffff0000 or below 0x100000. + * + * The linker scripts computs gdtptr16_offset by simply returning + * the low 16 bits. This means that the intial segment used + * when start is called must be 64K aligned. This should not + * restrict the address as the ip address can be anything. + */ + + movw %cs, %ax + shlw $4, %ax + movw $EXT(gdtptr16_offset), %bx + subw %ax, %bx + data32 lgdt %cs:(%bx) + + movl %cr0, %eax + andl $0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */ + orl $0x60000001, %eax /* CD, NW, PE = 1 */ + movl %eax, %cr0 + + /* Now that we are in protected mode jump to a 32 bit code segment. */ + data32 ljmp $ROM_CODE_SEG, $__protected_start + +/** The gdt has a 4 Gb code segment at 0x10, and a 4 GB data segment + * at 0x18; these are Linux-compatible. + */ + +.align 4 +.globl EXT(gdtptr16) +EXT(gdtptr16): + .word gdt_end - gdt -1 /* compute the table limit */ + .long gdt /* we know the offset */ + +.globl EXT(_estart) +EXT(_estart): + .code32 + diff --git a/src/cpu/i386/entry16.lds b/src/cpu/i386/entry16.lds new file mode 100644 index 0000000000..db37e66302 --- /dev/null +++ b/src/cpu/i386/entry16.lds @@ -0,0 +1,2 @@ + gdtptr16_offset = gdtptr16 & 0xffff; + _start_offset = _start & 0xffff; diff --git a/src/cpu/i386/entry32.inc b/src/cpu/i386/entry32.inc new file mode 100644 index 0000000000..8ccd638e95 --- /dev/null +++ b/src/cpu/i386/entry32.inc @@ -0,0 +1,55 @@ +/* For starting linuxBIOS in protected mode */ + +#include <arch/rom_segs.h> + +/* .section ".rom.text" */ + .code32 + + .align 4 +.globl EXT(gdtptr) + +gdt: +EXT(gdtptr): + .word gdt_end - gdt -1 /* compute the table limit */ + .long gdt /* we know the offset */ + .word 0 + +/* flat code segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xcf, 0x00 + +/* flat data segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x93, 0xcf, 0x00 + +gdt_end: + + +/* + * When we come here we are in protected mode. We expand + * the stack and copies the data segment from ROM to the + * memory. + * + * After that, we call the chipset bootstrap routine that + * does what is left of the chipset initialization. + * + * NOTE aligned to 4 so that we are sure that the prefetch + * cache will be reloaded. + */ + .align 4 +.globl EXT(protected_start) +EXT(protected_start): + + lgdt %cs:gdtptr + ljmp $ROM_CODE_SEG, $__protected_start + +__protected_start: + intel_chip_post_macro(0x10) /* post 10 */ + + movw $ROM_DATA_SEG, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + diff --git a/src/cpu/i386/entry32.lds b/src/cpu/i386/entry32.lds new file mode 100644 index 0000000000..37a75ba6ae --- /dev/null +++ b/src/cpu/i386/entry32.lds @@ -0,0 +1,14 @@ +/* + _cache_ram_seg_base = DEFINED(CACHE_RAM_BASE)? CACHE_RAM_BASE - _rodata : 0; + _cache_ram_seg_base_low = (_cache_ram_seg_base) & 0xffff; + _cache_ram_seg_base_middle = (_cache_ram_seg_base >> 16) & 0xff; + _cache_ram_seg_base_high = (_cache_ram_seg_base >> 24) & 0xff; + + _rom_code_seg_base = _ltext - _text; + _rom_code_seg_base_low = (_rom_code_seg_base) & 0xffff; + _rom_code_seg_base_middle = (_rom_code_seg_base >> 16) & 0xff; + _rom_code_seg_base_high = (_rom_code_seg_base >> 24) & 0xff; +*/ + + + diff --git a/src/cpu/i386/reset16.inc b/src/cpu/i386/reset16.inc new file mode 100644 index 0000000000..7c911d9ff2 --- /dev/null +++ b/src/cpu/i386/reset16.inc @@ -0,0 +1,27 @@ + .section ".reset" + .code16 +.globl EXT(reset_vector) +EXT(reset_vector): +#if _ROMBASE >= 0xffff0000 + /* Hmm. + * _start_offset is the low 16 bits of _start. + * Theoretically we should have problems but it compiles + * and links properly with binutils 2.9.5 & 2.10.90 + * This is probably a case that needs fixing in binutils. + * And then we can just use _start. + * We also need something like the assume directive in + * other assemblers to tell it where the segment registers + * are pointing in memory right now. + */ + jmp EXT(_start_offset) +#elif (_ROMBASE < 0x100000) + ljmp $((_ROMBASE & 0xf0000)>>4),$EXT(_start_offset); +#else +#error _ROMBASE is an unsupported value +#endif + + . = 0x8; + .code32 + jmp EXT(protected_start) + + .previous diff --git a/src/cpu/i386/reset16.lds b/src/cpu/i386/reset16.lds new file mode 100644 index 0000000000..80f2fc0c6f --- /dev/null +++ b/src/cpu/i386/reset16.lds @@ -0,0 +1,14 @@ +/* + * _ROMTOP : The top of the rom used where we + * need to put the reset vector. + */ + +SECTIONS { + _ROMTOP = (_ROMBASE >= 0xffff0000)? 0xfffffff0 : 0xffff0; + . = _ROMTOP; + .reset . : { + *(.reset) + . = 15 ; + BYTE(0x00); + } +} diff --git a/src/cpu/i386/reset32.inc b/src/cpu/i386/reset32.inc new file mode 100644 index 0000000000..ec743b70cc --- /dev/null +++ b/src/cpu/i386/reset32.inc @@ -0,0 +1,10 @@ + .section ".reset" + .code16 +.globl EXT(reset_vector) +EXT(reset_vector): + + . = 0x8; + .code32 + jmp EXT(protected_start) + + .previous diff --git a/src/cpu/i386/reset32.lds b/src/cpu/i386/reset32.lds new file mode 100644 index 0000000000..fa6db86b1a --- /dev/null +++ b/src/cpu/i386/reset32.lds @@ -0,0 +1,14 @@ +/* + * _ROMTOP : The top of the rom used where we + * need to put the reset vector. + */ + +SECTIONS { + _ROMTOP = _ROMBASE + ROM_IMAGE_SIZE - 0x10; + . = _ROMTOP; + .reset (.): { + *(.reset) + . = 15 ; + BYTE(0x00); + } +} diff --git a/src/cpu/k8/cpufixup.c b/src/cpu/k8/cpufixup.c new file mode 100644 index 0000000000..9f306d1156 --- /dev/null +++ b/src/cpu/k8/cpufixup.c @@ -0,0 +1,59 @@ +/* Needed so the AMD K8 runs correctly. */ +#include <console/console.h> +#include <mem.h> +#include <cpu/p6/msr.h> + +#define TOP_MEM 0xc001001A +#define TOP_MEM2 0xc001001D +#define IORR_FIRST 0xC0010016 +#define IORR_LAST 0xC0010019 +#define SYSCFG 0xC0010010 + +#define MTRRVARDRAMEN (1 << 20) + +void k8_cpufixup(struct mem_range *mem) +{ + unsigned long lo = 0, hi = 0, i; + unsigned long ram_megabytes; + + /* For now no Athlon board has significant holes in it's + * address space so just find the last memory region + * and compute the end of memory from that. + */ + for(i = 0; mem[i].sizek; i++) + ; + if (i == 0) + return; + ram_megabytes = (mem[i-1].basek + mem[i-1].sizek) *1024; + + + // 8 MB alignment please + ram_megabytes += 0x7fffff; + ram_megabytes &= (~0x7fffff); + + // set top_mem registers to ram size + printk_spew("Setting top_mem to 0x%x\n", ram_megabytes); + rdmsr(TOP_MEM, lo, hi); + printk_spew("TOPMEM was 0x%02x:0x%02x\n", hi, lo); + hi = 0; + lo = ram_megabytes; + wrmsr(TOP_MEM, lo, hi); + + // I am setting this even though I won't enable it + wrmsr(TOP_MEM2, lo, hi); + + /* zero the IORR's before we enable to prevent + * undefined side effects + */ + lo = hi = 0; + for (i = IORR_FIRST; i <= IORR_LAST; i++) + wrmsr(i, lo, hi); + + rdmsr(SYSCFG, lo, hi); + printk_spew("SYSCFG was 0x%x:0x%x\n", hi, lo); + lo |= MTRRVARDRAMEN; + wrmsr(SYSCFG, lo, hi); + rdmsr(SYSCFG, lo, hi); + printk_spew("SYSCFG IS NOW 0x%x:0x%x\n", hi, lo); +} + diff --git a/src/cpu/k8/earlymtrr.inc b/src/cpu/k8/earlymtrr.inc new file mode 100644 index 0000000000..7cd8443618 --- /dev/null +++ b/src/cpu/k8/earlymtrr.inc @@ -0,0 +1,99 @@ +#include <cpu/k8/mtrr.h> + +/* The fixed and variable MTRRs are powered-up with random values, clear them to + * MTRR_TYPE_UNCACHABLE for safty reason + */ + +earlymtrr_start: + xorl %eax, %eax # clear %eax and %edx + xorl %edx, %edx # + movl $fixed_mtrr_msr, %esi + +clear_fixed_var_mtrr: + lodsl (%esi), %eax + testl %eax, %eax + jz clear_fixed_var_mtrr_out + + movl %eax, %ecx + xorl %eax, %eax + wrmsr + + jmp clear_fixed_var_mtrr +clear_fixed_var_mtrr_out: + +/* enable memory access for 0 - 8MB using top_mem */ + movl $TOP_MEM, %ecx + xorl %edx, %edx + movl $0x0800000, %eax + wrmsr + +set_var_mtrr: + /* enable caching for 0 - 128MB using variable mtrr */ + movl $0x200, %ecx + rdmsr + andl $0xfffffff0, %edx + orl $0x00000000, %edx + andl $0x00000f00, %eax + orl $0x00000006, %eax + wrmsr + + movl $0x201, %ecx + rdmsr + andl $0xfffffff0, %edx + orl $0x0000000f, %edx + andl $0x000007ff, %eax + orl $0xf0000800, %eax + wrmsr + +#if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE) + /* enable write protect caching so we can do execute in place + * on the flash rom. + */ + movl $0x202, %ecx + xorl %edx, %edx + movl $(XIP_ROM_BASE | 0x005), %eax + wrmsr + + movl $0x203, %ecx + movl $0x0000000f, %edx + movl $(~(XIP_ROM_SIZE - 1) | 0x800), %eax + wrmsr +#endif /* XIP_ROM_SIZE && XIP_ROM_BASE */ + +enable_mtrr: + /* Set the default memory type and enable fixed and variable MTRRs */ + movl $0x2ff, %ecx + xorl %edx, %edx + /* Enable Variable MTRRs */ + movl $0x00000800, %eax + wrmsr + + /* Enable the MTRRs in SYSCFG */ + movl $SYSCFG_MSR, %ecx + rdmsr + orl $(SYSCFG_MSR_MtrrVarDramEn), %eax + wrmsr + + /* enable cache */ + movl %cr0, %eax + andl $0x9fffffff,%eax + movl %eax, %cr0 + + jmp earlymtrr_end + +fixed_mtrr_msr: + .long 0x250, 0x258, 0x259 + .long 0x268, 0x269, 0x26A + .long 0x26B, 0x26C, 0x26D + .long 0x26E, 0x26F +var_mtrr_msr: + .long 0x200, 0x201, 0x202, 0x203 + .long 0x204, 0x205, 0x206, 0x207 + .long 0x208, 0x209, 0x20A, 0x20B + .long 0x20C, 0x20D, 0x20E, 0x20F +var_iorr_msr: + .long 0xC0010016, 0xC0010017, 0xC0010018, 0xC0010019 +mem_top: + .long 0xC001001A, 0xC001001D + .long 0x000 /* NULL, end of table */ +earlymtrr_end: diff --git a/src/cpu/p5/cpuid.c b/src/cpu/p5/cpuid.c new file mode 100644 index 0000000000..d90cc2c124 --- /dev/null +++ b/src/cpu/p5/cpuid.c @@ -0,0 +1,222 @@ +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +#include <console/console.h> +#include <cpu/p5/cpuid.h> +#ifdef i586 +#include <cpu/p6/msr.h> +#endif + + +int mtrr_check(void) +{ +#ifdef i686 + /* Only Pentium Pro and later have MTRR */ + unsigned long low, high; + + printk_debug("\nMTRR check\n"); + + rdmsr(0x2ff, low, high); + low = low >> 10; + + printk_debug("Fixed MTRRs : "); + if (low & 0x01) + printk_debug("Enabled\n"); + else + printk_debug("Disabled\n"); + + printk_debug("Variable MTRRs: "); + if (low & 0x02) + printk_debug("Enabled\n"); + else + printk_debug("Disabled\n"); + + printk_debug("\n"); + + post_code(0x93); + return ((int) low); +#else /* !i686 */ + return 0; +#endif /* i686 */ +} + +void display_cpuid(void) +{ + int op, eax, ebx, ecx, edx; + int max_op; + + max_op = 0; + + printk_debug("\n"); + + for (op = 0; op <= max_op; op++) { + cpuid(op, &eax, &ebx, &ecx, &edx); + + if (0 == op) { + max_op = eax; + printk_debug("Max cpuid index : %d\n", eax); + printk_debug("Vendor ID : " + "%c%c%c%c%c%c%c%c%c%c%c%c\n", + ebx, ebx >> 8, ebx >> 16, ebx >> 24, edx, + edx >> 8, edx >> 16, edx >> 24, ecx, ecx >> 8, + ecx >> 16, ecx >> 24); + } else if (1 == op) { + printk_debug("Processor Type : 0x%02x\n", + (eax >> 12) & 0x03); + printk_debug("Processor Family : 0x%02x\n", + (eax >> 8) & 0x0f); + printk_debug("Processor Model : 0x%02x\n", + (eax >> 4) & 0x0f); + printk_debug("Processor Mask : 0x%02x\n", + (ecx >> 0) & 0x0f); + printk_debug("Processor Stepping : 0x%02x\n", + (eax >> 0) & 0x0f); + printk_debug("Feature flags : 0x%08x\n", edx); + } else if (2 == op) { + int desc[4]; + int ii; + int _desc; + + printk_debug("\n"); + + printk_debug("Cache/TLB descriptor values: %d " + "reads required\n", eax & 0xff); + + desc[0] = eax; + desc[1] = ebx; + desc[2] = ecx; + desc[3] = edx; + + for (ii = 1; ii < 16; ii++) { + if (desc[ii >> 2] & 0x80000000) { + printk_debug("reserved descriptor\n"); + continue; + } + + _desc = + ((desc[ii >> 2]) >> ((ii & 0x3) << 3)) + & 0xff; + printk_debug("Desc 0x%02x : ", _desc); + + switch (_desc) { + case 0x00: + printk_debug("null\n"); + break; + + case 0x01: + printk_debug("Instr TLB: " + "4KB pages, " + "4-way set assoc, " + "32 entries\n"); + break; + + case 0x02: + printk_debug("Instr TLB: " + "4MB pages, " + "fully assoc, " "2 entries\n"); + break; + + case 0x03: + printk_debug("Data TLB: " + "4KB pages, " + "4-way set assoc, " + "64 entries\n"); + break; + + case 0x04: + printk_debug("Data TLB: " + "4MB pages, " + "4-way set assoc, " + "8 entries\n"); + break; + + case 0x06: + printk_debug("Inst cache: " + "8K bytes, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x08: + printk_debug("Inst cache: " + "16K bytes, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x0a: + printk_debug("Data cache: " + "8K bytes, " + "2-way set assoc, " + "32 byte line size\n"); + break; + + case 0x0c: + printk_debug("Data cache: " + "16K bytes, " + "2-way or 4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x40: + printk_debug("No L2 cache\n"); + break; + + case 0x41: + printk_debug("L2 Unified cache: " + "128K bytes, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x42: + printk_debug("L2 Unified cache: " + "256K bytes, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x43: + printk_debug("L2 Unified cache: " + "512K bytes, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x44: + printk_debug("L2 Unified cache: " + "1M byte, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x45: + printk_debug("L2 Unified cache: " + "2M byte, " + "4-way set assoc, " + "32 byte line size\n"); + break; + + case 0x82: + printk_debug("L2 Unified cache: " + "256K bytes, " + "8-way set assoc, " + "32 byte line size\n"); + break; + + default: + printk_debug("UNKNOWN\n"); + } + } + printk_debug("\n"); + } else { + printk_debug("op: 0x%02x eax:0x%08x " + "ebx:0x%08x ecx:0x%08x edx:0x%08x\n", + op, eax, ebx, ecx, edx); + } + } + + printk_debug("\n"); + post_code(0x92); +} diff --git a/src/cpu/p6/mtrr.c b/src/cpu/p6/mtrr.c new file mode 100644 index 0000000000..b88e174869 --- /dev/null +++ b/src/cpu/p6/mtrr.c @@ -0,0 +1,356 @@ +/* + * intel_mtrr.c: setting MTRR to decent values for cache initialization on P6 + * + * Derived from intel_set_mtrr in intel_subr.c and mtrr.c in linux kernel + * + * Copyright 2000 Silicon Integrated System Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: Intel Architecture Software Developer's Manual, Volume 3: System Programming + * + * $Id$ + */ + +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +#include <console/console.h> +#include <mem.h> +#include <cpu/p6/msr.h> +#include <cpu/p6/mtrr.h> +#include <cpu/k7/mtrr.h> + +#define arraysize(x) (sizeof(x)/sizeof((x)[0])) + +static unsigned int mtrr_msr[] = { + MTRRfix64K_00000_MSR, MTRRfix16K_80000_MSR, MTRRfix16K_A0000_MSR, + MTRRfix4K_C0000_MSR, MTRRfix4K_C8000_MSR, MTRRfix4K_D0000_MSR, MTRRfix4K_D8000_MSR, + MTRRfix4K_E0000_MSR, MTRRfix4K_E8000_MSR, MTRRfix4K_F0000_MSR, MTRRfix4K_F8000_MSR, +}; + + +static void intel_enable_fixed_mtrr(void) +{ + unsigned long low, high; + + rdmsr(MTRRdefType_MSR, low, high); + low |= 0xc00; + wrmsr(MTRRdefType_MSR, low, high); +} + +static void intel_enable_var_mtrr(void) +{ + unsigned long low, high; + + rdmsr(MTRRdefType_MSR, low, high); + low |= 0x800; + wrmsr(MTRRdefType_MSR, low, high); +} + +static inline void disable_cache(void) +{ + unsigned int tmp; + /* Disable cache */ + /* Write back the cache and flush TLB */ + asm volatile ( + "movl %%cr0, %0\n\t" + "orl $0x40000000, %0\n\t" + "wbinvd\n\t" + "movl %0, %%cr0\n\t" + "wbinvd\n\t" + :"=r" (tmp) + ::"memory"); +} + +static inline void enable_cache(void) +{ + unsigned int tmp; + // turn cache back on. + asm volatile ( + "movl %%cr0, %0\n\t" + "andl $0x9fffffff, %0\n\t" + "movl %0, %%cr0\n\t" + :"=r" (tmp) + ::"memory"); +} + +/* setting variable mtrr, comes from linux kernel source */ +static void intel_set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, unsigned char type) +{ + unsigned long base_high, base_low; + unsigned long mask_high, mask_low; + + base_high = basek >> 22; + base_low = basek << 10; + + if (sizek < 4*1024*1024) { + mask_high = 0x0F; + mask_low = ~((sizek << 10) -1); + } + else { + mask_high = 0x0F & (~((sizek >> 22) -1)); + mask_low = 0; + } + + if (reg >= 8) + return; + + // it is recommended that we disable and enable cache when we + // do this. + disable_cache(); + if (sizek == 0) { + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ + wrmsr (MTRRphysMask_MSR (reg), 0, 0); + } else { + /* Bit 32-35 of MTRRphysMask should be set to 1 */ + wrmsr (MTRRphysBase_MSR(reg), base_low | type, base_high); + wrmsr (MTRRphysMask_MSR(reg), mask_low | 0x800, mask_high); + } + enable_cache(); +} + +/* setting variable mtrr, comes from linux kernel source */ +void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type) +{ + unsigned int tmp; + + if (reg >= 8) + return; + + // it is recommended that we disable and enable cache when we + // do this. + disable_cache(); + if (size == 0) { + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ + wrmsr (MTRRphysMask_MSR (reg), 0, 0); + } else { + /* Bit 32-35 of MTRRphysMask should be set to 1 */ + wrmsr (MTRRphysBase_MSR (reg), base | type, 0); + wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0x0F); + } + + // turn cache back on. + enable_cache(); +} + +/* fms: find most sigificant bit set, stolen from Linux Kernel Source. */ +static inline unsigned int fms(unsigned int x) +{ + int r; + + __asm__("bsrl %1,%0\n\t" + "jnz 1f\n\t" + "movl $0,%0\n" + "1:" : "=r" (r) : "g" (x)); + return r; +} + +/* fms: find least sigificant bit set */ +static inline unsigned int fls(unsigned int x) +{ + int r; + + __asm__("bsfl %1,%0\n\t" + "jnz 1f\n\t" + "movl $32,%0\n" + "1:" : "=r" (r) : "g" (x)); + return r; +} + +/* setting up variable and fixed mtrr + * + * From Intel Vol. III Section 9.12.4, the Range Size and Base Alignment has some kind of requirement: + * 1. The range size must be 2^N byte for N >= 12 (i.e 4KB minimum). + * 2. The base address must be 2^N aligned, where the N here is equal to the N in previous + * requirement. So a 8K range must be 8K aligned not 4K aligned. + * + * These requirement is meet by "decompositing" the ramsize into Sum(Cn * 2^n, n = [0..N], Cn = [0, 1]). + * For Cm = 1, there is a WB range of 2^m size at base address Sum(Cm * 2^m, m = [N..n]). + * A 124MB (128MB - 4MB SMA) example: + * ramsize = 124MB == 64MB (at 0MB) + 32MB (at 64MB) + 16MB (at 96MB ) + 8MB (at 112MB) + 4MB (120MB). + * But this wastes a lot of MTRR registers so we use another more "aggresive" way with Uncacheable Regions. + * + * In the Uncacheable Region scheme, we try to cover the whole ramsize by one WB region as possible, + * If (an only if) this can not be done we will try to decomposite the ramesize, the mathematical formula + * whould be ramsize = Sum(Cn * 2^n, n = [0..N], Cn = [-1, 0, 1]). For Cn = -1, a Uncachable Region is used. + * The same 124MB example: + * ramsize = 124MB == 128MB WB (at 0MB) + 4MB UC (at 124MB) + * or a 156MB (128MB + 32MB - 4MB SMA) example: + * ramsize = 156MB == 128MB WB (at 0MB) + 32MB WB (at 128MB) + 4MB UC (at 156MB) + */ +/* 2 MTRRS are reserved for the operating system */ +#define BIOS_MTRRS 6 +#define OS_MTRRS 2 +#define MTRRS (BIOS_MTRRS + OS_MTRRS) + + +static void set_fixed_mtrrs(unsigned int first, unsigned int last, unsigned char type) +{ + unsigned int i; + unsigned int fixed_msr = NUM_FIXED_RANGES >> 3; + unsigned long low, high; + low = high = 0; /* Shut up gcc */ + for(i = first; i < last; i++) { + /* When I switch to a new msr read it in */ + if (fixed_msr != i >> 3) { + /* But first write out the old msr */ + if (fixed_msr < (NUM_FIXED_RANGES >> 3)) { + disable_cache(); + wrmsr(mtrr_msr[fixed_msr], low, high); + enable_cache(); + } + fixed_msr = i>>3; + rdmsr(mtrr_msr[fixed_msr], low, high); + } + if ((i & 7) < 4) { + low &= ~(0xff << ((i&3)*8)); + low |= type << ((i&3)*8); + } else { + high &= ~(0xff << ((i&3)*8)); + high |= type << ((i&3)*8); + } + } + /* Write out the final msr */ + if (fixed_msr < (NUM_FIXED_RANGES >> 3)) { + disable_cache(); + wrmsr(mtrr_msr[fixed_msr], low, high); + enable_cache(); + } +} + +static unsigned fixed_mtrr_index(unsigned long addrk) +{ + unsigned index; + index = (addrk - 0) >> 6; + if (index >= 8) { + index = ((addrk - 8*64) >> 4) + 8; + } + if (index >= 24) { + index = ((addrk - (8*64 + 16*16)) >> 2) + 24; + } + if (index > NUM_FIXED_RANGES) { + index = NUM_FIXED_RANGES; + } + return index; +} + +static unsigned int range_to_mtrr(unsigned int reg, + unsigned long range_startk, unsigned long range_sizek, + unsigned long next_range_startk) +{ + if (!range_sizek || (reg >= BIOS_MTRRS)) { + return reg; + } + while(range_sizek) { + unsigned long max_align, align; + unsigned long sizek; + /* Compute the maximum size I can make a range */ + max_align = fls(range_startk); + align = fms(range_sizek); + if (align > max_align) { + align = max_align; + } + sizek = 1 << align; + printk_debug("Setting variable MTRR %d, base: %4dMB, range: %4dMB, type WB\n", + reg, range_startk >>10, sizek >> 10); + intel_set_var_mtrr(reg++, range_startk, sizek, MTRR_TYPE_WRBACK); + range_startk += sizek; + range_sizek -= sizek; + if (reg >= BIOS_MTRRS) + break; + } + return reg; +} + +void setup_mtrrs(struct mem_range *mem) +{ + /* Try this the simple way of incrementally adding together + * mtrrs. If this doesn't work out we can get smart again + * and clear out the mtrrs. + */ + struct mem_range *memp; + unsigned long range_startk, range_sizek; + unsigned int reg; + + printk_debug("\n"); + /* Initialized the fixed_mtrrs to uncached */ + printk_debug("Setting fixed MTRRs(%d-%d) type: UC\n", + 0, NUM_FIXED_RANGES); + set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHABLE); + + /* Now see which of the fixed mtrrs cover ram. + */ + for(memp = mem; memp->sizek; memp++) { + unsigned int start_mtrr; + unsigned int last_mtrr; + start_mtrr = fixed_mtrr_index(memp->basek); + last_mtrr = fixed_mtrr_index(memp->basek + memp->sizek); + if (start_mtrr >= NUM_FIXED_RANGES) { + break; + } + printk_debug("Setting fixed MTRRs(%d-%d) type: WB\n", + start_mtrr, last_mtrr); + set_fixed_mtrrs(start_mtrr, last_mtrr, MTRR_TYPE_WRBACK); + } + printk_debug("DONE fixed MTRRs\n"); + /* Cache as many memory areas as possible */ + /* FIXME is there an algorithm for computing the optimal set of mtrrs? + * In some cases it is definitely possible to do better. + */ + range_startk = 0; + range_sizek = 0; + reg = 0; + for (memp = mem; memp->sizek; memp++) { + /* See if I can merge with the last range + * Either I am below 1M and the fixed mtrrs handle it, or + * the ranges touch. + */ + if ((memp->basek <= 1024) || (range_startk + range_sizek == memp->basek)) { + unsigned long endk = memp->basek + memp->sizek; + range_sizek = endk - range_startk; + continue; + } + /* Write the range mtrrs */ + if (range_sizek != 0) { + reg = range_to_mtrr(reg, range_startk, range_sizek, memp->basek); + range_startk = 0; + range_sizek = 0; + if (reg >= BIOS_MTRRS) + break; + } + /* Allocate an msr */ + range_startk = memp->basek; + range_sizek = memp->sizek; + } + /* Write the last range */ + reg = range_to_mtrr(reg, range_startk, range_sizek, 0); + printk_debug("DONE variable MTRRs\n"); + printk_debug("Clear out the extra MTRR's\n"); + /* Clear out the extra MTRR's */ + while(reg < MTRRS) { + intel_set_var_mtrr(reg++, 0, 0, 0); + } + /* enable fixed MTRR */ + printk_debug("call intel_enable_fixed_mtrr()\n"); + intel_enable_fixed_mtrr(); + printk_debug("call intel_enable_var_mtrr()\n"); + intel_enable_var_mtrr(); + printk_debug("Leave %s\n", __FUNCTION__); +} diff --git a/src/devices/device.c b/src/devices/device.c new file mode 100644 index 0000000000..ffc7253389 --- /dev/null +++ b/src/devices/device.c @@ -0,0 +1,423 @@ +/* + * (c) 1999--2000 Martin Mares <mj@suse.cz> + * (c) 2003 Eric Biederman <ebiederm@xmission.com> + */ +/* lots of mods by ron minnich (rminnich@lanl.gov), with + * the final architecture guidance from Tom Merritt (tjm@codegen.com) + * In particular, we changed from the one-pass original version to + * Tom's recommended multiple-pass version. I wasn't sure about doing + * it with multiple passes, until I actually started doing it and saw + * the wisdom of Tom's recommendations ... + * + * Lots of cleanups by Eric Biederman to handle bridges, and to + * handle resource allocation for non-pci devices. + */ + +#include <console/console.h> +#include <bitops.h> +#include <device.h> +#include <arch/io.h> +#include <pci.h> + +/** + * This is the root of the device tree. A PCI tree always has + * one bus, bus 0. Bus 0 contains devices and bridges. + */ +struct device dev_root; +/* Linked list of ALL devices */ +struct device *all_devices = 0; +/* pointer to the last device */ +static struct device **last_dev_p = &all_devices; + +#define DEVICE_MEM_HIGH 0xFEC00000UL /* Reserve 20M for the system */ +#define DEVICE_IO_START 0x1000 + + +unsigned long device_memory_base; + + +/* Append a new device to the global device chain. + * The chain is used to find devices once everything is set up. + */ +void append_device(struct device *dev) +{ + *last_dev_p = dev; + last_dev_p = &dev->next; +} + + +/** round a number to an alignment. + * @param val the starting value + * @param roundup Alignment as a power of two + * @returns rounded up number + */ +static unsigned long round(unsigned long val, unsigned long roundup) +{ + /* ROUNDUP MUST BE A POWER OF TWO. */ + unsigned long inverse; + inverse = ~(roundup - 1); + val += (roundup - 1); + val &= inverse; + return val; +} + +static unsigned long round_down(unsigned long val, unsigned long round_down) +{ + /* ROUND_DOWN MUST BE A POWER OF TWO. */ + unsigned long inverse; + inverse = ~(round_down - 1); + val &= inverse; + return val; +} + + +/** Read the resources on all devices of a given bus. + * @param bus bus to read the resources on. + */ +static void read_resources(struct device *bus) +{ + struct device *curdev; + + + /* Walk through all of the devices and find which resources they need. */ + for(curdev = bus->children; curdev; curdev = curdev->sibling) { + if (curdev->resources > 0) { + continue; + } + curdev->ops->read_resources(curdev); + } +} + +static struct device *largest_resource(struct device *bus, struct resource **result_res, + unsigned long type_mask, unsigned long type) +{ + struct device *curdev; + struct device *result_dev = 0; + struct resource *last = *result_res; + struct resource *result = 0; + int seen_last = 0; + for(curdev = bus->children; curdev; curdev = curdev->sibling) { + int i; + for(i = 0; i < curdev->resources; i++) { + struct resource *resource = &curdev->resource[i]; + /* If it isn't the right kind of resource ignore it */ + if ((resource->flags & type_mask) != type) { + continue; + } + /* Be certain to pick the successor to last */ + if (resource == last) { + seen_last = 1; + continue; + } + if (last && ( + (last->align < resource->align) || + ((last->align == resource->align) && + (last->size < resource->size)) || + ((last->align == resource->align) && + (last->size == resource->size) && + (!seen_last)))) { + continue; + } + if (!result || + (result->align < resource->align) || + ((result->align == resource->align) && + (result->size < resource->size))) { + result_dev = curdev; + result = resource; + } + } + } + *result_res = result; + return result_dev; +} + +/* Compute allocate resources is the guts of the resource allocator. + * + * The problem. + * - Allocate resources locations for every device. + * - Don't overlap, and follow the rules of bridges. + * - Don't overlap with resources in fixed locations. + * - Be efficient so we don't have ugly strategies. + * + * The strategy. + * - Devices that have fixed addresses are the minority so don't + * worry about them too much. Instead only use part of the address + * space for devices with programmable addresses. This easily handles + * everything except bridges. + * + * - PCI devices are required to have thier sizes and their alignments + * equal. In this case an optimal solution to the packing problem + * exists. Allocate all devices from highest alignment to least + * alignment or vice versa. Use this. + * + * - So we can handle more than PCI run two allocation passes on + * bridges. The first to see how large the resources are behind + * the bridge, and what their alignment requirements are. The + * second to assign a safe address to the devices behind the + * bridge. This allows me to treat a bridge as just a device with + * a couple of resources, and not need to special case it in the + * allocator. Also this allows handling of other types of bridges. + * + */ + +void compute_allocate_resource( + struct device *bus, + struct resource *bridge, + unsigned long type_mask, + unsigned long type) +{ + struct device *dev; + struct resource *resource; + unsigned long base; + unsigned long align, min_align; + min_align = 0; + base = bridge->base; + + /* We want different minimum alignments for different kinds of + * resources. These minimums are not device type specific + * but resource type specific. + */ + if (bridge->flags & IORESOURCE_IO) { + min_align = log2(DEVICE_IO_ALIGN); + } + if (bridge->flags & IORESOURCE_MEM) { + min_align = log2(DEVICE_MEM_ALIGN); + } + + printk_spew("DEV: %02x:%02x.%01x compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d\n", + bus->bus->secondary, + PCI_SLOT(bus->devfn), PCI_FUNC(bus->devfn), + (bridge->flags & IORESOURCE_IO)? "io": + (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem", + base, bridge->size, bridge->align, bridge->gran); + + /* Make certain I have read in all of the resources */ + read_resources(bus); + + /* Remember I haven't found anything yet. */ + resource = 0; + + /* Walk through all the devices on the current bus and compute the addresses */ + while((dev = largest_resource(bus, &resource, type_mask, type))) { + unsigned long size; + /* Do NOT I repeat do not ignore resources which have zero size. + * If they need to be ignored dev->read_resources should not even + * return them. Some resources must be set even when they have + * no size. PCI bridge resources are a good example of this. + */ + + /* Propogate the resource alignment to the bridge register */ + if (resource->align > bridge->align) { + bridge->align = resource->align; + } + + /* Make certain we are dealing with a good minimum size */ + size = resource->size; + align = resource->align; + if (align < min_align) { + align = min_align; + } + if (resource->flags & IORESOURCE_IO) { + /* Don't allow potential aliases over the + * legacy pci expansion card addresses. + */ + if ((base > 0x3ff) && ((base & 0x300) != 0)) { + base = (base & ~0x3ff) + 0x400; + } + /* Don't allow allocations in the VGA IO range. + * PCI has special cases for that. + */ + else if ((base >= 0x3b0) && (base <= 0x3df)) { + base = 0x3e0; + } + } + if (((round(base, 1UL << align) + size) -1) <= resource->limit) { + /* base must be aligned to size */ + base = round(base, 1UL << align); + resource->base = base; + resource->flags |= IORESOURCE_SET; + base += size; + + printk_spew( + "DEV: %02x:%02x.%01x %02x * [0x%08lx - 0x%08lx] %s\n", + dev->bus->secondary, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + resource->index, + resource->base, resource->base + resource->size -1, + (resource->flags & IORESOURCE_IO)? "io": + (resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem"); + } + + } + /* A pci bridge resource does not need to be a power + * of two size, but it does have a minimum granularity. + * Round the size up to that minimum granularity so we + * know not to place something else at an address postitively + * decoded by the bridge. + */ + bridge->size = round(base, 1UL << bridge->gran) - bridge->base; + + printk_spew("DEV: %02x:%02x.%01x compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d done\n", + bus->bus->secondary, + PCI_SLOT(bus->devfn), PCI_FUNC(bus->devfn), + (bridge->flags & IORESOURCE_IO)? "io": + (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem", + base, bridge->size, bridge->align, bridge->gran); + + +} + +static void allocate_vga_resource(void) +{ + /* FIXME handle the VGA pallette snooping */ + struct device *dev, *vga, *bus; + bus = vga = 0; + for(dev = all_devices; dev; dev = dev->next) { + uint32_t class_revision; + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_revision); + if (((class_revision >> 24) == 0x03) && + ((class_revision >> 16) != 0x380)) { + if (!vga) { + printk_debug("Allocating VGA resource\n"); + vga = dev; + } + if (vga == dev) { + /* All legacy VGA cards have MEM & I/O space registers */ + dev->command |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO; + } else { + /* It isn't safe to enable other VGA cards */ + dev->command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO); + } + } + } + if (vga) { + bus = vga->bus; + } + /* Now walk up the bridges setting the VGA enable */ + while(bus) { + uint16_t ctrl; + pci_read_config_word(bus, PCI_BRIDGE_CONTROL, &ctrl); + ctrl |= PCI_BRIDGE_CTL_VGA; + pci_write_config_word(bus, PCI_BRIDGE_CONTROL, ctrl); + bus = (bus == bus->bus)? 0 : bus->bus; + } +} + + +/** Assign the computed resources to the bridges and devices on the bus. + * Recurse to any bridges found on this bus first. Then do the devices + * on this bus. + * @param bus Pointer to the structure for this bus + */ +void assign_resources(struct device *bus) +{ + struct device *curdev; + + printk_debug("ASSIGN RESOURCES, bus %d\n", bus->secondary); + + for (curdev = bus->children; curdev; curdev = curdev->sibling) { + curdev->ops->set_resources(curdev); + } + printk_debug("ASSIGNED RESOURCES, bus %d\n", bus->secondary); +} + +static void enable_resources(struct device *bus) +{ + struct device *curdev; + + /* Walk through the chain of all pci devices and enable them. + * This is effectively a breadth first traversal so we should + * not have enalbing ordering problems. + */ + for (curdev = all_devices; curdev; curdev = curdev->next) { + uint16_t command; + pci_read_config_word(curdev, PCI_COMMAND, &command); + command |= curdev->command; + printk_debug("DEV: %02x:%02x.%01x cmd <- %02x\n", + curdev->bus->secondary, + PCI_SLOT(curdev->devfn), PCI_FUNC(curdev->devfn), + command); + pci_write_config_word(curdev, PCI_COMMAND, command); + } +} + +/** Enumerate the resources on the PCI by calling pci_init + */ +void dev_enumerate(void) +{ + struct device *root; + printk_info("Enumerating buses..."); + root = &dev_root; + if (!root->ops) { + root->ops = &default_pci_ops_root; + } + root->subordinate = root->ops->scan_bus(root, 0); + printk_info("done\n"); +} + +/** Starting at the root, compute what resources are needed and allocate them. + * I/O starts at PCI_IO_START. Since the assignment is hierarchical we + * set the values into the dev_root struct. + */ +void dev_configure(void) +{ + struct device *root = &dev_root; + printk_info("Allocating resources..."); + printk_debug("\n"); + + + root->ops->read_resources(root); + + /* Make certain the io devices are allocated somewhere + * safe. + */ + root->resource[0].base = DEVICE_IO_START; + root->resource[0].flags |= IORESOURCE_SET; + /* Now reallocate the pci resources memory with the + * highest addresses I can manage. + */ + root->resource[1].base = + round_down(DEVICE_MEM_HIGH - root->resource[1].size, + 1UL << root->resource[1].align); + device_memory_base = root->resource[1].base; + root->resource[1].flags |= IORESOURCE_SET; + // now just set things into registers ... we hope ... + root->ops->set_resources(root); + + allocate_vga_resource(); + + printk_info("done.\n"); +} + +/** Starting at the root, walk the tree and enable all devices/bridges. + * What really happens is computed COMMAND bits get set in register 4 + */ +void dev_enable(void) +{ + printk_info("Enabling resourcess..."); + + /* now enable everything. */ + enable_resources(&dev_root); + printk_info("done.\n"); +} + +/** Starting at the root, walk the tree and call a driver to + * do device specific setup. + */ +void dev_initialize(void) +{ + struct device *dev; + + printk_info("Initializing devices...\n"); + for (dev = all_devices; dev; dev = dev->next) { + if (dev->ops->init) { + printk_debug("PCI: %02x:%02x.%01x init\n", + dev->bus->secondary, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + dev->ops->init(dev); + } + } + printk_info("Devices initialized\n"); +} + + diff --git a/src/devices/device_util.c b/src/devices/device_util.c new file mode 100644 index 0000000000..fdaa20d966 --- /dev/null +++ b/src/devices/device_util.c @@ -0,0 +1,56 @@ +#include <console/console.h> +#include <device.h> + +/** + * Given a bus and a devfn number, find the device structure + * @param bus The bus number + * @param devfn a device/function number + * @return pointer to the device structure + */ +struct device *dev_find_slot(unsigned int bus, unsigned int devfn) +{ + struct device *dev; + + for (dev = all_devices; dev; dev = dev->next) + if (dev->bus->secondary == bus && dev->devfn == devfn) + break; + return dev; +} + +/** Find a device of a given vendor and type + * @param vendor Vendor ID (e.g. 0x8086 for Intel) + * @param device Device ID + * @param from Pointer to the device structure, used as a starting point + * in the linked list of all_devices, which can be 0 to start at the + * head of the list (i.e. all_devices) + * @return Pointer to the device struct + */ +struct device *dev_find_device(unsigned int vendor, unsigned int device, struct device *from) +{ + if (!from) + from = all_devices; + else + from = from->next; + while (from && (from->vendor != vendor || from->device != device)) + from = from->next; + return from; +} + +/** Find a device of a given class + * @param class Class of the device + * @param from Pointer to the device structure, used as a starting point + * in the linked list of all_devices, which can be 0 to start at the + * head of the list (i.e. all_devices) + * @return Pointer to the device struct + */ +struct device *dev_find_class(unsigned int class, struct device *from) +{ + if (!from) + from = all_devices; + else + from = from->next; + while (from && from->class != class) + from = from->next; + return from; +} + diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c new file mode 100644 index 0000000000..2b309a9ae1 --- /dev/null +++ b/src/devices/pci_device.c @@ -0,0 +1,670 @@ +/* + * PCI Bus Services, see include/linux/pci.h for further explanation. + * + * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, + * David Mosberger-Tang + * + * Copyright 1997 -- 1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz> + * + * Copyright 2003 -- Eric Biederman <ebiederman@lnxi.com> + */ + +#include <console/console.h> +#include <stdlib.h> +#include <stdint.h> +#include <bitops.h> +#include <pci.h> +#include <pci_ids.h> +#include <string.h> + +static unsigned int pci_scan_bridge(struct device *bus, unsigned int max); + +/** Given a device and register, read the size of the BAR for that register. + * @param dev Pointer to the device structure + * @param resource Pointer to the resource structure + * @param index Address of the pci configuration register + */ +static void pci_get_resource(struct device *dev, struct resource *resource, unsigned long index) +{ + uint32_t addr, size, base; + unsigned long type; + + /* Initialize the resources to nothing */ + resource->base = 0; + resource->size = 0; + resource->align = 0; + resource->gran = 0; + resource->limit = 0; + resource->flags = 0; + resource->index = index; + + pci_read_config_dword(dev, index, &addr); + if (addr == 0xffffffffUL) + return; + + /* FIXME: more consideration for 64-bit PCI devices, + * we currently detect their size but otherwise + * treat them as 32-bit resources + */ + /* get the size */ + pci_write_config_dword(dev, index, ~0); + pci_read_config_dword(dev, index, &size); + + /* get the minimum value the bar can be set to */ + pci_write_config_dword(dev, index, 0); + pci_read_config_dword(dev, index, &base); + + /* restore addr */ + pci_write_config_dword(dev, index, addr); + + /* + * some broken hardware has read-only registers that do not + * really size correctly. You can tell this if addr == size + * Example: the acer m7229 has BARs 1-4 normally read-only. + * so BAR1 at offset 0x10 reads 0x1f1. If you size that register + * by writing 0xffffffff to it, it will read back as 0x1f1 -- a + * violation of the spec. + * We catch this case and ignore it by settting size and type to 0. + * This incidentally catches the common case where registers + * read back as 0 for both address and size. + */ + if ((addr == size) && (addr == base)) { + if (size != 0) { + printk_debug( + "PCI: %02x:%02x.%01x register %02x(%08x), read-only ignoring it\n", + dev->bus->secondary, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + index, addr); + } + resource->flags = 0; + } + /* Now compute the actual size, See PCI Spec 6.2.5.1 ... */ + else if (size & PCI_BASE_ADDRESS_SPACE_IO) { + type = size & (~PCI_BASE_ADDRESS_IO_MASK); + /* BUG! Top 16 bits can be zero (or not) + * So set them to 0xffff so they go away ... + */ + resource->size = (~((size | 0xffff0000) & PCI_BASE_ADDRESS_IO_MASK)) +1; + resource->align = log2(resource->size); + resource->gran = resource->align; + resource->flags = IORESOURCE_IO; + resource->limit = 0xffff; + } + else { + /* A Memory mapped base address */ + type = size & (~PCI_BASE_ADDRESS_MEM_MASK); + resource->size = (~(size &PCI_BASE_ADDRESS_MEM_MASK)) +1; + resource->align = log2(resource->size); + resource->gran = resource->align; + resource->flags = IORESOURCE_MEM; + if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { + resource->flags |= IORESOURCE_PREFETCH; + } + type &= PCI_BASE_ADDRESS_MEM_TYPE_MASK; + if (type == PCI_BASE_ADDRESS_MEM_TYPE_32) { + /* 32bit limit */ + resource->limit = 0xffffffffUL; + } + else if (type == PCI_BASE_ADDRESS_MEM_TYPE_1M) { + /* 1MB limit */ + resource->limit = 0x000fffffUL; + } + else if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) { + unsigned long index_hi; + /* 64bit limit + * For now just treat this as a 32bit limit + */ + index_hi = index + 4; + resource->limit = 0xffffffffUL; + resource->flags |= IORESOURCE_PCI64; + pci_read_config_dword( dev, index_hi, &addr); + /* get the extended size */ + pci_write_config_dword(dev, index_hi, 0xffffffffUL); + pci_read_config_dword( dev, index_hi, &size); + + /* get the minimum value the bar can be set to */ + pci_write_config_dword(dev, index_hi, 0); + pci_read_config_dword(dev, index_hi, &base); + + /* restore addr */ + pci_write_config_dword(dev, index_hi, addr); + + if ((size == 0xffffffff) && (base == 0)) { + /* Clear the top half of the bar */ + pci_write_config_dword(dev, index_hi, 0); + } + else { + printk_err("PCI: %02x:%02x.%01x Unable to handle 64-bit address\n", + dev->bus->secondary, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + resource->flags = IORESOURCE_PCI64; + } + } + else { + /* Invalid value */ + resource->flags = 0; + } + } + /* dev->size holds the flags... */ + return; +} + +/** Read the base address registers for a given device. + * @param dev Pointer to the dev structure + * @param howmany How many registers to read (6 for device, 2 for bridge) + */ +static void pci_read_bases(struct device *dev, unsigned int howmany) +{ + unsigned int reg; + unsigned long index; + + reg = dev->resources; + for(index = PCI_BASE_ADDRESS_0; + (reg < MAX_RESOURCES) && (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) { + struct resource *resource; + resource = &dev->resource[reg]; + pci_get_resource(dev, resource, index); + reg += (resource->flags & (IORESOURCE_IO | IORESOURCE_MEM))? 1:0; + index += (resource->flags & IORESOURCE_PCI64)?8:4; + } + dev->resources = reg; +} + + +static void pci_bridge_read_bases(struct device *dev) +{ + unsigned int reg = dev->resources; + + /* FIXME handle bridges without some of the optional resources */ + + /* Initialize the io space constraints on the current bus */ + dev->resource[reg].base = 0; + dev->resource[reg].size = 0; + dev->resource[reg].align = log2(PCI_IO_BRIDGE_ALIGN); + dev->resource[reg].gran = log2(PCI_IO_BRIDGE_ALIGN); + dev->resource[reg].limit = 0xffffUL; + dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_PCI_BRIDGE; + dev->resource[reg].index = PCI_IO_BASE; + compute_allocate_resource(dev, &dev->resource[reg], + IORESOURCE_IO, IORESOURCE_IO); + reg++; + + /* Initiliaze the prefetchable memory constraints on the current bus */ + dev->resource[reg].base = 0; + dev->resource[reg].size = 0; + dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN); + dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN); + dev->resource[reg].limit = 0xffffffffUL; + dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE; + dev->resource[reg].index = PCI_PREF_MEMORY_BASE; + compute_allocate_resource(dev, &dev->resource[reg], + IORESOURCE_MEM | IORESOURCE_PREFETCH, + IORESOURCE_MEM | IORESOURCE_PREFETCH); + reg++; + + /* Initialize the memory resources on the current bus */ + dev->resource[reg].base = 0; + dev->resource[reg].size = 0; + dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN); + dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN); + dev->resource[reg].limit = 0xffffffffUL; + dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE; + dev->resource[reg].index = PCI_MEMORY_BASE; + compute_allocate_resource(dev, &dev->resource[reg], + IORESOURCE_MEM | IORESOURCE_PREFETCH, + IORESOURCE_MEM); + reg++; + + dev->resources = reg; +} + + +static void pci_dev_read_resources(struct device *dev) +{ + uint32_t addr; + dev->resources = 0; + memset(&dev->resource[0], 0, sizeof(dev->resource)); + pci_read_bases(dev, 6); + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &addr); + dev->rom_address = (addr == 0xffffffff)? 0 : addr; +} + +static void pci_bus_read_resources(struct device *dev) +{ + uint32_t addr; + dev->resources = 0; + memset(&dev->resource[0], 0, sizeof(dev->resource)); + pci_bridge_read_bases(dev); + pci_read_bases(dev, 2); + + pci_read_config_dword(dev, PCI_ROM_ADDRESS1, &addr); + dev->rom_address = (addr == 0xffffffff)? 0 : addr; + +} + + +static void pci_set_resource(struct device *dev, struct resource *resource) +{ + unsigned long base, limit; + unsigned long bridge_align = PCI_MEM_BRIDGE_ALIGN; + unsigned char buf[10]; + + /* Make certain the resource has actually been set */ + if (!(resource->flags & IORESOURCE_SET)) { +#if 1 + printk_err("ERROR: %02x:%02x.%01x %02x not allocated\n", + dev->bus->secondary, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + resource->index); +#endif + return; + } + + /* Only handle PCI memory and IO resources for now */ + if (!(resource->flags & (IORESOURCE_MEM |IORESOURCE_IO))) + return; + + if (resource->flags & IORESOURCE_MEM) { + dev->command |= PCI_COMMAND_MEMORY; + bridge_align = PCI_MEM_BRIDGE_ALIGN; + } + if (resource->flags & IORESOURCE_IO) { + dev->command |= PCI_COMMAND_IO; + bridge_align = PCI_IO_BRIDGE_ALIGN; + } + if (resource->flags & IORESOURCE_PCI_BRIDGE) { + dev->command |= PCI_COMMAND_MASTER; + } + /* Get the base address */ + base = resource->base; + + /* Get the limit (rounded up) */ + limit = base + ((resource->size + bridge_align - 1UL) & ~(bridge_align -1)) -1UL; + + if (!(resource->flags & IORESOURCE_PCI_BRIDGE)) { + /* + * some chipsets allow us to set/clear the IO bit. + * (e.g. VIA 82c686a.) So set it to be safe) + */ + limit = base + resource->size -1; + if (resource->flags & IORESOURCE_IO) { + base |= PCI_BASE_ADDRESS_SPACE_IO; + } + pci_write_config_dword(dev, resource->index, base & 0xffffffff); + if (resource->flags & IORESOURCE_PCI64) { + /* FIXME handle real 64bit base addresses */ + pci_write_config_dword(dev, resource->index + 4, 0); + } + } + else if (resource->index == PCI_IO_BASE) { + /* set the IO ranges + * WARNING: we don't really do 32-bit addressing for IO yet! + */ + compute_allocate_resource(dev, resource, + IORESOURCE_IO, IORESOURCE_IO); + pci_write_config_byte(dev, PCI_IO_BASE, base >> 8); + pci_write_config_byte(dev, PCI_IO_LIMIT, limit >> 8); + } + else if (resource->index == PCI_MEMORY_BASE) { + /* set the memory range + */ + compute_allocate_resource(dev, resource, + IORESOURCE_MEM | IORESOURCE_PREFETCH, + IORESOURCE_MEM); + pci_write_config_word(dev, PCI_MEMORY_BASE, base >> 16); + pci_write_config_word(dev, PCI_MEMORY_LIMIT, limit >> 16); + } + else if (resource->index == PCI_PREF_MEMORY_BASE) { + /* set the prefetchable memory range + * WARNING: we don't really do 64-bit addressing for prefetchable memory yet! + */ + compute_allocate_resource(dev, resource, + IORESOURCE_MEM | IORESOURCE_PREFETCH, + IORESOURCE_MEM | IORESOURCE_PREFETCH); + pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, base >> 16); + pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, limit >> 16); + } + else { + printk_err("ERROR: invalid resource->index %x\n", + resource->index); + } + buf[0] = '\0'; + if (resource->flags & IORESOURCE_PCI_BRIDGE) { + sprintf(buf, "bus %d ", dev->secondary); + } + + printk_debug( + "PCI: %02x:%02x.%01x %02x <- [0x%08lx - 0x%08lx] %s%s\n", + dev->bus->secondary, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + resource->index, + resource->base, limit, + buf, + (resource->flags & IORESOURCE_IO)? "io": + (resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem"); + return; +} + +static void pci_dev_set_resources(struct device *dev) +{ + struct resource *resource, *last; + uint8_t line; + + last = &dev->resource[dev->resources]; + + for(resource = &dev->resource[0]; resource < last; resource++) { + pci_set_resource(dev, resource); + } + if (dev->children) { + assign_resources(dev); + } + + /* set a default latency timer */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); + + /* set a default secondary latency timer */ + if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) { + pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40); + } + + /* zero the irq settings */ + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &line); + if (line) { + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 0); + } + /* set the cache line size, so far 64 bytes is good for everyone */ + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 >> 2); +} + +struct device_operations default_pci_ops_dev = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .init = 0, + .scan_bus = 0, +}; +struct device_operations default_pci_ops_bus = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .init = 0, + .scan_bus = pci_scan_bridge, +}; +static void set_pci_ops(struct device *dev) +{ + struct pci_driver *driver; + if (dev->ops) { + return; + } + /* Look through the list of setup drivers and find one for + * this pci device + */ + for(driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) { + if ((driver->vendor == dev->vendor) && + (driver->device = dev->device)) { + dev->ops = driver->ops; + break; + } + } + /* If I don't have a specific driver use the default operations */ + switch(dev->hdr_type & 0x7f) { /* header type */ + case PCI_HEADER_TYPE_NORMAL: /* standard header */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + goto bad; + dev->ops = &default_pci_ops_dev; + break; + case PCI_HEADER_TYPE_BRIDGE: + if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) + goto bad; + dev->ops = &default_pci_ops_bus; + break; + default: + bad: + printk_err("PCI: %02x:%02x.%01x [%04x/%04x/%06x] has unknown header " + "type %02x, ignoring.\n", + dev->bus->secondary, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + dev->vendor, dev->device, + dev->class >> 8, dev->hdr_type); + } + return; +} + +/** + * Given a bus and a devfn number, find the device structure + * @param bus The bus structure + * @param devfn a device/function number + * @return pointer to the device structure + */ +static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn) +{ + struct device *dev = 0; + for(; *list; list = &(*list)->sibling) { + if ((*list)->devfn == devfn) { + /* Unlink from the list */ + dev = *list; + *list = (*list)->sibling; + dev->sibling = 0; + break; + } + } + return dev; +} + + +/** Scan the pci bus devices and bridges. + * @param pci_bus pointer to the bus structure + * @param max current bus number + * @return The maximum bus number found, after scanning all subordinate busses + */ +unsigned int pci_scan_bus(struct device *bus, unsigned int max) +{ + unsigned int devfn; + struct device *dev, **bus_last; + struct device *old_devices; + struct device *child; + + printk_debug("PCI: pci_scan_bus for bus %d\n", bus->secondary); + + old_devices = bus->children; + bus->children = 0; + bus_last = &bus->children; + + post_code(0x24); + + + /* probe all devices on this bus with some optimization for non-existance and + single funcion devices */ + for (devfn = 0; devfn < 0xff; devfn++) { + struct device dummy; + uint32_t id, class; + uint8_t cmd, tmp, hdr_type; + + /* First thing setup the device structure */ + dev = pci_scan_get_dev(&old_devices, devfn); + + dummy.bus = bus; + dummy.devfn = devfn; + pci_read_config_dword(&dummy, PCI_VENDOR_ID, &id); + /* some broken boards return 0 if a slot is empty: */ + if (!dev && + (id == 0xffffffff || id == 0x00000000 || + id == 0x0000ffff || id == 0xffff0000)) { + printk_spew("PCI: devfn 0x%x, bad id 0x%x\n", devfn, id); + if (PCI_FUNC(devfn) == 0x00) { + /* if this is a function 0 device and it is not present, + skip to next device */ + devfn += 0x07; + } + /* multi function device, skip to next function */ + continue; + } + pci_read_config_byte(&dummy, PCI_HEADER_TYPE, &hdr_type); + pci_read_config_dword(&dummy, PCI_CLASS_REVISION, &class); + + if (!dev) { + if ((dev = malloc(sizeof(*dev))) == 0) { + printk_err("PCI: out of memory.\n"); + continue; + } + memset(dev, 0, sizeof(*dev)); + } + + dev->bus = bus; + dev->devfn = devfn; + dev->vendor = id & 0xffff; + dev->device = (id >> 16) & 0xffff; + dev->hdr_type = hdr_type; + /* class code, the upper 3 bytes of PCI_CLASS_REVISION */ + dev->class = class >> 8; + + /* non-destructively determine if device can be a master: */ + pci_read_config_byte(dev, PCI_COMMAND, &cmd); + pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); + pci_read_config_byte(dev, PCI_COMMAND, &tmp); + + dev->master = ((tmp & PCI_COMMAND_MASTER) != 0); + pci_write_config_byte(dev, PCI_COMMAND, cmd); + + /* Look at the vendor and device id, or at least the + * header type and class and figure out which set of configuration + * methods to use. + */ + set_pci_ops(dev); + /* Kill the device if we don't have some pci operations for it */ + if (!dev->ops) { + free(dev); + continue; + } + printk_debug("PCI: %02x:%02x.%01x [%04x/%04x]\n", + bus->secondary, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + dev->vendor, dev->device); + + /* Put it into the global device chain. */ + append_device(dev); + + /* Now insert it into the list of devices held by the parent bus. */ + *bus_last = dev; + bus_last = &dev->sibling; + + if (PCI_FUNC(devfn) == 0x00 && (hdr_type & 0x80) != 0x80) { + /* if this is not a multi function device, don't waste time probe + another function. Skip to next device. */ + devfn += 0x07; + } + } + post_code(0x25); + + for(child = bus->children; child; child = child->sibling) { + if (!child->ops->scan_bus) + continue; + max = child->ops->scan_bus(child, max); + + } + /* + * We've scanned the bus and so we know all about what's on + * the other side of any bridges that may be on this bus plus + * any devices. + * + * Return how far we've got finding sub-buses. + */ + printk_debug("PCI: pci_scan_bus returning with max=%02x\n", max); + post_code(0x55); + return max; +} + +/** Scan the bus, first for bridges and next for devices. + * @param pci_bus pointer to the bus structure + * @return The maximum bus number found, after scanning all subordinate busses + */ +static unsigned int pci_scan_bridge(struct device *bus, unsigned int max) +{ + uint32_t buses; + uint16_t cr; + /* Set up the primary, secondary and subordinate bus numbers. We have + * no idea how many buses are behind this bridge yet, so we set the + * subordinate bus number to 0xff for the moment + */ + bus->secondary = ++max; + bus->subordinate = 0xff; + + /* Clear all status bits and turn off memory, I/O and master enables. */ + pci_read_config_word(bus, PCI_COMMAND, &cr); + pci_write_config_word(bus, PCI_COMMAND, 0x0000); + pci_write_config_word(bus, PCI_STATUS, 0xffff); + + /* + * Read the existing primary/secondary/subordinate bus + * number configuration. + */ + pci_read_config_dword(bus, PCI_PRIMARY_BUS, &buses); + + /* Configure the bus numbers for this bridge: the configuration + * transactions will not be propagated by the bridge if it is not + * correctly configured + */ + buses &= 0xff000000; + buses |= (((unsigned int) (bus->bus->secondary) << 0) | + ((unsigned int) (bus->secondary) << 8) | + ((unsigned int) (bus->subordinate) << 16)); + pci_write_config_dword(bus, PCI_PRIMARY_BUS, buses); + + /* Now we can scan all subordinate buses i.e. the bus hehind the bridge */ + max = pci_scan_bus(bus, max); + + /* We know the number of buses behind this bridge. Set the subordinate + * bus number to its real value + */ + bus->subordinate = max; + buses = (buses & 0xff00ffff) | + ((unsigned int) (bus->subordinate) << 16); + pci_write_config_dword(bus, PCI_PRIMARY_BUS, buses); + pci_write_config_word(bus, PCI_COMMAND, cr); + + return max; +} + + +static void pci_root_read_resources(struct device *bus) +{ + int res = 0; + /* Initialize the system wide io space constraints */ + bus->resource[res].base = 0x400; + bus->resource[res].size = 0; + bus->resource[res].align = 0; + bus->resource[res].gran = 0; + bus->resource[res].limit = 0xffffUL; + bus->resource[res].flags = IORESOURCE_IO; + bus->resource[res].index = PCI_IO_BASE; + compute_allocate_resource(bus, &bus->resource[res], + IORESOURCE_IO, IORESOURCE_IO); + res++; + + /* Initialize the system wide memory resources constraints */ + bus->resource[res].base = 0; + bus->resource[res].size = 0; + bus->resource[res].align = 0; + bus->resource[res].gran = 0; + bus->resource[res].limit = 0xffffffffUL; + bus->resource[res].flags = IORESOURCE_MEM; + bus->resource[res].index = PCI_MEMORY_BASE; + compute_allocate_resource(bus, &bus->resource[res], + IORESOURCE_MEM, IORESOURCE_MEM); + res++; + + bus->resources = res; +} +static void pci_root_set_resources(struct device *bus) +{ + compute_allocate_resource(bus, + &bus->resource[0], IORESOURCE_IO, IORESOURCE_IO); + compute_allocate_resource(bus, + &bus->resource[1], IORESOURCE_MEM, IORESOURCE_MEM); + assign_resources(bus); +} + +struct device_operations default_pci_ops_root = { + .read_resources = pci_root_read_resources, + .set_resources = pci_root_set_resources, + .init = 0, + .scan_bus = pci_scan_bus, +}; + diff --git a/src/include/boot/elf.h b/src/include/boot/elf.h new file mode 100644 index 0000000000..3503388078 --- /dev/null +++ b/src/include/boot/elf.h @@ -0,0 +1,401 @@ +#ifndef ELF_H +#define ELF_H + +/* Standard ELF types. */ + +#include <stdint.h> +#include <stddef.h> +#include <arch/boot/boot.h> + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* Type of symbol indices. */ +typedef uint32_t Elf32_Symndx; +typedef uint64_t Elf64_Symndx; + + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOPROC 0xff00 /* Processor-specific */ +#define ET_HIPROC 0xffff /* Processor-specific */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_486 6 /* Intel 80486 */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* Amdahl */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ +#define EM_RS6000 11 /* RS6000 */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_nCUBE 16 /* nCUBE */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH32 */ +#define EM_MMA 39 /* Fujitsu MMA */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_NUM 54 + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +#define EM_ALPHA 0x9026 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + + +/* Program segment header. */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_NUM 7 /* Number of defined types. */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + + +/* Note section contents. Each entry in the note section begins with + a header of a fixed form. */ + +typedef struct +{ + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +typedef struct +{ + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Known names of notes. */ + +/* Solaris entries in the note section have this name. */ +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +/* Note entries for GNU systems have this name. */ +#define ELF_NOTE_GNU "GNU" + + +/* Defined types of notes for Solaris. */ + +/* Value of descriptor (one word) is desired pagesize for the binary. */ +#define ELF_NOTE_PAGESIZE_HINT 1 + + +/* Defined note types for GNU systems. */ + +/* ABI information. The descriptor consists of words: + word 0: OS descriptor + word 1: major version of the ABI + word 2: minor version of the ABI + word 3: subminor version of the ABI +*/ +#define ELF_NOTE_ABI 1 + +/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI + note section entry. */ +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 + + +/* Motorola 68k specific definitions. */ + +/* Intel 80386 specific definitions. */ + +/* SUN SPARC specific definitions. */ + +/* Values for Elf64_Ehdr.e_flags. */ + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_SUN_US1 0x000200 +#define EF_SPARC_HAL_R1 0x000400 + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ +#define EF_MIPS_PIC 2 /* Contains PIC code */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ + +/* Legal values for MIPS architecture level. */ + +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Special program header types. */ + +#define PF_MIPS_LOCAL 0x10000000 + + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNL 1 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 2 /* Program uses arch. extensions. */ +#define EF_PARISC_ARCH 0xffff0000 /* Architecture version. */ +/* Defined values are: + 0x020b PA-RISC 1.0 big-endian + 0x0210 PA-RISC 1.1 big-endian + 0x028b PA-RISC 1.0 little-endian + 0x0290 PA-RISC 1.1 little-endian +*/ + + +/* Alpha specific definitions. */ + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ +#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ + + +/* PowerPC specific declarations */ + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_NEW_ABI 0x80 +#define EF_OLD_ABI 0x100 + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base */ + +#if ELF_CLASS == ELFCLASS32 +typedef Elf32_Ehdr Elf_ehdr; +typedef Elf32_Phdr Elf_phdr; +#endif + +#if ELF_CLASS == ELFCLASS64 +typedef Elf64_Ehdr Elf_ehdr; +typedef Elf64_Phdr Elf_phdr; +#endif + +extern int elf_check_arch(Elf_ehdr *ehdr); +extern void jmp_to_elf_entry(void *entry, unsigned long buffer); +struct lb_memory; +extern int elfboot(struct lb_memory *mem); + +#define FIRMWARE_TYPE "LinuxBIOS" +#define BOOTLOADER "elfboot" +#define BOOTLOADER_VERSION "1.3" + +#endif /* elf.h */ diff --git a/src/include/boot/elf_boot.h b/src/include/boot/elf_boot.h new file mode 100644 index 0000000000..ee6750d293 --- /dev/null +++ b/src/include/boot/elf_boot.h @@ -0,0 +1,89 @@ +#ifndef ELF_BOOT_H +#define ELF_BOOT_H + +#include <stdint.h> + +/* This defines the structure of a table of parameters useful for ELF + * bootable images. These parameters are all passed and generated + * by the bootloader to the booted image. For simplicity and + * consistency the Elf Note format is reused. + * + * All of the information must be Position Independent Data. + * That is it must be safe to relocate the whole ELF boot parameter + * block without changing the meaning or correctnes of the data. + * Additionally it must be safe to permute the order of the ELF notes + * to any possible permutation without changing the meaning or correctness + * of the data. + * + */ + +#define ELF_HEAD_SIZE (8*1024) +#define ELF_BOOT_MAGIC 0x0E1FB007 + +typedef uint16_t Elf_Half; +typedef uint32_t Elf_Word; +typedef uint64_t Elf_Xword; + +typedef struct +{ + Elf_Word b_signature; /* "0x0E1FB007" */ + Elf_Word b_size; + Elf_Half b_checksum; + Elf_Half b_records; +} Elf_Bhdr; + +typedef struct +{ + Elf_Word n_namesz; /* Length of the note's name. */ + Elf_Word n_descsz; /* Length of the note's descriptor. */ + Elf_Word n_type; /* Type of the note. */ +} Elf_Nhdr; + + +/* For standard notes n_namesz must be zero */ +/* All of the following standard note types provide a single null + * terminated string in the descriptor. + */ +#define EBN_FIRMWARE_TYPE 0x00000001 +/* On platforms that support multiple classes of firmware this field + * specifies the class of firmware you are loaded under. + */ +#define EBN_BOOTLOADER_NAME 0x00000002 +/* This specifies just the name of the bootloader for easy comparison */ +#define EBN_BOOTLOADER_VERSION 0x00000003 +/* This specifies the version of the bootlader */ +#define EBN_COMMAND_LINE 0x00000004 +/* This specifies a command line that can be set by user interaction, + * and is provided as a free form string to the loaded image. + */ + + +/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */ + +#define ELF_NOTE_BOOT "ELFBoot" + +#define EIN_PROGRAM_NAME 0x00000001 +/* The program in this ELF file */ +#define EIN_PROGRAM_VERSION 0x00000002 +/* The version of the program in this ELF file */ +#define EIN_PROGRAM_CHECKSUM 0x00000003 +/* ip style checksum of the memory image. */ + + +/* Linux image notes for booting... The name for all of these is Linux */ + +#define LINUX_NOTE_BOOT "Linux" + +#define LIN_COMMAND_LINE 0x00000001 +/* The command line to pass to the loaded kernel. */ +#define LIN_ROOT_DEV 0x00000002 +/* The root dev to pass to the loaded kernel. */ +#define LIN_RAMDISK_FLAGS 0x00000003 +/* Various old ramdisk flags */ +#define LIN_INITRD_START 0x00000004 +/* Start of the ramdisk in bytes */ +#define LIN_INITRD_SIZE 0x00000005 +/* Size of the ramdisk in bytes */ + + +#endif /* ELF_BOOT_H */ diff --git a/src/include/boot/linuxbios_tables.h b/src/include/boot/linuxbios_tables.h new file mode 100644 index 0000000000..5f37993807 --- /dev/null +++ b/src/include/boot/linuxbios_tables.h @@ -0,0 +1,183 @@ +#ifndef LINUXBIOS_TABLES_H +#define LINUXBIOS_TABLES_H + +#include <stdint.h> + +/* The linuxbios table information is for conveying information + * from the firmware to the loaded OS image. Primarily this + * is expected to be information that cannot be discovered by + * other means, such as quering the hardware directly. + * + * All of the information should be Position Independent Data. + * That is it should be safe to relocated any of the information + * without it's meaning/correctnes changing. For table that + * can reasonably be used on multiple architectures the data + * size should be fixed. This should ease the transition between + * 32 bit and 64 bit architectures etc. + * + * The completeness test for the information in this table is: + * - Can all of the hardware be detected? + * - Are the per motherboard constants available? + * - Is there enough to allow a kernel to run that was written before + * a particular motherboard is constructed? (Assuming the kernel + * has drivers for all of the hardware but it does not have + * assumptions on how the hardware is connected together). + * + * With this test it should be straight forward to determine if a + * table entry is required or not. This should remove much of the + * long term compatibility burden as table entries which are + * irrelevant or have been replaced by better alternatives may be + * dropped. Of course it is polite and expidite to include extra + * table entries and be backwards compatible, but it is not required. + */ + + +struct lb_header +{ + uint8_t signature[4]; /* LBIO */ + uint32_t header_bytes; + uint32_t header_checksum; + uint32_t table_bytes; + uint32_t table_checksum; + uint32_t table_entries; +}; + +/* Every entry in the boot enviroment list will correspond to a boot + * info record. Encoding both type and size. The type is obviously + * so you can tell what it is. The size allows you to skip that + * boot enviroment record if you don't know what it easy. This allows + * forward compatibility with records not yet defined. + */ +struct lb_record { + uint32_t tag; /* tag ID */ + uint32_t size; /* size of record (in bytes) */ +}; + +#define LB_TAG_UNUSED 0x0000 + +#define LB_TAG_MEMORY 0x0001 + +struct lb_memory_range { + uint64_t start; + uint64_t size; + uint32_t type; +#define LB_MEM_RAM 1 /* Memory anyone can use */ +#define LB_MEM_RESERVED 2 /* Don't use this memory region */ +#define LB_MEM_TABLE 16 /* Ram configuration tables are kept in */ + +}; + +struct lb_memory { + uint32_t tag; + uint32_t size; + struct lb_memory_range map[0]; +}; + +#define LB_TAG_HWRPB 0x0002 +struct lb_hwrpb { + uint32_t tag; + uint32_t size; + uint64_t hwrpb; +}; + +#define LB_TAG_MAINBOARD 0x0003 +struct lb_mainboard { + uint32_t tag; + uint32_t size; + uint8_t vendor_idx; + uint8_t part_number_idx; + uint8_t strings[0]; +}; + +#define LB_TAG_VERSION 0x0004 +#define LB_TAG_EXTRA_VERSION 0x0005 +#define LB_TAG_BUILD 0x0006 +#define LB_TAG_COMPILE_TIME 0x0007 +#define LB_TAG_COMPILE_BY 0x0008 +#define LB_TAG_COMPILE_HOST 0x0009 +#define LB_TAG_COMPILE_DOMAIN 0x000a +#define LB_TAG_COMPILER 0x000b +#define LB_TAG_LINKER 0x000c +#define LB_TAG_ASSEMBLER 0x000d +struct lb_string { + uint32_t tag; + uint32_t size; + uint8_t string[0]; +}; + +/* The following structures are for the cmos definitions table */ +#define LB_TAG_CMOS_OPTION_TABLE 200 +/* cmos header record */ +struct cmos_option_table { + uint32_t tag; /* CMOS definitions table type */ + uint32_t size; /* size of the entire table */ + uint32_t header_length; /* length of header */ +}; + +/* cmos entry record + This record is variable length. The name field may be + shorter than CMOS_MAX_NAME_LENGTH. The entry may start + anywhere in the byte, but can not span bytes unless it + starts at the beginning of the byte and the length is + fills complete bytes. +*/ +#define LB_TAG_OPTION 201 +struct cmos_entries { + uint32_t tag; /* entry type */ + uint32_t size; /* length of this record */ + uint32_t bit; /* starting bit from start of image */ + uint32_t length; /* length of field in bits */ + uint32_t config; /* e=enumeration, h=hex, r=reserved */ + uint32_t config_id; /* a number linking to an enumeration record */ +#define CMOS_MAX_NAME_LENGTH 32 + uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name of entry in ascii, + variable length int aligned */ +}; + + +/* cmos enumerations record + This record is variable length. The text field may be + shorter than CMOS_MAX_TEXT_LENGTH. +*/ +#define LB_TAG_OPTION_ENUM 202 +struct cmos_enums { + uint32_t tag; /* enumeration type */ + uint32_t size; /* length of this record */ + uint32_t config_id; /* a number identifying the config id */ + uint32_t value; /* the value associated with the text */ +#define CMOS_MAX_TEXT_LENGTH 32 + uint8_t text[CMOS_MAX_TEXT_LENGTH]; /* enum description in ascii, + variable length int aligned */ +}; + +/* cmos defaults record + This record contains default settings for the cmos ram. +*/ +#define LB_TAG_OPTION_DEFAULTS 203 +struct cmos_defaults { + uint32_t tag; /* default type */ + uint32_t size; /* length of this record */ + uint32_t name_length; /* length of the following name field */ + uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name identifying the default */ +#define CMOS_IMAGE_BUFFER_SIZE 128 + uint8_t default_set[CMOS_IMAGE_BUFFER_SIZE]; /* default settings */ +}; + +#define LB_TAG_OPTION_CHECKSUM 204 +struct cmos_checksum { + uint32_t tag; + uint32_t size; + /* In practice everything is byte aligned, but things are measured + * in bits to be consistent. + */ + uint32_t range_start; /* First bit that is checksummed (byte aligned) */ + uint32_t range_end; /* Last bit that is checksummed (byte aligned) */ + uint32_t location; /* First bit of the checksum (byte aligned) */ + uint32_t type; /* Checksum algorithm that is used */ +#define CHECKSUM_NONE 0 +#define CHECKSUM_PCBIOS 1 +}; + + + +#endif /* LINUXBIOS_TABLES_H */ diff --git a/src/include/boot/tables.h b/src/include/boot/tables.h new file mode 100644 index 0000000000..618c32ef94 --- /dev/null +++ b/src/include/boot/tables.h @@ -0,0 +1,9 @@ +#ifndef BOOT_TABLES_H +#define BOOT_TABLES_H + +#include <mem.h> +#include <boot/linuxbios_tables.h> + +struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_map); + +#endif /* BOOT_TABLES_H */ diff --git a/src/include/console/console.h b/src/include/console/console.h new file mode 100644 index 0000000000..57ba9da268 --- /dev/null +++ b/src/include/console/console.h @@ -0,0 +1,76 @@ +#ifndef CONSOLE_CONSOLE_H_ +#define CONSOLE_CONSOLE_H_ + +#include <stdint.h> +#include <console/loglevel.h> + +void console_init(void); +void console_tx_byte(unsigned char byte); +void console_tx_flush(void); +void post_code(uint8_t value); +void die(char *msg); + +struct console_driver { + void (*init)(void); + void (*tx_byte)(unsigned char byte); + void (*tx_flush)(void); +}; + +#define __console __attribute__((unused, __section__ (".rodata.console_drivers"))) + +/* Defined by the linker... */ +extern struct console_driver console_drivers[]; +extern struct console_driver econsole_drivers[]; + +extern int console_loglevel; +int do_printk(int msg_level, const char *fmt, ...); + +#define printk_emerg(fmt, arg...) do_printk(BIOS_EMERG ,fmt, ##arg) +#define printk_alert(fmt, arg...) do_printk(BIOS_ALERT ,fmt, ##arg) +#define printk_crit(fmt, arg...) do_printk(BIOS_CRIT ,fmt, ##arg) +#define printk_err(fmt, arg...) do_printk(BIOS_ERR ,fmt, ##arg) +#define printk_warning(fmt, arg...) do_printk(BIOS_WARNING ,fmt, ##arg) +#define printk_notice(fmt, arg...) do_printk(BIOS_NOTICE ,fmt, ##arg) +#define printk_info(fmt, arg...) do_printk(BIOS_INFO ,fmt, ##arg) +#define printk_debug(fmt, arg...) do_printk(BIOS_DEBUG ,fmt, ##arg) +#define printk_spew(fmt, arg...) do_printk(BIOS_SPEW ,fmt, ##arg) + +#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_EMERG +#undef printk_emerg +#define printk_emerg(fmt, arg...) do {} while(0) +#endif +#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_ALERT +#undef printk_alert +#define printk_alart(fmt, arg...) do {} while(0) +#endif +#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_CRIT +#undef printk_crit +#define printk_crit(fmt, arg...) do {} while(0) +#endif +#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_ERR +#undef printk_err +#define printk_err(fmt, arg...) do {} while(0) +#endif +#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_WARNING +#undef printk_warning +#define printk_warning(fmt, arg...) do {} while(0) +#endif +#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_NOTICE +#undef printk_notice +#define printk_notice(fmt, arg...) do {} while(0) +#endif +#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_INFO +#undef printk_info +#define printk_info(fmt, arg...) do {} while(0) +#endif +#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_DEBUG +#undef printk_debug +#define printk_debug(fmt, arg...) do {} while(0) +#endif +#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_SPEW +#undef printk_spew +#define printk_spew(fmt, arg...) do {} while(0) +#endif + + +#endif /* CONSOLE_CONSOLE_H_ */ diff --git a/src/include/console/loglevel.h b/src/include/console/loglevel.h new file mode 100644 index 0000000000..a191b308d3 --- /dev/null +++ b/src/include/console/loglevel.h @@ -0,0 +1,30 @@ +#ifndef LOGLEVEL_H +#define LOGLEVEL_H + +/* Safe for inclusion in assembly */ + +#ifndef MAXIMUM_CONSOLE_LOGLEVEL +#define MAXIMUM_CONSOLE_LOGLEVEL 8 +#endif + +#ifndef DEFAULT_CONSOLE_LOGLEVEL +#define DEFAULT_CONSOLE_LOGLEVEL 8 /* anything MORE serious than BIOS_SPEW */ +#endif + +#if (DEFAULT_CONSOLE_LOGLEVEL <= MAXIMUM_CONSOLE_LOGLEVEL) +#define ASM_CONSOLE_LOGLEVEL DEFAULT_CONSOLE_LOGLEVEL +#else +#define ASM_CONSOLE_LOGLEVEL MAXIMUM_CONSOLE_LOGLEVEL +#endif + +#define BIOS_EMERG 0 /* system is unusable */ +#define BIOS_ALERT 1 /* action must be taken immediately */ +#define BIOS_CRIT 2 /* critical conditions */ +#define BIOS_ERR 3 /* error conditions */ +#define BIOS_WARNING 4 /* warning conditions */ +#define BIOS_NOTICE 5 /* normal but significant condition */ +#define BIOS_INFO 6 /* informational */ +#define BIOS_DEBUG 7 /* debug-level messages */ +#define BIOS_SPEW 8 /* Way too many details */ + +#endif /* LOGLEVEL_H */ diff --git a/src/include/cpu/cpu.h b/src/include/cpu/cpu.h new file mode 100644 index 0000000000..208dab055b --- /dev/null +++ b/src/include/cpu/cpu.h @@ -0,0 +1,11 @@ +#ifndef CPU_CPU_H +#define CPU_CPU_H + +#include <mem.h> + +unsigned long cpu_initialize(struct mem_range *mem); +#define CPU_ENABLED 1 /* Processor is available */ +#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */ + + +#endif /* CPU_CPU_H */ diff --git a/src/include/cpu/cpufixup.h b/src/include/cpu/cpufixup.h new file mode 100644 index 0000000000..b23afa510a --- /dev/null +++ b/src/include/cpu/cpufixup.h @@ -0,0 +1,24 @@ +#ifndef CPU_CPUFIXUP_H +#define CPU_CPUFIXUP_H + +struct mem_range; + +#include <cpu/k8/cpufixup.h> +#include <cpu/k7/cpufixup.h> +#include <cpu/p6/cpufixup.h> + +#if CPU_FIXUP == 1 +# if defined(k8) +# define cpufixup(mem) k8_cpufixup(mem) +# elif defined(k7) +# define cpufixup(mem) k7_cpufixup(mem) +# elif defined(i786) +# define cpufixup(mem) i786_cpufixup(mem) +# elif defined(i686) +# define cpufixup(mem) p6_cpufixup(mem) +# endif +#else +# define cpufixup(mem) do {} while(0) +#endif + +#endif /* CPU_CPUFIXUP_H */ diff --git a/src/include/cpu/k7/cpufixup.h b/src/include/cpu/k7/cpufixup.h new file mode 100644 index 0000000000..0e3db3d655 --- /dev/null +++ b/src/include/cpu/k7/cpufixup.h @@ -0,0 +1,6 @@ +#ifndef CPU_K7_CPUFIXUP_H +#define CPU_K7_CPUFIXUP_H + +void k7_cpufixup(struct mem_range *mem); + +#endif /* CPU_K7_CPUFIXUP_H */ diff --git a/src/include/cpu/k7/mtrr.h b/src/include/cpu/k7/mtrr.h new file mode 100644 index 0000000000..ea376da2df --- /dev/null +++ b/src/include/cpu/k7/mtrr.h @@ -0,0 +1,42 @@ +#ifndef CPU_K7_MTRR_H +#define CPU_K7_MTRR_H + +#include <cpu/p6/mtrr.h> + +#define IORR_FIRST 0xC0010016 +#define IORR_LAST 0xC0010019 +#define SYSCFG 0xC0010010 + +#define MTRR_READ_MEM (1 << 4) +#define MTRR_WRITE_MEM (1 << 3) + +#define SYSCFG_MSR 0xC0010010 +#define SYSCFG_MSR_EvictEn (1 << 22) +#define SYSCFG_MSR_TOM2En (1 << 21) +#define SYSCFG_MSR_MtrrVarDramEn (1 << 20) +#define SYSCFG_MSR_MtrrFixDramModEn (1 << 19) +#define SYSCFG_MSR_MtrrFixDramEn (1 << 18) +#define SYSCFG_MSR_UcLockEn (1 << 17) +#define SYSCFG_MSR_ChxToDirtyDis (1 << 16) +#define SYSCFG_MSR_SysEccEn (1 << 15) +#define SYSCFG_MSR_RdBlkL2WayEn (1 << 14) +#define SYSCFG_MSR_SysFillValIsD1 (1 << 13) +#define SYSCFG_MSR_IcInclusive (1 << 12) +#define SYSCFG_MSR_ClVicBlkEn (1 << 11) +#define SYSCFG_MSR_SetDirtyEnO (1 << 10) +#define SYSCFG_MSR_SetDirtyEnS (1 << 9) +#define SYSCFG_MSR_SetDirtyEnE (1 << 8) +#define SYSCFG_MSR_SysVicLimitMask ((1 << 8) - (1 << 5)) +#define SYSCFG_MSR_SysAckLimitMask ((1 << 5) - (1 << 0)) + + + +#define IORR0_BASE 0xC0010016 +#define IORR0_MASK 0xC0010017 +#define IORR1_BASE 0xC0010018 +#define IORR1_MASK 0xC0010019 +#define TOP_MEM 0xC001001A +#define TOP_MEM2 0xC001001D +#define HWCR_MSR 0xC0010015 + +#endif /* CPU_K7_MTRR_H */ diff --git a/src/include/cpu/k8/cpufixup.h b/src/include/cpu/k8/cpufixup.h new file mode 100644 index 0000000000..9500ec216e --- /dev/null +++ b/src/include/cpu/k8/cpufixup.h @@ -0,0 +1,6 @@ +#ifndef CPU_K8_CPUFIXUP_H +#define CPU_K8_CPUFIXUP_H + +void k8_cpufixup(struct mem_range *mem); + +#endif /* CPU_K8_CPUFIXUP_H */ diff --git a/src/include/cpu/k8/mtrr.h b/src/include/cpu/k8/mtrr.h new file mode 100644 index 0000000000..ce9e6d4d04 --- /dev/null +++ b/src/include/cpu/k8/mtrr.h @@ -0,0 +1,45 @@ +#ifndef CPU_K8_MTRR_H +#define CPU_K8_MTRR_H + +#include <cpu/k7/mtrr.h> + +#if 0 +#define IORR_FIRST 0xC0010016 +#define IORR_LAST 0xC0010019 +#define SYSCFG 0xC0010010 + +#define MTRR_READ_MEM (1 << 4) +#define MTRR_WRITE_MEM (1 << 3) + +#define SYSCFG_MSR 0xC0010010 +#define SYSCFG_MSR_EvictEn (1 << 22) +#define SYSCFG_MSR_TOM2En (1 << 21) +#define SYSCFG_MSR_MtrrVarDramEn (1 << 20) +#define SYSCFG_MSR_MtrrFixDramModEn (1 << 19) +#define SYSCFG_MSR_MtrrFixDramEn (1 << 18) +#define SYSCFG_MSR_UcLockEn (1 << 17) +#define SYSCFG_MSR_ChxToDirtyDis (1 << 16) +#define SYSCFG_MSR_SysEccEn (1 << 15) +#define SYSCFG_MSR_RdBlkL2WayEn (1 << 14) +#define SYSCFG_MSR_SysFillValIsD1 (1 << 13) +#define SYSCFG_MSR_IcInclusive (1 << 12) +#define SYSCFG_MSR_ClVicBlkEn (1 << 11) +#define SYSCFG_MSR_SetDirtyEnO (1 << 10) +#define SYSCFG_MSR_SetDirtyEnS (1 << 9) +#define SYSCFG_MSR_SetDirtyEnE (1 << 8) +#define SYSCFG_MSR_SysVicLimitMask ((1 << 8) - (1 << 5)) +#define SYSCFG_MSR_SysAckLimitMask ((1 << 5) - (1 << 0)) + + + +#define IORR0_BASE 0xC0010016 +#define IORR0_MASK 0xC0010017 +#define IORR1_BASE 0xC0010018 +#define IORR1_MASK 0xC0010019 +#define TOP_MEM 0xC001001A +#define TOP_MEM2 0xC001001D +#define HWCR_MSR 0xC0010015 + +#endif + +#endif /* CPU_K8_MTRR_H */ diff --git a/src/include/cpu/p5/cpuid.h b/src/include/cpu/p5/cpuid.h new file mode 100644 index 0000000000..b8ffc88a84 --- /dev/null +++ b/src/include/cpu/p5/cpuid.h @@ -0,0 +1,25 @@ +#ifndef CPU_P5_CPUID_H +#define CPU_P5_CPUID_H + +int mtrr_check(void); +void display_cpuid(void); + +/* + * Generic CPUID function. copied from Linux kernel headers + */ + +static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx) +{ + __asm__("pushl %%ebx\n\t" + "cpuid\n\t" + "movl %%ebx, %%esi\n\t" + "popl %%ebx\n\t" + : "=a" (*eax), + "=S" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "a" (op) + : "cc"); +} + +#endif /* CPU_P5_CPUID_H */ diff --git a/src/include/cpu/p6/apic.h b/src/include/cpu/p6/apic.h new file mode 100644 index 0000000000..b91cdb2a86 --- /dev/null +++ b/src/include/cpu/p6/apic.h @@ -0,0 +1,175 @@ +#ifndef APIC_H +#define APIC_H + +#define APIC_BASE_MSR 0x1B +#define APIC_BASE_MSR_BOOTSTRAP_PROCESSOR (1 << 8) +#define APIC_BASE_MSR_ENABLE (1 << 11) +#define APIC_BASE_MSR_ADDR_MASK 0xFFFFF000 + +#define APIC_DEFAULT_BASE 0xfee00000 + +#define APIC_ID 0x020 +#define APIC_LVR 0x030 +#define APIC_ARBID 0x090 +#define APIC_RRR 0x0C0 +#define APIC_SVR 0x0f0 +#define APIC_SPIV 0x0f0 +#define APIC_SPIV_ENABLE 0x100 +#define APIC_ESR 0x280 +#define APIC_ESR_SEND_CS 0x00001 +#define APIC_ESR_RECV_CS 0x00002 +#define APIC_ESR_SEND_ACC 0x00004 +#define APIC_ESR_RECV_ACC 0x00008 +#define APIC_ESR_SENDILL 0x00020 +#define APIC_ESR_RECVILL 0x00040 +#define APIC_ESR_ILLREGA 0x00080 +#define APIC_ICR 0x300 +#define APIC_DEST_SELF 0x40000 +#define APIC_DEST_ALLINC 0x80000 +#define APIC_DEST_ALLBUT 0xC0000 +#define APIC_ICR_RR_MASK 0x30000 +#define APIC_ICR_RR_INVALID 0x00000 +#define APIC_ICR_RR_INPROG 0x10000 +#define APIC_ICR_RR_VALID 0x20000 +#define APIC_INT_LEVELTRIG 0x08000 +#define APIC_INT_ASSERT 0x04000 +#define APIC_ICR_BUSY 0x01000 +#define APIC_DEST_LOGICAL 0x00800 +#define APIC_DM_FIXED 0x00000 +#define APIC_DM_LOWEST 0x00100 +#define APIC_DM_SMI 0x00200 +#define APIC_DM_REMRD 0x00300 +#define APIC_DM_NMI 0x00400 +#define APIC_DM_INIT 0x00500 +#define APIC_DM_STARTUP 0x00600 +#define APIC_DM_EXTINT 0x00700 +#define APIC_VECTOR_MASK 0x000FF +#define APIC_ICR2 0x310 +#define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF) +#define SET_APIC_DEST_FIELD(x) ((x)<<24) +#define APIC_LVTT 0x320 +#define APIC_LVTPC 0x340 +#define APIC_LVT0 0x350 +#define APIC_LVT_TIMER_BASE_MASK (0x3<<18) +#define GET_APIC_TIMER_BASE(x) (((x)>>18)&0x3) +#define SET_APIC_TIMER_BASE(x) (((x)<<18)) +#define APIC_TIMER_BASE_CLKIN 0x0 +#define APIC_TIMER_BASE_TMBASE 0x1 +#define APIC_TIMER_BASE_DIV 0x2 +#define APIC_LVT_TIMER_PERIODIC (1<<17) +#define APIC_LVT_MASKED (1<<16) +#define APIC_LVT_LEVEL_TRIGGER (1<<15) +#define APIC_LVT_REMOTE_IRR (1<<14) +#define APIC_INPUT_POLARITY (1<<13) +#define APIC_SEND_PENDING (1<<12) +#define APIC_LVT_RESERVED_1 (1<<11) +#define APIC_DELIVERY_MODE_MASK (7<<8) +#define APIC_DELIVERY_MODE_FIXED (0<<8) +#define APIC_DELIVERY_MODE_NMI (4<<8) +#define APIC_DELIVERY_MODE_EXTINT (7<<8) +#define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7) +#define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8)) +#define APIC_MODE_FIXED 0x0 +#define APIC_MODE_NMI 0x4 +#define APIC_MODE_EXINT 0x7 +#define APIC_LVT1 0x360 +#define APIC_LVTERR 0x370 + + +#if !defined(ASSEMBLY) + +#include <console/console.h> + + +#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr)))) + +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((struct __xchg_dummy *)(x)) + +/* + * Note: no "lock" prefix even on SMP: xchg always implies lock anyway + * Note 2: xchg has side effect, so that attribute volatile is necessary, + * but generally the primitive is invalid, *ptr is output argument. --ANK + */ +static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +{ + switch (size) { + case 1: + __asm__ __volatile__("xchgb %b0,%1" + :"=q" (x) + :"m" (*__xg(ptr)), "0" (x) + :"memory"); + break; + case 2: + __asm__ __volatile__("xchgw %w0,%1" + :"=r" (x) + :"m" (*__xg(ptr)), "0" (x) + :"memory"); + break; + case 4: + __asm__ __volatile__("xchgl %0,%1" + :"=r" (x) + :"m" (*__xg(ptr)), "0" (x) + :"memory"); + break; + } + return x; +} + + +static inline unsigned long apic_read(unsigned long reg) +{ + return *((volatile unsigned long *)(APIC_DEFAULT_BASE+reg)); +} + +extern inline void apic_write_atomic(unsigned long reg, unsigned long v) +{ + xchg((volatile unsigned long *)(APIC_DEFAULT_BASE+reg), v); +} + +static inline void apic_write(unsigned long reg, unsigned long v) +{ + *((volatile unsigned long *)(APIC_DEFAULT_BASE+reg)) = v; +} + +static inline void apic_wait_icr_idle(void) +{ + do { } while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY ); +} + +#ifdef CONFIG_X86_GOOD_APIC +# define FORCE_READ_AROUND_WRITE 0 +# define apic_read_around(x) apic_read(x) +# define apic_write_around(x,y) apic_write((x),(y)) +#else +# define FORCE_READ_AROUND_WRITE 1 +# define apic_read_around(x) apic_read(x) +# define apic_write_around(x,y) apic_write_atomic((x),(y)) +#endif + +static inline int apic_remote_read(int apicid, int reg, unsigned long *pvalue) +{ + int timeout; + unsigned long status; + int result; + apic_wait_icr_idle(); + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); + apic_write_around(APIC_ICR, APIC_DM_REMRD | (reg >> 4)); + timeout = 0; + do { +#if 0 + udelay(100); +#endif + status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK; + } while (status == APIC_ICR_RR_INPROG && timeout++ < 1000); + + result = -1; + if (status == APIC_ICR_RR_VALID) { + *pvalue = apic_read(APIC_RRR); + result = 0; + } + return result; +} +#endif /* ASSEMBLY */ + +#endif /* APIC_H */ diff --git a/src/include/cpu/p6/cpufixup.h b/src/include/cpu/p6/cpufixup.h new file mode 100644 index 0000000000..9b0f2fa096 --- /dev/null +++ b/src/include/cpu/p6/cpufixup.h @@ -0,0 +1,6 @@ +#ifndef CPU_P6_CPUFIXUP_H +#define CPU_P6_CPUFIXUP_H + +void p6_cpufixup(struct mem_range *mem); + +#endif /* CPU_P6_CPUFIXUP_H */ diff --git a/src/include/cpu/p6/msr.h b/src/include/cpu/p6/msr.h new file mode 100644 index 0000000000..4977b0201d --- /dev/null +++ b/src/include/cpu/p6/msr.h @@ -0,0 +1,33 @@ +#ifndef CPU_P6_MSR_H +#define CPU_P6_MSR_H + +/* + * Access to machine-specific registers (available on 586 and better only) + * Note: the rd* operations modify the parameters directly (without using + * pointer indirection), this allows gcc to optimize better + */ + +#define rdmsr(msr,val1,val2) \ + __asm__ __volatile__("rdmsr" \ + : "=a" (val1), "=d" (val2) \ + : "c" (msr)) + +#define wrmsr(msr,val1,val2) \ + __asm__ __volatile__("wrmsr" \ + : /* no outputs */ \ + : "c" (msr), "a" (val1), "d" (val2)) + +#define rdtsc(low,high) \ + __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) + +#define rdtscl(low) \ + __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx") + +#define rdtscll(val) \ + __asm__ __volatile__ ("rdtsc" : "=A" (val)) + +#define rdpmc(counter,low,high) \ + __asm__ __volatile__("rdpmc" \ + : "=a" (low), "=d" (high) \ + : "c" (counter)) +#endif /* CPU_P6_MSR_H */ diff --git a/src/include/cpu/p6/mtrr.h b/src/include/cpu/p6/mtrr.h new file mode 100644 index 0000000000..16af10b81b --- /dev/null +++ b/src/include/cpu/p6/mtrr.h @@ -0,0 +1,44 @@ +#ifndef __LINUXBIOS_CPU_P6_MTRR_H +#define __LINUXBIOS_CPU_P6_MTRR_H + +/* These are the region types */ +#define MTRR_TYPE_UNCACHABLE 0 +#define MTRR_TYPE_WRCOMB 1 +/*#define MTRR_TYPE_ 2*/ +/*#define MTRR_TYPE_ 3*/ +#define MTRR_TYPE_WRTHROUGH 4 +#define MTRR_TYPE_WRPROT 5 +#define MTRR_TYPE_WRBACK 6 +#define MTRR_NUM_TYPES 7 + +#define MTRRcap_MSR 0x0fe +#define MTRRdefType_MSR 0x2ff + +#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg)) +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1) + +#define NUM_FIXED_RANGES 88 +#define MTRRfix64K_00000_MSR 0x250 +#define MTRRfix16K_80000_MSR 0x258 +#define MTRRfix16K_A0000_MSR 0x259 +#define MTRRfix4K_C0000_MSR 0x268 +#define MTRRfix4K_C8000_MSR 0x269 +#define MTRRfix4K_D0000_MSR 0x26a +#define MTRRfix4K_D8000_MSR 0x26b +#define MTRRfix4K_E0000_MSR 0x26c +#define MTRRfix4K_E8000_MSR 0x26d +#define MTRRfix4K_F0000_MSR 0x26e +#define MTRRfix4K_F8000_MSR 0x26f + + +#if !defined(ASSEMBLY) + +void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type); +#if defined(INTEL_PPRO_MTRR) +struct mem_range; +void setup_mtrrs(struct mem_range *mem); +#endif + +#endif /* ASSEMBLY */ + +#endif /* __LINUXBIOS_CPU_P6_MTRR_H */ diff --git a/src/include/delay.h b/src/include/delay.h new file mode 100644 index 0000000000..bffb719a55 --- /dev/null +++ b/src/include/delay.h @@ -0,0 +1,8 @@ +#ifndef DELAY_H +#define DELAY_H + +void udelay(int usecs); +void mdelay(int msecs); +void delay(int secs); + +#endif /* DELAY_H */ diff --git a/src/include/ip_checksum.h b/src/include/ip_checksum.h new file mode 100644 index 0000000000..c2cb938294 --- /dev/null +++ b/src/include/ip_checksum.h @@ -0,0 +1,7 @@ +#ifndef IP_CHECKSUM_H +#define IP_CHECKSUM_H + +unsigned long compute_ip_checksum(void *addr, unsigned long length); +unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new); + +#endif /* IP_CHECKSUM_H */ diff --git a/src/include/mem.h b/src/include/mem.h new file mode 100644 index 0000000000..e8f633b25a --- /dev/null +++ b/src/include/mem.h @@ -0,0 +1,13 @@ +#ifndef MEM_H +#define MEM_H + +struct mem_range { + unsigned long basek; + unsigned long sizek; +}; + +/* mem_range arrays are non-overlapping, in ascending order and null terminated */ + +struct mem_range *sizeram(void); + +#endif /* MEM_H */ diff --git a/src/include/part/fallback_boot.h b/src/include/part/fallback_boot.h new file mode 100644 index 0000000000..1eb2f7bffc --- /dev/null +++ b/src/include/part/fallback_boot.h @@ -0,0 +1,16 @@ +#ifndef PART_FALLBACK_BOOT_H +#define PART_FALLBACK_BOOT_H + +#ifndef ASSEMBLY + +#if HAVE_FALLBACK_BOOT +void boot_successful(void); +#else +#define boot_successful() +#endif + +#endif /* ASSEMBLY */ + +#define RTC_BOOT_BYTE 48 + +#endif /* PART_FALLBACK_BOOT_H */ diff --git a/src/include/part/sizeram.h b/src/include/part/sizeram.h new file mode 100644 index 0000000000..50a44f3e82 --- /dev/null +++ b/src/include/part/sizeram.h @@ -0,0 +1,7 @@ +#ifndef PART_SIZERAM_H +#define PART_SIZERAM_H + +struct mem_rang; +struct mem_range *sizeram(void); + +#endif /* PART_SIZERAM_H */ diff --git a/src/include/pc80/mc146818rtc.h b/src/include/pc80/mc146818rtc.h new file mode 100644 index 0000000000..1daf39aa25 --- /dev/null +++ b/src/include/pc80/mc146818rtc.h @@ -0,0 +1,110 @@ +#ifndef PC80_MC146818RTC_H +#define PC80_MC146818RTC_H + +#ifndef RTC_BASE_PORT +#define RTC_BASE_PORT 0x70 +#endif + +#define RTC_PORT(x) (RTC_BASE_PORT + (x)) + +/* On PCs, the checksum is built only over bytes 16..45 */ +#define PC_CKS_RANGE_START 16 +#define PC_CKS_RANGE_END 45 +#define PC_CKS_LOC 46 + + +/* Linux bios checksum is built only over bytes 49..125 */ +#define LB_CKS_RANGE_START 49 +#define LB_CKS_RANGE_END 125 +#define LB_CKS_LOC 126 + + +/* control registers - Moto names + */ +#define RTC_REG_A 10 +#define RTC_REG_B 11 +#define RTC_REG_C 12 +#define RTC_REG_D 13 + + +/********************************************************************** + * register details + **********************************************************************/ +#define RTC_FREQ_SELECT RTC_REG_A + +/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus, + * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete, + * totalling to a max high interval of 2.228 ms. + */ +# define RTC_UIP 0x80 +# define RTC_DIV_CTL 0x70 + /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */ +# define RTC_REF_CLCK_4MHZ 0x00 +# define RTC_REF_CLCK_1MHZ 0x10 +# define RTC_REF_CLCK_32KHZ 0x20 + /* 2 values for divider stage reset, others for "testing purposes only" */ +# define RTC_DIV_RESET1 0x60 +# define RTC_DIV_RESET2 0x70 + /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */ +# define RTC_RATE_SELECT 0x0F +# define RTC_RATE_NONE 0x00 +# define RTC_RATE_32786HZ 0x01 +# define RTC_RATE_16384HZ 0x02 +# define RTC_RATE_8192HZ 0x03 +# define RTC_RATE_4096HZ 0x04 +# define RTC_RATE_2048HZ 0x05 +# define RTC_RATE_1024HZ 0x06 +# define RTC_RATE_512HZ 0x07 +# define RTC_RATE_256HZ 0x08 +# define RTC_RATE_128HZ 0x09 +# define RTC_RATE_64HZ 0x0a +# define RTC_RATE_32HZ 0x0b +# define RTC_RATE_16HZ 0x0c +# define RTC_RATE_8HZ 0x0d +# define RTC_RATE_4HZ 0x0e +# define RTC_RATE_2HZ 0x0f + +/**********************************************************************/ +#define RTC_CONTROL RTC_REG_B +# define RTC_SET 0x80 /* disable updates for clock setting */ +# define RTC_PIE 0x40 /* periodic interrupt enable */ +# define RTC_AIE 0x20 /* alarm interrupt enable */ +# define RTC_UIE 0x10 /* update-finished interrupt enable */ +# define RTC_SQWE 0x08 /* enable square-wave output */ +# define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */ +# define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ +# define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */ + +/**********************************************************************/ +#define RTC_INTR_FLAGS RTC_REG_C +/* caution - cleared by read */ +# define RTC_IRQF 0x80 /* any of the following 3 is active */ +# define RTC_PF 0x40 +# define RTC_AF 0x20 +# define RTC_UF 0x10 + +/**********************************************************************/ +#define RTC_VALID RTC_REG_D +# define RTC_VRT 0x80 /* valid RAM and time */ +/**********************************************************************/ + + +/* On PCs, the checksum is built only over bytes 16..45 */ +#define PC_CKS_RANGE_START 16 +#define PC_CKS_RANGE_END 45 +#define PC_CKS_LOC 46 + +#define LB_CKS_RANGE_START 49 +#define LB_CKS_RANGE_END 125 +#define LB_CKS_LOC 126 + +#if !defined(ASSEMBLY) +void rtc_init(int invalid); +#if USE_OPTION_TABLE == 1 +int get_option(void *dest, char *name); +#else +#define get_option(dest, name) (-2) +#endif +#endif + +#endif /* PC80_MC146818RTC_H */ diff --git a/src/include/smp/atomic.h b/src/include/smp/atomic.h new file mode 100644 index 0000000000..b36e0e2051 --- /dev/null +++ b/src/include/smp/atomic.h @@ -0,0 +1,53 @@ +#ifndef SMP_ATOMIC_H +#define SMP_ATOMIC_H + +#ifdef SMP +#include <arch/smp/atomic.h> +#else + +typedef struct { int counter; } atomic_t; +#define ATOMIC_INIT(i) { (i) } + +/** + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_read(v) ((v)->counter) + +/** + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_set(v,i) (((v)->counter) = (i)) + + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_inc(v) (((v)->counter)++) + + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_dec(v) (((v)->counter)--) + + +#endif /* SMP */ + +#endif /* SMP_ATOMIC_H */ diff --git a/src/include/smp/spinlock.h b/src/include/smp/spinlock.h new file mode 100644 index 0000000000..9e0f8af0a9 --- /dev/null +++ b/src/include/smp/spinlock.h @@ -0,0 +1,24 @@ +#ifndef SMP_SPINLOCK_H +#define SMP_SPINLOCK_H + +#ifdef SMP +#include <arch/smp/spinlock.h> +#else /* !SMP */ + +/* Most GCC versions have a nasty bug with empty initializers */ +#if (__GNUC__ > 2) +typedef struct { } spinlock_t; +#define SPIN_LOCK_UNLOCKED (spinlock_t) { } +#else +typedef struct { int gcc_is_buggy; } spinlock_t; +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } +#endif + +#define barrier() do {} while(0) +#define spin_is_locked(lock) 0 +#define spin_unlock_wait(lock) do {} while(0) +#define spin_lock(lock) do {} while(0) +#define spin_unlock(lock) do {} while(0) +#endif + +#endif /* SMP_SPINLOCK_H */ diff --git a/src/include/smp/start_stop.h b/src/include/smp/start_stop.h new file mode 100644 index 0000000000..c0eebd0e2c --- /dev/null +++ b/src/include/smp/start_stop.h @@ -0,0 +1,17 @@ +#ifndef SMP_START_STOP_H +#define SMP_START_STOP_H + +#if SMP == 1 +#include <smp/atomic.h> +unsigned long this_processors_id(void); +int processor_index(unsigned long processor_id); +void stop_cpu(unsigned long processor_id); +int start_cpu(unsigned long processor_id); +void startup_other_cpus(unsigned long *processor_map); +#else +#define this_processors_id() 0 +#define startup_other_cpus(p) do {} while(0) +#define processor_index(p) 0 +#endif + +#endif /* SMP_START_STOP_H */ diff --git a/src/include/stdlib.h b/src/include/stdlib.h new file mode 100644 index 0000000000..eb67d20fe7 --- /dev/null +++ b/src/include/stdlib.h @@ -0,0 +1,14 @@ +#ifndef STDLIB_H +#define STDLIB_H + +#include <stddef.h> + +extern void *malloc(size_t size); +void free(void *ptr); + +/* Extensions to malloc... */ +typedef size_t malloc_mark_t; +void malloc_mark(malloc_mark_t *place); +void malloc_release(malloc_mark_t *place); + +#endif /* STDLIB_H */ diff --git a/src/include/stream/read_bytes.h b/src/include/stream/read_bytes.h new file mode 100644 index 0000000000..dd3ef04090 --- /dev/null +++ b/src/include/stream/read_bytes.h @@ -0,0 +1,13 @@ +#ifndef STREAM_READ_BYTES_H +#define STREAM_READ_BYTES_H + +#include <stdint.h> + +typedef long byte_offset_t; + +extern int stream_init(void); +extern byte_offset_t stream_read(void *vdest, byte_offset_t count); +extern byte_offset_t stream_skip(byte_offset_t count); +extern void stream_fini(void); + +#endif /* STREAM_READ_BYTES_H */ diff --git a/src/include/string.h b/src/include/string.h new file mode 100644 index 0000000000..cf9bbb14d2 --- /dev/null +++ b/src/include/string.h @@ -0,0 +1,36 @@ +#ifndef STRING_H +#define STRING_H + +#include <stddef.h> + +// yes, linux has fancy ones. We don't care. This stuff gets used +// hardly at all. And the pain of including those files is just too high. + +//extern inline void strcpy(char *dst, char *src) {while (*src) *dst++ = *src++;} + +//extern inline int strlen(char *src) { int i = 0; while (*src++) i++; return i;} + +static inline size_t strnlen(const char *src, size_t max) +{ + size_t i = 0; + while((*src++) && (i < max)) { + i++; + } + return i; +} + +static inline size_t strlen(const char *src) +{ + size_t i = 0; + while(*src++) { + i++; + } + return i; +} + +extern void *memcpy(void *dest, const void *src, size_t n); +extern void *memset(void *s, int c, size_t n); +extern int memcmp(const void *s1, const void *s2, size_t n); + +extern int sprintf(char * buf, const char *fmt, ...); +#endif /* STRING_H */ diff --git a/src/include/uart8250.h b/src/include/uart8250.h new file mode 100644 index 0000000000..ae45615758 --- /dev/null +++ b/src/include/uart8250.h @@ -0,0 +1,7 @@ +#ifndef UART8250_H +#define UART8250_H + +void uart8250_tx_byte(unsigned base_port, unsigned char data); +void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs); + +#endif /* UART8250_H */ diff --git a/src/include/version.h b/src/include/version.h new file mode 100644 index 0000000000..223b9a3f75 --- /dev/null +++ b/src/include/version.h @@ -0,0 +1,22 @@ +#ifndef VERSION_H +#define VERSION_H + +/* Motherboard Information */ +extern const char mainboard_vendor[]; +extern const char mainboard_part_number[]; + +/* LinuxBIOS Version */ +extern const char linuxbios_version[]; +extern const char linuxbios_extra_version[]; +extern const char linuxbios_build[]; + +/* When LinuxBIOS was compiled */ +extern const char linuxbios_compile_time[]; +extern const char linuxbios_compile_by[]; +extern const char linuxbios_compile_host[]; +extern const char linuxbios_compile_domain[]; +extern const char linuxbios_compiler[]; +extern const char linuxbios_linker[]; +extern const char linuxbios_assembler[]; + +#endif /* VERSION_H */ diff --git a/src/lib/clog2.c b/src/lib/clog2.c new file mode 100644 index 0000000000..092b49c821 --- /dev/null +++ b/src/lib/clog2.c @@ -0,0 +1,18 @@ +#include <console/console.h> + +unsigned long log2(unsigned long x) +{ + // assume 8 bits per byte. + unsigned long i = 1 << (sizeof(x)*8 - 1); + unsigned long pow = sizeof(x) * 8 - 1; + + if (! x) { + printk_warning("%s called with invalid parameter of 0\n", + __FUNCTION__); + return -1; + } + for(; i > x; i >>= 1, pow--) + ; + + return pow; +} diff --git a/src/lib/compute_ip_checksum.c b/src/lib/compute_ip_checksum.c new file mode 100644 index 0000000000..0b8eb90f85 --- /dev/null +++ b/src/lib/compute_ip_checksum.c @@ -0,0 +1,53 @@ +#include <stdint.h> +#include <ip_checksum.h> + +unsigned long compute_ip_checksum(void *addr, unsigned long length) +{ + uint8_t *ptr; + volatile union { + uint8_t byte[2]; + uint16_t word; + } value; + unsigned long sum; + unsigned long i; + /* In the most straight forward way possible, + * compute an ip style checksum. + */ + sum = 0; + ptr = addr; + for(i = 0; i < length; i++) { + unsigned long value; + value = ptr[i]; + if (i & 1) { + value <<= 8; + } + /* Add the new value */ + sum += value; + /* Wrap around the carry */ + if (sum > 0xFFFF) { + sum = (sum + (sum >> 16)) & 0xFFFF; + } + } + value.byte[0] = sum & 0xff; + value.byte[1] = (sum >> 8) & 0xff; + return (~value.word) & 0xFFFF; +} + +unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new) +{ + unsigned long checksum; + sum = ~sum & 0xFFFF; + new = ~new & 0xFFFF; + if (offset & 1) { + /* byte swap the sum if it came from an odd offset + * since the computation is endian independant this + * works. + */ + new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00); + } + checksum = sum + new; + if (checksum > 0xFFFF) { + checksum -= 0xFFFF; + } + return (~checksum) & 0xFFFF; +} diff --git a/src/lib/delay.c b/src/lib/delay.c new file mode 100644 index 0000000000..af5f78613e --- /dev/null +++ b/src/lib/delay.c @@ -0,0 +1,15 @@ +#include <delay.h> +void mdelay(int msecs) +{ + int i; + for(i = 0; i < msecs; i++) { + udelay(1000); + } +} +void delay(int secs) +{ + int i; + for(i = 0; i < secs; i++) { + mdelay(1000); + } +} diff --git a/src/lib/fallback_boot.c b/src/lib/fallback_boot.c new file mode 100644 index 0000000000..1bddd0a169 --- /dev/null +++ b/src/lib/fallback_boot.c @@ -0,0 +1,25 @@ +#include <console/console.h> +#include <part/fallback_boot.h> +#include <pc80/mc146818rtc.h> +#include <arch/io.h> + +void boot_successful(void) +{ + /* Remember I succesfully booted by setting + * the initial boot direction + * to the direction that I booted. + */ + unsigned char index, byte; + index = inb(RTC_PORT(0)) & 0x80; + index |= RTC_BOOT_BYTE; + outb(index, RTC_PORT(0)); + + byte = inb(RTC_PORT(1)); + byte &= 0xfe; + byte |= (byte & 2) >> 1; + + /* If we are in normal mode set the boot count to 0 */ + if(byte & 1) + byte &= 0x0f; + outb(byte, RTC_PORT(1)); +} diff --git a/src/lib/malloc.c b/src/lib/malloc.c new file mode 100644 index 0000000000..bd403e47e9 --- /dev/null +++ b/src/lib/malloc.c @@ -0,0 +1,52 @@ +#include <stdlib.h> +#include <console/console.h> + +#if 0 +#define MALLOCDBG(x) +#else +#define MALLOCDBG(x) printk_spew x +#endif +extern unsigned char _heap, _eheap; +static size_t free_mem_ptr = (size_t)&_heap; /* Start of heap */ +static size_t free_mem_end_ptr = (size_t)&_eheap; /* End of heap */ + + +void malloc_mark(malloc_mark_t *place) +{ + *place = free_mem_ptr; + printk_spew("malloc_mark 0x%08lx\n", (unsigned long)free_mem_ptr); +} + +void malloc_release(malloc_mark_t *ptr) +{ + free_mem_ptr = *ptr; + printk_spew("malloc_release 0x%08lx\n", (unsigned long)free_mem_ptr); +} + +void *malloc(size_t size) +{ + void *p; + + MALLOCDBG(("%s Enter, size %d, free_mem_ptr %p\n", __FUNCTION__, size, free_mem_ptr)); + if (size < 0) + die("Error! malloc: Size < 0"); + if (free_mem_ptr <= 0) + die("Error! malloc: Free_mem_ptr <= 0"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *) free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + die("Error! malloc: Free_mem_ptr >= free_mem_end_ptr"); + + MALLOCDBG(("malloc 0x%08lx\n", (unsigned long)p)); + + return p; +} + +void free(void *where) +{ + /* Don't care */ +} diff --git a/src/lib/memcmp.c b/src/lib/memcmp.c new file mode 100644 index 0000000000..46f13a41bd --- /dev/null +++ b/src/lib/memcmp.c @@ -0,0 +1,17 @@ +#include <string.h> + +int memcmp(const void *src1, const void *src2, size_t bytes) +{ + const unsigned char *s1, *s2; + int result; + s1 = src1; + s2 = src2; + result = 0; + while((bytes > 0) && (result == 0)) { + result = *s1 - *s2; + bytes--; + s1++; + s2++; + } + return result; +} diff --git a/src/lib/memcpy.c b/src/lib/memcpy.c new file mode 100644 index 0000000000..ad8e8bd3f0 --- /dev/null +++ b/src/lib/memcpy.c @@ -0,0 +1,11 @@ +#include <string.h> +void *memcpy(void *__dest, __const void *__src, size_t __n) +{ + int i; + char *d = (char *) __dest, *s = (char *) __src; + + for (i = 0; i < __n; i++) + d[i] = s[i]; + + return __dest; +} diff --git a/src/lib/memset.c b/src/lib/memset.c new file mode 100644 index 0000000000..c1bb4f841f --- /dev/null +++ b/src/lib/memset.c @@ -0,0 +1,12 @@ +#include <string.h> + +void *memset(void *s, int c, size_t n) +{ + int i; + char *ss = (char *) s; + + for (i = 0; i < n; i++) + ss[i] = c; + + return s; +} diff --git a/src/lib/uart8250.c b/src/lib/uart8250.c new file mode 100644 index 0000000000..778919b7ff --- /dev/null +++ b/src/lib/uart8250.c @@ -0,0 +1,64 @@ +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +/* Should support 8250, 16450, 16550, 16550A type uarts */ +#include <arch/io.h> +#include <uart8250.h> + +/* Data */ +#define UART_RBR 0x00 +#define UART_TBR 0x00 + +/* Control */ +#define UART_IER 0x01 +#define UART_IIR 0x02 +#define UART_FCR 0x02 +#define UART_LCR 0x03 +#define UART_MCR 0x04 +#define UART_DLL 0x00 +#define UART_DLM 0x01 + +/* Status */ +#define UART_LSR 0x05 +#define UART_MSR 0x06 +#define UART_SCR 0x07 + +static inline int uart8250_can_tx_byte(unsigned base_port) +{ + return inb(base_port + UART_LSR) & 0x20; +} + +static inline void uart8250_wait_to_tx_byte(unsigned base_port) +{ + while(!uart8250_can_tx_byte(base_port)) + ; +} + +static inline void uart8250_wait_until_sent(unsigned base_port) +{ + while(!(inb(base_port + UART_LSR) & 0x40)) + ; +} + +void uart8250_tx_byte(unsigned base_port, unsigned char data) +{ + uart8250_wait_to_tx_byte(base_port); + outb(data, base_port + UART_TBR); + /* Make certain the data clears the fifos */ + uart8250_wait_until_sent(base_port); +} + +void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs) +{ + lcs &= 0x7f; + /* disable interrupts */ + outb(0x0, base_port + UART_IER); + /* enable fifo's */ + outb(0x01, base_port + UART_FCR); + /* Set Baud Rate Divisor to 12 ==> 115200 Baud */ + outb(0x80 | lcs, base_port + UART_LCR); + outb(divisor & 0xFF, base_port + UART_DLL); + outb((divisor >> 8) & 0xFF, base_port + UART_DLM); + outb(lcs, base_port + UART_LCR); +} diff --git a/src/lib/version.c b/src/lib/version.c new file mode 100644 index 0000000000..73d52ca843 --- /dev/null +++ b/src/lib/version.c @@ -0,0 +1,62 @@ +#include <version.h> + +#define __STR(X) #X +#define STR(X) __STR(X) + +#ifndef MAINBOARD_VENDOR +#error MAINBOARD_VENDOR not defined +#endif +#ifndef MAINBOARD_PART_NUMBER +#error MAINBOARD_PART_NUMBER not defined +#endif + +#ifndef LINUXBIOS_VERSION +#error LINUXBIOS_VERSION not defined +#endif +#ifndef LINUXBIOS_BUILD +#error LINUXBIOS_BUILD not defined +#endif + +#ifndef LINUXBIOS_COMPILE_TIME +#error LINUXBIOS_COMPILE_TIME not defined +#endif +#ifndef LINUXBIOS_COMPILE_BY +#error LINUXBIOS_COMPILE_BY not defined +#endif +#ifndef LINUXBIOS_COMPILE_HOST +#error LINUXBIOS_COMPILE_HOST not defined +#endif + +#ifndef LINUXBIOS_COMPILER +#error LINUXBIOS_COMPILER not defined +#endif +#ifndef LINUXBIOS_LINKER +#error LINUXBIOS_LINKER not defined +#endif +#ifndef LINUXBIOS_ASSEMBLER +#error LINUXBIOS_ASSEMBLER not defined +#endif + + +#ifndef LINUXBIOS_EXTRA_VERSION +#define LINUXBIOS_EXTRA_VERSION +#endif + +const char mainboard_vendor[] = STR(MAINBOARD_VENDOR); +const char mainboard_part_number[] = STR(MAINBOARD_PART_NUMBER); + +const char linuxbios_version[] = STR(LINUXBIOS_VERSION); +const char linuxbios_extra_version[] = STR(LINUXBIOS_EXTRA_VERSION); +const char linuxbios_build[] = STR(LINUXBIOS_BUILD); + +const char linuxbios_compile_time[] = STR(LINUXBIOS_COMPILE_TIME); +const char linuxbios_compile_by[] = STR(LINUXBIOS_COMPILE_BY); +const char linuxbios_compile_host[] = STR(LINUXBIOS_COMPILE_HOST); +const char linuxbios_compile_domain[] = STR(LINUXBIOS_COMPILE_DOMAIN); +const char linuxbios_compiler[] = STR(LINUXBIOS_COMPILER); +const char linuxbios_linker[] = STR(LINUXBIOS_LINKER); +const char linuxbios_assembler[] = STR(LINUXBIOS_ASSEMBLER); + + + + diff --git a/src/mainboard/amd/solo/auto.c b/src/mainboard/amd/solo/auto.c new file mode 100644 index 0000000000..bc549fac90 --- /dev/null +++ b/src/mainboard/amd/solo/auto.c @@ -0,0 +1,1070 @@ +#define ASSEMBLY 1 +#include "arch/romcc_io.h" +#include "pc80/serial.c" +#include "arch/i386/lib/console.c" +#include "ram/ramtest.c" + + +static void sdram_set_registers(void) +{ + static const unsigned int register_values[] = { + /* Routing Table Node i + * F0:0x40 i = 0, + * F0:0x44 i = 1, + * F0:0x48 i = 2, + * F0:0x4c i = 3, + * F0:0x50 i = 4, + * F0:0x54 i = 5, + * F0:0x58 i = 6, + * F0:0x5c i = 7 + * [ 0: 3] Request Route + * [0] Route to this node + * [1] Route to Link 0 + * [2] Route to Link 1 + * [3] Route to Link 2 + * [11: 8] Response Route + * [0] Route to this node + * [1] Route to Link 0 + * [2] Route to Link 1 + * [3] Route to Link 2 + * [19:16] Broadcast route + * [0] Route to this node + * [1] Route to Link 0 + * [2] Route to Link 1 + * [3] Route to Link 2 + */ + 0xc040, 0xfff0f0f0, 0x00010101, + 0xc044, 0xfff0f0f0, 0x00010101, + 0xc048, 0xfff0f0f0, 0x00010101, + 0xc04c, 0xfff0f0f0, 0x00010101, + 0xc050, 0xfff0f0f0, 0x00010101, + 0xc054, 0xfff0f0f0, 0x00010101, + 0xc058, 0xfff0f0f0, 0x00010101, + 0xc05c, 0xfff0f0f0, 0x00010101, + + /* Hypetransport Transaction Control Register + * F0:0x68 + * [ 0: 0] Disable read byte probe + * 0 = Probes issues + * 1 = Probes not issued + * [ 1: 1] Disable Read Doubleword probe + * 0 = Probes issued + * 1 = Probes not issued + * [ 2: 2] Disable write byte probes + * 0 = Probes issued + * 1 = Probes not issued + * [ 3: 3] Disalbe Write Doubleword Probes + * 0 = Probes issued + * 1 = Probes not issued. + * [ 4: 4] Disable Memroy Controller Target Start + * 0 = TgtStart packets are generated + * 1 = TgtStart packets are not generated. + * [ 5: 5] CPU1 Enable + * 0 = Second CPU disabled or not present + * 1 = Second CPU enabled. + * [ 6: 6] CPU Request PassPW + * 0 = CPU requests do not pass posted writes + * 1 = CPU requests pass posted writes. + * [ 7: 7] CPU read Respons PassPW + * 0 = CPU Responses do not pass posted writes + * 1 = CPU responses pass posted writes. + * [ 8: 8] Disable Probe Memory Cancel + * 0 = Probes may generate MemCancels + * 1 = Probes may not generate MemCancels + * [ 9: 9] Disable Remote Probe Memory Cancel. + * 0 = Probes hitting dirty blocks generate memory cancel packets + * 1 = Only probed caches on the same node as the memory controller + * generate cancel packets. + * [10:10] Disable Fill Probe + * 0 = Probes issued for cache fills + * 1 = Probes not issued for cache fills. + * [11:11] Response PassPw + * 0 = Downstream response PassPW based on original request + * 1 = Downstream response PassPW set to 1 + * [12:12] Change ISOC to Ordered + * 0 = Bit 1 of coherent HT RdSz/WrSz command used for iosynchronous prioritization + * 1 = Bit 1 of coherent HT RdSz/WrSz command used for ordering. + * [14:13] Buffer Release Priority select + * 00 = 64 + * 01 = 16 + * 10 = 8 + * 11 = 2 + * [15:15] Limit Coherent HT Configuration Space Range + * 0 = No coherent HT configuration space restrictions + * 1 = Limit coherent HT configuration space based on node count + * [16:16] Local Interrupt Conversion Enable. + * 0 = ExtInt/NMI interrups unaffected. + * 1 = ExtInt/NMI broadcat interrupts converted to LINT0/1 + * [17:17] APIC Extended Broadcast Enable. + * 0 = APIC broadcast is 0F + * 1 = APIC broadcast is FF + * [18:18] APIC Extended ID Enable + * 0 = APIC ID is 4 bits. + * 1 = APIC ID is 8 bits. + * [19:19] APIC Extended Spurious Vector Enable + * 0 = Lower 4 bits of spurious vector are read-only 1111 + * 1 = Lower 4 bits of spurious vecotr are writeable. + * [20:20] Sequence ID Source Node Enable + * 0 = Normal operation + * 1 = Keep SeqID on routed packets for debugging. + * [22:21] Downstream non-posted request limit + * 00 = No limit + * 01 = Limited to 1 + * 10 = Limited to 4 + * 11 = Limited to 8 + * [23:23] RESERVED + * [25:24] Medium-Priority Bypass Count + * - Maximum # of times a medium priority access can pass a low + * priority access before Medium-Priority mode is disabled for one access. + * [27:26] High-Priority Bypass Count + * - Maximum # of times a high prioirty access can pass a medium or low + * priority access before High-prioirty mode is disabled for one access. + * [28:28] Enable High Priority CPU Reads + * 0 = Cpu reads are medium prioirty + * 1 = Cpu reads are high prioirty + * [29:29] Disable Low Priority Writes + * 0 = Non-isochronous writes are low priority + * 1 = Non-isochronous writes are medium prioirty + * [30:30] Disable High Priority Isochronous writes + * 0 = Isochronous writes are high priority + * 1 = Isochronous writes are medium priority + * [31:31] Disable Medium Priority Isochronous writes + * 0 = Isochronous writes are medium are high + * 1 = With bit 30 set makes Isochrouns writes low priority. + */ + 0xc068, 0x00800000, 0x0f00840f, + /* HT Initialization Control Register + * F0:0x68 + * [ 0: 0] Routing Table Disable + * 0 = Packets are routed according to routing tables + * 1 = Packets are routed according to the default link field + * [ 1: 1] Request Disable (BSP should clear this) + * 0 = Request packets may be generated + * 1 = Request packets may not be generated. + * [ 3: 2] Default Link (Read-only) + * 00 = LDT0 + * 01 = LDT1 + * 10 = LDT2 + * 11 = CPU on same node + * [ 4: 4] Cold Reset + * - Scratch bit cleared by a cold reset + * [ 5: 5] BIOS Reset Detect + * - Scratch bit cleared by a cold reset + * [ 6: 6] INIT Detect + * - Scratch bit cleared by a warm or cold reset not by an INIT + * + */ + 0xc06C, 0xffffff8c, 0x00000000, + /* LDTi Capabilities Registers + * F0:0x80 i = 0, + * F0:0xA0 i = 1, + * F0:0xC0 i = 2, + */ + /* LDTi Link Control Registrs + * F0:0x84 i = 0, + * F0:0xA4 i = 1, + * F0:0xC4 i = 2, + * [ 1: 1] CRC Flood Enable + * 0 = Do not generate sync packets on CRC error + * 1 = Generate sync packets on CRC error + * [ 2: 2] CRC Start Test (Read-Only) + * [ 3: 3] CRC Force Frame Error + * 0 = Do not generate bad CRC + * 1 = Generate bad CRC + * [ 4: 4] Link Failure + * 0 = No link failure detected + * 1 = Link failure detected + * [ 5: 5] Initialization Complete + * 0 = Initialization not complete + * 1 = Initialization complete + * [ 6: 6] Receiver off + * 0 = Recevier on + * 1 = Receiver off + * [ 7: 7] Transmitter Off + * 0 = Transmitter on + * 1 = Transmitter off + * [ 9: 8] CRC_Error + * 00 = No error + * [0] = 1 Error on byte lane 0 + * [1] = 1 Error on byte lane 1 + * [12:12] Isochrnous Enable (Read-Only) + * [13:13] HT Stop Tristate Enable + * 0 = Driven during an LDTSTOP_L + * 1 = Tristated during and LDTSTOP_L + * [14:14] Extended CTL Time + * 0 = CTL is asserted for 16 bit times during link initialization + * 1 = CTL is asserted for 50us during link initialization + * [18:16] Max Link Width In (Read-Only?) + * 000 = 8 bit link + * 001 = 16bit link + * [19:19] Doubleword Flow Control in (Read-Only) + * 0 = This link does not support doubleword flow control + * 1 = This link supports doubleword flow control + * [22:20] Max Link Width Out (Read-Only?) + * 000 = 8 bit link + * 001 = 16bit link + * [23:23] Doubleworld Flow Control out (Read-Only) + * 0 = This link does not support doubleword flow control + * 1 = This link supports doubleworkd flow control + * [26:24] Link Width In + * 000 = Use 8 bits + * 001 = Use 16 bits + * 010 = reserved + * 011 = Use 32 bits + * 100 = Use 2 bits + * 101 = Use 4 bits + * 110 = reserved + * 111 = Link physically not connected + * [27:27] Doubleword Flow Control In Enable + * 0 = Doubleword flow control disabled + * 1 = Doubleword flow control enabled (Not currently supported) + * [30:28] Link Width Out + * 000 = Use 8 bits + * 001 = Use 16 bits + * 010 = reserved + * 011 = Use 32 bits + * 100 = Use 2 bits + * 101 = Use 4 bits + * 110 = reserved + * 111 = Link physically not connected + * [31:31] Doubleworld Flow Control Out Enable + * 0 = Doubleworld flow control disabled + * 1 = Doubleword flow control enabled (Not currently supported) + */ + 0xc084, 0x00009c05, 0x11110020, + /* LDTi Frequency/Revision Registers + * F0:0x88 i = 0, + * F0:0xA8 i = 1, + * F0:0xC8 i = 2, + * [ 4: 0] Minor Revision + * Contains the HT Minor revision + * [ 7: 5] Major Revision + * Contains the HT Major revision + * [11: 8] Link Frequency (Takes effect the next time the link is reconnected) + * 0000 = 200Mhz + * 0001 = reserved + * 0010 = 400Mhz + * 0011 = reserved + * 0100 = 600Mhz + * 0101 = 800Mhz + * 0110 = 1000Mhz + * 0111 = reserved + * 1000 = reserved + * 1001 = reserved + * 1010 = reserved + * 1011 = reserved + * 1100 = reserved + * 1101 = reserved + * 1110 = reserved + * 1111 = 100 Mhz + * [15:12] Error (Not currently Implemented) + * [31:16] Indicates the frequency capabilities of the link + * [16] = 1 encoding 0000 of freq supported + * [17] = 1 encoding 0001 of freq supported + * [18] = 1 encoding 0010 of freq supported + * [19] = 1 encoding 0011 of freq supported + * [20] = 1 encoding 0100 of freq supported + * [21] = 1 encoding 0101 of freq supported + * [22] = 1 encoding 0110 of freq supported + * [23] = 1 encoding 0111 of freq supported + * [24] = 1 encoding 1000 of freq supported + * [25] = 1 encoding 1001 of freq supported + * [26] = 1 encoding 1010 of freq supported + * [27] = 1 encoding 1011 of freq supported + * [28] = 1 encoding 1100 of freq supported + * [29] = 1 encoding 1101 of freq supported + * [30] = 1 encoding 1110 of freq supported + * [31] = 1 encoding 1111 of freq supported + */ + 0xC088, 0xfffff0ff, 0x00000200, + /* LDTi Feature Capability + * F0:0x8C i = 0, + * F0:0xAC i = 1, + * F0:0xCC i = 2, + */ + /* LDTi Buffer Count Registers + * F0:0x90 i = 0, + * F0:0xB0 i = 1, + * F0:0xD0 i = 2, + */ + /* LDTi Bus Number Registers + * F0:0x94 i = 0, + * F0:0xB4 i = 1, + * F0:0xD4 i = 2, + * For NonCoherent HT specifies the bus number downstream (behind the host bridge) + * [ 0: 7] Primary Bus Number + * [15: 8] Secondary Bus Number + * [23:15] Subordiante Bus Number + * [31:24] reserved + */ + 0xC094, 0xff000000, 0x00ff0000, + /* LDTi Type Registers + * F0:0x98 i = 0, + * F0:0xB8 i = 1, + * F0:0xD8 i = 2, + */ + /* Careful set limit registers before base registers which contain the enables */ + /* DRAM Limit i Registers + * F1:0x44 i = 0 + * F1:0x4C i = 1 + * F1:0x54 i = 2 + * F1:0x5C i = 3 + * F1:0x64 i = 4 + * F1:0x6C i = 5 + * F1:0x74 i = 6 + * F1:0x7C i = 7 + * [ 2: 0] Destination Node ID + * 000 = Node 0 + * 001 = Node 1 + * 010 = Node 2 + * 011 = Node 3 + * 100 = Node 4 + * 101 = Node 5 + * 110 = Node 6 + * 111 = Node 7 + * [ 7: 3] Reserved + * [10: 8] Interleave select + * specifies the values of A[14:12] to use with interleave enable. + * [15:11] Reserved + * [31:16] DRAM Limit Address i Bits 39-24 + * This field defines the upper address bits of a 40 bit address + * that define the end of the DRAM region. + */ + 0xC144, 0x0000f8f8, 0x003f0000, + 0xC148, 0x0000f8f8, 0x00000001, + 0xC154, 0x0000f8f8, 0x00000002, + 0xC158, 0x0000f8f8, 0x00000003, + 0xC164, 0x0000f8f8, 0x00000004, + 0xC168, 0x0000f8f8, 0x00000005, + 0xC174, 0x0000f8f8, 0x00000006, + 0xC178, 0x0000f8f8, 0x00000007, + /* DRAM Base i Registers + * F1:0x40 i = 0 + * F1:0x48 i = 1 + * F1:0x50 i = 2 + * F1:0x58 i = 3 + * F1:0x60 i = 4 + * F1:0x68 i = 5 + * F1:0x70 i = 6 + * F1:0x78 i = 7 + * [ 0: 0] Read Enable + * 0 = Reads Disabled + * 1 = Reads Enabled + * [ 1: 1] Write Enable + * 0 = Writes Disabled + * 1 = Writes Enabled + * [ 7: 2] Reserved + * [10: 8] Interleave Enable + * 000 = No interleave + * 001 = Interleave on A[12] (2 nodes) + * 010 = reserved + * 011 = Interleave on A[12] and A[14] (4 nodes) + * 100 = reserved + * 101 = reserved + * 110 = reserved + * 111 = Interleve on A[12] and A[13] and A[14] (8 nodes) + * [15:11] Reserved + * [13:16] DRAM Base Address i Bits 39-24 + * This field defines the upper address bits of a 40-bit address + * that define the start of the DRAM region. + */ + 0xC140, 0x0000f8fc, 0x00000003, + 0xC148, 0x0000f8fc, 0x00400000, + 0xC150, 0x0000f8fc, 0x00400000, + 0xC158, 0x0000f8fc, 0x00400000, + 0xC160, 0x0000f8fc, 0x00400000, + 0xC168, 0x0000f8fc, 0x00400000, + 0xC170, 0x0000f8fc, 0x00400000, + 0xC178, 0x0000f8fc, 0x00400000, + + /* Memory-Mapped I/O Limit i Registers + * F1:0x84 i = 0 + * F1:0x8C i = 1 + * F1:0x94 i = 2 + * F1:0x9C i = 3 + * F1:0xA4 i = 4 + * F1:0xAC i = 5 + * F1:0xB4 i = 6 + * F1:0xBC i = 7 + * [ 2: 0] Destination Node ID + * 000 = Node 0 + * 001 = Node 1 + * 010 = Node 2 + * 011 = Node 3 + * 100 = Node 4 + * 101 = Node 5 + * 110 = Node 6 + * 111 = Node 7 + * [ 3: 3] Reserved + * [ 5: 4] Destination Link ID + * 00 = Link 0 + * 01 = Link 1 + * 10 = Link 2 + * 11 = Reserved + * [ 6: 6] Reserved + * [ 7: 7] Non-Posted + * 0 = CPU writes may be posted + * 1 = CPU writes must be non-posted + * [31: 8] Memory-Mapped I/O Limit Address i (39-16) + * This field defines the upp adddress bits of a 40-bit address that + * defines the end of a memory-mapped I/O region n + */ + 0xC184, 0x00000048, 0x00e1ff00, + 0xC18C, 0x00000048, 0x00dfff00, + 0xC194, 0x00000048, 0x00e3ff00, + 0xC19C, 0x00000048, 0x00000000, + 0xC1A4, 0x00000048, 0x00000000, + 0xC1AC, 0x00000048, 0x00000000, + 0xC1B4, 0x00000048, 0x00000b00, + + + /* Memory-Mapped I/O Base i Registers + * F1:0x80 i = 0 + * F1:0x88 i = 1 + * F1:0x90 i = 2 + * F1:0x98 i = 3 + * F1:0xA0 i = 4 + * F1:0xA8 i = 5 + * F1:0xB0 i = 6 + * F1:0xB8 i = 7 + * [ 0: 0] Read Enable + * 0 = Reads disabled + * 1 = Reads Enabled + * [ 1: 1] Write Enable + * 0 = Writes disabled + * 1 = Writes Enabled + * [ 2: 2] Cpu Disable + * 0 = Cpu can use this I/O range + * 1 = Cpu requests do not use this I/O range + * [ 3: 3] Lock + * 0 = base/limit registers i are read/write + * 1 = base/limit registers i are read-only + * [ 7: 4] Reserved + * [31: 8] Memory-Mapped I/O Base Address i (39-16) + * This field defines the upper address bits of a 40bit address + * that defines the start of memory-mapped I/O region i + */ + 0xC1BC, 0x00000048, 0x00fe0b00, + 0xC180, 0x000000f0, 0x00e00003, + 0xC188, 0x000000f0, 0x00d80003, + 0xC190, 0x000000f0, 0x00e20003, + 0xC198, 0x000000f0, 0x00000000, + 0xC1A0, 0x000000f0, 0x00000000, + 0xC1A8, 0x000000f0, 0x00000000, + 0xC1B0, 0x000000f0, 0x0000a003, + 0xC1B8, 0x000000f0, 0x00400003, + + /* PCI I/O Limit i Registers + * F1:0xC4 i = 0 + * F1:0xCC i = 1 + * F1:0xD4 i = 2 + * F1:0xDC i = 3 + * [ 2: 0] Destination Node ID + * 000 = Node 0 + * 001 = Node 1 + * 010 = Node 2 + * 011 = Node 3 + * 100 = Node 4 + * 101 = Node 5 + * 110 = Node 6 + * 111 = Node 7 + * [ 3: 3] Reserved + * [ 5: 4] Destination Link ID + * 00 = Link 0 + * 01 = Link 1 + * 10 = Link 2 + * 11 = reserved + * [11: 6] Reserved + * [24:12] PCI I/O Limit Address i + * This field defines the end of PCI I/O region n + * [31:25] Reserved + */ + 0xC1C4, 0xFE000FC8, 0x0000d000, + 0xC1CC, 0xFE000FC8, 0x000ff000, + 0xC1D4, 0xFE000FC8, 0x00000000, + 0xC1DC, 0xFE000FC8, 0x00000000, + + /* PCI I/O Base i Registers + * F1:0xC0 i = 0 + * F1:0xC8 i = 1 + * F1:0xD0 i = 2 + * F1:0xD8 i = 3 + * [ 0: 0] Read Enable + * 0 = Reads Disabled + * 1 = Reads Enabled + * [ 1: 1] Write Enable + * 0 = Writes Disabled + * 1 = Writes Enabled + * [ 3: 2] Reserved + * [ 4: 4] VGA Enable + * 0 = VGA matches Disabled + * 1 = matches all address < 64K and where A[9:0] is in the + * range 3B0-3BB or 3C0-3DF independen of the base & limit registers + * [ 5: 5] ISA Enable + * 0 = ISA matches Disabled + * 1 = Blocks address < 64K and in the last 768 bytes of eack 1K block + * from matching agains this base/limit pair + * [11: 6] Reserved + * [24:12] PCI I/O Base i + * This field defines the start of PCI I/O region n + * [31:25] Reserved + */ + 0xC1C0, 0xFE000FCC, 0x0000d003, + 0xC1C8, 0xFE000FCC, 0x00001013, + 0xC1D0, 0xFE000FCC, 0x00000000, + 0xC1D8, 0xFE000FCC, 0x00000000, + + /* Config Base and Limit i Registers + * F1:0xE0 i = 0 + * F1:0xE4 i = 1 + * F1:0xE8 i = 2 + * F1:0xEC i = 3 + * [ 0: 0] Read Enable + * 0 = Reads Disabled + * 1 = Reads Enabled + * [ 1: 1] Write Enable + * 0 = Writes Disabled + * 1 = Writes Enabled + * [ 2: 2] Device Number Compare Enable + * 0 = The ranges are based on bus number + * 1 = The ranges are ranges of devices on bus 0 + * [ 3: 3] Reserved + * [ 6: 4] Destination Node + * 000 = Node 0 + * 001 = Node 1 + * 010 = Node 2 + * 011 = Node 3 + * 100 = Node 4 + * 101 = Node 5 + * 110 = Node 6 + * 111 = Node 7 + * [ 7: 7] Reserved + * [ 9: 8] Destination Link + * 00 = Link 0 + * 01 = Link 1 + * 10 = Link 2 + * 11 - Reserved + * [15:10] Reserved + * [23:16] Bus Number Base i + * This field defines the lowest bus number in configuration region i + * [31:24] Bus Number Limit i + * This field defines the highest bus number in configuration regin i + */ + 0xC1E0, 0x0000FC88, 0xff000003, + 0xC1E4, 0x0000FC88, 0x00000000, + 0xC1E8, 0x0000FC88, 0x00000000, + 0xC1EC, 0x0000FC88, 0x00000000, + + /* DRAM CS Base Address i Registers + * F2:0x40 i = 0 + * F2:0x44 i = 1 + * F2:0x48 i = 2 + * F2:0x4C i = 3 + * F2:0x50 i = 4 + * F2:0x54 i = 5 + * F2:0x58 i = 6 + * F2:0x5C i = 7 + * [ 0: 0] Chip-Select Bank Enable + * 0 = Bank Disabled + * 1 = Bank Enabled + * [ 8: 1] Reserved + * [15: 9] Base Address (19-13) + * An optimization used when all DIMM are the same size... + * [20:16] Reserved + * [31:21] Base Address (35-25) + * This field defines the top 11 addresses bit of a 40-bit + * address that define the memory address space. These + * bits decode 32-MByte blocks of memory. + */ + 0xC240, 0x001f01fe, 0x00000001, + 0xC244, 0x001f01fe, 0x01000001, + 0xC248, 0x001f01fe, 0x02000001, + 0xC24C, 0x001f01fe, 0x03000001, + 0xC250, 0x001f01fe, 0x00000000, + 0xC254, 0x001f01fe, 0x00000000, + 0xC258, 0x001f01fe, 0x00000000, + 0xC25C, 0x001f01fe, 0x00000000, + /* DRAM CS Mask Address i Registers + * F2:0x60 i = 0 + * F2:0x64 i = 1 + * F2:0x68 i = 2 + * F2:0x6C i = 3 + * F2:0x70 i = 4 + * F2:0x74 i = 5 + * F2:0x78 i = 6 + * F2:0x7C i = 7 + * Select bits to exclude from comparison with the DRAM Base address register. + * [ 8: 0] Reserved + * [15: 9] Address Mask (19-13) + * Address to be excluded from the optimized case + * [20:16] Reserved + * [29:21] Address Mask (33-25) + * The bits with an address mask of 1 are excluded from address comparison + * [31:30] Reserved + * + */ + 0xC260, 0xC01f01ff, 0x00e0fe00, + 0xC264, 0xC01f01ff, 0x00e0fe00, + 0xC268, 0xC01f01ff, 0x00e0fe00, + 0xC26C, 0xC01f01ff, 0x00e0fe00, + 0xC270, 0xC01f01ff, 0x00000000, + 0xC274, 0xC01f01ff, 0x00000000, + 0xC278, 0xC01f01ff, 0x00000000, + 0xC27C, 0xC01f01ff, 0x00000000, + /* DRAM Bank Address Mapping Register + * F2:0x80 + * Specify the memory module size + * [ 2: 0] CS1/0 + * [ 6: 4] CS3/2 + * [10: 8] CS5/4 + * [14:12] CS7/6 + * 000 = 32Mbyte (Rows = 12 & Col = 8) + * 001 = 64Mbyte (Rows = 12 & Col = 9) + * 010 = 128Mbyte (Rows = 13 & Col = 9)|(Rows = 12 & Col = 10) + * 011 = 256Mbyte (Rows = 13 & Col = 10)|(Rows = 12 & Col = 11) + * 100 = 512Mbyte (Rows = 13 & Col = 11)|(Rows = 14 & Col = 10) + * 101 = 1Gbyte (Rows = 14 & Col = 11)|(Rows = 13 & Col = 12) + * 110 = 2Gbyte (Rows = 14 & Col = 12) + * 111 = reserved + * [ 3: 3] Reserved + * [ 7: 7] Reserved + * [11:11] Reserved + * [31:15] + */ + 0xC280, 0xffff8888, 0x00000033, + /* DRAM Timing Low Register + * F2:0x88 + * [ 2: 0] Tcl (Cas# Latency, Cas# to read-data-valid) + * 000 = reserved + * 001 = CL 2 + * 010 = CL 3 + * 011 = reserved + * 100 = reserved + * 101 = CL 2.5 + * 110 = reserved + * 111 = reserved + * [ 3: 3] Reserved + * [ 7: 4] Trc (Row Cycle Time, Ras#-active to Ras#-active/bank auto refresh) + * 0000 = 7 bus clocks + * 0001 = 8 bus clocks + * ... + * 1110 = 21 bus clocks + * 1111 = 22 bus clocks + * [11: 8] Trfc (Row refresh Cycle time, Auto-refresh-active to RAS#-active or RAS#auto-refresh) + * 0000 = 9 bus clocks + * 0010 = 10 bus clocks + * .... + * 1110 = 23 bus clocks + * 1111 = 24 bus clocks + * [14:12] Trcd (Ras#-active to Case#-read/write Delay) + * 000 = reserved + * 001 = reserved + * 010 = 2 bus clocks + * 011 = 3 bus clocks + * 100 = 4 bus clocks + * 101 = 5 bus clocks + * 110 = 6 bus clocks + * 111 = reserved + * [15:15] Reserved + * [18:16] Trrd (Ras# to Ras# Delay) + * 000 = reserved + * 001 = reserved + * 010 = 2 bus clocks + * 011 = 3 bus clocks + * 100 = 4 bus clocks + * 101 = reserved + * 110 = reserved + * 111 = reserved + * [19:19] Reserved + * [23:20] Tras (Minmum Ras# Active Time) + * 0000 to 0100 = reserved + * 0101 = 5 bus clocks + * ... + * 1111 = 15 bus clocks + * [26:24] Trp (Row Precharge Time) + * 000 = reserved + * 001 = reserved + * 010 = 2 bus clocks + * 011 = 3 bus clocks + * 100 = 4 bus clocks + * 101 = 5 bus clocks + * 110 = 6 bus clocks + * 111 = reserved + * [27:27] Reserved + * [28:28] Twr (Write Recovery Time) + * 0 = 2 bus clocks + * 1 = 3 bus clocks + * [31:29] Reserved + */ + 0xC288, 0xe8088008, 0x03623125, + /* DRAM Timing High Register + * F2:0x8C + * [ 0: 0] Twtr (Write to Read Delay) + * 0 = 1 bus Clocks + * 1 = 2 bus Clocks + * [ 3: 1] Reserved + * [ 6: 4] Trwf (Read to Write Delay) + * 000 = 1 bus clocks + * 001 = 2 bus clocks + * 010 = 3 bus clocks + * 011 = 4 bus clocks + * 100 = 5 bus clocks + * 101 = 6 bus clocks + * 110 = reserved + * 111 = reserved + * [ 7: 7] Reserved + * [12: 8] Tref (Refresh Rate) + * 00000 = 100Mhz 4K rows + * 00001 = 133Mhz 4K rows + * 00010 = 166Mhz 4K rows + * 01000 = 100Mhz 8K/16K rows + * 01001 = 133Mhz 8K/16K rows + * 01010 = 166Mhz 8K/16K rows + * [19:13] Reserved + * [22:20] Twcl (Write CAS Latency) + * 000 = 1 Mem clock after CAS# (Unbuffered Dimms) + * 001 = 2 Mem clocks after CAS# (Registered Dimms) + * [31:23] Reserved + */ + 0xC28c, 0xff8fe08e, 0x00000930, + + /* DRAM Config Low Register + * F2:0x90 + * [ 0: 0] DLL Disable + * 0 = Enabled + * 1 = Disabled + * [ 1: 1] D_DRV + * 0 = Normal Drive + * 1 = Weak Drive + * [ 2: 2] QFC_EN + * 0 = Disabled + * 1 = Enabled + * [ 3: 3] Disable DQS Hystersis (FIXME handle this one carefully) + * 0 = Enable DQS input filter + * 1 = Disable DQS input filtering + * [ 7: 4] Reserved + * [ 8: 8] DRAM_Init + * 0 = Initialization done or not yet started. + * 1 = Initiate DRAM intialization sequence + * [ 9: 9] SO-Dimm Enable + * 0 = Do nothing + * 1 = SO-Dimms present + * [10:10] DramEnable + * 0 = DRAM not enabled + * 1 = DRAM initialized and enabled + * [11:11] Memory Clear Status + * 0 = Memory Clear function has not completed + * 1 = Memory Clear function has completed + * [12:12] Exit Self-Refresh + * 0 = Exit from self-refresh done or not yet started + * 1 = DRAM exiting from self refresh + * [13:13] Self-Refresh Status + * 0 = Normal Operation + * 1 = Self-refresh mode active + * [15:14] Read/Write Queue Bypass Count + * 00 = 2 + * 01 = 4 + * 10 = 8 + * 11 = 16 + * [16:16] 128-bit/64-Bit + * 0 = 64bit Interface to DRAM + * 1 = 128bit Interface to DRAM + * [17:17] DIMM ECC Enable + * 0 = Some DIMMs do not have ECC + * 1 = ALL DIMMS have ECC bits + * [18:18] UnBuffered DIMMs + * 0 = Buffered DIMMS + * 1 = Unbuffered DIMMS + * [19:19] Enable 32-Byte Granularity + * 0 = Optimize for 64byte bursts + * 1 = Optimize for 32byte bursts + * [20:20] DIMM 0 is x4 + * [21:21] DIMM 1 is x4 + * [22:22] DIMM 2 is x4 + * [23:23] DIMM 3 is x4 + * 0 = DIMM is not x4 + * 1 = x4 DIMM present + * [24:24] Disable DRAM Receivers + * 0 = Receivers enabled + * 1 = Receivers disabled + * [27:25] Bypass Max + * 000 = Arbiters chois is always respected + * 001 = Oldest entry in DCQ can be bypassed 1 time + * 010 = Oldest entry in DCQ can be bypassed 2 times + * 011 = Oldest entry in DCQ can be bypassed 3 times + * 100 = Oldest entry in DCQ can be bypassed 4 times + * 101 = Oldest entry in DCQ can be bypassed 5 times + * 110 = Oldest entry in DCQ can be bypassed 6 times + * 111 = Oldest entry in DCQ can be bypassed 7 times + * [31:28] Reserved + */ + 0xC290, 0xf0000000, + (4 << 25)|(0 << 24)| + (0 << 23)|(0 << 22)|(0 << 21)|(0 << 20)| + (1 << 19)|(1 << 18)|(0 << 17)|(0 << 16)| + (2 << 14)|(0 << 13)|(0 << 12)| + (0 << 11)|(0 << 10)|(0 << 9)|(0 << 8)| + (0 << 3) |(0 << 1) |(0 << 0), + /* DRAM Config High Register + * F2:0x94 + * [ 0: 3] Maximum Asynchronous Latency + * 0000 = 0 ns + * ... + * 1111 = 15 ns + * [ 7: 4] Reserved + * [11: 8] Read Preamble + * 0000 = 2.0 ns + * 0001 = 2.5 ns + * 0010 = 3.0 ns + * 0011 = 3.5 ns + * 0100 = 4.0 ns + * 0101 = 4.5 ns + * 0110 = 5.0 ns + * 0111 = 5.5 ns + * 1000 = 6.0 ns + * 1001 = 6.5 ns + * 1010 = 7.0 ns + * 1011 = 7.5 ns + * 1100 = 8.0 ns + * 1101 = 8.5 ns + * 1110 = 9.0 ns + * 1111 = 9.5 ns + * [15:12] Reserved + * [18:16] Idle Cycle Limit + * 000 = 0 cycles + * 001 = 4 cycles + * 010 = 8 cycles + * 011 = 16 cycles + * 100 = 32 cycles + * 101 = 64 cycles + * 110 = 128 cycles + * 111 = 256 cycles + * [19:19] Dynamic Idle Cycle Center Enable + * 0 = Use Idle Cycle Limit + * 1 = Generate a dynamic Idle cycle limit + * [22:20] DRAM MEMCLK Frequency + * 000 = 100Mhz + * 001 = reserved + * 010 = 133Mhz + * 011 = reserved + * 100 = reserved + * 101 = 166Mhz + * 110 = reserved + * 111 = reserved + * [24:23] Reserved + * [25:25] Memory Clock Ratio Valid (FIXME carefully enable memclk) + * 0 = Disable MemClks + * 1 = Enable MemClks + * [26:26] Memory Clock 0 Enable + * 0 = Disabled + * 1 = Enabled + * [27:27] Memory Clock 1 Enable + * 0 = Disabled + * 1 = Enabled + * [28:28] Memory Clock 2 Enable + * 0 = Disabled + * 1 = Enabled + * [29:29] Memory Clock 3 Enable + * 0 = Disabled + * 1 = Enabled + * [31:30] Reserved + */ + 0xC294, 0xc180f0f0, 0x0e2b0a05, + /* DRAM Delay Line Register + * F2:0x98 + * Adjust the skew of the input DQS strobe relative to DATA + * [15: 0] Reserved + * [23:16] Delay Line Adjust + * Adjusts the DLL derived PDL delay by one or more delay stages + * in either the faster or slower direction. + * [24:24} Adjust Slower + * 0 = Do Nothing + * 1 = Adj is used to increase the PDL delay + * [25:25] Adjust Faster + * 0 = Do Nothing + * 1 = Adj is used to decrease the PDL delay + * [31:26] Reserved + */ + 0xC298, 0xfc00ffff, 0x00000000, + /* DRAM Scrub Control Register + * F3:0x58 + * [ 4: 0] DRAM Scrube Rate + * [ 7: 5] reserved + * [12: 8] L2 Scrub Rate + * [15:13] reserved + * [20:16] Dcache Scrub + * [31:21] reserved + * Scrub Rates + * 00000 = Do not scrub + * 00001 = 40.00 ns + * 00010 = 80.00 ns + * 00011 = 160.00 ns + * 00100 = 320.00 ns + * 00101 = 640.00 ns + * 00110 = 1.28 us + * 00111 = 2.56 us + * 01000 = 5.12 us + * 01001 = 10.20 us + * 01011 = 41.00 us + * 01100 = 81.90 us + * 01101 = 163.80 us + * 01110 = 327.70 us + * 01111 = 655.40 us + * 10000 = 1.31 ms + * 10001 = 2.62 ms + * 10010 = 5.24 ms + * 10011 = 10.49 ms + * 10100 = 20.97 ms + * 10101 = 42.00 ms + * 10110 = 84.00 ms + * All Others = Reserved + */ + 0xC358, 0xffe0e0e0, 0x00000000, + /* DRAM Scrub Address Low Register + * F3:0x5C + * [ 0: 0] DRAM Scrubber Redirect Enable + * 0 = Do nothing + * 1 = Scrubber Corrects errors found in normal operation + * [ 5: 1] Reserved + * [31: 6] DRAM Scrub Address 31-6 + */ + 0xC35C, 0x0000003e, 0x00000000, + /* DRAM Scrub Address High Register + * F3:0x60 + * [ 7: 0] DRAM Scrubb Address 39-32 + * [31: 8] Reserved + */ + 0xC360, 0xffffff00, 0x00000000, + }; + int i; + int max; + print_debug("setting up northbridge registers\r\n"); + max = sizeof(register_values)/sizeof(register_values[0]); + for(i = 0; i < max; i += 3) { + unsigned long reg; +#if 0 + print_debug_hex32(register_values[i]); + print_debug(" <-"); + print_debug_hex32(register_values[i+2]); + print_debug("\r\n"); +#endif + reg = pcibios_read_config_dword( + 0, register_values[i] >> 8, register_values[i] & 0xff); + reg &= register_values[i+1]; + reg |= register_values[i+2] & ~register_values[i+1]; + pcibios_write_config_dword( + 0, register_values[i] >> 8, register_values[i] & 0xff, reg); + } + print_debug("setting up northbridge registers done. hurray!\r\n"); +} + +#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) + +#define DRAM_CONFIG_LOW 0x90 +#define DCL_DLL_Disable (1<<0) +#define DCL_D_DRV (1<<1) +#define DCL_QFC_EN (1<<2) +#define DCL_DisDqsHys (1<<3) +#define DCL_DramInit (1<<8) +#define DCL_DramEnable (1<<10) +#define DCL_MemClrStatus (1<<11) +#define DCL_DimmEcEn (1<<17) + +static void sdram_set_spd_registers(void) +{ + unsigned long dcl; + dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18,2), DRAM_CONFIG_LOW); + /* Until I know what is going on disable ECC support */ + dcl &= ~DCL_DimmEcEn; + pcibios_write_config_dword(0, PCI_DEVFN(0x18,2), DRAM_CONFIG_LOW, dcl); +} + +#define TIMEOUT_LOOPS 300000 +static void sdram_enable(void) +{ + unsigned long dcl; + + /* Toggle DisDqsHys to get it working */ + dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18,2), DRAM_CONFIG_LOW); + print_debug("dcl: "); + print_debug_hex32(dcl); + print_debug("\r\n"); + dcl |= DCL_DisDqsHys; + pcibios_write_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW, dcl); + dcl &= ~DCL_DisDqsHys; + dcl &= ~DCL_DLL_Disable; + dcl &= ~DCL_D_DRV; + dcl &= ~DCL_QFC_EN; + dcl |= DCL_DramInit; + pcibios_write_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW, dcl); + + print_debug("Initializing memory: "); + int loops = 0; + do { + dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW); + loops += 1; + if ((loops & 1023) == 0) { + print_debug(" "); + print_debug_hex32(loops); + } + } while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS)); + if (loops >= TIMEOUT_LOOPS) { + print_debug(" failed\r\n"); + } else { + print_debug(" done\r\n"); + } + +#if 0 + print_debug("Clearing memory: "); + loops = 0; + do { + dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW); + loops += 1; + if ((loops & 1023) == 0) { + print_debug(" "); + print_debug_hex32(loops); + } + } while(((dcl & DCL_MemClrStatus) == 0) && (loops < TIMEOUT_LOOPS)); + if (loops >= TIMEOUT_LOOPS) { + print_debug("failed\r\n"); + } else { + print_debug("done\r\n"); + } +#endif +} + +static void sdram_first_normal_reference(void) {} +static void sdram_enable_refresh(void) {} +static void sdram_special_finishup(void) {} + +static int sdram_enabled(void) +{ + unsigned long dcl; + int enabled; + dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW); + enabled = !!(dcl & DCL_DramEnable); + if (enabled) { + print_debug("DRAM already enabled."); + } + return enabled; +} + + +#include "sdram/generic_sdram.c" + +static void main(void) +{ + uart_init(); + console_init(); + if (!sdram_enabled()) { + sdram_initialize(); +#if 0 + ram_fill( 0x00100000, 0x00180000); + ram_verify(0x00100000, 0x00180000); +#endif +#if 1 + ram_fill( 0x00000000, 0x00001000); + ram_verify(0x00000000, 0x00001000); +#endif + } +} diff --git a/src/mainboard/amd/solo/cmos.layout b/src/mainboard/amd/solo/cmos.layout new file mode 100644 index 0000000000..5ba4c032c1 --- /dev/null +++ b/src/mainboard/amd/solo/cmos.layout @@ -0,0 +1,74 @@ +entries + +#start-bit length config config-ID name +#0 8 r 0 seconds +#8 8 r 0 alarm_seconds +#16 8 r 0 minutes +#24 8 r 0 alarm_minutes +#32 8 r 0 hours +#40 8 r 0 alarm_hours +#48 8 r 0 day_of_week +#56 8 r 0 day_of_month +#64 8 r 0 month +#72 8 r 0 year +#80 4 r 0 rate_select +#84 3 r 0 REF_Clock +#87 1 r 0 UIP +#88 1 r 0 auto_switch_DST +#89 1 r 0 24_hour_mode +#90 1 r 0 binary_values_enable +#91 1 r 0 square-wave_out_enable +#92 1 r 0 update_finished_enable +#93 1 r 0 alarm_interrupt_enable +#94 1 r 0 periodic_interrupt_enable +#95 1 r 0 disable_clock_updates +#96 288 r 0 temporary_filler +0 384 r 0 reserved_memory +384 1 e 4 boot_option +385 1 e 4 last_boot +386 1 e 1 ECC_memory +388 4 r 0 reboot_bits +392 3 e 5 baud_rate +400 1 e 1 power_on_after_fail +412 4 e 6 debug_level +416 4 e 7 boot_first +420 4 e 7 boot_second +424 4 e 7 boot_third +428 4 h 0 boot_index +432 8 h 0 boot_countdown +1008 16 h 0 check_sum + +enumerations + +#ID value text +1 0 Disable +1 1 Enable +2 0 Enable +2 1 Disable +4 0 Fallback +4 1 Normal +5 0 115200 +5 1 57600 +5 2 38400 +5 3 19200 +5 4 9600 +5 5 4800 +5 6 2400 +5 7 1200 +6 6 Notice +6 7 Info +6 8 Debug +6 9 Spew +7 0 Network +7 1 HDD +7 2 Floppy +7 8 Fallback_Network +7 9 Fallback_HDD +7 10 Fallback_Floppy +#7 3 ROM + +checksums + +checksum 392 1007 1008 + + diff --git a/src/mainboard/amd/solo/mainboard.c b/src/mainboard/amd/solo/mainboard.c new file mode 100644 index 0000000000..b8b8d6c3f2 --- /dev/null +++ b/src/mainboard/amd/solo/mainboard.c @@ -0,0 +1,25 @@ +#if 0 +#include <printk.h> +#endif + +void +mainboard_fixup(void) +{ +} + +void +final_mainboard_fixup(void) +{ +#if 0 +// void final_southbridge_fixup(void); +// void final_superio_fixup(void); + + printk_info("AMD Solo initializing..."); + +// final_southbridge_fixup(); + +//#ifndef USE_NEW_SUPERIO_INTERFACE +//final_superio_fixup(); +//#endif +#endif +} diff --git a/src/northbridge/amd/amdk8/northbridge.c b/src/northbridge/amd/amdk8/northbridge.c new file mode 100644 index 0000000000..1ba87bd083 --- /dev/null +++ b/src/northbridge/amd/amdk8/northbridge.c @@ -0,0 +1,22 @@ +#include <arch/io.h> +#include <stdint.h> +#include <mem.h> +#include <part/sizeram.h> + +struct mem_range *sizeram(void) +{ + static struct mem_range mem[3]; + uint32_t size; + /* Convert size in bytes to size in K */ + /* FIXME hardcoded for now */ + size = 512*1024; + + mem[0].basek = 0; + mem[0].sizek = 640; + mem[1].basek = 1024; + mem[1].sizek = size - mem[1].basek; + mem[2].basek = 0; + mem[2].sizek = 0; + return mem; +} + diff --git a/src/pc80/mc146818rtc.c b/src/pc80/mc146818rtc.c new file mode 100644 index 0000000000..b77653c52e --- /dev/null +++ b/src/pc80/mc146818rtc.c @@ -0,0 +1,249 @@ +#include <console/console.h> +#include <arch/io.h> +#include <pc80/mc146818rtc.h> +#include <boot/linuxbios_tables.h> +#include <string.h> + +#define CMOS_READ(addr) ({ \ +outb((addr),RTC_PORT(0)); \ +inb(RTC_PORT(1)); \ +}) + +#define CMOS_WRITE(val, addr) ({ \ +outb((addr),RTC_PORT(0)); \ +outb((val),RTC_PORT(1)); \ +}) + +/* control registers - Moto names + */ +#define RTC_REG_A 10 +#define RTC_REG_B 11 +#define RTC_REG_C 12 +#define RTC_REG_D 13 + + +/********************************************************************** + * register details + **********************************************************************/ +#define RTC_FREQ_SELECT RTC_REG_A + +/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus, + * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete, + * totalling to a max high interval of 2.228 ms. + */ +# define RTC_UIP 0x80 +# define RTC_DIV_CTL 0x70 + /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */ +# define RTC_REF_CLCK_4MHZ 0x00 +# define RTC_REF_CLCK_1MHZ 0x10 +# define RTC_REF_CLCK_32KHZ 0x20 + /* 2 values for divider stage reset, others for "testing purposes only" */ +# define RTC_DIV_RESET1 0x60 +# define RTC_DIV_RESET2 0x70 + /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */ +# define RTC_RATE_SELECT 0x0F +# define RTC_RATE_NONE 0x00 +# define RTC_RATE_32786HZ 0x01 +# define RTC_RATE_16384HZ 0x02 +# define RTC_RATE_8192HZ 0x03 +# define RTC_RATE_4096HZ 0x04 +# define RTC_RATE_2048HZ 0x05 +# define RTC_RATE_1024HZ 0x06 +# define RTC_RATE_512HZ 0x07 +# define RTC_RATE_256HZ 0x08 +# define RTC_RATE_128HZ 0x09 +# define RTC_RATE_64HZ 0x0a +# define RTC_RATE_32HZ 0x0b +# define RTC_RATE_16HZ 0x0c +# define RTC_RATE_8HZ 0x0d +# define RTC_RATE_4HZ 0x0e +# define RTC_RATE_2HZ 0x0f + +/**********************************************************************/ +#define RTC_CONTROL RTC_REG_B +# define RTC_SET 0x80 /* disable updates for clock setting */ +# define RTC_PIE 0x40 /* periodic interrupt enable */ +# define RTC_AIE 0x20 /* alarm interrupt enable */ +# define RTC_UIE 0x10 /* update-finished interrupt enable */ +# define RTC_SQWE 0x08 /* enable square-wave output */ +# define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */ +# define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ +# define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */ + +/**********************************************************************/ +#define RTC_INTR_FLAGS RTC_REG_C +/* caution - cleared by read */ +# define RTC_IRQF 0x80 /* any of the following 3 is active */ +# define RTC_PF 0x40 +# define RTC_AF 0x20 +# define RTC_UF 0x10 + +/**********************************************************************/ +#define RTC_VALID RTC_REG_D +# define RTC_VRT 0x80 /* valid RAM and time */ +/**********************************************************************/ + + + +static int rtc_checksum_valid(int range_start, int range_end, int cks_loc) +{ + int i; + unsigned sum, old_sum; + sum = 0; + for(i = range_start; i <= range_end; i++) { + sum += CMOS_READ(i); + } + sum = (~sum)&0x0ffff; + old_sum = ((CMOS_READ(cks_loc)<<8) | CMOS_READ(cks_loc+1))&0x0ffff; + return sum == old_sum; +} + +static void rtc_set_checksum(int range_start, int range_end, int cks_loc) +{ + int i; + unsigned sum; + sum = 0; + for(i = range_start; i <= range_end; i++) { + sum += CMOS_READ(i); + } + sum = ~(sum & 0x0ffff); + CMOS_WRITE(((sum >> 8) & 0x0ff), cks_loc); + CMOS_WRITE(((sum >> 0) & 0x0ff), cks_loc+1); +} + +#define RTC_CONTROL_DEFAULT (RTC_24H) +#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ) + +#if 0 /* alpha setup */ +#undef RTC_CONTROL_DEFAULT +#undef RTC_FREQ_SELECT_DEFAULT +#define RTC_CONTROL_DEFAULT (RTC_SQWE | RTC_24H) +#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ) +#endif +void rtc_init(int invalid) +{ + unsigned char x; + int cmos_invalid, checksum_invalid; + + printk_debug("RTC Init\n"); + /* See if there has been a CMOS power problem. */ + x = CMOS_READ(RTC_VALID); + cmos_invalid = !(x & RTC_VRT); + + /* See if there is a CMOS checksum error */ + checksum_invalid = !rtc_checksum_valid(PC_CKS_RANGE_START, + PC_CKS_RANGE_END,PC_CKS_LOC); + + if (invalid || cmos_invalid || checksum_invalid) { + int i; + printk_warning("RTC:%s%s%s zeroing cmos\n", + invalid?" Clear requested":"", + cmos_invalid?" Power Problem":"", + checksum_invalid?" Checksum invalid":""); +#if 0 + CMOS_WRITE(0, 0x01); + CMOS_WRITE(0, 0x03); + CMOS_WRITE(0, 0x05); + for(i = 10; i < 48; i++) { + CMOS_WRITE(0, i); + } + + if (cmos_invalid) { + /* Now setup a default date of Sat 1 January 2000 */ + CMOS_WRITE(0, 0x00); /* seconds */ + CMOS_WRITE(0, 0x02); /* minutes */ + CMOS_WRITE(1, 0x04); /* hours */ + CMOS_WRITE(7, 0x06); /* day of week */ + CMOS_WRITE(1, 0x07); /* day of month */ + CMOS_WRITE(1, 0x08); /* month */ + CMOS_WRITE(0, 0x09); /* year */ + } +#endif + } + /* See if there is a LB CMOS checksum error */ + checksum_invalid = !rtc_checksum_valid(LB_CKS_RANGE_START, + LB_CKS_RANGE_END,LB_CKS_LOC); + if(checksum_invalid) + printk_debug("Invalid CMOS LB checksum\n"); + + /* Setup the real time clock */ + CMOS_WRITE(RTC_CONTROL_DEFAULT, RTC_CONTROL); + /* Setup the frequency it operates at */ + CMOS_WRITE(RTC_FREQ_SELECT_DEFAULT, RTC_FREQ_SELECT); + /* Make certain we have a valid checksum */ + rtc_set_checksum(PC_CKS_RANGE_START, + PC_CKS_RANGE_END,PC_CKS_LOC); + /* Clear any pending interrupts */ + (void) CMOS_READ(RTC_INTR_FLAGS); +} + + +#if USE_OPTION_TABLE == 1 +/* This routine returns the value of the requested bits + input bit = bit count from the beginning of the cmos image + length = number of bits to include in the value + ret = a character pointer to where the value is to be returned + output the value placed in ret + returns 0 = successful, -1 = an error occurred +*/ +static int get_cmos_value(unsigned long bit, unsigned long length, void *vret) +{ + unsigned char *ret; + unsigned long byte,byte_bit; + unsigned long i; + unsigned char uchar; + + /* The table is checked when it is built to ensure all + values are valid. */ + ret = vret; + byte=bit/8; /* find the byte where the data starts */ + byte_bit=bit%8; /* find the bit in the byte where the data starts */ + if(length<9) { /* one byte or less */ + uchar = CMOS_READ(byte); /* load the byte */ + uchar >>= byte_bit; /* shift the bits to byte align */ + /* clear unspecified bits */ + ret[0] = uchar & ((1 << length) -1); + } + else { /* more that one byte so transfer the whole bytes */ + for(i=0;length;i++,length-=8,byte++) { + /* load the byte */ + ret[i]=CMOS_READ(byte); + } + } + return 0; +} + +int get_option(void *dest, char *name) +{ + extern struct cmos_option_table option_table; + struct cmos_option_table *ct; + struct cmos_entries *ce; + size_t namelen; + int found=0; + + /* Figure out how long name is */ + namelen = strnlen(name, CMOS_MAX_NAME_LENGTH); + + /* find the requested entry record */ + ct=&option_table; + ce=(struct cmos_entries*)((unsigned char *)ct + ct->header_length); + for(;ce->tag==LB_TAG_OPTION; + ce=(struct cmos_entries*)((unsigned char *)ce + ce->size)) { + if (memcmp(ce->name, name, namelen) == 0) { + found=1; + break; + } + } + if(!found) { + printk_err("ERROR: No cmos option '%s'\n", name); + return(-2); + } + + if(get_cmos_value(ce->bit, ce->length, dest)) + return(-3); + if(!rtc_checksum_valid(LB_CKS_RANGE_START, + LB_CKS_RANGE_END,LB_CKS_LOC)) + return(-4); + return(0); +} +#endif /* USE_OPTION_TABLE */ diff --git a/src/pc80/serial.c b/src/pc80/serial.c new file mode 100644 index 0000000000..b10d22dcba --- /dev/null +++ b/src/pc80/serial.c @@ -0,0 +1,93 @@ +#include <part/fallback_boot.h> + +/* Base Address */ +#ifndef TTYS0_BASE +#define TTYS0_BASE 0x3f8 +#endif + +#ifndef TTYS0_BAUD +#define TTYS0_BAUD 115200 +#endif + +#if ((115200%TTYS0_BAUD) != 0) +#error Bad ttys0 baud rate +#endif + +#define TTYS0_DIV (115200/TTYS0_BAUD) + +/* Line Control Settings */ +#ifndef TTYS0_LCS +/* Set 8bit, 1 stop bit, no parity */ +#define TTYS0_LCS 0x3 +#endif + +#define UART_LCS TTYS0_LCS + +/* Data */ +#define UART_RBR 0x00 +#define UART_TBR 0x00 + +/* Control */ +#define UART_IER 0x01 +#define UART_IIR 0x02 +#define UART_FCR 0x02 +#define UART_LCR 0x03 +#define UART_MCR 0x04 +#define UART_DLL 0x00 +#define UART_DLM 0x01 + +/* Status */ +#define UART_LSR 0x05 +#define UART_MSR 0x06 +#define UART_SCR 0x07 + +static int uart_can_tx_byte(void) +{ + return inb(TTYS0_BASE + UART_LSR) & 0x20; +} + +static void uart_wait_to_tx_byte(void) +{ + while(!uart_can_tx_byte()) + ; +} + +static void uart_wait_until_sent(void) +{ + while(!(inb(TTYS0_BASE + UART_LSR) & 0x40)) + ; +} + +static void uart_tx_byte(unsigned char data) +{ + uart_wait_to_tx_byte(); + outb(data, TTYS0_BASE + UART_TBR); + /* Make certain the data clears the fifos */ + uart_wait_until_sent(); +} + +static void uart_init(void) +{ + /* disable interrupts */ + outb(0x0, TTYS0_BASE + UART_IER); + /* enable fifo's */ + outb(0x01, TTYS0_BASE + UART_FCR); + /* Set Baud Rate Divisor to 12 ==> 115200 Baud */ + outb(0x80 | UART_LCS, TTYS0_BASE + UART_LCR); +#if 0 && USE_OPTION_TABLE == 1 + { + static const unsigned char divisor[] = { 1,2,3,6,12,24,48,96 }; + unsigned ttys0_div, ttys0_index; + outb(RTC_BOOT_BYTE + 1, 0x70); + ttys0_index = inb(0x71); + ttys0_index &= 7; + ttys0_div = divisor[ttys0_index]; + outb(ttys0_div & 0xff, TTYS0_BASE + UART_DLL); + outb(0, TTYS0_BASE + UART_DLM); + } +#else + outb(TTYS0_DIV & 0xFF, TTYS0_BASE + UART_DLL); + outb((TTYS0_DIV >> 8) & 0xFF, TTYS0_BASE + UART_DLM); +#endif + outb(UART_LCS, TTYS0_BASE + UART_LCR); +} diff --git a/src/pc80/serial.inc b/src/pc80/serial.inc new file mode 100644 index 0000000000..b0f12699e1 --- /dev/null +++ b/src/pc80/serial.inc @@ -0,0 +1,106 @@ +#include <part/fallback_boot.h> + + +/* Base Address */ +#ifndef TTYS0_BASE +#define TTYS0_BASE 0x3f8 +#endif + +/* Baud Rate */ +#ifndef TTYS0_BAUD +#define TTYS0_BAUD 115200 +#endif + +#if ((115200%TTYS0_BAUD) != 0) +#error Bad ttys0 baud rate +#endif + +/* Baud Rate Divisor */ +#define TTYS0_DIV (115200/TTYS0_BAUD) +#define TTYS0_DIV_LO (TTYS0_DIV&0xFF) +#define TTYS0_DIV_HI ((TTYS0_DIV >> 8)&0xFF) + +/* Line Control Settings */ +#ifndef TTYS0_LCS +/* Set 8bit, 1 stop bit, no parity */ +#define TTYS0_LCS 0x3 +#endif + +/* Data */ +#define TTYS0_RBR (TTYS0_BASE+0x00) + +/* Control */ +#define TTYS0_TBR TTYS0_RBR +#define TTYS0_IER (TTYS0_BASE+0x01) +#define TTYS0_IIR (TTYS0_BASE+0x02) +#define TTYS0_FCR TTYS0_IIR +#define TTYS0_LCR (TTYS0_BASE+0x03) +#define TTYS0_MCR (TTYS0_BASE+0x04) +#define TTYS0_DLL TTYS0_RBR +#define TTYS0_DLM TTYS0_IER + +/* Status */ +#define TTYS0_LSR (TTYS0_BASE+0x05) +#define TTYS0_MSR (TTYS0_BASE+0x06) +#define TTYS0_SCR (TTYS0_BASE+0x07) + +#if USE_OPTION_TABLE == 1 +.section ".rom.data" + .type div,@object + .size div,8 +div: +.byte 1,2,3,6,12,24,48,96 + +.previous +#endif + + jmp serial0 + + /* uses: ax, dx */ +#define TTYS0_TX_AL \ + mov %al, %ah ; \ +9: mov $TTYS0_LSR, %dx ; \ + inb %dx, %al ; \ + test $0x20, %al ; \ + je 9b ; \ + mov $TTYS0_TBR, %dx ; \ + mov %ah, %al ; \ + outb %al, %dx + + +serial0: + /* Set 115.2Kbps,8n1 */ + /* Set 8bit, 1 stop bit, no parity, DLAB */ + mov $TTYS0_LCR, %dx + mov $(TTYS0_LCS | 0x80), %al + out %al, %dx + + /* set Baud Rate Divisor to 1 ==> 115200 Buad */ +#if USE_OPTION_TABLE == 1 + + movb $(RTC_BOOT_BYTE+1), %al + outb %al, $0x70 + xorl %edx,%edx + inb $0x71, %al + andb $7,%al + movb %al,%dl + movb div(%edx),%al + mov $TTYS0_DLL, %dx + out %al, %dx + mov $TTYS0_DLM, %dx + xorb %al,%al + out %al, %dx +#else + mov $TTYS0_DLL, %dx + mov $TTYS0_DIV_LO, %al + out %al, %dx + mov $TTYS0_DLM, %dx + mov $TTYS0_DIV_HI, %al + out %al, %dx +#endif + /* Disable DLAB */ + mov $TTYS0_LCR, %dx + mov $(TTYS0_LCS & 0x7f), %al + out %al, %dx + + diff --git a/src/ram/ramtest.c b/src/ram/ramtest.c new file mode 100644 index 0000000000..0e5e6982a3 --- /dev/null +++ b/src/ram/ramtest.c @@ -0,0 +1,89 @@ +static void write_phys(unsigned long addr, unsigned long value) +{ + unsigned long *ptr; + ptr = (void *)addr; + *ptr = value; +} + +static unsigned long read_phys(unsigned long addr) +{ + unsigned long *ptr; + ptr = (void *)addr; + return *ptr; +} + +void ram_fill(unsigned long start, unsigned long stop) +{ + unsigned long addr; + /* + * Fill. + */ + print_debug("DRAM fill: "); + print_debug_hex32(start); + print_debug("-"); + print_debug_hex32(stop); + print_debug("\r\n"); + for(addr = start; addr < stop ; addr += 4) { + /* Display address being filled */ + if ((addr & 0xffff) == 0) { + print_debug_hex32(addr); + print_debug("\r"); + } + write_phys(addr, addr); + }; + /* Display final address */ + print_debug_hex32(addr); + print_debug("\r\nDRAM filled\r\n"); +} + +void ram_verify(unsigned long start, unsigned long stop) +{ + unsigned long addr; + /* + * Verify. + */ + print_debug("DRAM verify: "); + print_debug_hex32(start); + print_debug_char('-'); + print_debug_hex32(stop); + print_debug("\r\n"); + for(addr = start; addr < stop ; addr += 4) { + unsigned long value; + /* Display address being tested */ + if ((addr & 0xffff) == 0) { + print_debug_hex32(addr); + print_debug("\r"); + } + value = read_phys(addr); + if (value != addr) { + /* Display address with error */ + print_err_hex32(addr); + print_err_char(':'); + print_err_hex32(value); + print_err("\r\n"); + } + } + /* Display final address */ + print_debug_hex32(addr); + print_debug("\r\nDRAM verified\r\n"); +} + + +void ramcheck(unsigned long start, unsigned long stop) +{ + int result; + /* + * This is much more of a "Is my DRAM properly configured?" + * test than a "Is my DRAM faulty?" test. Not all bits + * are tested. -Tyson + */ + print_debug("Testing DRAM : "); + print_debug_hex32(start); + print_debug("-"); + print_debug_hex32(stop); + print_debug("\r\n"); + ram_fill(start, stop); + ram_verify(start, stop); + print_debug("Done.\n"); +} + diff --git a/src/sdram/generic_dump_spd.c b/src/sdram/generic_dump_spd.c new file mode 100644 index 0000000000..27f1844d3c --- /dev/null +++ b/src/sdram/generic_dump_spd.c @@ -0,0 +1,25 @@ +void dump_spd_registers(void) +{ + unsigned device; + device = SMBUS_MEM_DEVICE_START; + printk_debug("\n"); + while(device <= SMBUS_MEM_DEVICE_END) { + int status = 0; + int i; + printk_debug("dimm %02x", device); + for(i = 0; (i < 256) && (status == 0); i++) { + unsigned char byte; + if ((i % 20) == 0) { + printk_debug("\n%3d: ", i); + } + status = smbus_read_byte(device, i, &byte); + if (status != 0) { + printk_debug("bad device\n"); + continue; + } + printk_debug("%02x ", byte); + } + device += SMBUS_MEM_DEVICE_INC; + printk_debug("\n"); + } +} diff --git a/src/sdram/generic_sdram.c b/src/sdram/generic_sdram.c new file mode 100644 index 0000000000..be5ae87407 --- /dev/null +++ b/src/sdram/generic_sdram.c @@ -0,0 +1,35 @@ +void sdram_no_memory(void) +{ + print_err("No memory!!\r\n"); + while(1) { + hlt(); + } +} + +/* Setup SDRAM */ +void sdram_initialize(void) +{ + print_debug("Ram1\r\n"); + /* Set the registers we can set once to reasonable values */ + sdram_set_registers(); + + print_debug("Ram2\r\n"); + /* Now setup those things we can auto detect */ + sdram_set_spd_registers(); + + print_debug("Ram3\r\n"); + /* Now that everything is setup enable the SDRAM. + * Some chipsets do the work for use while on others + * we need to it by hand. + */ + sdram_enable(); + + print_debug("Ram4\r\n"); + sdram_first_normal_reference(); + + print_debug("Ram5\r\n"); + sdram_enable_refresh(); + sdram_special_finishup(); + + print_debug("Ram6\r\n"); +} diff --git a/src/stream/rom_stream.c b/src/stream/rom_stream.c new file mode 100644 index 0000000000..20b7686c84 --- /dev/null +++ b/src/stream/rom_stream.c @@ -0,0 +1,58 @@ +#include <console/console.h> +#include <stdlib.h> +#include <stddef.h> +#include <stream/read_bytes.h> +#include <string.h> + + +#ifndef CONFIG_ROM_STREAM_START +#define CONFIG_ROM_STREAM_START 0xffff0000UL +#endif + +static const unsigned char *rom_start = (void *)CONFIG_ROM_STREAM_START; +static const unsigned char *rom_end = (void *)(CONFIG_ROM_STREAM_START + PAYLOAD_SIZE - 1); +static const unsigned char *rom; + +int stream_init(void) +{ + rom = rom_start; + + printk_spew("%6d:%s() - rom_stream: 0x%08lx - 0x%08lx\n" + __LINE__, __FUNCTION__, + (unsigned long)rom_start, + (unsigned long)rom_end); + return 0; +} + + +void stream_fini(void) +{ + return; +} + +byte_offset_t stream_skip(byte_offset_t count) +{ + byte_offset_t bytes; + bytes = count; + if ((rom + bytes) > rom_end) { + printk_warning("%6d:%s() - overflowed source buffer\n", + __LINE__, __FUNCTION__); + bytes = 0; + if (rom <= rom_end) { + bytes = (rom_end - rom) + 1; + } + } + rom += bytes; + return bytes; +} + +byte_offset_t stream_read(void *vdest, byte_offset_t count) +{ + unsigned char *dest = vdest; + const unsigned char *src = rom; + byte_offset_t bytes; + + bytes = stream_skip(count); + memcpy(dest, src, bytes); + return bytes; +} |