nckernel  0.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
isr.c
Go to the documentation of this file.
1 #include <sys/types.h>
2 #include <stdio.h>
3 #include <stdint.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <stddef.h>
8 #include <pthread.h>
9 #include <assert.h>
10 #include <unistd.h>
11 
12 #include <object.h>
13 #include <list.h>
14 #include <thread.h>
15 #include <interrupt.h>
16 #include <isr.h>
17 #include <arch.h>
18 #include <x86_util.h>
19 
20 #include <segment.h> /* for USER, KERNEL macro definitions */
21 #include <paging.h> /* for cr3 structure - x86.h references this */
22 #include <x86.h>
23 
24 #include <debug.h>
25 
26 struct irq_handler {
27  struct list_head head;
28  int (*handler)(int sub_irq, void *info, void *data);
29  int priority;
30  void *data;
31 };
32 
33 struct list {
34  struct list_head head;
35  int idx;
36  int cnt;
38  struct list_head list;
39 };
40 
41 static LIST_HEAD(s_list);
42 
43 int register_irq(int idx, int priority, int (*handler)(int, void *, void *), void *data)
44 {
45  struct list_head *pos;
46  struct list *entry;
47  struct irq_handler *item;
48  struct irq_handler *tmp;
49  unsigned long flags;
50 
51  irq_local_save(&flags);
52  item = malloc(sizeof(*item));
53  if (!item) {
54  irq_local_restore(flags);
55  return -ENOMEM;
56  }
57 
58  entry = NULL;
59  list_for_each(pos, &s_list) {
60  entry = list_entry(pos, struct list, head);
61  if (entry->idx == idx) {
62  break;
63  }
64  entry = NULL;
65  }
66 
67  if (!entry) {
68  entry = malloc(sizeof(*entry));
69  if (!entry) {
70  free(item);
71  irq_local_restore(flags);
72  return -ENOMEM;
73  }
74 
75  entry->idx = idx;
76  entry->cnt = 0;
77  entry->max_priority = 0;
78  INIT_LIST_HEAD(&entry->list);
79 
80  list_add_tail(&entry->head, &s_list);
81  }
82 
83  entry->cnt++;
84  if (priority > entry->max_priority) {
85  entry->max_priority = priority;
86  }
87 
89  list_for_each(pos, &entry->list) {
90  tmp = list_entry(pos, struct irq_handler, head);
91 
92  if (tmp->priority >= priority) {
93  break;
94  }
95  }
96 
97  item->handler = handler;
98  item->priority = priority;
99  item->data = data;
100 
101  list_add_tail(&item->head, pos);
102  irq_local_restore(flags);
103  return 0;
104 }
105 
106 int unregister_irq(int idx, int (*handler)(int, void *, void *), void *data)
107 {
108  struct list_head *n;
109  struct list_head *pos;
110  struct list *entry;
111  struct irq_handler *item;
112  unsigned long flags;
113 
114  irq_local_save(&flags);
115  entry = NULL;
116  list_for_each_safe(pos, n, &s_list) {
117  entry = list_entry(pos, struct list, head);
118  if (entry->idx == idx) {
119  break;
120  }
121  entry = NULL;
122  }
123 
124  if (!entry) {
125  irq_local_restore(flags);
126  return -ENOENT;
127  }
128 
129  list_for_each_safe(pos, n, &entry->list) {
130  item = list_entry(pos, struct irq_handler, head);
131  if (item->handler == handler && item->data == data) {
132  entry->cnt--;
133 
134  list_del(&item->head);
135  free(item);
136 
137  if (!entry->cnt) {
138  list_del(&entry->head);
139  free(entry);
140  }
141  irq_local_restore(flags);
142  return 0;
143  }
144  }
145 
146  irq_local_restore(flags);
147  return -ENOENT;
148 }
149 
150 static inline struct thread *select_next_thread(struct thread *tcb)
151 {
152  struct x86_arch_data *arch_data;
153  struct list_head *n;
154  struct thread *it;
155  int status;
156 
157  it = tcb;
158  n = LIST_NEXT(&it->link);
159  while (1) {
160  it = list_entry(n, struct thread, link);
161  if (tcb == it) { /* 쓰레드가 하나 뿐 인 경우 */
162  break;
163  }
164 
165  n = LIST_NEXT(n); /* 다음 쓰레드를 찾아 놓고 */
166 
167  if (it->sem) { /* 세마포어가 있는 쓰레드는 스킵! */
168  continue;
169  }
170 
171  status = thread_get_status(it);
172  if (status == RUNNING) { /* 실행 중인 쓰레드를 선택 */
173  break;
174  }
175 
176  if (status == DELETED) {
177  pthread_cancel(it);
178  } else if (status == CREATED) {
179  } else if (status == READY) {
181  }
182  }
183 
184  arch_data = thread_get_arch_data(it);
185  assert(arch_data && "Arch data is not valid");
186 
187  if (x86_util_get_ring(it) == USER) {
188  unsigned long sp;
189  struct x86_user_data *user_data;
190  unsigned char *io_bitmap;
191 
198  sp = thread_get_stack_pointer(it);
199  user_data = thread_get_user_data(it);
200  assert(user_data && "User data is not valid");
201 
203  io_bitmap = tss_io_bitmap_get();
204  assert(io_bitmap && "I/O Bitmap is not valid");
205 
206  memcpy(io_bitmap, user_data->io_bitmap,
207  sizeof(user_data->io_bitmap));
208  }
209  load_cr3(arch_data->pma_pgd);
210 
211  return it;
212 }
213 
214 static inline void create_info(struct pt_regs *reg, struct intr_info *info)
215 {
216  if (reg->irq != IRQ_NR_SW) {
217  info->argc = 0;
218  info->argv = NULL;
219  info->irq = -1;
220  info->ret = -ENOSYS;
221  return;
222  }
223 
224  info->irq = reg->pushad.eax;
225  info->argc = reg->pushad.ecx;
226  if (info->argc) {
227  int size;
228 
229  size = sizeof(*info->argv) * info->argc;
230 
231  info->argv = malloc(size);
232  assert(info->argv);
233 
243  memcpy(info->argv, (void *)reg->pushad.esp, size);
244  } else {
245  info->argv = NULL;
246  }
247 
248  return;
249 }
250 
251 static inline void destroy_info(struct pt_regs *reg, struct intr_info *info)
252 {
253  if (reg->irq != IRQ_NR_SW) {
254  return;
255  }
256 
257  reg->pushad.eax = info->ret;
258 
259  if (info->argv) {
260  free(info->argv);
261  }
262 }
263 
264 asmlinkage struct pt_regs *do_irq(struct pt_regs *reg)
265 {
266  struct list_head *pos;
267  struct list *entry;
268  struct thread *tcb;
269 
270  tcb = (struct thread *)pthread_self();
271  if (!tcb) {
272  dbg_printf("[%s:%d]\n", __func__, __LINE__);
273  halt();
274  }
275 
276  tcb->esp = (uint32_t *)reg;
277 
278  list_for_each(pos, &s_list) {
279  entry = list_entry(pos, struct list, head);
280  if (entry->idx == reg->irq) {
281  break;
282  }
283 
284  entry = NULL;
285  }
286 
287  if (entry) {
288  struct intr_info info;
289  struct irq_handler *item;
290 
301  create_info(reg, &info);
302 
303  list_for_each(pos, &entry->list) {
304  item = list_entry(pos, struct irq_handler, head);
305  if (!item->handler) {
306  continue;
307  }
308 
309  info.ret = item->handler(info.irq, &info, item->data);
310  }
311 
312  destroy_info(reg, &info);
313  } else {
314  dbg_printf("[%s:%d] IRQ 0x%x has no handler\r",
315  __func__, __LINE__, reg->irq);
316  }
317 
318  tcb = select_next_thread(tcb);
319  if (!tcb) {
320  dbg_printf("[%s:%d]\n", __func__, __LINE__);
321  halt();
322  }
323 
324  reg = (struct pt_regs *)tcb->esp;
325  return reg;
326 }
327 
328 /* End of a file */