forked from Howerd/colorForth
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cf2023.lst
10201 lines (10201 loc) · 700 KB
/
cf2023.lst
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
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1 ; cf2023.nasm 2023 Apr 04 MD5 "roomed-zebra"
2 ; Fixing Magenta Variables
3 ; Added "locate" - pressing the Enter key executes the red word or locates the green word at the cursor
4 ; "chm" ( check MD5 ) in colorForth shows "ff" "la:rrr" "nos" "td"
5 ; colorForth for 80x86 PC for NASM , with 1024x768 and 800x600 graphics options
6 ; Adapted by Howerd Oakford from code by :
7 ; Chuck Moore : inventor, MASM
8 ; Mark Slicker : ported to GNU Assembler
9 ; Peter Appelman : ported to NASM with qwerty keyboard
10 ; Josh Grams : multitasker
11 ; John Comeau : BIOS boot from ClusterFix
12 ; Marco Nicola : 2drop and 2dup bug fix
13 ; Miroslav Popov : keyboard instead of keypad typos
14 ; and others... Thanks to all!!!
15 ; Feedback welcome : [email protected] www.inventio.co.uk
16
17 ; %define NOT_BOCHS ; Bochs cannot handle resetting of the PIT chips, so we disable this to allow operation in Bochs
18
19 ; CPU 386 ; Assemble instructions for the 386 instruction set
20
21 %define FORCE_800x600_VESA 0 ; true to force 800 x 600 x 16 bits for testing in bochs
22
23 %define START_BLOCK_NUMBER 64 ; must be an even number. Note: if you change this you must shift the blocks in cf2022Ref.img accordingly!
24
25 %define SIZE_OF_FONT_IN_BLOCKS 12
26 %define OFFSET_OF_FONT ( ( START_BLOCK_NUMBER - SIZE_OF_FONT_IN_BLOCKS ) * 0x400 )
27 %define LAST_BLOCK_NUMBER 511 ; must be an odd number
28
29 %define SECTORS_TO_LOAD ( ( LAST_BLOCK_NUMBER + 1 ) * 2 ) ; number of 512 byte sectors
30
31 %define BITS_PER_PIXEL 16 ; MUST BE 16 !!! display pixel sizes, colour depth = 16 bit ( 2 bytes )
32
33 ; for the maximum supported screen : 1024 x 76go8 pixels :
34 %define MAX_SCREEN_WIDTH ( 1024 ) ; maximum screen width in pixels
35 %define MAX_SCREEN_HEIGHT ( 768 ) ; maximum screen height in pixels
36
37 %define BYTES_PER_PIXEL ( BITS_PER_PIXEL / 8 )
38
39 PIXEL_SHIFT equ 1 ; how many bits to shift to scale by BYTES_PER_PIXEL
40
41 ; Memory Map
42 ; start length
43 ; 0x100000 .... RAM
44 ; 0xC0000 0xFFFFF BIOS video ROM - its not RAM!
45 ; 0xB8000 0x08000 BIOS video RAM
46 ; 0x10000 0xA8000 cf2022.img file is copied here
47 ; 0x0F000 0x01000 BIOS shadow RAM - its OK to use this if we do not call the video BIOS
48 ; 0x0A000 0x05000 BIOS video RAM - do not use until we have changed video mode
49 ; 0x07c00 0x00200 BPB Boot sector after loading by BIOS
50 ; 0x07c0b <----- di points here, the BPB ( + offset ) and variables ( - offset ) are accessed via [di]
51 ; 0x07b8c 0x00080 variables referenced via [di], followed by BPB variables referenced via [di]
52 ; 0x07800 Stacks, size = 0x0200 each , growing downwards
53 ; 0x02000 0x06800 SECTOR_BUFFER
54 ; 0x00000 0x02000 BIOS RAM
55
56 %define SECTOR_BUFFER 0x00002000 ; buffer for disk reads and writes
57 %define SECTOR_BUFFER_SIZE 0x4800 ; 18 K bytes, 36 x 512 byte sectors
58 %define INTERRUPT_VECTORS ( SECTOR_BUFFER - 0x0400 ) ; the IDT register points to these interrupt vectors
59 %define VESA_BUFFER ( INTERRUPT_VECTORS - 0x0400 ) ; for the VESA mode information
60 %define DAP_BUFFER ( VESA_BUFFER - 0x0020 ) ; 0x1BE0 for the Int 0x13 Disk Address Packet (DAP)
61 %define DISK_INFO ( DAP_BUFFER - 0x0020 ) ; for the Int 0x13 AH=08h get info
62 %define IDT_AND_PIC_SETTINGS ( DISK_INFO - 0x0040 ) ; bytes 0x00 - 0x05 SIDT value, 0x06 PIC1 IMR , 0x07 PIC2 IMR values saved at startup
63 %define V_REGS ( IDT_AND_PIC_SETTINGS - 0x0020 ) ; test only - registers before and after thunk call
64 %define MD5_OUTPUT_BUFFER ( V_REGS - 0x0020 ) ; the MD5 hash result
65
66 %define TRASH_BUFFER ( (508 * 0x0400) + 0x10000 ) ; Block 508, saves words deleted while editing
67
68 %define PIC_BIOS_IDT_SETTINGS ( IDT_AND_PIC_SETTINGS ) ; bytes 0x00 - 0x05 SIDT value, 0x06 PIC1 IMR , 0x07 PIC2 IMR values saved at startup
69 %define PIC_BIOS_IMR_SETTINGS ( IDT_AND_PIC_SETTINGS + 6 ) ; bytes 0x00 - 0x05 SIDT value, 0x06 PIC1 IMR , 0x07 PIC2 IMR
70
71 %define PIC_NEW_IDT_SETTINGS ( IDT_AND_PIC_SETTINGS + 0x10 ) ; bytes 0x00 - 0x05 SIDT value, 0x08 new PIC1 IMR , 0x09 new PIC2 IMR
72 %define PIC_NEW_IMR_SETTINGS ( IDT_AND_PIC_SETTINGS + 0x16 ) ; bytes 0x00 - 0x05 SIDT value, 0x08 new PIC1 IMR , 0x09 new PIC2 IMR
73
74 %define IDT_AND_PIC_SETTINGS_PAD ( IDT_AND_PIC_SETTINGS + 0x20 )
75
76 %define vesa_BytesPerScanLine ( VESA_BUFFER + 0x0E ) ; screen width ( number of horizontal pixels )
77 %define vesa_XResolution ( VESA_BUFFER + 0x12 ) ; screen width ( number of horizontal pixels )
78 %define vesa_YResolution ( VESA_BUFFER + 0x14 ) ; screen height ( number of vertical pixels )
79 %define vesa_BitsPerPixel ( VESA_BUFFER + 0x19 ) ; bits per pixel
80 %define vesa_SavedMode ( VESA_BUFFER + 0x1E ) ; "Reserved" - we save the VESA mode here
81 %define vesa_PhysBasePtr ( VESA_BUFFER + 0x28 ) ; address of linear frame buffer
82
83 %define BOOTOFFSET 0x7C00
84
85 %assign RELOC_BIT 16 ; the relocation address must be a power of 2
86 %assign RELOCATED 1 << RELOC_BIT ; 0x10000
87
88 ; *****************************************************************************
89 ; Data and Return stack allocation, four pairs of data and return stacks
90 ; Note : the return stack must be in the lowest 64K byte segment, for the BIOS calls to work
91 ; *****************************************************************************
92 %define DATA_STACK_SIZE_0 $0400 ;
93 %define DATA_STACK_SIZE_1 $0500 ; must be > $400 for colorForth "Life" program to work
94 %define DATA_STACK_SIZE_2 $0100 ;
95 %define DATA_STACK_SIZE_3 $0100 ;
96 %define DATA_STACK_SIZE_GAP $0100 ; leave space under the last data stack to check for underflow
97
98 %define RETURN_STACK_SIZE $0100 ;
99
100 ; return stacks
101 %define RETURN_STACK_0 ( $7800 ) ; top of stack memory area
102 %define RETURN_STACK_1 ( RETURN_STACK_0 - RETURN_STACK_SIZE )
103 %define RETURN_STACK_2 ( RETURN_STACK_1 - RETURN_STACK_SIZE )
104 %define RETURN_STACK_3 ( RETURN_STACK_2 - RETURN_STACK_SIZE )
105
106 ; data stacks
107 %define DATA_STACK_0 ( RETURN_STACK_3 - RETURN_STACK_SIZE )
108 %define DATA_STACK_1 ( DATA_STACK_0 - DATA_STACK_SIZE_0 ) ; BIG data stack for the show task
109 %define DATA_STACK_2 ( DATA_STACK_1 - DATA_STACK_SIZE_1 )
110 %define DATA_STACK_3 ( DATA_STACK_2 - DATA_STACK_SIZE_2 )
111 %define STACK_MEMORY_START ( DATA_STACK_3 - DATA_STACK_SIZE_3 - DATA_STACK_SIZE_GAP )
112
113 ; four pairs of stacks, one for each task
114 %define TOTAL_STACK_SIZE ( RETURN_STACK_0 - STACK_MEMORY_START )
115
116 %define STACK_ANALYSIS_BUFFER ( STACK_MEMORY_START - 0x200 )
117
118 ; *****************************************************************************
119 ; *****************************************************************************
120
121 %define _TOS_ eax
122 %define _TOS_x_ ax
123 %define _TOS_l_ al
124
125 %define _SCRATCH_ ebx
126 %define _SCRATCH_x_ bx
127 %define _SCRATCH_l_ bl
128
129 %define _MOV_TOS_LIT_ (0xB8) ; the opcode for mov eax, 32_bit_literal (in next 32 bit cell)
130
131 %macro _DUP_ 0 ; Top Of Stack is in the _TOS_ register
132 lea esi, [ esi - 4 ] ; pre-decrement the stack pointer, does not set the flags
133 ; sub esi, byte 0x04 ; pre-decrement the stack pointer, also sets the flags
134 mov [ esi ], _TOS_ ; copy the Top Of Stack ( TOS ) register to Second On Stack ( on the real stack )
135 %endmacro
136
137 %macro _SWAP_ 0
138 xchg _TOS_, [ esi ]
139 %endmacro
140
141 %macro _OVER_ 0
142 sub esi, byte 0x04 ; pre-decrement the stack pointer
143 mov [ esi ], _TOS_ ; copy the Top Of Stack ( TOS ) register to Second On Stack ( on the real stack )
144 mov _TOS_, [ esi + 4 ]
145 %endmacro
146
147 %macro _DROP_ 0
148 lodsd ; loads a 32 bit dword from [ds:esi] into eax then increments esi by 4
149 %endmacro
150 ; Note : stosd ; stores eax into the location pointed to by edi then increments edi by 4
151 ; Note also : eax is used as _TOS_ ( Top Of Stack )
152
153 ; Define the location of the wordlists in RAM
154 %define START_OF_RAM 0x00468000
155 %define WORDLIST_SIZE 0x2000
156 %define ForthNames START_OF_RAM ; copied to RAM here from ROM ( i.e. boot program ) version
157 %define ForthLocates ( ForthNames + WORDLIST_SIZE ) ; copied to RAM here from ROM ( i.e. boot program ) version
158 %define ForthJumpTable ( ForthLocates + WORDLIST_SIZE ) ; copied to RAM here from ROM ( i.e. boot program ) version
159 %define MacroNames ( ForthJumpTable + WORDLIST_SIZE ) ; copied to RAM here from ROM ( i.e. boot program ) version
160 %define MacroJumpTable ( MacroNames + WORDLIST_SIZE ) ; copied to RAM here from ROM ( i.e. boot program ) version
161 %define MacroLocates ( MacroJumpTable + WORDLIST_SIZE ) ; copied to RAM here from ROM ( i.e. boot program ) version
162 ; some more room...
163 %define H0 0x00480000 ; ( MacroLocates + WORDLIST_SIZE ) ; initial value of the dictionary pointer
164
165 %define SECTOR 512 ; bytes per floppy sector
166 %define HEADS 2 ; heads on 1.44M floppy drive
167 %define SECTORS 18 ; floppy sectors per track
168 %define CYLINDER (SECTOR * SECTORS * HEADS)
169 %define CELL 4 ; bytes per cell
170 %define DEBUGGER 0xe1 ; port to hardware debugger?
171
172 ; int 0x13 Disk Address Packet (DAP) pointed to by si :
173 %define o_Int13_DAP_size ( 0x00 ) ; 2 0x0010
174 %define o_Int13_DAP_num_sectors ( 0x02 ) ; 2 0x0001
175 %define o_Int13_DAP_address ( 0x04 ) ; 2 0x2000
176 %define o_Int13_DAP_segment ( 0x06 ) ; 2 0x0000
177 %define o_Int13_DAP_LBA_64_lo ( 0x08 ) ; 4 0x00000028
178 %define o_Int13_DAP_LBA_64_hi ( 0x0C ) ; 4 0x00000000
179 ; extended DAP values
180 %define o_Int13_DAP_readwrite ( 0x10 ) ; 2 0x0000
181 %define o_Int13_DAP_saved_DX ( 0x12 ) ; 2 0x0000
182 %define o_Int13_DAP_returned_AX ( 0x14 ) ; 2 0xHH00 see AH Return Code below
183 %define o_Int13_DAP_returned_carry_flag ( 0x16 ) ; 2 0x0000
184 %define o_Int13_DAP_saved_CHS_CX ( 0x18 ) ; 2 0x0000
185 %define o_Int13_DAP_saved_CHS_DX ( 0x1A ) ; 2 0x0000
186
187 %macro LOAD_RELATIVE_ADDRESS 1
188 mov _TOS_, ( ( ( %1 - $$ ) + RELOCATED ) )
189 %endmacro
190
191 ; emit the given following character
192 %macro EMIT_IMM 1
193 ; push esi
194 _DUP_
195 mov _TOS_, %1
196 call emit_
197 ; pop esi
198 %endmacro
199
200 ; *****************************************************************************
201 ; Registers used
202 ; *****************************************************************************
203 ; _TOS_ is the top stack item ( eax --> ebx )
204 ; esp the call ... ret return stack pointer
205 ; edi dictionary pointer ( H --> : HERE ( -- a ) H @ ; )
206 ; esi is the stack pointer, also needed by lods and movs
207 ; e.g. lodsd loads a 32 bit dword from [ds:esi] into _TOS_, increments esi by 4
208 ; ebx scratch register
209 ; ecx counter and scratch register
210 ; edx run-time pointer (?), "a register" used by a! , otherwise scratch register
211 ; ebp variable pointer register
212 ; "ds" = selector 0x10 ==> 0x0000:0000
213 ; "es" = selector 0x10 ==> 0x0000:0000
214 ; "ss" = selector 0x10 ==> 0x0000:0000
215
216 ; colours RGB in 16 bits
217 colour_background equ 0x0000
218 colour_yellow equ 0xFFE0
219 colour_black equ 0x0000
220 colour_red equ 0xF800
221 colour_green equ 0x0600
222 colour_cyan equ 0x07FF
223 colour_white equ 0xFFFF
224 colour_light_blue equ 0x841F
225 colour_silver equ 0xC618
226 colour_magenta equ 0xF81F
227 colour_magentaData equ 0xD010
228 colour_blue equ 0x001F
229 colour_orange equ 0xE200
230 colour_dark_yellow equ 0xFFE0
231 colour_dark_green equ 0x07C0
232 colour_PacMan equ 0xE200
233 colour_blockNumber equ 0xE200
234
235 [BITS 16] ; Real Mode code (16 bit)
236
237 org RELOCATED
238
239 start:
240 codeStart:
241 00000000 E98100 jmp main_16bit ; 0x03 bytes | EB 58 90 00 Jump to boot code
242 times 3 - ($ - $$) nop ; fill with 1 or 0 no-ops to address 3
243 ; BIOS boot parameter table = 0x25 bytes
244 00000003 6366323032322030 db 'cf2022 0' ; 03 Eight byte OEM name
245 0000000B 0002 dw 0x0200 ; 11 Number of Bytes Per Sector
246 0000000D 08 db 0x08 ; 13 Number of Sectors Per Cluster
247 0000000E E005 dw 0x05E0 ; 14 Number of Reserved Sectors until the FAT
248 00000010 02 db 0x02 ; 16 Number of Copies of FAT : always = 2
249 00000011 0000 dw 0x0000 ; 17 Maximum number of Root Directory Entries
250 00000013 0000 dw 0x0000 ; 19 Not used for FAT32
251 00000015 F8 db 0xF8 ; 21 Media type F0 = 1.44M 3.5 inch floppy disk, F8 = hard disk changes 2022 Mar14
252 00000016 0000 dw 0x0000 ; 22 Sectors Per FAT for FAT12 and FAT16 - not used for FAT32
253 00000018 3F00 dw 0x003F ; 24 Sectors per Track
254 0000001A FF00 dw 0x00FF ; 26 Number of heads
255 0000001C 38000000 dd 0x00000038 ; 28 Hidden sectors preceding the partition that contains this FAT volume
256 00000020 C8777400 dd 0x007477C8 ; 32
257 00000024 101D0000 dd 0x00001D10 ; 36 Sectors Per FAT for FAT32
258 00000028 0000 dw 0x0000 ; 40
259 0000002A 0000 dw 0x0000 ; 42
260 0000002C 02000000 dd 0x00000002 ; 44 Start of all directories, including root.
261 00000030 0100 dw 0x0001 ; 48
262 00000032 0600 dw 0x0006 ; 50 Offset in sectors from this sector to the backup BPB sector
263 ; times 12 db 0 ; 0x0C bytes | 00 00 00 00 00 00 00 00 00 00 00 00 52
264 ; db 0x00 ; 64
265 ; db 0x00 ; 65
266 ; db 0x29 ; 66 Extended Boot Signature
267 ; dd 0x44444444 ; 67 serial number
268 ; db 'colorForth ' ; 71 Eleven byte Volume Label
269 ; db 'cFblocks' ; 82 Eight byte File System name
270
271 ; ******************************************************************************
272 ; ******************************************************************************
273
274 00000034 90<rep 4h> align 8, nop ; has to be aligned to 8 for GDT
275 ; Note : we are NOT using null descriptor as GDT descriptor, see: http://wiki.osdev.org/GDT_Tutorial
276 ; "The null descriptor which is never referenced by the processor. Certain emulators, like Bochs, will complain about limit exceptions if you do not have one present.
277 ; Some use this descriptor to store a pointer to the GDT itself (to use with the LGDT instruction).
278 ; The null descriptor is 8 bytes wide and the pointer is 6 bytes wide so it might just be the perfect place for this."
279
280 gdt: ; the GDT descriptor
281 00000038 2F00 dw gdt_end - gdt - 1 ; GDT limit
282 0000003A [407C] dw gdt0 + BOOTOFFSET ; pointer to start of table, low 16 bits
283 0000003C 00000000 dw 0 , 0 ; the high bits of the longword pointer to gdt
284
285 gdt0: ; null descriptor
286 00000040 0000 dw 0 ; 0,1 limit 15:0
287 00000042 0000 dw 0 ; 2,3 base 15:0
288 00000044 00 db 0 ; 4 base 23:16
289 00000045 00 db 0 ; 5 type
290 00000046 00 db 0 ; 6 limit 19:16, flags
291 00000047 00 db 0 ; 7 base 31:24
292 code32p_SELECTOR_0x08 equ $ - gdt0
293 ; bytes 1 0 3 2 5 4 7 6
294 00000048 FFFF0000009ACF00 dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; 32-bit protected-mode code, limit 0xFFFFF
295 data32p_SELECTOR_0x10 equ $ - gdt0
296 00000050 FFFF00000092CF00 dw 0xFFFF, 0x0000, 0x9200, 0x00CF ; 32-bit protected-mode data, limit 0xFFFFF
297 code16r_SELECTOR_0x18 equ $ - gdt0
298 00000058 FFFF0000009A0000 dw 0xFFFF, 0x0000, 0x9A00, 0x0000 ; 16-bit real-mode code, limit 0xFFFFF
299 data16r_SELECTOR_0x20 equ $ - gdt0
300 00000060 FFFF000000920000 dw 0xFFFF, 0x0000, 0x9200, 0x0000 ; 16-bit real-mode data, limit 0xFFFFF
301 gdt_end:
302
303 ; ******************************************************************************
304 ; ******************************************************************************
305
306 ; align to 4 so we can access variables from high-level Forth
307 align 4, nop
308
309 data_area: ; data area begins here
310
311 bootsector: ; LBA of boot sector
312 00000068 00000000 dd 0
313
314 ; save disk information, cylinder, sector, head and drive from BIOS call
315 driveinfo_Drive_DX: ; use low byte to store boot Drive into from BIOS DL
316 0000006C 0000 dw 0
317
318 driveinfo_CX: ; [7:6] [15:8][7] logical last index of cylinders = number_of - 1 (because index starts with 0)
319 ; [5:0][7] logical last index of sectors per track = number_of (because index starts with 1)
320 0000006E 0000 dw 0
321
322 ; cylinders, sectors, heads of boot drive
323 ; low word: high byte is head
324 ; high word: cylinder and sector: C76543210 C98S543210
325 driveinfo_Cylinder:
326 00000070 00 db 0
327 driveinfo_Head:
328 00000071 00 db 0
329 driveinfo_SectorsPertrack:
330 00000072 0000 dw 0
331
332 align 4, nop
333
334 destination:
335 00000074 00000100 dd RELOCATED
336
337 dispPtr:
338 00000078 40010000 dd 0x00000140
339
340 v_bytesPerLine:
341 0000007C 00000000 dd 0x00
342
343 v_scanCode:
344 00000080 00000000 dd 0x00
345
346 align 4
347
348 ; ******************************************************************************
349 ; the main program called from initial 16 bit mode
350 ; ******************************************************************************
351
352 main_16bit:
353
354 00000084 FA cli ; clear interrupts
355 ; turns out we don't need interrupts at all, even when using BIOS routines
356 ; but we need to turn them off after disk calls because BIOS leaves them on
357
358 00000085 56 push si ; need to transfer SI to unused register BX later
359
360 ; note: cannot touch DX or BP registers until we've checked for partition boot
361 ; (SI could be used as well as BP but we use SI for relocation)
362
363 ;see mbrboot.nasm
364 ; Note : relocate the bootblock before we do anything else
365 00000086 5B pop bx ; we cannot use the current stack after changing SS or SP
366 ; ... because mbrboot.nasm places stack at 0x7c00, in SECTOR_BUFFER
367 ; and we cannot use BP because its default segment is SS
368 00000087 31C0 xor ax, ax
369 00000089 8ED8 mov ds, ax
370 0000008B 8EC0 mov es, ax
371
372 0000008D BE007C mov si, BOOTOFFSET
373 00000090 BF0020 mov di, SECTOR_BUFFER
374 00000093 89FC mov sp, di
375 00000095 B90001 mov cx, 0x100
376 00000098 F3A5 rep movsw ; note that this instruction doesn't change AX , it moves DS:SI to ES:DI and increments SI and DI
377
378 0000009A 8ED0 mov ss, ax ; stack segment also zero
379 0000009C B4B8 mov ah, 0xb8 ; video RAM
380 0000009E 8EE8 mov gs, ax ; store in unused segment register
381
382 000000A0 0F0116387C lgdt [gdt - $$ + BOOTOFFSET]
383
384 000000A5 E82E01 call SetupUnrealMode ; gs and ss must be initialized before going to Unreal Mode
385
386 ; *****************************************************************************
387 ; Enable the A20 address line, otherwise all odd 1 MByte pages are disabled
388 ; Using the "PS/2 Controller" or 8042 "Keyboard controller"
389 ; *****************************************************************************
390 ; from http://wiki.osdev.org/%228042%22_PS/2_Controller#Step_1:_Initialise_USB_Controllers
391 ; Write a command to the on-board 8042 "Keyboard controller" port 0x64 :
392 ; 0x20 Read "byte 0" from internal RAM Controller Configuration Byte
393 ; 0x21 to 0x3F Read "byte N" from internal RAM (where 'N' is the command byte & 0x1F)
394 ; 0x60 Write next byte to "byte 0" of internal RAM (Controller Configuration Byte)
395 ; 0x61 to 0x7F Write next byte to "byte N" of internal RAM (where 'N' is the command byte & 0x1F)
396 ; 0xA7 Disable second PS/2 port
397 ; 0xA8 Enable second PS/2 port
398 ; 0xA9 Test second PS/2 port
399 ; 0x00 test passed
400 ; 0x01 clock line stuck low
401 ; 0x02 clock line stuck high
402 ; 0x03 data line stuck low
403 ; 0x04 data line stuck high
404 ; 0xAA Test PS/2 Controller
405 ; 0x55 test passed
406 ; 0xFC test failed
407 ; 0xAB Test first PS/2 port
408 ; 0x00 test passed
409 ; 0x01 clock line stuck low
410 ; 0x02 clock line stuck high
411 ; 0x03 data line stuck low
412 ; 0x04 data line stuck high
413 ; 0xAC Diagnostic dump (real all bytes of internal RAM) Unknown
414 ; 0xAD Disable first PS/2 port None
415 ; 0xAE Enable first PS/2 port None
416 ; 0xC0 Read controller input port Unknown (none of these bits have a standard/defined purpose)
417 ; 0xC1 Copy bits 0 to 3 of input port to status bits 4 to 7 None
418 ; 0xC2 Copy bits 4 to 7 of input port to status bits 4 to 7 None
419 ; 0xD0 Read Controller Output Port Controller Output Port (see below)
420 ; 0xD1 Write next byte to Keyboard Controller Output Port Note: Check if output buffer is empty first
421 ; 0xD2 Write next byte to first PS/2 port output buffer
422 ; 0xD3 Write next byte to second PS/2 port output buffer
423 ; 0xD4 Write next byte to second PS/2 port input buffer
424 ; 0xF0 to 0xFF Pulse output line low for 6 ms.
425 ; Bits 0 to 3 are used as a mask (0 = pulse line, 1 = do not pulse line) and correspond to 4 different output lines.
426 ; Bit 0 is the "reset" line, active low.
427 000000A8 B0D1 mov al, 0xD1 ; 0xD1 = Write next byte to Keyboard Controller Output Port
428 000000AA E664 out 0x64, al ; On-board controller Command Write
429 .back:
430 000000AC E464 in al, 0x64
431 000000AE 2402 and al, 0x02
432 000000B0 75FA jnz .back
433 000000B2 B04B mov al, 0x4B
434 000000B4 E660 out 0x60, al
435
436 ; *****************************************************************************
437 ; Get disk drive parameters from the BIOS
438 ; *****************************************************************************
439
440 000000B6 BF687C mov di, (data_area - $$ + BOOTOFFSET) ; setup the data index pointer
441 000000B9 6631C0 xor eax, eax
442 000000BC 660FBAE810 bts eax, 16 ; in case NOT booted from partition: sector 1, head 0, cylinder 0
443 000000C1 08F6 or dh, dh ; booted from partition?
444 000000C3 740B jz .forward3
445 000000C5 668B4708 mov eax, [ bx + 8 ] ; SI (now BX) contains pointer to partition record
446 000000C9 66894500 mov [ byte di + (bootsector - data_area) ], eax ; offset 8 was LBA of first absolute sector
447 000000CD 668B07 mov eax, [bx] ; CHS of first sector in partition
448 .forward3:
449 000000D0 88D0 mov al, dl ; bootdrive into AL
450 000000D2 6689850400 mov [ word di + ( driveinfo_Drive_DX - data_area) ], eax ; save the Drive info from BIOS
451 000000D7 B408 mov ah, 8 ; get drive parameters
452 000000D9 06 push es ; this operation messes with ES
453 000000DA 57 push di ; and DI
454 000000DB BFC017 mov di, DISK_INFO ; point di at the table returned by this software interrupt
455 000000DE CD13 int 0x13
456 000000E0 72FE jc $ ; stop here on error
457
458 000000E2 E80601 call ReSetupUnrealMode
459 000000E5 5F pop di
460 000000E6 07 pop es
461
462 ; ******************************************************************************
463 ; load the bootdisk into both low and high RAM
464 ; ******************************************************************************
465
466 000000E7 895508 mov [ byte di + ( driveinfo_Cylinder - data_area) ], dx ; heads in high byte
467 000000EA 80E13F and cl, 0x3F ; we don't care about two high bits of cylinder count
468 000000ED 894D0A mov [ byte di + ( driveinfo_SectorsPertrack - data_area) ], cx ; cylinders and sectors/track
469 000000F0 8B5504 mov dx, [ byte di + ( driveinfo_Drive_DX - data_area) ] ; restore dl Drive value from BIOS, dh = 0
470 ; mov dl, 0x00 ; try this 2022 Mar 14
471 000000F3 8B4D06 mov cx, [ di + ( driveinfo_CX - data_area) ] ; restore cl value, ch = 0
472 000000F6 BE0004 mov si, SECTORS_TO_LOAD
473
474 000000F9 BB0020 mov bx, SECTOR_BUFFER ; relocate the sector we are running from
475 000000FC E89800 call relocate
476
477 000000FF BB007C mov bx, BOOTOFFSET ; we will fix this below by adding 0x200
478 ; remember the sector is 1-based, head and cylinder both 0-based
479
480 .nextsector:
481 00000102 FEC1 inc cl
482 00000104 4E dec si
483 00000105 747D jz setVideoMode ; success, so setup the video now...
484
485 .bootload:
486 00000107 B80102 mov ax, 0x201 ; read 1 sector
487 0000010A 80C702 add bh, 0x02 ; into next available slot in RAM
488 0000010D 7503 jnz .forward
489 0000010F 80EF02 sub bh, 0x02 ; at 0x10000 we go back to 0xfe00
490 .forward:
491 00000112 CD13 int 0x13
492 00000114 E8D400 call ReSetupUnrealMode
493 00000117 72FE jc $ ; stop here on error
494 00000119 E87B00 call relocate
495 0000011C 88C8 mov al, cl
496 0000011E 243F and al, 0x3F ; low 6 bits
497 00000120 3A450A cmp al, [ byte di + ( driveinfo_SectorsPertrack - data_area) ]
498 00000123 75DD jnz .nextsector
499 00000125 FEC6 inc dh ; next head
500 00000127 3A7509 cmp dh, [ byte di + ( driveinfo_Head - data_area) ]
501 0000012A 7609 jna .forward2 ; not JNZ, the head index is 1 less than head count
502 0000012C 30F6 xor dh, dh
503 0000012E FEC5 inc ch ; next cylinder
504 00000130 7503 jnz .forward2
505 00000132 80C140 add cl, 0x40 ; bit 8 of cylinder count
506 .forward2:
507 00000135 80E1C0 and cl, 0xC0 ; clear sector count, low 6 bits of cl
508 00000138 EBC8 jmp short .nextsector
509
510 ; ******************************************************************************
511 ; ******************************************************************************
512 ; Start here after loading the program
513 ; ******************************************************************************
514 ; ******************************************************************************
515
516 ; From : VESA BIOS EXTENSION (VBE) Core Functions Standard Version: 3.0 Date: September 16, 1998
517 ; Mandatory information for all VBE revisions
518 ; dw ModeAttributes ; 0x00 mode attributes
519 ; db WinAAttributes ; 0x02 window A attributes
520 ; db WinBAttributes ; 0x03 window B attributes
521 ; dw WinGranularity ; 0x04 window granularity
522 ; dw WinSize ; 0x06 window size
523 ; dw WinASegment ; 0x08 window A start segment
524 ; dw WinBSegment ; 0x0A window B start segment
525 ; dd WinFuncPtr ; 0x0C real mode pointer to window function
526 ; dw BytesPerScanLine ; 0x10 bytes per scan line <--------------
527 ; Mandatory information for VBE 1.2 and above
528 ; dw XResolution ; 0x12 horizontal resolution in pixels <-------------- scrnw
529 ; dw YResolution ; 0x14 vertical resolution in pixels <-------------- scrnh
530 ; db XCharSize ; 0x16 character cell width in pixels
531 ; db YCharSize ; 0x17 character cell height in pixels
532 ; db NumberOfPlanes ; 0x18 number of memory planes
533 ; db BitsPerPixel ; 0x19 bits per pixel <-------------- bpp
534 ; db NumberOfBanks ; 0x1A number of banks
535 ; db MemoryModel ; 0x1B memory model type
536 ; db BankSize ; 0x1C bank size in KB
537 ; db NumberOfImagePages ; 0x1D number of images
538 ; db Reserved ; 0x1E reserved for page function <-------------- mode (we copy it here)
539 ; Direct Color fields (required for direct/6 and YUV/7 memory models)
540 ; db RedMaskSize ; 0x1F size of direct color red mask in bits
541 ; db RedFieldPosition ; 0x20 bit position of lsb of red mask
542 ; db GreenMaskSize ; 0x21 size of direct color green mask in bits
543 ; db GreenFieldPosition ; 0x22 bit position of lsb of green mask
544 ; db BlueMaskSize ; 0x23 size of direct color blue mask in bits
545 ; db BlueFieldPosition ; 0x24 bit position of lsb of blue mask
546 ; db RsvdMaskSize ; 0x25 size of direct color reserved mask in bits
547 ; db RsvdFieldPosition ; 0x26 bit position of lsb of reserved mask
548 ; db DirectColorModeInfo ; 0x27 direct color mode attributes
549 ; Mandatory information for VBE 2.0 and above
550 ; dd PhysBasePtr ; 0x28 physical address for flat memory frame buffer <-------------- vframe
551 ; dd Reserved ; 0x2C Reserved - always set to 0
552 ; dw Reserved ; 0x30 Reserved - always set to 0
553 ; Mandatory information for VBE 3.0 and above
554 ; dw LinBytesPerScanLine ; 0x32 bytes per scan line for linear modes
555 ; db BnkNumberOfImagePages ; 0x34 number of images for banked modes
556 ; db LinNumberOfImagePages ; 0x35 number of images for linear modes
557 ; db LinRedMaskSize ; 0x36 size of direct color red mask (linear modes)
558 ; db LinRedFieldPosition ; 0x37 bit position of lsb of red mask (linear modes)
559 ; db LinGreenMaskSize ; 0x38 size of direct color green mask (linear modes)
560 ; db LinGreenFieldPosition ; 0x39 bit position of lsb of green mask (linear modes)
561 ; db LinBlueMaskSize ; 0x3A size of direct color blue mask (linear modes)
562 ; db LinBlueFieldPosition ; 0x3B bit position of lsb of blue mask (linear modes)
563 ; db LinRsvdMaskSize ; 0x3C size of direct color reserved mask (linear modes)
564 ; db LinRsvdFieldPosition ; 0x3D bit position of lsb of reserved mask (linear modes)
565 ; dd MaxPixelClock ; 0x3E maximum pixel clock (in Hz) for graphics mode
566 ; times 189 db 0 ; 0x42 remainder of ModeInfoBlock
567 ; End ; 0xFF
568
569 scanVESA: ; ( w+h+b -- ) in ax
570 0000013A 89C3 mov bx, ax
571 0000013C 57 push di ; save di
572 0000013D B91641 mov cx, ( 0x4117 - 1 ) ; start scanning from the expected VESA mode 0x4117 ( the -1 is because of the inc cx below )
573 .back:
574 00000140 FEC1 inc cl ; increment just the bottom byte, we test 0x41xx
575 00000142 80F916 cmp cl, 0x16 ; scanned from 0x4117 to 0x4116, not found, so show error
576 00000145 741B jz .failure
577 00000147 BF0018 mov di, VESA_BUFFER ; buffer for the VESA mode information block
578 0000014A B8014F mov ax, 0x4F01 ; INT 0x10, AX=0x4F01, CX=mode Get Mode Info
579 0000014D CD10 int 0x10
580 0000014F 3C4F cmp al, 0x4F ; success code = 0x4F
581 00000151 75ED jne .back ; try the next VESA mode
582 00000153 8B4512 mov ax, [di + 0x12] ; width
583 00000156 034514 add ax, [di + 0x14] ; height
584 00000159 024519 add al, [di + 0x19] ; bits per pixel
585 ; adc ah, 0 ; should not be necessary for the expected result, 0x400+0x300+0x10
586 0000015C 39D8 cmp ax, bx ; width + height + bits per pixel
587 0000015E 740A je .success
588 00000160 75DE jne .back ; try the next VESA mode
589 .failure: ; VESA mode not found, so continue
590 00000162 5F pop di ; restore di
591 00000163 B80000 mov ax, 0 ; return flag false
592 00000166 050000 add ax, 0 ; set the zero flag
593 00000169 C3 ret
594 .success:
595 0000016A 894D1E mov [ di + ( vesa_SavedMode - VESA_BUFFER ) ], cx ; save the VESA mode in the VESA_BUFFER at offset 0x1E "Reserved"
596 0000016D B80100 mov ax, 1 ; return flag true
597 00000170 050000 add ax, 0 ; set the zero flag
598 00000173 5F pop di ; restore di
599 00000174 C3 ret
600
601 setVESA: ; we found a valid VESA mode
602
603 00000175 1E push ds ; clear all flags including Interrupt using DS, known to be zero
604 00000176 9D popf ; this is necessary to clear T flag also, end register display
605
606 00000177 E8E000 call greet ; show greeting message
607
608 0000017A 89CB mov bx, cx
609 0000017C B8024F mov ax, 0x4F02 ; INT 0x10, AX=0x4F02, BX=mode, ES:DI=CRTCInfoBlock Set Video Mode
610 0000017F CD10 int 0x10
611
612 00000181 E9E400 jmp main_32bit
613
614 setVideoMode:
615 %if ( FORCE_800x600_VESA == 0 ) ; test the 800x600 mode in bochs, which supports 1024x768
616 00000184 B81007 mov ax, ( 1024 + 768 + BITS_PER_PIXEL ) ; try the highest resolution first
617 00000187 E8B0FF call scanVESA ; if VESA mode is found, jump to setVESA
618 0000018A 75E9 jnz setVESA ; success - we found the requested VESA mode
619 %endif
620 0000018C B88805 mov ax, ( 800 + 600 + BITS_PER_PIXEL ) ; then try a lower resolution
621 0000018F E8A8FF call scanVESA ; if VESA mode is found, jump to setVESA
622 00000192 75E1 jnz setVESA ; success - we found the requested VESA mode
623
624 ; mov ax, 640 + 480 + BITS_PER_PIXEL ; then try an even lower resolution
625 ; call scanVESA ; if VESA mode is found, jump to setVESA
626 ; jnz setVESA ; success - we found the requested VESA mode
627 00000194 E9B200 jmp showVESAerror ; we have tried all VESA modes without success, so report an error
628
629 ; ******************************************************************************
630 ; ******************************************************************************
631
632 relocate: ; copy 512 bytes from [bx] to FS:[destination]
633 00000197 60 pusha
634 00000198 B90001 mov cx, 0x200 / 2
635 0000019B 89DE mov si, bx
636 0000019D 668B5D0C mov ebx, [ byte di + ( destination - data_area) ]
637 .back:
638 000001A1 AD lodsw ; load the 16 bit value pointed to by SI into ax
639 000001A2 64678903 mov [fs:ebx], ax ; Note : the fs: uses the 32 bit FS value setup in Unreal Mode to move the data outside of the 1 Mbyte Real Mode address range
640 000001A6 6683C302 add ebx, byte +2
641 000001AA E2F5 loop .back
642
643 000001AC 66895D0C mov [ byte di + ( destination - data_area) ], ebx
644 000001B0 61 popa
645 000001B1 C3 ret
646
647 ; not used because it is very slow :
648 ; now set up for trap displaying registers on screen during bootup
649 ; push cs
650 ; push showstate - $$ + BOOTOFFSET
651 ; pop dword [word +4]
652
653 ; ******************************************************************************
654 ; ******************************************************************************
655 ;1. MasterBoot Record - MBR at Sector 0 (decimal 0) MBR
656 ; Partition at offset 1BE
657 ; BootSignature 0
658 ; Start Head|Sector|Cylinder 1 1 0
659 ; Partition Type B DOS 7.1+
660 ; End Head|Sector|Cylinder FE 3F 3E5
661 ; BPBsectorNumber 00 \ was 3F
662 ; Size of partition (decimal) 16035777 sectors, 8210317824 bytes, 8017889 Ki bytes, 7830 Mi bytes, 8 Gi bytes
663 ; Partition at offset 1CE
664 ; BootSignature 0
665 ; Start Head|Sector|Cylinder 0 0 0
666 ; Partition Type 0 Empty partition
667 ; End Head|Sector|Cylinder 0 0 0
668 ; BPBsectorNumber 0
669 ; Size of partition (decimal) 0 sectors, 0 bytes, 0 Ki bytes, 0 Mi bytes,
670
671 ; pretend to be a Master Boot Record so that the BIOS will load us
672 000001B2 77<rep Ch> times ( 0x000001BE - ( $ - $$ ) ) db 0x77
673 000001BE 800101000BFEFFE500- db 0x80, 0x01, 0x01, 0x00, 0x0B, 0xFE, 0xFF, 0xE5, 0x00, 0x00, 0x00, 0x00, 0xC1, 0xAF, 0xF4, 0x00 ; 0x1BE DOS partition 0 working on PC
673 000001C7 000000C1AFF400
674 000001CE 0000000000000000 db 00, 00, 00, 00, 00, 00, 00, 00 ; 0x1CE first 8 bytes of empty partition 1
675
676 SetupUnrealMode:
677 ; set the FS segment in "unreal" mode, must be done before the Trap Flag is set in EFLAGS register
678 000001D6 0F20C0 mov eax, cr0
679 000001D9 0C01 or al, 1 ; set the "protected mode enable" bit => "unreal mode"
680 000001DB 0F22C0 mov cr0, eax
681 000001DE 681000 push word data32p_SELECTOR_0x10 ; set the FS segment
682 000001E1 0FA1 pop fs
683 000001E3 FEC8 dec al ; clear the "protected mode enable" bit
684 000001E5 0F22C0 mov cr0, eax
685 000001E8 1E push ds ; now set FS to 0
686 000001E9 0FA1 pop fs
687
688 ReSetupUnrealMode:
689 000001EB 0E push cs ; for iret
690 000001EC 9C pushf ; for iret
691 000001ED 60 pusha
692 000001EE 89E5 mov bp, sp
693 000001F0 8B4610 mov ax, [bp + 16] ; get flags
694 ; or ah, 0x01 ; set Trap Flag, bit 8 in the EFLAGS register ; debug only - very slow!
695 000001F3 80E4FD and ah, ~0x02 ; reset interrupt flag
696 000001F6 874614 xchg ax, [ bp + 20 ] ; swap flags with return address
697 000001F9 894610 mov [ bp + 16 ], ax ; return address at top of stack after popa
698 000001FC 61 popa
699 000001FD CF iret
700
701 ; ******************************************************************************
702 ; ******************************************************************************
703
704 times 512 - 2 - ($ - $$) nop ; fill with no-ops to 55AA at end of boot sector
705 000001FE 55AA db 0x55 , 0xAA ; boot sector terminating bytes
706
707 ; ******************************************************************************
708 ; End of Boot Sector
709 ; ******************************************************************************
710
711 ; ******************************************************************************
712 ; Show the user a null terminated string - writes directly into video RAM
713 ; ******************************************************************************
714
715 displayString:
716
717 ; restore the pointer to screen memory into di
718 00000200 BF687C mov di, (data_area - $$ + BOOTOFFSET)
719 00000203 8B4510 mov ax, [ di + ( dispPtr - data_area) ]
720 00000206 89C7 mov di, ax
721
722 00000208 06 push es ; save es
723 00000209 B800B8 mov ax, 0xb800 ; video RAM segment
724 0000020C 8EC0 mov es, ax
725
726 backhere2:
727 0000020E AC lodsb ; loads a byte from [ds:si] into al, then increments si
728 0000020F 3C00 cmp al, 0
729 00000211 7406 jz forward1 ; If al = 0 then leave the loop
730 00000213 B40D mov ah, 0x0D ; text colour, magenta on black background
731 00000215 AB stosw ; stores ax into [es:di] then increments di
732 00000216 E9F5FF jmp backhere2
733 forward1:
734 ; save the pointer to screen memory from di
735 00000219 89F8 mov ax, di
736 0000021B BF687C mov di, (data_area - $$ + BOOTOFFSET)
737 0000021E 894510 mov [ di + ( dispPtr - data_area) ], ax
738 00000221 07 pop es ; restore es
739 00000222 C3 ret
740
741 ; display a string then Wait for a key press
742 displayStringW:
743
744 00000223 60 pusha
745 00000224 E8D9FF call displayString
746
747 00000227 31C0 xor ax, ax ; wait for and get a key press ( AX = 0 )
748 00000229 CD16 int 0x16 ; BIOS interrupt Read a Key From the Keyboard
749 0000022B 61 popa
750 0000022C C3 ret
751
752 ; msg_greeting2:
753 ; db ' Press any key : ' , 0x00
754
755 msg_VESAerror:
756 0000022D 4E6F2076616C696420- db 'No valid VESA mode found! ' , 0x02, 0x00
756 00000236 56455341206D6F6465-
756 0000023F 20666F756E64212002-
756 00000248 00
757 ; db ' No VESA mode ' , 0x02, 0x00
758
759 [BITS 16] ; Real Mode code (16 bit)
760
761 showVESAerror:
762 00000249 E80E00 call greet
763 0000024C 56 push si
764 0000024D C74510E001 mov word [ di + ( dispPtr - data_area) ] , 0x000001E0 ; line 3 0x50 x 2 x 3 = 0x1E0
765 00000252 BE2D7E mov si, ( msg_VESAerror - $$ + BOOTOFFSET ) ; string to display
766 00000255 E8CBFF call displayStringW
767 00000258 5E pop si
768 00000259 C3 ret
769
770 greet: ; jump here to show 16 bit version text
771 0000025A 56 push si
772 0000025B C745104001 mov word [ di + ( dispPtr - data_area) ] , 0x00000140 ; line 2 0x50 x 2 x 2 = 0x140
773 00000260 BE0080 mov si, ( version - $$ + BOOTOFFSET ) ; string to display
774 00000263 E89AFF call displayString
775 ; mov si, ( msg_greeting2 - $$ + BOOTOFFSET ) ; string to display
776 ; call displayStringW
777 00000266 5E pop si
778 00000267 C3 ret
779
780 ; ******************************************************************************
781 ; the main program in 32 bit ( protected ) mode
782 ; ******************************************************************************
783
784 main_32bit:
785
786 00000268 E88200 call setProtectedModeAPI ; called from 16 bit code, returns in 32 bit code
787
788 [BITS 32] ; Protected Mode code (32 bit) - assemble for 32 bit mode from now on
789
790 0000026B BC00780000 mov esp, RETURN_STACK_0 ; setup the return stack pointer
791 00000270 BE04740000 mov esi, ( DATA_STACK_0 + 4 ) ; setup our data stack pointer
792
793 00000275 E877370000 call save_BIOS_idt_and_pic ; to be restored later, when making BIOS calls
794 0000027A E8F8370000 call init_default_PIC_IMRs ; set the default values and copy the BIOS Interrupt Vectors to our new table
795 _DUP_
132 0000027F 8D76FC <1> lea esi, [ esi - 4 ]
133 <1>
134 00000282 8906 <1> mov [ esi ], _TOS_
796 00000284 B8001C0000 mov _TOS_, INTERRUPT_VECTORS
797 00000289 E81D370000 call lidt_ ; Load the new Interrupt Descriptor Table
798
799 0000028E E9C1300000 jmp dword warm
800
801 ; *****************************************************************************
802 ; calculate Cylinder, Head and Sector from zero-based sector number
803 ; see http://teaching.idallen.com/dat2343/00f/calculating_cylinder.htm
804 ; Note : uses pushad to copy registers onto the ESP stack, stores the
805 ; calculated values onto the stack at the correct offsets, then restores the
806 ; stack back to the registers.
807 ; *****************************************************************************
808
809 sector_chs: ; ( sector -- eax ) calculate CHS from a sector number in eax,
810 ; returns with DX = HHDD, CX = CCSS where HH=head, DD=drive, CC=cylinder, SS=sector
811 ; Note that the input sector number is zero based, and that the high 16 bits of EAX must be 0
812 00000293 60 pushad ; Pushes all general purpose registers onto the stack in the following order:
813 ; EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI. The value of ESP is the value before the actual push of ESP
814 ; 7 6 5 4 3 2 1 0 offset in cells from ESP
815 00000294 89E5 mov ebp, esp ; copy the original ESP stack pointer to EBP so we can access items on the stack easily
816
817 ; save the register values in the DAP buffer for use later, via ESI
818 00000296 BEE0170000 mov esi, DAP_BUFFER
819
820 0000029B 0305687C0000 add eax, [ bootsector - $$ + BOOTOFFSET]
821 000002A1 50 push eax ; save it while we calculate heads*sectors-per-track
822 000002A2 A0717C0000 mov al, [ driveinfo_Head - $$ + BOOTOFFSET] ; index of highest-numbered head
823 000002A7 FEC0 inc al ; 1-base the number to make count of heads
824 000002A9 F625727C0000 mul byte [ driveinfo_SectorsPertrack - $$ + BOOTOFFSET] ; sectors per track
825 000002AF 89C3 mov ebx, eax
826 000002B1 58 pop eax
827 000002B2 31D2 xor edx, edx ; clear high 32 bits
828 000002B4 F7F3 div ebx ; leaves cylinder number in eax, remainder in edx
829 000002B6 89C1 mov ecx, eax ; store cylinder number in another register
830 000002B8 89D0 mov eax, edx ; get remainder into AX
831 000002BA 8A1D727C0000 mov bl, [ driveinfo_SectorsPertrack - $$ + BOOTOFFSET] ; number of sectors per track
832 000002C0 F6F3 div bl ; head number into AX, remainder into DX
833 000002C2 88C3 mov bl, al ; result must be one byte, so store it in BL
834 000002C4 C1C108 rol ecx, 8 ; high 2 bits of cylinder number into high 2 bits of CL
835 000002C7 C0E106 shl cl, 6 ; makes room for sector number
836 000002CA 08E1 or cl, ah ; merge cylinder number with sector number
837 000002CC FEC1 inc cl ; one-base sector number
838 000002CE 894D18 mov [ ebp + ( 6 * 4 ) ], ecx ; store the result in ECX position on esp stack
839 000002D1 66894E18 mov word [ esi + o_Int13_DAP_saved_CHS_CX ], cx ; also save the calculated CX value
840 000002D5 668B0D6C7C0000 mov cx, [ driveinfo_Drive_DX - $$ + BOOTOFFSET] ; drive number in low 8 bits
841 000002DC 88DD mov ch, bl ; place head number in high bits
842 ; mov cl, 0x80
843 000002DE 894D14 mov [ ebp + ( 5 * 4 ) ], ecx ; store the result in EDX position on esp stack
844 000002E1 66894E1A mov word [ esi + o_Int13_DAP_saved_CHS_DX ], cx ; also save the calculated DX value
845 000002E5 61 popad ; restore registers from esp stack
846 000002E6 C3 ret
847
848 ; *****************************************************************************
849 ; enter Protected Mode (32 bit) and Real Mode (16 bit)
850 ; from http://ringzero.free.fr/os/protected%20mode/Pm/PM1.ASM
851 ; *****************************************************************************
852
853 [BITS 16] ; Real Mode code (16 bit)
854
855 enterProtectedMode: ; must come from a 'call' , can not be inlined
856 000002E7 58 pop ax
857 000002E8 680800 push code32p_SELECTOR_0x08
858 000002EB 50 push ax
859 000002EC CB retf
860
861 setProtectedModeAPI: ; set protected mode from 'Real' mode. Called from 16 bit code, returns to 32 bit code
862 000002ED 6660 pushad ; save all registers as doublewords
863 000002EF 0F20C0 mov eax, cr0
864 000002F2 0C01 or al, 1
865 000002F4 0F22C0 mov cr0, eax ; set the Protected Mode bit in the Control Register
866 000002F7 6631C0 xor eax, eax ; clear high bits of eax
867 000002FA E8EAFF call enterProtectedMode
868
869 [BITS 32] ; Protected Mode code (32 bit)
870
871 000002FD B810000000 mov eax, data32p_SELECTOR_0x10 ; Protected Mode data segment
872 00000302 668EC0 mov es, ax
873 00000305 668ED8 mov ds, ax
874 00000308 668ED0 mov ss, ax ; this makes stack segment 32 bits
875 0000030B 61 popad
876 0000030C 66C3 o16 ret
877
878 enter16bitProtectedMode: ; 32 bit code. Must come from a 'call' , can not be inlined
879 0000030E 58 pop eax ; return address
880 0000030F 6818000000 push dword code16r_SELECTOR_0x18 ; select 16-bit Protected Mode AKA 'Real' Mode
881 00000314 50 push eax
882 00000315 CB retf
883
884 setRealModeAPI: ; set 'Real' mode from protected mode.
885 ; Called from 32 bit code, returns to 16 bit code
886 ; assumed that protected-mode stack is based at 0
887 ; and that bits 16 through 19 will not change during time in realmode
888 00000316 60 pushad ; save 32-bit values of registers
889 00000317 89E1 mov ecx, esp ; do all possible 32-bit ops before going to 16 bits
890 00000319 0F20C2 mov edx, cr0
891 0000031C E8EDFFFFFF call enter16bitProtectedMode
892
893 [BITS 16] ; Real Mode code (16 bit)
894
895 00000321 B82000 mov ax, data16r_SELECTOR_0x20
896 00000324 8ED8 mov ds, ax
897 00000326 8EC0 mov es, ax
898 00000328 8ED0 mov ss, ax ; here the stack becomes 16 bits based at 0, and SP used not ESP
899 ; *** consider stack to be invalid from here until we reach real mode ***
900 0000032A 31C9 xor cx, cx ; clear low 16 bits
901 0000032C 66C1E904 shr ecx, 4 ; move high 4 bits into cl
902 00000330 FECA dec dl ; leave protected mode, only works if we KNOW bit 0 is set
903 00000332 0F22C2 mov cr0, edx
904 00000335 E80C00 call enterRealMode
905 00000338 31C0 xor ax, ax
906 0000033A 8ED8 mov ds, ax
907 0000033C 8EC0 mov es, ax
908 0000033E 8ED1 mov ss, cx
909 ; note we don't need to set SP to 8xxx if ESP is b8xxx, since
910 ; the b000 is now in SS, and the b of b8xxx is ignored in real mode
911 00000340 6661 popad
912 00000342 66C3 o32 ret
913
914 enterRealMode: ; 16 bit code. Must come from a 'call' , can not be inlined
915 00000344 58 pop ax
916 00000345 0FA0 push fs ; real-mode code segment
917 00000347 50 push ax
918 00000348 CB retf
919
920 [BITS 32] ; Protected Mode code (32 bit)
921
922 ; *****************************************************************************
923 ; *****************************************************************************
924
925 ;%include "JCreadwrite.nasm"
926 ; JCreadwrite.nasm 2012 Oct 23 read and write the disk using 16 bit BIOS calls
927 ; BIOS read and write routines for colorForth
928
929 [BITS 32] ; Protected Mode code (32 bit)
930
931 bios_read: ; ( a c -- a' c' ) \ read cylinder c into address a , leave next address and cylinder
932 ; c is cylinder, we will use 1.44Mb floppy's idea of cylinder regardless
933 ; a is byte address
934 ; leave updated c and a on stack as c' and a'
935 ; a cylinder is 36 tracks of 512 bytes each, 0x4800 bytes, 0x1200 cells (words)
936
937 00000349 FA cli ; disable interrupts
938 0000034A 60 pushad ; push all registers ( except esp ) and flags onto the stack
939 0000034B 89E5 mov ebp, esp ; copy of stack pointer for use below ( * ), points to registers copied by pushad , above
940
941 0000034D B924000000 mov ecx, HEADS * SECTORS ; sectors per track (both heads)
942 00000352 F6E1 mul cl ; sector number goes into AX
943 ; note that resultant sector number is zero-based going into sector_chs!
944 ; set up loop to read one floppy cylinder's worth
945
946 00000354 50 push eax ; absolute sector number to start
947 .back:
948 00000355 51 push ecx
949 00000356 E838FFFFFF call sector_chs ; convert to Cylinder-Head-Sector in CX-DX
950 0000035B E81F000000 call .readsector
951
952 00000360 8B5D04 mov ebx, [ ebp + ( 1 * 4 ) ] ; ( * ) get ESI stored on stack, via stack pointer saved in ebp
953 00000363 8B3B mov edi, [ebx] ; destination index address for movsd
954 00000365 B980000000 mov ecx, ( 512 >> 2 ) ; number of 32-bit words to move, 512 bytes
955 0000036A BE00200000 mov esi, SECTOR_BUFFER ; source index for movsd
956 0000036F F3A5 rep movsd ; copy ecx 32 bit words from ds:esi to es:edi
957 00000371 893B mov [ebx], edi
958 00000373 59 pop ecx
959 00000374 58 pop eax
960 00000375 40 inc eax
961 00000376 50 push eax
962 00000377 E2DC loop .back
963 00000379 58 pop eax
964 0000037A FF451C inc dword [ebp + 7 * 4] ; for updated cylinder number after return
965 0000037D 61 popad
966 0000037E C3 ret
967
968 .readsector: ; no need to save registers because we take care of them in calling routine
969 0000037F E892FFFFFF call setRealModeAPI
970 [BITS 16] ; Real Mode code (16 bit)
971 00000384 BB0020 mov bx, SECTOR_BUFFER
972 00000387 B80102 mov ax, 0x0201 ; read 1 sector
973 0000038A CD13 int 0x13
974 0000038C FA cli ; BIOS might have left interrupts enabled
975 0000038D E85DFF call setProtectedModeAPI ; called from 16 bit code, returns to 32 bit code
976 [BITS 32] ; Protected Mode code (32 bit)
977 00000390 C3 ret
978
979 bios_write: ; ( a c -- a' c' ) \ write cylinder c from address a , leave next address and cylinder
980 00000391 FA cli ; disable interrupts
981 00000392 60 pushad
982 00000393 89E5 mov ebp, esp
983 ; eax contains cylinder to start, the 'c' parameter
984 00000395 B924000000 mov ecx, HEADS * SECTORS ; sectors per track (both heads)
985 0000039A F6E1 mul cl ; absolute sector number goes into AX
986
987 0000039C 8B5D04 mov ebx, [ebp + ( 1 * 4 ) ] ; stored ESI on stack
988 0000039F 8B33 mov esi, [ebx] ; word address, 'a' parameter
989 ; shl esi, 2 ; change word address into byte address
990 ; set up loop to write one floppy cylinder's worth
991 000003A1 50 push eax ; absolute sector number to start
992
993 .back: