Subversion Repositories Kolibri OS

Rev

Rev 1065 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1065 Lrz 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                     ;;
3
;; Last modify Alexey Teplov  2008. All rights reserved.          ;;
4
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved.        ;;
5
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa             ;;
6
;; Distributed under terms of the GNU General Public License           ;;
7
;;                                                                     ;;
8
;;  kolibri_ldm.asm the module for Secondary Loader                    ;;
9
;;                                                                     ;;
10
;;  KolibriOS 16-bit loader module,                                    ;;
11
;;                        based on bootcode for KolibriOS              ;;
12
;;                                                                     ;;
13
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14
 
1156 Lrz 15
include "lang.inc"
16
 
1065 Lrz 17
macro _setcursor row,column
18
{
19
        mov     dx, row*256 + column
20
        call    setcursor
21
}
22
long_v_table equ 9   ;long of visible video table
23
size_of_step equ 10
24
d80x25_bottom_num equ 3
25
d80x25_top_num equ 4
26
;It's a module for Secondary Loader to load kolibri OS
27
;
28
start_of_code:
29
        cld
30
; \begin{diamond}[02.12.2005]
31
; if bootloader sets ax = 'KL', then ds:si points to loader block
32
;        cmp     ax, 'KL'
33
;        jnz     @f
34
;        mov     word [cs:cfgmanager.loader_block], si
35
;        mov     word [cs:cfgmanager.loader_block+2], ds
36
;@@:
37
; \end{diamond}[02.12.2005]
38
 
39
; if bootloader sets cx = 'HA' and dx = 'RD', then bx contains identifier of source hard disk
40
; (see comment to bx_from_load)
41
;        cmp     cx, 'HA'
42
;        jnz     no_hd_load
43
;        cmp     dx,'RD'
44
;        jnz     no_hd_load
45
;        mov     word [cs:bx_from_load], bx              ; {SPraid}[13.03.2007]
46
;no_hd_load:
47
 
48
; set up stack
49
	push	cs
50
	pop	ss
51
	xor	ax,ax
52
	mov	sp,ax
53
;        mov     ax, 3000h
54
;        mov     ss, ax
55
;        mov     sp, 0EC00h
56
; set up segment registers
57
        push    cs
58
        pop     ds
59
        push    cs
60
        pop     es
61
 
62
; set videomode
63
        mov     ax, 3
64
        int     0x10
65
 
66
;if lang eq ru
67
 ; Load & set russian VGA font (RU.INC)
68
        mov     bp, RU_FNT1             ; RU_FNT1 - First part
69
        mov     bx, 1000h               ; 768 bytes
70
        mov     cx, 30h                 ; 48 symbols
71
        mov     dx, 80h                 ; 128 - position of first symbol
72
        mov     ax, 1100h
73
        int     10h
74
 
75
        mov     bp, RU_FNT2             ; RU_FNT2 -Second part
76
        mov     bx, 1000h               ; 512 bytes
77
        mov     cx, 20h                 ; 32 symbols
78
        mov     dx, 0E0h                ; 224 - position of first symbol
79
        mov     ax, 1100h
80
        int     10h
81
 ; End set VGA russian font
82
;else if lang eq et
83
;        mov     bp, ET_FNT              ; ET_FNT1
84
;        mov     bx, 1000h               ;
85
;        mov     cx, 255                 ; 256 symbols
86
;        xor     dx, dx                  ; 0 - position of first symbol
87
;        mov     ax, 1100h
88
;        int     10h
89
;end if
90
 
91
; draw frames
92
        push    0xb800
93
        pop     es
94
        xor     di, di
95
        mov     ah, 1*16+15
96
 
97
; draw top
98
        mov     si, d80x25_top
99
        mov     cx, d80x25_top_num * 80
100
@@:
101
        lodsb
102
        stosw
103
        loop    @b
104
; draw spaces
105
        mov     si, space_msg
106
        mov     dx, 25 - d80x25_top_num - d80x25_bottom_num
107
dfl1:
108
        push    si
109
        mov     cx, 80
110
@@:
111
        lodsb
112
        stosw
113
        loop    @b
114
        pop     si
115
        dec     dx
116
        jnz     dfl1
117
; draw bottom
118
        mov     si, d80x25_bottom
119
        mov     cx, d80x25_bottom_num * 80
