-
Notifications
You must be signed in to change notification settings - Fork 2
/
interrupt.c
209 lines (178 loc) · 7.33 KB
/
interrupt.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
/*
* interrupt.c -
*/
#include <types.h>
#include <interrupt.h>
#include <segment.h>
#include <hardware.h>
#include <io.h>
#include <zeos_interrupt.h>
#include <system.h>
#include <sched.h>
#include <mm_address.h>
#include <utils.h>
#include <cbuffer.h>
#include <mm.h>
Gate idt[IDT_ENTRIES];
Register idtR;
char char_map[] =
{
'\0','\0','1','2','3','4','5','6',
'7','8','9','0','\'','¡','\0','\0',
'q','w','e','r','t','y','u','i',
'o','p','`','+','\0','\0','a','s',
'd','f','g','h','j','k','l','ñ',
'\0','º','\0','ç','z','x','c','v',
'b','n','m',',','.','-','\0','*',
'\0','\0','\0','\0','\0','\0','\0','\0',
'\0','\0','\0','\0','\0','\0','\0','7',
'8','9','-','4','5','6','+','1',
'2','3','0','\0','\0','\0','<','\0',
'\0','\0','\0','\0','\0','\0','\0','\0',
'\0','\0'
};
void setInterruptHandler(int vector, void (*handler)(), int maxAccessibleFromPL)
{
/***********************************************************************/
/* THE INTERRUPTION GATE FLAGS: R1: pg. 5-11 */
/* *************************** */
/* flags = x xx 0x110 000 ????? */
/* | | | */
/* | | \ D = Size of gate: 1 = 32 bits; 0 = 16 bits */
/* | \ DPL = Num. higher PL from which it is accessible */
/* \ P = Segment Present bit */
/***********************************************************************/
Word flags = (Word)(maxAccessibleFromPL << 13);
flags |= 0x8E00; /* P = 1, D = 1, Type = 1110 (Interrupt Gate) */
idt[vector].lowOffset = lowWord((DWord)handler);
idt[vector].segmentSelector = __KERNEL_CS;
idt[vector].flags = flags;
idt[vector].highOffset = highWord((DWord)handler);
}
void setTrapHandler(int vector, void (*handler)(), int maxAccessibleFromPL)
{
/***********************************************************************/
/* THE TRAP GATE FLAGS: R1: pg. 5-11 */
/* ******************** */
/* flags = x xx 0x111 000 ????? */
/* | | | */
/* | | \ D = Size of gate: 1 = 32 bits; 0 = 16 bits */
/* | \ DPL = Num. higher PL from which it is accessible */
/* \ P = Segment Present bit */
/***********************************************************************/
Word flags = (Word)(maxAccessibleFromPL << 13);
//flags |= 0x8F00; /* P = 1, D = 1, Type = 1111 (Trap Gate) */
/* Changed to 0x8e00 to convert it to an 'interrupt gate' and so
the system calls will be thread-safe. */
flags |= 0x8E00; /* P = 1, D = 1, Type = 1110 (Interrupt Gate) */
idt[vector].lowOffset = lowWord((DWord)handler);
idt[vector].segmentSelector = __KERNEL_CS;
idt[vector].flags = flags;
idt[vector].highOffset = highWord((DWord)handler);
}
void setIdt()
{
/* Program interrupts/exception service routines */
idtR.base = (DWord)idt;
idtR.limit = IDT_ENTRIES * sizeof(Gate) - 1;
/* ADD INITIALIZATION CODE FOR INTERRUPT VECTOR (IDT)*/
set_handlers();
setInterruptHandler(32, clock_handler, 0);
setInterruptHandler(33, keyboard_handler, 0);
set_idt_reg(&idtR);
}
void clock_routine() {
zeos_ticks++;
zeos_show_clock();
sched_update_data();
if (sched_change_needed()) {
sched_update_queues_state(&readyqueue, current());
sched_switch_process();
}
}
/* Gestiona la copia del cbuffer i els problemes ocasionats al ser un
* procés diferent del bloquejat el que ha d'accedir al espai d'@ del
* procés bloquejat.
* Llegeix min(keystoread,size del cbuffer) elements.
* - Retorna 1:
* Si ha pogut realitzar la copia.
* - Retorna 0:
* Si no ha pogut realitzar la copia per falta de pagines
* lliures en el procés per poder accedir al espai d'@ del
* procés bloquejat.
* */
int keyboard_cbuffer_read() {
struct list_head *list_blocked = list_first(&keyboardqueue);
struct task_struct * blocked_pcb = list_head_to_task_struct(list_blocked);
struct task_struct * current_pcb = current();
page_table_entry * pt_blocked = get_PT(blocked_pcb);
page_table_entry * pt_current = get_PT(current_pcb);
page_table_entry * dir_blocked = get_DIR(blocked_pcb);
page_table_entry * dir_current = get_DIR(current_pcb);
char bread;
if (dir_blocked != dir_current) { // Si són 2 procesos independents
int id_pag_buffer = ((int)blocked_pcb->kbinfo.keybuffer&0x003ff000)>>12;
int addr_buffer = ((int)blocked_pcb->kbinfo.keybuffer&0x00000FFF);
/*Cerca de entradeslliures a la taula de pàgines */
int free_pag = FIRST_FREE_PAG_P;
while(pt_current[free_pag].entry != 0 && free_pag<TOTAL_PAGES) free_pag++;
if (free_pag == TOTAL_PAGES) return 0; // Cas d'error
set_ss_pag(pt_current,free_pag, pt_blocked[id_pag_buffer].bits.pbase_addr);
while (!circularbIsEmpty(&cbuffer) && blocked_pcb->kbinfo.keystoread > 0) {
circularbRead(&cbuffer,&bread);
copy_to_user(&bread, (void *)((free_pag<<12)+addr_buffer), 1);
blocked_pcb->kbinfo.keystoread--;
blocked_pcb->kbinfo.keysread++;
blocked_pcb->kbinfo.keybuffer++;
addr_buffer++;
/* Si s'ha de canviar la pàgina */
if (addr_buffer == PAGE_SIZE) {
id_pag_buffer++;
set_ss_pag(pt_current,free_pag, pt_blocked[id_pag_buffer].bits.pbase_addr);
set_cr3(dir_current);
}
}
del_ss_pag(pt_current, free_pag);
}
else { // Si els 2 procesos són threads amb mem.compartida
while (!circularbIsEmpty(&cbuffer) && blocked_pcb->kbinfo.keystoread > 0) {
circularbRead(&cbuffer,&bread);
copy_to_user(&bread, blocked_pcb->kbinfo.keybuffer++, 1);
blocked_pcb->kbinfo.keystoread--;
blocked_pcb->kbinfo.keysread++;
}
}
return 1;
}
void keyboard_routine() {
unsigned char read = inb(0x60); // Lectura del Port
char keyPressed;
/* Primer bit indica Make(0)/Break(1) => key (Pressed/Relased)*/
if (read < 0x80) { // Make
if (read < 98) keyPressed = char_map[read] == '\0' ? 'C' : char_map[read];
else keyPressed = 'C';
/* Si el Buffer Circular no està ple */
if (!circularbIsFull(&cbuffer)) {
circularbWrite(&cbuffer,&keyPressed);
}
/* Com que el buffer es pot emplenar i no sempre podem garantir que es
* podrà buidar, sempre s'ha de comprovar si podem actuar. */
if (!list_empty(&keyboardqueue)) {
struct list_head * task_list = list_first(&keyboardqueue);
struct task_struct * taskbloqued = list_head_to_task_struct(task_list);
int ret = 0;
/* Si es compleix la condició hem d'intentar llegir el buffer */
if (taskbloqued->kbinfo.keystoread <= circularbNumElements(&cbuffer) || circularbIsFull(&cbuffer)) {
ret = keyboard_cbuffer_read();
}
/* Si hem pogut llegir del buffer i no queda res més per llegir:
* - Posem el procés en la readyqueue, i l'eliminem de la keyboardqueue */
if (taskbloqued->kbinfo.keystoread == 0 && ret) {
list_del(task_list);
sched_update_queues_state(&readyqueue, taskbloqued);
}
}
}
else { // Break
}
}