Updated documentation.
device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
+ /*
+ * ***********************
+ * Exception vectors
+ * ***********************
+ */
+ constants exc_vec width(8) "Exception vectors" {
+ vec_de = 0 "divide error";
+ vec_db = 1 "debug exception";
+ vec_nmi = 2 "non-maskable interrupt";
+ vec_bp = 3 "breakpoint";
+ vec_of = 4 "overflow";
+ vec_br = 5 "BOUND range exceeded";
+ vec_ud = 6 "invalid opcode";
+ vec_nm = 7 "device not available";
+
+ vec_df = 8 "double fault";
+ vec_cso = 9 "coprocessor segment overrun";
+ vec_ts = 10 "invalid TSS";
+ vec_np = 11 "segment not present";
+ vec_ss = 12 "stack fault";
+ vec_gp = 13 "general protection fault";
+ vec_pf = 14 "page fault";
+ // 15 reserved to intel
+
+ vec_mf = 16 "x87 FPU floating-point error";
+ vec_ac = 17 "alignment check";
+ vec_mc = 18 "machine check";
+ vec_xf = 19 "SIMD floating-point exception";
+ };
+
+ /*
+ * ***********************
+ * Address space for model-Specific registers
+ * ***********************
+ */
space msr(index) valuewise "Model-specific Registers";
+ /*
+ * ***********************
+ * Architectural MSRs
+ * ***********************
+ */
+
// 7.11.5
register mon_filter_size msr(0x06) "Monitor/Mwait filter size" type(uint64);
\usepackage{textcomp}
\usepackage{amsmath}
-\title{Mackerel 1.3 User Guide}
+\title{Mackerel 1.4 User Guide}
\author{Barrelfish project}
% \date{\today} % Uncomment (if needed) - date is automatic
\tnnumber{2}
\vhEntry{1.2}{31.05.2010}{TR}{Initial version under new formatting}
\vhEntry{1.3}{15.08.2011}{TR}{Added support for imports and new
command-line options}
+\vhEntry{1.4}{09.12.2011}{TR}{New mapping for constants}
\end{versionhistory}
% \intro{Abstract} % Insert abstract here
\begin{enumerate}
-\item An enumeration type \texttt{DP\_CNSTS\_t} with fields
- \texttt{DP\_FIELD1} and \texttt{DP\_FIELD2}. Note that the field
- names are not prefixed by the enumeration name, only the device
- prefix.
-
-\item An \texttt{snprintf}-like function to pretty-print values of the
- enumeration, with prototype:
+\item A type definition which defines type \texttt{DP\_CNSTS\_t} to be
+ an unsigned integer type (e.g.\ \texttt{uint8\_t} or
+ \texttt{uint64\_t}). The type is the smallest such type large
+ enough to hold the largest value in the constants declaration, or
+ (if the width is explicitly given) the smallest such type wider than
+ the given width.
+
+\item A set of CPP macro definitions \texttt{DP\_FIELD1} and
+ \texttt{DP\_FIELD2}, each of which expands to a C expression
+ consisting of the field value cast to type \texttt{DP\_CNSTS\_t}.
+
+ If the field value is specified as \texttt{1s}, the macro will
+ expand to the C value \texttt{-1LL} cast to type
+ \texttt{DP\_CNSTS\_t}.
+
+ Note that the field names are not prefixed by the constants name,
+ only the device prefix.
+
+ The motivation for using CPP macros (rather than C enumerations, as
+ in an earlier version of Mackerel) is that \texttt{enum} types are
+ only the size of C \texttt{int}s, whereas Mackerel can specify
+ values in \texttt{constants} declarations which are larger than
+ this (such as 64-bit values).
+
+ The motivation for not using constant unsigned integer declarations
+ is that macros allow us to only generate a header file, without
+ cluttering up the data segment with multiple copies of constants if
+ the generated header file is included more than once.
+
+\item A function which takes an argument of type \texttt{DP\_CNSTS\_t}
+ and returns a pointer to a string containing the description of the
+ field value, or NULL if the argument does not correspond to a field
+ value:
\begin{quote}
- \texttt{int DP\_CNSTS\_prtval(char *s, size\_t sz, DP\_CNSTS\_t e);}
+ \texttt{int DP\_CNSTS\_describe(DP\_CNSTS\_t e);}
\end{quote}
-
-\item A function which returns 1 if an enumeration value is valid, 0
- if otherwise:
+ Note that this function can also simply be used as a test of whether
+ the value is valid.
+
+\item An \texttt{snprintf}-like function to pretty-print values of
+ type \texttt{DP\_CNSTS\_t}, with prototype:
\begin{quote}
- \texttt{int DP\_CNSTS\_chk(DP\_CNSTS\_t e);}
+ \texttt{int DP\_CNSTS\_prtval(char *s, size\_t sz, DP\_CNSTS\_t e);}
\end{quote}
\end{enumerate}
find the relevant declarations quickly if you need to.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\chapter{Migrating from bit-field based version of Mackerel}\label{chap:migrating}
+\chapter{Migrating from the bit-field based version of Mackerel}
+\label{chap:migrating}
Previous versions of Mackerel generated a C API by defining packed C
bitfield structs for register types. This version of Mackerel avoids
-this in favour of masks and shifts, hidden behind inline functions.
+this in favor of masks and shifts, hidden behind inline functions.
This chapter gives some hints for migrating code written using the old
Mackerel to the new version.
\begin{description}
-\item[Main.hs] Top level file, which is used to run \Mac.
-\item[MackerelParser.hs] ParSec parser for language.
+\item[Attr.hs] Dealing with register field attributes.
+\item[BitFieldDriver.hs] Old code generator for device drivers using
+ bitfields, deprecated.
\item[CAbsSyntax.hs] Contains combinators for rendering C code.
+\item[CSyntax.hs] Old-style C combinators, deprecated.
\item[Checks.hs] Compile-time checks.
-\item[ConstTable.hs] Constants definitions.
\item[Dev.hs] Overall device representation.
\item[Fields.hs] Representing register fields.
-\item[Attr.hs] Dealing with register field attributes.
-\item[RegisterTable.hs] Representing registers and register arrays.
-\item[ShiftDriver.hs] Code generator for device drivers using shifts
- and masks.
-\item[Space.hs] Representing address spaces.
-\item[TypeTable.hs] Representing register types.
-\item[CSyntax.hs] Old-style C combinators, deprecated.
-\item[BitFieldDriver.hs] Old code generator for device drivers using
- bitfields, deprecated.
+\item[MackerelParser.hs] ParSec parser for language.
+\item[Main.hs] Top level file, which is used to run \Mac.
\item[Poly.hs] Polynomial arithmetic for compile-time expression
reduction (currently unused)
+\item[RegisterTable.hs] Representing registers and register arrays.
+\item[ShiftDriver.hs] Code generator for device drivers using shifts and masks.
+\item[Space.hs] Representing address spaces.
+\item[TypeName.hs] Data type for scoping type names when importing.
+\item[TypeTable.hs] Representing register, data, and constants types.
\end{description}
\end{document}
#include <arch/x86/ipi_notify.h>
#include <barrelfish_kpi/cpu_arch.h>
+#include <dev/ia32_dev.h>
+
#ifdef FPU_LAZY_CONTEXT_SWITCH
# include <fpu.h>
#endif
}
}
-
-static const char *exception_names[32] = {
- "#DE: divide error",
- "#DB: debug exception",
- "NMI: non-maskable interrupt",
- "#BP: breakpoint",
- "#OF: overflow",
- "#BR: BOUND range exceeded",
- "#UD: invalid opcode",
- "#NM: device not available",
-
- "#DF: double fault",
- "CSO: coprocessor segment overrun",
- "#TS: invalid TSS",
- "#NP: segment not present",
- "#SS: stack fault",
- "#GP: general protection fault",
- "#PF: page fault",
- "<reserved to intel",
-
- "#MF: x87 FPU floating-point error",
- "#AC: alignment check",
- "#MC: machine check",
- "#XF: SIMD floating-point exception",
- "<reserved to intel",
- "<reserved to intel",
- "<reserved to intel",
- "<reserved to intel"
-};
-
/**
* \brief Handles kernel exceptions
*
uintptr_t *gdb_save_frame)
{
lvaddr_t fault_address;
+ char *descr;
if (vec == 666) {
panic("unhandled kernel exception (vector 666)");
assert(vec < NEXCEPTIONS);
printk(LOG_PANIC, "exception %d (error code 0x%lx): ", (int)vec, error);
-
- switch(vec) {
- case 0: // Divide Error (#DE)
- case 1: // Debug Exception (#DB)
- case 2: // NMI Interrupt
- case 3: // Breakpoint (#BP)
- case 4: // Overflow (#OF)
- case 5: // BOUND Range Exceeded (#BR)
- case 6: // Invalid Opcode (#UD)
- case 7: // Device Not Available (#NM)
- case 8: // Double fault (#DF)
- case 9: // Coprocessor Segment Overrun
- case 10: // Invalid TSS (#TS)
- case 11: // Segment Not Present (#NP)
- case 12: // Stack Fault (#SS)
- case 13: // General Protection Fault (#GP)
- case 17: // Alignment Check Exception (#AC)
- case 18: // Machine check (#MC)
- printf("%s\n", exception_names[vec]);
- break;
-
- case 14: // Page Fault (#PF)
+
+ if (vec == ia32_vec_pf) {
printf("%s page fault due to %s%s, while in %s mode%s\n",
error & ERR_PF_READ_WRITE ? "write" : "read",
error & ERR_PF_PRESENT ? "access violation" : "page not present",
__asm volatile("mov %%cr2, %[fault_address]"
: [fault_address] "=r" (fault_address));
printf("Address that caused the fault: 0x%lx\n", fault_address);
- break;
- default:
+ } else if ((descr = ia32_exc_vec_describe(vec))) {
+ printf("%s\n", descr);
+ } else {
printf("unhandled exception!\n");
- break;
}
// Print faulting instruction pointer
constants_print_fn_name :: TN.Name -> String
constants_print_fn_name c = qual_typename c ["prtval"]
-constants_check_fn_name :: TT.Rec -> String
-constants_check_fn_name c = qual_typerec c ["chk" ]
+constants_describe_fn_name :: TT.Rec -> String
+constants_describe_fn_name c = qual_typerec c ["describe" ]
--
-- Register and datatype-related names
constants_decl :: TT.Rec -> [ C.Unit ]
constants_decl c =
- [ constants_comment c,
- constants_enum c,
- constants_typedef c,
- constants_print_fn c,
- constants_check_fn c ]
+ [ constants_comment c,
+ constants_typedef c ] ++
+ ( constants_enum c ) ++
+ [ C.Blank,
+ constants_describe_fn c,
+ constants_print_fn c ]
constants_c_type :: TT.Rec -> C.TypeSpec
constants_c_type c = C.TypeName $ constants_c_name c
Nothing -> " - no width specified"
Just w -> printf " - width %d bits" w ]
-constants_enum :: TT.Rec -> C.Unit
+constants_enum :: TT.Rec -> [ C.Unit ]
constants_enum c =
- let n = constants_c_name c
- in
- C.EnumDecl n [ C.EnumItem (constants_elem_c_name v)
- (Just $ C.HexConstant $ constants_eval $ TT.cval v) | v <- TT.tt_vals c ]
+ [ C.Define (constants_elem_c_name v) [] (constants_eval c v) | v <- TT.tt_vals c ]
constants_typedef :: TT.Rec -> C.Unit
constants_typedef c =
- let n = constants_c_name c
- in C.TypeDef (C.Enum n) n
+ C.TypeDef (C.TypeName $ round_field_size $ TT.tt_size c) (constants_c_name c)
-
--- XXX
-constants_eval (ExprConstant (-1)) = 0xffffffff
-constants_eval (ExprConstant i) = i
+constants_eval :: TT.Rec -> TT.Val -> String
+constants_eval c v =
+ printf "((%s)%s)" (constants_c_name c) (case TT.cval v of
+ ExprConstant (-1) -> "(-1LL)"
+ ExprConstant i -> printf "0x%x" i
+ )
constants_print_fn :: TT.Rec -> C.Unit
constants_print_fn c =
[ C.Param (C.Ptr $ C.TypeName "char") cv_s,
C.Param (C.TypeName "size_t") cv_size,
C.Param (constants_c_type c) cv_e ]
- [ C.Switch (C.Variable cv_e)
- [ C.Case (C.Variable $ constants_elem_c_name v)
- [ C.Return $ C.Call "snprintf"
- [ C.Variable cv_s,
- C.Variable cv_size,
- C.StringConstant "%s",
- C.StringConstant $ TT.cdesc v ]
- ] | v <- TT.tt_vals c ]
- [ C.Return $ C.Call "snprintf"
- [ C.Variable cv_s,
- C.Variable cv_size,
- C.StringConstant "Unknown constant %s value 0x%x",
- C.StringConstant (constants_c_name c),
- C.Variable cv_e ]
- ]
+ [ C.VarDecl C.NoScope C.NonConst (C.Ptr $ C.TypeName "char") "d"
+ (Just $ C.Call (constants_describe_fn_name c) [ C.Variable cv_e ]),
+ C.If (C.Variable "d")
+ [ C.Return $ C.Call "snprintf"
+ [ C.Variable cv_s,
+ C.Variable cv_size,
+ C.StringConstant "%s",
+ C.Variable "d"
+ ]
+ ]
+ [ C.Return $ C.Call "snprintf"
+ [ C.Variable cv_s,
+ C.Variable cv_size,
+ C.StringConstant "Unknown constant %s value 0x%lx",
+ C.StringConstant (constants_c_name c),
+ C.Cast (C.TypeName "uint64_t") (C.Variable cv_e)
]
+ ]
+ ]
+
+constants_describe_fn :: TT.Rec -> C.Unit
+constants_describe_fn c =
+ let
+ rep v = C.StringConstant $ printf "%s: %s" (TT.cname v) (TT.cdesc v)
+ in
+ C.StaticInline (C.Ptr $ C.TypeName "char") (constants_describe_fn_name c)
+ [ C.Param (constants_c_type c) cv_e ]
+ [ C.Switch (C.Variable cv_e)
+ [ C.Case (C.Variable $ constants_elem_c_name v)
+ [ C.Return $ rep v ]
+ | v <- TT.tt_vals c ]
+ [ C.Return $ C.Variable "NULL" ]
+ ]
-constants_check_fn :: TT.Rec -> C.Unit
-constants_check_fn c =
- C.StaticInline (C.TypeName "int") (constants_check_fn_name c)
- [ C.Param (constants_c_type c) cv_e ]
- [ C.Switch (C.Variable cv_e)
- [ C.Case (C.Variable $ constants_elem_c_name v)
- [ C.Return $ C.NumConstant 1 ]
- | v <- TT.tt_vals c ]
- [ C.Return $ C.NumConstant 0 ]
- ]
-------------------------------------------------------------------------
-- Render register type definitions
pos = p } ]
make_rtrec (Constants nm d vs w p) dev devorder =
let tn = TN.fromParts dev nm
+ vl = [ make_val tn v | v <- vs ]
in
[ ConstType { tt_name = tn,
tt_size = case w of
- Nothing -> (-1)
+ Nothing -> calc_const_size vl
Just t -> t,
- tt_vals = [ make_val tn v | v <- vs ],
+ tt_vals = vl,
tt_desc = d,
tt_width = w,
pos = p } ]
make_rtrec _ _ _ = []
+calc_const_size :: [Val] -> Integer
+calc_const_size vs =
+ let m = maximum [ i | t@Val { cval = (ExprConstant i) } <- vs ]
+ in
+ if m <= 0xff then 8
+ else if m <= 0xffff then 16
+ else if m <= 0xffffffff then 32
+ else 64
+
-- Building constant lists
make_val :: TN.Name -> AST -> Val
make_val tn (ConstVal i e d p)