120
@@:
121
        lodsb
122
        stosw
123
        loop    @b
124
 
125
        mov     byte [space_msg+80], 0    ; now space_msg is null terminated
126
 
127
        _setcursor d80x25_top_num,0
128
 
129
 
130
; TEST FOR 386+
131
 
132
        mov     bx, 0x4000
133
        pushf
134
        pop     ax
135
        mov     dx, ax
136
        xor     ax, bx
137
        push    ax
138
        popf
139
        pushf
140
        pop     ax
141
        and     ax, bx
142
        and     dx, bx
143
        cmp     ax, dx
144
        jnz     cpugood
145
        mov     si, not386
146
sayerr:
147
        call    print
148
        jmp     $
149
     cpugood:
150
 
151
        push    0
152
        popf
153
        sti
154
 
155
; set up esp
156
        movzx   esp, sp
157
 
158
        push    0
159
        pop     es
160
        and     word [es:0x9031], 0
161
; \begin{Mario79}
162
; find HDD IDE DMA PCI device
163
; check for PCI BIOS
164
        mov     ax, 0xB101
165
        int     0x1A
166
        jc      .nopci
167
        cmp     edx, 'PCI '
168
        jnz     .nopci
169
; find PCI class code
170
; class 1 = mass storage
171
; subclass 1 = IDE controller
172
; a) class 1, subclass 1, programming interface 0x80
173
        mov     ax, 0xB103
174
        mov     ecx, 1*10000h + 1*100h + 0x80
175
        xor     si, si  ; device index = 0
176
        int     0x1A
177
        jnc     .found
178
; b) class 1, subclass 1, programming interface 0x8A
179
        mov     ax, 0xB103
180
        mov     ecx, 1*10000h + 1*100h + 0x8A
181
        xor     si, si  ; device index = 0
182
        int     0x1A
183
        jnc     .found
184
; c) class 1, subclass 1, programming interface 0x85
185
        mov     ax, 0xB103
186
        mov     ecx, 1*10000h + 1*100h + 0x85
187
        xor     si, si
188
        int     0x1A
189
        jc      .nopci
190
.found:
191
; get memory base
192
        mov     ax, 0xB10A
193
        mov     di, 0x20        ; memory base is config register at 0x20
194
        int     0x1A
195
        jc      .nopci
196
        and     cx, 0xFFF0      ; clear address decode type
197
        mov     [es:0x9031], cx
198
.nopci:
199
; \end{Mario79}
200
 
201
        mov     al, 0xf6        ; Ñáðîñ êëàâèàòóðû, ðàçðåøèòü ñêàíèðîâàíèå
202
        out     0x60, al
203
        xor     cx, cx
204
wait_loop:       ; variant 2
205
; reading state of port of 8042 controller
206
        in      al, 64h
207
        and     al, 00000010b  ; ready flag
208
; wait until 8042 controller is ready
209
        loopnz  wait_loop
210
 
211
;;;/diamond today   5.02.2008
212
; set keyboard typematic rate & delay
213
        mov     al, 0xf3
214
        out     0x60, al
215
        xor     cx, cx
216
@@:
217
        in      al, 64h
218
        test    al, 2
219
        loopnz  @b
220
        mov     al, 0
221
        out     0x60, al
222
        xor     cx, cx
223
@@:
224
        in      al, 64h
225
        test    al, 2
226
        loopnz  @b
227
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
228
; --------------- APM ---------------------
229
        and     word [es:0x9044], 0     ; ver = 0.0 (APM not found)
230
        mov     ax, 0x5300
231
        xor     bx, bx
232
        int     0x15
233
        jc      apm_end                 ; APM not found
234
        test    cx, 2
235
        jz      apm_end                 ; APM 32-bit protected-mode interface not supported
236
        mov     [es:0x9044], ax         ; Save APM Version
237
        mov     [es:0x9046], cx         ; Save APM flags
238
 
239
        ; Write APM ver ----
240
        and     ax, 0xf0f
241
        add     ax, '00'
242
        mov     si, msg_apm
243
        mov     [si + 5], ah
244
        mov     [si + 7], al
245
        _setcursor 0, 3
246
        call    printplain
247
        ; ------------------
248
 
249
        mov     ax, 0x5304              ; Disconnect interface
250
        xor     bx, bx
