#include "arch/kernel/cpu/segment_register.hpp" #include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" #include "arch/exception_handling/assert.hpp" namespace teachos::arch::kernel::cpu { auto reload_data_segment_registers() -> void { asm volatile("xor %%rax, %%rax\n" "mov %%rax, %%ss\n" "mov %%rax, %%ds\n" "mov %%rax, %%es\n" "mov %%rax, %%fs\n" "mov %%rax, %%gs\n" : /* no output from call */ : /* no input to call */ : "rax"); } auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void { asm volatile("xor %%rax, %%rax\n" "mov %[input], %%ax\n" "mov %%rax, %%ds\n" "mov %%rax, %%es\n" "mov %%rax, %%fs\n" "mov %%rax, %%gs\n" : /* no output from call */ : [input] "m"(data_segment) : "rax"); } auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector { context_switching::interrupt_descriptor_table::segment_selector current_value{}; asm volatile("mov %%cs, %[output]" : [output] "=r"(current_value)); return current_value; } auto validate_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void { context_switching::interrupt_descriptor_table::segment_selector ss{}; context_switching::interrupt_descriptor_table::segment_selector ds{}; context_switching::interrupt_descriptor_table::segment_selector es{}; context_switching::interrupt_descriptor_table::segment_selector fs{}; context_switching::interrupt_descriptor_table::segment_selector gs{}; asm volatile( "mov %%ss, %[ss_output]\n" "mov %%ds, %[ds_output]\n" "mov %%es, %[es_output]\n" "mov %%fs, %[fs_output]\n" "mov %%gs, %[gs_output]\n" : [ss_output] "=r"(ss), [ds_output] "=r"(ds), [es_output] "=r"(es), [fs_output] "=r"(fs), [gs_output] "=r"(gs)); auto result = (ss == ds && ss == es && ss == fs && ss == gs); exception_handling::assert(result, "[Segment Register] Values in data register are not the same."); result = (ss == data_segment); exception_handling::assert( result, "[Segment Register] Expected Data Segment is not the same as the value in the Stack Segment register."); } auto validate_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector code_segment) -> void { auto const cs = read_code_segment_register(); exception_handling::assert( cs == code_segment, "[Segment Register] Expected Code Segment is not the same as the value in the Code Segment register."); } auto validate_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment, context_switching::interrupt_descriptor_table::segment_selector code_segment) -> void { validate_data_segment_registers(data_segment); validate_code_segment_register(code_segment); } auto set_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector data_segment, context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) -> void { asm volatile("mov %%rsp, %%rax\n" "push %[data_segment]\n" "push %%rax\n" "pushfq\n" "push %[code_segment]\n" "mov %[return_function], %%rax\n" "push %%rax\n" "iretq\n" : /* no output from call */ : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) : "rax"); } } // namespace teachos::arch::kernel::cpu