lunes, 11 de mayo de 2015

Interrupciones en modo real

Interrupciones en modo real

Cuando se presiona una tecla se genera una interrupción de hardware. en este caso la interrupcion de hardware 09, la tabla de interrupciones esta a partir de la dirección de memoria 0x00, en la dirección 0x09 x 4 va estar el vector de interrupción que apunta a la rutina que atiende a la interrupción de teclado en este caso ¨keyhandler¨ .
Leemos el código de la tecla presionada "Scan code" no el código ascii, y lo imprimimos en pantalla.

El programa en assembler int.asm es el siguiente.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
[ORG 0x7c00]      ; add to offsets
   jmp start
 
   %include "print.inc"
 
start:   
   xor ax, ax   ; make it zero
   mov ds, ax   ; DS=0
   mov ss, ax   ; stack starts at 0
   mov sp, 0x9c00   ; 200h past code start
 
   mov ax, 0xb800   ; text video memory
   mov es, ax
 
   cli      ;no interruptions
   mov bx, 0x09   ;hardware interrupt #
   shl bx, 2   ;multiply by 4
   xor ax, ax
   mov gs, ax   ;start of memory
   mov [gs:bx], word keyhandler
   mov [gs:bx+2], ds ; segment
   sti
 
   jmp $      ; loop forever
 
keyhandler:
   in al, 0x60   ; get key data
   mov bl, al   ; save it
   mov byte [port60], al
 
   in al, 0x61   ; keybrd control
   mov ah, al
   or al, 0x80   ; disable bit 7
   out 0x61, al   ; send it back
   xchg ah, al   ; get original
   out 0x61, al   ; send that back
 
   mov al, 0x20   ; End of Interrupt
   out 0x20, al   ;
 
   and bl, 0x80   ; key released
   jnz done   ; don't repeat
 
   mov ax, [port60]
   mov  word [reg16], ax
   call printreg16
 
done:
   iret




port60   dw 0
 
   times 510-($-$$) db 0  ; fill sector w/ 0's
   dw 0xAA55        ; req'd by some BIOSes
;==========================================

El print.inc

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
;----------------------
dochar:
   call cprint         ; print one character
sprint:
   lodsb      ; string char to AL
   cmp al, 0
   jne dochar   ; else, we're done
   add byte [ypos], 1   ;down one row
   mov byte [xpos], 0   ;back to left
   ret
 
cprint:   
   mov ah, 0x0F   ; attrib = white on black
   mov cx, ax    ; save char/attribute
   movzx ax, byte [ypos]
   mov dx, 160   ; 2 bytes (char/attrib)
   mul dx      ; for 80 columns
   movzx bx, byte [xpos]
   shl bx, 1    ; times 2 to skip attrib
 
   mov di, 0        ; start of video memory
   add di, ax      ; add y offset
   add di, bx      ; add x offset
 
   mov ax, cx        ; restore char/attribute
   stosw              ; write char/attribute
   add byte [xpos], 1  ; advance to right
 
   ret
 
;------------------------------------
 
printreg16:
   mov di, outstr16
   mov ax, [reg16]
   mov si, hexstr
   mov cx, 4   ;four places
hexloop:
   rol ax, 4   ;leftmost will
   mov bx, ax   ; become
   and bx, 0x0f   ; rightmost
   mov bl, [si + bx];index into hexstr
   mov [di], bl
   inc di
   dec cx
   jnz hexloop
 
   mov si, outstr16
   call sprint
 
   ret
 
;------------------------------------
A este programa lo asemblamos con la siguiente linea de codigo:


$ nasm -o int.img int.asm

Para correrlo desde VirtualBox podemos hacer los pasos que se hicieron en la seccion Paso a Modo protegido  o genramos una maquina Virtual en sistema operativo seleccionamos


Luego vamos a la pestaña Storage y le agregamos un Floppy Disk




Para el Floppy Disk elegimos la imagen int.img ya generado arrancamos la Maquina Virtual


Aparecerá una pantalla negra y cuando presionemos una tecla se imprime el "Scan Code"



