Monday, November 29, 2010

CMOS read/wirte in coreboot/Linux

0x70 is the CMOS memory address I/O port,and 0x71 is the CMOS memory data I/O port

There are 128 bytes data in CMOS, or say 1024 bits in CMOS. The layout format of CMOS is at:
/coreboot/src/mainboard/asus/m2v-mx_se/cmos.layout
or link
http://www.bioscentral.com/misc/cmosmap.htm


If you want to read the 125th byte of CMOS memory:

#include <arch/io.h>
unsigned char addr = 125;
unsigned char data
outb(addr, 0x70);
data = inb(0x71)

If you want to write to the 125th byte of CMOS memory:

#include <arch/io.h>
unsigned char addr = 125;
unsgined char data = 0x01;
outb(addr, 0x70);
outb(data, 0x71);
There are also cmos_read() and cmos_write function at /coreboot/src/include/pc80/mc146818rtc.h

run previous command in history commands

!! : to run the previous command
^P : move up through history list, one command at a time. (Up arrow key)
^N : move down (or Down arrow key).
!n : run nth command in history list. where n is a number from your history list.
!n:p : only preview command number n (will not execute the command).
!string : Run most recent command starting with characters in string.

Tuesday, November 16, 2010

assembly tutorial

http://docs.sun.com/app/docs/doc/817-5477/ennab?a=view

 There are two types of lables: symbolic and numeric.

Symbolic Labels

A symbolic label consists of an identifier (or symbol) followed by a colon (:) (ASCII 0x3A). Symbolic labels must be defined only once. Symbolic labels have global scope and appear in the object file's symbol table.
Symbolic labels with identifiers beginning with a period (.) (ASCII 0x2E) are considered to have local scope and are not included in the object file's symbol table.

Numeric Labels

A numeric label consists of a single digit in the range zero (0) through nine (9) followed by a colon (:). Numeric labels are used only for local reference and are not included in the object file's symbol table. Numeric labels have limited scope and can be redefined repeatedly.
When a numeric label is used as a reference (as an instruction operand, for example), the suffixes b (“backward”) or f (“forward”) should be added to the numeric label. For numeric label N, the reference Nb refers to the nearest label N defined before the reference, and the reference Nf refers to the nearest label N defined after the reference. The following example illustrates the use of numeric labels:
1:          / define numeric label "1"
one:        / define symbolic label "one"

/ ... assembler code ...

jmp   1f    / jump to first numeric label "1" defined
            / after this instruction
            / (this reference is equivalent to label "two")

jmp   1b    / jump to last numeric label "1" defined
            / before this instruction
            / (this reference is equivalent to label "one")

1:          / redefine label "1"
two:        / define symbolic label "two"

jmp   1b    / jump to last numeric label "1" defined
            / before this instruction
            / (this reference is equivalent to label "two")

Operands
An x86 instruction can have zero to three operands. Operands are separated by commas (,) (ASCII 0x2C). For instructions with two operands, the first (lefthand) operand is the source operand, and the second (righthand) operand is the destination operand (that is, source->destination).

Note – The Intel assembler uses the opposite order (destination<-source) for operands.

