Fixed long-standing 64-bit constants bug, by dropping C enumerations in favor of...
authorMothy <troscoe@inf.ethz.ch>
Fri, 9 Dec 2011 16:53:58 +0000 (17:53 +0100)
committerMothy <troscoe@inf.ethz.ch>
Fri, 9 Dec 2011 16:53:58 +0000 (17:53 +0100)
Updated documentation.

devices/ia32.dev
doc/002-mackerel/Mackerel.tex
kernel/arch/x86_64/irq.c
tools/mackerel/ShiftDriver.hs
tools/mackerel/TypeTable.hs

index 7e9810f..2a841d2 100644 (file)
 
 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);
     
index 938ea99..f6de042 100644 (file)
@@ -16,7 +16,7 @@
 \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}
@@ -29,6 +29,7 @@
 \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
@@ -1031,21 +1032,49 @@ For a constants declaration of type \texttt{CNSTS}, having fields
 
 \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}
@@ -1739,11 +1768,12 @@ In addition, comments in the generated file are intended to help you
 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. 
 
@@ -1836,24 +1866,23 @@ The \Mac source directory contains the files listed below.
 
 \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}
index 2cbf0c4..7773f3b 100644 (file)
@@ -66,6 +66,8 @@
 #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
@@ -491,36 +493,6 @@ errval_t irq_table_delete(unsigned int nidt)
     }
 }
 
-
-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
  *
@@ -533,6 +505,7 @@ static __attribute__ ((used,noreturn))
                                          uintptr_t *gdb_save_frame)
 {
     lvaddr_t fault_address;
+    char *descr;
 
     if (vec == 666) {
         panic("unhandled kernel exception (vector 666)");
@@ -541,28 +514,8 @@ static __attribute__ ((used,noreturn))
     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",
@@ -574,11 +527,11 @@ static __attribute__ ((used,noreturn))
         __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
index 9a34b3e..46620d0 100644 (file)
@@ -94,8 +94,8 @@ constants_elem_c_name v = qual_device (TT.ctype v) [ TT.cname v ]
 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
@@ -550,11 +550,12 @@ device_space_includes d header
 
 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 
@@ -566,22 +567,20 @@ constants_comment 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 = 
@@ -589,33 +588,40 @@ 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
index 3c09069..a776126 100644 (file)
@@ -124,17 +124,27 @@ make_rtrec (DataType nm dsc (TypeDefn decls) o w p) dev devorder =
                      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)