viernes, 8 de mayo de 2015

Crear una MV DOS en VirtualBox

Crear una MV DOS en VirtualBox



Muchas veces es necesario trabajar con maquinas en modo real, el DOS es un sistema operativo que trabaja en modo  real.
Usamos el FreeDOS el cual lo podemos descargar de aqui.

Una vez descargado el archivo fd11src.iso iniciamos VirtualBox


  • Elegimos la pestana del procesador y reducimos la   "Execution Cap" de  100 % a 40 %.





  • Cambiamos el adaptador de red  de  "NAT" a "Bridged Adapter".



Luego procedemos como como cualquier otro sistema operativo, seleccionamos instalar a "harddisk"
  • Y el CD de instalación de FreeDOS  bootea la nueva maquina virtual.




  • Elegimos crear el disco C  "Create Drive C:" desde el menu de booteo.


  • Esto inicia la instalacion de  Free FDISK. Permitimos a Free FDISK soporte de  FAT32 respondiendo "Y"".




  • Creamos una particion  DOS eligiendo  "1".


  • Como la primera partición, y también debe ser la partición primaria. Elegimos  "1".


  • Si es la unica particion contestamos y queremos usar todo el espacio del disco respondemos: "Y".


  • Free FDISK muestra el resultado


  • Reboot.


Para intercambiar archivos entre FreeDOS y el Host habilitamos la red y un servidor FTP en el FreeDOS.

Habilitar la red 

Por default VirtualBox use el adaptador de red AMD's PCnet Fast III (Am79C973) . Este es un driver de paquetes libre que también usa FreeDOS. Para activarlo:
  • Tipee "auto" para abrir el editor y editar  AUTOEXEC.BAT

  • Remover "REM" en la linea mostrada en la figura, de tal forma que queda.
LH PCNTPK INT=0x60
  • Para habilitar el DHCP cliente remover "REM" de la siguiente linea y queda
DHCP
  • Reboote y deberá cargar una dirección IP
  • Para verificar la dirección IP vea el archivo C:\fdos\mtcp.cfg


Configurar el  FTP server

Para intercambiar archivos entre el  host y el FreeDOS guest, se debe iniciar el servidor FTP en DOS. FreeDOS incluye el programa TCP ftpsrv de Michael B. Brutman. Para usarlo debemos configurarlo.
FreeDOS 1.1 guarda la configuración de  mTCP en el archivo MTCP.CFG debemos realizar los siguientes comandos:
copy C:\FDOS\DOC\MTCP\SAMPLE.CFG C:\FDOS\MTCP.CFG
edit C:\fdos\mtcp.cfg
  • Activamos y seteamos las siguientes opciones:
MTU 1472
ftpsrv_password_file c:\fdos\ftppass.txt
ftpsrv_log_file c:\fdos\ftpsrv.log
FTPSRV_FILEBUFFER_SIZE 16
FTPSRV_TCPBUFFER_SIZE 16
FTPSRV_PACKETS_PER_POLL 2
  • Ahora creamos y editamos el archivo de  password  para el FTP server:
edit C:\fdos\ftppass.txt
  • IUsamos user como usuario y password como password para acceder a todos los archivos, el archivo ftppassword.txt quedaria asi:
user     password      [none]     [any]      all

Iniciamos el FTP server

  • Iniciamos el  FTP server con el siguiente comando:
ftpsrv
Ftpsrv.png
  • Nos conectamos desde una consola Linux con el usuario y password especificados en el archivo  C:\FDOS\ftppass.txt.



Ejecutamos un programa

En el Host linux editamos el siguiente programa para imprimir "Hello world"
; Guardarlo como dos.asm, assemble con nasm -f bin -o dos.com dos.asm
ORG       100h
Start:    JMP Main
strOfs    DB 'hello, world'
strLen    EQU $-strOfs   
Main:     MOV SI,strOfs  ; offset address de la cadena
          MOV CX,strLen  ; longitud de la cadena
          MOV AX, 0B800h ; segment address del buffer de video
          MOV ES, AX     ; se almacena en extra segment register
          MOV DI, 160    ; posicion en la pantalla 
          CLD            ; 
