MonkOS  v0.1
A simple 64-bit operating system (x86_64)
shell.c
Go to the documentation of this file.
1 //============================================================================
2 /// @file shell.c
3 /// @brief Simple kernel shell for testing purposes.
4 //
5 // Copyright 2016 Brett Vickers.
6 // Use of this source code is governed by a BSD-style license that can
7 // be found in the MonkOS LICENSE file.
8 //============================================================================
9 
10 #include <core.h>
11 #include <libc/stdio.h>
12 #include <libc/stdlib.h>
13 #include <libc/string.h>
14 #include <kernel/device/pci.h>
15 #include <kernel/device/tty.h>
16 #include <kernel/device/keyboard.h>
17 #include <kernel/mem/acpi.h>
18 #include <kernel/mem/heap.h>
19 #include <kernel/mem/paging.h>
20 #include <kernel/x86/cpu.h>
21 
22 #define TTY_CONSOLE 0
23 
24 // Forward declarations
25 static void command_prompt();
26 static void command_run();
27 static void keycode_run();
28 static bool cmd_display_help();
29 static bool cmd_display_apic();
30 static bool cmd_display_pci();
31 static bool cmd_display_pcie();
32 static bool cmd_switch_to_keycodes();
33 static bool cmd_test_heap();
34 
35 /// Shell mode descriptor.
36 typedef struct mode
37 {
38  void (*start)();
39  void (*run)();
40  void (*stop)();
41 } mode_t;
42 
43 // Standard shell command mode
45 {
48  NULL
49 };
50 
51 // Keycode display mode
53 {
54  NULL,
56  NULL
57 };
58 
60 
61 static void
63 {
64  if (active_mode->stop != NULL)
65  active_mode->stop();
66 
67  active_mode = mode;
68 
69  if (active_mode->start != NULL)
70  active_mode->start();
71 }
72 
73 /// A command descriptor, describing each command accepted in command mode.
74 struct cmd
75 {
76  const char *str;
77  const char *help;
78  bool (*run)();
79 };
80 
81 static struct cmd commands[] =
82 {
83  { "?", NULL, cmd_display_help },
84  { "help", "Show this help text", cmd_display_help },
85  { "apic", "Show APIC configuration", cmd_display_apic },
86  { "pci", "Show PCI devices", cmd_display_pci },
87  { "pcie", "Show PCIexpress configuration", cmd_display_pcie },
88  { "kc", "Switch to keycode display mode", cmd_switch_to_keycodes },
89  { "heap", "Test heap allocation", cmd_test_heap },
90 };
91 
92 static int
93 cmp_cmds(const void *c1, const void *c2)
94 {
95  return strcmp(((const struct cmd *)c1)->str,
96  ((const struct cmd *)c2)->str);
97 }
98 
99 static bool
101 {
102  tty_print(TTY_CONSOLE, "Available commands:\n");
103  for (int i = 0; i < arrsize(commands); i++) {
104  if (commands[i].help == NULL)
105  continue;
106  tty_printf(TTY_CONSOLE, " %-8s %s\n",
107  commands[i].str, commands[i].help);
108  }
109  return true;
110 }
111 
112 static bool
114 {
115  const struct acpi_madt *madt = acpi_madt();
116  if (madt == NULL) {
117  tty_print(TTY_CONSOLE, "No ACPI MADT detected.\n");
118  return true;
119  }
120 
121  tty_printf(TTY_CONSOLE, "Local APIC addr: %#x\n", madt->ptr_local_apic);
122 
123  const struct acpi_madt_local_apic *local = NULL;
124  while ((local = acpi_next_local_apic(local)) != NULL) {
125  tty_printf(TTY_CONSOLE, "Local APIC id %u: %s\n",
126  local->apicid,
127  (local->flags & 1) ? "Usable" : "Unusable");
128  }
129 
130  const struct acpi_madt_io_apic *io = NULL;
131  while ((io = acpi_next_io_apic(io)) != NULL) {
132  tty_printf(TTY_CONSOLE, "I/O APIC id %u: Addr=%#x Base=%u\n",
133  io->apicid,
134  io->ptr_io_apic,
135  io->interrupt_base);
136  }
137 
138  const struct acpi_madt_iso *iso = NULL;
139  while ((iso = acpi_next_iso(iso)) != NULL) {
140  tty_printf(TTY_CONSOLE, "ISO irq=%-2u int=%-2u flags=0x%04x\n",
141  iso->source,
142  iso->interrupt,
143  iso->flags);
144  }
145 
146  return true;
147 }
148 
149 static bool
151 {
152  pci_init(); // Temporary
153  return true;
154 }
155 
156 static bool
158 {
159  const struct acpi_mcfg_addr *addr = acpi_next_mcfg_addr(NULL);
160  if (addr == NULL) {
161  tty_print(TTY_CONSOLE, "No PCIe configuration.\n");
162  return true;
163  }
164 
165  while (addr != NULL) {
166  tty_printf(TTY_CONSOLE, "PCIe addr=0x%08x grp=%-2u bus=%02x..%02x\n",
167  addr->base, addr->seg_group, addr->bus_start,
168  addr->bus_end);
169  addr = acpi_next_mcfg_addr(addr);
170  }
171 
172  return true;
173 }
174 
175 static bool
177 {
179  "Entering keycode mode. Hit Alt-Tab to exit.\n");
180  switch_mode(&mode_keycode);
181  return false;
182 }
183 
184 static bool
186 {
187  pagetable_t pt;
188  pagetable_create(&pt, (void *)0x8000000000, PAGE_SIZE * 1024);
189  pagetable_activate(&pt);
190 
191  struct heap *heap = heap_create(&pt, (void *)0x9000000000, 1024);
192  void *ptr1 = heap_alloc(heap, 128);
193  void *ptr2 = heap_alloc(heap, 0xff00);
194  void *ptr3 = heap_alloc(heap, 8);
195  heap_free(heap, ptr1);
196  heap_free(heap, ptr2);
197  heap_free(heap, ptr3);
198 
199  heap_destroy(heap);
200  pagetable_activate(NULL);
201  pagetable_destroy(&pt);
202  return true;
203 }
204 
205 static bool
206 command_exec(const char *cmd)
207 {
208  if (cmd[0] == 0)
209  return true;
210 
211  for (int i = 0; i < arrsize(commands); i++) {
212  if (!strcmp(commands[i].str, cmd))
213  return commands[i].run();
214  }
215 
216  tty_printf(TTY_CONSOLE, "Unknown command: %s\n", cmd);
217  return true;
218 }
219 
220 static void
222 {
223  tty_print(TTY_CONSOLE, "> ");
224 }
225 
226 static void
228 {
229  char cmd[256];
230  int cmdlen = 0;
231 
232  for (;;) {
233  halt();
234 
235  key_t key;
236  bool avail;
237  while ((avail = kb_getkey(&key)) != false) {
238 
239  // If a printable character was typed, append it to the command.
240  if (key.ch >= 32 && key.ch < 127) {
241  if (cmdlen < arrsize(cmd) - 1) {
242  cmd[cmdlen] = key.ch;
243  tty_printc(TTY_CONSOLE, cmd[cmdlen]);
244  cmdlen++;
245  }
246  }
247 
248  // Handle special keys (like enter, backspace).
249  else if (key.brk == KEYBRK_DOWN) {
250 
251  if (key.code == KEY_ENTER) {
252  tty_printc(TTY_CONSOLE, '\n');
253 
254  // Strip trailing whitespace.
255  while (cmdlen > 0 && cmd[cmdlen - 1] == ' ')
256  cmdlen--;
257  cmd[cmdlen] = 0;
258 
259  // Execute the command.
260  bool cont = command_exec(cmd);
261  cmdlen = 0;
262  if (cont)
263  command_prompt();
264  else
265  return;
266  }
267 
268  else if (key.code == KEY_BACKSPACE && cmdlen > 0) {
269  tty_printc(TTY_CONSOLE, '\b');
270  cmdlen--;
271  }
272 
273  }
274  }
275  }
276 }
277 
278 static void
280 {
281  for (;;) {
282  halt();
283 
284  key_t key;
285  bool avail;
286  while ((avail = kb_getkey(&key)) != false) {
287  if (key.ch) {
288  tty_printf(
289  TTY_CONSOLE,
290  "Keycode: \033[%c]%02x\033[-] meta=%02x '%c'\n",
291  key.brk == KEYBRK_UP ? 'e' : '2',
292  key.code,
293  key.meta,
294  key.ch);
295  }
296  else {
297  tty_printf(
298  TTY_CONSOLE,
299  "Keycode: \033[%c]%02x\033[-] meta=%02x\n",
300  key.brk == KEYBRK_UP ? 'e' : '2',
301  key.code,
302  key.meta);
303  }
304  if ((key.brk == KEYBRK_UP) && (key.meta & META_ALT) &&
305  (key.code == KEY_TAB)) {
306  switch_mode(&mode_command);
307  return;
308  }
309  }
310  }
311 }
312 
313 void
315 {
316  qsort(commands, arrsize(commands), sizeof(struct cmd), cmp_cmds);
317 
318  active_mode = &mode_command;
319  active_mode->start();
320  for (;;)
321  active_mode->run();
322 }
MADT I/O APIC entry.
Definition: acpi.h:168
bool kb_getkey(key_t *key)
Return the available next key from the keyboard&#39;s input buffer.
Definition: keyboard.c:318
#define KEYBRK_DOWN
Key-down break code.
Definition: keyboard.h:19
static mode_t mode_keycode
Definition: shell.c:52
int strcmp(const char *str1, const char *str2)
Compare two strings and return a value indicating their lexicographical order.
MADT local APIC entry.
Definition: acpi.h:155
uint32_t ptr_io_apic
I/O APIC address.
Definition: acpi.h:174
Advanced configuration and power interface (ACPI) tables.
String and memory operations.
uint8_t apicid
I/O APIC ID.
Definition: acpi.h:172
A command descriptor, describing each command accepted in command mode.
Definition: shell.c:74
static bool cmd_display_pcie()
Definition: shell.c:157
__forceinline void halt()
Definition: cpu_inl.h:146
uint8_t bus_end
End PCI bus number.
Definition: acpi.h:104
uint8_t ch
Character value, if valid.
Definition: keyboard.h:92
void pagetable_create(pagetable_t *pt, void *vaddr, uint64_t size)
Create a new page table that can be used to associate virtual addresses with physical addresses...
Definition: paging.c:364
static bool cmd_display_apic()
Definition: shell.c:113
static void command_run()
Definition: shell.c:227
Keyboard input routines.
uint32_t interrupt
Interrupt this soruce will signal.
Definition: acpi.h:188
Core include file.
uint32_t flags
Local APIC flags (bit 0 = usable)
Definition: acpi.h:161
Definition: heap.c:32
void pagetable_destroy(pagetable_t *pt)
Destroy a page table.
Definition: paging.c:383
void heap_free(heap_t *heap, void *ptr)
Free memory previously allocated with heap_alloc.
Definition: heap.c:319
const struct acpi_madt_local_apic * acpi_next_local_apic(const struct acpi_madt_local_apic *prev)
Return a pointer to the next Local APIC structure entry in the MADT table.
Definition: acpi.c:398
uint32_t ptr_local_apic
Local APIC address.
Definition: acpi.h:116
MCFG entry, one or more of which appears at the tail of the acpi_mcfg struct.
Definition: acpi.h:99
#define TTY_CONSOLE
Definition: shell.c:22
void pagetable_activate(pagetable_t *pt)
Activate a page table on the CPU, so all virtual memory operations are performed relative to the page...
Definition: paging.c:403
static bool cmd_test_heap()
Definition: shell.c:185
static struct cmd commands[]
Definition: shell.c:81
uint16_t seg_group
PCI segment group number.
Definition: acpi.h:102
A simple heap memory manager.
A pagetable structure.
Definition: paging.h:66
const char * str
Definition: shell.c:76
void(* stop)()
Definition: shell.c:40
static bool command_exec(const char *cmd)
Definition: shell.c:206
static void command_prompt()
Definition: shell.c:221
static int cmp_cmds(const void *c1, const void *c2)
Definition: shell.c:93
void(* start)()
Definition: shell.c:38
Paged memory management.
void kshell()
Definition: shell.c:314
#define KEYBRK_UP
Key-up break code.
Definition: keyboard.h:20
PCI controller.
uint8_t apicid
Local APIC ID.
Definition: acpi.h:160
uint8_t source
Bus-relative source (IRQ)
Definition: acpi.h:187
#define PAGE_SIZE
Definition: paging.h:15
const struct acpi_mcfg_addr * acpi_next_mcfg_addr(const struct acpi_mcfg_addr *prev)
Return a pointer to the next Mapped Configuration (MCFG) address entry, used for PCIe.
Definition: acpi.c:419
void pci_init()
Definition: pci.c:134
void(* run)()
Definition: shell.c:39
const char * help
Definition: shell.c:77
x86 CPU-specific function implementations.
void * heap_alloc(heap_t *heap, uint64_t size)
Allocate memory from a heap.
Definition: heap.c:239
void tty_print(int id, const char *str)
Output a null-terminated string to the virtual console using the console&#39;s current text color and scr...
Definition: tty.c:343
heap_t * heap_create(pagetable_t *pt, void *vaddr, uint64_t maxpages)
Create a new heap from which to allocate virtual memory.
Definition: heap.c:61
MADT Interrupt Source Override (ISO) entry.
Definition: acpi.h:182
static bool cmd_display_help()
Definition: shell.c:100
const struct acpi_madt * acpi_madt()
Return a pointer to the ACPI multiple APIC description table (MADT).
Definition: acpi.c:364
const struct acpi_madt_io_apic * acpi_next_io_apic(const struct acpi_madt_io_apic *prev)
Return a pointer to the next I/O APIC structure entry in the MADT table.
Definition: acpi.c:405
static mode_t mode_command
Definition: shell.c:44
Standard i/o library.
void qsort(void *base, size_t num, size_t size, sortcmp cmp)
Sort the elements of an array using a sort comparison function.
static bool cmd_switch_to_keycodes()
Definition: shell.c:176
Shell mode descriptor.
Definition: shell.c:36
Multiple APIC description table (MADT).
Definition: acpi.h:112
void heap_destroy(heap_t *heap)
Destroy a heap, returning its memory to page table.
Definition: heap.c:90
uint16_t flags
MPS INTI flags.
Definition: acpi.h:189
int tty_printf(int id, const char *format,...)
Output a printf-formatted string to the virtual console using the console&#39;s current text color and sc...
Definition: tty.c:372
uint64_t base
Base address of configuration mechanism.
Definition: acpi.h:101
Teletype (console) screen text manipulation routines.
const struct acpi_madt_iso * acpi_next_iso(const struct acpi_madt_iso *prev)
Return a pointer to the next Interrupt Source Override (ISO) structure entry in the MADT table...
Definition: acpi.c:412
General utilities library.
#define META_ALT
Set while the alt key is pressed.
Definition: keyboard.h:25
uint32_t interrupt_base
Interrupt # where interrupts start.
Definition: acpi.h:175
static void switch_mode(mode_t *mode)
Definition: shell.c:62
#define arrsize(x)
Return the number of elements in the C array.
Definition: core.h:26
static mode_t * active_mode
Definition: shell.c:59
static void keycode_run()
Definition: shell.c:279
void tty_printc(int id, char ch)
Output a single character to the virtual console using the console&#39;s current text color and screen po...
Definition: tty.c:357
static bool cmd_display_pci()
Definition: shell.c:150
A record representing the state of the keyboard at the time a key was presssed or unpressed...
Definition: keyboard.h:87
uint8_t bus_start
Start PCI bus number.
Definition: acpi.h:103