Operands can be immediate (that is, constant expressions that evaluate to an inline value), register (a value in the processor number registers), or memory (a value stored in memory). An indirect operand contains the address of the actual operand value. Indirect operands are specified by prefixing the operand with an asterisk (*) (ASCII 0x2A). Only jump and call instructions can use indirect operands.
  • Immediate operands are prefixed with a dollar sign ($) (ASCII 0x24)
  • Register names are prefixed with a percent sign (%) (ASCII 0x25)
  • Memory operands are specified either by the name of a variable or by a register that contains the address of a variable. A variable name implies the address of a variable and instructs the computer to reference the contents of memory at that address. Memory references have the following syntax:segment:offset(base, index, scale).
    • Segment is any of the x86 architecture segment registers. Segment is optional: if specified, it must be separated from offset by a colon (:). If segment is omitted, the value of %ds (the default segment register) is assumed.
    • Offset is the displacement from segment of the desired memory value. Offset is optional.
    • Base and index can be any of the general 32–bit number registers.
    • Scale is a factor by which index is to be multipled before being added to base to specify the address of the operand. Scale can have the value of 1, 2, 4, or 8. If scale is not specified, the default value is 1.
    Some examples of memory addresses are:
    movl var, %eax
    Move the contents of memory location var into number register %eax.
    movl %cs:var, %eax
    Move the contents of memory location var in the code segment (register %cs) into number register %eax.
    movl $var, %eax
    Move the address of var into number register %eax.
    movl array_base(%esi), %eax
    Add the address of memory location array_base to the contents of number register %esi to determine an address in memory. Move the contents of this address into number register %eax.
    movl (%ebx, %esi, 4), %eax
    Multiply the contents of number register %esi by 4 and add the result to the contents of number register %ebx to produce a memory reference. Move the contents of this memory location into number register %eax.
    movl struct_base(%ebx, %esi, 4), %eax
    Multiply the contents of number register %esi by 4, add the result to the contents of number register %ebx, and add the result to the address of struct_base to produce an address. Move the contents of this address into number register %eax.


Assembler Directives

Directives are commands that are part of the assembler syntax but are not related to the x86 processor instruction set. All assembler directives begin with a period (.) (ASCII 0x2E).
.align integer, pad
The .align directive causes the next data generated to be aligned modulo integer bytes. Integer must be a positive integer expression and must be a power of 2. If specified, pad is an integer bye value used for padding. The default value of pad for the text section is 0x90 (nop); for other sections, the default value of pad is zero (0).
.bss
The .bss directive changes the current section to .bss.
.bss symbol, integer
Define symbol in the .bss section and add integer bytes to the value of the location counter for .bss. When issued with arguments, the .bss directive does not change the current section to .bss. Integer must be positive.
.
.globl symbol1, symbol2, ..., symbolN
The .globl directive declares each symbol in the list to be global. Each symbol is either defined externally or defined in the input file and accessible in other files. Default bindings for the symbol are overridden. A global symbol definition in one file satisfies an undefined reference to the same global symbol in another file. Multiple definitions of a defined global symbol are not allowed. If a defined global symbol has more than one definition, an error occurs. The .globl directive only declares the symbol to be global in scope, it does not define the symbol.
.group group, section, #comdat
The .group directive adds section to a COMDAT group. Refer to COMDAT Section in Linker and Libraries Guide for additional information about COMDAT.
.section section, attributes
The .section directive makes section the current section. If section does not exist, a new section with the specified name and attributes is created. If section is a non-reserved section, attributes must be included the first time section is specified by the .section directive.

translate linear address(virtual address) to physical address

First of all, we need to know the CR3, this register stores the bases address of page directory.

32 bits of linear address are divided into three fields:
directory: most significant 10 bits
table: intermediate 10 bits
offset: least significant 12 bits

there are 1024 (2^10 bytes / 4 bytes)entries in page directory table
there are 1024 (2^10 bytes / 4 bytes)entries in page table table


This link explain the structure of page directory entry and page table entry:
http://valhalla.bofh.pl/~l4mer/WDM/secureread/pde-pte.htm

 I also wrote a program to find all kernel memory in a memory dump: the assumption is I need to know CR3 of kernel mode.
here is the program:


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define NUMOFARG 3
#define SMALLBUFSIZE 20
#define NUMPDE 1024
#define NUMPTE 1024
#define COUNTER1 1024*1024*256
#define COUNTER2 1024*1024*4
#define COUNTER3 1024*4