nextChar: LODSB          ; carga AL de DS:[SI], e incrementa SI
          STOSB          ; almacena AL en ES:[DI], incrementa DI
          INC DI         ; salta sobre el byte de atributo
          LOOP nextChar  ; repite hasta CX=0
          MOV AH,00h     ; BIOS function GET KEYSTROKE
          INT 16h        ; Presione una tecla para continuar
          RET            ; Sale del programa
Lo asemblamos con:  nasm -f bin -o dos.com dos.asm y luego lo transferimos a la maquina virtual DOS.
En la maquina virtual DOS lo ejecutamos

Y imprime "Hello World"

Bibliografia


http://www.codeproject.com/Articles/45788/The-Real-Protected-Long-mode-assembly-tutorial-for

martes, 7 de abril de 2015

Fechas de Parcial

Fechas de Parcial

Introduccion y Evolucion de las Computadoras
Buses y Memoria Cache
Memoria Interna y Memoria Externa
Entradas y salidas
Soporte del Sistema Operativo
Unidad Aritmetica y Instrucciones x86
Direccionamiento
Practico  Calculadora de punto flotante.

Diapositivas Stallings
http:/www.drpaulcarter.com/pcasm/
1 Parcial 27 de abril
Notas 1 Parcial 

Direcciones


2 Parcial 15 de junio

Conceptos
ARP
IP
TCP
DHCP
NAT
Ruteo
DNS

domingo, 5 de abril de 2015

Medición perfomance de código

Medición perfomance de código

Para medir el tiempo que tarda la CPU en ejecutar un programa existe la instrucción de marca de Tiempo.

RDTSC

Este instrucción lee un registro de timer tics del procesador y nos devuelve el valor en el registro "RAX" tomando la marca de tiempo al comienzo del programa y restándosela a la marca de tiempo del final del programa obtenemos los tics de reloj que tardo en ejecutarse la subrutina.

La instrucción RDTSCP lee marcas de tiempo y devuelve el identificador de la CPU.
Contador Marca de tiempo
La instrucción RDTSCP carga los 64 bits  en el registro "RAX."
ejemplo
  rdtsc ; lee marca de tiempo
  mov time, eax ; muevo  contador a una variable
  fdiv ; division de punto flotante
rdtsc ; lee marca de tiempo
  sub eax, time ; Calcula la diferencia

Contador Marca de tiempo e Identificador de CPU
La instrucción RDTSCP carga los 64 bits  en el EAX y el idetificado e IA64_TSC_AUX MSR
en el registro RCX
Realiza dos lecturas del RDTSCP las resta y las imprime e imprime el cpu id
Se asembla mediante:

nasm -o print.o -f elf64 -g -F stabs print.asm
gcc -o print print.o

taskset 0x1 ./print ;Se ejecutara en el procesador 0
dbritos@HP:~/asm$ taskset 0x1 ./print
72
0

taskset 0x4 ./print ;Se ejecutara en el procesador 3

Con el comando taskset elijo en que procesador se va a correr la aplicación.

segment .text
EXTERN printf
GLOBAL main
main:
 RDTSCP
 mov rcx,1000000
miloop: mov rbx,rax
;Poner codigo a medir aqui
 RDTSCP
 push rcx
 sub rax,rbx
 mov rsi, rax
 mov rdi, fmt
 mov rax, 0
 call printf
 pop rsi
 mov rdi, fmt
 mov rax, 0
 call printf
 mov rax, 60 ; sys_exit
 mov rdi, 0 ; return 0 (success)
 syscall

segment .data
fmt: db "%d", 10,0


Bibliografia


http://www.intel.com.ar/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf

miércoles, 1 de abril de 2015

LLamadas a rutinas de asembler desde c++

LLamadas a rutinas de asembler desde c++


A continuacion presentamos un pequeño programa en asembler que es llamado desde C++.

El programa en asembler carga una constante en el registro "RAX", lo llamamos "c.asm".




global GetValueFromASM

