[go: up one dir, main page]

Menu

[r12]: / htdocs / articles / vt.html  Maximize  Restore  History

Download this file

474 lines (387 with data), 13.7 kB

  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
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
<html>
<head>
<title>linuxassembly.org - Using Virtual Terminals under Linux</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1 align="center">Using Virtual Terminals under Linux</h1>
<p align="center"><font size="-1">by <a href="mailto:linuxassembly@unusedino.de">Karsten Scheibler</a><br>
thanks to Richard Cooper</font></p>
<dl><dt><b>Remark&nbsp;(a):</b></dt>
<dd>Save this page as <tt>vt.html</tt> and use the following command to extract the source code with a sample Makefile:<br>
<tt>sh&nbsp;-c&nbsp;&quot;( mkdir&nbsp;vt&nbsp;&amp;&amp; cd&nbsp;vt&nbsp;&amp;&amp; awk&nbsp;'/^&lt;!--eof/{d=0}{if(d)print&gt;f}/^&lt;!--sof/{f=\$2;d=1}' )&nbsp;&lt;&nbsp;vt.html&quot;</tt>
</dd><dt><b>Remark&nbsp;(b):</b></dt>
<dd>Some browsers try to be super smart and reformat the html code
so you may have trouble to extract the files. This is the right time to learn more
about wget, a tool to download files via http or ftp ;-)
</dd><dt><b>Remark&nbsp;(c):</b></dt>
<dd>Some versions of nasm are known to generate broken code.
I have used nasm-0.98 for this example which worked for me.
</dd>
</dl>
<p align="justify">This code shows how to control the virtual terminal switching.
As a standalone example it doesn't make much sense, but in connection
with the <a href="fb.html">framebuffer</a> or <a href="modex.html">ModeX</a>
example code it is quite useful.</p>
<p align="justify">The switching between the virtual terminals is normally
controlled by the kernel. The key combinations ALT-F1, ALT-F2, ...,
ALT-CURSORLEFT, ALT-CURSORRIGHT are reserved for that. But it is
also possible to tell the kernel that you want to get a signal if
the user wants to leave the virtual terminal of your program (in this context
it is called release signal) and which signal you want to get when
the user switches back to the virtual terminal your program runs on
(acquire signal).</p>
<p align="justify">In this example <b>SIGUSR1</b> and
<b>SIGUSR2</b> are used
for this purpose. The according <a href="#handlers">handlers</a> are
registered with <b>sys_sigaction</b>. Now lets have a closer look how this
example works:<ul>
<li><a href="#release">vt_release_handler</a> simply sets vt_flag.</li>
We have no possibility to check if the signal was sent from
someone else, so this is all we can do here</li>
<li><a href="#acquire">vt_acquire_handler</a> checks if we are on our
own virtual terminal, if yes vt_flag gets cleared. If not someone
else sent us this signal and we ignore it</li>
<li>the main work is done in the <a href="#mainloop">mainloop</a>
it checks if someone pressed enter and looks also periodically for vt_flag if it
was changed. If the kernel sent us the release signal it expects
a confirmation that we are ready for the switch. In case someone
else sent us the signal this confirmation results in an error
(because the kernel doesn't know anything about a pending switch).
So the result will tell us if the signal was sent because of
a pending virtual terminal switch. But this is ugly, because
we can only check this after restoring the terminal to its
original state. Especially under <a href="modex.html#mainloop">ModeX</a>
this results in a screen flickering if someone else sends us
<b>SIGUSR1</b> and our terminal is active. Look here how
mainloop looks in the <a href="fb.html#mainloop">framebuffer</a>
example.
</ul></p>
<dl><dt><b>Note:</b></dt>
<dd><p align="justify">Instead of tinkering around with the release
signal, you can set the release signal in <a href="#setmode"><b>VT_SETMODE</b></a>
to 0, so you won't get one. To still recognize that the user
wants to switch the vt, you can enable
<a href="rawkb.html">raw keyboard mode</a> and look yourself for
ALT-F1. Use <b>VT_ACTIVATE</b> and <b>VT_WAITACTIVE</b>
to switch the vt manually, but you need root rights for this.
</p></dd></dl>
<p align="justify">It is also possible to place the switch code in the signal handlers itself,
but you have to ensure that the underlying program knows that the
switch happened to determine if graphics activity is allowed or not.</p>
<p align="justify">In the <a href="fb.html">framebuffer</a> and
<a href="modex.html">ModeX</a> code we make use of the
<b>KDSETMODE</b> ioctl to switch to <b>KD_GRAPHICS</b>.
It is not necessary to
switch back to <b>KD_TEXT</b> if a terminal switch is going to happen,
because the kernel manages this flag for every virtual terminal.</p>
<p>short procedure for handling vt switches:<ol type="1">
<li>register signal <a href="#handlers">handlers</a></li>
<li>use the <a href="#getstate"><b>VT_GETSTATE</b></a> ioctl to determine
the current virtual terminal (if this fails we are not
on local console)</li>
<li>tell the kernel via <a href="#setmode"><b>VT_SETMODE</b></a>
which signals to send in case of terminal release and acquire</li>
<li>handle incoming signals, in this example done in
the <a href="#mainloop">mainloop</a></li>
</ol></p>
<p align="justify">In this example we use <b>STDIN</b> as file
descriptor for <b>sys_ioctl</b>. This is ok as long as nobody
redirects it to a file or pipe. If you want that the
program even works in this cases: open <b>/dev/tty</b>
and use that file descriptor instead.</p>
<center><table><tr><td><pre>
<!--sof vt.n -->
;****************************************************************************
;****************************************************************************
;*
;* USING VIRTUAL TERMINALS UNDER LINUX
;*
;* written by Karsten Scheibler, 2003-DEC-08
;*
;****************************************************************************
;****************************************************************************
global vt_start
;****************************************************************************
;* some assign's
;****************************************************************************
%assign SYS_IOCTL 54
%assign SYS_SIGACTION 67
%assign SYS_SELECT 142
%assign VT_GETMODE 0x00005601
%assign VT_SETMODE 0x00005602
%assign VT_GETSTATE 0x00005603
%assign VT_RELDISP 0x00005605
%assign VT_PROCESS 1
%assign SIGUSR1 10
%assign SIGUSR2 12
%assign STDIN 0
%assign SA_RESTART 0x10000000
struc tvtmode
alignb 4
tvtmode_mode: resb 1
tvtmode_waitv: resb 1
tvtmode_relsig: resw 1
tvtmode_acqsig: resw 1
tvtmode_frsig: resw 1
endstruc
%if tvtmode_size != 8
%error "wrong size"
%endif
struc tvtstat
alignb 4
tvtstat_active: resw 1
tvtstat_signal: resw 1
tvtstat_state: resw 1
endstruc
%if tvtstat_size > 8
%error "wrong size"
%endif
%assign VT_MODE_SAVED 0x00000001
;****************************************************************************
;* data
;****************************************************************************
section .data
align 4
vt_state: dd 0
vt_flag: dd 0
section .bss
alignb 4
exit_handler: resd 1
error_handler: resd 1
vtmode_data: resb tvtmode_size
vtmode_original: resb tvtmode_size
vtstat_data: resb tvtstat_size
;****************************************************************************
;* vt_start
;****************************************************************************
section .text
vt_start:
xor dword eax, eax
xor dword ebx, ebx
call near vt_init
;<a name="mainloop"></a>mainloop: this code checks if the user
;pressed enter and checks if we have to switch the virtual terminal
.keypress1:
call near vt_check_keypress
cmp dword eax, byte 1
je near vt_end
call near vt_check_release
test dword eax, eax
js short .keypress1
call near vt_commit_release
test dword eax, eax
js short .keypress1
.keypress2:
call near vt_check_keypress ;vt is not active => no keypress
;possible, we simply use select to
;wait here
call near vt_check_acquire
test dword eax, eax
js short .keypress2
jmp short .keypress1
;****************************************************************************
;* vt_init
;****************************************************************************
section .text
vt_init:
mov dword [exit_handler], eax
mov dword [error_handler], ebx
;<a name="handlers"></a>signal handler for release and acquire signal
xor dword edx, edx
push dword edx
push dword SA_RESTART
push dword edx
push dword vt_release_handler
mov dword eax, SYS_SIGACTION
mov dword ebx, SIGUSR1
mov dword ecx, esp
int byte 0x80
add dword esp, byte 16
test dword eax, eax
js near vt_error
xor dword edx, edx
push dword edx
push dword SA_RESTART
push dword edx
push dword vt_acquire_handler
mov dword eax, SYS_SIGACTION
mov dword ebx, SIGUSR2
mov dword ecx, esp
int byte 0x80
add dword esp, byte 16
test dword eax, eax
js near vt_error
;<a name="getstate"></a>get current active virtual terminal
mov dword eax, SYS_IOCTL
mov dword ebx, STDIN
mov dword ecx, VT_GETSTATE
mov dword edx, vtstat_data
int byte 0x80
test dword eax, eax
js near vt_error
mov dword eax, SYS_IOCTL
mov dword ebx, STDIN
mov dword ecx, VT_GETMODE
mov dword edx, vtmode_data
int byte 0x80
test dword eax, eax
js near vt_error
mov dword eax, [vtmode_data]
mov dword ebx, [vtmode_data + 4]
mov dword [vtmode_original], eax
mov dword [vtmode_original + 4], ebx
or dword [vt_state], VT_MODE_SAVED
;<a name="setmode"></a>tell the kernel which signals to use
mov byte [vtmode_data + tvtmode_mode], VT_PROCESS
mov word [vtmode_data + tvtmode_relsig], SIGUSR1
mov word [vtmode_data + tvtmode_acqsig], SIGUSR2
mov dword eax, SYS_IOCTL
mov dword ebx, STDIN
mov dword ecx, VT_SETMODE
mov dword edx, vtmode_data
int byte 0x80
test dword eax, eax
js near vt_error
ret
;****************************************************************************
;* vt_check_keypress
;****************************************************************************
section .text
vt_check_keypress:
push dword (1 << STDIN)
mov dword ecx, esp
push dword 50000 ;1/20 second
push dword 0
mov dword eax, SYS_SELECT
mov dword ebx, (STDIN + 1)
xor dword edx, edx
xor dword esi, esi
mov dword edi, esp
int byte 0x80
add dword esp, byte 12
ret
;****************************************************************************
;* vt_check_release
;****************************************************************************
section .text
vt_check_release:
xor dword eax, eax
cmp dword [vt_flag], byte 1
je short .release
dec dword eax
.release:
ret
;****************************************************************************
;* vt_commit_release
;****************************************************************************
section .text
vt_commit_release:
mov dword eax, SYS_IOCTL
mov dword ebx, STDIN
mov dword ecx, VT_RELDISP
mov dword edx, 1
int byte 0x80
test dword eax, eax
jns short .release
mov dword [vt_flag], 0
.release:
ret
;****************************************************************************
;* vt_check_acquire
;****************************************************************************
section .text
vt_check_acquire:
xor dword eax, eax
cmp dword eax, [vt_flag]
je short .acquire
dec dword eax
.acquire:
ret
;<a name="release"></a>****************************************************************************
;* vt_release_handler
;****************************************************************************
section .text
vt_release_handler:
mov dword [vt_flag], 1
ret
;<a name="acquire"></a>****************************************************************************
;* vt_acquire_handler
;****************************************************************************
section .text
vt_acquire_handler:
sub dword esp, byte 8
mov dword eax, SYS_IOCTL
mov dword ebx, STDIN
mov dword ecx, VT_GETSTATE
mov dword edx, esp
int byte 0x80
mov word bx, [esp + tvtstat_active]
add dword esp, byte 8
test dword eax, eax
js short .no_acquire
cmp word bx, [vtstat_data + tvtstat_active]
jne short .no_acquire
mov dword [vt_flag], 0
.no_acquire:
ret
;****************************************************************************
;* vt_restore
;****************************************************************************
section .text
vt_restore:
test dword [vt_state], VT_MODE_SAVED
jz short .no_mode_saved
mov dword eax, SYS_IOCTL
mov dword ebx, STDIN
mov dword ecx, VT_SETMODE
mov dword edx, vtmode_original
int byte 0x80
.no_mode_saved:
ret
;****************************************************************************
;* vt_error
;****************************************************************************
section .text
vt_error:
call near vt_restore
xor dword eax, eax
cmp dword eax, [error_handler]
je short .no_handler
jmp dword [error_handler]
.no_handler:
inc dword eax
mov dword ebx, eax
int byte 0x80
;****************************************************************************
;* vt_end
;****************************************************************************
section .text
vt_end:
call near vt_restore
xor dword eax, eax
cmp dword eax, [exit_handler]
je short .no_handler
jmp dword [exit_handler]
.no_handler:
xor dword ebx, ebx
inc dword eax
int byte 0x80
;*********************************************** linuxassembly@unusedino.de *
<!--eof-->
</pre></td></tr></table></center>
<!--sof Makefile
NASM=nasm -w+orphan-labels -w+macro-params -w+number-overflow -f elf
STRIP=strip -R .note -R .comment
LD=ld -s
RM=rm -f
.PHONY: all clean
all: vt
vt: vt.n
${NASM} -o vt.o vt.n
${LD} -e vt_start -o vt vt.o
${STRIP} vt
clean:
${RM} *.bak *~ vt vt.o core
<!--eof-->
</body>
</html>