251
        int     0x15
252
        mov     ax, 0x5303              ; Connect 32 bit mode interface
253
        xor     bx, bx
254
        int     0x15
255
 
256
        mov     [es:0x9040], ebx
257
        mov     [es:0x9050], ax
258
        mov     [es:0x9052], cx
259
        mov     [es:0x9054], dx
260
 
261
apm_end:
262
        _setcursor d80x25_top_num, 0
263
 
264
;CHECK current of code
265
        cmp     [cfgmanager.loader_block], -1
266
        jz      noloaderblock
267
        les     bx, [cfgmanager.loader_block]
268
        cmp     byte [es:bx], 1
269
        mov     si, loader_block_error
270
        jnz     sayerr
271
        push    0
272
        pop     es
273
 
274
noloaderblock:
275
; DISPLAY VESA INFORMATION
276
         call    print_vesa_info
277
         call    calc_vmodes_table
278
         call    check_first_parm  ;check and enable cursor_pos
279
 
280
 
281
; \begin{diamond}[30.11.2005]
282
cfgmanager:
283
; settings:
284
; a) preboot_graph = graphical mode
285
;    preboot_gprobe = probe this mode?
286
; b) preboot_dma  = use DMA access?
287
; c) preboot_vrrm = use VRR?
288
 
289
; determine default settings
290
        mov     [.bSettingsChanged], 0
291
 
292
;.preboot_gr_end:
293
        mov     di, preboot_device
294
; if image in memory is present and [preboot_device] is uninitialized,
295
; set it to use this preloaded image
296
        cmp     byte [di], 0
297
        jnz     .preboot_device_inited
298
        cmp     [.loader_block], -1
299
        jz      @f
300
        les     bx, [.loader_block]
301
        test    byte [es:bx+1], 1
302
        jz      @f
303
        mov     byte [di], 3
304
        jmp     .preboot_device_inited
305
@@:
306
; otherwise, set [preboot_device] to 1 (default value - boot from floppy)
307
        mov     byte [di], 1
308
.preboot_device_inited:
309
; following 6 lines set variables to 1 if its current value is 0
310
        cmp     byte [di+preboot_dma-preboot_device], 1
311
        adc     byte [di+preboot_dma-preboot_device], 0
312
        cmp     byte [di+preboot_biosdisk-preboot_device], 1
313
        adc     byte [di+preboot_biosdisk-preboot_device], 0
314
        cmp     byte [di+preboot_vrrm-preboot_device], 1
315
        adc     byte [di+preboot_vrrm-preboot_device], 0
316
; notify user
317
        _setcursor 5,2
318
 
319
        mov     si, linef
320
        call    printplain
321
        mov     si, start_msg
322
        call    print
323
        mov     si, time_msg
324
        call    print
325
; get start time
326
        call    .gettime
327
        mov     [.starttime], eax
328
        mov     word [.timer], .newtimer
329
        mov     word [.timer+2], cs
330
.printcfg:
331
        _setcursor 9,0
332
        mov     si, current_cfg_msg
333
        call    print
334
        mov     si, curvideo_msg
335
        call    print
336
 
337
            call    draw_current_vmode
338
 
339
        mov     si, usebd_msg
340
        cmp     [preboot_biosdisk], 1
341
        call    .say_on_off
342
        mov     si, vrrm_msg
343
        cmp     [preboot_vrrm], 1
344
        call    .say_on_off
345
;        mov     si, preboot_device_msg
346
;        call    print
347
;        mov     al, [preboot_device]
348
;        and     eax, 7
349
;        mov     si, [preboot_device_msgs+eax*2]
350
;        call    printplain
351
.show_remarks:
352
; show remarks in gray color
353
        mov     di, ((21-num_remarks)*80 + 2)*2
354
        push    0xB800
355
        pop     es
356
        mov     cx, num_remarks
357
        mov     si, remarks
358
.write_remarks:
359
        lodsw
360
        push    si
361
        xchg    ax, si
362
        mov     ah, 1*16+7      ; background: blue (1), foreground: gray (7)
363
        push    di
364
.write_remark:
365
        lodsb
366
        test    al, al
367
        jz      @f
368
        stosw
369
        jmp     .write_remark
370
@@:
371
        pop     di
372
        pop     si
373
        add     di, 80*2