segment .data

segment .text
GetValueFromASM:
        mov rax, 8679869
        ret

El programa en "C++" que llama a la funcion "GetValueFromASM"  a este programa la guardamos en el archivo "main.pp".

#include <iostream>
using namespace std;
extern "C" int GetValueFromASM();

int main()
{
cout<<"ASM said " <<GetValueFromASM()<<endl;
return 0;
}
Para facilitar la compilacion realizamos un archivo "makefile" con el siguiente código.


runme: main.cpp c.o
 g++ main.cpp c.o -o runme

c.o: c.asm
 nasm -f elf64 c.asm -o c.o

lo ejecutamos y obtenemos lo siguiente:


dbritos@HP:~/asm$ make
nasm -f elf64 c.asm -o c.o
g++ main.cpp c.o -o runme
dbritos@HP:~/asm$ ./runme
ASM said 8679869
dbritos@HP:~/asm$ 


Pasando variables al asembler.



En la arquitectura "x64" las seis primeras variables enteras "C++" las pasa a través  de registros.
1    RDI
2    RSI
3    RDX
4    RCX
5    R8
6    R9

El asembler le retorna al "C++" las variables a través del registro "RAX"


El programa en "C++" que llama al programa "c" que dentro del programa a la función se le asigna el nombre de "AddInts()" a este programa la guardamos en el archivo "main.pp".


#include <iostream>
using namespace std;
extern "C" int AddInts(int a, int b, int c, int d);
int main()
{
int a,b,c,d;
cout<<"Escriba un numero:";
cin>>a;
cout<<"Escriba el segundo numero:";
cin>>b;
cout<<"Escriba el tercer numero:";
cin>>c;
cout<<"Escriba el cuarto numero:";
cin>>d;
cout<<"La suma de enteros es:"<<AddInts(a,b,c,d)<<endl;
return 0;
}
El programa en asembler que suma las cuatro variables y devuelve la suma en el registro "RAX", lo llamamos "addints.asm".


global AddInts
segment .data
segment .text

AddInts:
        mov eax,edi
        add eax,esi
        add eax,ecx
        add eax,edx
        ret

Para facilitar la compilación realizamos un archivo "makefile" con el siguiente código.

runme: main.cpp addints.o
        g++ main.cpp addints.o -o runme

addints.o: addints.asm
        nasm -f elf64 addints.asm -o addints.o

Lo ejecutamos y obtenemos los siguientes resultados:

/nasm/sumaabcd$ make
g++ main.cpp addints.o -o runme

/nasm/sumaabcd$ ./runme
Escriba un numero:1
Escriba el segundo numero:2
Escriba el tercer numero:3
Escriba el cuarto numero:4
La suma de enteros es:10

Bibliografia


 http://vikaskumar.org/amd64/

sábado, 28 de marzo de 2015

x86 Asembler scanf

x86 asembler

Para leer una cadena de caracteres desde el teclado usamos la funcion de ¨C¨ ¨scanf¨.


BITS 64
SECTION .text

extern printf
extern scanf

GLOBAL main
main:
 mov  rdi, yourname
 mov  al, 0         ; numero de argumentos en SSE
 call printf

 mov rax,  [welcome]
 mov [buf], rax

 mov  rdi, scanstring
 lea  rsi, [buf+8]
 mov  al, 0            ; numero de argumentos en SSE
 call scanf

 mov  rdi, buf
 mov  al, 0            ; numero de argumentos en SSE
 call printf

 mov  rdi, end
 mov  al, 0            ; numero de argumentos en SSE
 call printf

 ret

SECTION .bss
buf: resb 4096

SECTION .data
yourname:   db "Your name: ", 0
welcome:    db "Welcome "
end:        db "!", 10, 0
scanstring: db "%s"
Se lo asembla con:

nasm -f elf64 -l sf.lst -o sf.o sf.asm
 gcc -o sf  sf.o

Para leer un entero largo de 64 bits le pasamos a través del registro "rsi' el lugar donde lo va guardar y luego cargamos el valor leído en el registro "rsi' y lo imprimimos en pantalla.

