This repository has been archived by the owner on Nov 19, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
z502.c
3392 lines (2958 loc) · 126 KB
/
z502.c
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
/*********************************************************************
z502.c
This is the start of the code and declarations for the Z502 simulator.
Revision History:
1.0 August 1990 Initial coding
1.1 December 1990: Lots of minor problems cleaned up.
Portability attempted.
1.4 December 1992 Lots of minor changes.
1.5 August 1993 Lots of minor changes.
1.6 June 1995 Significant debugging aids added.
1.7 Sept. 1999 Minor compile issues.
2.0 Jan 2000 A number of fixes and improvements.
2.1 May 2001 Bug Fixes:
Disks no longer make cylinders visible
Hardware displays resource usage
2.2 July 2002 Make appropriate for undergraduates.
2.3 Dec 2002 Allow Mem calls from OS - conditional on POP_THE_STACK
Clear the STAT_VECTOR at the end of SoftwareTrap
3.0 August 2004: Modified to support memory mapped IO
3.1 August 2004: hardware interrupt runs on separate thread
3.11 August 2004: Support for OS level locking
3.12 Sept. 2004: Make threads schedule correctly
3.14 November 2004: Impliment DO_DEVICE_DEBUG in meaningful way.
3.15 November 2004: More DO_DEVICE_DEBUG to handle disks
3.20 May 2005: Get threads working on windows
3.26 October 2005: Make the hardware thread safe.
3.30 July 2006: Threading works on multiprocessor
3.40 July 2008: Minor improvements
3.50 August 2009: Fixes for 64 bit machines and multiprocessor
3.51 Sept. 2011: Fixed locking issue due to MemoryCommon - Linux
3.52 Sept. 2011: Fixed locking issue due to MemoryCommon - Linux
Release the lock when leaving MemoryCommon
3.60 August 2012: Used student supplied code to add support
for Mac machines
4.00 May 2013: Major revision to the way the simulator works.
It now runs off of multiple threads, and those
threads start in the test code avoiding many
many hacks.
4.02 December 2013: STAT_VECTOR not thread safe. Defined a method that
uses thread info to keep things sorted out.
4.03 December 2013: Store Z502_MODE on context save
4.10 June 2014: Many Many fixes
Disk transfer now doesn't occur until interrupt time.
4.20 January 2015: Make thread safe. Implement multiprocessors
4.30 January 2016: Many small bug fixes.
************************************************************************/
/************************************************************************
GLOBAL VARIABLES: These declarations are visible to both the
Z502 simulator and the OS502 if the OS declares them
extern.
************************************************************************/
#define HARDWARE_VERSION "4.40"
#include "global.h"
#include "syscalls.h"
#include "z502.h"
#include "protos.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#ifdef NT
#include <windows.h>
#include <winbase.h>
#include <sys/types.h>
#endif
#ifdef LINUX
#include <pthread.h>
#include <unistd.h>
#include <asm/errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
#ifdef MAC
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
// These are routines internal to the hardware, not visible to the OS
// Prototypes that allow the OS to get to this hardware are in protos.h
void AddEventToInterruptQueue(INT32, INT16, INT16, EVENT **);
void AssociateContextWithProcess(Z502CONTEXT *Context);
void ChargeTimeAndCheckEvents(INT32);
int CreateAThread(void *ThreadStartAddress, INT32 *data);
void CreateLock(INT32 *, char *CallingRoutine);
void CreateCondition(UINT32 *);
void CreateSectorStruct(INT16, INT16, char **);
void DequeueItemFromEventQueue(EVENT *, INT32 *);
void DoMemoryDebug(INT16, INT16);
void DoSleep(INT32 millisecs);
Z502CONTEXT *GetCurrentContext();
int GetLock(UINT32 RequestedMutex, char *CallingRoutine);
INT16 GetMode();
UINT16 *GetPageTableAddress();
int GetProcessorID();
void GetNextEventTime(INT32 *);
void GetSectorStructure(INT16, INT16, char **, INT32 *);
void GetNextOrderedEvent(INT32 *, INT16 *, INT16 *, INT32 *);
int GetMyTid();
int GetTryLock(UINT32 RequestedMutex, char *CallingRoutine);
void GoToExit(int);
void HaltSimulation();
void HandleWindowsError();
void HardwareClock(INT32 *);
void HardwareTimer(INT32);
void HardwareReadDisk(INT16, INT16, char *);
void HardwareWriteDisk(INT16, INT16, char *);
void HardwareCheckDisk(int DiskID);
void HardwareInterrupt(void);
void HardwareFault(INT16, INT16);
void HardwareInternalPanic(INT32);
void IdleSimulation();
void MakeContext(long *ReturningContextPointer, long starting_address,
UINT16* PageTable, BOOL user_or_kernel);
void MemoryCommon(INT32, char *, BOOL);
void PhysicalMemoryCommon(INT32, char *, BOOL);
void MemoryMappedIO(INT32, MEMORY_MAPPED_IO *, BOOL);
void PrintRingBuffer(void);
void PrintHardwareStats(void);
void PrintEventQueue();
void PrintLockDebug(int Action, char *LockCaller, int Mutex, int Return);
void PrintThreadTable(char *Explanation);
int ReleaseLock(UINT32 RequestedMutex, char* CallingRoutine);
void ResumeProcessExecution(Z502CONTEXT *Context);
void SetCurrentContext(Z502CONTEXT *Address);
void SetMode(INT16 mode);
void SetPageTableAddress(UINT16 *address);
int SignalCondition(UINT32 Condition, char* CallingRoutine);
void SoftwareTrap(SYSTEM_CALL_DATA *SystemCallData);
void SuspendProcessExecution(Z502CONTEXT *Context);
void SwitchContext(void **, BOOL);
int WaitForCondition(UINT32 Condition, UINT32 Mutex, INT32 WaitTime,
char * Caller);
void Z502Init();
INT32 STAT_VECTOR[SV_DIMENSION ][LARGEST_STAT_VECTOR_INDEX + 1];
void *TO_VECTOR[TO_VECTOR_TYPES ];
/*****************************************************************
These declarations are USED by the entire simulation. However,
they are protected from access by anyone other than the Z502.c.
The can be accessed via methods available in z502.c.
*****************************************************************/
// This is the definition of the physical memory supported by the hardware
char MEMORY[NUMBER_PHYSICAL_PAGES * PGSIZE ];
// The hardware keeps track of the address of the context currently being run
//Z502CONTEXT *Z502_CURRENT_CONTEXT[MAX_NUMBER_OF_PROCESSORS ];
// The hardware keeps track of the address of the page table currently in use
// IT MAY turn out we don't need this since we can find it in the context
//UINT16 *Z502_PAGE_TBL_ADDR[MAX_NUMBER_OF_PROCESSORS ];
// The hardware keeps track of the mode - user or kernel of the processor
//INT16 Z502_MODE[MAX_NUMBER_OF_PROCESSORS ]; // Kernel or user - hardware only
// This defines the number of processors used in the simulation
INT16 Z502_CURRENT_NUMBER_OF_PROCESSORS = 1;
/*****************************************************************
LOCAL VARIABLES: These declarations should be visible only
to the code in z502.c
*****************************************************************/
INT16 Z502Initialized = FALSE;
UINT32 CurrentSimulationTime = 0;
INT16 EventRingBuffer_index = 0;
EVENT EventQueue;
INT32 NumberOfInterruptsStarted = 0;
INT32 NumberOfInterruptsCompleted = 0;
SECTOR sector_queue[MAX_NUMBER_OF_DISKS ];
DISK_STATE DiskState[MAX_NUMBER_OF_DISKS ];
TIMER_STATE timer_state;
HARDWARE_STATS HardwareStats;
RING_EVENT EventRingBuffer[EVENT_RING_BUFFER_SIZE];
INT32 InterlockRecord[MEMORY_INTERLOCK_SIZE];
INT32 EventLock = -1; // Change from UINT32 - 08/2012
INT32 InterruptLock = -1;
INT32 HardwareLock = -1;
INT32 ThreadTableLock = -1;
INT32 SPPrintLock = -1;
INT32 MPPrintLock = -1;
UINT32 InterruptCondition = 0;
int NextConditionToAllocate = 1; // This was 0 and seemed to work
int InterruptTid; // The Task ID of the interrupt thread
// Contains info about all the threads created
THREAD_INFO ThreadTable[MAX_THREAD_TABLE_SIZE];
#ifdef NT
HANDLE LocalEvent[100];
#endif
#if defined LINUX || defined MAC
pthread_mutex_t LocalMutex[300];
pthread_cond_t LocalCondition[100];
int NextMutexToAllocate = 0;
#endif
/*****************************************************************
MemoryCommon
This code simulates a memory access. Actions include:
o Take a page fault if any of the following occur;
+ Illegal virtual address,
+ Page table doesn't exist,
+ Address is larger than page table,
+ Page table entry exists, but page is invalid.
o The page exists in physical memory, so get the physical address.
Be careful since it may wrap across frame boundaries.
o Copy data to/from caller's location.
o Set referenced/modified bit in page table.
o Advance time and see if an interrupt has occurred.
*****************************************************************/
void MemoryCommon(INT32 VirtualAddress, char *data_ptr, BOOL read_or_write) {
INT16 VirtualPageNumber;
INT32 phys_pg;
INT16 PhysicalAddress[4];
INT32 page_offset;
INT16 index;
INT32 ptbl_bits;
INT16 invalidity;
BOOL page_is_valid;
char Debug_Text[32];
strcpy(Debug_Text, "MemoryCommon");
GetLock(HardwareLock, "MemoryCommon#1");
if (VirtualAddress >= Z502MEM_MAPPED_MIN) {
MemoryMappedIO(VirtualAddress, (MEMORY_MAPPED_IO *) data_ptr,
read_or_write);
ReleaseLock(HardwareLock, "MemoryCommon#2");
return;
}
VirtualPageNumber = (INT16) ((VirtualAddress >= 0) ? VirtualAddress / PGSIZE : -1);
page_offset = VirtualAddress % PGSIZE;
page_is_valid = FALSE;
/* Loop until the virtual page passes all the tests */
while (page_is_valid == FALSE ) {
invalidity = 0; //software trap
if (VirtualPageNumber >= NUMBER_VIRTUAL_PAGES)
invalidity = 1; //cpu error
if (VirtualPageNumber < 0)
invalidity = 2; //invalid memory
if (GetPageTableAddress() == NULL)
invalidity = 3; //invalid physical memory
if ((invalidity == 0)
&& (GetPageTableAddress()[(UINT16) VirtualPageNumber]
& PTBL_VALID_BIT) == 0)
invalidity = 4; //PRIVILEGED_INSTRUCTION
DoMemoryDebug(invalidity, VirtualPageNumber);
if (invalidity > 0) {
if ((GetCurrentContext() != NULL)
&& ((GetCurrentContext()->StructureID)
!= CONTEXT_STRUCTURE_ID )) {
printf(
"The address of the current context is invalid in MemoryCommon\n");
printf("Something in the OS has destroyed this location.\n");
HardwareInternalPanic(ERR_OS502_GENERATED_BUG);
}
GetCurrentContext()->FaultInProgress = TRUE;
// The fault handler will do it's own locking - 11/13/11
ReleaseLock(HardwareLock, "MemoryCommon#3");
HardwareFault(INVALID_MEMORY, VirtualPageNumber);
// Regain the lock to protect the memory check - 11/13/11
GetLock(HardwareLock, "MemoryCommon#4");
} else
page_is_valid = TRUE;
} /* END of while */
phys_pg = GetPageTableAddress()[VirtualPageNumber] & PTBL_PHYS_PG_NO;
PhysicalAddress[0] = (INT16) (phys_pg * (INT32) PGSIZE + page_offset);
PhysicalAddress[1] = PhysicalAddress[0] + 1; /* first guess */
PhysicalAddress[2] = PhysicalAddress[0] + 2; /* first guess */
PhysicalAddress[3] = PhysicalAddress[0] + 3; /* first guess */
page_is_valid = FALSE;
if (page_offset > PGSIZE - 4) /* long int wraps over page */
{
while (page_is_valid == FALSE ) {
invalidity = 0;
if (VirtualPageNumber + 1 >= NUMBER_VIRTUAL_PAGES)
invalidity = 6;
if ((GetPageTableAddress()[(UINT16) VirtualPageNumber + 1]
& PTBL_VALID_BIT) == 0)
invalidity = 8;
DoMemoryDebug(invalidity, (short) (VirtualPageNumber + 1));
if (invalidity > 0) {
if (GetCurrentContext() != NULL
&& GetCurrentContext()->StructureID
!= CONTEXT_STRUCTURE_ID) {
printf("The address of the current context is invalid\n");
printf("in MemoryCommon. The OS has destroyed the \n");
printf("location holding the context.\n");
HardwareInternalPanic(ERR_OS502_GENERATED_BUG);
}
GetCurrentContext()->FaultInProgress = TRUE;
HardwareFault(INVALID_MEMORY, (INT16) (VirtualPageNumber + 1));
} else
page_is_valid = TRUE;
} /* End of while */
phys_pg =
GetPageTableAddress()[VirtualPageNumber + 1] & PTBL_PHYS_PG_NO;
for (index = PGSIZE - (INT16) page_offset; index <= 3; index++)
PhysicalAddress[index] = (INT16) ((phys_pg - 1) * (INT32) PGSIZE
+ page_offset + (INT32) index);
} /* End of if page */
if (phys_pg < 0 || phys_pg > NUMBER_PHYSICAL_PAGES - 1) {
printf("The physical address is invalid in MemoryCommon\n");
printf("Physical page = %d, Virtual Page = %d\n", phys_pg,
VirtualPageNumber);
HardwareInternalPanic(ERR_OS502_GENERATED_BUG);
}
if (GetCurrentContext() != NULL
&& GetCurrentContext()->StructureID != CONTEXT_STRUCTURE_ID) {
printf("The address of the context is invalid in MemoryCommon\n");
printf("Something in the OS has destroyed this location.\n");
HardwareInternalPanic(ERR_OS502_GENERATED_BUG);
}
GetCurrentContext()->FaultInProgress = FALSE;
if (read_or_write == SYSNUM_MEM_READ) {
data_ptr[0] = MEMORY[PhysicalAddress[0]];
data_ptr[1] = MEMORY[PhysicalAddress[1]];
data_ptr[2] = MEMORY[PhysicalAddress[2]];
data_ptr[3] = MEMORY[PhysicalAddress[3]];
ptbl_bits = PTBL_REFERENCED_BIT;
}
if (read_or_write == SYSNUM_MEM_WRITE) {
MEMORY[PhysicalAddress[0]] = data_ptr[0];
MEMORY[PhysicalAddress[1]] = data_ptr[1];
MEMORY[PhysicalAddress[2]] = data_ptr[2];
MEMORY[PhysicalAddress[3]] = data_ptr[3];
ptbl_bits = PTBL_REFERENCED_BIT | PTBL_MODIFIED_BIT;
}
GetPageTableAddress()[VirtualPageNumber] |= ptbl_bits;
if (page_offset > PGSIZE - 4)
GetPageTableAddress()[VirtualPageNumber + 1] |= ptbl_bits;
ChargeTimeAndCheckEvents(COST_OF_MEMORY_ACCESS);
ReleaseLock(HardwareLock, "MemoryCommon#5");
} // End of MemoryCommon
/*****************************************************************
DoMemoryDebug
Print out details about why a page fault occurred.
*****************************************************************/
void DoMemoryDebug(INT16 invalidity, INT16 vpn) {
if (DO_MEMORY_DEBUG == 0)
return;
printf("MEMORY DEBUG: ");
if (invalidity == 0) {
printf("Virtual Page Number %d was successful\n", vpn);
}
if (invalidity == 1) {
printf("You asked for a virtual page, %d, greater than the\n", vpn);
printf("\t\tmaximum number of virtual pages, %d\n",
NUMBER_VIRTUAL_PAGES);
}
if (invalidity == 2) {
printf("You asked for a virtual page, %d, less than\n", vpn);
printf("\t\tzero. What are you thinking?\n");
}
if (invalidity == 3) {
printf("A valid page table should have been set up when \n");
printf("\t\tthe process was created. Somehow that didn't");
printf("\t\thappen and the hardware can't find\n");
printf("\t\taddress of the page table.\n");
}
if (invalidity == 4) {
printf("You have not initialized the slot in the page table\n");
printf("\t\tcorresponding to virtual page %d\n", vpn);
printf("\t\tYou must aim this virtual page at a physical frame\n");
printf("\t\tand mark this page table slot as valid.\n");
}
if (invalidity == 6) {
printf("The address you asked for crosses onto a second page.\n");
printf("\t\tThis second page took a fault.\n");
printf("You asked for a virtual page, %d, greater than the\n", vpn);
printf("\t\tmaximum number of virtual pages, %d\n",
NUMBER_VIRTUAL_PAGES);
}
if (invalidity == 8) {
printf("The address you asked for crosses onto a second page.\n");
printf("\t\tThis second page took a fault.\n");
printf("You have not initialized the slot in the page table\n");
printf("\t\tcorresponding to virtual page %d\n", vpn);
printf("\t\tYou must aim this virtual page at a physical frame\n");
printf("\t\tand mark this page table slot as valid.\n");
}
} // End of DoMemoryDebug
/*****************************************************************
Z502MemoryRead and Z502_MEM_WRITE
Set a flag and call common code
*****************************************************************/
void Z502MemoryRead(INT32 VirtualAddress, INT32 *data_ptr) {
MemoryCommon(VirtualAddress, (char *) data_ptr, (BOOL) SYSNUM_MEM_READ);
} // End Z502MemoryRead
void Z502MemoryWrite(INT32 VirtualAddress, INT32 *data_ptr) {
MemoryCommon(VirtualAddress, (char *) data_ptr, (BOOL) SYSNUM_MEM_WRITE);
} // End Z502MemoryWrite
/*************************************************************************
Z502MemoryReadModify
Do atomic modify of a memory location. If the input parameters are
incorrect, then return SuccessfulAction = FALSE.
If the memory location
is already locked by someone else, and we're asked to lock
return SuccessfulAction = FALSE.
If the lock was obtained here, return SuccessfulAction = TRUE.
If the lock was held by us or someone else, and we're asked to UNlock,
return SuccessfulAction = TRUE.
NOTE: There are 10 lock locations set aside for the hardware's use.
It is assumed that the hardware will have initialized these locks
early on so that they don't interfere with this mechanism.
*************************************************************************/
void Z502MemoryReadModify(INT32 VirtualAddress, INT32 NewLockValue,
INT32 Suspend, INT32 *SuccessfulAction) {
int WhichRecord;
// GetLock( HardwareLock, "Z502_READ_MODIFY" ); JB - 7/26/06
if (VirtualAddress < MEMORY_INTERLOCK_BASE
|| VirtualAddress
>= MEMORY_INTERLOCK_BASE + MEMORY_INTERLOCK_SIZE + 10
|| (NewLockValue != 0 && NewLockValue != 1)
|| (Suspend != TRUE && Suspend != FALSE )) {
*SuccessfulAction = FALSE;
return;
}
WhichRecord = VirtualAddress - MEMORY_INTERLOCK_BASE + 10;
if (InterlockRecord[WhichRecord] == -1)
CreateLock(&(InterlockRecord[WhichRecord]), "Z502MemoryReadModify");
if (NewLockValue == 1 && Suspend == FALSE)
*SuccessfulAction = GetTryLock(InterlockRecord[WhichRecord],
"Z502MemReadMod");
if (NewLockValue == 1 && Suspend == TRUE) {
*SuccessfulAction = GetLock(InterlockRecord[WhichRecord],
"Z502_READ_MODIFY");
}
if (NewLockValue == 0) {
*SuccessfulAction = ReleaseLock(InterlockRecord[WhichRecord],
"Z502_READ_MODIFY");
}
// ReleaseLock( HardwareLock, "Z502_READ_MODIFY" ); JB - 7/26/06
} // End Z502MemoryReadModify
/*************************************************************************
MemoryMappedIO
We talk to devices via certain memory addresses found in memory
hyperspace. In other words, these memory addresses don't point to
real physical memory. You must be privileged to touch this hardware.
*************************************************************************/
void MemoryMappedIO(INT32 address, MEMORY_MAPPED_IO *mmio, BOOL ReadOrWrite) {
//MEMORY_MAPPED_IO mmio = (MEMORY_MAPPED_IO ) Data;
INT32 index;
INT32 Temporary;
long LongTemporary;
// We assume that Memory Common has set the Hardware Lock - we don't
// want to do it again.
// GetLock ( HardwareLock, "memory_mapped_io" );
// We need to be in kernel mode or be in interrupt handler
if (GetMode() != KERNEL_MODE && InterruptTid != GetMyTid()) {
HardwareFault(PRIVILEGED_INSTRUCTION, 0);
return;
}
ChargeTimeAndCheckEvents(COST_OF_MEMORY_MAPPED_IO);
// Switch off the IO Function that the user has defined when
// doing the memory request
switch (address) {
// There's only one action here. Don't worry about the user packet
case Z502Halt: {
if (ReadOrWrite == SYSNUM_MEM_WRITE) {
HaltSimulation();
} else {
mmio->Field4 = ERR_BAD_PARAM;
}
break;
}
// There's only one action here. Don't worry about the user packet
case Z502Idle: {
if (ReadOrWrite == SYSNUM_MEM_WRITE) {
IdleSimulation();
} else {
mmio->Field4 = ERR_BAD_PARAM;
}
break;
}
case Z502InterruptDevice: {
// We want to get the device ID and status
mmio->Field4 = ERR_SUCCESS; // Assume success
Temporary = 0; // Used as flag to show action found
if ((ReadOrWrite == SYSNUM_MEM_READ)
&& (mmio->Mode == Z502GetInterruptInfo)) {
mmio->Field1 = -1;
Temporary = 1;
// We want to find the target device and assure that it was activated by
// the thread that's now looking for it. This means that if a thread
// took a memory fault, that it will be THAT thread in the OS fault
// handler that will pull this page number. NOTE that the interrupts
// should be single threaded - there's only one interrupt thread that
// put things on and off the STAT_VECTOR. But there are many fault
// threads - one for each of the active processes - so we need to
// do the disambiguation here.
for (index = 0; index <= LARGEST_STAT_VECTOR_INDEX; index++) {
if ((STAT_VECTOR[SV_ACTIVE ][index] != 0)
&& (STAT_VECTOR[SV_TID ][index] == GetMyTid())) {
mmio->Field1 = index; // Device ID
mmio->Field2 = STAT_VECTOR[SV_VALUE ][index]; // Device Status
STAT_VECTOR[SV_VALUE ][index] = 0; // Invalidate the record
STAT_VECTOR[SV_ACTIVE ][index] = 0;
STAT_VECTOR[SV_TID ][index] = 0;
break;
}
} // end of for
// No device was found - report it as an error
if (mmio->Field1 == -1) {
mmio->Field4 = ERR_NO_DEVICE_FOUND;
}
break;
}
// We want to clear the interrupt status of the device we were working with
// The code for Z502ClearInterruptStatus was removed in Rev 4.40
if (Temporary == 0) {
printf(
"PANIC #1 - Illegal use of parameters in Z502InterruptDevice\n");
mmio->Field4 = ERR_BAD_PARAM;
}
break;
}
case Z502Clock: {
HardwareClock(&Temporary);
mmio->Field1 = Temporary;
break;
}
case Z502Timer: {
// Set the timer - the number of time units to delay
if (mmio->Mode == Z502Start) {
HardwareTimer(mmio->Field1);
break;
}
// Get the status of the timer
if (mmio->Mode == Z502Status) {
if (timer_state.timer_in_use == TRUE)
mmio->Field1 = DEVICE_IN_USE;
else
mmio->Field1 = DEVICE_FREE;
break;
}
mmio->Field4 = ERR_BAD_PARAM;
printf("PANIC #2 - Illegal use of Memory Mapped IO\n");
break;
} // End of case Z502Timer
// Do the various operations required for the disk
case Z502Disk: {
mmio->Field4 = 0;
// Check for Status mode first
if (mmio->Mode == Z502Status) {
if (mmio->Field1 >= 0 && mmio->Field1 < MAX_NUMBER_OF_DISKS) {
if (DiskState[mmio->Field1].DiskInUse == TRUE)
mmio->Field2 = DEVICE_IN_USE;
else
mmio->Field2 = DEVICE_FREE;
} else {
mmio->Field4 = ERR_BAD_DEVICE_ID; //Not a legal disk number
}
break;
} // End of Mode == Status
// It's not status, do Read/Write/Check Disk
if ((mmio->Field1 >= 0 && mmio->Field1 < MAX_NUMBER_OF_DISKS )
&& (mmio->Field2 >= 0 && mmio->Field2 <= NUMBER_LOGICAL_SECTORS )) {
if (mmio->Mode == Z502DiskRead) {
HardwareReadDisk((INT16) mmio->Field1, mmio->Field2,
(char *) mmio->Field3);
}
if (mmio->Mode == Z502DiskWrite) {
HardwareWriteDisk((INT16) mmio->Field1, mmio->Field2,
(char *) mmio->Field3);
}
if (mmio->Mode == Z502CheckDisk) {
HardwareCheckDisk(mmio->Field1);
}
break;
}
// We get here only if there's a confusion
if (DO_DEVICE_DEBUG) {
printf("------ BEGIN DO_DEVICE DEBUG - IN Z502Disk ----- \n");
printf("ERROR: Invalid parameter in command from OS\n");
printf("-------- END DO_DEVICE DEBUG - ------------------\n");
}
mmio->Field4 = ERR_BAD_PARAM;
break;
} // End of case == Z502Disk
// Implement the Context Hardware Instructions
// This includes initializing and creating the context, and then
// starting up that context.
case Z502Context: {
if (mmio->Mode == Z502StartContext) {
ReleaseLock(HardwareLock, "StartContext");
// We only implement the mode of suspending the caller
SwitchContext((void *) &mmio->Field1, mmio->Field2);
GetLock(HardwareLock, "StartContext");
mmio->Field4 = ERR_SUCCESS; // Error code
break;
} // End of Mode === StartContext
if (mmio->Mode == Z502InitializeContext) {
MakeContext(&LongTemporary, mmio->Field2, (UINT16 *) mmio->Field3,
KERNEL_MODE);
mmio->Field1 = LongTemporary; // Context pointer
mmio->Field4 = ERR_SUCCESS; // Error code
break;
} // End of Mode == InitializeContext
if (mmio->Mode == Z502GetPageTable) {
mmio->Field1 = (long) GetPageTableAddress();
mmio->Field4 = ERR_SUCCESS; // Error code
break;
} // End of Mode == Z502GetPageTable
if (mmio->Mode == Z502GetCurrentContext) {
long *abc = (long *) GetCurrentContext();
mmio->Field1 = (long) abc;
mmio->Field4 = ERR_SUCCESS; // Error code
break;
} // End of Mode == Z502GetCurrentContext
mmio->Field4 = ERR_BAD_PARAM; // Couldn't handle the mode
if (DO_DEVICE_DEBUG) {
printf("- BEGIN DO_DEVICE DEBUG - Z502Context - \n");
printf("ERROR: Illegal Mode in Context memory mapped IO\n");
printf("-------- END DO_DEVICE DEBUG - ----------\n");
}
break;
} // End of case Context
// Implement a multiprocessor simulation
case Z502Processor: {
mmio->Field4 = ERR_SUCCESS;
if (mmio->Mode == Z502SetProcessorNumber) {
if (mmio->Field1 > MAX_NUMBER_OF_PROCESSORS) {
mmio->Field4 = ERR_BAD_PARAM;
} else {
Z502_CURRENT_NUMBER_OF_PROCESSORS = mmio->Field1;
}
break;
} // End of Z502SetProcessorNumber
// The returned variable was set to 1 when declared.
// It will only be greater than 1 when the SetProcessorNumber
// call has occurred.
if (mmio->Mode == Z502GetProcessorNumber) {
mmio->Field1 = Z502_CURRENT_NUMBER_OF_PROCESSORS;
} // End of Z502SetProcessorNumber
break;
} // End of case Z502Processor
default: { // Bad news if we get here - we don't know how to handle it!
mmio->Field4 = ERR_BAD_PARAM;
break;
}
} // End of switch
} // End MemoryMappedIO
/*****************************************************************
PhysicalMemoryCommon
This code is designed to let an operating system touch physical
memory - in fact if a user tries to enter this routine, a
fault occurs.
The routine reads or writes an entire page of physical memory
from or to a buffer containing PGSIZE number of bytes.
This allows the OS to do physical memory accesses without worrying
about the page table.
*****************************************************************/
void PhysicalMemoryCommon(INT32 PhysicalPageNumber, char *data_ptr,
BOOL read_or_write) {
INT16 PhysicalPageAddress;
INT16 index;
char Debug_Text[32];
strcpy(Debug_Text, "PhysicalMemoryCommon");
GetLock(HardwareLock, Debug_Text);
// If a user tries to do this call from user mode, a fault occurs
if (GetMode() != KERNEL_MODE) {
HardwareFault(PRIVILEGED_INSTRUCTION, 0);
return;
}
// If the user has asked for an illegal physical page, take a fault
// then return with no modification to the user's buffer.
if (PhysicalPageNumber < 0 || PhysicalPageNumber > NUMBER_PHYSICAL_PAGES) {
ReleaseLock(HardwareLock, Debug_Text);
HardwareFault(INVALID_PHYSICAL_MEMORY, PhysicalPageNumber);
return;
}
PhysicalPageAddress = PGSIZE * PhysicalPageNumber;
if (read_or_write == SYSNUM_MEM_READ) {
for (index = 0; index < PGSIZE ; index++)
data_ptr[index] = MEMORY[PhysicalPageAddress + index];
}
if (read_or_write == SYSNUM_MEM_WRITE) {
for (index = 0; index < PGSIZE ; index++)
MEMORY[PhysicalPageAddress + index] = data_ptr[index];
}
ChargeTimeAndCheckEvents(COST_OF_MEMORY_ACCESS);
ReleaseLock(HardwareLock, Debug_Text);
} // End of PhysicalMemoryCommon
/*****************************************************************
Z502ReadPhysicalMemory and Z502WritePhysicalMemory
This code reads physical memory. It doesn't matter what you have
the page table set to, this code will ignore the page table and
read/write the physical memory.
*****************************************************************/
void Z502ReadPhysicalMemory(INT32 PhysicalPageNumber, char *PhysicalDataPointer) {
PhysicalMemoryCommon(PhysicalPageNumber, PhysicalDataPointer,
(BOOL) SYSNUM_MEM_READ);
} // End Z502ReadPhysicalMemory
void Z502WritePhysicalMemory(INT32 PhysicalPageNumber,
char *PhysicalDataPointer) {
PhysicalMemoryCommon(PhysicalPageNumber, PhysicalDataPointer,
(BOOL) SYSNUM_MEM_WRITE);
} // End Z502WritePhysicalMemory
/*************************************************************************
HardwareReadDisk
This code simulates a disk read. Actions include:
o If not in KERNEL_MODE, then cause priv inst trap.
o Do range check on disk_id, sector; give
interrupt error = ERR_BAD_PARAM if illegal.
o If an event for this disk already exists ( the disk
is already busy ), then give interrupt error ERR_DISK_IN_USE.
o Search for sector structure off of hashed value.
o If search fails give interrupt error = ERR_NO_PREVIOUS_WRITE
o Copy data from sector to buffer.
o From DiskState information, determine how long this request will take.
o Request a future interrupt for this event.
o Advance time and see if an interrupt has occurred.
**************************************************************************/
void HardwareReadDisk(INT16 disk_id, INT16 sector, char *buffer_ptr) {
INT32 local_error;
char *sector_ptr = 0;
INT32 access_time;
INT16 error_found;
error_found = 0;
// We need to be in kernel mode or be in interrupt handler
if (GetMode() != KERNEL_MODE && InterruptTid != GetMyTid()) {
HardwareFault(PRIVILEGED_INSTRUCTION, 0);
return;
}
// This SHOULD have been checked in MemoryMappedIO
if (disk_id < 0 || disk_id >= MAX_NUMBER_OF_DISKS) {
disk_id = 0; /* To aim at legal vector */
error_found = ERR_BAD_PARAM;
}
if (sector < 0 || sector >= NUMBER_LOGICAL_SECTORS)
error_found = ERR_BAD_PARAM;
if (error_found == 0) {
GetSectorStructure(disk_id, sector, §or_ptr, &local_error);
if (local_error != 0)
error_found = ERR_NO_PREVIOUS_WRITE;
if (DiskState[disk_id].DiskInUse == TRUE)
error_found = ERR_DISK_IN_USE;
}
/* If we found an error, add an event that will cause an immediate
hardware interrupt. */
if (error_found != 0) {
if (DO_DEVICE_DEBUG) {
printf("--- BEGIN DO_DEVICE DEBUG - IN read_disk ----- \n");
printf("ERROR: Something screwed up The error\n");
printf(" code is %d that you can look up in global.h\n",
error_found);
printf(" The disk will cause an interrupt to tell \n");
printf(" you about that error.\n");
printf("--- END DO_DEVICE DEBUG - ---------------------\n");
}
AddEventToInterruptQueue(CurrentSimulationTime,
(INT16) (DISK_INTERRUPT + disk_id), error_found,
&DiskState[disk_id].EventPtr);
} else {
//memcpy(buffer_ptr, sector_ptr, PGSIZE); // Bugfix 07/2014
DiskState[disk_id].Destination = buffer_ptr;
DiskState[disk_id].Source = sector_ptr;
access_time = CurrentSimulationTime + 100
+ abs(DiskState[disk_id].LastSector - sector) / 20;
HardwareStats.disk_reads[disk_id]++;
HardwareStats.time_disk_busy[disk_id] += access_time
- CurrentSimulationTime;
if (DO_DEVICE_DEBUG) {
printf("\nDEVICE_DEBUG: Time = %d: ", CurrentSimulationTime);
printf(" Disk %d READ will interrupt at time = %d\n", disk_id,
access_time);
}
AddEventToInterruptQueue(access_time,
(INT16) (DISK_INTERRUPT + disk_id), (INT16) ERR_SUCCESS,
&DiskState[disk_id].EventPtr);
DiskState[disk_id].LastSector = sector;
}
DiskState[disk_id].DiskInUse = TRUE;
// printf("1. Setting %d TRUE\n", disk_id );
ChargeTimeAndCheckEvents(COST_OF_DISK_ACCESS);
} // End of HardwareReadDisk
/*****************************************************************
HardwareWriteDisk
This code simulates a disk write. Actions include:
o If not in KERNEL_MODE, then cause priv inst trap.
o Do range check on disk_id, sector; give interrupt error
= ERR_BAD_PARAM if illegal.
o If an event for this disk already exists ( the disk is already busy ),
then give interrupt error ERR_DISK_IN_USE.
o Search for sector structure off of hashed value.
o If search fails give create a sector on the simulated disk.
o Copy data from buffer to sector.
o From DiskState information, determine how long this request will take.
o Request a future interrupt for this event.
o Advance time and see if an interrupt has occurred.
*****************************************************************/
void HardwareWriteDisk(INT16 disk_id, INT16 sector, char *buffer_ptr) {
INT32 local_error;
char *sector_ptr;
INT32 access_time;
INT16 error_found;
error_found = 0;
// We need to be in kernel mode or be in interrupt handler
if (GetMode() != KERNEL_MODE && InterruptTid != GetMyTid()) {
HardwareFault(PRIVILEGED_INSTRUCTION, 0);
return;
}
if (disk_id < 0 || disk_id >= MAX_NUMBER_OF_DISKS) {
disk_id = 1; /* To aim at legal vector */
error_found = ERR_BAD_PARAM;
}
if (sector < 0 || sector >= NUMBER_LOGICAL_SECTORS)
error_found = ERR_BAD_PARAM;
if (DiskState[disk_id].DiskInUse == TRUE)
error_found = ERR_DISK_IN_USE;
if (error_found != 0) {
if (DO_DEVICE_DEBUG) {
printf("---- BEGIN DO_DEVICE DEBUG - IN write_disk --- \n");
printf("ERROR: in your disk request. The error\n");
printf(" code is %d that you can look up in global.h\n",
error_found);
printf(" The disk will cause an interrupt to tell \n");
printf(" you about that error.\n");
printf("---- END DO_DEVICE DEBUG - --------------------\n");
}
AddEventToInterruptQueue(CurrentSimulationTime,
(INT16) (DISK_INTERRUPT + disk_id - 1), error_found,
&DiskState[disk_id].EventPtr);
} else {
GetSectorStructure(disk_id, sector, §or_ptr, &local_error);
if (local_error != 0) /* No structure for this sector exists */
CreateSectorStruct(disk_id, sector, §or_ptr);
//memcpy(sector_ptr, buffer_ptr, PGSIZE); // Bugfix 07/2014
DiskState[disk_id].Destination = sector_ptr;
DiskState[disk_id].Source = buffer_ptr;
access_time = (INT32) CurrentSimulationTime + 100
+ abs(DiskState[disk_id].LastSector - sector) / 20;
HardwareStats.disk_writes[disk_id]++;
HardwareStats.time_disk_busy[disk_id] += access_time
- CurrentSimulationTime;
if (DO_DEVICE_DEBUG) {
printf("\nDEVICE_DEBUG: Time = %d: ", CurrentSimulationTime);
printf("Disk %d WRITE will cause interrupt at time = %d\n", disk_id,
access_time);
}
AddEventToInterruptQueue(access_time,
(INT16) (DISK_INTERRUPT + disk_id), (INT16) ERR_SUCCESS,
&DiskState[disk_id].EventPtr);
DiskState[disk_id].LastSector = sector;
}
// No matter if the disk request succeeds or fails, the disk is set as busy
DiskState[disk_id].DiskInUse = TRUE;
// printf("2. Setting %d TRUE\n", disk_id );
ChargeTimeAndCheckEvents(COST_OF_DISK_ACCESS);
} // End of HardwareWriteDisk
/*****************************************************************
HardwareCheckDisk()
This code added so we can print out the contents of a formatted
disk.
This enables us to check that the disk is correctly set up.
We assume before we get here someone has checked the validity
of the disk
This code was written for Rev 4.30 in February 2016
*****************************************************************/
void HardwareCheckDisk(int DiskID) {
FILE *Output;
int Index, Index2;
int Result;
INT32 local_error;
char *BufferPointer;
unsigned char LocalBuffer[PGSIZE ];
char OutputString[120];
char TempString[16];
Output = fopen("CheckDiskData", "w");
for (Index = 0; Index < NUMBER_LOGICAL_SECTORS ; Index++) {
// HardwareReadDisk(DiskID, Index, &BufferPointer);
GetSectorStructure(DiskID, Index, &BufferPointer, &local_error);
if (local_error == 0) { // it's a good sector
memcpy(LocalBuffer, BufferPointer, PGSIZE);
// Determine if the Sector contains all zeros. If so, don't print.
Result = 0;
for (Index2 = 0; Index2 < PGSIZE ; Index2++) {
Result += LocalBuffer[Index2];
}
if (Result > 0) {