int main(int argc, char **argv)
{
    if(argc != NUMOFARG)
    {
    fprintf(stderr, "Usage: %s MemFile RegFile\n", argv[0]);
    exit(1);
    }

    /* Generate new memory file with size of 256 MB
     * which initial to 0 */
    FILE *newMemFile = fopen("newMemDump", "w+");
    if(newMemFile == NULL)
    {
    fprintf(stderr, "Cannot create new memory file\n");
    exit(1);
    }

    int m;
    for(m = 0; m < COUNTER1; m++)
    fputc('\0', newMemFile);
   
    /* Read the CR3 from register file */
    FILE *regFile = fopen(argv[2], "r");
    if(regFile == NULL)
    {
    fprintf(stderr, "Cannot open register file\n");
    exit(1);
    }

    char regName[SMALLBUFSIZE];
    char regEqual[SMALLBUFSIZE];
    unsigned int regAddr;
    int ret;

    int numOf4K = 0;
    int numOf4M = 0;

    while(1)
    {
    ret = fscanf(regFile, "%s\t%s\t%x\n", regName, regEqual, &regAddr);
//    printf("%s\t%s\t%x\n", regName,regEqual, regAddr);
   
    if(strcmp(regName, "CR3") == 0)
        break;
    if(ret == 0 || ferror(regFile) || feof(regFile))
        break;
    }

    fclose(regFile);

    /* Read the memory file */
    FILE *memFile = fopen(argv[1], "r");
    if(memFile == NULL)
    {
    fprintf(stderr, "Cannot open memroy file\n");
    exit(1);
    }

    /* Loop for Each Page Directory Entry
     * There are 2^10 = 1024 entries in PDE
     * We will check the present bit in each PDE
     * */
    int i, j;
    unsigned int CR3 = regAddr;
   
    // Store the content of Page Direcotry Entry
    unsigned int PDEContent;
    unsigned int PTEContent;

    for(i = 0; i < NUMPDE; i++)
    {
    fseek(memFile, CR3+4*i, SEEK_SET);

    if(fread(&PDEContent, 4, 1, memFile) != 1)
    {
        fprintf(stderr, "Read Page Direcotry Entry Error\n");
        exit(1);
    }

    // if the last bit of the PDE entry is 0, this PDE entry is
    // not present. we just jump to next loop
    if(PDEContent%2 == 0)
        continue;

//    printf("%x\n", PDEContent);

    // check if the 4M bit has been setted
    if(PDEContent & 0x00000080 )
    {
        // This PDEContent has the 4M bit set
        numOf4M++;
        // copy the memory file to new memory file
        // 1. seek the original file indicator
        // 2. seek the new meory file indicator
        // 3. copy the content to the new memory file
        PDEContent &= 0xFFFFF000;
        fseek(newMemFile, PDEContent, SEEK_SET);
        fseek(memFile, PDEContent, SEEK_SET);
        for(m = 0; m < COUNTER2; m++)
        fputc(fgetc(memFile), newMemFile);
    }
    else
    {
        // This PDE has 4KB bit set, so we need to go though page
        // table entry.       
        PDEContent &= 0xFFFFF000;
       
        for(j = 0; j < NUMPTE; j++)
        {
        fseek(memFile, PDEContent+4*j, SEEK_SET);

        if(fread(&PTEContent, 4, 1, memFile) != 1)
        {
            fprintf(stderr, "Read Page Table Entry Error\n");
            exit(1);
        }
        // if the present bit is not set in the Page Table Entry
        // we jump to next iteration
        if(PTEContent%2 == 0)
            continue;

        numOf4K++;
        PTEContent &= 0xFFFFF000;
        fseek(newMemFile, PTEContent, SEEK_SET);
            fseek(memFile, PTEContent, SEEK_SET);
            for(m = 0; m < COUNTER3; m++)
            fputc(fgetc(memFile), newMemFile);
        }
    }
    }
    fclose(newMemFile);
    fclose(memFile);

    printf("num of 4M is: %d\n", numOf4M);
    printf("Num of 4K is: %d\n", numOf4K);
    printf("Total kenerl memory size is: %d K\n", numOf4M*4096 + numOf4K);
    return 1;
}

segment selectors, segmentation registers, segment descirptors

*****************
Protected Mode
*****************
Segment Selector: 16 bits field.
15-3: index of entries in gdt or in ldt
2: table indicator (0 descriptor stores in gdt; 1 descriptor stores in ldt )
1-0: requester privilege level(in CS register, it is current privilege level called CPL, 0 denotes kernel mode, 3 denotes user mode.)