374
        loop    .write_remarks
375
.wait:
376
        _setcursor 25,0         ; out of screen
377
; set timer interrupt handler
378
        cli
379
        push    0
380
        pop     es
381
        push    dword [es:8*4]
382
        pop     dword [.oldtimer]
383
        push    dword [.timer]
384
        pop     dword [es:8*4]
385
;        mov     eax, [es:8*4]
386
;        mov     [.oldtimer], eax
387
;        mov     eax, [.timer]
388
;        mov     [es:8*4], eax
389
        sti
390
; wait for keypressed
391
        xor     ax,ax
392
        int     16h
393
        push    ax
394
; restore timer interrupt
395
;        push    0
396
;        pop     es
397
        mov     eax, [.oldtimer]
398
        mov     [es:8*4], eax
399
        mov     [.timer], eax
400
        _setcursor 7,0
401
        mov     si, space_msg
402
        call    printplain
403
; clear remarks and restore normal attributes
404
        push    es
405
        mov     di, ((21-num_remarks)*80 + 2)*2
406
        push    0xB800
407
        pop     es
408
        mov     cx, num_remarks
409
        mov     ax, ' ' + (1*16 + 15)*100h
410
@@:
411
        push    cx
412
        mov     cx, 76
413
        rep     stosw
414
        pop     cx
415
        add     di, 4*2
416
        loop    @b
417
        pop     es
418
        pop     ax
419
; switch on key
420
        cmp     al, 13
421
        jz      .continue
422
        or      al, 20h
423
        cmp     al, 'a'
424
        jz      .change_a
425
        cmp     al, 'b'
426
        jz      .change_b
427
        cmp     al, 'c'
428
        jnz     .show_remarks
429
 
430
        _setcursor 15,0
431
        mov     si, vrrmprint
432
        call    print
433
        mov     bx, '12'
434
        call    getkey
435
        mov     [preboot_vrrm], al
436
        _setcursor 12,0
437
.d:
438
        mov     [.bSettingsChanged], 1
439
        call    clear_vmodes_table             ;clear vmodes_table
440
        jmp    .printcfg
441
.change_a:
442
.loops:
443
        call    draw_vmodes_table
444
        _setcursor 25,0         ; out of screen
445
        xor     ax,ax
446
        int     0x16
447
;        call    clear_table_cursor             ;clear current position of cursor
448
 
449
        mov     si,word [cursor_pos]
450
 
451
        cmp     ah,0x48;x,0x48E0               ; up
452
        jne     .down
453
        cmp     si,modes_table
454
        jbe     .loops
455
        sub     word [cursor_pos],size_of_step
456
        jmp     .loops
457
 
458
.down:  cmp     ah,0x50;x,0x50E0               ; down
459
        jne     .pgup
460
        cmp     word[es:si+10],-1
461
        je      .loops
462
        add     word [cursor_pos],size_of_step
463
        jmp     .loops
464
 
465
.pgup:  cmp     ah,0x49                 ; page up
466
        jne     .pgdn
467
        sub     si, size_of_step*long_v_table
468
        cmp     si, modes_table
469
        jae     @f
470
        mov     si, modes_table
471
@@:
472
        mov     word [cursor_pos], si
473
        mov     si, word [home_cursor]
474
        sub     si, size_of_step*long_v_table
475
        cmp     si, modes_table
476
        jae     @f
477
        mov     si, modes_table
478
@@:
479
        mov     word [home_cursor], si
480
        jmp     .loops
481
 
482
.pgdn:  cmp     ah,0x51                 ; page down
483
        jne     .enter
484
        mov     ax, [end_cursor]
485
        add     si, size_of_step*long_v_table
486
        cmp     si, ax
487
        jb      @f
488
        mov     si, ax
489
        sub     si, size_of_step
490
@@:
491
        mov     word [cursor_pos], si
492
        mov     si, word [home_cursor]
493
        sub     ax, size_of_step*long_v_table
494
        add     si, size_of_step*long_v_table
495
        cmp     si, ax
496
        jb      @f
497
        mov     si, ax
498
@@:
499
        mov     word [home_cursor], si
500
        jmp     .loops
501
 
502
.enter: cmp     al,0x0D;x,0x1C0D               ; enter
503
        jne     .loops
504
        push    word [cursor_pos]
505
        pop     bp