BITS 64
SECTION .text

extern printf
extern scanf

GLOBAL main
main:
 mov rdi, scanstring
 mov rsi, numero
 xor al,al ; number of arguments in SSE
 call scanf
 mov rsi,[numero]
 mov rdi, scanstring
 mov al, 0 ; number of arguments in SSE
 call printf
 ret

SECTION .data
numero:   dq 0
scanstring: db "%ld"

Lo asemblamos con:

nasm -f elf64 -l sfd.lst -o sf.o sfd.asm
 gcc -o sfd  sfd.o

Para ingresar números en notación de punto flotante, se utilizan los registros "MMX" y en el registro "RAX" colocamos el numero de registros "MMX" usados, en el programa no se observan el uso de los registros "MMX" ya que quedan implícitos, la salida de la función "scanf" es el registro "MMX0" y la entrada de la función "printf" es el mismo registro.


BITS 64
SECTION .text

extern printf
extern scanf

GLOBAL main
main:
 push    rbp
 mov rdi, scanstring
 mov rax,1 ; number of arguments in SSE
 call scanf
 mov rdi, scanstringp
 mov rax, 1 ; number of arguments in SSE
 call printf
 pop rbp
 ret

SECTION .data

scanstring:  db "%lf",0
scanstringp: db "%lf",10,0


Se lo asembla con:

nasm -f elf64 -l sff.lst -o sff.o sff.asm
 gcc -o sff  sff.o

Muchas veces los registros "MMX" se pueden estar usando y es conveniente que la función "scanf" guarde los valores directamente en memoria, para esto usamos la siguiente variante del ejemplo anterior.


BITS 64
SECTION .text

extern printf
extern scanf

GLOBAL main
main:
 push    rbp
 mov qword  rax, 0    
 push qword 0  
 mov rdi, scanstring
 mov  rsi, rsp  
 mov rax,0 ; number of arguments in SSE
 call scanf
 movsd xmm0, [rsp]  
 pop rax  
 mov rdi, scanstring
 mov rax, 1 ; number of arguments in SSE
 call printf
 pop rbp
 ret

SECTION .data

scanstring: db "%lf",0
Se lo asembla con:

nasm -f elf64 -l sff.lst -o sff.o sff.asm
 gcc -o sff  sff.o

x86 Assembler printf

x86 Assembler printf


Podemos realizar el mismo programa "Hello World" pero llamando a funciones de "C". El llamado de funciones de "C" es diferente para arquitecturas de 32 bits y arquitecturas de 64 bits aquí nos ocuparemos de arquitecturas de 64 bits.
La convención para llamadas a rutinas de ¨C¨ desde asembler se pude ver aquí.
El siguiente programa escribe "Hello World" en pantalla usando la función de "C" printf



 SECTION .data
msg:      db "Hello, world,", 0
fmt:      db "%s", 10, 0

        SECTION .text
        extern printf
        global main
main:

        mov esi, msg    ; 64-bit Direccion comienzo de la cadena
        mov edi, fmt    ; Formato de la cadena
        mov eax, 0      ; printf is varargs,  EAX cuenta

                        ;el numero de argumentos no enteros pasados
        call printf

        mov ebx, 0      ; normal-exit code
        mov eax, 1      ; process-termination service
        int 0x80        ; linux kernel service
Se lo asembla con:

nasm -f elf64 hello.asm -o hello.o
gcc -o hello hello.o
Se lo ejecuta:

 ./hello
Hello, world,

Con la función "printf" no solo podemos escribir cadenas de caracteres sino números en una variedad de formatos, en el siguiente programa podemos ver un ejemplo de impresión de números enteros de punto flotante y hexadecimales.