Segmentation Registers: is to hold segment selectors, these registers are called cs, ss, ds, es, fs and gs.
cs: The code segment registers, which points to a segment containing program insturction
ss: The stack segment registers, which points to a segment containing the current program stack
ds: The data segment registers, which points to a segment containing global and static data

Segment Descriptor: 8 bytes, it describes the segment characteristics.
segment descirptor are stored either in the global descriptors table (GDT) or in local descriptors table (LDT).
Remember Descriptor privilege level (DPL) is in segment descriptor. we need to check CPL < DPL, then we could access that memory.


Translating a logical address to linear address by using SEGMENTATION UNIT

index * 8 + (base address of gdt or ldt) + (32 bits offset) = linear address


please see understanding Linux kernel chapter 2. page 41 for more information.

*****************
Real Mode

*****************
In real mode, the CS is different from CS in protected mode, It stores physical address
like instruction ljmp 0xa000, 0x0000
it will set the cs = 0xa000, and eip =0x0000
translating to physical address is: 
so the instruction will be executing is: cs * 16 + eip = 0xa0000
remember, there is no global descriptor table in real mode.

Monday, November 15, 2010

ljmp, outb

ljmp 0xa000, 0x0000
this instruction will set the CS to 0xa000 and set the EIP 0x0000. Bascially, it will start to execute code at location CS*16 + EIP = 0xa0000

in real mode, if you write:
jmp 0xa0000, it won't work, it will have compile errors. because there is only 16 bits.

see first part is CS, second part is EIP
http://docs.sun.com/app/docs/doc/805-4693/6j4emccqq?l=ru&a=view

please also see wiki jmp instruction
http://en.wikipedia.org/wiki/JMP_%28x86_instruction%29


outb %al, (%dx)
outb %al, %dx
outb %al, 0x80

oub instruction only could out to value stores at dx, or immeidate values.
please see more inforamtion from
"Intel Architecture Software Developer's Manual, Volume 2: Instruction Set Reference Manual

Friday, November 12, 2010

GAS v.s. NASM

AT&T GCC GAS
http://sig9.com/articles/att-syntax
http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax



NASM, X86, Intel
http://www.drpaulcarter.com/pcasm/

Now we saw some of the major differences between Intel syntax and AT&T syntax. I’ve wrote only a few of them. For a complete information, refer to GNU Assembler documentations. Now we’ll look at some examples for better understanding.

+------------------------------+------------------------------------+
|       Intel Code             |      AT&T Code                     |
+------------------------------+------------------------------------+
| mov     eax,1                |  movl    $1,%eax                   |   
| mov     ebx,0ffh             |  movl    $0xff,%ebx                |   
| int     80h                  |  int     $0x80                     |   
| mov     ebx, eax             |  movl    %eax, %ebx                |
| mov     eax,[ecx]            |  movl    (%ecx),%eax               |
| mov     eax,[ebx+3]          |  movl    3(%ebx),%eax              | 
| mov     eax,[ebx+20h]        |  movl    0x20(%ebx),%eax           |
| add     eax,[ebx+ecx*2h]     |  addl    (%ebx,%ecx,0x2),%eax      |
| lea     eax,[ebx+ecx]        |  leal    (%ebx,%ecx),%eax          |
| sub     eax,[ebx+ecx*4h-20h] |  subl    -0x20(%ebx,%ecx,0x4),%eax |

Thursday, November 11, 2010

global, static variables in C

In this post, I am going to explain the global, static variables in C

********
main.c
********
int a[2];             // this is the non-static global variable, could be used at other files
int static b;        // this is the static global variable, could only be used in this file

void main()
{
 int static c;       // this is the static variable like in java. associated with class.
                          // it only has one copy,
 swap();
}

********
swap.c
********
extern int a[2];

void swap()
{
int tmp;
tmp = a[0];
a[0] = a[1];
a[1] = a[0]
}

deals please see slides 14
http://www.cs.gmu.edu/~setia/cs367/slides/index.html

Monday, November 8, 2010

