~cypheon/xos

ref: 666e83dc8928b3ec9831d91515bdb4d183e7d25f xos/kernel.c -rw-r--r-- 4.6 KiB
666e83dc — Johann Rudloff Add memory map detection in bootloader. 7 years ago
                                                                                
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
#define DEBUG

#include <sys/atpic.h>
#include <sys/console.h>
#include <sys/io.h>
#include <sys/kernel.h>
#include <sys/memory.h>
#include <sys/paging.h>
#include <sys/proc.h>
#include <sys/types.h>

#include <dev/blockdev.h>
#include <dev/ide.h>
#include <fs/ext2.h>
#include <kern/scheduler.h>

#include <stdlib.h>

#include <debug.h>

console_t global_console;

static inline void idle(void) {
  asm volatile ("hlt" : : );
}

struct gdt_entry {
  uint16_t limit_low;
  uint16_t base_low;
  uint8_t base_middle;
  uint8_t access;
  uint8_t flags;
  uint8_t base_high;
} __attribute__((__packed__));

struct gdt_desc {
  uint16_t limit;
  uint32_t addr;
} __attribute__((__packed__));

struct gdt_entry gdt[6];

static void setup_gdt(void);
static void setup_tss(void);

static struct proc *launch(const char *binary, uint32_t mem);

void kernel_main() {
  kprint("kernel main entered\n");
  console_init(&global_console);
  setup_gdt();

  kmem_init();
  paging_init();


  console_clear(&global_console);
  console_print(&global_console, "xos kernel loaded\n");

  setup_idt();

  struct proc *proc1 = launch("/init", 0x70000000);
  struct proc *proc2 = launch("/init2", 0x70000000);
  sched_add(proc1);
  sched_add(proc2);

  sched_run_next_proc();

  while(1){idle();};
}

static struct proc *launch(const char *binary, uint32_t mem) {
  struct blockdev *hda0 = ide_create_partition(IDE_CHANNEL_PRIMARY, IDE_DRIVE_MASTER, 0);

  ext2_mount *root = fs_mount_ext2(hda0);

  void *init_code = kmalloc_align(PAGE_SIZE, 4096);
  void *init_data2 = kmalloc_align(PAGE_SIZE, 4096);

  struct proc *p = proc_create();

  uint32_t in = fs_find(root, binary);
  ext2_inode init_file;
  fs_read_inode(root, in, &init_file);
  /*fs_inode_read_block(root, &init_file, 0, init_code);*/
  void *code_mapped = (void *)mem;
  void *code_mapped2 = (void *)(mem + PAGE_SIZE);
  pd_map_page(p->pd, code_mapped, init_code, PT_FLAG_USER | PT_FLAG_WRITABLE);
  pd_map_page(p->pd, code_mapped2, init_data2, PT_FLAG_USER | PT_FLAG_WRITABLE);
  fs_inode_read_block(root, &init_file, 0, init_code);

  *(p->pcb) = (struct pcb){
    .esp = mem + 2*PAGE_SIZE,
    .eip = (uint32_t)code_mapped,
    .eax = 42,
    .ebp = 0,
  };
  return p;
}

void panic(const char *msg) {
  kprint("\n\nPANIC\n=====\n\n");
  kprint(msg);

  console_print(&global_console, "\n\nPANIC\n=====\n\n");
  console_print(&global_console, msg);
  while(1) {};
}

static void setup_gdt(void) {
  gdt[0] = (struct gdt_entry){0};
  // kernel code
  gdt[1] = (struct gdt_entry){limit_low: 0xffff, base_low: 0, base_middle: 0, access: 0x9a, flags: 0xcf, base_high: 0};
  // kernel data
  gdt[2] = (struct gdt_entry){limit_low: 0xffff, base_low: 0, base_middle: 0, access: 0x92, flags: 0xcf, base_high: 0};
  // userspace code
  gdt[3] = (struct gdt_entry){limit_low: 0xffff, base_low: 0, base_middle: 0, access: 0xfa, flags: 0xcf, base_high: 0};
  // userspace data
  gdt[4] = (struct gdt_entry){limit_low: 0xffff, base_low: 0, base_middle: 0, access: 0xf2, flags: 0xcf, base_high: 0};
  // userspace tss
  gdt[5] = (struct gdt_entry){limit_low: 0xffff, base_low: 0, base_middle: 0, access: 0x92, flags: 0xcf, base_high: 0};

  struct gdt_desc gdt_load = {limit: 6 * 8, addr: (uint32_t)gdt};
  asm volatile (
      "lgdt %0\n"
      :
      : "m"(gdt_load)
      : "memory"
      );
  setup_tss();
}

struct tss_entry {
  uint32_t link;
  uint32_t esp0;
  uint32_t ss0;
  uint32_t pad[23];
} __attribute__((__packed__));

struct tss_entry userspace_tss;

static void setup_tss(void) {
  uint32_t base = (uint32_t)&userspace_tss;
  uint32_t limit = sizeof(userspace_tss);// + (uint32_t)&userspace_tss;
  gdt[5] = (struct gdt_entry){
             base_low: (base & 0xffff),
             base_middle: (base >> 16) & 0xff,
             base_high: (base >> 24) & 0xff,
             limit_low: (limit & 0xffff),
             access: 0xe9,
             flags: 0x00,
  };
  userspace_tss.esp0 = 0x200000 - 0x20000; // FIXME: this leaves 128k of regular kernel stack space
  userspace_tss.ss0 = 0x10;

  asm volatile (
      "mov $0x2b, %%ax\n"
      "ltr %%ax"
      :
      :
      : "eax"
      );
}

void syscall_entry(uint32_t syscall) {
  khexprint("syscall", syscall);
  khexprint("current esp", current->pcb->esp);
  khexprint("current eip", current->pcb->eip);
  if (syscall == 4) {
    uint32_t fd = *(uint32_t *)(current->pcb->esp + 4);
    void *buf = *(void **)(current->pcb->esp + 8);
    uint32_t len = *(uint32_t *)(current->pcb->esp + 12);
    khexprint("fd", fd);
    khexprint("buf", (uint32_t)buf);
    khexprint("len", len);
    char msg[128];
    memcpy(msg, buf, len);
    msg[len] = '\0';
    console_print(&global_console, msg);
  }

  sched_run_next_proc();
}