; printf2_64.asm  use "C" printf on char, string, 
; int, long int, float, double
; 
; Assemble: nasm -f elf64 -l printf2.lst -o printf2.o printf2.asm
; Link:  gcc -m64 -o printf2  printf2.o
; Run:  ./printf2 > printf2.out
; Output: cat printf2.out
; 
; A similar "C" program   printf2_64.c 
; #include 
; int main()
; {
;   char      char1='a';            /* sample character */
;   char      str1[]="mystring";    /* sample string */
;   int       len=9;                /* sample string */
;   int       inta1=12345678;       /* sample integer 32-bit */
;   long int  inta2=12345678900;    /* sample long integer 64-bit */
;   long int  hex1=0x123456789ABCD; /* sample hexadecimal 64-bit*/
;   float     flt1=5.327e-30;       /* sample float 32-bit */
;   double    flt2=-123.4e300;      /* sample double 64-bit*/
; 
;   printf("printf2_64: flt2=%e\n", flt2);
;   printf("char1=%c, srt1=%s, len=%d\n", char1, str1, len);
;   printf("char1=%c, srt1=%s, len=%d, inta1=%d, inta2=%ld\n",
;          char1, str1, len, inta1, inta2);
;   printf("hex1=%lX, flt1=%e, flt2=%e\n", hex1, flt1, flt2);
;   return 0;
; }
        extern printf               ; the C function to be called

        SECTION .data               ; Data section

     ; format strings for printf
fmt2: db "printf2: flt2=%e", 10, 0
fmt3: db "char1=%c, str1=%s, len=%d", 10, 0
fmt4: db "char1=%c, str1=%s, len=%d, inta1=%d, inta2=%ld", 10, 0
fmt5: db "hex1=%lX, flt1=%e, flt2=%e", 10, 0
 
char1: db 'a'   ; a character 
str1:  db "mystring",0         ; a C string, "string" needs 0
len:   equ $-str1   ; len has value, not an address
inta1: dd 12345678  ; integer 12345678, note dd
inta2: dq 12345678900  ; long integer 12345678900, note dq
hex1:  dq 0x123456789ABCD         ; long hex constant, note dq
flt1:  dd 5.327e-30  ; 32-bit floating point, note dd
flt2:  dq -123.456789e300         ; 64-bit floating point, note dq

 SECTION .bss
  
flttmp: resq 1           ; 64-bit temporary for printing flt1
 
        SECTION .text                   ; Code section.

        global main          ; "C" main program 
main:            ; label, start of main program
 push    rbp   ; set up stack frame 
 fld dword [flt1]         ; need to convert 32-bit to 64-bit
 fstp qword [flttmp]          ; floating load makes 80-bit,
                                 ; store as 64-bit
 mov rdi,fmt2
 movq xmm0, qword [flt2]
 mov rax, 1   ; 1 xmm register
 call printf

 mov rdi, fmt3  ; first arg, format
 mov rsi, [char1]  ; second arg, char
 mov rdx, str1  ; third arg, string
 mov rcx, len  ; fourth arg, int
 mov rax, 0   ; no xmm used
 call printf

 mov rdi, fmt4  ; first arg, format
 mov rsi, [char1]  ; second arg, char
 mov rdx, str1  ; third arg, string
 mov rcx, len  ; fourth arg, int
 mov r8, [inta1]  ; fifth arg, inta1 32->64
 mov r9, [inta2]  ; sixth arg, inta2
 mov rax, 0   ; no xmm used
 call printf

 mov rdi, fmt5  ; first arg, format
 mov rsi, [hex1]  ; second arg, char
 movq xmm0, qword [flttmp]    ; first double
 movq xmm1, qword [flt2] ; second double
 mov rax, 2   ; 2 xmm used
 call printf
 
 pop rbp   ; restore stack 
        mov     rax, 0   ; exit code, 0=normal
        ret    ; main returns to operating system
Luego lo asemblamos y linkeamos con los siguientes comandos:

nasm -f elf64 -l printf2.lst -o printf2.o printf2.asm
 gcc -o printf2 printf2.o

Se lo ejecuta:

 ./printf2 
printf2: flt2=-1.234568e+302
char1=a, str1=mystring, len=9
char1=a, str1=mystring, len=9, inta1=12345678, inta2=12345678900
hex1=123456789ABCD, flt1=5.327000e-30, flt2=-1.234568e+302