linker script

please see more details of this link:
http://sourceware.org/binutils/docs-2.16/ld/Scripts.html#Scripts

First of all, let me introduce what the linker does:
after you compile the program:
gcc -c -g -Wall main.c
gcc -c -g -Wall swap.c

you will get two relocatable binary file: main.o and swap.o file. By using linker(ld), you will relocate the two .o files into a executable binary file named a.out.

if you want more detail information about linker, please see the slides 14:
http://www.cs.gmu.edu/~setia/cs367/slides/index.html


Every link is controlled by a linker script. This script is written in the linker command language.
for example, smm.ld is link script.
please see man ld or info ld, you could use option: -T to add the link script.
If you don't specify -T option, the linker will use the default linker script.

I also attached a sample of the formate of linker command language:
/* Maximum number of CPUs/cores */
CPUS = 4;

SECTIONS
{
    /* This is the actual SMM handler.
     *
     * We just put code, rodata, data and bss all in a row.
     */
    . = 0xa0000;
    .handler (.): {
        /* Assembler stub */
        *(.handler)

        /* C code of the SMM handler */
        *(.text);
        *(.text.*);

        /* C read-only data of the SMM handler */
        . = ALIGN(16);
        *(.rodata)
        *(.rodata.*)

        /* C read-write data of the SMM handler */
         . = ALIGN(4);
        *(.data)

        /* C uninitialized data of the SMM handler */
         . = ALIGN(4);
        *(.bss)
        *(.sbss)

        /* What is this? */
        *(COMMON)
         . = ALIGN(4);
    }

    /* We are using the ASEG interleaved to stuff the SMM handlers
     * for all CPU cores in there. The jump table redirects the execution
     * to the actual SMM handler
     */
    . = 0xa8000 - (( CPUS - 1) * 0x400);
    .jumptable : {
        *(.jumptable)
    }

    /DISCARD/ : {
        *(.comment)
        *(.note)
        *(.note.*)
    }
}

x86-64 assembly

I am going to address the difference between IA32 and x86-64 ATT assemly.
if you want to see more details, please see lecture 13 of:
http://www.cs.gmu.edu/~setia/cs367/slides/index.html

EBP will not be the special register.
ESP will be constant.
pass arguments by using registers(MAX = 6).
allocate local variables aromatically at the function call.

Thursday, November 4, 2010

AT&T assembly examples

In this blog, I am going to give some example of assembly language.

movb  $0x11, 0xa0000 // this is going to write 1 byte 0x11 to memory 0xa0000
movw $0xa000, %dx // this is going move 2 bytes 0xa000 to register dx
movl  $0x0000ffcc, %eax // this is going to move 4 bytes to register eax

/*write some ports*/
movb $0x11, %al
movw $0x80, %dx
outb %al, %dx
// this is going to write a single byte at the port 0x80
// us dx to store the port number seems like the convention
// if it is in: inb %dx, %al // read from port %dx, and store it in %al


/*write to serial port 0x3f8*/
movb $0x11, %al
movw $0x3f8, %dx
outb %al, %dx
// this code if you don't move serial port number to dx, just using outb %al, $3f8
// this will not work. I don't know why, but I think I have tested.

/*use a loop to do copy*/

movl $0xa0000, %eax
movl $smm_handler_start, %ebx
movl $smm_handler_end, %ecx
subl $smm_handler_start, %ecx
mylabel:
             movb (%ebx), %dl
             movb %dl, (%eax)
             inc %eax
             inc %ebx
             loop mylabel

// this code is going to copy content from [smm_hanlder_start, smm_handler_end) to memory address 0xa0000. smm_handler_start and smm_handler_end are label in another .S file. and they need to declare it as .global, and current file need to declare it as .extern. the number of times the loop will execute is the value at ecx. but in C is different. For example:
foo.S
.global smm_handler_start

smm_handler_start:
...
...


bar.c
extern uint_8 smm_handler_start
// if you want to get the address of smm_hanlder_start
// you need to use it like: &smm_hanlder_start (= $smm_hanlder_start in asm)