diff options
| author | Jon duSaint | 2022-05-03 10:13:04 -0700 |
|---|---|---|
| committer | Jon duSaint | 2022-05-03 10:13:04 -0700 |
| commit | 1b86e776c0eff16184b3d3e9c31d20214c2b5d68 (patch) | |
| tree | 52cbad8481865ccbfb02ae243dbab7fe748a8507 | |
| parent | 1d7ce9124a2fa3cbe8dc5761228ca29abf20659f (diff) | |
cpuid: add old project
| -rw-r--r-- | README | 9 | ||||
| -rw-r--r-- | cpuid/Makefile | 45 | ||||
| -rw-r--r-- | cpuid/bochs.cfg | 47 | ||||
| -rw-r--r-- | cpuid/boot.S | 282 | ||||
| -rw-r--r-- | cpuid/cpuid.h | 206 | ||||
| -rw-r--r-- | cpuid/entry.c | 39 | ||||
| -rw-r--r-- | cpuid/head.S | 569 | ||||
| -rw-r--r-- | cpuid/igate.S | 134 | ||||
| -rw-r--r-- | cpuid/interrupt.c | 406 | ||||
| -rw-r--r-- | cpuid/interrupt.h | 63 | ||||
| -rw-r--r-- | cpuid/keyboard.c | 200 | ||||
| -rw-r--r-- | cpuid/keyboard.h | 160 | ||||
| -rw-r--r-- | cpuid/ld.conf | 75 | ||||
| -rw-r--r-- | cpuid/libcpuid/cpuid.c | 3854 | ||||
| -rw-r--r-- | cpuid/log.c | 76 | ||||
| -rw-r--r-- | cpuid/malloc.c | 469 | ||||
| -rw-r--r-- | cpuid/memory.c | 376 | ||||
| -rw-r--r-- | cpuid/serial.c | 0 | ||||
| -rw-r--r-- | cpuid/setsectors.pl | 46 | ||||
| -rw-r--r-- | cpuid/spinlock.c | 31 | ||||
| -rw-r--r-- | cpuid/spinlock.h | 27 | ||||
| -rw-r--r-- | cpuid/stdio.c | 303 | ||||
| -rw-r--r-- | cpuid/stdio.h | 19 | ||||
| -rw-r--r-- | cpuid/stdlib.h | 24 | ||||
| -rw-r--r-- | cpuid/string.c | 197 | ||||
| -rw-r--r-- | cpuid/string.h | 25 | ||||
| -rw-r--r-- | cpuid/timer.c | 87 | ||||
| -rw-r--r-- | cpuid/video.c | 251 |
28 files changed, 8020 insertions, 0 deletions
@@ -24,6 +24,15 @@ this during my first deployment to Afghanistan way back in 2002. Internet access was nil and all I had was a copy of ActiveState Perl to keep me entertained. This was the result. +## CPUID + +Incomplete and somewhat out of data micro-OS that boots and is +supposed to display CPUID information. The part that isn't complete +is the CPUID-display part, though there's a test program that works +pretty well. The actual OS part seems to work just fine, making this +of passing interest. + + ## decomp  diff --git a/cpuid/Makefile b/cpuid/Makefile new file mode 100644 index 0000000..069e755 --- /dev/null +++ b/cpuid/Makefile @@ -0,0 +1,45 @@ +# Makefile for CPUID + +CC = /usr/bin/gcc +LD = /usr/bin/ld +PERL = /usr/bin/perl + +LDCONF = ld.conf + +CFLAGS = -Wall -Os -m32 -fno-reorder-functions -nostartfiles -nostdlib -fno-builtin -I. -I. +LDFLAGS = -T $(LDCONF) -melf_i386 -s + +BOOTSECTORSRC = boot.S +BOOTSECTOR = $(BOOTSECTORSRC:.S=.o) + +CFILES = entry.c interrupt.c memory.c video.c keyboard.c serial.c log.c string.c stdio.c malloc.c spinlock.c timer.c +HFILES = cpuid.h string.h stdlib.h stdio.h spinlock.h +SFILES = head.S igate.S +OFILES = $(SFILES:.S=.o) $(CFILES:.c=.o) +ASMFILES = $(CFILES:.c=.S) + +MAPFILE = boot.map +SETSECTORS = $(PERL) setsectors.pl $(MAPFILE) + +.PHONY : all asm clean + +all : floppy.img + +floppy.img : boot + dd if=/dev/zero of=$@ bs=512 count=2880 + dd if=boot of=$@ bs=512 conv=notrunc + +boot : $(BOOTSECTOR) $(OFILES) $(HFILES) + $(LD) $(LDFLAGS) $(BOOTSECTOR) $(OFILES) -o $@ -M >$(MAPFILE) + $(SETSECTORS) + +asm : $(ASMFILES) + +%.o : %.S + $(CC) -DASM $(CFLAGS) -c $< -o $@ + +%.S : %.c + $(CC) $(CFLAGS) -S $< -o $@ + +clean : + rm -f $(OFILES) $(ASMFILES) $(BOOTSECTOR) boot.map *~ boot floppy.img diff --git a/cpuid/bochs.cfg b/cpuid/bochs.cfg new file mode 100644 index 0000000..2780b87 --- /dev/null +++ b/cpuid/bochs.cfg @@ -0,0 +1,47 @@ +# configuration file generated by Bochs +config_interface: textconfig +display_library: x +megs: 32 +romimage: file="/usr/share/bochs/BIOS-bochs-latest", address=0x00000 +vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest" +boot: floppy +# no floppya +# no floppyb +ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 +ata2: enabled=0 +ata3: enabled=0 +parport1: enabled=1, file="" +parport2: enabled=0 +com1: enabled=1, mode=null, dev="" +com2: enabled=0 +com3: enabled=0 +com4: enabled=0 +i440fxsupport: enabled=1 +usb1: enabled=0 +sb16: enabled=0 +floppy_bootsig_check: disabled=0 +vga_update_interval: 40000 +vga: extension=vbe +keyboard_serial_delay: 250 +keyboard_paste_delay: 100000 +cpu: count=1, ips=2000000 +text_snapshot_check: 0 +mouse: enabled=0 +private_colormap: enabled=0 +clock: sync=none, time0=local +ne2k: enabled=0 +pnic: enabled=0 +# no loader +log: - +logprefix: %t%e%d +debugger_log: - +panic: action=ask +error: action=report +info: action=report +debug: action=ignore +pass: action=fatal +keyboard_mapping: enabled=0, map= +keyboard_type: mf +user_shortcut: keys=none +# no cmosimage diff --git a/cpuid/boot.S b/cpuid/boot.S new file mode 100644 index 0000000..bc80b6a --- /dev/null +++ b/cpuid/boot.S @@ -0,0 +1,282 @@ + # boot.S + + # Boot sector for CPUID. This does basic CPU bring up and transfers + # control to C for the rest of the bring up (IDT) and for the + # interactive code + + +#include "cpuid.h" + + + .code16 + + .global _start +_start: ljmp $0, $boing + +/* BPB + * BIOSs seem to expect this FAT12 relic to be here. + * + * For 3.5" floppies: tracks 80, sectors/track 18, sectors/disk 2880 + */ + +/* OEM Name is 6 bytes to make room for above absolute jump */ +BPB_OEM_Name: + .asciz "E2-OS" +BPB_bytes_per_sector: + .word 512 +BPB_sectors_per_cluster: + .byte 1 +BPB_reserved_sector_count: + .word 0 +BPB_number_FAT: + .byte 0 +BPB_max_nrootdirent: + .word 0 +BPB_total_sectors: + .word 2880 +BPB_media_descriptor: + .byte 0x00 /* this field can't be accurate */ +BPB_sector_per_FAT: + .word 0 +BPB_sectors_per_track: + .word 18 +BPB_number_heads: + .word 2 + + + # real mode setup +boing: cli + xorw %ax, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw $REAL_STACK, %ax + movw %ax, %sp + sti + + # check load drive - should be fd0 (dl == 0) + testb %dl, %dl + jnz not_from_floppy_error + + # reset floppy controller + xorb %ah, %ah + int $0x13 + + # load the rest of the program + call print_loading_message + call copy_from_floppy + call print_done_message + + # jump to the initialization code in head.S + movl $CPUID_BOOT_SIGNATURE, %edx + jmp _head + + +#------------------------------------------------------------------------------ +# +# copy_from_floppy -- +# +# Copy the program from the floppy. The number of sectors to be +# copied is magically generated during the linking stage. +# +#------------------------------------------------------------------------------ + +copy_from_floppy: + enter $16, $0 + + # -16(%bp) floppy error counter + # -12(%bp) current_sector + # -8(%bp) number_of_sectors (round_up (size (program) / 512)) + # -4(%bp) current_segment (starts at 1000) + + movw $1, -12(%bp) + movw number_of_sectors, %ax + movw %ax, -8(%bp) + movw $(HEAD_ADDR >> 4), -4(%bp) + +copy_block: + # reset error counter + movw $2, -16(%bp) +try_again: + movw -12(%bp), %ax + call lba_to_chs + + movw -4(%bp), %es + xorw %bx, %bx + xorb %dl, %dl + movw $0x0240, %ax + + int $0x13 + jnc read_ok + + # read failed - reset floppy, decrement error counter, and try again + xorb %ah, %ah + xorb %dl, %dl + int $0x13 + + decw -16(%bp) + jnc try_again + + # tried 3 times and failed - bail out + jmp floppy_error + +read_ok: + movw $0x0e2e, %ax + movw $0x0001, %bx + int $0x10 + + # update segment + addw $0x0800, -4(%bp) + + # update sector + addw $64, -12(%bp) + + # update number of sectors + ### FIXME - there's room now, so do this right + + movw $64, %ax + subw %ax, -8(%bp) + + jnc copy_block + + # all done + + leave + ret + + +#------------------------------------------------------------------------------ +# +# lba_to_chs -- +# +# Convert an LBA sector in AX to CHS. +# +# +# Input: +# linear sector number in AX +# +# Output: +# CH - cylinder number, CL - sector number, DH - head number +# +#------------------------------------------------------------------------------ + +lba_to_chs: + xorw %dx, %dx + movb $18, %cl # can get away with this since DS16 < 256 + idivw %cx + + movw %dx, %cx + incw %cx # cx[0..5] = sector + + xorw %dx, %dx + shrw $1, %ax + jnc 1f + + incb %dh # dh[0] = head + +1: shlw $6, %ax + orw %ax, %cx # cx[15..6] = track + + ret + + +#------------------------------------------------------------------------------ +# +# not_from_floppy_error -- +# +# Print an error message if the load drive is not fd0. +# +#------------------------------------------------------------------------------ + +not_from_floppy_error: + movw $not_from_floppy_msg, %si + call message + jmp halt + +#------------------------------------------------------------------------------ +# +# print_loading_message -- +# +# Print "Loading" while data from the floppy loads. +# +#------------------------------------------------------------------------------ + +print_loading_message: + movw $loading_msg, %si + jmp message + +#------------------------------------------------------------------------------ +# +# print_done_message -- +# +# Print "done" once the data from the floppy has loaded. +# +#------------------------------------------------------------------------------ + +print_done_message: + movw $done_msg, %si + jmp message + +#------------------------------------------------------------------------------ +# +# floppy_error -- +# +# Print a floppy error message and loop forever. +# +#------------------------------------------------------------------------------ + +floppy_error: + movw $floppy_error_msg, %si + call message + jmp halt + +#------------------------------------------------------------------------------ +# +# message -- +# +# Display a message. +# +#------------------------------------------------------------------------------ + +message: + lodsb + cmpb $0, %al + jz 1f + + movb $0xe, %ah + movw $0x0001, %bx + int $0x10 + jmp message + +1: ret + +#------------------------------------------------------------------------------ +# +# halt -- +# +# Call hlt in an infinite loop. +# +#------------------------------------------------------------------------------ + +halt: hlt + jmp halt + + + + .align 1 +not_from_floppy_msg: + .asciz "Boot drive must be fd0!" +loading_msg: + .asciz "Loading" +done_msg: + .asciz " done" +floppy_error_msg: + .asciz "Unable to read floppy!" + + .align 2 + .global number_of_sectors +number_of_sectors: + .word 0 # filled in via loader magic + + .org 510 + .byte 0x55, 0xaa diff --git a/cpuid/cpuid.h b/cpuid/cpuid.h new file mode 100644 index 0000000..de0845d --- /dev/null +++ b/cpuid/cpuid.h @@ -0,0 +1,206 @@ +/*----------------------------------------------------------------------------- + * + * cpuid.h -- + * + * Global definitions for cpuid. + * + *----------------------------------------------------------------------------- + */ + +#ifndef _CPUID_H +#define _CPUID_H + + +#define CPUID_BOOT_SIGNATURE 0xaddabead + + +/* + *----------------------------------------------------------------------------- + * + * Memory locations. See above memory map. + * + * Memory map for cpuid: + * + * Heap + * 200000 - + * CPUID text + data + * 100000 - (CLOAD_ADDR) + * BIOS/video stuff + * a0000 - (STACK) + * Protected mode stack (64k) + * 10000 - + * _head + * 8000 - (HEAD_ADDR) + * Not used + * 7e00 - + * Boot sector + * 7c00 - (REAL_STACK) + * Real mode stack + * 6000 - + * Interrupt descriptor table + * 5000 - (IDT) + * Page table for first 4MiB + * 4000 - (PAGE_TABLE) + * Page directory + * 3000 - (PAGE_DIRECTORY) + * e820 map + * 2000 - (E820_MAP) + * 1800 - + * Global descriptor table + * 1000 - (GDT) + * Not used + * + *----------------------------------------------------------------------------- + */ + +#define GDT 0x01000 +#define IDT 0x05000 +#define REAL_STACK 0x07c00 +#define HEAD_ADDR 0x08000 +#define STACK 0xa0000 +#define CLOAD_ADDR 0x100000 + +/* + *----------------------------------------------------------------------------- + * + * Segment descriptors -- + * + * CS is code segment, and DS is data segment. Both have base 0, + * limit 4GB, and are 32 bit segments (flat 32 bit address space). + * + *----------------------------------------------------------------------------- + */ + +#define CS 0x0008 +#define DS 0x0010 + + +/* + *----------------------------------------------------------------------------- + * + * BIOS int 15 function e820 interface -- + * + * + * + *----------------------------------------------------------------------------- + */ + +#ifndef ASM + +struct e820info { + unsigned long long BaseAddr; + unsigned long long Length; + unsigned long Type; +}; + +#endif /* !ASM */ + +#define SMAP 0x534d4150 +#define E820_MAP 0x2000 +#define E820_SIZE 20 +#define E820_MAX 128 + +#define E820_TYPE_ARM 1 +#define E820_TYPE_ARR 2 +#define E820_TYPE_ACPI 3 +#define E820_TYPE_NVS 4 + +/* + *----------------------------------------------------------------------------- + * + * Page tables -- + * + * + * + *----------------------------------------------------------------------------- + */ + +#define PAGE_DIRECTORY 0x3000 +#define PAGE_TABLE 0x4000 + +#define PAGE_SIZE 0x1000 +#define MASK4k 0xfffff000 + + + +#ifndef ASM + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <spinlock.h> +#include <interrupt.h> +#include <keyboard.h> + +/* GCC provided stdarg.h */ +#include <stdarg.h> + +#define LOG_SIZE (PAGE_SIZE * 16) + +enum panic_reason { + NO_REASON, + MEMORY_EXHAUSTED +}; + +#define PANIC(m) ({ goto_xy (0, 0); \ + print_str ("!!!!! PANIC: "); \ + print_hex32 ((unsigned long)m); \ + print_str (" !!!!!"); \ + halt (); }) + +static inline void +outb (char val, char port) +{ + asm ("movb %0, %%al\n\t" + "outb %%al, %1\n" + :: "m" (val), "i" (port) + : "al"); +} + +static inline unsigned char +inb (char port) +{ + char byte; + + asm ("inb %1, %%al\n\t" + "movb %%al, %0\n" + : "=m" (byte) + : "i" (port) + : "al"); + + return byte; +} + +static inline void +halt (void) +{ + while (1) { + asm ("hlt\n"); + } +} + +extern volatile int logging; + +extern void goto_xy (unsigned long x, unsigned long y); +extern void get_xy (unsigned long *x, unsigned long *y); +extern void putchar (char); +extern void print_str (char *); +extern void print_hex8 (unsigned char); +extern void print_hex16 (unsigned short); +extern void print_hex32 (unsigned long); +extern void print_hex64 (unsigned long long); +extern void dump_cpu (void); + +extern void *get_pages (unsigned long, unsigned long *); +extern void create_heap (void); + +extern void setup_log (void); +extern void log_msg (char *); +extern void console_dump_log (void); +extern void serial_dump_log (void); + +extern void timer_init (void); + +#endif /* !ASM */ + +#endif /* !_CPUID_H */ diff --git a/cpuid/entry.c b/cpuid/entry.c new file mode 100644 index 0000000..b302383 --- /dev/null +++ b/cpuid/entry.c @@ -0,0 +1,39 @@ +/* + *----------------------------------------------------------------------------- + * + * entry.c -- + * + * Entry point of protected mode C code for CPUID. This completes + * protected mode setup (initialized IDT) and installs serial port, + * video, and keyboard handlers, then calls cpuid. + * + *----------------------------------------------------------------------------- + */ + +#include <cpuid.h> + +static char banner[] = "=========================== Welcome to CPUID! ===========================\n\n"; + +void +entry (void) +{ + print_str (banner); + + create_idt (); + nmi_on (); + sti (); + + create_heap (); + setup_log (); + + timer_init (); + keyboard_init (); + + +/* serial_init (); */ + +/* do_cpuid (); */ + + /* loop forever */ + halt (); +} diff --git a/cpuid/head.S b/cpuid/head.S new file mode 100644 index 0000000..2a91802 --- /dev/null +++ b/cpuid/head.S @@ -0,0 +1,569 @@ + # head.S + # Stub called by the boot loader. This is where the memory map + # is made, the system is moved into protected mode, and the call + # into the actual C code is finally done. + +#include <cpuid.h> + + .text + .code16 + +#------------------------------------------------------------------------------ +# +# _head -- +# +# Start routine after control transfers from the boot sector. +# +# When this routine is called, interrupts should be enabled, the +# CPU is still in real mode, and the entire program should be loaded. +# +#------------------------------------------------------------------------------ + .global _head +_head: + # check signature + cmpl $CPUID_BOOT_SIGNATURE, %edx + jne bad_signature_flaming_death + + # turn off the cursor + movw 0x0100, %cx + movb $1, %ah + int $0x10 + + # check that there is memory available from 1-2 MiB + movb $0x88, %ah + int $015 + jnc 1f + + call unknown_memory_warning + movw $1024, %ax + +1: cmpw $1024, %ax + jae 2f + + # less than two MiB of memory available - not cool + call clear_screen + movw $not_enough_mem_msg, %si + call message + jmp halt + + + # OK, life is good, let's get this show on the road +2: call map_memory + + # get into protected mode + + call enable_A20 + + # copy the GDT to its place + xorw %ax, %ax + movw %ax, %es + movw $GDT_STORE, %si + movw $GDT, %di + movw $((GDT_STORE_END - GDT_STORE) >> 1), %cx + cld + rep + movsw + + # turn off all interrupts + cli + movb $0x80, %al + outb %al, $0x70 + + lgdt GDT_ADDR + + # C will load IDT + + movl %cr0, %eax + orl $1, %eax + movl %eax, %cr0 + + jmp flush +flush: + # protected mode setup + movw $DS, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + movl $STACK, %eax + movl %eax, %esp + + # off to 32 bit land + .code32 + .byte 0x66 + ljmp $CS, $finish_this_setup + +#------------------------------------------------------------------------------ +# +# 16 bit subroutines -- +# +#------------------------------------------------------------------------------ + + .code16 + +unknown_memory_warning: + call clear_screen + movw $unknown_mem_msg, %si + call message + + # beep a few times + movw $4, %dx +1: movb $182, %al + outb %al, $0x43 + movw $1140, %ax + outb %al, $0x42 + movb %ah, %al + outb %al, $0x42 + inb $0x61, %al + orb $0x3, %al + outb %al, $0x61 + + # wait + movb $25, %bl +2: movw $0xffff, %cx +3: decw %cx + jnz 3b + decb %bl + jnz 2b + + inb $0x61, %al + andb $0xfc, %al + outb %al, $0x61 + + # wait + movb $125, %bl +2: movw $0xffff, %cx +3: decw %cx + jnz 3b + decb %bl + jnz 2b + + decw %dx + jnz 1b + + ret + +#------------------------------------------------------------------------------ +# +# map_memory -- +# +# Build a map of memory, using int 15 function e820. If this doesn't +# work, throw an egregious error and bail out like a coward. +# +#------------------------------------------------------------------------------ + +map_memory: + movw $((E820_MAP & ~0xfff) >> 4), %ax + movw %ax, %es + movw $(E820_MAP & 0xfff), %di + movl $0, %es:(%di) + addw $4, %di + xorl %ebx, %ebx + pushw $E820_MAX + +domap: movl $0xe820, %eax + movl $E820_SIZE, %ecx + movl $SMAP, %edx + + int $0x15 + jc e820_error + + cmpl $SMAP, %eax + jne e820_error + + addw $E820_SIZE, %di + jc e820_error + + incl %es:(E820_MAP & 0xfff) + + popw %ax + decw %ax + pushw %ax + jc mapdone + + testl %ebx, %ebx + jnz domap + +mapdone: + popw %ax + + # create a null entry to signal the end of the map + xorl %eax, %eax + movw $5, %cx +1: movl %eax, (%di) + addw $4, %di + loop 1b + + ret + +#------------------------------------------------------------------------------ +# +# e820_error -- +# +# Print a generic error message when something goes awry with the int 15 +# function e820 memory discovery code. +# +#------------------------------------------------------------------------------ + +e820_error: + call clear_screen + movw $bad_e820_msg, %si + call message + jmp halt + +#------------------------------------------------------------------------------ +# +# bad_signature_flaming_death -- +# +# Print an error message and halt. This is called when the signature +# in EDX doesn't match CPUID_BOOT_SIGNATURE. I can't imagine this ever +# actually happen, but it does provide an opportunity to include +# "flaming_death" in a symbol. +# +#------------------------------------------------------------------------------ + +bad_signature_flaming_death: + call clear_screen + movw $bad_signature_msg, %si + call message + jmp halt + +#------------------------------------------------------------------------------ +# +# clear_screen -- +# +# Clear the screen and home the cursor. +# +#------------------------------------------------------------------------------ + +clear_screen: + movw $0x0600, %ax + xorw %bx, %bx + xorw %cx, %cx + movw $0x1950, %dx + int $0x10 + + movb $2, %ah + movb $1, %bh + movw $0, %dx + int $0x10 + + ret + +#------------------------------------------------------------------------------ +# +# message -- +# +# Display a message. +# +#------------------------------------------------------------------------------ + +message: + lodsb + cmpb $0, %al + jz 1f + + movb $0xe, %ah + movw $0x0001, %bx + int $0x10 + jmp message + +1: ret + +#------------------------------------------------------------------------------ +# +# halt -- +# +# Call hlt in an infinite loop. +# +#------------------------------------------------------------------------------ + +halt: hlt + jmp halt + + +#------------------------------------------------------------------------------ +# +# enable_A20 -- +# +# Enable the A20 via the 8042 keyboard controller. This and all of its +# subroutines were borrowed more or less intact from +# linux/arch/i386/boot/setup.S +# +#------------------------------------------------------------------------------ + +A20_TEST_LOOPS = 32 # Iterations per wait +A20_ENABLE_LOOPS = 255 # Total loops to try + +enable_A20: +A20_try_loop: + /* First, see if we are on a system with no A20 gate. */ + call A20_test + jnz A20_done + +A20_kbc: + call empty_8042 + + /* command write */ + movb $0xd1, %al + outb %al, $0x64 + call empty_8042 + + /* A20 on */ + movb $0xdf, %al + outb %al, $0x60 + call empty_8042 + +A20_kbc_wait: + xorw %cx, %cx +A20_kbc_wait_loop: + call A20_test + jnz A20_done + loop A20_kbc_wait_loop + + decb (A20_tries) + jnz A20_try_loop + + /* unable to enable A20 - die with message */ + call clear_screen + movw $A20_error_msg, %si + call message + jmp halt + + /* If we get here, all is good */ +A20_done: + ret + +A20_TEST_ADDR = 4*0x80 + +A20_test: + pushw %cx + pushw %ax + xorw %cx, %cx + /* low memory */ + movw %cx, %fs + decw %cx + /* High memory area */ + movw %cx, %gs + movw $A20_TEST_LOOPS, %cx + movw %fs:(A20_TEST_ADDR), %ax + pushw %ax +A20_test_wait: + incw %ax + movw %ax, %fs:(A20_TEST_ADDR) + /* Serialize and make delay constant */ + call delay + cmpw %gs:(A20_TEST_ADDR+0x10), %ax + loope A20_test_wait + + popw %fs:(A20_TEST_ADDR) + popw %ax + popw %cx + ret + +empty_8042: + pushl %ecx + movl $100000, %ecx + +empty_8042_loop: + decl %ecx + jz empty_8042_end_loop + + call delay + + inb $0x64, %al # 8042 status port + testb $1, %al # output buffer? + jz no_output + + call delay + inb $0x60, %al # read it + jmp empty_8042_loop + +no_output: + testb $2, %al # is input buffer full? + jnz empty_8042_loop # yes - loop +empty_8042_end_loop: + popl %ecx + ret + +delay: outb %al,$0x80 + ret + +#------------------------------------------------------------------------------ +# +# 32 bit code -- +# +#------------------------------------------------------------------------------ + + .code32 + +#------------------------------------------------------------------------------ +# +# finish_this_setup -- +# +# Create page tables for the first MiB of memory and relocate the rest +# of the program into the proper place. Then head off into C land. +# +#------------------------------------------------------------------------------ + +finish_this_setup: + # clear eflags + xorl %eax, %eax + pushl %eax + popf + + # enable paging - the first 2MiB are mapped, the rest is done + # in C land + + # set up page directory + + # zero it out first + movl $PAGE_DIRECTORY, %ecx + xorl %edi, %edi +1: movl $0, (%ecx,%edi,4) + incl %edi + cmpl $1024, %edi + jb 1b + + # only point to first 4MiB page table for now + movl $PAGE_DIRECTORY, %edi + movl $((PAGE_TABLE & MASK4k) | 0x003), (%edi) + + + # set up the page table + + # EAX will be the PTE + xorl %eax, %eax + # EBX is the current range number + xorl %ebx, %ebx + # ECX is the page table base + movl $PAGE_TABLE, %ecx + # EDI is the PTE index + xorl %edi, %edi + +range_loop: + # EDX is the limit of the current range + movl ranges(,%ebx,4), %edx + + # use the LSb of the range to set the RW bit + movb %bl, %al + notb %al + andb $1, %al + shlb $1, %al + + # set the rest of the page attributes + orb $1, %al + + # now loop within the range +page_loop: + # create PTE + movl %eax, (%ecx,%edi,4) + + # increment page address + addl $0x1000, %eax + # increment PTE index + incl %edi + + # is our new address + cmpl %eax, %edx + jnc page_loop + + # increment the range + incl %ebx + + + # more to do? + cmpl $512, %edi + jb range_loop + + + # all done with the page table, store the page directory address + movl $PAGE_DIRECTORY, %eax + movl %eax, %cr3 + + #movl $0x07320731, %ebx + #movl %ebx, 0xb8000 + + # turn on paging + movl %cr0, %eax + orl $0x80000000, %eax + movl %eax, %cr0 + + #movl $0x07340733, %ebx + #movl %ebx, 0xb8000 + + # relocate the rest of the program + movl $CLOAD_ADDR, %edi + movl $code_start, %esi + movl $code_end, %ecx + subl %esi, %ecx + shrl $2, %ecx + cld + + rep + movsd + + # clear the screen + movl $(0x8000 / 4), %ecx + movl $0xb8000, %eax + +1: movl $0, -4(%eax,%ecx,4) + loop 1b + + # off to C land + jmp entry + + + .data + + .align 1 +A20_tries: + .byte A20_ENABLE_LOOPS + +bad_signature_msg: + .asciz "Invalid boot signature in EDX!" + +bad_e820_msg: + .asciz "Trouble encountered creating E820 memory map!" + +A20_error_msg: + .asciz "Unable to enable A20!" + +unknown_mem_msg: + .asciz "Unable to determine memory size - this may cause problems." + +not_enough_mem_msg: + .asciz "CPUID requires at least 2MiB of RAM!" + + .align 8 +GDT_STORE: + # null descriptor + .fill 8, 1, 0x00 + + # CS + .word 0xffff + .word 0x0000 + .word 0x9c00 + .word 0x00cf + + # DS + .word 0xffff + .word 0x0000 + .word 0x9200 + .word 0x00cf +GDT_STORE_END: + + .align 4 +GDT_ADDR: + .word GDT_STORE_END - GDT_STORE + .long GDT + + # upper limit of memory ranges (used for building page tables) +ranges: + .long 0x000a0000 # rw + .long 0x000b8000 # ro + .long 0x000c0000 # rw + .long 0x00100000 # ro + .long 0x00200000 # rw diff --git a/cpuid/igate.S b/cpuid/igate.S new file mode 100644 index 0000000..dcc8d8c --- /dev/null +++ b/cpuid/igate.S @@ -0,0 +1,134 @@ + # igate.S + # Interrupt handling routines. + + +#include <cpuid.h> + + .macro SAVE_STATE + cli + pusha + .endm + + .macro RESTORE_STATE + popa + sti + .endm + + .global divide_error_stub +divide_error_stub: + SAVE_STATE + call divide_error + RESTORE_STATE + iret + + .global nmi_stub +nmi_stub: + SAVE_STATE + call nmi + RESTORE_STATE + iret + + .global breakpoint_stub +breakpoint_stub: + SAVE_STATE + call breakpoint + RESTORE_STATE + iret + + .global overflow_stub +overflow_stub: + SAVE_STATE + call overflow + RESTORE_STATE + iret + + .global bound_range_stub +bound_range_stub: + SAVE_STATE + call bound_range + RESTORE_STATE + iret + + .global ud_stub +ud_stub: + SAVE_STATE + call ud + RESTORE_STATE + iret + + .global no_math_stub +no_math_stub: + SAVE_STATE + call no_math + RESTORE_STATE + iret + + .global df_stub +df_stub: + SAVE_STATE + call df + RESTORE_STATE + addl $4, %esp + iret + + .global invalid_tss_stub +invalid_tss_stub: + SAVE_STATE + call invalid_tss + RESTORE_STATE + addl $4, %esp + iret + + .global segment_np_stub +segment_np_stub: + SAVE_STATE + call segment_np + RESTORE_STATE + addl $4, %esp + iret + + .global stack_fault_stub +stack_fault_stub: + SAVE_STATE + call stack_fault + RESTORE_STATE + addl $4, %esp + iret + + .global gp_stub +gp_stub: + SAVE_STATE + call gp + RESTORE_STATE + addl $4, %esp + iret + + .global pf_stub +pf_stub: + SAVE_STATE + call pf + RESTORE_STATE + addl $4, %esp + iret + + .global math_fault_stub +math_fault_stub: + SAVE_STATE + call math_fault + RESTORE_STATE + iret + + .global alignment_check_stub +alignment_check_stub: + SAVE_STATE + call alignment_check + RESTORE_STATE + addl $4, %esp + iret + + .global simd_stub +simd_stub: + SAVE_STATE + call simd + RESTORE_STATE + iret diff --git a/cpuid/interrupt.c b/cpuid/interrupt.c new file mode 100644 index 0000000..143c922 --- /dev/null +++ b/cpuid/interrupt.c @@ -0,0 +1,406 @@ +/* + *----------------------------------------------------------------------------- + * + * interrupt.c -- + * + * Interrupt handler routines. + * + *----------------------------------------------------------------------------- + */ + +#include <cpuid.h> + +volatile int interrupt_received = 0; + +struct gate { + unsigned short offset_low; /* address[15:0] */ + unsigned short segment; /* segment selector */ + unsigned rsvd0:5; /* 00000 */ + unsigned zero1:3; /* always 0 */ + unsigned type:3; /* 110: interrupt, 111: trap */ + unsigned D:1; /* size of gate (1 is 32 bit) */ + unsigned zero0:1; /* always 0 */ + unsigned DPL:2; /* descriptor privilege level */ + unsigned P:1; /* present */ + unsigned short offset_high; /* address[31:16] */ +} __attribute__ ((packed)); + + +struct { + unsigned short length; + unsigned long address; +} __attribute__ ((packed)) idtp = { + 256 * 8, + IDT +}; + + +/* + *----------------------------------------------------------------------------- + * + * Assembly stub interrupt handlers. These save the CPU state and call the + * real interrupt routine with the requisite info. + * + *----------------------------------------------------------------------------- + */ + +extern void divide_error_stub (void); +extern void nmi_stub (void); +extern void breakpoint_stub (void); +extern void overflow_stub (void); +extern void bound_range_stub (void); +extern void ud_stub (void); +extern void no_math_stub (void); +extern void df_stub (void); +extern void invalid_tss_stub (void); +extern void segment_np_stub (void); +extern void stack_fault_stub (void); +extern void gp_stub (void); +extern void pf_stub (void); +extern void math_fault_stub (void); +extern void alignment_check_stub (void); +extern void simd_stub (void); + + +#define REGISTERS unsigned long edi, \ + unsigned long esi, \ + unsigned long ebp, \ + unsigned long esp, \ + unsigned long ebx, \ + unsigned long edx, \ + unsigned long ecx, \ + unsigned long eax + +#define REGISTER_NAMES edi, esi, ebp, esp, ebx, edx, ecx, eax + +/* + * Send EOI to the 8259. + */ +void +acknowledge_irq (void) +{ + outb (0x20, 0x20); + outb (0x20, 0xa0); +} + + +static void +remap_irqs (void) +{ + /* + * Initialize 8259s. + */ + + /* ICW1 */ + outb (0x11, 0x20); + outb (0x11, 0xa0); + + /* ICW2 */ + outb (0x20, 0x21); + outb (0x28, 0xa1); + + /* ICW3 */ + outb (0x04, 0x21); + outb (0x02, 0xa1); + + /* ICW4 */ + outb (0x01, 0x21); + outb (0x01, 0xa1); + + /* + * Mask external interrupts. + */ + outb (0xff, 0x21); + outb (0xff, 0xa1); +} + + +void +print_interrupt (char name[], int id, REGISTERS, unsigned long eip, + unsigned long cs, unsigned long eflags, + unsigned long error_code) +{ + unsigned long cr0, cr2, cr3, cr4; + + asm ("movl %%cr0, %%eax\n\t" + "movl %%eax, %[cr0]\n\t" + "movl %%cr2, %%eax\n\t" + "movl %%eax, %[cr2]\n\t" + "movl %%cr3, %%eax\n\t" + "movl %%eax, %[cr3]\n\t" + "movl %%cr4, %%eax\n\t" + "movl %%eax, %[cr4]\n\t" + : [cr0] "=m" (cr0), + [cr2] "=m" (cr2), + [cr3] "=m" (cr3), + [cr4] "=m" (cr4) + :); + + logging = 0; + + /* can't use printf as it calls malloc and this may be called from #PF */ + + print_str (name); + putchar ('('); + print_hex32 (id); + print_str (") at "); + print_hex32 (cs); + putchar (':'); + print_hex32 (eip); + print_str (" Error code: "); + print_hex32 (error_code); + putchar ('\n'); + print_str ("EAX: "); + print_hex32 (eax); + print_str (" EBX: "); + print_hex32 (ebx); + print_str (" ECX: "); + print_hex32 (ecx); + print_str (" EDX: "); + print_hex32 (edx); + putchar ('\n'); + print_str ("ESP: "); + print_hex32 (esp + 12); + print_str (" EBP: "); + print_hex32 (ebp); + print_str (" ESI: "); + print_hex32 (esi); + print_str (" EDI: "); + print_hex32 (edi); + putchar ('\n'); + print_str ("EFLAGS: "); + print_hex32 (eflags); + putchar ('\n'); + print_str ("CR0: "); + print_hex32 (cr0); + print_str (" CR2: "); + print_hex32 (cr2); + print_str (" CR3: "); + print_hex32 (cr3); + print_str (" CR4: "); + print_hex32 (cr4); + putchar ('\n'); + + logging = 1; +} + +void +terminate (void) +{ + logging = 0; + + print_str ("!!!!!! Your computer will now be terminated !!!!!!"); + + cli (); + halt (); + /* should maybe actually shut down here */ +} + + +void +divide_error (REGISTERS, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#DE", 0, REGISTER_NAMES, eip, cs, eflags, 0); +} + +void +nmi (REGISTERS, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("NMI", 2, REGISTER_NAMES, eip, cs, eflags, 0); + terminate (); +} + +void +breakpoint (REGISTERS, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#BP", 3, REGISTER_NAMES, eip, cs, eflags, 0); +} + +void +overflow (REGISTERS, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#OF", 4, REGISTER_NAMES, eip, cs, eflags, 0); +} + +void +bound_range (REGISTERS, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#BR", 5, REGISTER_NAMES, eip, cs, eflags, 0); +} + +void +ud (REGISTERS, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + char *text = (char *)eip; + int k; + + print_str ("#UD(06) at "); + print_hex16 (cs); + putchar (':'); + print_hex32 (eip); + putchar ('\n'); + + for (k = 0; k < 16; k++) { + print_hex8 (text[k]); + putchar (' '); + } + + putchar ('\n'); + + terminate (); +} + +void +no_math (REGISTERS, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#NM", 7, REGISTER_NAMES, eip, cs, eflags, 0); +} + +void +df (REGISTERS, unsigned long error_code, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#DF", 8, REGISTER_NAMES, eip, cs, eflags, error_code); + terminate (); +} + +void +invalid_tss (REGISTERS, unsigned long error_code, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#TS", 10, REGISTER_NAMES, eip, cs, eflags, error_code); + terminate (); +} + +void +segment_np (REGISTERS, unsigned long error_code, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#NP", 11, REGISTER_NAMES, eip, cs, eflags, error_code); + terminate (); +} + +void +stack_fault (REGISTERS, unsigned long error_code, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#SS", 12, REGISTER_NAMES, eip, cs, eflags, error_code); + terminate (); +} + +void +gp (REGISTERS, unsigned long error_code, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#GP", 13, REGISTER_NAMES, eip, cs, eflags, error_code); + terminate (); +} + +void +pf (REGISTERS, unsigned long error_code, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#PF", 14, REGISTER_NAMES, eip, cs, eflags, error_code); + terminate (); +} + +void +math_fault (REGISTERS, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#MF", 16, REGISTER_NAMES, eip, cs, eflags, 0); +} + +void +alignment_check (REGISTERS, unsigned long error_code, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#AC", 17, REGISTER_NAMES, eip, cs, eflags, error_code); + terminate (); +} + +void +simd (REGISTERS, unsigned long eip, + unsigned long cs, unsigned long eflags) +{ + print_interrupt ("#XF", 19, REGISTER_NAMES, eip, cs, eflags, 0); +} + + + + +void +install_iv (unsigned long n, void (*handler)(), enum vector_type type) +{ + struct gate *gate = (struct gate *)(IDT + n * 8); + unsigned long handler_addr = (unsigned long)handler; + + gate->offset_high = (unsigned short)((handler_addr >> 16) & 0xffff); + gate->P = 1; + gate->DPL = 0; + gate->zero0 = 0; + gate->D = 1; + gate->type = type; + gate->zero1 = 0; + gate->rsvd0 = 0; + gate->segment = CS; + gate->offset_low = (unsigned short)(handler_addr & 0xffff); +} + +void +install_null_iv (unsigned long n) +{ + struct gate *gate = (struct gate *)(IDT + n * 8); + + memset ((void *)gate, 0, sizeof (struct gate)); +} + + +void +create_idt (void) +{ + unsigned long n; + + remap_irqs (); + + install_iv (0, ÷_error_stub, TRAP); + install_null_iv (1); /* 1 (debug) is reserved */ + install_iv (2, &nmi_stub, INTERRUPT); + install_iv (3, &breakpoint_stub, TRAP); + install_iv (4, &overflow_stub, TRAP); + install_iv (5, &bound_range_stub, TRAP); + install_iv (6, &ud_stub, TRAP); + install_iv (7, &no_math_stub, TRAP); + install_iv (8, &df_stub, TRAP); + install_null_iv (9); /* 9 (coprocessor segment overrun) is null */ + install_iv (10, &invalid_tss_stub, TRAP); + install_iv (11, &segment_np_stub, TRAP); + install_iv (12, &stack_fault_stub, TRAP); + install_iv (13, &gp_stub, TRAP); + install_iv (14, &pf_stub, TRAP); + install_null_iv (15); /* 15 is null */ + install_iv (16, &math_fault_stub, TRAP); + install_iv (17, &alignment_check_stub, TRAP); + install_null_iv (18); /* MCE is not enabled */ + install_iv (19, &simd_stub, TRAP); + + /* + * 20-31 are reserved by the processor + * 32-47 are mapped to IRQ0-15 - individual routines will be installed later + * 48-255 are user defined and will be null + * + */ + for (n = 20; n <= 255; n++) { + install_null_iv (n); + } + + asm ("lidt %0\n" + :: "m" (idtp)); +} diff --git a/cpuid/interrupt.h b/cpuid/interrupt.h new file mode 100644 index 0000000..e922011 --- /dev/null +++ b/cpuid/interrupt.h @@ -0,0 +1,63 @@ +/* + *----------------------------------------------------------------------------- + * + * interrupt.h + * + * Interface to interrupt handling. + * + *----------------------------------------------------------------------------- + */ + +#ifndef _INTERRUPT_H +#define _INTERRUPT_H + +extern volatile int interrupt_received; + +enum vector_type { + INTERRUPT = 6, + TRAP = 7 +}; + + +static inline void +nmi_on (void) +{ + asm ("movb $0x00, %%al\n\t" + "outb %%al, $0x70\n\t" + "inb $0x71, %%al\n" ::: "al"); +} + +static inline void +nmi_off (void) +{ + asm ("movb $0x80, %%al\n\t" + "outb %%al, $0x70\n\t" + "inb $0x71, %%al\n" ::: "al"); +} + +static inline void +cli (void) +{ + asm ("cli\n"); +} + +static inline void +sti (void) +{ + asm ("sti\n"); +} + +extern void acknowledge_irq (void); + +extern void create_idt (void); + +extern void wait_for_interrupt (void); +extern void service_interrupt (void); + +extern void install_iv (unsigned long vector, + void (*handler)(), + enum vector_type type); + +extern void install_null_iv (unsigned long vector); + +#endif /* !_INTERRUPT_H */ diff --git a/cpuid/keyboard.c b/cpuid/keyboard.c new file mode 100644 index 0000000..a7ebe6b --- /dev/null +++ b/cpuid/keyboard.c @@ -0,0 +1,200 @@ +/* + *----------------------------------------------------------------------------- + * + * keyboard.c -- + * + * Keyboard handler. + * + *----------------------------------------------------------------------------- + */ + +#include <cpuid.h> + +volatile int keyboard_has_data = 0; + +static unsigned long *buffer; +static volatile int nkeys; + +static int shift = 0; +static int ctrl = 0; +static int alt = 0; +static int caps_lock = 0; +static int num_lock = 0; +static int scroll_lock = 0; + + + +/* + *----------------------------------------------------------------------------- + * + * read_keypress -- + * + * Read a fully formed keypress from the keyboard, translated into + * "one word" form, either blocking while waiting for a key, or + * returning a value indicating the buffer is empty, depending on + * the value of BLOCK. + * + *----------------------------------------------------------------------------- + */ + +unsigned long +read_keypress (int block) +{ + if (block) { + while (nkeys == 0) asm ("hlt\n"); + } else { + if (nkeys == 0) { + return KEYBOARD_BUFFER_EMPTY; + } + } + + return buffer[--nkeys]; +} + +static void +create_keyboard_buffer (void) +{ + buffer = malloc (KEYBOARD_BUFFER_SIZE * sizeof (unsigned long)); + nkeys = 0; +} + + +void +toggle_lock_key (unsigned long key) +{ + unsigned char indicators; + + switch (key) { + case KEY_CAPSLOCK: + caps_lock = caps_lock ? 0 : 1; + break; + case KEY_NUMLOCK: + num_lock = num_lock ? 0 : 1; + break; + case KEY_SCROLLLOCK: + scroll_lock = scroll_lock ? 0 : 1; + break; + } + + indicators = caps_lock << 2 | num_lock << 1 | scroll_lock; + + outb (0xed, KEYBOARD_DATA_PORT); + /* wait for output to be read by keyboard */ + KEYBOARD_POLL_WHILE (inb (0x64) & 1); + /* get ack */ + KEYBOARD_POLL_WHILE (inb (KEYBOARD_DATA_PORT) != KEYBOARD_ACK); + + outb (indicators, KEYBOARD_DATA_PORT); + /* wait for output to be read by keyboard */ + KEYBOARD_POLL_WHILE (inb (0x64) & 1); + /* get ack */ + KEYBOARD_POLL_WHILE (inb (KEYBOARD_DATA_PORT) != KEYBOARD_ACK); +} + + +int +translate_keys (char code) +{ + return 0; +} + + +static unsigned long current = 0; + +void +keyboard (void) +{ + unsigned char status; + unsigned char code; + + acknowledge_irq (); + + status = inb (KEYBOARD_STATUS_PORT); + + if (!DATA_IN_8042 (status)) { + /* shouldn't happen */ + return; + } + + code = inb (KEYBOARD_DATA_PORT); + + if (code == KEYBOARD_ACK) { + /* received spurious ACK - just ignore it */ + return; + } + + /* Check for modifiers up. */ + if (KEYUP (code)) { + switch (code & ~KEYUPMASK) { + case KEY_CTRL: + ctrl = 0; + return; + case KEY_LSHIFT: + case KEY_RSHIFT: + shift = 0; + return; + case KEY_ALT: + alt = 0; + return; + } + } + + /* Check for modifiers down. */ + switch (code) { + case KEY_CTRL: + ctrl = 1; + return; + case KEY_LSHIFT: + case KEY_RSHIFT: + shift = 1; + return; + case KEY_ALT: + alt = 1; + return; + } + + + current = (current << 8) | ((unsigned long)code & 0xff); + + if (!KEYCODE_IS_COMPLETE (current)) { + return; + } + + /* check for caps/scroll/num lock */ + + if (IS_LOCK_KEY (current)) { + toggle_lock_key (current); + current = 0; + return; + } + + + buffer[nkeys++] = current; + + print_hex32 (current); + + current = 0; + interrupt_received = 1; +} + +extern void keyboard_stub (void); +asm (".global keyboard_stub\n" + "keyboard_stub:\n\t" + "call keyboard\n\t" + "iret\n"); + +void +enable_keyboard (void) +{ + install_iv (KEYBOARD_INTERRUPT, &keyboard_stub, INTERRUPT); + + outb (inb (0x21) & 0xfd, 0x21); +} + +void +keyboard_init (void) +{ + create_keyboard_buffer (); + + enable_keyboard (); +} diff --git a/cpuid/keyboard.h b/cpuid/keyboard.h new file mode 100644 index 0000000..fad24fa --- /dev/null +++ b/cpuid/keyboard.h @@ -0,0 +1,160 @@ +/* + *----------------------------------------------------------------------------- + * + * keyboard.h -- + * + * Interface and definitions for use with the keyboard driver. + * + *----------------------------------------------------------------------------- + */ + +#ifndef _KEYBOARD_H +#define _KEYBOARD_H + + +#define KEYBOARD_INTERRUPT 0x21 + +#define KEYUPMASK 0x80 + +#define KEYUP(k) ((k) & KEYUPMASK) + + +#define KEY_ESC 0x01 +#define KEY_1 0x02 +#define KEY_2 0x03 +#define KEY_3 0x04 +#define KEY_4 0x05 +#define KEY_5 0x06 +#define KEY_6 0x07 +#define KEY_7 0x08 +#define KEY_8 0x09 +#define KEY_9 0x0a +#define KEY_0 0x0b +#define KEY_DASH 0x0c +#define KEY_EQ 0x0d +#define KEY_BS 0x0e +#define KEY_TAB 0x0f +#define KEY_Q 0x10 +#define KEY_W 0x11 +#define KEY_E 0x12 +#define KEY_R 0x13 +#define KEY_T 0x14 +#define KEY_Y 0x15 +#define KEY_U 0x16 +#define KEY_I 0x17 +#define KEY_O 0x18 +#define KEY_P 0x19 +#define KEY_LBRACKET 0x1a +#define KEY_RBRACKET 0x1b +#define KEY_RET 0x1c +#define KEY_CTRL 0x1d +#define KEY_A 0x1e +#define KEY_S 0x1f +#define KEY_D 0x20 +#define KEY_F 0x21 +#define KEY_G 0x22 +#define KEY_H 0x23 +#define KEY_J 0x24 +#define KEY_K 0x25 +#define KEY_L 0x26 +#define KEY_SEMI 0x27 +#define KEY_TICK 0x28 +#define KEY_BACKTICK 0x29 +#define KEY_LSHIFT 0x2a +#define KEY_BACKSLASH 0x2b +#define KEY_Z 0x2c +#define KEY_X 0x2d +#define KEY_C 0x2e +#define KEY_V 0x2f +#define KEY_B 0x30 +#define KEY_N 0x31 +#define KEY_M 0x32 +#define KEY_COMMA 0x33 +#define KEY_DOT 0x34 +#define KEY_SLASH 0x35 +#define KEY_RSHIFT 0x36 +#define KEY_KPSPLAT 0x37 +#define KEY_ALT 0x38 +#define KEY_SPACE 0x39 +#define KEY_CAPSLOCK 0x3a +#define KEY_F1 0x3b +#define KEY_F2 0x3c +#define KEY_F3 0x3d +#define KEY_F4 0x3e +#define KEY_F5 0x3f +#define KEY_F6 0x40 +#define KEY_F7 0x41 +#define KEY_F8 0x42 +#define KEY_F9 0x43 +#define KEY_F10 0x44 +#define KEY_NUMLOCK 0x45 +#define KEY_SCROLLLOCK 0x46 +#define KEY_KP7 0x47 +#define KEY_KP8 0x48 +#define KEY_KP9 0x49 +#define KEY_KPMINUS 0x4a +#define KEY_KP4 0x4b +#define KEY_KP5 0x4c +#define KEY_KP6 0x4d +#define KEY_KPPLUS 0x4e +#define KEY_KP1 0x4f +#define KEY_KP2 0x50 +#define KEY_KP3 0x51 +#define KEY_KP0 0x52 +#define KEY_KPDOT 0x53 + +#define KEY_ESCAPE_CODE 0xe0 + +#define KEY_KPRET ((ESCAPE_CODE << 8) & 0x1c) +#define KEY_HOME ((ESCAPE_CODE << 8) & 0x47) +#define KEY_LEFT ((ESCAPE_CODE << 8) & 0x48) +#define KEY_PGUP ((ESCAPE_CODE << 8) & 0x49) +#define KEY_RIGHT ((ESCAPE_CODE << 8) & 0x4b) +#define KEY_UP ((ESCAPE_CODE << 8) & 0x4d) +#define KEY_END ((ESCAPE_CODE << 8) & 0x4f) +#define KEY_DOWN ((ESCAPE_CODE << 8) & 0x50) +#define KEY_PGOWN ((ESCAPE_CODE << 8) & 0x51) +#define KEY_INSERT ((ESCAPE_CODE << 8) & 0x52) +#define KEY_DELETE ((ESCAPE_CODE << 8) & 0x53) + +// e0 2a e0 37 - SysRq +// e1 1d 45 - Break + +/* #define KEY_ ((ESCAPE_CODE << 8) & */ +/* #define KEY_ ((ESCAPE_CODE << 8) & */ +/* #define KEY_ ((ESCAPE_CODE << 8) & */ +/* #define KEY_ ((ESCAPE_CODE << 8) & */ +/* #define KEY_ ((ESCAPE_CODE << 8) & */ + + +#define KEYBOARD_BUFFER_EMPTY (-1) + +#define KEYBOARD_BUFFER_SIZE 64 + +#define KEYBOARD_DATA_PORT 0x60 +#define KEYBOARD_STATUS_PORT 0x64 +#define KEYBOARD_ACK 0xfa + + +#define DATA_IN_8042(s) ((s) & 0x01) +#define IS_LOCK_KEY(k) ((k) == KEY_SCROLLLOCK || (k) == KEY_NUMLOCK || (k) == KEY_CAPSLOCK) + +/* !!! */ +#define KEYCODE_IS_COMPLETE(c) (((c) & 0xff) != KEY_ESCAPE_CODE)/* ?? */ +/* !!! */ + +#define KEYBOARD_POLL_WHILE(cond) do { \ + unsigned long timeout = 0xffffff; \ + while ((cond) && timeout--); \ + } while (0) + + + +extern volatile int keyboard_has_data; + + +extern unsigned long read_keypress (int block); +extern void keyboard_init (void); + + +#endif /* !_KEYBOARD_H */ diff --git a/cpuid/ld.conf b/cpuid/ld.conf new file mode 100644 index 0000000..88c3adb --- /dev/null +++ b/cpuid/ld.conf @@ -0,0 +1,75 @@ +/* + *----------------------------------------------------------------------------- + * + * ld.conf -- + * + * Loader script for locating sections in their proper place on the + * floppy image, ensuring that addresses are what they ought to be + * (e.g. all addresses in the boot sector are from 0x7c00 to 0x7dff), + * and for providing relocation information so that sections can + * be moved to their proper place during boot time. + * + *----------------------------------------------------------------------------- + */ + + +/* + *----------------------------------------------------------------------------- + * + * OUTPUT_FORMAT -- + * + * Specify that the output is to be a raw binary. This could also be + * specified on the command line, but it makes more sense here. + * + *----------------------------------------------------------------------------- + */ +OUTPUT_FORMAT(binary); + + +/* + *----------------------------------------------------------------------------- + * + * SECTIONS -- + * + * This link map loads all the sections in the following manner: + * + * | Section | Memory Address | Disk Address | + * |==============|=======================|======================| + * | boot sector | 0x7c00 | 0 | + * | head | 0x8000 | 0x200 | + * | .text | 0x100000 | Aligned after head | + * | .data | Aligned after .text | Aligned after .text | + * | .rodata | Aligned after .data | Aligned after .data | + * | .bss | Aligned after .rodata | Not present | + * |==============|=======================|======================| + * + *----------------------------------------------------------------------------- + */ + +SECTIONS +{ + bootsector 0x7c00 : AT ( 0 ) { boot.o } + head 0x8000 : AT ( 0x200 ) { head.o(.text) head.o(.data) } + .text 0x100000 : AT ( ALIGN(0x200 + SIZEOF(head), 16) ) { entry.o(.text) *(.text) } + .data ALIGN(16) : AT ( ALIGN(LOADADDR(.text) + SIZEOF(.text), 16) ) { *(.data) } + .rodata ALIGN(16) : AT ( ALIGN(LOADADDR(.data) + SIZEOF(.data), 16) ) { *(.rodata*) } + .bss ALIGN(16) : { *(.bss) } +} + + +/* + *----------------------------------------------------------------------------- + * + * code_start / code_end -- + * + * These symbols are used in _head to relocate the .text, .data, and + * .rodata sections to their home in higher memory. + * + *----------------------------------------------------------------------------- + */ + +code_start = 0x8000 + LOADADDR(.text) - 0x200; +code_end = ALIGN(0x8000 + LOADADDR(.rodata) + SIZEOF(.rodata) - 0x200, 16); + +bss_start = ADDR(.bss); +bss_end = ALIGN(ADDR(.bss) + SIZEOF(.bss), 4096); diff --git a/cpuid/libcpuid/cpuid.c b/cpuid/libcpuid/cpuid.c new file mode 100644 index 0000000..53ba390 --- /dev/null +++ b/cpuid/libcpuid/cpuid.c @@ -0,0 +1,3854 @@ +/* +** Copyright 2003,2004,2005,2006 by Todd Allen. All Rights Reserved. +** Permission to use, copy, modify, distribute, and sell this software and +** its documentation for any purpose is hereby granted without fee, provided +** that the above copyright notice appear in all copies and that both the +** copyright notice and this permission notice appear in supporting +** documentation. +** +** No representations are made about the suitability of this software for any +** purpose. It is provided ``as is'' without express or implied warranty, +** including but not limited to the warranties of merchantability, fitness +** for a particular purpose, and noninfringement. In no event shall Todd +** Allen be liable for any claim, damages, or other liability, whether in +** action of contract, tort, or otherwise, arising from, out of, or in +** connection with this software. +*/ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <linux/major.h> +#define _GNU_SOURCE +#include <getopt.h> + +typedef int boolean; +#define TRUE 1 +#define FALSE 0 + +typedef char* string; +typedef const char* cstring; +typedef const char* const ccstring; +#define SAME 0 + +#define STR(x) #x +#define XSTR(x) STR(x) + +#define MAX(l,r) ((l) > (r) ? (l) : (r)) + +#define LENGTH(array, type) (sizeof(array) / sizeof(type)) + +#define BPI 32 +#define POWER2(power) \ + (1 << (power)) +#define RIGHTMASK(width) \ + (((width) >= BPI) ? ~0 : POWER2(width)-1) +#define BIT_EXTRACT_LE(value, start, after) \ + (((value) & RIGHTMASK(after)) >> start) + +const char* program = NULL; + +typedef struct { + ccstring name; + unsigned int low_bit; + unsigned int high_bit; + ccstring* images; +} named_item; + +#define NIL_IMAGES (ccstring*)NULL + +static unsigned int +get_max_len (named_item names[], + unsigned int length) +{ + unsigned int result = 0; + unsigned int i; + + for (i = 0; i < length; i++) { + result = MAX(result, strlen(names[i].name)); + } + + return result; +} + +static void +print_names(unsigned int value, + named_item names[], + unsigned int length, + unsigned int max_len) +{ + unsigned int i; + + if (max_len == 0) { + max_len = get_max_len(names, length); + } + + for (i = 0; i < length; i++) { + unsigned int field = BIT_EXTRACT_LE(value, + names[i].low_bit, + names[i].high_bit + 1); + if (names[i].images != NIL_IMAGES + && names[i].images[field] != NULL) { + printf(" %-*s = %s\n", + max_len, + names[i].name, + names[i].images[field]); + } else { + printf(" %-*s = 0x%0x (%u)\n", + max_len, + names[i].name, + field, + field); + } + } +} + +static ccstring bools[] = { "false", + "true" }; + +typedef enum { + VENDOR_UNKNOWN, + VENDOR_INTEL, + VENDOR_AMD, + VENDOR_CYRIX, + VENDOR_VIA, + VENDOR_TRANSMETA, + VENDOR_UMC, + VENDOR_NEXGEN, + VENDOR_RISE +} vendor_t; + +#define __F(v) ((v) & 0x00000f00) +#define __FM(v) ((v) & 0x00000ff0) +#define __FMS(v) ((v) & 0x00000fff) +#define __XF(v) ((v) & 0x0ff00f00) +#define __XFM(v) ((v) & 0x0ff00ff0) +#define __XFMS(v) ((v) & 0x0ff00fff) +#define __XFXM(v) ((v) & 0x0fff0ff0) +#define __XFXMS(v) ((v) & 0x0fff0fff) + +#define __TF(v) ((v) & 0x00003f00) +#define __TFM(v) ((v) & 0x00003ff0) +#define __TFMS(v) ((v) & 0x00003fff) +#define __TXF(v) ((v) & 0x0ff03f00) +#define __TXFM(v) ((v) & 0x0ff03ff0) +#define __TXFMS(v) ((v) & 0x0ff03fff) + +#define _T(v) ((v) << 12) +#define _F(v) ((v) << 8) +#define _M(v) ((v) << 4) +#define _S(v) (v) +#define _XF(v) ((v) << 20) +#define _XM(v) ((v) << 16) + +#define __B(v) ((v) & 0x000000ff) +#define _B(v) (v) + +#define __XB(v) ((v) & 0x00000fff) +#define _XB(v) (v) + +#define START \ + if (0) +#define F(f,str) \ + else if (__F(val) == _F(f) ) printf(str) +#define FM(f,m,str) \ + else if (__FM(val) == _F(f) +_M(m) ) printf(str) +#define FMS(f,m,s,str) \ + else if (__FMS(val) == _F(f) +_M(m)+_S(s) ) printf(str) +#define XF(xf,str) \ + else if (__XF(val) == _XF(xf) +_F(15) ) printf(str) +#define XFM(xf,m,str) \ + else if (__XFM(val) == _XF(xf) +_F(15)+_M(m) ) printf(str) +#define XFMS(xf,m,s,str) \ + else if (__XFMS(val) == _XF(xf) +_F(15)+_M(m)+_S(s) ) printf(str) +#define XFXM(xf,xm,m,str) \ + else if (__XFXM(val) == _XF(xf)+_XM(xm)+_F(15)+_M(m) ) printf(str) +#define XFXMS(xf,xm,m,s,str) \ + else if (__XFXMS(val) == _XF(xf)+_XM(xm)+_F(15)+_M(m)+_S(s) ) printf(str) +#define TF(t,f,str) \ + else if (__TF(val) == _T(t) +_F(f) ) printf(str) +#define TFM(t,f,m,str) \ + else if (__TFM(val) == _T(t) +_F(f) +_M(m) ) printf(str) +#define TFMS(t,f,m,s,str) \ + else if (__TFMS(val) == _T(t) +_F(f) +_M(m)+_S(s) ) printf(str) +#define TXF(t,xf,str) \ + else if (__TXF(val) == _T(t)+_XF(xf) +_F(15) ) printf(str) +#define TXFM(t,xf,m,str) \ + else if (__TXFM(val) == _T(t)+_XF(xf) +_F(15)+_M(m) ) printf(str) +#define TXFMS(t,xf,m,s,str) \ + else if (__TXFMS(val) == _T(t)+_XF(xf) +_F(15)+_M(m)+_S(s) ) printf(str) +#define TXFXM(t,xf,xm,m,str) \ + else if (__TXFXM(val) == _T(t)+_XF(xf)+_XM(xm)+_F(15)+_M(m) ) printf(str) +#define TXFXMS(t,xf,xm,m,s,str) \ + else if (__TXFXMS(val) == _T(t)+_XF(xf)+_XM(xm)+_F(15)+_M(m)+_S(s) ) printf(str) +#define FC(f,m,c,str) \ + else if (__F(val) == _F(f) && cd == (c)) printf(str) +#define FMC(f,m,c,str) \ + else if (__FM(val) == _F(f) +_M(m) && cd == (c)) printf(str) +#define FMSC(f,m,s,c,str) \ + else if (__FMS(val) == _F(f) +_M(m)+_S(s) && cd == (c)) printf(str) +#define XFC(xf,c,str) \ + else if (__XF(val) == _XF(xf) +_F(15) && cd == (c)) printf(str) +#define XFMC(xf,m,c,str) \ + else if (__XFM(val) == _XF(xf) +_F(15)+_M(m) && cd == (c)) printf(str) +#define XFMSC(xf,m,s,c,str) \ + else if (__XFMS(val) == _XF(xf) +_F(15)+_M(m)+_S(s) && cd == (c)) printf(str) +#define XFXMC(xf,xm,m,c,str) \ + else if (__XFXM(val) == _XF(xf)+_XM(xm)+_F(15)+_M(m) && cd == (c)) printf(str) +#define XFXMSC(xf,xm,m,s,c,str) \ + else if (__XFXMS(val) == _XF(xf)+_XM(xm)+_F(15)+_M(m)+_S(s) && cd == (c)) printf(str) +#define DEFAULT(str) \ + else printf(str) + +/* +** d? = think "desktop" +** s? = think "server" (multiprocessor) +** M? = think "mobile" +** D? = think "dual core" +** +** ?P = think Pentium +** ?X = think Xeon +** ?M = think Xeon MP +** ?C = think Celeron +** ?c = think Core +** ?A = think Athlon +** ?D = think Duron +** ?S = think Sempron +** ?O = think Opteron +** ?T = think Turion +*/ +typedef enum { + /* ==========Intel========== ============AMD============ Transmeta */ + UN, /* Unknown */ + dP, /* Pentium */ + MP, /* Mobile Pentium */ + sX, /* Xeon */ + sI, /* Xeon (Irwindale) */ + s7, /* Xeon (Series 7000) */ + sM, /* Xeon MP */ + sP, /* Xeon MP (Potomac) */ + MM, /* Mobile Pentium M */ + dC, /* Celeron */ + MC, /* Mobile Celeron */ + nC, /* not Celeron */ + dc, /* CPU (often Core Solo) */ + Dc, /* Core Duo */ + Da, /* Core Duo (Allendale) */ + dO, /* Opteron */ + d8, /* Opteron (8xx) */ + dX, /* Athlon XP */ + dt, /* Athlon XP (Thorton) */ + MX, /* mobile Athlon XP-M */ + ML, /* mobile Athlon XP-M (LV) */ + dA, /* Athlon(64) */ + dm, /* Athlon(64) (Manchester) */ + sA, /* Athlon MP */ + MA, /* mobile Athlon(64) */ + dF, /* Athlon 64 FX */ + dD, /* Pentium D Duron */ + sD, /* Duron MP */ + MD, /* mobile Duron */ + dS, /* Sempron */ + MS, /* mobile Sempron */ + DO, /* Dual Core Opteron */ + D8, /* Dual Core Opteron (8xx) */ + MT, /* mobile Turion */ + t2, /* TMx200 */ + t4, /* TMx400 */ + t5, /* TMx500 */ + t6, /* TMx600 */ + t8, /* TMx800 */ +} code_t; + +typedef struct { + vendor_t vendor; + unsigned int val_1_eax; + unsigned int val_1_ebx; + unsigned int val_1_ecx; + unsigned int val_1_edx; + unsigned int val_4_eax; + unsigned int val_80000001_ebx; + unsigned int val_80000001_ecx; + unsigned int val_80000008_ecx; + unsigned int transmeta_proc_rev; + char brand[48]; + char transmeta_info[48]; + + struct mp { + boolean ok; + unsigned int cores; + unsigned int hyperthreads; + } mp; + + /* ==============implications============== */ + /* PII (F6, M5) PIII (F6, M7) */ + /* ---------------------- --------------- */ + boolean L2_4w_1Mor2M; /* Xeon Xeon */ + boolean L2_4w_512K; /* normal, Mobile or Xeon normal or Xeon */ + boolean L2_4w_256K; /* Mobile - */ + boolean L2_8w_1Mor2M; /* - Xeon */ + boolean L2_8w_512K; /* - normal */ + boolean L2_8w_256K; /* - normal or Xeon */ + /* none */ /* Celeron - */ + + boolean L2_2M; /* Nocona lacks, Irwindale has */ + /* Conroe has more, Allendale has this */ + boolean L3; /* Cranford lacks, Potomac has */ + + boolean L2_256K; /* Barton has more, Thorton has this */ + boolean L2_512K; /* Toledo has more, Manchester E6 has this */ +} code_stash_t; + +#define NIL_STASH { VENDOR_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", \ + { FALSE, 0, 0 }, \ + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, \ + FALSE, FALSE, \ + FALSE, FALSE } + +static void +stash_intel_cache(code_stash_t* stash, + unsigned char value) +{ + switch (value) { + case 0x42: stash->L2_4w_256K = TRUE; break; + case 0x43: stash->L2_4w_512K = TRUE; break; + case 0x44: stash->L2_4w_1Mor2M = TRUE; break; + case 0x45: stash->L2_4w_1Mor2M = TRUE; break; + case 0x82: stash->L2_8w_256K = TRUE; break; + case 0x83: stash->L2_8w_512K = TRUE; break; + case 0x84: stash->L2_8w_1Mor2M = TRUE; break; + case 0x85: stash->L2_8w_1Mor2M = TRUE; break; + } + + switch (value) { + case 0x45: + case 0x85: + case 0x88: + stash->L2_2M = TRUE; + break; + } + + switch (value) { + case 0x22: + case 0x23: + case 0x25: + case 0x29: + case 0x46: + case 0x47: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x88: + case 0x89: + case 0x8a: + case 0x8d: + stash->L3 = TRUE; + break; + } + + switch (value) { + case 0x3c: + case 0x42: + case 0x7a: + case 0x7e: + case 0x82: + stash->L2_256K = TRUE; + break; + } + + switch (value) { + case 0x3e: + case 0x43: + case 0x7b: + case 0x7f: + case 0x83: + case 0x86: + stash->L2_512K = TRUE; + break; + } +} + +static code_t +decode_transmeta_rev_cache (const code_stash_t* stash) +{ + /* TODO: Add codes for Transmeta Crusoe TM5700/TM5900 */ + /* TODO: Add codes for Transmeta Efficeon */ + switch (stash->transmeta_proc_rev & 0xffff0000) { + case 0x01010000: + return t2; + case 0x01020000: + return t4; + case 0x01030000: + if ((stash->transmeta_proc_rev & 0xffffff00) == 0x00000000) { + if (stash->L2_4w_256K) { + return t4; + } else if (stash->L2_4w_512K) { + return t6; + } else { + return UN; + } + } else { + return UN; + } + case 0x01040000: + case 0x01050000: + if (stash->L2_4w_256K) { + return t5; + } else if (stash->L2_4w_512K) { + return t8; + } else { + return UN; + } + default: + return UN; + } +} + +static code_t +decode_rev_cache (const code_stash_t* stash) +{ + switch (stash->vendor) { + case VENDOR_INTEL: + switch (__FM(stash->val_1_eax)) { + case _F(6) + _M(5): + if (stash->L2_4w_1Mor2M) { + return sX; + } else if (stash->L2_4w_512K) { + return nC; + } else if (stash->L2_4w_256K) { + return MP; + } else { + return dC; + } + case _F(6) + _M(7): + if (stash->L2_4w_1Mor2M || stash->L2_8w_1Mor2M) { + return sX; + } else if (stash->L2_8w_512K) { + return dP; + } else { + return UN; + } + default: + return UN; + } + case VENDOR_TRANSMETA: + switch (__FM(stash->val_1_eax)) { + case _F(5) + _M(4): + return decode_transmeta_rev_cache(stash); + default: + return UN; + } + default: + return UN; + } +} + +static code_t +decode_brand(const code_stash_t* stash) +{ + const char* brand = stash->brand; + + switch (stash->vendor) { + case VENDOR_INTEL: + if (strstr(brand, "Mobile") != NULL) { + if (strstr(brand, "Celeron") != NULL) { + return MC; + } else if (strstr(brand, "Pentium") != NULL) { + return MP; + } + } else { + if (strstr(brand, "Xeon MP") != NULL + || strstr(brand, "Xeon(TM) MP") != NULL) { + return sM; + } else if (strstr(brand, "Xeon") != NULL) { + return sX; + } else if (strstr(brand, "Celeron") != NULL) { + return dC; + } else if (strstr(brand, "Pentium(R) M") != NULL) { + return MM; + } else if (strstr(brand, "Pentium(R) D") != NULL) { + return dD; + } else if (strstr(brand, "Pentium") != NULL) { + return dP; + } else if (strstr(brand, "Genuine Intel(R) CPU") != NULL + || strstr(brand, "Intel(R) Core(TM)2 CPU") != NULL) { + return dc; + } + } + return UN; + case VENDOR_AMD: + if (strstr(brand, "mobile") != NULL) { + if (strstr(brand, "Athlon(tm) XP-M (LV)") != NULL) { + return ML; + } else if (strstr(brand, "Athlon(tm) XP-M") != NULL) { + return MX; + } else if (strstr(brand, "Duron") != NULL) { + return MD; + } else if (strstr(brand, "Athlon") != NULL) { + return MA; + } + } else if (strstr(brand, "Mobile") != NULL) { + if (strstr(brand, "Athlon(tm) XP") != NULL) { + return MX; + } else if (strstr(brand, "Athlon(tm) 64") != NULL) { + return MA; + } else if (strstr(brand, "Sempron") != NULL) { + return MS; + } + } else { + if (strstr(brand, "Dual Core") != NULL) { + return DO; + } else if (strstr(brand, "Athlon(tm) XP") != NULL + || strstr(brand, "Athlon(TM) XP") != NULL) { + return dX; + } else if (strstr(brand, "Athlon(tm) 64 FX") != NULL) { + return dF; + } else if (strstr(brand, "Athlon(tm) MP") != NULL) { + return sA; + } else if (strstr(brand, "Duron(tm) MP") != NULL) { + return sD; + } else if (strstr(brand, "Duron") != NULL) { + return dD; + } else if (strstr(brand, "Athlon") != NULL) { + return dA; + } else if (strstr(brand, "Sempron") != NULL) { + return dS; + } else if (strstr(brand, "Opteron") != NULL) { + return dO; + } else if (strstr(brand, "Turion") != NULL) { + return MT; + } + } + return UN; + default: + return UN; + } +} + +static code_t +decode_brand_code(const code_stash_t* stash) +{ + unsigned int val_1_eax = stash->val_1_eax; + unsigned int val_1_ebx = stash->val_1_ebx; + + switch (__B(val_1_ebx)) { + case _B(0): return UN; + case _B(1): return dC; + case _B(2): return dP; + case _B(3): return __FMS(val_1_eax) == _F(6) + _M(11) + _S(1) ? dC : sX; + case _B(4): return dP; + case _B(6): return dP; + case _B(7): return dC; + case _B(8): return dP; + case _B(9): return dP; + case _B(10): return dC; + case _B(11): return __XFMS(val_1_eax) <= _XF(0) + _M(1) + _S(2) ? sM : sX; + case _B(12): return sM; + case _B(14): return __XFMS(val_1_eax) <= _XF(0) + _M(1) + _S(3) ? sX : MM; + case _B(15): return __XFM(val_1_eax) == _XF(0) + _M(2) ? MM : MC; + case _B(16): return dC; + case _B(17): return MP; + case _B(18): return dC; + case _B(19): return MC; + case _B(20): return dC; + case _B(21): return MP; + case _B(22): return dP; + case _B(23): return MC; + default: return UN; + } +} + +static code_t +specialize_intel_mp(code_t result, + const code_stash_t* stash) +{ + if (stash->vendor == VENDOR_INTEL) { + switch (result) { + case dc: + if (stash->mp.cores == 4) { + // This can happen for pre-production Woodcrest cores + result = sX; + } else if (stash->mp.cores == 2) { + result = Dc; + } + break; + default: + /* DO NOTHING */ + break; + } + } + + return result; +} + +static code_t +specialize_intel_cache(code_t result, + const code_stash_t* stash) +{ + if (stash->vendor == VENDOR_INTEL) { + switch (result) { + case sX: + switch (__XFMS(stash->val_1_eax)) { + case _XF(0) + _F(15) + _M(4) + _S(3): + if (stash->L3) { + /* to distinguish Irwindale from Nocona */ + result = sI; + } + } + break; + case sM: + switch (__XFMS(stash->val_1_eax)) { + case _XF(0) + _F(15) + _M(4) + _S(1): + if (stash->L3) { + /* to distinguish Potomac from Cranford */ + result = sP; + } + } + break; + case Dc: + switch (__FMS(stash->val_1_eax)) { + case _F(6) + _M(15) + _S(5): + case _F(6) + _M(15) + _S(6): + if (stash->L2_2M) { + result = Da; + } + } + break; + default: + /* DO NOTHING */ + break; + } + } + + return result; +} + +#define IS_VMX(val_1_ecx) (BIT_EXTRACT_LE((val_1_ecx), 5, 6)) + +static code_t +specialize_intel_VT(code_t result, + const code_stash_t* stash) +{ + if (stash->vendor == VENDOR_INTEL) { + switch (result) { + case sX: + switch (__XFMS(stash->val_1_eax)) { + case _XF(0) + _F(15) + _M(4) + _S(8): + /* + ** Is this the best way to distinguish these two processors? + ** Dual-Core Xeon (Paxville A0) + ** Dual-Core Xeon Processor 7000 (Paxville A0) + ** Empirically, the significant differences are the VMX flag and + ** the "execution disable" flag. The VMX flag is in an + ** Intel-defined CPUID function, so it's used. + */ + if (IS_VMX(stash->val_1_ecx)) { + /* to distinguish Paxville Series 7000 from Paxville 2.80 GHz */ + result = s7; + } + } + break; + default: + /* DO NOTHING */ + break; + } + } + + return result; +} + +static code_t +specialize_amd_model(code_t result, + const code_stash_t* stash) +{ + if (stash->vendor == VENDOR_AMD) { + switch (result) { + case dO: + case DO: + switch (__XFXM(stash->val_1_eax)) { + case _XF(0) + _F(15) + _XM(2) + _M(1): /* Italy/Egypt */ + case _XF(0) + _F(15) + _XM(2) + _M(5): /* Troy/Athens */ + { + unsigned int msb; + + if (__XB(stash->val_80000001_ebx) != 0) { + msb = BIT_EXTRACT_LE(__XB(stash->val_80000001_ebx), 6, 12); + } else if (_B(stash->val_1_ebx) != 0) { + /* + ** Nothing explains how the msb of this brand should be + ** interpreted. I concluded it must be shifted left by 2 + ** with a little reverse engineering. That's the only way + ** it gets the right answer for the machine aero, which has + ** brand 0x83, and is known to be a 244. + */ + msb = BIT_EXTRACT_LE(__B(stash->val_1_ebx), 5, 8) << 2; + } else { + return result; + } + + switch (msb) { + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x2a: + case 0x30: + case 0x31: + case 0x39: + case 0x32: + case 0x33: + /* It's a 2xx */ + /* DO NOTHING */ + break; + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x2b: + case 0x34: + case 0x35: + case 0x3a: + case 0x36: + case 0x37: + /* It's an 8xx */ + switch (result) { + case dO: + result = d8; /* to distinguish Athens from Troy */ + break; + case DO: + result = D8; /* to distinguish Egypt from Italy */ + break; + default: + /* Shouldn't happen */ + break; + } + } + } + } + break; + default: + /* DO NOTHING */ + break; + } + } + + return result; +} + +static code_t +specialize_amd_cache(code_t result, + const code_stash_t* stash) +{ + if (stash->vendor == VENDOR_AMD) { + switch (result) { + case dX: + switch (__FMS(stash->val_1_eax)) { + case _F(6) + _M(10) + _S(0): + if (stash->L2_256K) { + /* to distinguish Thorton from Barton */ + result = dt; + } + } + break; + case dA: + switch (__XFXM(stash->val_1_eax)) { + case _XF(0) + _F(15) + _XM(2) + _M(3): + if (stash->L2_512K) { + /* to distinguish Manchester E6 from Toledo */ + result = dm; + } + } + break; + default: + /* DO NOTHING */ + break; + } + } + + return result; +} + +static code_t +decode(const code_stash_t* stash) +{ + code_t result; + + result = decode_brand_code(stash); + if (result == UN) { + result = decode_brand(stash); + } + if (result == UN) { + result = decode_rev_cache(stash); + } + + result = specialize_intel_mp(result, stash); + result = specialize_intel_cache(result, stash); + result = specialize_intel_VT(result, stash); + result = specialize_amd_model(result, stash); + result = specialize_amd_cache(result, stash); + + return result; +} + +static void +print_synth_intel(const char* name, + unsigned int val, /* val_1_eax */ + code_t cd) +{ + printf(name); + START; + FM ( 4, 0, "Intel i80486DX-25/33"); + FM ( 4, 1, "Intel i80486DX-50"); + FM ( 4, 2, "Intel i80486SX"); + FM ( 4, 3, "Intel i80486DX/2"); + FM ( 4, 4, "Intel i80486SL"); + FM ( 4, 5, "Intel i80486SX/2"); + FM ( 4, 7, "Intel i80486DX/2-WB"); + FM ( 4, 8, "Intel i80486DX/4"); + FM ( 4, 9, "Intel i80486DX/4-WB"); + F ( 4, "Intel i80486 (unknown model)"); + FM ( 5, 0, "Intel Pentium 60/66 A-step"); + TFM (1, 5, 1, "Intel Pentium 60/66 OverDrive for P5"); + FMS ( 5, 1, 3, "Intel Pentium 60/66 (B1)"); + FMS ( 5, 1, 5, "Intel Pentium 60/66 (C1)"); + FMS ( 5, 1, 7, "Intel Pentium 60/66 (D1)"); + FM ( 5, 1, "Intel Pentium 60/66"); + TFM (1, 5, 2, "Intel Pentium 75 - 200 OverDrive for P54C"); + FMS ( 5, 2, 1, "Intel Pentium P54C 75 - 200 (B1)"); + FMS ( 5, 2, 2, "Intel Pentium P54C 75 - 200 (B3)"); + FMS ( 5, 2, 4, "Intel Pentium P54C 75 - 200 (B5)"); + FMS ( 5, 2, 5, "Intel Pentium P54C 75 - 200 (C2/mA1)"); + FMS ( 5, 2, 6, "Intel Pentium P54C 75 - 200 (E0)"); + FMS ( 5, 2, 11, "Intel Pentium P54C 75 - 200 (cB1)"); + FMS ( 5, 2, 12, "Intel Pentium P54C 75 - 200 (cC0)"); + FM ( 5, 2, "Intel Pentium P54C 75 - 200"); + TFM (1, 5, 3, "Intel Pentium OverDrive for i486 (P24T)"); + TFM (1, 5, 4, "Intel Pentium OverDrive for P54C"); + FMS ( 5, 4, 3, "Intel Pentium MMX P55C (B1)"); + FMS ( 5, 4, 4, "Intel Pentium MMX P55C (A3)"); + FM ( 5, 4, "Intel Pentium MMX P55C"); + FMS ( 5, 7, 0, "Intel Pentium MMX P54C 75 - 200 (A4)"); + FM ( 5, 7, "Intel Pentium MMX P54C 75 - 200"); + FMS ( 5, 8, 1, "Intel Pentium MMX P55C (A0), .25um"); + FMS ( 5, 8, 2, "Intel Pentium MMX P55C (B2), .25um"); + FM ( 5, 8, "Intel Pentium MMX P55C, .25um"); + F ( 5, "Intel Pentium (unknown model)"); + FM ( 6, 0, "Intel Pentium Pro A-step"); + FMS ( 6, 1, 1, "Intel Pentium Pro (B0)"); + FMS ( 6, 1, 2, "Intel Pentium Pro (C0)"); + FMS ( 6, 1, 6, "Intel Pentium Pro (sA0)"); + FMS ( 6, 1, 7, "Intel Pentium Pro (sA1)"); + FMS ( 6, 1, 9, "Intel Pentium Pro (sB1)"); + FM ( 6, 1, "Intel Pentium Pro"); + TFM (1, 6, 3, "Intel Pentium II OverDrive"); + FMS ( 6, 3, 3, "Intel Pentium II (Klamath C0), .28um"); + FMS ( 6, 3, 4, "Intel Pentium II (Klamath C1), .28um"); + FM ( 6, 3, "Intel Pentium II (Klamath), .28um"); + FM ( 6, 4, "Intel Pentium P55CT OverDrive (Deschutes)"); + FMSC ( 6, 5, 0, MP, "Intel Mobile Pentium II (Deschutes A0), .25um"); + FMSC ( 6, 5, 0, sX, "Intel Pentium II Xeon (Deschutes A0), .25um"); + FMSC ( 6, 5, 0, dC, "Intel Celeron (Deschutes A0), .25um"); + FMSC ( 6, 5, 0, nC, "Intel Pentium II / Pentium II Xeon / Mobile Pentium II (Deschutes A0), .25um"); + FMS ( 6, 5, 0, "Intel Pentium II / Pentium II Xeon / Celeron / Mobile Pentium II (Deschutes A0), .25um"); + FMSC ( 6, 5, 1, sX, "Intel Pentium II Xeon (Deschutes A1), .25um"); + FMSC ( 6, 5, 1, dC, "Intel Celeron (Deschutes A1), .25um"); + FMSC ( 6, 5, 1, nC, "Intel Pentium II / Pentium II Xeon (Deschutes A1), .25um"); + FMS ( 6, 5, 1, "Intel Pentium II / Pentium II Xeon / Celeron (Deschutes A1), .25um"); + FMSC ( 6, 5, 2, MP, "Intel Mobile Pentium II (Deschutes B0), .25um"); + FMSC ( 6, 5, 2, sX, "Intel Pentium II Xeon (Deschutes B0), .25um"); + FMSC ( 6, 5, 2, dC, "Intel Celeron (Deschutes B0), .25um"); + FMSC ( 6, 5, 2, nC, "Intel Pentium II / Pentium II Xeon / Mobile Pentium II (Deschutes B0), .25um"); + FMS ( 6, 5, 2, "Intel Pentium II / Pentium II Xeon / Celeron / Mobile Pentium II (Deschutes B0), .25um"); + FMSC ( 6, 5, 3, sX, "Intel Pentium II Xeon (Deschutes B1), .25um"); + FMSC ( 6, 5, 3, dC, "Intel Celeron (Deschutes B1), .25um"); + FMSC ( 6, 5, 3, nC, "Intel Pentium II / Pentium II Xeon (Deschutes B1), .25um"); + FMS ( 6, 5, 3, "Intel Pentium II / Pentium II Xeon / Celeron (Deschutes B1), .25um"); + FMC ( 6, 5, MP, "Intel Mobile Pentium II (Deschutes), .25um"); + FMC ( 6, 5, sX, "Intel Pentium II Xeon (Deschutes), .25um"); + FMC ( 6, 5, dC, "Intel Celeron (Deschutes), .25um"); + FMC ( 6, 5, nC, "Intel Pentium II / Pentium II Xeon / Mobile Pentium II (Deschutes), .25um"); + FM ( 6, 5, "Intel Pentium II / Pentium II Xeon / Celeron / Mobile Pentium II (Deschutes), .25um"); + FMSC ( 6, 6, 0, dP, "Intel Pentium II (Mendocino A0), L2 cache"); + FMSC ( 6, 6, 0, dC, "Intel Celeron (Mendocino A0), L2 cache"); + FMS ( 6, 6, 0, "Intel Pentium II (Mendocino A0) / Celeron (Mendocino A0), L2 cache"); + FMSC ( 6, 6, 5, dP, "Intel Pentium II (Mendocino B0), L2 cache"); + FMSC ( 6, 6, 5, dC, "Intel Celeron (Mendocino B0), L2 cache"); + FMS ( 6, 6, 5, "Intel Pentium II (Mendocino B0) / Celeron (Mendocino B0), L2 cache"); + FMS ( 6, 6, 10, "Intel Mobile Pentium II (Mendocino A0), L2 cache"); + FM ( 6, 6, "Intel Pentium II (Mendocino), L2 cache"); + FMSC ( 6, 7, 2, dP, "Intel Pentium III (Katmai B0), .25um"); + FMSC ( 6, 7, 2, sX, "Intel Pentium III Xeon (Katmai B0), .25um"); + FMS ( 6, 7, 2, "Intel Pentium III / Pentium III Xeon (Katmai B0), .25um"); + FMSC ( 6, 7, 3, dP, "Intel Pentium III (Katmai C0), .25um"); + FMSC ( 6, 7, 3, sX, "Intel Pentium III Xeon (Katmai C0), .25um"); + FMS ( 6, 7, 3, "Intel Pentium III / Pentium III Xeon (Katmai C0), .25um"); + FMC ( 6, 7, dP, "Intel Pentium III (Katmai), .25um"); + FMC ( 6, 7, sX, "Intel Pentium III Xeon (Katmai), .25um"); + FM ( 6, 7, "Intel Pentium III / Pentium III Xeon (Katmai), .25um"); + FMSC ( 6, 8, 1, dP, "Intel Pentium III (Coppermine A2), .18um"); + FMSC ( 6, 8, 1, MP, "Intel Mobile Pentium III (Coppermine A2), .18um"); + FMSC ( 6, 8, 1, sX, "Intel Pentium III Xeon (Coppermine A2), .18um"); + FMSC ( 6, 8, 1, dC, "Intel Celeron (Coppermine A2), .18um"); + FMSC ( 6, 8, 1, MC, "Intel Mobile Celeron (Coppermine A2), .18um"); + FMS ( 6, 8, 1, "Intel Pentium III / Pentium III Xeon / Celeron / Mobile Pentium III (Coppermine A2) / Mobile Celeron (Coppermine A2), .18um"); + FMSC ( 6, 8, 3, dP, "Intel Pentium III (Coppermine B0), .18um"); + FMSC ( 6, 8, 3, MP, "Intel Mobile Pentium III (Coppermine B0), .18um"); + FMSC ( 6, 8, 3, sX, "Intel Pentium III Xeon (Coppermine B0), .18um"); + FMSC ( 6, 8, 3, dC, "Intel Celeron (Coppermine B0), .18um"); + FMSC ( 6, 8, 3, MC, "Intel Mobile Celeron (Coppermine B0), .18um"); + FMS ( 6, 8, 3, "Intel Pentium III / Pentium III Xeon / Celeron / Mobile Pentium III (Coppermine B0) / Mobile Celeron (Coppermine B0), .18um"); + FMSC ( 6, 8, 6, dP, "Intel Pentium III (Coppermine C0), .18um"); + FMSC ( 6, 8, 6, MP, "Intel Mobile Pentium III (Coppermine C0), .18um"); + FMSC ( 6, 8, 6, sX, "Intel Pentium III Xeon (Coppermine C0), .18um"); + FMSC ( 6, 8, 6, dC, "Intel Celeron (Coppermine C0), .18um"); + FMSC ( 6, 8, 6, MC, "Intel Mobile Celeron (Coppermine C0), .18um"); + FMS ( 6, 8, 6, "Intel Pentium III / Pentium III Xeon / Celeron / Mobile Pentium III (Coppermine C0) / Mobile Celeron (Coppermine C0), .18um"); + FMSC ( 6, 8, 10, dP, "Intel Pentium III (Coppermine D0), .18um"); + FMSC ( 6, 8, 10, MP, "Intel Mobile Pentium III (Coppermine D0), .18um"); + FMSC ( 6, 8, 10, sX, "Intel Pentium III Xeon (Coppermine D0), .18um"); + FMSC ( 6, 8, 10, dC, "Intel Celeron (Coppermine D0), .18um"); + FMSC ( 6, 8, 10, MC, "Intel Mobile Celeron (Coppermine D0), .18um"); + FMS ( 6, 8, 10, "Intel Pentium III / Pentium III Xeon / Celeron / Mobile Pentium III (Coppermine D0) / Mobile Celeron (Coppermine D0), .18um"); + FMC ( 6, 8, dP, "Intel Pentium III (Coppermine), .18um"); + FMC ( 6, 8, MP, "Intel Mobile Pentium III (Coppermine), .18um"); + FMC ( 6, 8, sX, "Intel Pentium III Xeon (Coppermine), .18um"); + FMC ( 6, 8, dC, "Intel Celeron (Coppermine), .18um"); + FMC ( 6, 8, MC, "Intel Mobile Celeron (Coppermine), .18um"); + FM ( 6, 8, "Intel Pentium III / Pentium III Xeon / Celeron / Mobile Pentium III (Coppermine) / Mobile Celeron (Coppermine), .18um"); + FMSC ( 6, 9, 5, dP, "Intel Pentium M (Banias B1), .13um"); + FMSC ( 6, 9, 5, dC, "Intel Celeron M (Banias B1), .13um"); + FMS ( 6, 9, 5, "Intel Pentium M / Celeron M (Banias B1), .13um"); + FMC ( 6, 9, dP, "Intel Pentium M (Banias), .13um"); + FMC ( 6, 9, dC, "Intel Celeron M (Banias), .13um"); + FM ( 6, 9, "Intel Pentium M / Celeron M (Banias), .13um"); + FMS ( 6, 10, 0, "Intel Pentium III Xeon (Cascades A0), .18um"); + FMS ( 6, 10, 1, "Intel Pentium III Xeon (Cascades A1), .18um"); + FMS ( 6, 10, 4, "Intel Pentium III Xeon (Cascades B0), .18um"); + FM ( 6, 10, "Intel Pentium III Xeon (Cascades), .18um"); + FMSC ( 6, 11, 1, dP, "Intel Pentium III (Tualatin A1), .13um"); + FMSC ( 6, 11, 1, dC, "Intel Celeron (Tualatin A1), .13um"); + FMSC ( 6, 11, 1, MC, "Intel Mobile Celeron (Tualatin A1), .13um"); + FMS ( 6, 11, 1, "Intel Pentium III / Celeron / Mobile Celeron (Tualatin A1), .13um"); + FMSC ( 6, 11, 4, dP, "Intel Pentium III (Tualatin B1), .13um"); + FMSC ( 6, 11, 4, dC, "Intel Celeron (Tualatin B1), .13um"); + FMSC ( 6, 11, 4, MC, "Intel Mobile Celeron (Tualatin B1), .13um"); + FMS ( 6, 11, 4, "Intel Pentium III / Celeron / Mobile Celeron (Tualatin B1), .13um"); + FMC ( 6, 11, dP, "Intel Pentium III (Tualatin), .13um"); + FMC ( 6, 11, dC, "Intel Celeron (Tualatin), .13um"); + FMC ( 6, 11, MC, "Intel Mobile Celeron (Tualatin), .13um"); + FM ( 6, 11, "Intel Pentium III / Celeron / Mobile Celeron (Tualatin), .13um"); + FMSC ( 6, 13, 6, dP, "Intel Pentium M (Dothan B1), 90nm"); + FMSC ( 6, 13, 6, dC, "Intel Celeron M (Dothan B1), 90nm"); + FMS ( 6, 13, 6, "Intel Pentium M (Dothan B1) / Celeron M (Dothan B1), 90nm"); + FMSC ( 6, 13, 8, dP, "Intel Pentium M (Dothan C0), 90nm"); + FMSC ( 6, 13, 8, dC, "Intel Celeron M (Dothan C0), 90nm"); + FMS ( 6, 13, 8, "Intel Pentium M (Dothan C0) / Celeron M (Dothan C0), 90nm"); + FM ( 6, 13, "Intel Pentium M (Dothan) / Celeron M (Dothan), 90nm"); + /* + ** Is MP the correct code for: + ** Intel Core Solo (Yonah C0) / Core Duo (Yonah C0)? + */ + FMSC ( 6, 14, 8, dc, "Intel Core Solo (Yonah C0), 65nm"); + FMSC ( 6, 14, 8, Dc, "Intel Core Duo (Yonah C0), 65nm"); + FMSC ( 6, 14, 8, dC, "Intel Celeron (Yonah C0), 65nm"); + FMSC ( 6, 14, 8, sX, "Intel Xeon Processor LV (Sossaman C0), 65nm"); + FMS ( 6, 14, 8, "Intel Core Solo (Yonah C0) / Core Duo (Yonah C0) / Xeon Processor LV (Sossaman C0) / Celeron (Yonah C0), 65nm"); + FMSC ( 6, 14, 12, dc, "Intel Core Solo (Yonah D0), 65nm"); + FMSC ( 6, 14, 12, Dc, "Intel Core Duo (Yonah D0), 65nm"); + FMS ( 6, 14, 12, "Intel Core Solo (Yonah D0) / Core Duo (Yonah D0), 65nm"); + FMC ( 6, 14, dc, "Intel Core Solo (Yonah), 65nm"); + FMC ( 6, 14, Dc, "Intel Core Duo (Yonah), 65nm"); + FMC ( 6, 14, sX, "Intel Xeon Processor LV (Sossaman), 65nm"); + FMC ( 6, 14, dC, "Intel Celeron (Yonah), 65nm"); + FM ( 6, 14, "Intel Core Solo (Yonah) / Core Duo (Yonah) / Xeon Processor LV (Sossaman) / Celeron (Yonah), 65nm"); + /* + ** How to distinguish? + ** Core 2 Duo (Conroe B1) + ** Core 2 Extreme Processor (Conroe B1) + */ + FMSC ( 6, 15, 5, Dc, "Intel Core 2 Duo (Conroe B1) / Core 2 Extreme Processor (Conroe B1)"); + FMSC ( 6, 15, 5, Da, "Intel Core 2 Duo (Allendale B1)"); + FMSC ( 6, 15, 5, sX, "Intel Dual-Core Xeon Processor 5100 (Woodcrest B1) (pre-production), 65nm"); + FMS ( 6, 15, 5, "Intel Core 2 Duo (Conroe/Allendale B1) / Core 2 Extreme Processor (Conroe B1)"); + /* + ** How to distinguish? + ** Core 2 Duo (Conroe B2) + ** Core 2 Extreme Processor (Conroe B2) + */ + FMSC ( 6, 15, 6, Dc, "Intel Core 2 Duo (Conroe B2) / Core 2 Extreme Processor (Conroe B2)"); + FMSC ( 6, 15, 6, Da, "Intel Core 2 Duo (Allendale B2)"); + FMS ( 6, 15, 6, "Intel Core 2 Duo (Conroe/Allendale B2) / Core 2 Extreme Processor (Conroe B2) / Dual-Core Xeon Processor 5100 (Woodcrest B2), 65nm"); + FMC ( 6, 15, Dc, "Intel Core 2 Duo (Conroe) / Core 2 Extreme Processor (Conroe)"); + FMC ( 6, 15, Da, "Intel Core 2 Duo (Allendale)"); + FMC ( 6, 15, sX, "Intel Dual-Core Xeon Processor 5100 (Woodcrest), 65nm"); + FM ( 6, 15, "Intel Core 2 Duo (Conroe/Allendale) / Core 2 Extreme Processor (Conroe) / Dual-Core Xeon Processor 5100 (Woodcrest), 65nm"); + F ( 6, "Intel Pentium II / Pentium III / Pentium M / Celeron / Mobile Celeron / Celeron M / Core Solo / Core Duo / Core 2 / Core 2 Extreme Processor / Xeon Processor LV / Xeon Processor 5100 (unknown model)"); + FMS ( 7, 6, 4, "Intel Itanium (C0)"); + FMS ( 7, 7, 4, "Intel Itanium (C1)"); + FMS ( 7, 8, 4, "Intel Itanium (C2)"); + F ( 7, "Intel Itanium (unknown model)"); + XFMS ( 0, 0, 7, "Intel Pentium 4 (Willamette B2), .18um"); + XFMSC( 0, 0, 10, dP, "Intel Pentium 4 (Willamette C1), .18um"); + XFMSC( 0, 0, 10, sX, "Intel Xeon (Foster C1), .18um"); + XFMS ( 0, 0, 10, "Intel Pentium 4 (Willamette C1) / Xeon (Foster C1), .18um"); + XFMC ( 0, 0, dP, "Intel Pentium 4 (Willamette), .18um"); + XFMC ( 0, 0, sX, "Intel Xeon (Foster), .18um"); + XFM ( 0, 0, "Intel Pentium 4 (Willamette) / Xeon (Foster), .18um"); + XFMS ( 0, 1, 1, "Intel Xeon MP (Foster C0), .18um"); + XFMSC( 0, 1, 2, dP, "Intel Pentium 4 (Willamette D0), .18um"); + XFMSC( 0, 1, 2, sX, "Intel Xeon (Foster D0), .18um"); + XFMS ( 0, 1, 2, "Intel Pentium 4 (Willamette D0) / Xeon (Foster D0), .18um"); + XFMSC( 0, 1, 3, dP, "Intel Pentium 4(Willamette E0), .18um"); + XFMSC( 0, 1, 3, dC, "Intel Celeron 478-pin (Willamette E0), .18um"); + XFMS ( 0, 1, 3, "Intel Pentium 4 / Celeron (Willamette E0), .18um"); + XFMC ( 0, 1, dP, "Intel Pentium 4 (Willamette), .18um"); + XFMC ( 0, 1, sX, "Intel Xeon (Foster), .18um"); + XFM ( 0, 1, "Intel Pentium 4 (Willamette) / Xeon (Foster), .18um"); + XFMS ( 0, 2, 2, "Intel Xeon MP (Gallatin A0), .13um"); + XFMSC( 0, 2, 4, dP, "Intel Pentium 4 (Northwood B0), .13um"); + XFMSC( 0, 2, 4, sX, "Intel Xeon (Prestonia B0), .13um"); + XFMSC( 0, 2, 4, MM, "Intel Mobile Pentium 4 Processor-M (Northwood B0), .13um"); + XFMSC( 0, 2, 4, MC, "Intel Mobile Celeron (Northwood B0), .13um"); + XFMS ( 0, 2, 4, "Intel Pentium 4 (Northwood B0) / Xeon (Prestonia B0) / Mobile Pentium 4 Processor-M (Northwood B0) / Mobile Celeron (Northwood B0), .13um"); + XFMSC( 0, 2, 5, dP, "Intel Pentium 4 (Northwood B1/M0), .13um"); + XFMSC( 0, 2, 5, sX, "Intel Xeon (Prestonia B1), .13um"); + XFMSC( 0, 2, 5, sM, "Intel Xeon MP (Gallatin B1), .13um"); + XFMS ( 0, 2, 5, "Intel Pentium 4 (Northwood B1/M0) / Xeon (Prestonia B1) / Xeon MP (Gallatin B1), .13um"); + XFMS ( 0, 2, 6, "Intel Xeon MP (Gallatin C0), .13um"); + XFMSC( 0, 2, 7, dP, "Intel Pentium 4 (Northwood C1), .13um"); + XFMSC( 0, 2, 7, sX, "Intel Xeon (Prestonia C1), .13um"); + XFMSC( 0, 2, 7, MM, "Intel Mobile Pentium 4 Processor-M (Northwood C1), .13um"); + XFMSC( 0, 2, 7, dC, "Intel Celeron 478-pin (Northwood C1), .13um"); + XFMSC( 0, 2, 7, MC, "Intel Mobile Celeron (Northwood C1), .13um"); + XFMS ( 0, 2, 7, "Intel Pentium 4 (Northwood C1) / Xeon (Prestonia C1) / Mobile Pentium 4 Processor-M (Northwood C1) / Celeron 478-Pin (Northwood C1) / Mobile Celeron (Northwood C1), .13um"); + XFMSC( 0, 2, 9, dP, "Intel Pentium 4 (Northwood D1), .13um"); + XFMSC( 0, 2, 9, MP, "Intel Mobile Pentium 4 (Northwood D1), .13um"); + XFMSC( 0, 2, 9, sX, "Intel Xeon (Prestonia D1), .13um"); + XFMSC( 0, 2, 9, MM, "Intel Mobile Pentium 4 Processor-M (Northwood D1), .13um"); + XFMSC( 0, 2, 9, dC, "Intel Celeron 478-pin (Northwood D1), .13um"); + XFMSC( 0, 2, 9, MC, "Intel Mobile Celeron (Northwood D1), .13um"); + XFMS ( 0, 2, 9, "Intel Pentium 4 (Northwood D1) / Xeon (Prestonia D1) / Mobile Pentium 4 (Northwood D1) / Mobile Pentium 4 Processor-M (Northwood D1) / Celeron 478-pin, .13um"); + XFMC ( 0, 2, dP, "Intel Pentium 4 (Northwood), .13um"); + XFMC ( 0, 2, sX, "Intel Xeon (Prestonia), .13um"); + XFMC ( 0, 2, sM, "Intel Xeon MP (Gallatin), .13um"); + XFM ( 0, 2, "Intel Pentium 4 (Northwood) / Xeon (Prestonia) / Xeon MP (Gallatin) / Mobile Pentium 4 / Mobile Pentium 4 Processor-M / Celeron 478-pin, .13um"); + XFMSC( 0, 3, 3, dP, "Intel Pentium 4 (Prescott C0), 90nm"); + XFMSC( 0, 3, 3, dC, "Intel Celeron D (Prescott C0), 90nm"); + XFMS ( 0, 3, 3, "Intel Pentium 4 (Prescott C0) / Celeron D (Prescott C0), 90nm"); + XFMSC( 0, 3, 4, dP, "Intel Pentium 4 (Prescott D0), 90nm"); + XFMSC( 0, 3, 4, MP, "Intel Mobile Pentium 4 (Prescott D0), 90nm"); + XFMSC( 0, 3, 4, dC, "Intel Celeron D (Prescott D0), 90nm"); + XFMSC( 0, 3, 4, sX, "Intel Xeon (Nocona D0), 90nm"); + XFMS ( 0, 3, 4, "Intel Pentium 4 (Prescott D0) / Xeon (Nocona D0) / Mobile Pentium 4 (Prescott D0), 90nm"); + XFMC ( 0, 3, dP, "Intel Pentium 4 (Prescott), 90nm"); + XFMC ( 0, 3, MP, "Intel Mobile Pentium 4 (Prescott), 90nm"); + XFMC ( 0, 3, sX, "Intel Xeon (Nocona), 90nm"); + XFM ( 0, 3, "Intel Pentium 4 (Prescott) / Xeon (Nocona) / Mobile Pentium 4 (Prescott), 90nm"); + XFMSC( 0, 4, 1, dP, "Intel Pentium 4 (Prescott E0), 90nm"); + XFMSC( 0, 4, 1, dC, "Intel Celeron D (Prescott E0), 90nm"); + XFMSC( 0, 4, 1, MP, "Intel Mobile Pentium 4 (Prescott E0), 90nm"); + XFMSC( 0, 4, 1, sX, "Intel Xeon (Nocona E0), 90nm"); + XFMSC( 0, 4, 1, sM, "Intel Xeon MP (Cranford A0), 90nm"); + XFMSC( 0, 4, 1, sP, "Intel Xeon MP (Potomac C0), 90nm"); + XFMS ( 0, 4, 1, "Intel Pentium 4 (Prescott E0) / Xeon (Nocona E0) / Xeon MP (Cranford A0 / Potomac C0) / Celeron D (Prescott E0 ) / Mobile Pentium 4 (Prescott E0), 90nm"); + XFMSC( 0, 4, 3, dP, "Intel Pentium 4 (Prescott N0), 90nm"); + XFMSC( 0, 4, 3, sX, "Intel Xeon (Nocona N0), 90nm"); + XFMSC( 0, 4, 3, sI, "Intel Xeon (Irwindale N0), 90nm"); + XFMS ( 0, 4, 3, "Intel Pentium 4 (Prescott N0) / Xeon (Nocona N0 / Irwindale N0), 90nm"); + XFMSC( 0, 4, 4, dD, "Intel Pentium D Processor 8x0 (Smithfield A0), 90nm"); + XFMSC( 0, 4, 4, dc, "Intel Pentium Extreme Edition Processor 840 (Smithfield A0), 90nm"); + XFMS ( 0, 4, 4, "Intel Pentium D Processor 8x0 (Smithfield A0) / Pentium Extreme Edition Processor 840 (Smithfield A0), 90nm"); + XFMSC( 0, 4, 7, dD, "Intel Pentium D Processor 8x0 (Smithfield B0), 90nm"); + XFMSC( 0, 4, 7, dc, "Pentium Extreme Edition Processor 840 (Smithfield B0), 90nm"); + XFMS ( 0, 4, 7, "Intel Pentium D Processor 8x0 (Smithfield B0) / Pentium Extreme Edition Processor 840 (Smithfield B0), 90nm"); + XFMSC( 0, 4, 8, sX, "Intel Dual-Core Xeon (Paxville A0), 90nm"); + XFMSC( 0, 4, 8, s7, "Intel Dual-Core Xeon Processor 7000 (Paxville A0), 90nm"); + XFMS ( 0, 4, 8, "Intel Dual-Core Xeon (Paxville A0) / Dual-Core Xeon Processor 7000 (Paxville A0), 90nm"); + XFMSC( 0, 4, 9, dP, "Intel Pentium 4 (Prescott G1), 90nm"); + XFMSC( 0, 4, 9, sM, "Intel Xeon MP (Cranford B0), 90nm"); + XFMSC( 0, 4, 9, dC, "Intel Celeron D (Prescott G1), 90nm"); + XFMS ( 0, 4, 9, "Intel Pentium 4 (Prescott G1) / Xeon MP (Cranford B0) / Celeron D (Prescott G1), 90nm"); + XFMSC( 0, 4, 10, dP, "Intel Pentium 4 (Prescott R0), 90nm"); + XFMSC( 0, 4, 10, sX, "Intel Xeon (Nocona R0), 90nm"); + XFMSC( 0, 4, 10, sI, "Intel Xeon (Irwindale R0), 90nm"); + XFMS ( 0, 4, 10, "Intel Pentium 4 (Prescott R0) / Xeon (Nocona R0 / Irwindale R0), 90nm"); + XFMC ( 0, 4, dP, "Intel Pentium 4 (Prescott) / Pentium Extreme Edition (Smithfield A0), 90nm"); + XFMC ( 0, 4, dD, "Intel Pentium D (Smithfield A0), 90nm"); + XFMC ( 0, 4, dC, "Intel Celeron D (Prescott), 90nm"); + XFMC ( 0, 4, MP, "Intel Mobile Pentium 4 (Prescott), 90nm"); + XFMC ( 0, 4, sX, "Intel Xeon (Nocona), 90nm"); + XFMC ( 0, 4, sI, "Intel Xeon (Irwindale), 90nm"); + XFMC ( 0, 4, sM, "Intel Xeon MP (Nocona), 90nm"); + XFM ( 0, 4, "Intel Pentium 4 (Prescott) / Xeon (Nocona / Irwindale) / Pentium D (Smithfield A0) / Pentium Extreme Edition (Smithfield A0) / Mobile Pentium 4 (Prescott) / Xeon MP (Nocona) / Xeon MP (Cranford / Potomac) / Celeron D (Prescott) / Dual-Core Xeon (Paxville A0) / Dual-Core Xeon Processor 7000 (Paxville A0), 90nm"); + /* + ** How to distinguish? + ** Pentium 4 Processor 6x1 (Cedar Mill) + ** Pentium Extreme Edition Processor 955 (Presler) + */ + XFMSC( 0, 6, 2, dD, "Intel Pentium D Processor 9xx (Presler B1), 65nm"); + XFMSC( 0, 6, 2, dP, "Intel Pentium 4 Processor 6x1 (Cedar Mill B1) / Pentium Extreme Edition Processor 955 (Presler B1)"); + XFMS ( 0, 6, 2, "Intel Pentium 4 Processor 6x1 (Cedar Mill B1) / Pentium Extreme Edition Processor 955 (Presler B1) / Pentium D Processor 900 (Presler B1), 65nm"); + XFMSC( 0, 6, 4, dD, "Intel Pentium D Processor 9xx (Presler C1), 65nm"); + XFMSC( 0, 6, 4, dP, "Intel Pentium 4 Processor 6x1 (Cedar Mill C1) / Pentium Extreme Edition Processor 955 (Presler C1)"); + XFMSC( 0, 6, 4, dC, "Intel Celeron D Processor 3xx (Cedar Mill C1), 65nm"); + XFMSC( 0, 6, 4, sX, "Intel Xeon Processor 5000 (Dempsey C1), 65nm"); + XFMS ( 0, 6, 4, "Intel Pentium 4 Processor 6x1 (Cedar Mill C1) / Pentium Extreme Edition Processor 955 (Presler C1) / Intel Pentium D Processor 9xx (Presler C1), 65nm / Intel Xeon Processor 5000 (Dempsey C1) / Celeron D Processor 3xx (Cedar Mill C1), 65nm"); + XFMS ( 0, 6, 8, "Intel Xeon Processor 71x0 (Tulsa B0), 65nm"); + XFMC ( 0, 6, dD, "Intel Pentium D Processor 9xx (Presler), 65nm"); + XFMC ( 0, 6, dP, "Intel Pentium 4 Processor 6x1 (Cedar Mill) / Pentium Extreme Edition Processor 955 (Presler)"); + XFMC ( 0, 6, dC, "Intel Celeron D Processor 3xx (Cedar Mill), 65nm"); + XFMC ( 0, 6, sX, "Intel Xeon Processor 5000 (Dempsey) / Xeon Processor 71x0 (Tulsa), 65nm"); + XFM ( 0, 6, "Intel Pentium 4 Processor 6x1 (Cedar Mill) / Pentium Extreme Edition Processor 955 (Presler) / Pentium D Processor 900 (Presler) / Intel Xeon Processor 5000 (Dempsey) / Xeon Processor 71x0 (Tulsa) / Celeron D Processor 3xx (Cedar Mill), 65nm"); + XFC ( 0, dP, "Intel Pentium 4 (unknown model)"); + XFC ( 0, sX, "Intel Xeon (unknown model)"); + XFC ( 0, sM, "Intel Xeon MP (unknown model)"); + XFC ( 0, sP, "Intel Xeon MP (unknown model)"); + XF ( 0, "Intel Pentium 4 / Xeon / Xeon MP / Mobile Pentium 4 / Celeron / Celeron D / Mobile Celeron / Dual-Core Xeon / Dual-Core Xeon Processor 7000 (unknown model)"); + XFMS ( 1, 0, 7, "Intel Itanium2 (McKinley B3), .18um"); + XFM ( 1, 0, "Intel Itanium2 (McKinley), .18um"); + XFMS ( 1, 1, 5, "Intel Itanium2 (Madison/Deerfield B1), .13um"); + XFM ( 1, 1, "Intel Itanium2 (Madison/Deerfield), .13um"); + XFMS ( 1, 2, 1, "Intel Itanium2 (Madison A1), .13um"); + XFMS ( 1, 2, 2, "Intel Itanium2 (Madison A2), .13um"); + XFM ( 1, 2, "Intel Itanium2 (Madison), .13um"); + XFMS ( 2, 0, 5, "Intel Itanium2 (Montecito C1), 90nm"); + XFM ( 2, 0, "Intel Itanium2 (Montecito), 90nm"); + XF ( 1, "Intel Itanium2 (unknown model)"); + DEFAULT ("unknown"); + printf("\n"); +} + +static void +print_synth_amd_model(const code_stash_t* stash) +{ + unsigned int msb; + unsigned int NN; + + if (stash == NULL) return; + + if (__XB(stash->val_80000001_ebx) != 0) { + msb = BIT_EXTRACT_LE(__XB(stash->val_80000001_ebx), 6, 12); + NN = BIT_EXTRACT_LE(__XB(stash->val_80000001_ebx), 0, 6); + } else if (_B(stash->val_1_ebx) != 0) { + /* + ** Nothing explains how the msb of this brand should be interpreted. I + ** concluded it must be shifted left by 2 with a little reverse + ** engineering. That's the only way it gets the right answer for the + ** machine aero, which has brand 0x83, and is known to be a 244. + */ + msb = BIT_EXTRACT_LE(__B(stash->val_1_ebx), 5, 8) << 2; + NN = BIT_EXTRACT_LE(__B(stash->val_1_ebx), 0, 5); + } else { + return; + } + +#define XX (22 + NN) +#define YY (38 + 2*NN) +#define ZZ (24 + NN) +#define TT (24 + NN) +#define RR (45 + 5*NN) +#define EE ( 9 + NN) + + switch (msb) { + case 0x04: + case 0x05: + case 0x08: + case 0x09: + case 0x1d: + case 0x1e: + case 0x20: + printf(" Processor %02d00+", XX); + break; + case 0x0a: + printf(" ML-%02d", XX); + break; + case 0x0b: + printf(" MT-%02d", XX); + break; + case 0x0c: + case 0x0d: + printf(" Processor 1%02d", YY); + break; + case 0x0e: + printf(" Processor 1%02d HE", YY); + break; + case 0x0f: + printf(" Processor 1%02d EE", YY); + break; + case 0x10: + case 0x11: + printf(" Processor 2%02d", YY); + break; + case 0x12: + printf(" Processor 2%02d HE", YY); + break; + case 0x13: + printf(" Processor 2%02d EE", YY); + break; + case 0x14: + case 0x15: + printf(" Processor 8%02d", YY); + break; + case 0x16: + printf(" Processor 8%02d HE", YY); + break; + case 0x17: + printf(" Processor 8%02d EE", YY); + break; + case 0x18: + printf(" Processor %02d00+", EE); + case 0x21: + case 0x22: + case 0x23: + case 0x26: + printf(" Processor %02d00+", TT); + break; + case 0x24: + printf("-%02d", ZZ); + break; + case 0x29: + case 0x2c: + case 0x2d: + case 0x38: + printf(" Processor 1%02d", RR); + break; + case 0x2e: + printf(" Processor 1%02d HE", RR); + break; + case 0x2f: + printf(" Processor 1%02d EE", RR); + break; + case 0x2a: + case 0x30: + case 0x31: + case 0x39: + printf(" Processor 2%02d", RR); + break; + case 0x32: + printf(" Processor 2%02d HE", RR); + break; + case 0x33: + printf(" Processor 2%02d EE", RR); + break; + case 0x2b: + case 0x34: + case 0x35: + case 0x3a: + printf(" Processor 8%02d", RR); + break; + case 0x36: + printf(" Processor 8%02d HE", RR); + break; + case 0x37: + printf(" Processor 8%02d EE", RR); + break; + } + +#undef XX +#undef YY +#undef ZZ +#undef TT +#undef RR +#undef EE +} + +static void +print_synth_amd(const char* name, + unsigned int val, + code_t cd, + const code_stash_t* stash) +{ + printf(name); + START; + FM (4, 3, "AMD 80486DX2"); + FM (4, 7, "AMD 80486DX2WB"); + FM (4, 8, "AMD 80486DX4"); + FM (4, 9, "AMD 80486DX4WB"); + FM (4, 14, "AMD 5x86"); + FM (4, 15, "AMD 5xWB"); + F (4, "AMD 80486 / 5x (unknown model)"); + FM (5, 0, "AMD SSA5 (PR75, PR90, PR100)"); + FM (5, 1, "AMD 5k86 (PR120, PR133)"); + FM (5, 2, "AMD 5k86 (PR166)"); + FM (5, 3, "AMD 5k86 (PR200)"); + FM (5, 6, "AMD K6, .30um"); + FM (5, 7, "AMD K6 (Little Foot), .25um"); + FMS (5, 8, 0, "AMD K6-2 (Chomper A)"); + FMS (5, 8, 12, "AMD K6-2 (Chomper A)"); + FM (5, 8, "AMD K6-2 (Chomper)"); + FMS (5, 9, 1, "AMD K6-III (Sharptooth B)"); + FM (5, 9, "AMD K6-III (Sharptooth)"); + FM (5, 13, "AMD K6-2+, K6-III+"); + F (5, "AMD 5k86 / K6 (unknown model)"); + FM (6, 1, "AMD Athlon, .25um"); + FM (6, 2, "AMD Athlon (K75 / Pluto / Orion), .18um"); + FMS (6, 3, 0, "AMD Duron / mobile Duron (Spitfire A0)"); + FMS (6, 3, 1, "AMD Duron / mobile Duron (Spitfire A2)"); + FM (6, 3, "AMD Duron / mobile Duron (Spitfire)"); + FMS (6, 4, 2, "AMD Athlon (Thunderbird A4-A7)"); + FMS (6, 4, 4, "AMD Athlon (Thunderbird A9)"); + FM (6, 4, "AMD Athlon (Thunderbird)"); + FMSC (6, 6, 0, dA, "AMD Athlon (Palomino A0)"); + FMSC (6, 6, 0, sA, "AMD Athlon MP (Palomino A0)"); + FMSC (6, 6, 0, MA, "AMD mobile Athlon 4 (Palomino A0)"); + FMSC (6, 6, 0, sD, "AMD Duron MP (Palomino A0)"); + FMSC (6, 6, 0, MD, "AMD mobile Duron (Palomino A0)"); + FMS (6, 6, 0, "AMD Athlon / Athlon MP mobile Athlon 4 / mobile Duron (Palomino A0)"); + FMSC (6, 6, 1, dA, "AMD Athlon (Palomino A2)"); + FMSC (6, 6, 1, sA, "AMD Athlon MP (Palomino A2)"); + FMSC (6, 6, 1, dD, "AMD Duron (Palomino A2)"); + FMSC (6, 6, 1, MA, "AMD mobile Athlon 4 (Palomino A2)"); + FMSC (6, 6, 1, sD, "AMD Duron MP (Palomino A2)"); + FMSC (6, 6, 1, MD, "AMD mobile Duron (Palomino A2)"); + FMS (6, 6, 1, "AMD Athlon / Athlon MP / Duron / mobile Athlon / mobile Duron (Palomino A2)"); + FMSC (6, 6, 2, sA, "AMD Athlon MP (Palomino A5)"); + FMSC (6, 6, 2, dX, "AMD Athlon XP (Palomino A5)"); + FMSC (6, 6, 2, dD, "AMD Duron (Palomino A5)"); + FMSC (6, 6, 2, MA, "AMD mobile Athlon 4 (Palomino A5)"); + FMSC (6, 6, 2, sD, "AMD Duron MP (Palomino A5)"); + FMSC (6, 6, 2, MD, "AMD mobile Duron (Palomino A5)"); + FMS (6, 6, 2, "AMD Athlon MP / Athlon XP / Duron / Duron MP / mobile Athlon / mobile Duron (Palomino A5)"); + FMC (6, 6, dA, "AMD Athlon (Palomino)"); + FMC (6, 6, dX, "AMD Athlon XP (Palomino)"); + FMC (6, 6, dD, "AMD Duron (Palomino)"); + FMC (6, 6, MA, "AMD mobile Athlon (Palomino)"); + FMC (6, 6, MD, "AMD mobile Duron (Palomino)"); + FM (6, 6, "AMD Athlon / Athlon MP / Athlon XP / Duron / Duron MP / mobile Athlon / mobile Duron (Palomino)"); + FMSC (6, 7, 0, dD, "AMD Duron (Morgan A0)"); + FMSC (6, 7, 0, sD, "AMD Duron MP (Morgan A0)"); + FMSC (6, 7, 0, MD, "AMD mobile Duron (Morgan A0)"); + FMS (6, 7, 0, "AMD Duron / Duron MP / mobile Duron (Morgan A0)"); + FMSC (6, 7, 1, dD, "AMD Duron (Morgan A1)"); + FMSC (6, 7, 1, sD, "AMD Duron MP (Morgan A1)"); + FMSC (6, 7, 1, MD, "AMD mobile Duron (Morgan A1)"); + FMS (6, 7, 1, "AMD Duron / Duron MP / mobile Duron (Morgan A1)"); + FMC (6, 7, dD, "AMD Duron (Morgan)"); + FMC (6, 7, sD, "AMD Duron MP (Morgan)"); + FMC (6, 7, MD, "AMD mobile Duron (Morgan)"); + FM (6, 7, "AMD Duron / Duron MP / mobile Duron (Morgan)"); + FMSC (6, 8, 0, dX, "AMD Athlon XP (Thoroughbred A0)"); + FMSC (6, 8, 0, sA, "AMD Athlon MP (Thoroughbred A0)"); + FMSC (6, 8, 0, dD, "AMD Duron (Applebred A0)"); + FMSC (6, 8, 0, sD, "AMD Duron MP (Applebred A0)"); + FMSC (6, 8, 0, dS, "AMD Sempron (Thoroughbred A0)"); + FMSC (6, 8, 0, MX, "AMD mobile Athlon XP (Thoroughbred A0)"); + FMS (6, 8, 0, "AMD Athlon XP / Athlon MP / Sempron / Duron / Duron MP (Thoroughbred A0)"); + FMSC (6, 8, 1, dX, "AMD Athlon XP (Thoroughbred B0)"); + FMSC (6, 8, 1, sA, "AMD Athlon MP (Thoroughbred B0)"); + FMSC (6, 8, 1, dS, "AMD Sempron (Thoroughbred B0)"); + FMSC (6, 8, 1, dD, "AMD Duron (Thoroughbred B0)"); + FMSC (6, 8, 1, sD, "AMD Duron MP (Thoroughbred B0)"); + FMS (6, 8, 1, "AMD Athlon XP / Athlon MP / Sempron / Duron / Duron MP (Thoroughbred B0)"); + FMC (6, 8, dX, "AMD Athlon XP (Thoroughbred)"); + FMC (6, 8, sA, "AMD Athlon MP (Thoroughbred)"); + FMC (6, 8, dS, "AMD Sempron (Thoroughbred)"); + FMC (6, 8, sD, "AMD Duron MP (Thoroughbred)"); + FMC (6, 8, MX, "AMD mobile Athlon XP (Thoroughbred)"); + FM (6, 8, "AMD Athlon XP / Athlon MP / Sempron / Duron / Duron MP (Thoroughbred)"); + FMSC (6, 10, 0, dX, "AMD Athlon XP (Barton A2)"); + FMSC (6, 10, 0, dt, "AMD Athlon XP (Thorton A2)"); + FMSC (6, 10, 0, sA, "AMD Athlon MP (Barton A2)"); + FMSC (6, 10, 0, dS, "AMD Sempron (Barton A2)"); + FMSC (6, 10, 0, MX, "AMD mobile Athlon XP-M (Barton A2)"); + FMSC (6, 10, 0, ML, "AMD mobile Athlon XP-M (LV) (Barton A2)"); + FMS (6, 10, 0, "AMD Athlon XP / Athlon MP / Sempron / mobile Athlon XP-M / mobile Athlon XP-M (LV) (Barton A2)"); + FMC (6, 10, dX, "AMD Athlon XP (Barton)"); + FMC (6, 10, sA, "AMD Athlon MP (Barton)"); + FMC (6, 10, dS, "AMD Sempron (Barton)"); + FMC (6, 10, MX, "AMD mobile Athlon XP-M (Barton)"); + FMC (6, 10, ML, "AMD mobile Athlon XP-M (LV) (Barton)"); + FM (6, 10, "AMD Athlon XP / Athlon MP / Sempron / mobile Athlon XP-M / mobile Athlon XP-M (LV) (Barton)"); + F (6, "AMD Athlon / Athlon XP / Athlon MP / Duron / Duron MP / Sempron / mobile Athlon / mobile Athlon XP-M / mobile Athlon XP-M (LV) / mobile Duron (unknown model)"); + F (7, "AMD Opteron (unknown model)"); + XFXMS (0, 0, 4, 0, "AMD Athlon 64 (SledgeHammer SH7-B0), .13um"); + XFXMSC(0, 0, 4, 8, dA, "AMD Athlon 64 (SledgeHammer SH7-C0), 754-pin, .13um"); + XFXMSC(0, 0, 4, 8, MA, "AMD mobile Athlon 64 (SledgeHammer SH7-C0), 754-pin, .13um"); + XFXMSC(0, 0, 4, 8, MX, "AMD mobile Athlon XP-M (SledgeHammer SH7-C0), 754-pin, .13um"); + XFXMS (0, 0, 4, 8, "AMD Athlon 64 (SledgeHammer SH7-C0) / mobile Athlon 64 (SledgeHammer SH7-C0) / mobile Athlon XP-M (SledgeHammer SH7-C0), 754-pin, .13um"); + XFXMSC(0, 0, 4, 10, dA, "AMD Athlon 64 (SledgeHammer SH7-CG), 940-pin, .13um"); + XFXMSC(0, 0, 4, 10, MA, "AMD mobile Athlon 64 (SledgeHammer SH7-CG), 940-pin, .13um"); + XFXMSC(0, 0, 4, 10, MX, "AMD mobile Athlon XP-M (SledgeHammer SH7-CG), 940-pin, .13um"); + XFXMS (0, 0, 4, 10, "AMD Athlon 64 (SledgeHammer SH7-CG) / mobile Athlon 64 (SledgeHammer SH7-CG) / mobile Athlon XP-M (SledgeHammer SH7-CG), 940-pin, .13um"); + XFXMC (0, 0, 4, dA, "AMD Athlon 64 (SledgeHammer SH7), .13um"); + XFXMC (0, 0, 4, MA, "AMD mobile Athlon 64 (SledgeHammer SH7), .13um"); + XFXMC (0, 0, 4, MX, "AMD mobile Athlon XP-M (SledgeHammer SH7), .13um"); + XFXM (0, 0, 4, "AMD Athlon 64 (SledgeHammer SH7) / mobile Athlon 64 (SledgeHammer SH7) / mobile Athlon XP-M (SledgeHammer SH7), .13um"); + XFXMS (0, 0, 5, 0, "AMD Opteron (DP SledgeHammer SH7-B0), 940-pin, .13um"); + XFXMS (0, 0, 5, 1, "AMD Opteron (DP SledgeHammer SH7-B3), 940-pin, .13um"); + XFXMSC(0, 0, 5, 8, dO, "AMD Opteron (DP SledgeHammer SH7-C0), 940-pin, .13um"); + XFXMSC(0, 0, 5, 8, dF, "AMD Athlon 64 FX (DP SledgeHammer SH7-C0), 940-pin, .13um"); + XFXMS (0, 0, 5, 8, "AMD Opteron (DP SledgeHammer SH7-C0) / Athlon 64 FX (DP SledgeHammer SH7-C0), 940-pin, .13um"); + XFXMSC(0, 0, 5, 10, dO, "AMD Opteron (DP SledgeHammer SH7-CG), 940-pin, .13um"); + XFXMSC(0, 0, 5, 10, dF, "AMD Athlon 64 FX (DP SledgeHammer SH7-CG), 940-pin, .13um"); + XFXMS (0, 0, 5, 10, "AMD Opteron (DP SledgeHammer SH7-CG) / Athlon 64 FX (DP SledgeHammer SH7-CG), 940-pin, .13um"); + XFXMC (0, 0, 5, dO, "AMD Opteron (SledgeHammer SH7), 940-pin, .13um"); + XFXMC (0, 0, 5, dF, "AMD Athlon 64 FX (SledgeHammer SH7), 940-pin, .13um"); + XFXM (0, 0, 5, "AMD Opteron (SledgeHammer SH7) / Athlon 64 (SledgeHammer SH7) FX, 940-pin, .13um"); + XFXMSC(0, 0, 7, 10, dA, "AMD Athlon 64 (DP SledgeHammer SH7-CG), 939-pin, .13um"); + XFXMSC(0, 0, 7, 10, dF, "AMD Athlon 64 FX (DP SledgeHammer SH7-CG), 939-pin, .13um"); + XFXMS (0, 0, 7, 10, "AMD Athlon 64 (DP SledgeHammer SH7-CG) / Athlon 64 FX (DP SledgeHammer SH7-CG), 939-pin, .13um"); + XFXMC (0, 0, 7, dA, "AMD Athlon 64 (DP SledgeHammer SH7), 939-pin, .13um"); + XFXMC (0, 0, 7, dF, "AMD Athlon 64 FX (DP SledgeHammer SH7), 939-pin, .13um"); + XFXM (0, 0, 7, "AMD Athlon 64 (DP SledgeHammer SH7) / Athlon 64 FX (DP SledgeHammer SH7), 939-pin, .13um"); + XFXMSC(0, 0, 8, 2, dA, "AMD Athlon 64 (ClawHammer CH7-CG), 754-pin, .13um"); + XFXMSC(0, 0, 8, 2, MA, "AMD mobile Athlon 64 (Odessa CH7-CG), 754-pin, .13um"); + XFXMSC(0, 0, 8, 2, MS, "AMD mobile Sempron (ClawHammer CH7-CG), 754-pin, .13um"); + XFXMSC(0, 0, 8, 2, MX, "AMD mobile Athlon XP-M (ClawHammer CH7-CG), 754-pin, .13um"); + XFXMS (0, 0, 8, 2, "AMD Athlon 64 (ClawHammer CH7-CG) / mobile Athlon 64 (Odessa CH7-CG) / mobile Sempron (ClawHammer CH7-CG) / mobile Athlon XP-M (ClawHammer CH7-CG), 754-pin, .13um"); + XFXMC (0, 0, 8, dA, "AMD Athlon 64 (ClawHammer CH7), 754-pin, .13um"); + XFXMC (0, 0, 8, MA, "AMD mobile Athlon 64 (Odessa CH7), 754-pin, .13um"); + XFXMC (0, 0, 8, MS, "AMD mobile Sempron (Odessa CH7), 754-pin, .13um"); + XFXMC (0, 0, 8, MX, "AMD mobile Athlon XP-M (Odessa CH7), 754-pin, .13um"); + XFXM (0, 0, 8, "AMD Athlon 64 (ClawHammer CH7) / mobile Athlon 64 (Odessa CH7) / mobile Sempron (Odessa CH7) / mobile Athlon XP-M (Odessa CH7), 754-pin, .13um"); + XFXMS (0, 0, 11, 2, "AMD Athlon 64 (ClawHammer CH7-CG), 939-pin, .13um"); + XFXM (0, 0, 11, "AMD Athlon 64 (ClawHammer CH7), 939-pin, .13um"); + XFXMSC(0, 0, 12, 0, dA, "AMD Athlon 64 (NewCastle DH7-CG), 754-pin, .13um"); + XFXMSC(0, 0, 12, 0, MA, "AMD mobile Athlon 64 (Dublin DH7-CG), 754-pin, .13um"); + XFXMSC(0, 0, 12, 0, dS, "AMD Sempron (Paris DH7-CG), 754-pin, .13um"); + XFXMSC(0, 0, 12, 0, MS, "AMD mobile Sempron (Sonora DH7-CG), 754-pin, .13um"); + XFXMSC(0, 0, 12, 0, MX, "AMD mobile Athlon XP-M (Dublin DH7-CG), 754-pin, .13um"); + XFXMS (0, 0, 12, 0, "AMD Athlon 64 (NewCastle DH7-CG) / Sempron (Paris DH7-CG) / mobile Athlon 64 (Dublin DH7-CG) / mobile Sempron (Sonora DH7-CG) / mobile Athlon XP-M (Dublin DH7-CG), 754-pin, .13um"); + XFXMC (0, 0, 12, dA, "AMD Athlon 64 (NewCastle DH7), 754-pin, .13um"); + XFXMC (0, 0, 12, MA, "AMD mobile Athlon 64 (Dublin DH7), 754-pin, .13um"); + XFXMC (0, 0, 12, dS, "AMD Sempron (Paris DH7), 754-pin, .13um"); + XFXMC (0, 0, 12, MS, "AMD mobile Sempron (Sonora DH7), 754-pin, .13um"); + XFXMC (0, 0, 12, MX, "AMD mobile Athlon XP-M (NewCastle DH7), 754-pin, .13um"); + XFXM (0, 0, 12, "AMD Athlon 64 (NewCastle DH7) / Sempron (Paris DH7) / mobile Athlon 64 (Dublin DH7) / mobile Sempron (Sonora DH7) / mobile Athlon XP-M (Dublin DH7), 754-pin, .13um"); + XFXMSC(0, 0, 14, 0, dA, "AMD Athlon 64 (NewCastle DH7-CG), 754-pin, .13um"); + XFXMSC(0, 0, 14, 0, MA, "AMD mobile Athlon 64 (Dublin DH7-CG), 754-pin, .13um"); + XFXMSC(0, 0, 14, 0, dS, "AMD Sempron (Paris DH7-CG), 754-pin, .13um"); + XFXMSC(0, 0, 14, 0, MS, "AMD mobile Sempron (Sonora DH7-CG), 754-pin, .13um"); + XFXMSC(0, 0, 14, 0, MX, "AMD mobile Athlon XP-M (Dublin DH7-CG), 754-pin, .13um"); + XFXMS (0, 0, 14, 0, "AMD Athlon 64 (NewCastle DH7-CG) / Sempron (Paris DH7-CG) / mobile Athlon 64 (Dublin DH7-CG) / mobile Sempron (Sonora DH7-CG) / mobile Athlon XP-M (Dublin DH7-CG), 754-pin, .13um"); + XFXMC (0, 0, 14, dA, "AMD Athlon 64 (NewCastle DH7), 754-pin, .13um"); + XFXMC (0, 0, 14, MA, "AMD mobile Athlon 64 (Dublin DH7), 754-pin, .13um"); + XFXMC (0, 0, 14, dS, "AMD Sempron (Paris DH7), 754-pin, .13um"); + XFXMC (0, 0, 14, MS, "AMD mobile Sempron (Sonora DH7), 754-pin, .13um"); + XFXMC (0, 0, 14, MX, "AMD mobile Athlon XP-M (Dublin DH7), 754-pin, .13um"); + XFXM (0, 0, 14, "AMD Athlon 64 (NewCastle DH7) / Sempron (Paris DH7) / mobile Athlon 64 (Dublin DH7) / mobile Sempron (Sonora DH7) / mobile Athlon XP-M (Dublin DH7), 754-pin, .13um"); + XFXMSC(0, 0, 15, 0, dA, "AMD Athlon 64 (NewCastle DH7-CG), 939-pin, .13um"); + XFXMSC(0, 0, 15, 0, MA, "AMD mobile Athlon 64 (Dublin DH7-CG), 939-pin, .13um"); + XFXMSC(0, 0, 15, 0, dS, "AMD Sempron (Paris DH7-CG), 939-pin, .13um"); + XFXMS (0, 0, 15, 0, "AMD Athlon 64 (NewCastle DH7-CG) / Sempron (Paris DH7-CG) / mobile Athlon 64 (Dublin DH7-CG), 939-pin, .13um"); + XFXMC (0, 0, 15, dA, "AMD Athlon 64 (NewCastle DH7), 939-pin, .13um"); + XFXMC (0, 0, 15, MA, "AMD mobile Athlon 64 (Dublin DH7), 939-pin, .13um"); + XFXMC (0, 0, 15, dS, "AMD Sempron (Paris DH7), 939-pin, .13um"); + XFXM (0, 0, 15, "AMD Athlon 64 (NewCastle DH7) / Sempron (Paris DH7) / mobile Athlon 64 (Dublin DH7), 939-pin, .13um"); + XFXMSC(0, 1, 4, 0, dA, "AMD Athlon 64 (Winchester SH7-D0), 754-pin, 90nm"); + XFXMSC(0, 1, 4, 0, MA, "AMD mobile Athlon 64 (Oakville SH7-D0), 754-pin, 90nm"); + XFXMSC(0, 1, 4, 0, MX, "AMD mobile Athlon XP-M (Oakville SH7-D0), 754-pin, 90nm"); + XFXMS (0, 1, 4, 0, "AMD Athlon 64 (Winchester SH7-D0) / mobile Athlon 64 (Oakville SH7-D0) / mobile Athlon XP-M (Oakville SH7-D0), 754-pin, 90nm"); + XFXMC (0, 1, 4, dA, "AMD Athlon 64 (Winchester SH7), 754-pin, 90nm"); + XFXMC (0, 1, 4, MA, "AMD mobile Athlon 64 (Winchester SH7), 754-pin, 90nm"); + XFXMC (0, 1, 4, MX, "AMD mobile Athlon XP-M (Winchester SH7), 754-pin, 90nm"); + XFXM (0, 1, 4, "AMD Athlon 64 (Winchester SH7) / mobile Athlon 64 (Winchester SH7) / mobile Athlon XP-M (Winchester SH7), 754-pin, 90nm"); + XFXMSC(0, 1, 5, 0, dO, "AMD Opteron (Winchester SH7-D0), 940-pin, 90nm"); + XFXMSC(0, 1, 5, 0, dF, "AMD Athlon 64 FX (Winchester SH7-D0), 940-pin, 90nm"); + XFXMS (0, 1, 5, 0, "AMD Opteron (Winchester SH7-D0) / Athlon 64 FX (Winchester SH7-D0), 940-pin, 90nm"); + XFXMC (0, 1, 5, dO, "AMD Opteron (Winchester SH7), 940-pin, 90nm"); + XFXMC (0, 1, 5, dF, "AMD Athlon 64 FX (Winchester SH7), 940-pin, 90nm"); + XFXM (0, 1, 5, "AMD Opteron (Winchester SH7) / Athlon 64 FX (Winchester SH7), 940-pin, 90nm"); + XFXMSC(0, 1, 7, 0, dA, "AMD Athlon 64 (Winchester SH7-D0), 939-pin, 90nm"); + XFXMSC(0, 1, 7, 0, dF, "AMD Athlon 64 FX (Winchester SH7-D0), 939-pin, 90nm"); + XFXMS (0, 1, 7, 0, "AMD Athlon 64 (Winchester SH7-D0) / Athlon 64 FX (Winchester SH7-D0), 939-pin, 90nm"); + XFXMC (0, 1, 7, dA, "AMD Athlon 64 (Winchester SH7), 939-pin, 90nm"); + XFXMC (0, 1, 7, dF, "AMD Athlon 64 FX (Winchester SH7), 939-pin, 90nm"); + XFXM (0, 1, 7, "AMD Athlon 64 (Winchester SH7) / Athlon 64 FX (Winchester SH7), 939-pin, 90nm"); + XFXMSC(0, 1, 8, 0, dA, "AMD Athlon 64 (Winchester CH-D0), 754-pin, 90nm"); + XFXMSC(0, 1, 8, 0, MA, "AMD mobile Athlon 64 (Oakville CH-D0), 754-pin, 90nm"); + XFXMSC(0, 1, 8, 0, MS, "AMD mobile Sempron (Palermo CH-D0), 754-pin, 90nm"); + XFXMSC(0, 1, 8, 0, MX, "AMD mobile Athlon XP-M (Oakville CH-D0), 754-pin, 90nm"); + XFXMS (0, 1, 8, 0, "AMD Athlon 64 (Winchester CH-D0) / mobile Athlon 64 (Oakville CH-D0) / mobile Sempron (Palermo CH-D0) / mobile Athlon XP-M (Oakville CH-D0), 754-pin, 90nm"); + XFXMC (0, 1, 8, dA, "AMD Athlon 64 (Winchester CH), 754-pin, 90nm"); + XFXMC (0, 1, 8, MA, "AMD mobile Athlon 64 (Winchester CH), 754-pin, 90nm"); + XFXMC (0, 1, 8, MS, "AMD mobile Sempron (Palermo CH), 754-pin, 90nm"); + XFXMC (0, 1, 8, MX, "AMD mobile Athlon XP-M (Winchester CH), 754-pin, 90nm"); + XFXM (0, 1, 8, "AMD Athlon 64 (Winchester CH) / mobile Athlon 64 (Winchester CH) / mobile Sempron (Palermo CH) / mobile Athlon XP-M (Winchester CH), 754-pin, 90nm"); + XFXMS (0, 1, 11, 0, "AMD Athlon 64 (Winchester CH-D0), 939-pin, 90nm"); + XFXM (0, 1, 11, "AMD Athlon 64 (Winchester CH), 939-pin, 90nm"); + XFXMSC(0, 1, 12, 0, dA, "AMD Athlon 64 (Winchester DH8-D0), 754-pin, 90nm"); + XFXMSC(0, 1, 12, 0, MA, "AMD mobile Athlon 64 (Oakville DH8-D0), 754-pin, 90nm"); + XFXMSC(0, 1, 12, 0, dS, "AMD Sempron (Palermo DH8-D0), 754-pin, 90nm"); + XFXMSC(0, 1, 12, 0, MS, "AMD mobile Sempron (Palermo DH8-D0), 754-pin, 90nm"); + XFXMSC(0, 1, 12, 0, MX, "AMD Athlon XP-M (Winchester DH8-D0), 754-pin, 90nm"); + XFXMS (0, 1, 12, 0, "AMD Athlon 64 (Winchester DH8-D0) / Sempron (Palermo DH8-D0) / mobile Athlon 64 (Oakville DH8-D0) / mobile Sempron (Palermo DH8-D0) / mobile Athlon XP-M (Winchester DH8-D0), 754-pin, 90nm"); + XFXMC (0, 1, 12, dA, "AMD Athlon 64 (Winchester DH8), 754-pin, 90nm"); + XFXMC (0, 1, 12, MA, "AMD mobile Athlon 64 (Winchester DH8), 754-pin, 90nm"); + XFXMC (0, 1, 12, dS, "AMD Sempron (Palermo DH8), 754-pin, 90nm"); + XFXMC (0, 1, 12, MS, "AMD mobile Sempron (Palermo DH8), 754-pin, 90nm"); + XFXMC (0, 1, 12, MX, "AMD Athlon XP-M (Winchester DH8), 754-pin, 90nm"); + XFXM (0, 1, 12, "AMD Athlon 64 (Winchester DH8) / Sempron (Palermo DH8) / mobile Athlon 64 (Winchester DH8) / mobile Sempron (Palermo DH8) / mobile Athlon XP-M (Winchester DH8), 754-pin, 90nm"); + XFXMSC(0, 1, 15, 0, dA, "AMD Athlon 64 (Winchester DH8-D0), 939-pin, 90nm"); + XFXMSC(0, 1, 15, 0, dS, "AMD Sempron (Palermo DH8-D0), 939-pin, 90nm"); + XFXMS (0, 1, 15, 0, "AMD Athlon 64 (Winchester DH8-D0) / Sempron (Palermo DH8-D0), 939-pin, 90nm"); + XFXMC (0, 1, 15, dA, "AMD Athlon 64 (Winchester DH8), 939-pin, 90nm"); + XFXMC (0, 1, 15, dS, "AMD Sempron (Palermo DH8), 939-pin, 90nm"); + XFXM (0, 1, 15, "AMD Athlon 64 (Winchester DH8) / Sempron (Palermo DH8), 939-pin, 90nm"); + XFXMSC(0, 2, 1, 0, DO, "AMD Dual Core Opteron (Italy JH-E1), 940-pin, 90nm"); + XFXMSC(0, 2, 1, 0, D8, "AMD Dual Core Opteron (Egypt JH-E1), 940-pin, 90nm"); + XFXMS (0, 2, 1, 0, "AMD Dual Core Opteron (Italy/Egypt JH-E1), 940-pin, 90nm"); + XFXMSC(0, 2, 1, 2, DO, "AMD Dual Core Opteron (Italy JH-E6), 940-pin, 90nm"); + XFXMSC(0, 2, 1, 2, D8, "AMD Dual Core Opteron (Egypt JH-E6), 940-pin, 90nm"); + XFXMS (0, 2, 1, 2, "AMD Dual Core Opteron (Italy/Egypt JH-E6), 940-pin, 90nm"); + XFXM (0, 2, 1, "AMD Dual Core Opteron (Italy/Egypt JH), 940-pin, 90nm"); + XFXMSC(0, 2, 3, 2, DO, "AMD Dual Core Opteron (Denmark JH-E6), 939-pin, 90nm"); + XFXMSC(0, 2, 3, 2, dA, "AMD Athlon 64 X2 (Toledo JH-E6), 939-pin, 90nm"); + XFXMSC(0, 2, 3, 2, dm, "AMD Athlon 64 X2 (Manchester JH-E6), 939-pin, 90nm"); + XFXMS (0, 2, 3, 2, "AMD Dual Core Opteron (Denmark JH-E6) / Athlon 64 X2 (Toledo JH-E6), 939-pin, 90nm"); + XFXMC (0, 2, 3, DO, "AMD Dual Core Opteron (Denmark JH), 939-pin, 90nm"); + XFXMC (0, 2, 3, dA, "AMD Athlon 64 X2 (Toledo JH), 939-pin, 90nm"); + XFXMC (0, 2, 3, dm, "AMD Athlon 64 X2 (Manchester JH), 939-pin, 90nm"); + XFXM (0, 2, 3, "AMD Dual Core Opteron (Denmark JH) / Athlon 64 X2 (Toledo JH / Manchester JH), 939-pin, 90nm"); + XFXMSC(0, 2, 4, 2, MA, "AMD mobile Athlon 64 (Newark SH-E5), 754-pin, 90nm"); + XFXMSC(0, 2, 4, 2, MT, "AMD mobile Turion (Lancaster SH-E5), 754-pin, 90nm"); + XFXMS (0, 2, 4, 2, "AMD mobile Athlon 64 (Newark SH-E5) / mobile Turion (Lancaster SH-E5), 754-pin, 90nm"); + XFXMC (0, 2, 4, MA, "AMD mobile Athlon 64 (Newark SH), 754-pin, 90nm"); + XFXMC (0, 2, 4, MT, "AMD mobile Turion (Lancaster SH), 754-pin, 90nm"); + XFXM (0, 2, 4, "AMD mobile Athlon 64 (Newark SH) / mobile Turion (Lancaster SH), 754-pin, 90nm"); + XFXMC (0, 2, 5, dO, "AMD Opteron (Troy SH-E4), 940-pin, 90nm"); + XFXMC (0, 2, 5, d8, "AMD Opteron (Athens SH-E4), 940-pin, 90nm"); + XFXM (0, 2, 5, "AMD Opteron (Troy/Athens SH-E4), 940-pin, 90nm"); + XFXMSC(0, 2, 7, 1, dO, "AMD Opteron (Venus SH-E4), 939-pin, 90nm"); + XFXMSC(0, 2, 7, 1, dA, "AMD Athlon 64 (San Diego SH-E4), 939-pin, 90nm"); + XFXMSC(0, 2, 7, 1, dF, "AMD Athlon 64 FX (San Diego SH-E4), 939-pin, 90nm"); + XFXMS (0, 2, 7, 1, "AMD Opteron (Venus SH-E4) / Athlon 64 (San Diego SH-E4) / Athlon 64 FX (San Diego SH-E4), 939-pin, 90nm"); + XFXMC (0, 2, 7, dO, "AMD Opteron (San Diego SH), 939-pin, 90nm"); + XFXMC (0, 2, 7, dA, "AMD Athlon 64 (San Diego SH), 939-pin, 90nm"); + XFXMC (0, 2, 7, dF, "AMD Athlon 64 FX (San Diego SH), 939-pin, 90nm"); + XFXM (0, 2, 7, "AMD Opteron (San Diego SH) / Athlon 64 (San Diego SH) / Athlon 64 FX (San Diego SH), 939-pin, 90nm"); + XFXM (0, 2, 11, "AMD Athlon 64 X2 (Manchester BH-E4), 939-pin, 90nm"); + XFXMS (0, 2, 12, 0, "AMD Sempron (Palermo DH-E3), 754-pin, 90nm"); + XFXMSC(0, 2, 12, 2, dS, "AMD Sempron (Palermo DH-E6), 754-pin, 90nm"); + XFXMSC(0, 2, 12, 2, MS, "AMD mobile Sempron (Palermo DH-E6), 754-pin, 90nm"); + XFXMS (0, 2, 12, 2, "AMD Sempron (Palermo DH-E6) / mobile Sempron (Palermo DH-E6), 754-pin, 90nm"); + XFXMC (0, 2, 12, dS, "AMD Sempron (Palermo DH), 754-pin, 90nm"); + XFXMC (0, 2, 12, MS, "AMD mobile Sempron (Palermo DH), 754-pin, 90nm"); + XFXM (0, 2, 12, "AMD Sempron (Palermo DH) / mobile Sempron (Palermo DH), 754-pin, 90nm"); + XFXMSC(0, 2, 15, 0, dA, "AMD Athlon 64 (Venice DH-E3), 939-pin, 90nm"); + XFXMSC(0, 2, 15, 0, dS, "AMD Sempron (Palermo DH-E3), 939-pin, 90nm"); + XFXMS (0, 2, 15, 0, "AMD Athlon 64 (Venice DH-E3) / Sempron (Palermo DH-E3), 939-pin, 90nm"); + XFXMSC(0, 2, 15, 2, dA, "AMD Athlon 64 (Venice DH-E6), 939-pin, 90nm"); + XFXMSC(0, 2, 15, 2, dS, "AMD Sempron (Palermo DH-E6), 939-pin, 90nm"); + XFXMS (0, 2, 15, 2, "AMD Athlon 64 (Venice DH-E6) / Sempron (Palermo DH-E6), 939-pin, 90nm"); + XFXMC (0, 2, 15, dA, "AMD Athlon 64 (Venice DH), 939-pin, 90nm"); + XFXMC (0, 2, 15, dS, "AMD Sempron (Palermo DH), 939-pin, 90nm"); + XFXM (0, 2, 15, "AMD Athlon 64 (Venice DH) / Sempron (Palermo DH), 939-pin, 90nm"); + XF (0, "AMD Opteron / Athlon 64 / Athlon 64 FX / Sempron / Dual Core Opteron / Athlon 64 X2 / mobile Athlon 64 / mobile Sempron / mobile Athlon XP-M (DP) (unknown model)"); + DEFAULT ("unknown"); + + /* + ** I can't get any consistent answers on what values are appropriate for the + ** following: + ** Georgetown/Sonora (nearly identical mobile Semprons variants of what?) + ** Albany/Roma (nearly identical mobile Semprons variants of what?) + */ + + print_synth_amd_model(stash); + + printf("\n"); +} + +static void +print_synth_cyrix(const char* name, + unsigned int val) +{ + printf(name); + START; + FM (4, 4, "Cyrix Media GX / GXm"); + FM (4, 9, "Cyrix 5x86"); + F (4, "Cyrix 5x86 (unknown model)"); + FM (5, 2, "Cyrix M1 6x86"); + FM (5, 4, "Cyrix M1 WinChip (C6)"); + FM (5, 8, "Cyrix M1 WinChip 2 (C6-2)"); + FM (5, 9, "Cyrix M1 WinChip 3 (C6-2)"); + F (5, "Cyrix M1 (unknown model)"); + FM (6, 0, "Cyrix M2 6x86MX"); + FM (6, 5, "Cyrix M2"); + F (6, "Cyrix M2 (unknown model)"); + DEFAULT ("unknown"); + printf("\n"); +} + +static void +print_synth_via(const char* name, + unsigned int val) +{ + printf(name); + START; + FM (6, 6, "VIA C3 (Samuel WinChip C5A core)"); + FM (6, 6, "VIA C3 (Samuel WinChip C5A core)"); + FMS(6, 7, 0, "VIA C3 (Samuel 2 WinChip C5B core) / Eden ESP 4000/5000/6000"); + FMS(6, 7, 1, "VIA C3 (Samuel 2 WinChip C5B core) / Eden ESP 4000/5000/6000"); + FMS(6, 7, 2, "VIA C3 (Samuel 2 WinChip C5B core) / Eden ESP 4000/5000/6000"); + FMS(6, 7, 3, "VIA C3 (Samuel 2 WinChip C5B core) / Eden ESP 4000/5000/6000"); + FMS(6, 7, 4, "VIA C3 (Samuel 2 WinChip C5B core) / Eden ESP 4000/5000/6000"); + FMS(6, 7, 5, "VIA C3 (Samuel 2 WinChip C5B core) / Eden ESP 4000/5000/6000"); + FMS(6, 7, 6, "VIA C3 (Samuel 2 WinChip C5B core) / Eden ESP 4000/5000/6000"); + FMS(6, 7, 7, "VIA C3 (Samuel 2 WinChip C5B core) / Eden ESP 4000/5000/6000"); + FM (6, 7, "VIA C3 (Ezra WinChip C5C core)"); + FM (6, 8, "VIA C3 (Ezra-T WinChip C5N core)"); + FMS(6, 9, 0, "VIA C3 / Eden ESP 7000/8000/10000 (Nehemiah WinChip C5XL core)"); + FMS(6, 9, 1, "VIA C3 / Eden ESP 7000/8000/10000 (Nehemiah WinChip C5XL core)"); + FMS(6, 9, 2, "VIA C3 / Eden ESP 7000/8000/10000 (Nehemiah WinChip C5XL core)"); + FMS(6, 9, 3, "VIA C3 / Eden ESP 7000/8000/10000 (Nehemiah WinChip C5XL core)"); + FMS(6, 9, 4, "VIA C3 / Eden ESP 7000/8000/10000 (Nehemiah WinChip C5XL core)"); + FMS(6, 9, 5, "VIA C3 / Eden ESP 7000/8000/10000 (Nehemiah WinChip C5XL core)"); + FMS(6, 9, 6, "VIA C3 / Eden ESP 7000/8000/10000 (Nehemiah WinChip C5XL core)"); + FMS(6, 9, 7, "VIA C3 / Eden ESP 7000/8000/10000 (Nehemiah WinChip C5XL core)"); + FM (6, 9, "VIA C3 / C3-M / Eden-N (Nehemiah WinChip C5P core)"); + FM (6, 10, "VIA C7 / C7-M (Esther WinChip C5J core)"); + F (6, "VIA C3 / C3-M / C7 / C7-M / Eden ESP 7000/8000/10000 (unknown model)"); + DEFAULT ("unknown"); + printf("\n"); +} + +static void +print_synth_umc(const char* name, + unsigned int val) +{ + printf(name); + START; + FM (4, 1, "UMC U5D (486DX)"); + FMS(4, 2, 3, "UMC U5S (486SX)"); + FM (4, 2, "UMC U5S (486SX) (unknown stepping)"); + DEFAULT ("unknown"); + printf("\n"); +} + +static void +print_synth_nexgen(const char* name, + unsigned int val) +{ + printf(name); + START; + FMS(5, 0, 4, "NexGen P100"); + FMS(5, 0, 6, "NexGen P120 (E2/C0)"); + DEFAULT ("unknown"); + printf("\n"); +} + +static void +print_synth_rise(const char* name, + unsigned int val) +{ + printf(name); + START; + FM (5, 0, "Rise mP6 iDragon, .25u"); + FM (5, 2, "Rise mP6 iDragon, .18u"); + FM (5, 8, "Rise mP6 iDragon II, .25u"); + FM (5, 9, "Rise mP6 iDragon II, .18u"); + DEFAULT ("unknown"); + printf("\n"); +} + +static void +print_synth_transmeta(const char* name, + unsigned int val, + code_t cd) +{ + /* TODO: Add code-based detail for Transmeta Crusoe TM5700/TM5900 */ + /* TODO: Add code-based detail for Transmeta Efficeon */ + printf(name); + START; + FMSC(5, 4, 2, t2, "Transmeta Crusoe TM3200"); + FMS (5, 4, 2, "Transmeta Crusoe TM3x00 (unknown model)"); + FMSC(5, 4, 3, t4, "Transmeta Crusoe TM5400"); + FMSC(5, 4, 3, t5, "Transmeta Crusoe TM5500 / Crusoe SE TM55E"); + FMSC(5, 4, 3, t6, "Transmeta Crusoe TM5600"); + FMSC(5, 4, 3, t8, "Transmeta Crusoe TM5800 / Crusoe SE TM58E"); + FMS (5, 4, 3, "Transmeta Crusoe TM5x00 (unknown model)"); + FM (5, 4, "Transmeta Crusoe"); + F (5, "Transmeta Crusoe (unknown model)"); + DEFAULT ("unknown"); + printf("\n"); +} + +static void +print_x_synth_amd(unsigned int val) +{ + printf(" (simple synth) = "); + START; + FM (4, 3, "AMD 80486DX2"); + FM (4, 7, "AMD 80486DX2WB"); + FM (4, 8, "AMD 80486DX4"); + FM (4, 9, "AMD 80486DX4WB"); + FM (4, 14, "AMD 5x86"); + FM (4, 15, "AMD 5xWB"); + F (4, "AMD 80486 / 5x (unknown model)"); + FM (5, 0, "AMD SSA5 (PR75, PR90, PR100)"); + FM (5, 1, "AMD 5k86 (PR120, PR133)"); + FM (5, 2, "AMD 5k86 (PR166)"); + FM (5, 3, "AMD 5k86 (PR200)"); + F (5, "AMD 5k86 (unknown model)"); + FM (6, 6, "AMD K6, .30um"); + FM (6, 7, "AMD K6 (Little Foot), .25um"); + FMS (6, 8, 0, "AMD K6-2 (Chomper A)"); + FMS (6, 8, 12, "AMD K6-2 (Chomper A)"); + FM (6, 8, "AMD K6-2 (Chomper)"); + FMS (6, 9, 1, "AMD K6-III (Sharptooth B)"); + FM (6, 9, "AMD K6-III (Sharptooth)"); + FM (6, 13, "AMD K6-2+, K6-III+"); + F (6, "AMD K6 (unknown model)"); + FM (7, 1, "AMD Athlon, .25um"); + FM (7, 2, "AMD Athlon (K75 / Pluto / Orion), .18um"); + FMS (7, 3, 0, "AMD Duron / mobile Duron (Spitfire A0)"); + FMS (7, 3, 1, "AMD Duron / mobile Duron (Spitfire A2)"); + FM (7, 3, "AMD Duron / mobile Duron (Spitfire)"); + FMS (7, 4, 2, "AMD Athlon (Thunderbird A4-A7)"); + FMS (7, 4, 4, "AMD Athlon (Thunderbird A9)"); + FM (7, 4, "AMD Athlon (Thunderbird)"); + FMS (7, 6, 0, "AMD Athlon / Athlon MP mobile Athlon 4 / mobile Duron (Palomino A0)"); + FMS (7, 6, 1, "AMD Athlon / Athlon MP / Duron / mobile Athlon / mobile Duron (Palomino A2)"); + FMS (7, 6, 2, "AMD Athlon MP / Athlon XP / Duron / Duron MP / mobile Athlon / mobile Duron (Palomino A5)"); + FM (7, 6, "AMD Athlon / Athlon MP / Athlon XP / Duron / Duron MP / mobile Athlon / mobile Duron (Palomino)"); + FMS (7, 7, 0, "AMD Duron / Duron MP / mobile Duron (Morgan A0)"); + FMS (7, 7, 1, "AMD Duron / Duron MP / mobile Duron (Morgan A1)"); + FM (7, 7, "AMD Duron / Duron MP / mobile Duron (Morgan)"); + FMS (7, 8, 0, "AMD Athlon XP / Athlon MP / Sempron / Duron / Duron MP (Thoroughbred A0)"); + FMS (7, 8, 1, "AMD Athlon XP / Athlon MP / Sempron / Duron / Duron MP (Thoroughbred B0)"); + FM (7, 8, "AMD Athlon XP / Athlon MP / Sempron / Duron / Duron MP (Thoroughbred)"); + FMS (7, 10, 0, "AMD Athlon XP / Athlon MP / Sempron / mobile Athlon XP-M / mobile Athlon XP-M (LV) (Barton A2)"); + FM (7, 10, "AMD Athlon XP / Athlon MP / Sempron / mobile Athlon XP-M / mobile Athlon XP-M (LV) (Barton)"); + F (7, "AMD Athlon XP / Athlon MP / Sempron / Duron / Duron MP / mobile Athlon / mobile Athlon XP-M / mobile Athlon XP-M (LV) / mobile Duron (unknown model)"); + XFXMS(0, 0, 4, 0, "AMD Athlon 64 (SledgeHammer SH7-B0), .13um"); + XFXMS(0, 0, 4, 8, "AMD Athlon 64 (SledgeHammer SH7-C0) / mobile Athlon 64 (SledgeHammer SH7-C0) / mobile Athlon XP-M (SledgeHammer SH7-C0), 754-pin, .13um"); + XFXMS(0, 0, 4, 10, "AMD Athlon 64 (SledgeHammer SH7-CG) / mobile Athlon 64 (SledgeHammer SH7-CG) / mobile Athlon XP-M (SledgeHammer SH7-CG), 940-pin, .13um"); + XFXM (0, 0, 4, "AMD Athlon 64 (SledgeHammer SH7) / mobile Athlon 64 (SledgeHammer SH7) / mobile Athlon XP-M (SledgeHammer SH7), .13um"); + XFXMS(0, 0, 5, 0, "AMD Opteron (DP SledgeHammer SH7-B0), 940-pin, .13um"); + XFXMS(0, 0, 5, 1, "AMD Opteron (DP SledgeHammer SH7-B3), 940-pin, .13um"); + XFXMS(0, 0, 5, 8, "AMD Opteron (DP SledgeHammer SH7-C0) / Athlon 64 FX (DP SledgeHammer SH7-C0), 940-pin, .13um"); + XFXMS(0, 0, 5, 10, "AMD Opteron (DP SledgeHammer SH7-CG) / Athlon 64 FX (DP SledgeHammer SH7-CG), 940-pin, .13um"); + XFXM (0, 0, 5, "AMD Opteron (SledgeHammer SH7) / Athlon 64 (SledgeHammer SH7) FX, 940-pin, .13um"); + XFXMS(0, 0, 7, 10, "AMD Athlon 64 (DP SledgeHammer SH7-CG) / Athlon 64 FX (DP SledgeHammer SH7-CG), 939-pin, .13um"); + XFXM (0, 0, 7, "AMD Athlon 64 (DP SledgeHammer SH7) / Athlon 64 FX (DP SledgeHammer SH7), 939-pin, .13um"); + XFXMS(0, 0, 8, 2, "AMD Athlon 64 (ClawHammer CH7-CG) / mobile Athlon 64 (Odessa CH7-CG) / mobile Sempron (ClawHammer CH7-CG) / mobile Athlon XP-M (ClawHammer CH7-CG), 754-pin, .13um"); + XFXM (0, 0, 8, "AMD Athlon 64 (ClawHammer CH7) / mobile Athlon 64 (Odessa CH7) / mobile Sempron (Odessa CH7) / mobile Athlon XP-M (Odessa CH7), 754-pin, .13um"); + XFXMS(0, 0, 11, 2, "AMD Athlon 64 (ClawHammer CH7-CG), 939-pin, .13um"); + XFXM (0, 0, 11, "AMD Athlon 64 (ClawHammer CH7), 939-pin, .13um"); + XFXMS(0, 0, 12, 0, "AMD Athlon 64 (NewCastle DH7-CG) / Sempron (Paris DH7-CG) / mobile Athlon 64 (Dublin DH7-CG) / mobile Sempron (Sonora DH7-CG) / mobile Athlon XP-M (Dublin DH7-CG), 754-pin, .13um"); + XFXM (0, 0, 12, "AMD Athlon 64 (NewCastle DH7) / Sempron (Paris DH7) / mobile Athlon 64 (Dublin DH7) / mobile Sempron (Sonora DH7) / mobile Athlon XP-M (Dublin DH7), 754-pin, .13um"); + XFXMS(0, 0, 14, 0, "AMD Athlon 64 (NewCastle DH7-CG) / Sempron (Paris DH7-CG) / mobile Athlon 64 (Dublin DH7-CG) / mobile Sempron (Sonora DH7-CG) / mobile Athlon XP-M (Dublin DH7-CG), 754-pin, .13um"); + XFXM (0, 0, 14, "AMD Athlon 64 (NewCastle DH7) / Sempron (Paris DH7) / mobile Athlon 64 (Dublin DH7) / mobile Sempron (Sonora DH7) / mobile Athlon XP-M (Dublin DH7), 754-pin, .13um"); + XFXMS(0, 0, 15, 0, "AMD Athlon 64 (NewCastle DH7-CG) / Sempron (Paris DH7-CG) / mobile Athlon 64 (Dublin DH7-CG), 939-pin, .13um"); + XFXM (0, 0, 15, "AMD Athlon 64 (NewCastle DH7) / Sempron (Paris DH7) / mobile Athlon 64 (Dublin DH7), 939-pin, .13um"); + XFXMS(0, 1, 4, 0, "AMD Athlon 64 (Winchester SH7-D0) / mobile Athlon 64 (Oakville SH7-D0) / mobile Athlon XP-M (Oakville SH7-D0), 754-pin, 90nm"); + XFXM (0, 1, 4, "AMD Athlon 64 (Winchester SH7) / mobile Athlon 64 (Winchester SH7) / mobile Athlon XP-M (Winchester SH7), 754-pin, 90nm"); + XFXMS(0, 1, 5, 0, "AMD Opteron (Winchester SH7-D0) / Athlon 64 FX (Winchester SH7-D0), 940-pin, 90nm"); + XFXM (0, 1, 5, "AMD Opteron (Winchester SH7) / Athlon 64 FX (Winchester SH7), 940-pin, 90nm"); + XFXMS(0, 1, 7, 0, "AMD Athlon 64 (Winchester SH7-D0) / Athlon 64 FX (Winchester SH7-D0), 939-pin, 90nm"); + XFXM (0, 1, 7, "AMD Athlon 64 (Winchester SH7) / Athlon 64 FX (Winchester SH7), 939-pin, 90nm"); + XFXMS(0, 1, 8, 0, "AMD Athlon 64 (Winchester CH-D0) / mobile Athlon 64 (Oakville CH-D0) / mobile Sempron (Palermo CH-D0) / mobile Athlon XP-M (Oakville CH-D0), 754-pin, 90nm"); + XFXM (0, 1, 8, "AMD Athlon 64 (Winchester CH) / mobile Athlon 64 (Winchester CH) / mobile Sempron (Palermo CH) / mobile Athlon XP-M (Winchester CH), 754-pin, 90nm"); + XFXMS(0, 1, 11, 0, "AMD Athlon 64 (Winchester CH-D0), 939-pin, 90nm"); + XFXM (0, 1, 11, "AMD Athlon 64 (Winchester CH), 939-pin, 90nm"); + XFXMS(0, 1, 12, 0, "AMD Athlon 64 (Winchester DH8-D0) / Sempron (Palermo DH8-D0) / mobile Athlon 64 (Oakville DH8-D0) / mobile Sempron (Palermo DH8-D0) / mobile Athlon XP-M (Winchester DH8-D0), 754-pin, 90nm"); + XFXM (0, 1, 12, "AMD Athlon 64 (Winchester DH8) / Sempron (Palermo DH8) / mobile Athlon 64 (Winchester DH8) / mobile Sempron (Palermo DH8) / mobile Athlon XP-M (Winchester DH8), 754-pin, 90nm"); + XFXMS(0, 1, 15, 0, "AMD Athlon 64 (Winchester DH8-D0) / Sempron (Palermo DH8-D0), 939-pin, 90nm"); + XFXM (0, 1, 15, "AMD Athlon 64 (Winchester DH8) / Sempron (Palermo DH8), 939-pin, 90nm"); + XFXMS(0, 2, 1, 0, "AMD Dual Core Opteron (Italy/Egypt JH-E1), 940-pin, 90nm"); + XFXMS(0, 2, 1, 2, "AMD Dual Core Opteron (Italy/Egypt JH-E6), 940-pin, 90nm"); + XFXM (0, 2, 1, "AMD Dual Core Opteron (Italy/Egypt JH), 940-pin, 90nm"); + XFXMS(0, 2, 3, 2, "AMD Dual Core Opteron (Denmark JH-E6) / Athlon 64 X2 (Toledo JH-E6 / Manchester JH-E6), 939-pin, 90nm"); + XFXM (0, 2, 3, "AMD Dual Core Opteron (Denmark JH) / Athlon 64 X2 (Toledo JH / Manchester JH), 939-pin, 90nm"); + XFXMS(0, 2, 4, 2, "AMD mobile Athlon 64 (Newark SH-E5) / mobile Turion (Lancaster SH-E5), 754-pin, 90nm"); + XFXM (0, 2, 4, "AMD mobile Athlon 64 (Newark SH) / mobile Turion (Lancaster SH), 754-pin, 90nm"); + XFXM (0, 2, 5, "AMD Opteron (Troy/Athens SH-E4), 940-pin, 90nm"); + XFXMS(0, 2, 7, 1, "AMD Opteron (Troy/Athens SH-E4) / Opteron (Venus SH-E4) / Athlon 64 (San Diego SH-E4) / Athlon 64 FX (San Diego SH-E4), 939-pin, 90nm"); + XFXM (0, 2, 7, "AMD Opteron (San Diego SH) / Athlon 64 (San Diego SH) / Athlon 64 FX (San Diego SH), 939-pin, 90nm"); + XFXM (0, 2, 11, "AMD Athlon 64 X2 (Manchester BH-E4), 939-pin, 90nm"); + XFXMS(0, 2, 12, 0, "AMD Sempron (Palermo DH-E3), 754-pin, 90nm"); + XFXMS(0, 2, 12, 2, "AMD Sempron (Venice DH-E6) / mobile Sempron (Palermo DH-E6), 754-pin, 90nm"); + XFXM (0, 2, 12, "AMD Sempron (Venice DH) / mobile Sempron (Palermo DH), 754-pin, 90nm"); + XFXMS(0, 2, 15, 0, "AMD Athlon 64 (Venice DH-E3) / Sempron (Palermo DH-E3), 939-pin, 90nm"); + XFXMS(0, 2, 15, 2, "AMD Athlon 64 (Toledo DH-E6) / Sempron (Palermo DH-E6), 939-pin, 90nm"); + XFXM (0, 2, 15, "AMD Athlon 64 (Toledo DH) / Sempron (Palermo DH), 939-pin, 90nm"); + XF (0, "AMD Opteron / Athlon 64 / Sempron / Turion / Athlon 64 FX / Athlon XP-M / mobile Athlon 64 / mobile Sempron / mobile Athlon XP-M (unknown)"); + DEFAULT ("unknown"); + printf("\n"); +} + +static void +print_x_synth_via(unsigned int val) +{ + printf(" (simple synth) = "); + START; + FM (6, 6, "VIA C3 (WinChip C5A)"); + FM (6, 6, "VIA C3 (WinChip C5A)"); + FMS(6, 7, 0, "VIA C3 (WinChip C5B)"); + FMS(6, 7, 1, "VIA C3 (WinChip C5B)"); + FMS(6, 7, 2, "VIA C3 (WinChip C5B)"); + FMS(6, 7, 3, "VIA C3 (WinChip C5B)"); + FMS(6, 7, 4, "VIA C3 (WinChip C5B)"); + FMS(6, 7, 5, "VIA C3 (WinChip C5B)"); + FMS(6, 7, 6, "VIA C3 (WinChip C5B)"); + FMS(6, 7, 7, "VIA C3 (WinChip C5B)"); + FM (6, 7, "VIA C3 (WinChip C5C)"); + FM (6, 8, "VIA C3 (WinChip C5N)"); + FM (6, 9, "VIA C3 (WinChip C5XL)"); + F (6, "VIA C3 (unknown model)"); + DEFAULT ("unknown"); + printf("\n"); +} + +static void +print_synth_simple(unsigned int val_eax, + vendor_t vendor) +{ + switch (vendor) { + case VENDOR_INTEL: + print_synth_intel(" (simple synth) = ", val_eax, UN); + break; + case VENDOR_AMD: + print_synth_amd(" (simple synth) = ", val_eax, UN, NULL); + break; + case VENDOR_CYRIX: + print_synth_cyrix(" (simple synth) = ", val_eax); + break; + case VENDOR_VIA: + print_synth_via(" (simple synth) = ", val_eax); + break; + case VENDOR_TRANSMETA: + print_synth_transmeta(" (simple synth) = ", val_eax, UN); + break; + case VENDOR_UMC: + print_synth_umc(" (simple synth) = ", val_eax); + break; + case VENDOR_NEXGEN: + print_synth_nexgen(" (simple synth) = ", val_eax); + break; + case VENDOR_RISE: + print_synth_rise(" (simple synth) = ", val_eax); + break; + case VENDOR_UNKNOWN: + /* DO NOTHING */ + break; + } +} + +static void +print_synth(const code_stash_t* stash) +{ + code_t cd = decode(stash); + + switch (stash->vendor) { + case VENDOR_INTEL: + print_synth_intel(" (synth) = ", stash->val_1_eax, cd); + break; + case VENDOR_AMD: + print_synth_amd(" (synth) = ", stash->val_1_eax, cd, stash); + break; + case VENDOR_CYRIX: + print_synth_cyrix(" (synth) = ", stash->val_1_eax); + break; + case VENDOR_VIA: + print_synth_via(" (synth) = ", stash->val_1_eax); + break; + case VENDOR_TRANSMETA: + print_synth_transmeta(" (simple synth) = ", stash->val_1_eax, cd); + break; + case VENDOR_UMC: + print_synth_umc(" (simple synth) = ", stash->val_1_eax); + break; + case VENDOR_NEXGEN: + print_synth_nexgen(" (simple synth) = ", stash->val_1_eax); + break; + case VENDOR_RISE: + print_synth_rise(" (simple synth) = ", stash->val_1_eax); + break; + case VENDOR_UNKNOWN: + /* DO NOTHING */ + break; + } +} + +#define GET_LogicalProcessorCount(val_1_ebx) \ + (BIT_EXTRACT_LE((val_1_ebx), 16, 24)) +#define IS_HTT(val_1_edx) \ + (BIT_EXTRACT_LE((val_1_edx), 28, 29)) +#define IS_CmpLegacy(val_80000001_ecx) \ + (BIT_EXTRACT_LE((val_80000001_ecx), 1, 2)) +#define GET_NC_INTEL(val_4_eax) \ + (BIT_EXTRACT_LE((val_4_eax), 26, 32)) +#define GET_NC_AMD(val_80000008_ecx) \ + (BIT_EXTRACT_LE((val_80000008_ecx), 0, 8)) + +static void decode_mp_synth(code_stash_t* stash) +{ + /* + ** This logic based on the AMD CPUID Specification (25481). + ** NOTE: The AMD CPUID documentation says that c always will be 0 + ** on a single-core machine. But Intel doesn't follow that + ** convention and uses 1 for a single-core machine. So, cope. + */ + if (IS_HTT(stash->val_1_edx)) { + unsigned int tc = GET_LogicalProcessorCount(stash->val_1_ebx); + unsigned int c; + switch (stash->vendor) { + case VENDOR_INTEL: + c = GET_NC_INTEL(stash->val_4_eax) + 1; + stash->mp.ok = TRUE; + break; + case VENDOR_AMD: + c = GET_NC_AMD(stash->val_80000008_ecx) + 1; + stash->mp.ok = (tc == c) == IS_CmpLegacy(stash->val_80000001_ecx); + break; + default: + c = 0; + stash->mp.ok = FALSE; + break; + } + if (!stash->mp.ok) { + stash->mp.cores = -1; + stash->mp.hyperthreads = -1; + // DO NOTHING + } else if (c > 1) { + if (tc == c) { + stash->mp.cores = c; + stash->mp.hyperthreads = 1; + } else { + stash->mp.cores = c; + stash->mp.hyperthreads = tc / c; + } + } else { + stash->mp.cores = 1; + stash->mp.hyperthreads = (tc >= 2 ? tc : 2); + } + } else { + stash->mp.ok = TRUE; + stash->mp.cores = 1; + stash->mp.hyperthreads = 1; + } +} + +static void print_mp_synth(const struct mp* mp) +{ + printf(" (multi-processing synth): "); + if (!mp->ok) { + printf("?"); + } else if (mp->cores > 1) { + if (mp->hyperthreads > 1) { + printf("multi-core (c=%u), hyper-threaded (t=%u)", + mp->cores, mp->hyperthreads); + } else { + printf("multi-core (c=%u)", mp->cores); + } + } else if (mp->hyperthreads > 1) { + printf("hyper-threaded (t=%u)", mp->hyperthreads); + } else { + printf("none"); + } + printf("\n"); +} + +static void +print_1_eax(unsigned int value, + vendor_t vendor) +{ + static ccstring processor[] = { "primary processor (0)", + "Intel OverDrive (1)", + "secondary processor (2)", + NULL }; + static ccstring family[] = { NULL, + NULL, + NULL, + "Intel 80386 (3)", + "Intel 80486, AMD Am486, UMC 486 U5 (4)", + "Intel Pentium, AMD K5/K6," + " Cyrix M1, NexGen Nx586," + " Centaur C6, Rise mP6," + " Transmeta Crusoe (5)", + "Intel Pentium Pro/II/III/Celeron," + " AMD Athlon/Duron, Cyrix M2," + " VIA C3 (6)", + "Intel Itanium," + " AMD Athlon 64/Opteron/Sempron/Turion" + " (7)", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "Intel Pentium 4/Pentium D/" + "Pentium Extreme Edition/Celeron/Xeon/" + "Xeon MP/Itanium2," + " AMD Athlon 64/Athlon XP-M/Opteron/" + "Sempron/Turion (15)" }; + static named_item names[] + = { { "processor type" , 12, 13, processor }, + { "family" , 8, 11, family }, + { "model" , 4, 7, NIL_IMAGES }, + { "stepping id" , 0, 3, NIL_IMAGES }, + { "extended family" , 20, 27, NIL_IMAGES }, + { "extended model" , 16, 19, NIL_IMAGES }, + }; + + printf(" version information (1/eax):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); + + print_synth_simple(value, vendor); +} + +#define B(b,str) \ + else if ( __B(val_ebx) == _B(b)) \ + printf(str) +#define FMB(f,m,b,str) \ + else if ( __FM(val_eax) == _F(f) +_M(m) \ + && __B(val_ebx) == _B(b)) \ + printf(str) +#define FMSB(f,m,s,b,str) \ + else if ( __FMS(val_eax) == _F(f) +_M(m)+_S(s) \ + && __B(val_ebx) == _B(b)) \ + printf(str) +#define XFMB(xf,m,b,str) \ + else if ( __XFM(val_eax) == _XF(xf)+_F(15)+_M(m) \ + && __B(val_ebx) == _B(b)) \ + printf(str) +#define XFMSB(xf,m,s,b,str) \ + else if ( __XFMS(val_eax) == _XF(xf)+_F(15)+_M(m)+_S(s) \ + && __B(val_ebx) == _B(b)) \ + printf(str) + +static void +print_brand(unsigned int val_eax, + unsigned int val_ebx) +{ + printf(" brand id = 0x%02x (%u): ", __B(val_ebx), __B(val_ebx)); + START; + B ( 1, "Intel Celeron, .18um"); + B ( 2, "Intel Pentium III, .18um"); + FMSB (6, 11, 1, 3, "Intel Celeron, .13um"); + B ( 3, "Intel Pentium III Xeon, .18um"); + B ( 4, "Intel Pentium III, .13um"); + B ( 6, "Mobile Intel Pentium III, .13um"); + B ( 7, "Mobile Intel Celeron, .13um"); + XFMB (0, 0, 8, "Intel Pentium 4, .18um"); + XFMSB(0, 1, 0, 8, "Intel Pentium 4, .18um"); + XFMSB(0, 1, 1, 8, "Intel Pentium 4, .18um"); + XFMSB(0, 1, 2, 8, "Intel Pentium 4, .18um"); + B ( 8, "Mobile Intel Celeron 4, .13um"); + B ( 9, "Intel Pentium 4, .13um"); + B ( 10, "Intel Celeron 4, .18um"); + XFMB (0, 0, 11, "Intel Xeon MP, .18um"); + XFMSB(0, 1, 0, 11, "Intel Xeon MP, .18um"); + XFMSB(0, 1, 1, 11, "Intel Xeon MP, .18um"); + XFMSB(0, 1, 2, 11, "Intel Xeon MP, .18um"); + B ( 11, "Intel Xeon, .13um"); + B ( 12, "Intel Xeon MP, .13um"); + XFMB (0, 0, 14, "Intel Xeon, .18um"); + XFMSB(0, 1, 0, 14, "Intel Xeon, .18um"); + XFMSB(0, 1, 1, 14, "Intel Xeon, .18um"); + XFMSB(0, 1, 2, 14, "Intel Xeon, .18um"); + XFMB (0, 2, 14, "Mobile Intel Pentium 4 Processor-M"); + B ( 14, "Mobile Intel Xeon, .13um"); + XFMB (0, 2, 15, "Mobile Intel Pentium 4 Processor-M"); + B ( 15, "Mobile Intel Celeron 4"); + B ( 17, "Mobile Genuine Intel"); + B ( 18, "Intel Celeron M"); + B ( 19, "Mobile Intel Celeron"); + B ( 20, "Intel Celeron"); + B ( 21, "Mobile Genuine Intel"); + B ( 22, "Intel Pentium M, .13um"); + B ( 23, "Mobile Intel Celeron"); + DEFAULT ("unknown"); + printf("\n"); +} + +static void +print_1_ebx(unsigned int value) +{ + static named_item names[] + = { { "process local APIC physical ID" , 24, 31, NIL_IMAGES }, + { "cpu count" , 16, 23, NIL_IMAGES }, + { "CLFLUSH line size" , 8, 15, NIL_IMAGES }, + { "brand index" , 0, 7, NIL_IMAGES }, + }; + + printf(" miscellaneous (1/ebx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_1_ecx(unsigned int value) +{ + static named_item names[] + = { { "PNI/SSE3: Prescott New Instructions" , 0, 0, bools }, + { "MONITOR/MWAIT" , 3, 3, bools }, + { "CPL-qualified debug store" , 4, 4, bools }, + { "VMX: virtual machine extensions" , 5, 5, bools }, + { "Enhanced Intel SpeedStep Technology" , 7, 7, bools }, + { "thermal monitor 2" , 8, 8, bools }, + { "context ID: adaptive or shared L1 data" , 10, 10, bools }, + { "cmpxchg16b available" , 13, 13, bools }, + { "xTPR disable" , 14, 14, bools }, + }; + + printf(" feature information (1/ecx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_1_edx(unsigned int value) +{ + static named_item names[] + = { { "x87 FPU on chip" , 0, 0, bools }, + { "virtual-8086 mode enhancement" , 1, 1, bools }, + { "debugging extensions" , 2, 2, bools }, + { "page size extensions" , 3, 3, bools }, + { "time stamp counter" , 4, 4, bools }, + { "RDMSR and WRMSR support" , 5, 5, bools }, + { "physical address extensions" , 6, 6, bools }, + { "machine check exception" , 7, 7, bools }, + { "CMPXCHG8B inst." , 8, 8, bools }, + { "APIC on chip" , 9, 9, bools }, + { "SYSENTER and SYSEXIT" , 11, 11, bools }, + { "memory type range registers" , 12, 12, bools }, + { "PTE global bit" , 13, 13, bools }, + { "machine check architecture" , 14, 14, bools }, + { "conditional move/compare instruction" , 15, 15, bools }, + { "page attribute table" , 16, 16, bools }, + { "page size extension" , 17, 17, bools }, + { "processor serial number" , 18, 18, bools }, + { "CLFLUSH instruction" , 19, 19, bools }, + { "debug store" , 21, 21, bools }, + { "thermal monitor and clock ctrl" , 22, 22, bools }, + { "MMX Technology" , 23, 23, bools }, + { "FXSAVE/FXRSTOR" , 24, 24, bools }, + { "SSE extensions" , 25, 25, bools }, + { "SSE2 extensions" , 26, 26, bools }, + { "self snoop" , 27, 27, bools }, + { "hyper-threading / multi-core supported" , 28, 28, bools }, + { "therm. monitor" , 29, 29, bools }, + { "IA64" , 30, 30, bools }, + { "pending break event" , 31, 31, bools }, + }; + + printf(" feature information (1/edx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void print_2_meaning(unsigned char value, + vendor_t vendor, + unsigned int val_1_eax) +{ + if (vendor == VENDOR_CYRIX || vendor == VENDOR_VIA) { + switch (value) { + case 0x70: printf("TLB: 4k pages, 4-way, 32 entries"); return; + case 0x74: printf("Cyrix-specific: ?"); return; + case 0x77: printf("Cyrix-specific: ?"); return; + case 0x80: printf("L1 cache: 16K, 4-way, 16 byte lines"); return; + case 0x82: printf("Cyrix-specific: ?"); return; + case 0x84: printf("L2 cache: 1M, 8-way, 32 byte lines"); return; + } + } + + switch (value) { + case 0x01: printf("instruction TLB: 4K pages, 4-way, 32 entries"); break; + case 0x02: printf("instruction TLB: 4M pages, 4-way, 2 entries"); break; + case 0x03: printf("data TLB: 4K pages, 4-way, 64 entries"); break; + case 0x04: printf("data TLB: 4M pages, 4-way, 8 entries"); break; + case 0x06: printf("L1 instruction cache: 8K, 4-way, 32 byte lines"); break; + case 0x08: printf("L1 instruction cache: 16K, 4-way, 32 byte lines"); break; + case 0x0a: printf("L1 data cache: 8K, 2-way, 32 byte lines"); break; + case 0x0c: printf("L1 data cache: 16K, 4-way, 32 byte lines"); break; + case 0x10: printf("L1 data cache: 16K, 4-way, 32 byte lines"); break; + case 0x15: printf("L1 instruction cache: 16K, 4-way, 32 byte lines"); break; + case 0x1a: printf("L2 cache: 96K, 6-way, 64 byte lines"); break; + case 0x22: printf("L3 cache: 512K, 4-way, 64 byte lines"); break; + case 0x23: printf("L3 cache: 1M, 8-way, 64 byte lines"); break; + case 0x25: printf("L3 cache: 2M, 8-way, 64 byte lines"); break; + case 0x29: printf("L3 cache: 4M, 8-way, 64 byte lines"); break; + case 0x2c: printf("L1 data cache: 32K, 8-way, 64 byte lines"); break; + case 0x30: printf("L1 cache: 32K, 8-way, 64 byte lines"); break; + case 0x39: printf("L2 cache: 128K, 4-way, sectored, 64 byte lines"); break; + case 0x3a: printf("L2 cache: 192K, 6-way, sectored, 64 byte lines"); break; + case 0x3b: printf("L2 cache: 128K, 2-way, sectored, 64 byte lines"); break; + case 0x3c: printf("L2 cache: 256K, 4-way, sectored, 64 byte lines"); break; + case 0x3d: printf("L2 cache: 384K, 6-way, sectored, 64 byte lines"); break; + case 0x3e: printf("L2 cache: 512K, 4-way, sectored, 64 byte lines"); break; + case 0x40: if (__F(val_1_eax) <= _F(6)) { + printf("No L2 cache"); + } else { + printf("No L3 cache"); + } + break; + case 0x41: printf("L2 cache: 128K, 4-way, 32 byte lines"); break; + case 0x42: printf("L2 cache: 256K, 4-way, 32 byte lines"); break; + case 0x43: printf("L2 cache: 512K, 4-way, 32 byte lines"); break; + case 0x44: printf("L2 cache: 1M, 4-way, 32 byte lines"); break; + case 0x45: printf("L2 cache: 2M, 4-way, 32 byte lines"); break; + case 0x46: printf("L3 cache: 4M, 4-way, 64 byte lines"); break; + case 0x47: printf("L3 cache: 8M, 8-way, 64 byte lines"); break; + case 0x49: printf("L3 cache: 4M, 16-way, 64 byte lines"); break; + case 0x4a: printf("L3 cache: 6M, 12-way, 64 byte lines"); break; + case 0x4b: printf("L3 cache: 8M, 16-way, 64 byte lines"); break; + case 0x4c: printf("L3 cache: 12M, 12-way, 64 byte lines"); break; + case 0x4d: printf("L3 cache: 16M, 16-way, 64 byte lines"); break; + case 0x50: printf("instruction TLB: 4K & 2M/4M pages, 64 entries"); break; + case 0x51: printf("instruction TLB: 4K & 2M/4M pages, 128 entries"); break; + case 0x52: printf("instruction TLB: 4K & 2M/4M pages, 256 entries"); break; + case 0x5b: printf("data TLB: 4K & 4M pages, 64 entries"); break; + case 0x5c: printf("data TLB: 4K & 4M pages, 128 entries"); break; + case 0x5d: printf("data TLB: 4K & 4M pages, 256 entries"); break; + case 0x60: printf("L1 data cache: 16K, 8-way, 64 byte lines"); break; + case 0x66: printf("L1 data cache: 8K, 4-way, 64 byte lines"); break; + case 0x67: printf("L1 data cache: 16K, 4-way, 64 byte lines"); break; + case 0x68: printf("L1 data cache: 32K, 4-way, 64 byte lines"); break; + case 0x70: printf("Trace cache: 12K-uop, 8-way"); break; + case 0x71: printf("Trace cache: 16K-uop, 8-way"); break; + case 0x72: printf("Trace cache: 32K-uop, 8-way"); break; + case 0x73: printf("Trace cache: 64K-uop, 8-way"); break; + case 0x77: printf("L1 instruction cache: 16K, 4-way, sectored," + " 64 byte lines"); break; + case 0x78: printf("L2 cache: 1M, 4-way, 64 byte lines"); break; + case 0x79: printf("L2 cache: 128K, 8-way, sectored, 64 byte lines"); break; + case 0x7a: printf("L2 cache: 256K, 8-way, sectored, 64 byte lines"); break; + case 0x7b: printf("L2 cache: 512K, 8-way, sectored, 64 byte lines"); break; + case 0x7c: printf("L2 cache: 1M, 8-way, sectored, 64 byte lines"); break; + case 0x7d: printf("L2 cache: 2M, 8-way, sectored, 64 byte lines"); break; + case 0x7e: printf("L2 cache: 256K, 8-way, sectored, 128 byte lines"); break; + case 0x7f: printf("L2 cache: 512K, 2-way, 64 byte lines"); break; + case 0x81: printf("L2 cache: 128K, 8-way, 32 byte lines"); break; + case 0x82: printf("L2 cache: 256K, 8-way, 32 byte lines"); break; + case 0x83: printf("L2 cache: 512K, 8-way, 32 byte lines"); break; + case 0x84: printf("L2 cache: 1M, 8-way, 32 byte lines"); break; + case 0x85: printf("L2 cache: 2M, 8-way, 32 byte lines"); break; + case 0x86: printf("L2 cache: 512K, 4-way, 64 byte lines"); break; + case 0x87: printf("L2 cache: 1M, 8-way, 64 byte lines"); break; + case 0x88: printf("L3 cache: 2M, 4-way, 64 byte lines"); break; + case 0x89: printf("L3 cache: 4M, 4-way, 64 byte lines"); break; + case 0x8a: printf("L3 cache: 8M, 4-way, 64 byte lines"); break; + case 0x8d: printf("L3 cache: 3M, 12-way, 128 byte lines"); break; + case 0x90: printf("instruction TLB: 4K-256M, fully, 64 entries"); break; + case 0x96: printf("instruction TLB: 4K-256M, fully, 32 entries"); break; + case 0x9b: printf("instruction TLB: 4K-256M, fully, 96 entries"); break; + case 0xb0: printf("instruction TLB: 4K, 4-way, 128 entries"); break; + case 0xb3: printf("data TLB: 4K, 4-way, 128 entries"); break; + case 0xf0: printf("64 byte prefetching"); break; + case 0xf1: printf("128 byte prefetching"); break; + default: printf("unknown"); break; + } +} + +static void print_2_byte(unsigned char value, + vendor_t vendor, + unsigned int val_1_eax) +{ + if (value == 0x00) return; + + printf(" 0x%02x: ", value); + print_2_meaning(value, vendor, val_1_eax); + printf("\n"); +} + +static void +print_4_eax(unsigned int value) +{ + static ccstring cache_type[] = { "no more caches (0)", + "data cache (1)", + "instruction cache (2)", + "unified cache (3)" }; + static named_item names[] + = { { "cache type" , 0, 4, cache_type }, + { "cache level" , 5, 7, NIL_IMAGES }, + { "self-initializing cache level" , 8, 8, bools }, + { "fully associative cache" , 9, 9, bools }, + { "extra threads sharing this cache" , 14, 25, NIL_IMAGES }, + { "extra processor cores on this die" , 26, 31, NIL_IMAGES }, + }; + + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 33); +} + +static void +print_4_ebx(unsigned int value) +{ + static named_item names[] + = { { "system coherency line size" , 0, 11, NIL_IMAGES }, + { "physical line partitions" , 12, 21, NIL_IMAGES }, + { "ways of associativity" , 22, 31, NIL_IMAGES }, + }; + + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 33); +} + +static void +print_5_eax(unsigned int value) +{ + static named_item names[] + = { { "smallest monitor-line size (bytes)" , 0, 15, NIL_IMAGES }, + }; + + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 39); +} + +static void +print_5_ebx(unsigned int value) +{ + static named_item names[] + = { { "largest monitor-line size (bytes)" , 0, 15, NIL_IMAGES }, + }; + + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 39); +} + +static void +print_5_ecx(unsigned int value) +{ + static named_item names[] + = { { "enum of Monitor-MWAIT exts supported" , 0, 0, bools }, + { "supports intrs as break-event for MWAIT" , 1, 1, bools }, + }; + + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 39); +} + +static void +print_5_edx(unsigned int value) +{ + static named_item names[] + = { { "number of C0 sub C-states using MWAIT" , 0, 3, NIL_IMAGES }, + { "number of C1 sub C-states using MWAIT" , 4, 7, NIL_IMAGES }, + { "number of C2 sub C-states using MWAIT" , 8, 11, NIL_IMAGES }, + { "number of C3 sub C-states using MWAIT" , 12, 15, NIL_IMAGES }, + { "number of C4 sub C-states using MWAIT" , 16, 19, NIL_IMAGES }, + }; + + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 39); +} + +static void +print_6_eax(unsigned int value) +{ + static named_item names[] + = { { "digital thermometer" , 0, 0, bools }, + { "operating point protection" , 2, 2, bools }, + }; + + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 39); +} + +static void +print_6_ebx(unsigned int value) +{ + static named_item names[] + = { { "digital thermometer thresholds" , 0, 3, NIL_IMAGES }, + }; + + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 39); +} + +static void +print_6_ecx(unsigned int value) +{ + static named_item names[] + = { { "ACNT/MCNT supported performance measure" , 0, 0, bools }, + }; + + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 39); +} + +static void +print_a_eax(unsigned int value) +{ + static named_item names[] + = { { "version ID" , 0, 7, NIL_IMAGES }, + { "number of counters per logical processor", 8, 15, NIL_IMAGES }, + { "bit width of counter" , 16, 23, NIL_IMAGES }, + { "length of EBX bit vector" , 24, 31, NIL_IMAGES }, + }; + + printf(" Architecture Performance Monitoring Features (0xa/eax):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_a_ebx(unsigned int value) +{ + static named_item names[] + = { { "core cycle event not available" , 0, 0, bools }, + { "instruction retired event not available" , 1, 1, bools }, + { "reference cycles event not available" , 2, 2, bools }, + { "last-level cache ref event not available", 3, 3, bools }, + { "last-level cache miss event not avail" , 4, 4, bools }, + { "branch inst retired event not available" , 5, 5, bools }, + { "branch mispred retired event not avail" , 6, 6, bools }, + }; + + printf(" Architecture Performance Monitoring Features (0xa/ebx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000001_eax_amd(unsigned int value) +{ + static ccstring family[] = { NULL, + NULL, + NULL, + NULL, + "AMD Am486 (4)", + "AMD K5 (5)", + "AMD K6 (6)", + "AMD Athlon/Duron (7)", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "AMD Athlon 64/Opteron/Sempron/Turion (15)" }; + static named_item names[] + = { { "generation " , 8, 11, family }, + { "model " , 4, 7, NIL_IMAGES }, + { "stepping " , 0, 3, NIL_IMAGES }, + }; + + printf(" extended processor signature (0x80000001/eax):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); + + print_x_synth_amd(value); +} + +static void +print_80000001_eax_via(unsigned int value) +{ + static ccstring family[] = { NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "VIA C3" }; + static named_item names[] + = { { "generation " , 8, 11, family }, + { "model " , 4, 7, NIL_IMAGES }, + { "stepping " , 0, 3, NIL_IMAGES }, + }; + + printf(" extended processor signature (0x80000001/eax):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); + + print_x_synth_via(value); +} + +static void +print_80000001_eax_transmeta(unsigned int value) +{ + static ccstring family[] = { NULL, + NULL, + NULL, + NULL, + NULL, + "Transmeta Crusoe" }; + static named_item names[] + = { { "generation " , 8, 11, family }, + { "model " , 4, 7, NIL_IMAGES }, + { "stepping " , 0, 3, NIL_IMAGES }, + }; + + printf(" extended processor signature (0x80000001/eax):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); + + print_synth_transmeta(" (simple synth)", value, UN); +} + +static void +print_80000001_eax(unsigned int value, + vendor_t vendor) +{ + switch (vendor) { + case VENDOR_AMD: + print_80000001_eax_amd(value); + break; + case VENDOR_VIA: + print_80000001_eax_via(value); + break; + case VENDOR_TRANSMETA: + print_80000001_eax_transmeta(value); + break; + case VENDOR_INTEL: + case VENDOR_CYRIX: + case VENDOR_UMC: + case VENDOR_NEXGEN: + case VENDOR_RISE: + case VENDOR_UNKNOWN: + /* DO NOTHING */ + break; + } +} + +static void +print_80000001_edx_intel(unsigned int value) +{ + static named_item names[] + = { { "SYSCALL and SYSRET instructions" , 11, 11, bools }, + { "execution disable" , 20, 20, bools }, + { "64-bit extensions technology available" , 29, 29, bools }, + }; + + printf(" extended feature flags (0x80000001/edx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000001_edx_amd(unsigned int value) +{ + static named_item names[] + = { { "x87 FPU on chip" , 0, 0, bools }, + { "virtual-8086 mode enhancement" , 1, 1, bools }, + { "debugging extensions" , 2, 2, bools }, + { "page size extensions" , 3, 3, bools }, + { "time stamp counter" , 4, 4, bools }, + { "RDMSR and WRMSR support" , 5, 5, bools }, + { "physical address extensions" , 6, 6, bools }, + { "machine check exception" , 7, 7, bools }, + { "CMPXCHG8B inst." , 8, 8, bools }, + { "APIC on chip" , 9, 9, bools }, + { "SYSCALL and SYSRET instructions" , 11, 11, bools }, + { "memory type range registers" , 12, 12, bools }, + { "global paging extension" , 13, 13, bools }, + { "machine check architecture" , 14, 14, bools }, + { "conditional move/compare instruction" , 15, 15, bools }, + { "page attribute table" , 16, 16, bools }, + { "page size extension" , 17, 17, bools }, + { "multiprocessing capable" , 19, 19, bools }, + { "no-execute page protection" , 20, 20, bools }, + { "AMD multimedia instruction extensions" , 22, 22, bools }, + { "MMX Technology" , 23, 23, bools }, + { "FXSAVE/FXRSTOR" , 24, 24, bools }, + { "SSE extensions" , 25, 25, bools }, + { "RDTSCP" , 27, 27, bools }, + { "long mode (AA-64)" , 29, 29, bools }, + { "3DNow! instruction extensions" , 30, 30, bools }, + { "3DNow! instructions" , 31, 31, bools }, + }; + + printf(" extended feature flags (0x80000001/edx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000001_edx_cyrix_via(unsigned int value) +{ + static named_item names[] + = { { "x87 FPU on chip" , 0, 0, bools }, + { "virtual-8086 mode enhancement" , 1, 1, bools }, + { "debugging extensions" , 2, 2, bools }, + { "page size extensions" , 3, 3, bools }, + { "time stamp counter" , 4, 4, bools }, + { "RDMSR and WRMSR support" , 5, 5, bools }, + { "physical address extensions" , 6, 6, bools }, + { "machine check exception" , 7, 7, bools }, + { "CMPXCHG8B inst." , 8, 8, bools }, + { "APIC on chip" , 9, 9, bools }, + { "SYSCALL and SYSRET instructions" , 11, 11, bools }, + { "memory type range registers" , 12, 12, bools }, + { "global paging extension" , 13, 13, bools }, + { "machine check architecture" , 14, 14, bools }, + { "conditional move/compare instruction" , 15, 15, bools }, + { "page attribute table" , 16, 16, bools }, + { "page size extension" , 17, 17, bools }, + { "multiprocessing capable" , 19, 19, bools }, + { "AMD multimedia instruction extensions" , 22, 22, bools }, + { "MMX Technology" , 23, 23, bools }, + { "extended MMX" , 24, 24, bools }, + { "SSE extensions" , 25, 25, bools }, + { "AA-64" , 29, 29, bools }, + { "3DNow! instruction extensions" , 30, 30, bools }, + { "3DNow! instructions" , 31, 31, bools }, + }; + + printf(" extended feature flags (0x80000001/edx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000001_edx_transmeta(unsigned int value) +{ + static named_item names[] + = { { "x87 FPU on chip" , 0, 0, bools }, + { "virtual-8086 mode enhancement" , 1, 1, bools }, + { "debugging extensions" , 2, 2, bools }, + { "page size extensions" , 3, 3, bools }, + { "time stamp counter" , 4, 4, bools }, + { "RDMSR and WRMSR support" , 5, 5, bools }, + { "CMPXCHG8B inst." , 8, 8, bools }, + { "conditional move/compare instruction" , 15, 15, bools }, + { "FP conditional move instructions" , 16, 16, bools }, + { "MMX Technology" , 23, 23, bools }, + }; + + printf(" extended feature flags (0x80000001/edx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000001_edx(unsigned int value, + vendor_t vendor) +{ + switch (vendor) { + case VENDOR_INTEL: + print_80000001_edx_intel(value); + break; + case VENDOR_AMD: + print_80000001_edx_amd(value); + break; + case VENDOR_CYRIX: + case VENDOR_VIA: + print_80000001_edx_cyrix_via(value); + break; + case VENDOR_TRANSMETA: + print_80000001_edx_transmeta(value); + break; + case VENDOR_UMC: + case VENDOR_NEXGEN: + case VENDOR_RISE: + case VENDOR_UNKNOWN: + /* DO NOTHING */ + break; + } +} + +static void +print_80000001_ecx_amd(unsigned int value) +{ + static named_item names[] + = { { "LAHF/SAHF supported in 64-bit mode" , 0, 0, bools }, + { "CMP Legacy" , 1, 1, bools }, + { "SVM: secure virtual machine" , 2, 2, bools }, + { "AltMovCr8" , 4, 4, bools }, + }; + + printf(" AMD feature flags (0x80000001/ecx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000001_ecx_intel(unsigned int value) +{ + static named_item names[] + = { { "LAHF/SAHF supported in 64-bit mode" , 0, 0, bools }, + }; + + printf(" Intel feature flags (0x80000001/ecx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000001_ecx(unsigned int value, + vendor_t vendor) +{ + switch (vendor) { + case VENDOR_AMD: + print_80000001_ecx_amd(value); + break; + case VENDOR_INTEL: + print_80000001_ecx_intel(value); + break; + case VENDOR_CYRIX: + case VENDOR_VIA: + case VENDOR_TRANSMETA: + case VENDOR_UMC: + case VENDOR_NEXGEN: + case VENDOR_RISE: + case VENDOR_UNKNOWN: + /* DO NOTHING */ + break; + } +} + +static void +print_80000001_ebx_amd(unsigned int value) +{ + static ccstring processor[] = { "reserved (0b000000)", + "reserved (0b000001)", + "reserved (0b000010)", + "reserved (0b000011)", + "UP client (0b000100)", + "reserved (0b000101)", + "reserved (0b000110)", + "reserved (0b000111)", + "mobile client (0b001000)", + "mobile client low-power mobile VIDs" + " (0b001001)", + "reserved (0b001010)", + "reserved (0b001011)", + "UP server (0b001100)", + "reserved (0b001101)", + "UP server low-power 55W (0b001110)", + "UP server low-power 30W (0b001111)", + "2P server (0b010000)", + "reserved (0b010001)", + "2P server low-power 55W (0b010010)", + "2P server low-power 30W (0b010011)", + "MP server (0b010100)", + "reserved (0b010101)", + "MP server low-power 55W (0b010110)", + "MP server low-power 30W (0b010111)", + "reserved (0b011000)", + "reserved (0b011001)", + "reserved (0b011010)", + "reserved (0b011011)", + "reserved (0b011100)", + "mobile client, 32-bit (0b011101)", + "mobile client, 32-bit low-power mobile" + " VIDs (0b011110)", + "reserved (0b011111)", + "desktop/DTR client, 32-bit (0b100000)", + "mobile client, 32-bit (0b100001)", + "desktop/DTR client, 32-bit (0b100010)", + "mobile client, 32-bit, low-power mobile" + " VIDs (0b100011)", + "desktop client (0b100100)", + "reserved (0b100101)", + "reserved (0b100110)", + "reserved (0b100111)", + "reserved (0b101000)", + "reserved (0b101001)", + "reserved (0b101010)", + "reserved (0b101011)", + "reserved (0b101100)", + "reserved (0b101101)", + "reserved (0b101110)", + "reserved (0b101111)", + "reserved (0b110000)", + "reserved (0b110001)", + "reserved (0b110010)", + "reserved (0b110011)", + "reserved (0b110100)", + "reserved (0b110101)", + "reserved (0b110110)", + "reserved (0b110111)", + "reserved (0b111000)", + "reserved (0b111001)", + "reserved (0b111010)", + "reserved (0b111011)", + "reserved (0b111100)", + "reserved (0b111101)", + "reserved (0b111110)", + "reserved (0b111111)" }; + static named_item names[] + = { { "MSB" , 6, 12, processor }, + { "NN" , 0, 6, NIL_IMAGES }, + }; + + printf(" extended brand id = 0x%03x (%u):\n", __XB(value), __XB(value)); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000001_ebx(unsigned int value, + vendor_t vendor) +{ + switch (vendor) { + case VENDOR_AMD: + print_80000001_ebx_amd(value); + break; + case VENDOR_INTEL: + case VENDOR_CYRIX: + case VENDOR_VIA: + case VENDOR_TRANSMETA: + case VENDOR_UMC: + case VENDOR_NEXGEN: + case VENDOR_RISE: + case VENDOR_UNKNOWN: + /* DO NOTHING */ + break; + } +} + +static void +print_80000005_eax(unsigned int value) +{ + static named_item names[] + = { { "instruction # entries" , 0, 7, NIL_IMAGES }, + { "instruction associativity" , 8, 15, NIL_IMAGES }, + { "data # entries" , 16, 23, NIL_IMAGES }, + { "data associativity" , 24, 31, NIL_IMAGES }, + }; + + printf(" L1 TLB/cache information: 2M/4M pages & L1 TLB" + " (0x80000005/eax):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000005_ebx(unsigned int value) +{ + static named_item names[] + = { { "instruction # entries" , 0, 7, NIL_IMAGES }, + { "instruction associativity" , 8, 15, NIL_IMAGES }, + { "data # entries" , 16, 23, NIL_IMAGES }, + { "data associativity" , 24, 31, NIL_IMAGES }, + }; + + printf(" L1 TLB/cache information: 4K pages & L1 TLB" + " (0x80000005/ebx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000005_ecx(unsigned int value) +{ + static named_item names[] + = { { "line size (bytes)" , 0, 7, NIL_IMAGES }, + { "lines per tag" , 8, 15, NIL_IMAGES }, + { "associativity" , 16, 23, NIL_IMAGES }, + { "size (Kb)" , 24, 31, NIL_IMAGES }, + }; + + printf(" L1 data cache information (0x80000005/ecx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000005_edx(unsigned int value) +{ + static named_item names[] + = { { "line size (bytes)" , 0, 7, NIL_IMAGES }, + { "lines per tag" , 8, 15, NIL_IMAGES }, + { "associativity" , 16, 23, NIL_IMAGES }, + { "size (Kb)" , 24, 31, NIL_IMAGES }, + }; + + printf(" L1 instruction cache information (0x80000005/ecx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static ccstring l2_assoc[] = { "L2 off (0)", + "direct mapped (1)", + "2-way (2)", + NULL, + "4-way (4)", + NULL, + "8-way (6)", + NULL, + "16-way (8)", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "full (15)" }; + +static void +print_80000006_eax(unsigned int value) +{ + static named_item names[] + = { { "instruction # entries" , 0, 11, NIL_IMAGES }, + { "instruction associativity" , 12, 15, l2_assoc }, + { "data # entries" , 16, 27, NIL_IMAGES }, + { "data associativity" , 28, 31, l2_assoc }, + }; + + printf(" L2 TLB/cache information: 2M/4M pages & L2 TLB" + " (0x80000006/eax):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000006_ebx(unsigned int value) +{ + static named_item names[] + = { { "instruction # entries" , 0, 11, NIL_IMAGES }, + { "instruction associativity" , 12, 15, l2_assoc }, + { "data # entries" , 16, 27, NIL_IMAGES }, + { "data associativity" , 28, 31, l2_assoc }, + }; + + printf(" L2 TLB/cache information: 4K pages & L2 TLB (0x80000006/ebx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000006_ecx(unsigned int value, + code_stash_t* stash) +{ + static named_item names[] + = { { "line size (bytes)" , 0, 7, NIL_IMAGES }, + { "lines per tag" , 8, 11, NIL_IMAGES }, + { "associativity" , 12, 15, l2_assoc }, + { "size (Kb)" , 16, 31, NIL_IMAGES }, + }; + + printf(" L2 unified cache information (0x80000006/ecx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); + + if (((value >> 12) & 0xf) == 4 && (value >> 16) == 256) { + stash->L2_4w_256K = TRUE; + } else if (((value >> 12) & 0xf) == 4 && (value >> 16) == 512) { + stash->L2_4w_512K = TRUE; + } +} + +static void +print_80000007_edx(unsigned int value) +{ + static named_item names[] + = { { "temperature sensing diode" , 0, 0, NIL_IMAGES }, + { "frequency ID (FID) control" , 1, 1, NIL_IMAGES }, + { "voltage ID (VID) control" , 2, 2, NIL_IMAGES }, + { "thermal trip (TTP)" , 3, 3, NIL_IMAGES }, + { "thermal monitor (TM)" , 4, 4, NIL_IMAGES }, + { "software thermal control (STC)" , 5, 5, NIL_IMAGES }, + { "TscInvariant" , 8, 8, NIL_IMAGES }, + }; + + printf(" Advanced Power Management Features (0x80000007/edx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000008_eax(unsigned int value) +{ + static named_item names[] + = { { "maximum physical address" , 0, 7, NIL_IMAGES }, + { "maximum linear address" , 8, 15, NIL_IMAGES }, + }; + + printf(" Physical Address and Linear Address Size (0x80000008/eax):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_80000008_ecx(unsigned int value) +{ + static named_item names[] + = { { "number of logical CPU cores - 1" , 0, 7, NIL_IMAGES }, + { "ApicIdCoreIdSize" , 12, 15, NIL_IMAGES }, + }; + + printf(" Logical CPU cores (0x80000008/ecx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_8000000a_eax(unsigned int value) +{ + static named_item names[] + = { { "SvmRev: SVM revision" , 0, 7, NIL_IMAGES }, + }; + + printf(" SVM Secure Virtual Machine (0x8000000a/eax):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_8000000a_edx(unsigned int value) +{ + static named_item names[] + = { { "LBR virtualization" , 1, 1, bools }, + }; + + printf(" SVM Secure Virtual Machine (0x8000000a/edx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_8000000a_ebx(unsigned int value) +{ + printf(" NASID: number of address space identifiers = 0x%x (%u):\n", + value, value); +} + +static void +print_80860001_eax(unsigned int value) +{ + static ccstring family[] = { NULL, + NULL, + NULL, + NULL, + NULL, + "Transmeta Crusoe" }; + static named_item names[] + = { { "generation " , 8, 11, family }, + { "model " , 4, 7, NIL_IMAGES }, + { "stepping " , 0, 3, NIL_IMAGES }, + }; + + printf(" Transmeta processor signature (0x80860001/eax):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); + + print_synth_transmeta(" (simple synth)", value, UN); +} + +static void +print_80860001_edx(unsigned int value) +{ + static named_item names[] + = { { "recovery CMS active" , 0, 0, bools }, + { "LongRun" , 1, 1, bools }, + { "LongRun Table Interface LRTI (CMS 4.2)" , 3, 3, bools }, + { "persistent translation technology 1.x" , 7, 7, bools }, + { "persistent translation technology 2.0" , 8, 8, bools }, + }; + + printf(" Transmeta feature flags (0x80860001/edx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +print_transmeta_proc_rev_meaning(unsigned int proc_rev) +{ + switch (proc_rev & 0xffff0000) { + case 0x01010000: + printf("(TM3200)"); + break; + case 0x01020000: + printf("(TM5400)"); + break; + case 0x01030000: + if ((proc_rev & 0xffffff00) == 0x00000000) { + printf("(TM5400 / TM5600)"); + } else { + printf("(unknown)"); + } + break; + case 0x01040000: + case 0x01050000: + printf("(TM5500 / TM5800)"); + break; + default: + printf("(unknown)"); + break; + } +} + +static void +print_80860001_ebx_ecx(unsigned int val_ebx, + unsigned int val_ecx) +{ + printf(" Transmeta processor revision (0x80000001/edx)" + " = %u.%u-%u.%u-%u ", + (val_ebx >> 24) & 0xff, + (val_ebx >> 16) & 0xff, + (val_ebx >> 8) & 0xff, + (val_ebx >> 0) & 0xff, + val_ecx); + + if (val_ebx == 0x20000000) { + printf("(see 80860002/eax)"); + } else { + print_transmeta_proc_rev_meaning(val_ebx); + } +} + +static void +print_80860002_eax(unsigned int value, + code_stash_t* stash) +{ + if (stash->transmeta_proc_rev == 0x02000000) { + printf(" Transmeta processor revision (0x80860002/eax)" + " = %u.%u-%u.%u ", + (value >> 24) & 0xff, + (value >> 16) & 0xff, + (value >> 8) & 0xff, + (value >> 0) & 0xff); + + print_transmeta_proc_rev_meaning(value); + + stash->transmeta_proc_rev = value; + } +} + +static void +print_c0000001_edx(unsigned int value) +{ + static named_item names[] + = { { "alternate instruction set" , 0, 0, bools }, + { "alternate instruction set enabled" , 1, 1, bools }, + { "random number generator" , 2, 2, bools }, + { "random number generator enabled" , 3, 3, bools }, + { "LongHaul MSR 0000_110Ah" , 4, 4, bools }, + { "FEMMS" , 5, 5, bools }, + { "advanced cryptography engine (ACE)" , 6, 6, bools }, + { "advanced cryptography engine (ACE)enabled", 7, 7, bools }, + }; + + printf(" extended feature flags (0xc0000001/edx):\n"); + print_names(value, names, LENGTH(names, named_item), + /* max_len => */ 0); +} + +static void +usage(void) +{ + printf("usage: %s [options...]\n", program); + printf("\n"); + printf("Dump detailed information about the CPU(s) gathered from the CPUID" + " instruction,\n"); + printf("and also determine the exact model of CPU(s).\n"); + printf("\n"); + printf("options:\n"); + printf("\n"); + printf(" -1, --one-cpu display information only for the first" + " CPU.\n"); + printf(" (Meaningful only with -k or --kernel.)\n"); + printf(" -f FILE, --file=FILE read raw hex information (-r output) from" + " FILE instead\n"); + printf(" of from executions of the cpuid" + " instruction\n"); + printf(" -h, -H, --help display this help information\n"); + printf(" -i, --inst use the CPUID instruction: The information" + " it provides\n"); + printf(" is reliable, but it works on only the" + " current CPU.\n"); + printf(" This should be OK on single-chip systems or" + " homogeneous\n"); + printf(" multi-chip systems. It is not necessary to" + " be root.\n"); + printf(" (This option is the default.)\n"); + printf(" -k, --kernel use the CPUID kernel module: This displays" + " information\n"); + printf(" for all CPUs, but the information it" + " provides is not\n"); + printf(" reliable for all combinations of CPU type" + " and kernel\n"); + printf(" version. Typically, it is necessary to be" + " root.\n"); + printf(" -r, --raw display raw hex information with no" + " decoding\n"); + printf(" -v, --version display cpuid version\n"); + printf("\n"); + exit(1); +} + +static void +explain_errno(void) +{ + if (errno == ENODEV || errno == ENXIO) { + fprintf(stderr, + "%s: if running a modular kernel, execute" + " \"modprobe cpuid\",\n", + program); + fprintf(stderr, + "%s: wait a few seconds, and then try again\n", + program); + fprintf(stderr, + "%s: or consider using the -i option\n", program); + } else if (errno == ENOENT) { + fprintf(stderr, + "%s: if running a modular kernel, execute" + " \"modprobe cpuid\",\n", + program); + fprintf(stderr, + "%s: wait a few seconds, and then try again;\n", + program); + fprintf(stderr, + "%s: if it still fails, try executing:\n", + program); + fprintf(stderr, + "%s: mknod /dev/cpu/0/cpuid c %u 0\n", + program, CPUID_MAJOR); + fprintf(stderr, + "%s: mknod /dev/cpu/1/cpuid c %u 1\n", + program, CPUID_MAJOR); + fprintf(stderr, + "%s: etc.\n", + program); + fprintf(stderr, + "%s: and then try again\n", + program); + fprintf(stderr, + "%s: or consider using the -i option\n", program); + } else if ((errno == EPERM || errno == EACCES) && getuid() != 0) { + fprintf(stderr, + "%s: on most systems," + " it is necessary to execute this as root\n", + program); + fprintf(stderr, + "%s: or consider using the -i option\n", program); + } + exit(1); +} + +#define WORD_EAX 0 +#define WORD_EBX 1 +#define WORD_ECX 2 +#define WORD_EDX 3 + +#define WORD_NUM 4 + +#define FOUR_CHARS_VALUE(s) \ + ((unsigned int)((s)[0] + ((s)[1] << 8) + ((s)[2] << 16) + ((s)[3] << 24))) +#define IS_VENDOR_ID(words, s) \ + ( (words)[WORD_EBX] == FOUR_CHARS_VALUE(&(s)[0]) \ + && (words)[WORD_EDX] == FOUR_CHARS_VALUE(&(s)[4]) \ + && (words)[WORD_ECX] == FOUR_CHARS_VALUE(&(s)[8])) + +static void +print_reg_raw (unsigned int reg, + const unsigned int words[WORD_NUM]) +{ + printf(" 0x%08x: eax=0x%08x ebx=0x%08x ecx=0x%08x edx=0x%08x\n", + (unsigned int)reg, + words[WORD_EAX], words[WORD_EBX], + words[WORD_ECX], words[WORD_EDX]); +} + +static void +print_reg (unsigned int reg, + const unsigned int words[WORD_NUM], + boolean raw, + unsigned int try, + code_stash_t* stash) +{ + if (raw) { + print_reg_raw(reg, words); + } else if (reg == 0) { + // basic_max already set to words[WORD_EAX] + printf(" vendor_id = \"%4.4s%4.4s%4.4s\"\n", + (const char*)&words[WORD_EBX], + (const char*)&words[WORD_EDX], + (const char*)&words[WORD_ECX]); + if (IS_VENDOR_ID(words, "GenuineIntel")) { + stash->vendor = VENDOR_INTEL; + } else if (IS_VENDOR_ID(words, "AuthenticAMD")) { + stash->vendor = VENDOR_AMD; + } else if (IS_VENDOR_ID(words, "CyrixInstead")) { + stash->vendor = VENDOR_CYRIX; + } else if (IS_VENDOR_ID(words, "CentaurHauls")) { + stash->vendor = VENDOR_VIA; + } else if (IS_VENDOR_ID(words, "UMC UMC UMC ")) { + stash->vendor = VENDOR_UMC; + } else if (IS_VENDOR_ID(words, "NexGenDriven")) { + stash->vendor = VENDOR_NEXGEN; + } else if (IS_VENDOR_ID(words, "RiseRiseRise")) { + stash->vendor = VENDOR_RISE; + } else if (IS_VENDOR_ID(words, "GenuineTMx86")) { + stash->vendor = VENDOR_TRANSMETA; + } + } else if (reg == 1) { + print_1_eax(words[WORD_EAX], stash->vendor); + print_1_ebx(words[WORD_EBX]); + print_brand(words[WORD_EAX], words[WORD_EBX]); + print_1_edx(words[WORD_EDX]); + print_1_ecx(words[WORD_ECX]); + stash->val_1_eax = words[WORD_EAX]; + stash->val_1_ebx = words[WORD_EBX]; + stash->val_1_ecx = words[WORD_ECX]; + stash->val_1_edx = words[WORD_EDX]; + } else if (reg == 2) { + unsigned int word = 0; + for (; word < 4; word++) { + if ((words[word] & 0x80000000) == 0) { + const unsigned char* bytes = (const unsigned char*)&words[word]; + unsigned int byte = (try == 0 && word == WORD_EAX ? 1 + : 0); + for (; byte < 4; byte++) { + print_2_byte(bytes[byte], stash->vendor, stash->val_1_eax); + stash_intel_cache(stash, bytes[byte]); + } + } + } + } else if (reg == 3) { + printf(" processor serial number:" + " %04X-%04X-%04X-%04X-%04X-%04X\n", + stash->val_1_eax >> 16, stash->val_1_eax & 0xffff, + words[WORD_EDX] >> 16, words[WORD_EDX] & 0xffff, + words[WORD_ECX] >> 16, words[WORD_ECX] & 0xffff); + } else if (reg == 4) { + printf(" deterministic cache parameters (4):\n"); + print_4_eax(words[WORD_EAX]); + print_4_ebx(words[WORD_EAX]); + printf(" number of sets - 1 (s) = %u\n", words[WORD_ECX]); + stash->val_4_eax = words[WORD_EAX]; + } else if (reg == 5) { + printf(" MONITOR/MWAIT (5):\n"); + print_5_eax(words[WORD_EAX]); + print_5_ebx(words[WORD_EAX]); + print_5_ecx(words[WORD_ECX]); + print_5_edx(words[WORD_EDX]); + } else if (reg == 6) { + printf(" Thermal and Power Management Features (6):\n"); + print_6_eax(words[WORD_EAX]); + print_6_ebx(words[WORD_EAX]); + print_6_ecx(words[WORD_ECX]); + } else if (reg == 7) { + /* Reserved: DO NOTHING */ + } else if (reg == 8) { + /* Reserved: DO NOTHING */ + } else if (reg == 9) { + /* Reserved: DO NOTHING */ + } else if (reg == 0xa) { + print_a_eax(words[WORD_EAX]); + print_a_ebx(words[WORD_EBX]); + } else if (reg == 0x80000000) { + // basic_max already set to words[WORD_EAX] + } else if (reg == 0x80000001) { + print_80000001_eax(words[WORD_EAX], stash->vendor); + print_80000001_edx(words[WORD_EDX], stash->vendor); + print_80000001_ebx(words[WORD_EBX], stash->vendor); + print_80000001_ecx(words[WORD_ECX], stash->vendor); + stash->val_80000001_ebx = words[WORD_EBX]; + stash->val_80000001_ecx = words[WORD_ECX]; + } else if (reg == 0x80000002) { + memcpy(&stash->brand[0], words, sizeof(unsigned int)*WORD_NUM); + } else if (reg == 0x80000003) { + memcpy(&stash->brand[16], words, sizeof(unsigned int)*WORD_NUM); + } else if (reg == 0x80000004) { + memcpy(&stash->brand[32], words, sizeof(unsigned int)*WORD_NUM); + printf(" brand = \"%s\"\n", stash->brand); + } else if (reg == 0x80000005) { + print_80000005_eax(words[WORD_EAX]); + print_80000005_ebx(words[WORD_EBX]); + print_80000005_ecx(words[WORD_ECX]); + print_80000005_edx(words[WORD_EDX]); + } else if (reg == 0x80000006) { + print_80000006_eax(words[WORD_EAX]); + print_80000006_ebx(words[WORD_EBX]); + print_80000006_ecx(words[WORD_ECX], stash); + } else if (reg == 0x80000007) { + print_80000007_edx(words[WORD_EDX]); + } else if (reg == 0x80000008) { + print_80000008_eax(words[WORD_EAX]); + print_80000008_ecx(words[WORD_ECX]); + stash->val_80000008_ecx = words[WORD_ECX]; + } else if (reg == 0x80000009) { + /* reserved for Intel feature flag expansion */ + } else if (reg == 0x8000000a) { + print_8000000a_eax(words[WORD_EAX]); + print_8000000a_edx(words[WORD_EAX]); + print_8000000a_ebx(words[WORD_EBX]); + } else if (0x8000000b <= reg && reg <= 0x80000018) { + /* reserved for vendors to be determined feature flag expansion */ + } else if (reg == 0x80860000) { + // basic_max already set to words[WORD_EAX] + } else if (reg == 0x80860001) { + print_80860001_eax(words[WORD_EAX]); + print_80860001_edx(words[WORD_EDX]); + print_80860001_ebx_ecx(words[WORD_EBX], words[WORD_ECX]); + } else if (reg == 0x80860002) { + print_80860002_eax(words[WORD_EAX], stash); + printf(" Transmeta CMS revision (0x80000002/ecx)" + " = %u.%u-%u.%u-%u ", + (words[WORD_EBX] >> 24) & 0xff, + (words[WORD_EBX] >> 16) & 0xff, + (words[WORD_EBX] >> 8) & 0xff, + (words[WORD_EBX] >> 0) & 0xff, + words[WORD_ECX]); + } else if (reg == 0x80860003) { + memcpy(&stash->transmeta_info[0], words, sizeof(unsigned int)*WORD_NUM); + } else if (reg == 0x80860004) { + memcpy(&stash->transmeta_info[16], words, sizeof(unsigned int)*WORD_NUM); + } else if (reg == 0x80860005) { + memcpy(&stash->transmeta_info[32], words, sizeof(unsigned int)*WORD_NUM); + } else if (reg == 0x80860006) { + memcpy(&stash->transmeta_info[48], words, sizeof(unsigned int)*WORD_NUM); + printf(" Transmeta information = \"%s\"\n", stash->transmeta_info); + } else if (reg == 0x80860007) { + printf(" Transmeta core clock frequency = %u MHz\n", + words[WORD_EAX]); + printf(" Transmeta processor voltage = %u mV\n", + words[WORD_EBX]); + printf(" Transmeta performance = %u%%\n", + words[WORD_ECX]); + printf(" Transmeta gate delay = %u fs\n", + words[WORD_EDX]); + } else if (reg == 0xc0000000) { + // basic_max already set to words[WORD_EAX] + } else if (reg == 0xc0000001) { + if (stash->vendor == VENDOR_VIA) { + printf(" 0x%08x: eax=0x%08x\n", + (unsigned int)reg, words[WORD_EAX]); + print_c0000001_edx(words[WORD_EDX]); + } else { + /* DO NOTHING */ + } + } else { + print_reg_raw(reg, words); + } +} + +#define USE_INSTRUCTION (-2) + +static int +real_setup(unsigned int cpu, + boolean inst) +{ + if (inst) { + return USE_INSTRUCTION; + } else { + int cpuid_fd = -1; + char cpuid_name[20]; + + if (cpuid_fd == -1 && cpu == 0) { + cpuid_fd = open("/dev/cpuid", O_RDONLY); + if (cpuid_fd == -1 && errno != ENOENT) { + fprintf(stderr, + "%s: cannot open /dev/cpuid; errno = %d (%s)\n", + program, errno, strerror(errno)); + explain_errno(); + } + } + + if (cpuid_fd == -1) { + sprintf(cpuid_name, "/dev/cpu/%u/cpuid", cpu); + cpuid_fd = open(cpuid_name, O_RDONLY); + if (cpuid_fd == -1) { + if (cpu > 0) { + if (errno == ENXIO) return -1; + if (errno == ENODEV) return -1; + } + if (errno != ENOENT) { + fprintf(stderr, + "%s: cannot open /dev/cpuid or %s; errno = %d (%s)\n", + program, cpuid_name, errno, strerror(errno)); + explain_errno(); + } + } + } + + if (cpuid_fd == -1) { + /* + ** Lots of Linux's omit the /dev/cpuid or /dev/cpu/%u/cpuid files. + ** Try creating a temporary file with mknod. + ** + ** mkstemp is of absolutely no security value here because I can't + ** use the actual file it generates, and have to delete it and + ** re-create it with mknod. But I have to use it anyway to + ** eliminate errors from smartypants gcc/glibc during the link if I + ** attempt to use tempnam. + */ + char tmpname[20]; + int dummy_fd; + strcpy(tmpname, "/tmp/cpuidXXXXXX"); + dummy_fd = mkstemp(tmpname); + if (dummy_fd != -1) { + close(dummy_fd); + remove(tmpname); + { + +#define cpuid_makedev(maj,min) \ + ((((dev_t)((maj) & 0x00000fffU)) << 8) | \ + (((dev_t)((maj) & 0xfffff000U)) << 32) | \ + (((dev_t)((min) & 0x000000ffU)) << 0) | \ + (((dev_t)((min) & 0xffffff00U)) << 12)) + int status = mknod(tmpname, + (S_IFCHR | S_IRUSR), + cpuid_makedev(CPUID_MAJOR, cpu)); + if (status == 0) { + cpuid_fd = open(tmpname, O_RDONLY); + remove(tmpname); + } + } + } + if (cpuid_fd == -1) { + if (cpu > 0) { + if (errno == ENXIO) return -1; + if (errno == ENODEV) return -1; + } + fprintf(stderr, + "%s: cannot open /dev/cpuid or %s; errno = %d (%s)\n", + program, cpuid_name, errno, strerror(errno)); + explain_errno(); + } + } + + return cpuid_fd; + } +} + +static int real_get (int cpuid_fd, + unsigned int reg, + unsigned int words[], + boolean quiet) +{ + if (cpuid_fd == USE_INSTRUCTION) { + asm("cpuid" + : "=a" (words[WORD_EAX]), + "=b" (words[WORD_EBX]), + "=c" (words[WORD_ECX]), + "=d" (words[WORD_EDX]) + : "a" (reg)); + } else { + int status; + + status = lseek(cpuid_fd, reg, SEEK_SET); + if (status == -1) { + if (quiet) { + return FALSE; + } else { + fprintf(stderr, + "%s: unable to seek cpuid file to offset 0x%08x;" + " errno = %d (%s)\n", + program, reg, errno, strerror(errno)); + exit(1); + } + } + + status = read(cpuid_fd, words, 16); + if (status == -1) { + if (quiet) { + return FALSE; + } else { + fprintf(stderr, + "%s: unable to read cpuid file at offset 0x%08x;" + " errno = %d (%s)\n", + program, reg, errno, strerror(errno)); + exit(1); + } + } + } + + return TRUE; +} + +static void +do_real(boolean one_cpu, + boolean inst, + boolean raw) +{ + unsigned int cpu; + + for (cpu = 0;; cpu++) { + int cpuid_fd = -1; + code_stash_t stash = NIL_STASH; + unsigned int basic_max; + unsigned int reg; + + if (one_cpu && cpu > 0) break; + if (inst && cpu > 0) break; + + cpuid_fd = real_setup(cpu, inst); + if (cpuid_fd == -1) break; + + if (inst) { + printf("CPU:\n"); + } else { + printf("CPU %u:\n", cpu); + } + + basic_max = 0; + for (reg = 0; reg <= basic_max; reg++) { + unsigned int words[WORD_NUM]; + + real_get(cpuid_fd, reg, words, FALSE); + + if (reg == 0) { + basic_max = words[WORD_EAX]; + } + + if (reg == 2) { + unsigned int max_tries = words[WORD_EAX] & 0xff; + unsigned int try = 0; + + if (!raw) { + printf(" cache and TLB information (2):\n"); + } + + for (;;) { + print_reg(reg, words, raw, try, &stash); + + try++; + if (try >= max_tries) break; + + real_get(cpuid_fd, reg, words, FALSE); + } while (try < max_tries); + } else { + print_reg(reg, words, raw, 0, &stash); + } + } + + basic_max = 0x80000000; + for (reg = 0x80000000; reg <= basic_max; reg++) { + boolean success; + unsigned int words[WORD_NUM]; + + success = real_get(cpuid_fd, reg, words, TRUE); + if (!success) break; + + if (reg == 0x80000000) { + basic_max = words[WORD_EAX]; + } + + print_reg(reg, words, raw, 0, &stash); + } + + basic_max = 0x80860000; + for (reg = 0x80860000; reg <= basic_max; reg++) { + boolean success; + unsigned int words[WORD_NUM]; + + success = real_get(cpuid_fd, reg, words, TRUE); + if (!success) break; + + if (reg == 0x80860000) { + basic_max = words[WORD_EAX]; + } + + print_reg(reg, words, raw, 0, &stash); + } + + basic_max = 0xc0000000; + for (reg = 0xc0000000; reg <= basic_max; reg++) { + boolean success; + unsigned int words[WORD_NUM]; + + success = real_get(cpuid_fd, reg, words, TRUE); + if (!success) break; + + if (reg == 0xc0000000) { + basic_max = words[WORD_EAX]; + } + + print_reg(reg, words, raw, 0, &stash); + } + + if (!raw) { + decode_mp_synth(&stash); + print_mp_synth(&stash.mp); + print_synth(&stash); + } + + close(cpuid_fd); + } +} + +static void +do_file(ccstring filename, + boolean raw) +{ + boolean seen_cpu = FALSE; + unsigned int cpu = -1; + unsigned int try2 = -1; + code_stash_t stash; + + FILE* file = fopen(filename, "r"); + if (file == NULL) { + fprintf(stderr, + "%s: unable to open %s; errno = %d (%s)\n", + program, filename, errno, strerror(errno)); + exit(1); + } + + while (!feof(file)) { + char buffer[80]; + char* ptr; + unsigned int len; + int status; + unsigned int reg; + unsigned int words[WORD_NUM]; + + ptr = fgets(buffer, LENGTH(buffer, char), file); + if (ptr == NULL && errno == 0) break; + if (ptr == NULL) { + fprintf(stderr, + "%s: unable to read a line of text from %s;" + " errno = %d (%s)\n", + program, filename, errno, strerror(errno)); + exit(1); + } + + len = strlen(buffer); + + status = sscanf(ptr, "CPU %u:\r", &cpu); + if (status == 1 || strcmp(ptr, "CPU:\n") == SAME) { + if (!raw && seen_cpu) { + decode_mp_synth(&stash); + print_mp_synth(&stash.mp); + print_synth(&stash); + } + + seen_cpu = TRUE; + + if (status == 1) { + printf("CPU %u:\n", cpu); + } else { + printf("CPU:\n"); + } + try2 = 0; + { + static code_stash_t empty_stash = NIL_STASH; + stash = empty_stash; + } + continue; + } + + status = sscanf(ptr, + " 0x%x: eax=0x%x ebx=0x%x ecx=0x%x edx=0x%x\r", + ®, + &words[WORD_EAX], &words[WORD_EBX], + &words[WORD_ECX], &words[WORD_EDX]); + if (status == 5) { + if (reg == 2) { + if (try2 == 0) { + if (!raw) { + printf(" cache and TLB information (2):\n"); + } + } + print_reg(reg, words, raw, try2++, &stash); + } else { + print_reg(reg, words, raw, 0, &stash); + } + continue; + } + + fprintf(stderr, + "%s: unexpected input with -f option: %s\n", + program, ptr); + exit(1); + } + + if (!raw && seen_cpu) { + decode_mp_synth(&stash); + print_mp_synth(&stash.mp); + print_synth(&stash); + } + + fclose(file); +} + +int +main(int argc, + string argv[]) +{ + static ccstring shortopts = "+hH1ikrf:v"; + static const struct option longopts[] = { + { "help", no_argument, NULL, 'h' }, + { "one-cpu", no_argument, NULL, '1' }, + { "inst", no_argument, NULL, 'i' }, + { "kernel", no_argument, NULL, 'k' }, + { "raw", no_argument, NULL, 'r' }, + { "file", required_argument, NULL, 'f' }, + { "version", no_argument, NULL, 'v' }, + { NULL, no_argument, NULL, '\0' } + }; + + boolean opt_one_cpu = FALSE; + boolean opt_inst = FALSE; + boolean opt_kernel = FALSE; + boolean opt_raw = FALSE; + cstring opt_filename = NULL; + boolean opt_version = FALSE; + + program = strrchr(argv[0], '/'); + if (program == NULL) { + program = argv[0]; + } else { + program++; + } + + opterr = 0; + + for (;;) { + int longindex; + int opt = getopt_long(argc, argv, shortopts, longopts, &longindex); + + if (opt == EOF) break; + + switch (opt) { + case 'h': + case 'H': + usage(); + /*NOTREACHED*/ + case '1': + opt_one_cpu = TRUE; + break; + case 'i': + opt_inst = TRUE; + break; + case 'k': + opt_kernel = TRUE; + break; + case 'r': + opt_raw = TRUE; + break; + case 'f': + opt_filename = optarg; + break; + case 'v': + opt_version = TRUE; + break; + case '?': + default: + if (optopt == '\0') { + fprintf(stderr, + "%s: unrecogized option: %s\n", program, argv[optind-1]); + } else { + fprintf(stderr, + "%s: unrecognized option letter: %c\n", program, optopt); + } + usage(); + /*NOTREACHED*/ + } + } + + if (optind < argc) { + fprintf(stderr, "%s: unrecognized argument: %s\n", program, argv[optind]); + usage(); + /*NOTREACHED*/ + } + + if (opt_inst && opt_kernel) { + fprintf(stderr, + "%s: -i/--inst and -k/--kernel are incompatible options\n", + program); + exit(1); + } + + // Default to -i. So use inst unless -k is specified. + boolean inst = !opt_kernel; + + if (opt_version) { + printf("cpuid version %s\n", XSTR(VERSION)); + } else { + if (opt_filename != NULL) { + do_file(opt_filename, opt_raw); + } else { + do_real(opt_one_cpu, inst, opt_raw); + } + } + + exit(0); + /*NOTREACHED*/ +} diff --git a/cpuid/log.c b/cpuid/log.c new file mode 100644 index 0000000..a755233 --- /dev/null +++ b/cpuid/log.c @@ -0,0 +1,76 @@ +/* + *----------------------------------------------------------------------------- + * + * log.c -- + * + * Logging functionality. + * + *----------------------------------------------------------------------------- + */ + +#include <cpuid.h> + +volatile int logging = 1; + +static int in_early_log = 1; + +static char *log; +static unsigned long logsize = PAGE_SIZE; +static unsigned long logptr = 0; + +static char early_log[PAGE_SIZE]; + +static spinlock loglock = SPINLOCK_NEW; + +void +setup_log (void) +{ + spinlock_acquire (&loglock); + + log = get_pages (LOG_SIZE / PAGE_SIZE, &logsize); + logptr = 0; + + in_early_log = 0; + + spinlock_release (&loglock); +} + +void +log_msg (char *msg) +{ + size_t size = strlen (msg); + size_t noutput; + char *current_log; + + if (!logging) { + return; + } + + spinlock_acquire (&loglock); + + noutput = MIN (size, logsize - logptr); + + if (in_early_log) { + current_log = early_log; + } else { + current_log = log; + } + + strncat (current_log, msg, noutput); + + logptr += noutput; + + spinlock_release (&loglock); +} + +void +console_dump_log (void) +{ + +} + +void +serial_dump_log (void) +{ + +} diff --git a/cpuid/malloc.c b/cpuid/malloc.c new file mode 100644 index 0000000..8791069 --- /dev/null +++ b/cpuid/malloc.c @@ -0,0 +1,469 @@ +/* memory.c + * This file is a part of decomp - a disassembler. Here are the memory + * allocation and deallocation routines. + * + * Copyright (C) 2001 Jonathan duSaint <dusaint@earthlink.net> + * + * The memory allocation is fairly routine. The justification for not + * using malloc as is is primarily a speed issue. Secondary is the + * fact that this organization allows sloppy memory accounting in the + * main program. When disassembling a file, there will be a lot of + * allocations and deallocations of small, similarly-sized blocks of + * memory (i.e. INSN). By not releasing the memory each time a section + * read is completed, it allows the same block to be reused for the + * next section. + * The mechanism of allocation is that large, CHUNK_SIZE sized blocks + * of memory are requested from the system. They are kept track of + * by overlaying the first sizeof (sys_block) bytes with a + * struct sys_block and having the next pointer point to the next + * block, or being NULL. That way, when xfree is called, the linked + * list, kept in the variable memory, is walked and each node is free'd. + * Each block is then carved up into smaller blocks. Each of these + * smaller blocks has the first sizeof (mem_header) bytes overlaid + * by a struct mem_header. Then, if one of the smaller blocks is needed, + * the struct mem_header is placed on the alloc list. If, relative + * to the size of the memory request, it is fairly large, it is + * partitioned into two blocks. One is placed on the alloc list and + * returned to the caller; the other is placed on the free list. Then, + * as space is needed, adjacent free blocks are merged to create larger + * blocks. If the global variable memory_trace is non-zero, then + * messages are printed to stdout as important/interesting events + * take place. Also provided is the function void mem_trace (void), + * which prints the alloc list, the free list, and the sys list. + * + * Started around 15 October 2001. + */ + + +#include <cpuid.h> + + +/* the default amount of memory to request from the system each time */ +#define DEFAULT_CHUNK_SIZE PAGE_SIZE + +/* round an amount of memory to the next page size up */ +#define ROUND_TO_PAGE_SIZE(a) (((a) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1)) + +/* the minimum size of housekeeping info in a sys block */ +#define ALLOC_ADJUST (sizeof (struct sys_block) + sizeof (struct mem_header)) + +/* the smallest amount which will be returned */ +#define MIN_ALLOC_AMOUNT 8 + +/* the largest amount that can be handled at one time */ +#define MAX_ALLOC_AMOUNT (chunk_size - ALLOC_ADJUST) + + +/* header for a block of memory - this is what is referenced on + both the alloc and free lists */ +struct mem_header { + /* size of the chunk, not including the header */ + unsigned long size; + struct mem_header *next; +} __attribute__ ((packed)); + + +/* header for the block returned by a call to malloc(3) */ +struct sys_block { + struct sys_block *next; +} __attribute__ ((packed)); + + +/* the free list */ +static struct mem_header *free_list = NULL; + +/* the alloc list */ +static struct mem_header *alloc_list = NULL; + +/* the list of malloc'ed blocks */ +static struct sys_block *memory; + + +/* info used for keeping stats */ + +/* the total memory alloc'ed from the OS */ +static unsigned long total_alloced; + +/* the number of calls to xmalloc */ +static unsigned long xmalloc_calls; + +/* the number of bytes returned by xmalloc */ +static unsigned long xmalloc_bytes; + +/* the number of bytes free'd by xfree */ +static unsigned long xfree_bytes; + + +/* the allocation size for memory chunks */ +static unsigned long chunk_size; + +/* whether or not to print status messages */ +volatile int memory_trace = 0; + +/* whether or not memory is fragmented */ +static int free_list_needs_compacting = 0; + +/* forward declaration needed for mem_trace */ +void compact_free_list (void); + + +/* mem_trace + * Called in case something bad has happened. Prints the contents + * of the alloc list, the free list, and the sys list. + */ +#if 0 +void +mem_trace (void) +{ + struct mem_header *tmp; + struct sys_block *sys; + + fprintf (stderr, "alloc list:\n"); + tmp = alloc_list; + while (tmp != NULL) + { + fprintf (stderr, " %p->(%p, %ld)\n", tmp, tmp->next, tmp->size); + tmp = tmp->next; + } + + fprintf (stderr, "free list (%d):\n", free_list_needs_compacting); + tmp = free_list; + while (tmp != NULL) + { + fprintf (stderr, " %p->(%p, %ld)\n", tmp, tmp->next, tmp->size); + tmp = tmp->next; + } + + sys = memory; + fprintf (stderr, "system memory:\n"); + while (sys != NULL) + { + fprintf (stderr, " %p - %p ->(%p)\n", sys, sys + chunk_size, + sys->next); + sys = sys->next; + } +} +#endif + + +/* free_list_insert_sorted + * Insert NEW onto the free list, sorted numerically by address. + */ +void +free_list_insert_sorted (struct mem_header *new) +{ + struct mem_header *free_tmp = free_list; + + /* check for empty list */ + if (free_list == NULL) + { + free_list = new; + free_list->next = NULL; + return; + } + + /* if NEW is the lowest address */ + if (new < free_tmp) + { + new->next = free_tmp; + free_list = new; + return; + } + + /* general case - find the insertion point */ + while (free_tmp->next != NULL) + { + if (new < free_tmp->next) break; + free_tmp = free_tmp->next; + } + + new->next = free_tmp->next; + free_tmp->next = new; +} + + +/* compact_free_list + * Defragment memory by merging all adjacent free blocks. + */ +void +compact_free_list (void) +{ + struct mem_header *free_tmp = free_list; + + /* search through the free list for adjacent blocks - if two + are adjacent, then merge them to create a larger block */ + while (free_tmp != NULL) + { + if (free_tmp->next == NULL) break; /* at the end of the list */ + + /* if two free blocks are adjacent */ + if ((void *)free_tmp + free_tmp->size + + sizeof (struct mem_header) == (void *)free_tmp->next) + { + /* merge them */ + free_tmp->size += free_tmp->next->size + + sizeof (struct mem_header); + free_tmp->next = free_tmp->next->next; + + continue; /* try again with this same block */ + } + + free_tmp = free_tmp->next; + } + + free_list_needs_compacting = 0; +} + +/* mem_init + * Called when xmalloc is first invoked. Sets up the necessary + * data structures. + */ +void +mem_init (void) +{ + /* set up stats */ + total_alloced = 0; + xmalloc_calls = 0; + xmalloc_bytes = 0; + xfree_bytes = 0; + + /* set up the system list */ + memory = get_pages (chunk_size / PAGE_SIZE, NULL); + memory->next = NULL; + + /* set up the free list */ + free_list = (void *)memory + sizeof (struct sys_block); + free_list->size = chunk_size - sizeof (struct sys_block) + - sizeof (struct mem_header); + free_list->next = NULL; + + if (memory_trace) { + print_str ("== memtrace: alloc'd block: "); + print_hex32 ((unsigned long)memory); + print_str ("\n"); + } +} + + +/* malloc + * Allocate AMOUNT bytes of memory and return it with all of + * its bytes set to 0x00. + */ +void * +malloc (size_t amount) +{ + struct mem_header *free_tmp, *last, *ret_block; + struct sys_block *sys_temp; + + if (amount == 0) { + return NULL; + } + + chunk_size = DEFAULT_CHUNK_SIZE; + + /* if more than the default chunk size was requested */ + if (amount > MAX_ALLOC_AMOUNT) + chunk_size = amount + ALLOC_ADJUST; + + chunk_size = ROUND_TO_PAGE_SIZE (chunk_size); + + if (free_list == NULL && alloc_list == NULL) mem_init (); + + /* don't allocate less than MIN_ALLOC_AMOUNT */ + if (amount < MIN_ALLOC_AMOUNT) + amount = MIN_ALLOC_AMOUNT; + + /* keep stats */ + xmalloc_calls++; + xmalloc_bytes += amount; + + + /* loop until a block is found */ + while (1) + { + /* first walk the free list, looking for the correct size */ + last = NULL; + free_tmp = free_list; + + while (free_tmp != NULL) + { + if (free_tmp->size >= amount) goto GOT_FREE_BLOCK; + + last = free_tmp; + free_tmp = free_tmp->next; + } + + + /* didn't find a free block of the right size + - try compacting the free list */ + if (free_list_needs_compacting) + { + compact_free_list (); + continue; + } + + + /* if we got here, then we need to allocate a new chunk */ + + /* find the last chunk */ + sys_temp = memory; + while (sys_temp->next != NULL) sys_temp = sys_temp->next; + + /* alloc a new chunk and save its ptr */ + sys_temp->next = get_pages (chunk_size / PAGE_SIZE, NULL); + sys_temp->next->next = NULL; + + if (memory_trace) { + print_str ("== memtrace: alloc'ed block: "); + print_hex32 ((unsigned long)sys_temp->next); + print_str ("\n"); + } + + /* create the new free block */ + free_tmp = (void *)sys_temp->next + sizeof (struct sys_block); + free_tmp->next = NULL; + free_tmp->size = chunk_size - ALLOC_ADJUST; + + /* put that bad boy in the free list */ + free_list_insert_sorted (free_tmp); + + /* with this new large chunk, try again */ + } + + GOT_FREE_BLOCK: + /* remove the block from the free list */ + if (last == NULL) + free_list = free_tmp->next; + else + last->next = free_tmp->next; + + ret_block = free_tmp; + + + /* shrink the block, if possible */ + if (ret_block->size > amount + sizeof (struct mem_header) + MIN_ALLOC_AMOUNT) + { + struct mem_header *new = (void *)ret_block + + sizeof (struct mem_header) + amount; + + new->size = ret_block->size - sizeof (struct mem_header) - amount; + new->next = NULL; + ret_block->size = amount; + + free_list_insert_sorted (new); + } + + /* put it on the alloc list */ + ret_block->next = alloc_list; + alloc_list = ret_block; + + if (memory_trace) { + print_str ("== Memtrace: malloc returned bytes/block: "); + print_hex32 (amount); + print_str ("/"); + print_hex32 ((size_t)ret_block + sizeof (struct mem_header)); + print_str ("==\n"); + } + + + /* and (finally) return the memory */ + memset ((void *)ret_block + sizeof (struct mem_header), 0, amount); + return ((void *)ret_block + sizeof (struct mem_header)); +} + +/* free + * Add FREEMEM to the free list. + */ +void +free (void *freemem) +{ + struct mem_header *mem; + struct mem_header *tmp = alloc_list, *last = NULL; + + if (freemem == NULL) return; + + mem = freemem - sizeof (struct mem_header); + + /* find FREEMEM on the alloc list */ + while (tmp != NULL) + { + if (tmp == mem) break; + + last = tmp; + tmp = tmp->next; + } + + /* sanity check */ + if (tmp == NULL) + { + printf ("tried to free block %p (%p->(%p, %ld)) not on alloc list\n", + freemem, mem, mem->next, mem->size); + } + + /* keep stats */ + xfree_bytes += tmp->size; + + if (memory_trace) { + print_str ("== memtrace: freed bytes/block: "); + print_hex32 (tmp->size); + print_str ("/"); + print_hex32 ((size_t)freemem); + print_str ("\n"); + } + + /* remove from the alloc list */ + if (last == NULL) + alloc_list = tmp->next; + else + last->next = tmp->next; + + /* put it on the free list */ + free_list_insert_sorted (mem); + free_list_needs_compacting = 1; +} + +void * +realloc (void *mem, size_t amt) +{ + void *new; + + new = malloc (amt); + + if (new != NULL) { + memcpy (new, mem, amt); + free (mem); + } + + return new; +} + + +/* free_all + * Release all memory back to the OS. + */ +#if 0 +void +free_all (void) +{ + struct sys_block *temp; + + do + { + if (memory_trace) + printf ("=== freeing %p ===\n", memory); + + temp = memory->next; + free (memory); + memory = temp; + } + while (memory != NULL); + + if (memory_trace) + printf ("\n*** Stats ***\n" + " %ld total bytes alloc'ed from the system\n" + " %ld calls to xmalloc\n" + " %ld total bytes alloc'ed\n" + " %ld bytes freed\n", + total_alloced, xmalloc_calls, xmalloc_bytes, xfree_bytes); +} +#endif diff --git a/cpuid/memory.c b/cpuid/memory.c new file mode 100644 index 0000000..c4674d7 --- /dev/null +++ b/cpuid/memory.c @@ -0,0 +1,376 @@ +/* + *----------------------------------------------------------------------------- + * + * memory.c -- + * + * Protected mode memory management. + * + *----------------------------------------------------------------------------- + */ + +#include <cpuid.h> + +/* Bit 9 of a PTE get set when a page is in use */ +#define PAGE_USE_MASK (1UL << 9) +#define PAGE_USED(pte) (pte & PAGE_USE_MASK) +#define MARK_PAGE_USED(pte) ((pte) |= PAGE_USE_MASK) +#define MARK_PAGE_UNUSED(pte) ((pte) |= ~PAGE_USE_MASK) + +#define PDE(vaddr) ((unsigned long *)(PAGE_DIRECTORY \ + + ((((vaddr) >> 22) & 0x3ff) << 2))) +#define PT(vaddr) (*PDE(vaddr) & MASK4k) +#define PTE(vaddr) ((unsigned long *)(PT(vaddr) \ + + ((((vaddr) >> 12) & 0x3ff) << 2))) + + +extern char bss_end; + + +/* + *----------------------------------------------------------------------------- + * + * next_page -- + * + * Linear address of the next free page. All pages prior to this have + * been used, though they are not necessarily currently in use. This + * is updated during a call to get_pages(). + * + *----------------------------------------------------------------------------- + */ + +static unsigned long next_page; + +/* + *----------------------------------------------------------------------------- + * + * page_limit -- + * + * Linear address of the highest mapped page. This is, in effect, the + * amount of memory available (it would be page_limit * PAGE_SIZE - 1MiB). + * + *----------------------------------------------------------------------------- + */ + +static unsigned long page_limit; + + +/* + *----------------------------------------------------------------------------- + * + * memmap -- + * + * A map, created from the e820 memory map, of all usable memory. The + * length of the list is stored in mem_entries. + * + *----------------------------------------------------------------------------- + */ + +static unsigned long mem_entries; +static struct memory_map { + unsigned long memstart; + unsigned long memend; +} memmap[E820_MAX]; + + +/* + *----------------------------------------------------------------------------- + * + * print_e820_map -- + * + * Print the memory map returned by int 15 function e820 to the console. + * + *----------------------------------------------------------------------------- + */ + +static void +print_e820_map (struct e820info *e820info, unsigned long e820entries) +{ + unsigned long k; + char *type[] = { "", + "ARM (1)", /* Address Range Memory (usable) */ + "ARR (2)", /* Address Range Reserved (unusable) */ + "ACPI (3)", /* ACPI (usable) */ + "NVS (4)" }; /* NVS? (unusable) */ + + print_str ("E820 Map:\n"); + + for (k = 0; k < e820entries; k++) { + print_str (" - BaseAddr: "); + print_hex64 (e820info[k].BaseAddr); + print_str (" Length: "); + print_hex64 (e820info[k].Length); + print_str (" Type: "); + + if (e820info[k].Type < 1 || e820info[k].Type > 4) { + print_hex32 (e820info[k].Type); + print_str ("?"); + } else { + print_str (type[e820info[k].Type]); + } + + print_str ("\n"); + } +} + + +/* + *----------------------------------------------------------------------------- + * + * print_memory_map -- + * + * Print the generated memory map of usable memory to the console. + * + *----------------------------------------------------------------------------- + */ + +static void +print_memory_map (void) +{ + unsigned long k; + unsigned long amount = 0; + + print_str ("Usable memory:\n"); + + for (k = 0; k < mem_entries; k++) { + amount += memmap[k].memend - memmap[k].memstart; + + print_str (" - "); + print_hex32 (memmap[k].memstart); + print_str (" - "); + print_hex32 (memmap[k].memend); + print_str ("\n"); + } + + print_str (" "); + print_hex32 (amount); + print_str (" bytes total\n"); +} + + +/* + *----------------------------------------------------------------------------- + * + * create_memmap -- + * + * Create a map of usable memory from the e820 memory map returned by the + * BIOS. This map is then used to set up page tables for all of memory. + * + *----------------------------------------------------------------------------- + */ + +static void +create_memmap (struct e820info *e820info, unsigned long e820entries) +{ + unsigned long e, k; + + /* sort through the map and build a list of usable memory */ + for (e = 0, k = 0; k < e820entries; k++) { + if (e820info[k].Type != E820_TYPE_ARM) { + /* only care about usable memory here */ + continue; + } + + if (e820info[k].BaseAddr < 0x100000ULL) { + /* ignore entries below 1MB */ + continue; + } + + if (e > 0 + && e820info[k].BaseAddr == (unsigned long long)memmap[e-1].memend) { + /* this entry starts where the previous entry left off so merge them */ + memmap[e-1].memend = (unsigned long)(e820info[k].BaseAddr + + e820info[k].Length); + } else { + /* create new entry */ + memmap[e].memstart = (unsigned long)e820info[k].BaseAddr; + memmap[e].memend = (unsigned long)(e820info[k].BaseAddr + + e820info[k].Length); + e++; + } + } + + mem_entries = e; +} + + +/* + *----------------------------------------------------------------------------- + * + * set_up_page_tables -- + * + * Create page tables for all memory after bss_end. This will include + * recreating entries for some pages which were mapped in head.S. The + * resulting linear address space will be contiguous, regardless of + * what the underlying physical memory looks like. + * + *----------------------------------------------------------------------------- + */ + +static void +set_up_page_tables (void) +{ + unsigned long paddr, laddr; + unsigned long entry; + unsigned long *pde, *pte; + + /* first mark all pages up to bss_end as in use */ + for (laddr = 0; laddr < (unsigned long)&bss_end; laddr += PAGE_SIZE) { + /* no need to check for PD entry - it's been taken care of in head.S */ + pte = PTE (laddr); + + MARK_PAGE_USED (*pte); + } + + /* install pages in contiguous address space from bss_end to whenever */ + next_page = paddr = laddr = (unsigned long)&bss_end; + entry = 0; + +#if 0 + print_str ("laddr start "); + print_hex32 (laddr); + print_str ("\n"); +#endif + + while (1) { + /* check to see if we're at the end of the current physical range */ + if (paddr >= memmap[entry].memend) { + /* yes, use next entry */ + entry++; + + if (entry == mem_entries) { + /* done with page tables */ + break; + } + + paddr = memmap[entry].memstart; + } + + /* check the PDE for this page */ + pde = PDE (laddr); + + if (*pde == NULL) { + /* no PDE for this page - create a new table */ + unsigned long *next_ppage = PTE (next_page); + next_page += PAGE_SIZE; + + *pde = (*next_ppage & MASK4k) | 0x3; + MARK_PAGE_USED (*next_ppage); + +#if 0 + print_str ("Creating PDE: "); + print_hex32 ((unsigned long)pde); + print_str (" PTE: "); + print_hex32 (*next_ppage); + print_str (" laddr: "); + print_hex32 (laddr); + print_str ("\n"); +#endif + } + + pte = PTE (laddr); + *pte = paddr | 3; + + /* update vaddr */ + paddr += PAGE_SIZE; + laddr += PAGE_SIZE; + } + + page_limit = laddr - PAGE_SIZE; + +#if 0 + print_str ("page_limit: "); + print_hex32 (page_limit); + print_str ("\n"); + print_str ("next_page: "); + print_hex32 (next_page); + print_str ("\n"); +#endif +} + +/* + *----------------------------------------------------------------------------- + * + * + * + * + * + *----------------------------------------------------------------------------- + */ + +void +create_heap (void) +{ + unsigned long e820entries = *((unsigned long *)E820_MAP); + struct e820info *e820info = (struct e820info *)(E820_MAP + 4); + + print_e820_map (e820info, e820entries); + + create_memmap (e820info, e820entries); + + print_memory_map (); + + set_up_page_tables (); +} + + +/* + *----------------------------------------------------------------------------- + * + * get_pages -- + * + * Allocate a number of contiguous pages. If the requested number of + * pages can not be allocated, fewer pages are allocated and the + * actual number is returned. + * + * Input: + * pages_req: + * pages_ret: + * + * Returns: + * Pointer to the start of the returned pages. + * + *----------------------------------------------------------------------------- + */ + +void * +get_pages (unsigned long pages_req, unsigned long *pages_ret) +{ + unsigned long pages, k; + unsigned long npages_ret; + + pages = next_page; + npages_ret = 0; + + for (k = 0; k < pages_req; k++) { + unsigned long *pte = PTE (pages + k * PAGE_SIZE); + + if (PAGE_USED (*pte)) { + break; + } + + MARK_PAGE_USED (*pte); + npages_ret++; + next_page += PAGE_SIZE; + + if (next_page > page_limit) { + /* if the limit of mem has been reached, restart next_page */ + next_page = (unsigned long)&bss_end; + break; + } + } + + /* skip to next unused page */ + while (PAGE_USED (*(PTE (next_page)))) { + next_page += PAGE_SIZE; + if (next_page > page_limit) { + PANIC (MEMORY_EXHAUSTED); + } + } + + /* if the caller really doesn't care... */ + if (pages_ret != NULL) { + *pages_ret = npages_ret; + } + + return (void *)pages; +} diff --git a/cpuid/serial.c b/cpuid/serial.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cpuid/serial.c diff --git a/cpuid/setsectors.pl b/cpuid/setsectors.pl new file mode 100644 index 0000000..812a001 --- /dev/null +++ b/cpuid/setsectors.pl @@ -0,0 +1,46 @@ +#!/usr/bin/perl +# +#----------------------------------------------------------------------------- +# +# setsectors.pl +# +# Calculate the number of 512 byte sectors taken up by cpuid, subtracting +# one for the initial sector, and write the value to the location in +# the first sector of number_of_sectors. That location is read from +# the linker map file, the name of which is passed on the command line. +# +#----------------------------------------------------------------------------- + +use strict; +use warnings; + +use POSIX (); + + +my $mapfile = shift; +my $debug = shift; + +my $address; + +open (MAP, "<$mapfile") or die "Unable to open $mapfile: $!\n"; + +foreach my $line (<MAP>) { + $address = $1, last if $line =~ m/(0x[0-9a-fA-F]+)\s+number_of_sectors/; +} + +close MAP; + +print sprintf ("address: %#x\n", hex ($address) - 0x7c00) if defined $debug; + +my $fsize = (stat ('boot'))[7]; +my $nsectors = POSIX::ceil (($fsize - 512) / 512); + +print "fsize: $fsize, nsectors: $nsectors\n" if defined $debug; + +open (BOOT, "+<boot") or die "Unable to open boot sector: $!\n"; +binmode BOOT; # just in case + +sysseek BOOT, (hex ($address) - 0x7c00), 0; +syswrite BOOT, pack ('S', $nsectors), 2, 0; + +close BOOT; diff --git a/cpuid/spinlock.c b/cpuid/spinlock.c new file mode 100644 index 0000000..57993b3 --- /dev/null +++ b/cpuid/spinlock.c @@ -0,0 +1,31 @@ +/* + *----------------------------------------------------------------------------- + * + * spinlock.c -- + * + * Simple spinlock implementation. + * + *----------------------------------------------------------------------------- + */ + +#include <cpuid.h> + + +void +spinlock_acquire (spinlock *lock) +{ + asm (" movl %1, %%ecx\n" + "1: movl %2, %%eax\n" + " lock\n" + " cmpxchgl %%ecx, %0\n" + " jz 1b\n" + : "=m" (lock->locked) + : "i" (LOCKED), "i" (UNLOCKED) + : "eax", "ecx"); +} + +void +spinlock_release (spinlock *lock) +{ + lock->locked = UNLOCKED; +} diff --git a/cpuid/spinlock.h b/cpuid/spinlock.h new file mode 100644 index 0000000..7a3bc99 --- /dev/null +++ b/cpuid/spinlock.h @@ -0,0 +1,27 @@ +/* + *----------------------------------------------------------------------------- + * + * spinlock.h -- + * + * Implementation of a simple spinlock. + * + *----------------------------------------------------------------------------- + */ + +#ifndef _SPINLOCK_H +#define _SPINLOCK_H + +enum lock_state { + UNLOCKED, LOCKED +}; + +typedef struct _spinlock { + volatile enum lock_state locked; +} spinlock; + +#define SPINLOCK_NEW { UNLOCKED } + +extern void spinlock_acquire (spinlock *); +extern void spinlock_release (spinlock *); + +#endif /* !_SPINLOCK_H */ diff --git a/cpuid/stdio.c b/cpuid/stdio.c new file mode 100644 index 0000000..2afedf6 --- /dev/null +++ b/cpuid/stdio.c @@ -0,0 +1,303 @@ +/* + *----------------------------------------------------------------------------- + * + * stdio.c -- + * + * Minimal implementation of ISO C's stdio.h. + * + *----------------------------------------------------------------------------- + */ + +/* FIXME: this file is a mess */ + +#include <cpuid.h> + +void +process_format (char *buffer, int *p, int buflen, char *fmt, int *k) +{ +} + +enum size { + BYTE = -2, SHORT, INT, LONG, LONGLONG +}; + +long long +divs10(long long n) { + long long q, r; + + n = n + (n>>63 & 9); + + q = (n >> 1) + (n >> 2); + q = q + (q >> 4); + q = q + (q >> 8); + q = q + (q >> 16); + q = q >> 3; + r = n - q*10; + + return q + ((r + 6) >> 4); +} + +#define insert(c) ({ buffer[p] = (c); \ + p++; \ + if (p >= buflen) { \ + buflen *= 2; \ + buffer = realloc (buffer, buflen + 1); \ + } }) + + +/* + *----------------------------------------------------------------------------- + * + * printf -- + * + * Light version of the real printf. Current format characters + * recognized are: + * + * c + * s + * d + * x + * % + * + *----------------------------------------------------------------------------- + */ + +int +printf (char *fmt, ...) +{ + char *buffer; + int buflen, k, p, b; + int width; /* field width: 0 = unlimited */ + int zero_pad; /* pad left with zeros: 0 = no, 1 = yes */ + int align; /* 0 = right, 1 = left */ + enum size size; /* 0 = normal, 1 = l, 2 = ll, -1 = h, -2 = hh */ +#define TBUFLEN 64 + char tbuf[TBUFLEN]; + int tbp; + char byte; + short short_int; + long long_int; + long long longlong_int; + char *pint = NULL; + long long allint = 0; + int nintbytes = 0; + char fmt_char; + + va_list ap; + + va_start (ap, fmt); + + buflen = 2 * strlen (fmt); + + buffer = malloc (buflen + 1); + buffer[buflen] = '\0'; + + p = 0; + + for (k = 0; k < strlen (fmt); k++) { + width = 0; /* field width: 0 = unlimited */ + zero_pad = 0; /* pad left with zeros: 0 = no, 1 = yes */ + align = 0; /* 0 = right, 1 = left */ + size = INT; + tbp = TBUFLEN - 1; + + + if (fmt[k] != '%') { + insert (fmt[k]); + continue; + } + + /* skip past initial % */ + k++; + + /* %% */ + + if (fmt[k] == '%') { + insert ('%'); + continue; + } + + if (fmt[k] == '-') { + align = 1; + k++; + } + + if (fmt[k] == '0') { + zero_pad = 1; + k++; + } + + while (fmt[k] >= '0' && fmt[k] <= '9') { + width = 10 * width + (fmt[k] - '0'); + k++; + } + + if (fmt[k] == '\0') { + break; + } + + if (fmt[k] == 'h') { + size--; + k++; + } + if (fmt[k] == 'h') { + size--; + k++; + } + if (fmt[k] == 'l') { + size++; + k++; + } + if (fmt[k] == 'l') { + size++; + k++; + } + + /* use fmt_char to be able to do format substitutions */ + fmt_char = fmt[k]; + + /* %p becomes 0x%08x */ + if (fmt_char == 'p') { + fmt_char = 'x'; + size = LONG; + width = 8; + zero_pad = 1; + + insert ('0'); + insert ('x'); + } + + /* %s */ + + if (fmt_char == 's') { + char *arg = va_arg (ap, char *); + + /* copy string left justified */ + if (width > strlen (arg) && align) { + for (b = 0; b < strlen (arg); b++) { + insert (arg[b]); + } + } + + /* pad with spaces as needed */ + if (width > strlen (arg)) { + int pad; + + for (pad = 0; pad < width - strlen (arg); pad++) { + insert (' '); + } + } + + /* right justified, copy string */ + if (!align) { + for (b = 0; b < strlen (arg); b++) { + insert (arg[b]); + } + } + } + + /* %c */ + + if (fmt_char == 'c') { + char c = (char)va_arg (ap, int); + + insert (c); + } + + /* %d, %x */ + + if (fmt_char == 'x' || fmt_char == 'd') { + switch (size) { + case BYTE: + byte = (char)va_arg (ap, int); + pint = &byte; + allint = (long long)byte; + nintbytes = 1; + break; + case SHORT: + short_int = (short)va_arg (ap, int); + pint = (char *)&short_int; + allint = (long long)short_int; + nintbytes = 2; + break; + case INT: + case LONG: + long_int = va_arg (ap, long); + pint = (char *)&long_int; + allint = (long long)long_int; + nintbytes = 4; + break; + case LONGLONG: + longlong_int = va_arg (ap, long); + pint = (char *)&longlong_int; + allint = longlong_int; + nintbytes = 8; + break; + } + + tbp = TBUFLEN; + + /* x */ + if (fmt_char == 'x') { + char hex[] = "0123456789abcdef"; + + for (b = 0; b < nintbytes; b++) { + tbp--; + tbuf[tbp] = hex[*(pint+b) & 0xf]; + tbp--; + tbuf[tbp] = hex[(*(pint+b) >> 4) & 0xf]; + } + } + + /* d */ + if (fmt_char == 'd') { + long long d10q; + + while (allint) { + tbp--; + + d10q = divs10 (allint); + tbuf[tbp] = (char)('0' + (allint - 10*d10q)); + allint = d10q; + } + } + + /* get rid of leading zeros */ + while (tbuf[tbp] == '0' && tbp < TBUFLEN - 1) { + tbp++; + } + + /* pad value if requested */ + if (!align) { + for (b = 0; b < width - (TBUFLEN - tbp); b++) { + insert (zero_pad ? '0' : ' '); + } + } + + /* copy the formatted number */ + for (b = tbp; b < TBUFLEN; b++) { + insert (tbuf[b]); + } + + /* left justify if requested (and there's room) */ + if (align && width > (TBUFLEN - tbp)) { + for (b = 0; b < width - (TBUFLEN - tbp); b++) { + insert (' '); + } + } + + /* end of %x or %d */ + } + } + + + insert ('\0'); + + print_str (buffer); + + free (buffer); + + va_end (ap); + + return 0; +} diff --git a/cpuid/stdio.h b/cpuid/stdio.h new file mode 100644 index 0000000..daca518 --- /dev/null +++ b/cpuid/stdio.h @@ -0,0 +1,19 @@ +/* + *----------------------------------------------------------------------------- + * + * stdio.h -- + * + * Minimal implementation of a subset of ISO C's stdio.h. + * + *----------------------------------------------------------------------------- + */ + +#ifndef _STDIO_H +#define _STDIO_H + +#include <stdarg.h> + +extern int printf (char *fmt, ...) __attribute__ ((format (printf, 1, 2))); + + +#endif /* !_STDIO_H */ diff --git a/cpuid/stdlib.h b/cpuid/stdlib.h new file mode 100644 index 0000000..854286c --- /dev/null +++ b/cpuid/stdlib.h @@ -0,0 +1,24 @@ +/* + *----------------------------------------------------------------------------- + * + * stdlib.h -- + * + * Subset of ISO C's stdlib.h. + * + *----------------------------------------------------------------------------- + */ + +#ifndef _STDLIB_H +#define _STDLIB_H + +#define NULL 0 + +#define MIN(x,y) ((x < y) ? x : y) + +typedef unsigned long size_t; + +extern void *malloc (size_t amt) __attribute__ ((malloc)); +extern void free (void *mem); +extern void *realloc (void *mem, size_t amt) __attribute__ ((malloc)); + +#endif /* !_STDLIB_H */ diff --git a/cpuid/string.c b/cpuid/string.c new file mode 100644 index 0000000..0dfe8e0 --- /dev/null +++ b/cpuid/string.c @@ -0,0 +1,197 @@ +/* + *----------------------------------------------------------------------------- + * + * string.c -- + * + * Implementation of various ISO C functions found in string.h. + * + *----------------------------------------------------------------------------- + */ + +#include <cpuid.h> + +/* + *----------------------------------------------------------------------------- + * + * + * + * + * + *----------------------------------------------------------------------------- + */ + +// strstr + + +/* + *----------------------------------------------------------------------------- + * + * + * + * + * + *----------------------------------------------------------------------------- + */ + +void * +memcpy (void *dest, const void *src, size_t n) +{ + size_t k; + + for (k = 0; k < n; k++) { + *((char *)dest + k) = *((char *)src + k); + } + + return dest; +} + +/* + *----------------------------------------------------------------------------- + * + * + * + * + * + *----------------------------------------------------------------------------- + */ + +void * +memset (void *s, int c, size_t n) +{ + size_t k; + + for (k = 0; k < n; k++) { + *((char *)s) = (char)c; + } + + return s; +} + +/* + *----------------------------------------------------------------------------- + * + * + * + * + * + *----------------------------------------------------------------------------- + */ + +size_t +strlen (const char *s) +{ + size_t n = 0; + + while (*s++) n++; + + return n; +} + +/* + *----------------------------------------------------------------------------- + * + * + * + * + * + *----------------------------------------------------------------------------- + */ + +int +strncmp (const char *s1, const char *s2, size_t n) +{ + size_t k; + + for (k = 0; k < MIN (n, MIN (strlen (s1), strlen (s2))); k++) { + if (s1[k] < s2[k]) { + return -1; + } else if (s1[k] > s2[k]) { + return 1; + } + } + + return 0; +} + +/* + *----------------------------------------------------------------------------- + * + * + * + * + * + *----------------------------------------------------------------------------- + */ + +int +strcmp (const char *s1, const char *s2) +{ + return strncmp (s1, s2, MIN (strlen (s1), strlen (s2))); +} + +/* + *----------------------------------------------------------------------------- + * + * + * + * + * + *----------------------------------------------------------------------------- + */ + +char * +strncpy (char *dest, const char *src, size_t n) +{ + return (char *)memcpy ((void *)dest, (void *)src, n); +} + + +/* + *----------------------------------------------------------------------------- + * + * + * + * + * + *----------------------------------------------------------------------------- + */ + +char * +strcpy (char *dest, const char *src) +{ + return strncpy (dest, src, strlen (src) + 1); +} + +/* + *----------------------------------------------------------------------------- + * + * + * + * + * + *----------------------------------------------------------------------------- + */ + +char * +strncat (char *dest, const char *src, size_t n) +{ + strncpy (dest + strlen (dest), src, n); + + return dest; +} + +/* + *----------------------------------------------------------------------------- + * + * + * + * + * + *----------------------------------------------------------------------------- + */ + +char * +strcat (char *dest, const char *src) +{ + return strncat (dest, src, strlen (src) + 1); +} diff --git a/cpuid/string.h b/cpuid/string.h new file mode 100644 index 0000000..5c78729 --- /dev/null +++ b/cpuid/string.h @@ -0,0 +1,25 @@ +/* + *----------------------------------------------------------------------------- + * + * string.h -- + * + * Subset of the ISO C header file string.h. + * + *----------------------------------------------------------------------------- + */ + +#ifndef _STRING_H +#define _STRING_H + +#include <stdlib.h> + +extern void *memcpy (void *dest, const void *src, size_t n); +extern void *memset (void *s, int c, size_t n); + +extern size_t strlen (const char *s); +extern char *strncat (char *dest, const char *src, size_t n); +extern char *strcat (char *dest, const char *src); +extern char *strncpy (char *dest, const char *src, size_t n); +extern char *strcpy (char *dest, const char *src); + +#endif /* !_STRING_H */ diff --git a/cpuid/timer.c b/cpuid/timer.c new file mode 100644 index 0000000..29941be --- /dev/null +++ b/cpuid/timer.c @@ -0,0 +1,87 @@ +/* + *----------------------------------------------------------------------------- + * + * timer.c -- + * + * Handle the timer interrupt. + * + *----------------------------------------------------------------------------- + */ + +#include <cpuid.h> + +#define TIMER_INTERRUPT 0x20 + +#define TICK_HZ 64 + +/* spin at ~8Hz */ +#define TICK_MASK 0xf + +#define INPUT_TICKS 1193181 + +void +tick (void) +{ + static unsigned long ticks = 0; + static unsigned long v = 0; + char spinner[] = { '|', '/', '-', '\\' }; + char *vgabuf = (char *)0xb8000; + + acknowledge_irq (); + + ticks++; + + if (ticks & TICK_MASK) { + return; + } + + vgabuf[0] = spinner[v & 0x3]; + vgabuf[1] = 0x7; + + v++; +} + +extern void tick_stub (void); +asm (" .global tick_stub\n" + "tick_stub:\n\t" + " call tick\n\t" + " iret\n"); + +void +enable_timer (void) +{ + install_iv (TIMER_INTERRUPT, &tick_stub, INTERRUPT); + + outb (inb (0x21) & 0xfe, 0x21); +} + +void +disable_timer (void) +{ + outb (inb (0x21) & 0x01, 0x21); +} + +void +set_timer_interval (unsigned long interval) +{ + unsigned long counter; + + if (interval < 19) { + /* 18.2Hz is as low as this goes */ + interval = 19; + } + + counter = INPUT_TICKS / interval; + + outb (0x36, 0x43); + outb ((char)(counter & 0xff), 0x40); + outb ((char)((counter >> 8) & 0xff), 0x40); +} + +void +timer_init (void) +{ + set_timer_interval (TICK_HZ); + + enable_timer (); +} diff --git a/cpuid/video.c b/cpuid/video.c new file mode 100644 index 0000000..e5f1965 --- /dev/null +++ b/cpuid/video.c @@ -0,0 +1,251 @@ +/* + *----------------------------------------------------------------------------- + * + * video.c -- + * + * Routines for printing to the VGA color text mode buffer. + * + *----------------------------------------------------------------------------- + */ + +#include <cpuid.h> + + +/* VGA mem start address */ +#define VGAMEM 0xb8000 + +#define NROWS 25 +#define NCOLUMNS 80 + +#define COLOR 0x07 + +#define index(r,c) (2 * ((r) * NCOLUMNS + (c))) +#define at_end_of_line() (col == NCOLUMNS) +#define at_last_line() (row == NROWS - 1) + + +static char *vgamem = (char *)VGAMEM; + +static unsigned long row = 0; +static unsigned long col = 0; + + + +/* + *----------------------------------------------------------------------------- + * + * scroll_up -- + * + * Scroll the VGA buffer up one line, blanking the line at the bottom. + * + *----------------------------------------------------------------------------- + */ + +static void +scroll_up (void) +{ + memcpy ((void *)VGAMEM, (void *)(VGAMEM + NCOLUMNS * 2), + ((NROWS - 1) * NCOLUMNS * 2)); + + /* zero the newly cleared last line */ + asm ("xorl %%eax, %%eax\n" + "\tmovl %0, %%ecx\n" + "\tmovl %1, %%ebx\n" + "1:\tmovl %%eax, (%%ebx)\n" + "\taddl $4, %%ebx\n" + "\tloop 1b\n" + :: "i" (NCOLUMNS / 2), + "i" (VGAMEM + (NROWS - 1) * NCOLUMNS * 2)); + + col = 0; +} + +void +goto_xy (unsigned long x, unsigned long y) +{ + col = (x > NCOLUMNS) ? NCOLUMNS : x; + row = (y > NROWS) ? NROWS : y; +} + +void +get_xy (unsigned long *x, unsigned long *y) +{ + *x = col; + *y = row; +} + + +void +clear_screen (void) +{ + unsigned long *buf = (unsigned long *)vgamem; + unsigned long cur; + + for (cur = 0; cur < 0x2000; cur++) { + buf[cur] = 0; + } + + col = 0; + row = 0; +} + + +static void +newline (void) +{ + if (at_last_line ()) { + scroll_up (); + } else { + row++; + } + + col = 0; +} + +static void +_putchar (char c) +{ + if (at_end_of_line ()) { + newline (); + } else if (c == '\n') { + newline (); + return; + } + + *(vgamem + index (row, col)) = c; + *(vgamem + index (row, col) + 1) = COLOR; + + col++; +} + +void +print_str (char *msg) +{ + char c; + int k = 0; + + while ((c = msg[k])) { + _putchar (c); + k++; + } + + log_msg (msg); +} + +void +putchar (char c) +{ + char buf[2]; + + buf[0] = c; + buf[1] = '\0'; + + print_str (buf); +} + +void +print_hex8 (unsigned char val) +{ + char str[3]; + char vals[] = "0123456789abcdef"; + int k; + + for (k = 0; k < 2; k++) { + str[k] = vals[(val >> ((1-k) * 4)) & 0xf]; + } + str[2] = '\0'; + + print_str (str); +} + +void +print_hex16 (unsigned short val) +{ + char str[5]; + char vals[] = "0123456789abcdef"; + int k; + + for (k = 0; k < 4; k++) { + str[k] = vals[(val >> ((3-k) * 4)) & 0xf]; + } + str[4] = '\0'; + + print_str (str); +} + +void +print_hex32 (unsigned long val) +{ + char str[9]; + char vals[] = "0123456789abcdef"; + int k; + + for (k = 0; k < 8; k++) { + str[k] = vals[(val >> ((7-k) * 4)) & 0xf]; + } + str[8] = '\0'; + + print_str (str); +} + +void +print_hex64 (unsigned long long val) +{ + char str[17]; + char vals[] = "0123456789abcdef"; + int k; + + for (k = 0; k < 16; k++) { + str[k] = vals[(val >> ((15-k) * 4)) & 0xf]; + } + str[16] = '\0'; + + print_str (str); +} + +void +dump_cpu (void) +{ + unsigned long eax, ebx, ecx, edx, esi, edi, ebp, esp; + unsigned long cr0, cr2, cr3, cr4, eflags; + + asm ("movl %%eax, %[eax]\n\t" + "movl %%ebx, %[ebx]\n\t" + "movl %%ecx, %[ecx]\n\t" + "movl %%edx, %[edx]\n\t" + "movl %%esi, %[esi]\n\t" + "movl %%edi, %[edi]\n\t" + "movl %%ebp, %[ebp]\n\t" + "movl %%esp, %[esp]\n\t" + "movl %%cr0, %%eax\n\t" + "movl %%eax, %[cr0]\n\t" + "movl %%cr2, %%eax\n\t" + "movl %%eax, %[cr2]\n\t" + "movl %%cr3, %%eax\n\t" + "movl %%eax, %[cr3]\n\t" + "movl %%cr4, %%eax\n\t" + "movl %%eax, %[cr4]\n\t" + "pushf\n\t" + "popl %%eax\n" + "movl %%eax, %[eflags]\n\t" + : [eax] "=m" (eax), + [ebx] "=m" (ebx), + [ecx] "=m" (ecx), + [edx] "=m" (edx), + [esi] "=m" (esi), + [edi] "=m" (edi), + [ebp] "=m" (ebp), + [esp] "=m" (esp), + [cr0] "=m" (cr0), + [cr2] "=m" (cr2), + [cr3] "=m" (cr3), + [cr4] "=m" (cr4), + [eflags] "=m" (eflags) + :); + + printf ("EAX %08lx EBX %08lx ECX %08lx EDX %08lx\n" + "ESI %08lx EDI %08lx EBP %08lx ESP %08lx\n" + "CR0 %08lx CR2 %08lx CR3 %08lx CR4 %08lx\n" + "EFLAGS %08lx\n", + eax, ebx, ecx, edx, esi, edi, ebp, esp, cr0, cr2, cr3, cr4, eflags); +} |