506
        push    word [es:bp]
507
        pop     word [x_save]
508
        push    word [es:bp+2]
509
        pop     word [y_save]
510
        push    word [es:bp+6]
511
        pop     word [number_vm]
512
        mov     word [preboot_graph],bp           ;save choose
513
 
514
        jmp    .d
515
 
516
.change_b:
517
        _setcursor 15,0
518
;        mov     si, ask_dma
519
;        call    print
520
;        mov     bx, '13'
521
;        call    getkey
522
;        mov     [preboot_dma], al
523
        mov     si, ask_bd
524
        call    print
525
        mov     bx, '12'
526
        call    getkey
527
        mov     [preboot_biosdisk], al
528
        _setcursor 11,0
529
        jmp     .d
530
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
531
.say_on_off:
532
        pushf
533
        call    print
534
        mov     si, on_msg
535
        popf
536
        jz      @f
537
        mov     si, off_msg
538
@@:     jmp     printplain
539
; novesa and vervesa strings are not used at the moment of executing this code
540
virtual at novesa
541
.oldtimer dd ?
542
.starttime dd ?
543
.bSettingsChanged db ?
544
.timer dd ?
545
end virtual
546
.loader_block dd -1
547
.gettime:
548
        mov     ah, 0
549
        int     1Ah
550
        xchg    ax, cx
551
        shl     eax, 10h
552
        xchg    ax, dx
553
        ret
554
.newtimer:
555
        push    ds
556
        push    cs
557
        pop     ds
558
        pushf
559
        call    [.oldtimer]
560
        pushad
561
        call    .gettime
562
        sub     eax, [.starttime]
563
        sub     ax, 18*5
564
        jae     .timergo
565
        neg     ax
566
        add     ax, 18-1
567
        mov     bx, 18
568
        xor     dx, dx
569
        div     bx
570
if lang eq ru
571
; ¯®¤®¦¤¨â¥ 5 ᥪ㭤, 4/3/2 ᥪ㭤ë, 1 ᥪ㭤ã
572
        cmp     al, 5
573
        mov     cl, ' '
574
        jae     @f
575
        cmp     al, 1
576
        mov     cl, 'ã'
577
        jz      @f
578
        mov     cl, 'ë'
579
@@:     mov     [time_str+9], cl
580
else if lang eq et
581
        cmp     al, 1
582
        ja      @f
583
        mov     [time_str+9], ' '
584
        mov     [time_str+10],' '
585
@@:
586
else
587
; wait 5/4/3/2 seconds, 1 second
588
        cmp     al, 1
589
        mov     cl, 's'
590
        ja      @f
591
        mov     cl, ' '
592
@@:     mov     [time_str+9], cl
593
end if
594
        add     al, '0'
595
        mov     [time_str+1], al
596
        mov     si, time_msg
597
        _setcursor 7,0
598
        call    print
599
        _setcursor 25,0
600
        popad
601
        pop     ds
602
        iret
603
.timergo:
604
        push    0
605
        pop     es
606
        mov     eax, [.oldtimer]
607
        mov     [es:8*4], eax
608
        mov     sp, 0EC00h
609
.continue:
610
        sti
611
        _setcursor 6,0
612
        mov     si, space_msg
613
        call    printplain
614
        call    printplain
615
        _setcursor 6,0
616
        mov     si, loading_msg
617
        call    print
618
        _setcursor 15,0
619
        cmp     [.bSettingsChanged], 0
620
        jz      .load
621
        cmp     [.loader_block], -1
622
        jz      .load
623
        les     bx, [.loader_block]
624
        mov     eax, [es:bx+3]
625
        push    ds
626
        pop     es
627
        test    eax, eax
628
        jz      .load
629
        push    eax
630
        mov     si, save_quest
631
        call    print
632
.waityn:
633
        mov     ah, 0
634
        int     16h
635
        or      al, 20h
636
        cmp     al, 'n'
637
        jz      .loadc
638
        cmp     al, 'y'
639
        jnz     .waityn
640
        call    putchar
641
        mov     byte [space_msg+80], 186
642
        pop     eax
643
        push    cs
644
        push    .cont
645
        push    eax
646
        retf
647
.loadc:
648
        pop     eax
649
.cont:
650
        push    cs
651
        pop     ds
652
        mov     si, space_msg
