NOVA
Stripped down NOVA kernel for the OSY course
Loading...
Searching...
No Matches
Ec Class Reference

Public Member Functions

ALWAYS_INLINE NORETURN void make_current ()

Static Public Member Functions

HOT static NORETURN void ret_user_sysexit ()
static NORETURN void ret_user_iret () asm("ret_user_iret")
static NORETURN void idle ()
static void root_setup (mword)
HOT NORETURN static REGPARM_1 void syscall_handler (uint8 a) asm("syscall_handler")
 System call handler.
static ALWAYS_INLINE void * operator new (size_t)
static ALWAYS_INLINE void operator delete (void *)

Public Attributes

Ecnext

Static Public Attributes

static Eccurrent

Constructor & Destructor Documentation

◆ Ec()

Ec::Ec ( )
34{
35 regs.cs = SEL_USER_CODE;
36 regs.ds = SEL_USER_DATA;
37 regs.es = SEL_USER_DATA;
38 regs.ss = SEL_USER_DATA;
39 regs.efl = 0x200; // IF = 1
40}

Member Function Documentation

◆ idle()

void Ec::idle ( )
static
69{
70 for (;;)
71
72 UNREACHED;
73}

◆ make_current()

ALWAYS_INLINE NORETURN void Ec::make_current ( )
inline
60 {
61 current = this;
62 Tss::run.sp0 = reinterpret_cast<mword>(exc_regs() + 1);
63 Ec::ret_user_sysexit();
64 UNREACHED; // Tell the compiler to not generate function epilog
65 }

◆ operator delete()

ALWAYS_INLINE void Ec::operator delete ( void * )
inlinestatic
85{ /* nop */ }

◆ operator new()

ALWAYS_INLINE void * Ec::operator new ( size_t )
inlinestatic
82{ return Kalloc::allocator.alloc(sizeof (Ec)); }

◆ ret_user_iret()

void Ec::ret_user_iret ( )
static
54{
55 asm volatile ("lea %0, %%esp;" // Load address of current->regs
56 "popa;" // Restore all generic registers from there
57 "pop %%gs;" // Restore segment registers
58 "pop %%fs;"
59 "pop %%es;"
60 "pop %%ds;"
61 "add $8, %%esp;" // Skip Exc_regs::err and vec
62 "iret" // Return (restore %cs, %eip, %eflags)
63 : : "m" (current->regs) : "memory");
64
65 UNREACHED;
66}

◆ ret_user_sysexit()

void Ec::ret_user_sysexit ( )
static
43{
44 asm volatile ("lea %0, %%esp;" // Load address of current->regs
45 "popa;" // Restore all registers from there
46 "sti;" // Enable interrupts
47 "sysexit"
48 : : "m" (current->regs) : "memory");
49
50 UNREACHED;
51}

◆ root_setup()

