; Program for playing on PC-Speaker.
; For GNU/Linux 64 bit version. Root priveleges or kernel patch needed.
; Version: 4.
; Written on FreePascal (https://freepascal.org/).
; Copyright (C) 2021-2023 Artyomov Alexander
; http://self-made-free.ru/ (Ex http://aralni.narod.ru/)
; aralni@mail.ru
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU Affero General Public License as
; published by the Free Software Foundation, either version 3 of the
; License, or (at your option) any later version.
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU Affero General Public License for more details.
; You should have received a copy of the GNU Affero General Public License
; along with this program. If not, see <https://www.gnu.org/licenses/>.
format ELF64 dynamic 3 at 0
sys_write equ 1 ; the linux WRITE syscall
sys_lseek equ 8
SEEK_END equ 2
sys_exit equ 60 ; the linux EXIT syscall
sys_stdout equ 1 ; the file descriptor for standard output (to print/write to)
entry start
; NX bit:
segment gnustack
segment readable executable writeable
start:
call writehelp
call startspk
call startsignal
pop r8 ; pop the number of arguments from the stack
cmp r8, 1
jne arg
call gspkon
mov bx,1000
call gspk
mov ax, 1000
call sle
call gspkoff
jmp exit
arg:
pop rsi ; discard the program name, since we only want the commandline arguments
dec r8
loop1:
; loop condition
cmp r8, 0 ; check if we have to print more arguments
jz exit ; if not, jump to the 'end' label
; print the argument
mov rax, sys_write ; set the rax register to the syscall number we want to execute (WRITE)
mov rdi, sys_stdout ; specify the file we want to write to (standard output in this case)
pop rsi ; pop a pointer to the string we want to print from the stack
call getlength
syscall ; execute the system call
push rax
push rdi
push r8
push rsi
push rdx
call gspkon;
call playfile
call gspkoff;
mov ax, 500
call sle
pop rdx
pop rsi
pop r8
pop rdi
pop rax
; print a newline
mov rax, sys_write ; rax is overwritten by the kernel with the syscall return code, so we set it again
mov rdi, sys_stdout
lea rsi, [linebreak] ; this time we want to print a line break
mov rdx, 1 ; which is one byte long
syscall
dec r8 ; count down every time we print an argument until there are none left
jmp loop1 ; jump back to the top of the loop
; the program is finished, now exit cleanly by calling the EXIT syscall
exit:
mov rax, 60 ; load the EXIT syscall number into rax
xor rdi, rdi ; the program return code
;mov di, 10
syscall ; execute the system call
define SIGINT 2 ;Interrupt (ANSI)
define SIGTERM 15; Default kill signal
define SA_RESTORER 0x04000000 ;Required for x86_64 sigaction
define SYS_RT_SIGACTION 13 ;int sig,const struct sigaction __user * act,
writehelp:
mov rax, sys_write ; rax is overwritten by the kernel with the syscall return code, so we set it again
mov rdi, sys_stdout
lea rsi, [helpmsg] ; this time we want to print a line break
mov rdx, helpmsg_len ; which is one byte long
syscall
ret
error:
mov rax, 1 ; WRITE
mov rdi, 1 ; standard output
lea rsi, [errmsg] ; pointer to the string
mov rdx, errmsg_len ; specify the length of the string
syscall ; execute the system call
jmp exit;
open_error:
mov rax, 1
mov rdi, 1
lea rsi, [openerrmsg ]
mov rdx, openerrmsg_len
syscall
jmp exit;
len_error:
mov rax, 1
mov rdi, 1
lea rsi, [lenerrmsg]
mov rdx, lenerrmsg_len
syscall
jmp exit;
map_error:
mov rax, 1
mov rdi, 1
lea rsi, [maperrmsg]
mov rdx, maperrmsg_len
syscall
jmp exit;
consistent_error:
mov rax, 1
mov rdi, 1
lea rsi, [consistenterrmsg]
mov rdx, consistenterrmsg_len
syscall
call spkoff
jmp exit;
spkpatch: dq 0
retval1: dq 0
retval2: dq 0
file_descriptor: dq 0
file_size: dq 0
file_address : dq 0
ioperm:
push rax
push rdi
push rsi
push rdx
mov rax, 173
mov rdi, $42
mov rsi, 2
mov rdx, 1
syscall
mov [retval1], rax
mov rax, 173
mov rdi, $61
mov rsi, 1
mov rdx, 1
syscall
mov [retval2], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
spkon:
;push rax
mov r12, rax
in al, 61h
or al, 03h
out 61h, al
;pop rax
mov rax, r12
ret
spkoff:
;push rax
mov r12, rax
in al, 61h
or al, 03h
xor al, 03h
out 61h, al
;pop rax
mov rax, r12
ret
spk:
;push rax
mov r12, rax
mov al, 0B6h
out 43h, al
mov al, bl
out 42h, al
shr rbx, 8
mov al, bl
out 42h, al
;pop rax
mov rax, r12
ret
kspkon:
;push rax
mov r12, rax
mov rax, 1000
syscall
;pop rax
mov rax, r12
ret
kspkoff:
;push rax
mov r12, rax
mov rax, 1001
syscall
;pop rax
mov rax, r12
ret
kspk:
;push rax
mov r12, rax
;push rdi
mov r8, rdi
mov rax, 1002
mov rdi, rbx
syscall
;pop rdi
mov rdi, r8
;pop rax
mov rax, r12
ret
kspkpatchexists:
mov rax, 1003
syscall
cmp qword rax, 123
jne kspkpatchexistsexit
mov qword [spkpatch], 1
kspkpatchexistsexit:
ret
gspkon:
cmp qword [spkpatch], 1
je gspkonex
call spkon
ret
gspkonex:
call kspkon
ret
gspkoff:
cmp qword [spkpatch], 1
je gspkoffex
call spkoff
ret
gspkoffex:
call kspkoff
ret
gspk:
cmp qword [spkpatch], 1
je gspkex
call spk
ret
gspkex:
call kspk
ret
startspk:
call ioperm
cmp qword [retval1],0
jne patch_ex
cmp qword [retval2],0
jne patch_ex
ret
patch_ex:
call kspkpatchexists
cmp qword [spkpatch], 1
jne exit
ret
startsignal:
lea r10, [handler]
mov [sa_handler], r10
mov r10, 8 ; sizeof(sigset_t)
xor rdx, rdx
lea rsi, [sigaction]
mov rdi, SIGINT
mov rax, SYS_RT_SIGACTION
syscall
mov rdi, SIGTERM
mov rax, SYS_RT_SIGACTION
syscall
ret
handler:
call gspkoff;
mov rax, 1
mov rdi, 1
lea rsi, [signalmsg]
mov rdx, signalmsg_len
syscall
jmp exit
getlength:
xor rdx,rdx
glloop:
cmp byte [rsi+rdx],0
je glexit
inc rdx
jmp glloop
glexit:
ret
playfile:
mov rdi, rsi ; patchname
; открыть файл
mov rsi,0; открываем для чтения
mov rax,2; номер системного вызова
syscall; вызов функции "открыть файл"
cmp rax, 0; нет ли ошибки при открытии
jl open_error; перейти к концу программы.
mov rbx, rax; запомнить дескриптор файла
; получить длину файла
mov rdi,rax; дескриптор файла
mov rsi,0; от начала файла
mov rdx,2; SEEK_END
mov rax,8; номер системной функции
syscall; вызов функции получить длину
cmp rax,0; нет ли ошибки при открытии
jl len_error ; перейти к концу программы.
mov r15,rax; запомнить длину файла
call check
; отобразить файл
mov rdi,0; с начала
mov rsi,rax; длина файла
;PROT_READ 1 Read access is allowed.
;PROT_WRITE 2 Write access is allowed. Note that this value assumes PROT_READ also.
;PROT_NONE 8 No data access is allowed.
;PROT_EXEC 4 This value is allowed, but is equivalent to PROT_READ.
;MAP_SHARED 4 Changes are shared.
;MAP_PRIVATE 2 Changes are private.
;MAP_FIXED 1 Parameter addr has exact address
mov rdx,1; PROT_
mov r10,1; MAP_
mov r8,rbx; дескриптор файла
mov r9,0; с начала файла
mov rax,9; номер системного вызова
syscall; вызов функции отобразить файл
cmp rax,0; нет ли ошибки
jl map_error ; перейти к концу программы.
mov r13,rax; запомнить адрес начала отображенного файла
; закрыть файл
mov rdi,rbx; дескриптор файла
mov rax,3; номер системного вызова
syscall ; вызов функции "закрыть файл"
cmp rax,0; нет ли ошибки при открытии
jl map_error ; перейти к концу программы.
push rax
push rbx
push rdx
push rsi
;mov rbx,[r13]
;call spk
pop rsi
pop rdx
pop rbx
pop rax
; воспроизвести отображаемый файл
mov rbx,r13; адрес начала области
mov rdx,r15; обрабатываемая длина
fileloop:
push rdx
mov dword eax,[rbx]
push rbx
mov bx, ax
call play
pop rbx
pop rdx
add rbx, 4; к следующему двойному слову
sub rdx, 4; уменьшим счетчик
jnz fileloop; если не 0 - продолжим
; закрыть отображение
mov rdi,r13; адрес отображенного файла
mov rsi,r15; длина отображенной части файла
mov rax, 11; номер системного вызова
syscall
cmp rax,0; нет ли ошибки
jl error ; перейти к концу программы.
ret
play:
cmp bx, 0
jz noon
call gspk
jmp sl
noon:
call gspkoff
call sl
call gspkon
sl:
shr eax, 16
and rax, 1111111111111111b
cmp ax, 0
jz playret
sle:
; Signed divide RDX:RAX by r/m64, with result stored in RAX ← Quotient, RDX ← Remainder.
mov rdx, 0; RDX:RAX делимое в rax
mov rcx, 1000; делитель
div rcx; целое в RAX, остаток в RDX
mov r11, rax
mov rax, rdx
mov rbx, 1000000
mov cl, 0
mul rbx
; put a time structure on the stack
push rax ; nanoseconds
push r11; seconds
mov rax, 35 ; sys_nanosleep
mov rdi, rsp ;point to our time structure (requested)
mov rsi, rsp ; (remaining)
syscall
add rsp, 16 ; "free" our time structure
playret:
ret
check:
push rax
push rdx
push rcx
xor rdx, rdx
mov rcx, 4
div rcx
cmp rdx,0
jne consistent_error
pop rcx
pop rdx
pop rax
ret
segment readable writeable
linebreak db 0x0A ; ASCII character 10, a line break
fp dq 0 ; file handler
filesize dq 0 ; file size
sigaction:
sa_handler dq 0
sa_flags dq SA_RESTORER
sa_restorer dq 0;
sa_mask dq 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
errmsg: db 10,'>>> Error',10,0
errmsg_len = $-errmsg
lenerrmsg: db 10,'>>> [><] GET FILE LENGTH Error',10,0
lenerrmsg_len = $-lenerrmsg
openerrmsg: db 10,'>>> [*] FILE OPEN Error',10,0
openerrmsg_len = $-openerrmsg
maperrmsg: db 10,'>>> [*] FILE MAP Error',10,0
maperrmsg_len = $-maperrmsg
consistenterrmsg: db 10,'>>> [*] FILE Consistent Error',10,0
consistenterrmsg_len = $-consistenterrmsg
signalmsg: db 10,'--==[[ Breaked by SIGNAL ]]==--',10,0
signalmsg_len = $-signalmsg
helpmsg: db 'GALAXY ORGANIZER SPEAKER PLAYER Version 4',10,'Artyomov Alexander 2022-2023 License: GNU AGPLv3 and above',10,'Use: gorg64_spkplay or gorg64_spkplay somemusic.speaker somemusic2.speaker ...',10,0
helpmsg_len = $-helpmsg