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/arch/i386 | |
parent | b138ac83b53da9abf3dc9a87a1cd4b3d3a8150bd (diff) |
- 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/arch/i386')
28 files changed, 3159 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); +} + |