void Ec::root_setup ( mword mbi_addr)
static
76{
77 // Bootloader passed us the "Multiboot information" data
78 // structure. Among other things, it contains the physical address
79 // of the user space application we want to execute.
80
81 // To access the data at physical address, we have to "map" them
82 // to virtual memory. Ptab::remap() creates a temporary mapping of
83 // one 4 MB page.
84 Multiboot * mbi = static_cast<Multiboot *>(Ptab::remap (mbi_addr));
85
86 if (!(mbi->flags & Multiboot::MODULES) || (mbi->mods_count < 1))
87 panic ("No multiboot modules\n");
88
89 // Copy module desciptor to local variable
90 Multiboot_module mod = *static_cast<Multiboot_module *>(Ptab::remap (mbi->mods_addr));
91
92 // Get ELF header from the binary
93 Eh *eh = static_cast<Eh *>(Ptab::remap(mod.mod_start));
94 if (eh->ei_magic != 0x464c457f || eh->ei_class != 1 || eh->ei_data != 1 || eh->type != 2 || eh->machine != 3)
95 panic ("No ELF");
96
97 current->regs.edx = eh->entry; // Initial eip (why edx? see sysexit instruction)
98
99 unsigned count = eh->ph_count;
100
101 Ph *ph = static_cast<Ph *>(Ptab::remap(mod.mod_start + eh->ph_offset));
102
103 for (unsigned i = 0; i < count; i++, ph++) {
104
105 if (ph->type == Ph::PT_LOAD) {
106
107 if (ph->f_size > ph->m_size || ph->v_addr % PAGE_SIZE != ph->f_offs % PAGE_SIZE)
108 panic ("Bad ELF");
109
110 mword attr;
111 if (ph->flags & Ph::PF_W)
112 attr = Ptab::PRESENT | Ptab::USER | Ptab::RW;
113 else
114 attr = Ptab::PRESENT | Ptab::USER;
115
116 mword virt = align_dn(ph->v_addr, PAGE_SIZE);
117 mword phys = align_dn(ph->f_offs + mod.mod_start, PAGE_SIZE);
118 mword fsize = align_up(ph->v_addr % PAGE_SIZE + ph->f_size, PAGE_SIZE);
119 mword msize = align_up(ph->v_addr % PAGE_SIZE + ph->m_size, PAGE_SIZE);
120
121 while (msize > 0) {
122 if (fsize == 0) {
123 void *page = Kalloc::allocator.alloc_page (1, Kalloc::FILL_0);
124 if (!page)
125 panic ("Not enough memory\n");
126 phys = Kalloc::virt2phys (page);
127 }
128 if (!Ptab::insert_mapping(virt, phys, attr))
129 panic ("Not enough memory\n");
130 phys += PAGE_SIZE;
131 virt += PAGE_SIZE;
132 msize -= PAGE_SIZE;
133 fsize -= fsize ? PAGE_SIZE : 0;
134 }
135
136 // Zero .bss
137 if ((ph->m_size > ph->f_size) && (attr & Ptab::RW))
138 memset(reinterpret_cast<void*>(ph->v_addr + ph->f_size),
139 0x00, ph->m_size - ph->f_size);
140
141 Ec::break_min = Ec::break_current = virt;
142 }
143 }
144
145 // Allocate one page of memory for user space stack
146 void *stack = Kalloc::allocator.alloc_page (1, Kalloc::FILL_0);
147 if (!stack)
148 panic ("Not enough memory\n");
149
150 // Map the stack page at address below 0xc0000000 (starting at 0xbffff000)
151 if (!Ptab::insert_mapping (0xbffff000, Kalloc::virt2phys (stack),
152 Ptab::PRESENT | Ptab::RW | Ptab::USER))
153 panic ("Not enough memory\n");
154
155 current->regs.ecx = 0xc0000000; // Initial esp (why ecx? see sysexit instruction)
156
157 current->next = current;
158}
static mword virt2phys(void *)
Return the physical address that is mapped from the virtual address virt (opposite of phys2virt).
Definition kalloc.cc:98
void * alloc_page(unsigned count, Fill fill=NOFILL)
Allocate count virtually contiguous pages and optionally fill them with 0x00 or 0xFF.
Definition kalloc.cc:46
static void * remap(mword phys)
Maps the passed physical address to the fixed virtual address REMAP_SADDR as a single 4MB page.
Definition ptab.cc:65
static bool insert_mapping(mword virt, mword phys, mword attr)
Inserts a 4 KB mapping into the page table.
Definition ptab.cc:20

◆ syscall_handler()

void Ec::syscall_handler ( uint8 a)
static

System call handler.

Parameters
[in]aValue of the al register before the system call
17{
18 // Get access to registers stored during entering the system - see
19 // entry_sysenter in entry.S
20 Sys_regs * r = current->sys_regs();
21 Syscall_numbers number = static_cast<Syscall_numbers> (a);
22
23 switch (number) {
24 case sys_print: {
25 // Tisk řetězce na sériovou linku
26 char *data = reinterpret_cast<char*>(r->esi);
27 unsigned len = r->edi;
28 for (unsigned i = 0; i < len; i++)
29 printf("%c", data[i]);
30 break;
31 }
32 case sys_sum: {
33 // Naprosto nepotřebné systémové volání na sečtení dvou čísel
34 int first_number = r->esi;
35 int second_number = r->edi;
36 r->eax = first_number + second_number;
37 break;
38 }
39 // TODO: Add your system calls here
40 default:
41 printf ("unknown syscall %d\n", number);
42 break;
43 };
44
45 ret_user_sysexit();
46}

The documentation for this class was generated from the following files: