SMBIOS Library
checksum.cpp
Go to the documentation of this file.
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=c:cindent:textwidth=0:
3  *
4  * Copyright (C) 2005 Dell Inc.
5  * by Michael Brown <Michael_E_Brown@dell.com>
6  * Licensed under the Open Software License version 2.1
7  *
8  * Alternatively, you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published
10  * by the Free Software Foundation; either version 2 of the License,
11  * or (at your option) any later version.
12 
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  */
18 
19 // compat header should always be first header if including system headers
20 #define LIBSMBIOS_SOURCE
21 #include "smbios/compat.h"
22 
23 #include <sstream>
24 
25 #include "CmosRWImpl.h"
26 #include "TokenImpl.h"
27 
28 // message.h should be included last.
29 #include "smbios/message.h"
30 
31 using namespace std;
32 using namespace cmos;
33 
34 namespace smbios
35 {
36  static u8 byteChecksum(
37  const ICmosRW *cmos, u32 start, u32 end,
38  u32 indexPort, u32 dataPort );
39  static u16 wordChecksum(
40  const ICmosRW *cmos, u32 start, u32 end,
41  u32 indexPort, u32 dataPort, bool complement );
42  static u16 wordCrc(
43  const ICmosRW *cmos, u32 start, u32 end,
44  u32 indexPort, u32 dataPort );
45 
46 
47  // REGULAR CONSTRUCTOR
48  CmosRWChecksumObserver::CmosRWChecksumObserver(
49  string initDesc,
50  ICmosRW *initCmos,
51  int initCheckType, u32 initIndexPort, u32 initDataPort,
52  u32 initStart, u32 initEnd, u32 initChecksumLocation )
53  :
54  IObserver(),
55  description(initDesc),
56  cmos(initCmos),
57  checkType(initCheckType),
58  indexPort(initIndexPort),
59  dataPort(initDataPort),
60  start(initStart),
61  end(initEnd),
62  checksumLocation(initChecksumLocation)
63  {
64  observer::IObservable *ob = dynamic_cast<observer::IObservable*>(cmos);
65  if( ob )
66  ob->attach(this);
67  }
68 
69  // COPY CONSTRUCTOR
70  CmosRWChecksumObserver::CmosRWChecksumObserver( const CmosRWChecksumObserver &source )
71  :
72  IObserver(),
73  description(source.description),
74  cmos(source.cmos),
75  checkType(source.checkType),
76  indexPort(source.indexPort),
77  dataPort(source.dataPort),
78  start(source.start),
79  end(source.end),
80  checksumLocation(source.checksumLocation)
81  {
82  observer::IObservable *ob = dynamic_cast<observer::IObservable*>(cmos);
83  if( ob )
84  ob->attach(this);
85  }
86 
87  // DESTRUCTOR
89  {
90  observer::IObservable *ob = dynamic_cast<observer::IObservable*>(cmos);
91  if( ob )
92  ob->detach(this);
93  }
94 
95  void CmosRWChecksumObserver::update( const observer::IObservable *whatChanged, void *doUpdate )
96  {
97  const ICmosRW *cmos = dynamic_cast<const ICmosRW *>(whatChanged);
98 
99  const u8 *chksum = 0;
100  u16 wordRetval = 0;
101 
102  // optimize for the common case
103  u8 len = sizeof(wordRetval);
104  chksum = reinterpret_cast<const u8 *>(&wordRetval);
105 
106  // set up for the case where we throw an exception
107  ostringstream ost;
108  ost << hex ;
109  ost << description << endl;
110  ost << _("Checksum check for CMOS value does not match.") << endl;
111  InvalidChecksumImpl invalidChecksum;
112 
113  // All zeros indicates that this range is not checksummed
114  // icky to keep vc.net /w4 happy
115  if( !(start || end || checksumLocation))
116  return;
117 
118  switch( checkType )
119  {
121  ost << _("SMBIOS-specified checksum type is Byte Checksum. Type %(byte_chksum_type)i") << endl;
122  // works because we are little endian.
123  wordRetval = byteChecksum(cmos, start, end, indexPort, dataPort);
124  len = sizeof(u8);
125  break;
127  ost << _("SMBIOS-specified checksum type is Word Checksum. Type %(word_chksum_type)i") << endl;
128  wordRetval = wordChecksum(cmos, start, end, indexPort, dataPort, false);
129  break;
131  ost << _("SMBIOS-specified checksum type is One's Complement Word Checksum. Type %(word_chksum_n_type)i") << endl;
132  wordRetval = wordChecksum(cmos, start, end, indexPort, dataPort, true);
133  break;
134  case CHECK_TYPE_WORD_CRC:
135  ost << _("SMBIOS-specified checksum type is Word CRC. Type %(word_crc_type)i") << endl;
136  wordRetval = wordCrc(cmos, start, end, indexPort, dataPort);
137  break;
138  default:
139  ostringstream chkost;
140  chkost << hex;
141  chkost << _("Unknown checksum type encountered: ");
142  chkost << static_cast<int>(checkType);
143  throw smbios::Exception<smbios::IException>( chkost.str() );
144  }
145 
146 
147 
148  // if NULL parameter passed, or
149  // if parameter not null and evaluates to TRUE
150  if( !doUpdate || *static_cast<bool*>(doUpdate) )
151  {
152  // only write new checksum if it doesn't match what is already there
153  u32 actualChksum = 0;
154  u32 calculatedChksum = 0;
155  for( int i=0; i<len; ++i )
156  {
157  u8 byte = cmos->readByte(indexPort, dataPort, checksumLocation+i);
158  actualChksum = (actualChksum << 8) | byte;
159  calculatedChksum = calculatedChksum | (chksum[i] << (8*i));
160  }
161  if( actualChksum != calculatedChksum )
162  {
163  const cmos::Suppressable *o = dynamic_cast<const cmos::Suppressable *>(cmos);
164  o->suppressNotification(true);
165  for( int i=0; i<len; ++i )
166  {
167  cmos->writeByte(
168  indexPort, dataPort,
169  checksumLocation+i, chksum[len -i -1]);
170  }
171  o->resumeNotification(true);
172  }
173  }
174  else
175  {
176  u32 actualChksum = 0;
177  u32 calculatedChksum = 0;
178  for( int i=0; i<len; ++i )
179  {
180  u8 byte = cmos->readByte(indexPort, dataPort, checksumLocation+i);
181  actualChksum = (actualChksum << 8) | byte;
182  calculatedChksum = calculatedChksum | (chksum[i] << (8*i));
183  }
184  if( actualChksum != calculatedChksum )
185  {
186  ost << _("Checking alternate checksum algorithm results.") << endl
187  << _("Calculated (Type %(word_chksum_type)i) word checksum is: %(calc_word)i") << endl
188  << _("Calculated (Type %(byte_chksum_type)i) byte checksum is: %(calc_byte)i") << endl
189  << _("Calculated (Type %(word_crc_type)i) word crc is: %(calc_crc)i") << endl
190  << _("Calculated (Type %(word_chksum_n_type)i) 1's complement word checksum is: %(calc_word_n)i") << endl
191  << _("Actual data value is: %(actual)i") << endl
192  << _("Calculated data value is: %(calc)i") << endl
193  << _("Start: %(start)i") << endl
194  << _("End: %(end)i") << endl
195  << _("Checksum Loc: %(checksumLocation)i") << endl
196  << _("Index Port: %(index)i") << endl
197  << _("Data Port: %(data)i") << endl;
198 
199  invalidChecksum.setParameter( "byte_chksum_type", CHECK_TYPE_BYTE_CHECKSUM );
200  invalidChecksum.setParameter( "word_chksum_type", CHECK_TYPE_WORD_CHECKSUM );
201  invalidChecksum.setParameter( "word_chksum_n_type", CHECK_TYPE_WORD_CHECKSUM_N );
202  invalidChecksum.setParameter( "word_crc_type", CHECK_TYPE_WORD_CRC );
203  invalidChecksum.setParameter("calc_byte", byteChecksum(cmos, start, end, indexPort, dataPort));
204  invalidChecksum.setParameter("calc_word", wordChecksum(cmos, start, end, indexPort, dataPort, false));
205  invalidChecksum.setParameter("calc_word_n", wordChecksum(cmos, start, end, indexPort, dataPort, true));
206  invalidChecksum.setParameter("calc_crc", wordCrc(cmos, start, end, indexPort, dataPort));
207  invalidChecksum.setParameter("actual", actualChksum);
208  invalidChecksum.setParameter("calc", calculatedChksum);
209  invalidChecksum.setParameter("start", start);
210  invalidChecksum.setParameter("end", end);
211  invalidChecksum.setParameter("checksumLocation", checksumLocation);
212  invalidChecksum.setParameter("index", indexPort);
213  invalidChecksum.setParameter("data", dataPort);
214 
215  invalidChecksum.setMessageString( ost.str() );
216  throw invalidChecksum;
217  }
218  }
219  }
220 
221  /*******************
222  * Checksum functions
223  *******************/
224 
225 
226  static u8 byteChecksum(
227  const ICmosRW *cmos, u32 start, u32 end,
228  u32 indexPort, u32 dataPort )
229  {
230  u8 running_checksum=0;
231 
232  for( u32 i = start; i <= end; i++)
233  {
234  // not += to keep vc.net /w4 happy
235  running_checksum = running_checksum + cmos->readByte( indexPort, dataPort, i );
236  }
237 
238  return static_cast<u8>(running_checksum);
239  }
240 
241 
243  const ICmosRW *cmos, u32 start, u32 end,
244  u32 indexPort, u32 dataPort, bool complement )
245  {
246  u16 running_checksum=0;
247 
248  for( u32 i = start; i <= end; i++)
249  {
250  // not += to keep vc.net /w4 happy
251  running_checksum = running_checksum + cmos->readByte( indexPort, dataPort, i );
252  }
253 
254  if( complement )
255  running_checksum = (~running_checksum) + 1;
256  return running_checksum;
257  }
258 
259 
260  static u16 wordCrc(
261  const ICmosRW *cmos, u32 start, u32 end,
262  u32 indexPort, u32 dataPort )
263  {
264  u16 running_crc=0;
265 
266  for( u32 i = start; i <= end; i++)
267  {
268  running_crc ^= cmos->readByte( indexPort, dataPort, i );
269 
270  for( int j=0; j<7; j++ )
271  {
272  u16 temp = running_crc & 0x0001;
273  running_crc >>= 1;
274  if( temp != 0 )
275  {
276  running_crc |= 0x8000;
277  running_crc ^= 0xA001;
278  }
279  }
280  }
281 
282  return running_crc;
283  }
284 
285 }
286