summaryrefslogtreecommitdiff
path: root/src/kernel/arch/amd64/regs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/arch/amd64/regs.c')
-rw-r--r--src/kernel/arch/amd64/regs.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/src/kernel/arch/amd64/regs.c b/src/kernel/arch/amd64/regs.c
new file mode 100644
index 0000000..bb4e5aa
--- /dev/null
+++ b/src/kernel/arch/amd64/regs.c
@@ -0,0 +1,26 @@
+#include <kernel/arch/generic.h>
+#include <kernel/panic.h>
+
+void
+regs_safecopy(UserRegs *dst, const UserRegs *src)
+{
+ /* preserved flags: (see intel vol 1 3.4.3.)
+ * 1<<0 = CF, carry flag
+ * 1<<2 = PF, parity flag
+ * 1<<4 = AC, auxilary carry
+ * 1<<6 = ZF, zero flag
+ * 1<<7 = SF, sign flag
+ * 1<<11 = OF, overflow flag
+ * 1<<10 = DF, direction flag
+ */
+ static_assert(
+ ((1<<0) | (1<<2) | (1<<4) | (1<<6) | (1<<7) | (1<<10) | (1<<11))
+ == 0xCD5
+ );
+
+ uint64_t newflags = (src->flags & 0xCD5) | (dst->flags & ~0xCD5);
+ /* I "spelled it out" directly instead of using memcpy hoping that gcc
+ * maybe would notice it can skip copying the last 8 bytes. It didn't :( */
+ *dst = *src;
+ dst->flags = newflags;
+}