
; fasm demonstration of writing 64-bit ELF executable

format ELF64 executable

;section readable writeable
;
;msg db 'Hello 64-bit world!',0xA
;msg_size = $-msg
;
section readable executable writeable

entry $

; we save 512 bytes of AMD 64 mainboard CMOS
; old mainboards has 80h CMOS accessed by ports 70h,71h
; new 512 bytes CMOS is accessed by ports 72h,73h (first 256 bytes) and 73h,74h
;----------P00720075--------------------------
;PORT 0072-0075 - AMD-645 Peripheral Bus Controller - ACCESS TO EXTENDED CMOS
;SeeAlso: PORT 0070h
;
;0072  RW  CMOS memory address, region 2 (256 bytes)
;0073  RW  CMOS memory data, region 2
;0074  RW  CMOS memory address, region 3 (256 bytes)
;0075  RW  CMOS memory data, region 3
;Note:	on the AMD-645, ports 0072h and 0073h allow access to a full 256 bytes
;	  of RAM, including the standard 128 bytes available through ports
;	  0070h and 0071h

cmos_syze	=	200h
; 1st we need root privileges
; you can qeury this by sys_getuid and sys_getgid
	mov	eax,18h		; 24 sys_getuid
	int	80h
	or	rax,rax
	jz	we_are_root
	lea	rdi,[msg00]
	call	STDOUT_write
	jmp	egzyd

we_are_root:
; 2nd we must set ioperm permission to access ports
; for ports 0000-03FF this is done by sys_ioperm

	mov	edx,1		; 1 allow access to ports, 0 deny access
	mov	ecx,4		; number of ports
	mov	ebx,72h		; begin from port
	mov	eax,65h		; sys_ioperm
	int	80h
	or	rax,rax
	jz	ports_opened
	lea	rdi,[msg01]
	call	STDOUT_write
	jmp	egzyd
ports_opened:

; for ports 0000-FFFF this is done by sys_iopl
; mov ebx,0	; privilege level 0 for access ports by IN and OUT instructions
; mov eax,6Eh	; sys_iopl
; int 80h

; 3nd
; reading CMOS
	lea	rdi,[cmos]
	cld
	mov	ecx,200h
	xor	ebx,ebx
L0:	mov	edx,72h
	add	dl,bh
	add	dl,bh
	mov	al,bl
	out	dx,al
	inc	edx
	insb
	inc	ebx
	loop	L0

; 4th
; save CMOS to file
	mov	ecx,110100100b	; 110 owner can read write but don't execute
				; 100 group can read but don't write or execute
				; 100 other can read but don't write or execute
	lea	rbx,[filename]
	mov	eax,8		; sys_creat
	int	80h
	or	rax,rax
	jns	creat_OK
	lea	rdi,[msg02]
	call	STDOUT_write
	jmp	egzyd
	
creat_OK:
	mov	edx,cmos_syze
	lea	rcx,[cmos]
	xchg	rax,rbx		; file handle returned in RAX by sys_creat
	mov	eax,4		; sys_write
	int	80h
;not needed-	or	rax,rax
;not needed-	js	error_write
	cmp	rax,cmos_syze
	jz	write_OK
error_write:
	lea	rdi,[msg03]
	call	STDOUT_write
	jmp	egzyd

write_OK:
; rbx hold now file handle
	mov	eax,6		; sys_close
	int	80h

; successful
	lea	rdi,[msg04]
	call	STDOUT_write

egzyd:
	xor	ebx,ebx		
	mov	eax,1		; note that AMD 64 zero extend this move
				; e.g. if rax=FFFFFFFFFFFFFFFFh
				; after mov eax,00000001
				; CPU give zero-extended result
				; rax=0000000000000001h
				; this way is used because
				; mov eax use 5 bytes B8 01 00 00 00
				; but
				; mov rax use 10 bytes 48 B8 01 00 00 00 00 00 00 00
	int	80h		; 2 bytes opcode CD 80

STDOUT_write:
	lea	rdx,[rdi]		; save message offset for syscall
; fynd stryng syze
	cld
	mov	al,0
	or	rcx,-1		; save some bytes, mov rcx,FFFFFFFFFFFFFFFFh
				; use 10 bytes
				; or rcx,byte -1 make rcx=FFFFFFFFFFFFFFFFh
				; and use 4 bytes only !!! opcode 48 83 C9 FF
	repnz scasb
	not	rcx
	dec	rcx
	xchg	rcx,rdx
; rcx offset of message, rdx message_size
; write message to STDOUT
	mov	ebx,1		; 1=STDOUT
	mov	eax,4		; sys_write
	int	80h		; make syscall
	ret

msg00		db	0Ah,'No root uid!',0Ah,0
msg01		db	0Ah,"Can't sys_ioperm!",0Ah,0
msg02		db	0Ah,'Error sys_creat file!',0Ah,0
msg03		db	0Ah,'Error sys_write file!',0Ah,0
msg04		db	0Ah,'Successful.',0Ah,0

filename	db	'cmos.bin',0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;SECTION .bss		; uninitialised-data
;ALIGNB 8
align 8

cmos		rb	cmos_syze
