aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon duSaint2022-05-03 10:13:04 -0700
committerJon duSaint2022-05-03 10:13:04 -0700
commit1b86e776c0eff16184b3d3e9c31d20214c2b5d68 (patch)
tree52cbad8481865ccbfb02ae243dbab7fe748a8507
parent1d7ce9124a2fa3cbe8dc5761228ca29abf20659f (diff)

cpuid: add old project

-rw-r--r--README9
-rw-r--r--cpuid/Makefile45
-rw-r--r--cpuid/bochs.cfg47
-rw-r--r--cpuid/boot.S282
-rw-r--r--cpuid/cpuid.h206
-rw-r--r--cpuid/entry.c39
-rw-r--r--cpuid/head.S569
-rw-r--r--cpuid/igate.S134
-rw-r--r--cpuid/interrupt.c406
-rw-r--r--cpuid/interrupt.h63
-rw-r--r--cpuid/keyboard.c200
-rw-r--r--cpuid/keyboard.h160
-rw-r--r--cpuid/ld.conf75
-rw-r--r--cpuid/libcpuid/cpuid.c3854
-rw-r--r--cpuid/log.c76
-rw-r--r--cpuid/malloc.c469
-rw-r--r--cpuid/memory.c376
-rw-r--r--cpuid/serial.c0
-rw-r--r--cpuid/setsectors.pl46
-rw-r--r--cpuid/spinlock.c31
-rw-r--r--cpuid/spinlock.h27
-rw-r--r--cpuid/stdio.c303
-rw-r--r--cpuid/stdio.h19
-rw-r--r--cpuid/stdlib.h24
-rw-r--r--cpuid/string.c197
-rw-r--r--cpuid/string.h25
-rw-r--r--cpuid/timer.c87
-rw-r--r--cpuid/video.c251
28 files changed, 8020 insertions, 0 deletions
diff --git a/README b/README
index da2c346..9cfffb5 100644
--- a/README
+++ b/README
@@ -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
![Decomp](decomp/decomp.png)
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, &divide_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",
+ &reg,
+ &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);
+}