653
        mov     byte [si+80], 0
654
        _setcursor 15,0
655
        call    printplain
656
        _setcursor 15,0
657
.load:
658
; \end{diamond}[02.12.2005]
659
 
660
; ASK GRAPHICS MODE
661
 
662
        call    set_vmode
663
 
664
; GRAPHICS ACCELERATION
665
; force yes
666
        mov     [es:0x901C], byte 1
667
 
668
; DMA ACCESS TO HD
669
 
670
        mov     al, [preboot_dma]
671
        mov     [es:0x901F], al
672
 
673
; VRR_M USE
674
 
675
        mov     al,[preboot_vrrm]
676
        mov     [es:0x9030], al
677
        mov     [es:0x901E], byte 1
678
 
679
; BOOT DEVICE
680
 
681
        mov     al, [preboot_device]
682
        dec     al
683
        mov     [boot_dev], al
684
 
685
 
686
 
687
 
688
 
689
 
690
;;;;;;;;;;; set videomode
691
        xor     ax, ax
692
        mov     es, ax
693
 
694
        mov     ax, [es:0x9008]         ; vga & 320x200
695
        mov     bx, ax
696
        cmp     ax, 0x13
697
        je      setgr
698
        cmp     ax, 0x12
699
        je      setgr
700
        mov     ax, 0x4f02              ; Vesa
701
setgr:
702
        int     0x10
703
        test    ah, ah
704
        mov     si, fatalsel
705
        jnz     v_mode_error
706
; set mode 0x12 graphics registers:
707
        cmp     bx, 0x12
708
        jne     gmok2
709
 
710
        mov     al, 0x05
711
        mov     dx, 0x03ce
712
        push    dx
713
        out     dx, al      ; select GDC mode register
714
        mov     al, 0x02
715
        inc     dx
716
        out     dx, al      ; set write mode 2
717
 
718
        mov     al, 0x02
719
        mov     dx, 0x03c4
720
        out     dx, al      ; select VGA sequencer map mask register
721
        mov     al, 0x0f
722
        inc     dx
723
        out     dx, al      ; set mask for all planes 0-3
724
 
725
        mov     al, 0x08
726
        pop     dx
727
        out     dx, al      ; select GDC bit mask register
728
                           ; for writes to 0x03cf
729
gmok2:
730
        push    ds
731
        pop     es
732
 
733
	jmp	$
734
 
735
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
736
;data
737
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
738
include "lang.inc"
739
include "bootstr.inc"     ; language-independent boot messages
740
;if lang eq en
741
;include "booteng.inc"     ; english system boot messages
742
;else if lang eq ru
743
include "bootru.inc"      ; russian system boot messages
744
include "ru.inc"	       ; Russian font
745
;else if lang eq et
746
;include "bootet.inc"      ; estonian system boot messages
747
;include "et.inc"	       ; Estonian font
748
;else
749
;include "bootge.inc"      ; german system boot messages
750
;end if
751
 
752
include 'macros.inc'
753
include 'bootvesa.inc'
754
 
755
include "preboot.inc"
756
 
757
 
758
setcursor:
759
; in: dl=column, dh=row
760
        mov     ah, 2
761
        mov     bh, 0
762
        int     10h
763
        ret
764
 
765
putchar:
766
; in: al=character
767
        mov     ah, 0Eh
768
        mov     bh, 0
769
        int     10h
770
        ret
771
 
772
print:
773
; in: si->string
774
        mov     al, 186
775
        call    putchar
776
        mov     al, ' '
777
        call    putchar
778
 
779
printplain:
780
; in: si->string
781
        pusha
782
        lodsb
783
@@:
784
        call    putchar
785
        lodsb
786
        cmp     al, 0
787
        jnz     @b
788
        popa
789
        ret
790
 
791
getkey:
792
; get number in range [bl,bh] (bl,bh in ['0'..'9'])
793
; in: bx=range
794
; out: ax=digit (1..9, 10 for 0)
795
        mov     ah, 0
796
        int     16h
797
        cmp     al, bl
798
        jb      getkey
799
        cmp     al, bh
800
        ja      getkey
801
        push    ax
802
        call    putchar
803
        pop     ax
804
        and     ax, 0Fh
805
        jnz     @f
806
        mov     al, 10
807
@@:
808
        ret